From bf99a1aaadd2e93a15528cbaee6494e57f8e682a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 16 Jan 2024 01:39:32 +0600 Subject: [PATCH 0001/1190] Dark mode theme only for Windows --- src/qt/CMakeLists.txt | 3 +- src/qt/qdarkstyle/dark/darkstyle.qrc | 216 +++ src/qt/qdarkstyle/dark/darkstyle.qss | 2207 ++++++++++++++++++++++++++ src/qt/qt_main.cpp | 22 + src/qt/qt_styleoverride.cpp | 11 + src/qt/qt_winrawinputfilter.cpp | 53 + 6 files changed, 2511 insertions(+), 1 deletion(-) create mode 100644 src/qt/qdarkstyle/dark/darkstyle.qrc create mode 100644 src/qt/qdarkstyle/dark/darkstyle.qss diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index fb96de1ea..cc5bd6269 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -181,6 +181,7 @@ add_library(ui STATIC qt_mediahistorymanager.hpp ../qt_resources.qrc + ./qdarkstyle/dark/darkstyle.qrc ) if(RTMIDI) @@ -198,7 +199,7 @@ if(WIN32) target_sources(plat PRIVATE win_joystick_rawinput.c) endif() target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp) - target_link_libraries(86Box hid d3d9) + target_link_libraries(86Box hid d3d9 dwmapi) # CMake 3.22 messed this up for clang/clang++ # See https://gitlab.kitware.com/cmake/cmake/-/issues/22611 diff --git a/src/qt/qdarkstyle/dark/darkstyle.qrc b/src/qt/qdarkstyle/dark/darkstyle.qrc new file mode 100644 index 000000000..ce0d85be6 --- /dev/null +++ b/src/qt/qdarkstyle/dark/darkstyle.qrc @@ -0,0 +1,216 @@ + + + + rc/arrow_down.png + rc/arrow_down@2x.png + rc/arrow_down_disabled.png + rc/arrow_down_disabled@2x.png + rc/arrow_down_focus.png + rc/arrow_down_focus@2x.png + rc/arrow_down_pressed.png + rc/arrow_down_pressed@2x.png + rc/arrow_left.png + rc/arrow_left@2x.png + rc/arrow_left_disabled.png + rc/arrow_left_disabled@2x.png + rc/arrow_left_focus.png + rc/arrow_left_focus@2x.png + rc/arrow_left_pressed.png + rc/arrow_left_pressed@2x.png + rc/arrow_right.png + rc/arrow_right@2x.png + rc/arrow_right_disabled.png + rc/arrow_right_disabled@2x.png + rc/arrow_right_focus.png + rc/arrow_right_focus@2x.png + rc/arrow_right_pressed.png + rc/arrow_right_pressed@2x.png + rc/arrow_up.png + rc/arrow_up@2x.png + rc/arrow_up_disabled.png + rc/arrow_up_disabled@2x.png + rc/arrow_up_focus.png + rc/arrow_up_focus@2x.png + rc/arrow_up_pressed.png + rc/arrow_up_pressed@2x.png + rc/base_icon.png + rc/base_icon@2x.png + rc/base_icon_disabled.png + rc/base_icon_disabled@2x.png + rc/base_icon_focus.png + rc/base_icon_focus@2x.png + rc/base_icon_pressed.png + rc/base_icon_pressed@2x.png + rc/branch_closed.png + rc/branch_closed@2x.png + rc/branch_closed_disabled.png + rc/branch_closed_disabled@2x.png + rc/branch_closed_focus.png + rc/branch_closed_focus@2x.png + rc/branch_closed_pressed.png + rc/branch_closed_pressed@2x.png + rc/branch_end.png + rc/branch_end@2x.png + rc/branch_end_disabled.png + rc/branch_end_disabled@2x.png + rc/branch_end_focus.png + rc/branch_end_focus@2x.png + rc/branch_end_pressed.png + rc/branch_end_pressed@2x.png + rc/branch_line.png + rc/branch_line@2x.png + rc/branch_line_disabled.png + rc/branch_line_disabled@2x.png + rc/branch_line_focus.png + rc/branch_line_focus@2x.png + rc/branch_line_pressed.png + rc/branch_line_pressed@2x.png + rc/branch_more.png + rc/branch_more@2x.png + rc/branch_more_disabled.png + rc/branch_more_disabled@2x.png + rc/branch_more_focus.png + rc/branch_more_focus@2x.png + rc/branch_more_pressed.png + rc/branch_more_pressed@2x.png + rc/branch_open.png + rc/branch_open@2x.png + rc/branch_open_disabled.png + rc/branch_open_disabled@2x.png + rc/branch_open_focus.png + rc/branch_open_focus@2x.png + rc/branch_open_pressed.png + rc/branch_open_pressed@2x.png + rc/checkbox_checked.png + rc/checkbox_checked@2x.png + rc/checkbox_checked_disabled.png + rc/checkbox_checked_disabled@2x.png + rc/checkbox_checked_focus.png + rc/checkbox_checked_focus@2x.png + rc/checkbox_checked_pressed.png + rc/checkbox_checked_pressed@2x.png + rc/checkbox_indeterminate.png + rc/checkbox_indeterminate@2x.png + rc/checkbox_indeterminate_disabled.png + rc/checkbox_indeterminate_disabled@2x.png + rc/checkbox_indeterminate_focus.png + rc/checkbox_indeterminate_focus@2x.png + rc/checkbox_indeterminate_pressed.png + rc/checkbox_indeterminate_pressed@2x.png + rc/checkbox_unchecked.png + rc/checkbox_unchecked@2x.png + rc/checkbox_unchecked_disabled.png + rc/checkbox_unchecked_disabled@2x.png + rc/checkbox_unchecked_focus.png + rc/checkbox_unchecked_focus@2x.png + rc/checkbox_unchecked_pressed.png + rc/checkbox_unchecked_pressed@2x.png + rc/line_horizontal.png + rc/line_horizontal@2x.png + rc/line_horizontal_disabled.png + rc/line_horizontal_disabled@2x.png + rc/line_horizontal_focus.png + rc/line_horizontal_focus@2x.png + rc/line_horizontal_pressed.png + rc/line_horizontal_pressed@2x.png + rc/line_vertical.png + rc/line_vertical@2x.png + rc/line_vertical_disabled.png + rc/line_vertical_disabled@2x.png + rc/line_vertical_focus.png + rc/line_vertical_focus@2x.png + rc/line_vertical_pressed.png + rc/line_vertical_pressed@2x.png + rc/radio_checked.png + rc/radio_checked@2x.png + rc/radio_checked_disabled.png + rc/radio_checked_disabled@2x.png + rc/radio_checked_focus.png + rc/radio_checked_focus@2x.png + rc/radio_checked_pressed.png + rc/radio_checked_pressed@2x.png + rc/radio_unchecked.png + rc/radio_unchecked@2x.png + rc/radio_unchecked_disabled.png + rc/radio_unchecked_disabled@2x.png + rc/radio_unchecked_focus.png + rc/radio_unchecked_focus@2x.png + rc/radio_unchecked_pressed.png + rc/radio_unchecked_pressed@2x.png + rc/toolbar_move_horizontal.png + rc/toolbar_move_horizontal@2x.png + rc/toolbar_move_horizontal_disabled.png + rc/toolbar_move_horizontal_disabled@2x.png + rc/toolbar_move_horizontal_focus.png + rc/toolbar_move_horizontal_focus@2x.png + rc/toolbar_move_horizontal_pressed.png + rc/toolbar_move_horizontal_pressed@2x.png + rc/toolbar_move_vertical.png + rc/toolbar_move_vertical@2x.png + rc/toolbar_move_vertical_disabled.png + rc/toolbar_move_vertical_disabled@2x.png + rc/toolbar_move_vertical_focus.png + rc/toolbar_move_vertical_focus@2x.png + rc/toolbar_move_vertical_pressed.png + rc/toolbar_move_vertical_pressed@2x.png + rc/toolbar_separator_horizontal.png + rc/toolbar_separator_horizontal@2x.png + rc/toolbar_separator_horizontal_disabled.png + rc/toolbar_separator_horizontal_disabled@2x.png + rc/toolbar_separator_horizontal_focus.png + rc/toolbar_separator_horizontal_focus@2x.png + rc/toolbar_separator_horizontal_pressed.png + rc/toolbar_separator_horizontal_pressed@2x.png + rc/toolbar_separator_vertical.png + rc/toolbar_separator_vertical@2x.png + rc/toolbar_separator_vertical_disabled.png + rc/toolbar_separator_vertical_disabled@2x.png + rc/toolbar_separator_vertical_focus.png + rc/toolbar_separator_vertical_focus@2x.png + rc/toolbar_separator_vertical_pressed.png + rc/toolbar_separator_vertical_pressed@2x.png + rc/transparent.png + rc/transparent@2x.png + rc/transparent_disabled.png + rc/transparent_disabled@2x.png + rc/transparent_focus.png + rc/transparent_focus@2x.png + rc/transparent_pressed.png + rc/transparent_pressed@2x.png + rc/window_close.png + rc/window_close@2x.png + rc/window_close_disabled.png + rc/window_close_disabled@2x.png + rc/window_close_focus.png + rc/window_close_focus@2x.png + rc/window_close_pressed.png + rc/window_close_pressed@2x.png + rc/window_grip.png + rc/window_grip@2x.png + rc/window_grip_disabled.png + rc/window_grip_disabled@2x.png + rc/window_grip_focus.png + rc/window_grip_focus@2x.png + rc/window_grip_pressed.png + rc/window_grip_pressed@2x.png + rc/window_minimize.png + rc/window_minimize@2x.png + rc/window_minimize_disabled.png + rc/window_minimize_disabled@2x.png + rc/window_minimize_focus.png + rc/window_minimize_focus@2x.png + rc/window_minimize_pressed.png + rc/window_minimize_pressed@2x.png + rc/window_undock.png + rc/window_undock@2x.png + rc/window_undock_disabled.png + rc/window_undock_disabled@2x.png + rc/window_undock_focus.png + rc/window_undock_focus@2x.png + rc/window_undock_pressed.png + rc/window_undock_pressed@2x.png + + + darkstyle.qss + + diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss new file mode 100644 index 000000000..d785d6078 --- /dev/null +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -0,0 +1,2207 @@ +/* --------------------------------------------------------------------------- + + WARNING! File created programmatically. All changes made in this file will be lost! + + Created by the qtsass compiler v0.4.0 + + The definitions are in the "qdarkstyle.qss._styles.scss" module + +--------------------------------------------------------------------------- */ +/* Light Style - QDarkStyleSheet ------------------------------------------ */ +/* + +See Qt documentation: + + - https://doc.qt.io/qt-5/stylesheet.html + - https://doc.qt.io/qt-5/stylesheet-reference.html + - https://doc.qt.io/qt-5/stylesheet-examples.html + +--------------------------------------------------------------------------- */ +/* Reset elements ------------------------------------------------------------ + +Resetting everything helps to unify styles across different operating systems + +--------------------------------------------------------------------------- */ +* { + padding: 0px; + margin: 0px; + border: 0px; + border-style: none; + border-image: none; + outline: 0; +} + +/* specific reset for elements inside QToolBar */ +QToolBar * { + margin: 0px; + padding: 0px; +} + +/* QWidget ---------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QWidget { + background-color: #19232D; + border: 0px solid #455364; + padding: 0px; + color: #DFE1E2; + selection-background-color: #346792; + selection-color: #DFE1E2; +} + +QWidget:disabled { + background-color: #19232D; + color: #788D9C; + selection-background-color: #26486B; + selection-color: #788D9C; +} + +QWidget::item:selected { + background-color: #346792; +} + +QWidget::item:hover:!selected { + background-color: #1A72BB; +} + +/* QMainWindow ------------------------------------------------------------ + +This adjusts the splitter in the dock widget, not qsplitter +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow + +--------------------------------------------------------------------------- */ +QMainWindow::separator { + background-color: #455364; + border: 0px solid #19232D; + spacing: 0px; + padding: 2px; +} + +QMainWindow::separator:hover { + background-color: #60798B; + border: 0px solid #1A72BB; +} + +QMainWindow::separator:horizontal { + width: 5px; + margin-top: 2px; + margin-bottom: 2px; + image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); +} + +QMainWindow::separator:vertical { + height: 5px; + margin-left: 2px; + margin-right: 2px; + image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); +} + +/* QToolTip --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip + +--------------------------------------------------------------------------- */ +QToolTip { + background-color: #346792; + color: #DFE1E2; + /* If you remove the border property, background stops working on Windows */ + border: none; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Remove opacity, fix #174 - may need to use RGBA */ +} + +/* QStatusBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar + +--------------------------------------------------------------------------- */ +QStatusBar { + border: 1px solid #455364; + /* Fixes Spyder #9120, #9121 */ + background: #455364; + /* Fixes #205, white vertical borders separating items */ +} + +QStatusBar::item { + border: none; +} + +QStatusBar QToolTip { + background-color: #1A72BB; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Reducing transparency to read better */ + opacity: 230; +} + +QStatusBar QLabel { + /* Fixes Spyder #9120, #9121 */ + background: transparent; +} + +/* QCheckBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox + +--------------------------------------------------------------------------- */ +QCheckBox { + background-color: #19232D; + color: #DFE1E2; + spacing: 4px; + outline: none; + padding-top: 4px; + padding-bottom: 4px; +} + +QCheckBox:focus { + border: none; +} + +QCheckBox QWidget:disabled { + background-color: #19232D; + color: #788D9C; +} + +QCheckBox::indicator { + margin-left: 2px; + height: 14px; + width: 14px; +} + +QCheckBox::indicator:unchecked { + image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); +} + +QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); +} + +QCheckBox::indicator:unchecked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); +} + +QCheckBox::indicator:checked { + image: url(":/qss_icons/dark/rc/checkbox_checked.png"); +} + +QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); +} + +QCheckBox::indicator:checked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); +} + +QCheckBox::indicator:indeterminate { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); +} + +QCheckBox::indicator:indeterminate:disabled { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); +} + +QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); +} + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + font-weight: bold; + border: 1px solid #455364; + border-radius: 4px; + padding: 2px; + margin-top: 6px; + margin-bottom: 4px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 4px; + padding-left: 2px; + padding-right: 4px; + padding-top: -4px; +} + +QGroupBox::indicator { + margin-left: 2px; + margin-top: 2px; + padding: 0; + height: 14px; + width: 14px; +} + +QGroupBox::indicator:unchecked { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_checked.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); +} + +/* QRadioButton ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton + +--------------------------------------------------------------------------- */ +QRadioButton { + background-color: #19232D; + color: #DFE1E2; + spacing: 4px; + padding-top: 4px; + padding-bottom: 4px; + border: none; + outline: none; +} + +QRadioButton:focus { + border: none; +} + +QRadioButton:disabled { + background-color: #19232D; + color: #788D9C; + border: none; + outline: none; +} + +QRadioButton QWidget { + background-color: #19232D; + color: #DFE1E2; + spacing: 0px; + padding: 0px; + outline: none; + border: none; +} + +QRadioButton::indicator { + border: none; + outline: none; + margin-left: 2px; + height: 14px; + width: 14px; +} + +QRadioButton::indicator:unchecked { + image: url(":/qss_icons/dark/rc/radio_unchecked.png"); +} + +QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); +} + +QRadioButton::indicator:checked { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked.png"); +} + +QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); +} + +QRadioButton::indicator:checked:disabled { + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); +} + +/* QMenuBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar + +--------------------------------------------------------------------------- */ +QMenuBar { + background-color: #19232D; + padding: 2px; + border: 1px solid #455364; + color: #DFE1E2; + selection-background-color: #1A72BB; +} + +QMenuBar:focus { + border: 1px solid #346792; +} + +QMenuBar::item { + background: transparent; + padding: 4px; +} + +QMenuBar::item:selected { + padding: 4px; + background: transparent; + border: 0px solid #455364; + background-color: #1A72BB; +} + +QMenuBar::item:pressed { + padding: 4px; + border: 0px solid #455364; + background-color: #1A72BB; + color: #DFE1E2; + margin-bottom: 0px; + padding-bottom: 0px; +} + +/* QMenu ------------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu + +--------------------------------------------------------------------------- */ +QMenu { + border: 0px solid #455364; + color: #DFE1E2; + margin: 0px; + background-color: #37414F; + selection-background-color: #1A72BB; +} + +QMenu::separator { + height: 1px; + background-color: #60798B; + color: #DFE1E2; +} + +QMenu::item { + background-color: #37414F; + padding: 4px 24px 4px 28px; + /* Reserve space for selection border */ + border: 1px transparent #455364; +} + +QMenu::item:selected { + color: #DFE1E2; + background-color: #1A72BB; +} + +QMenu::item:pressed { + background-color: #1A72BB; +} + +QMenu::icon { + padding-left: 10px; + width: 14px; + height: 14px; +} + +QMenu::indicator { + padding-left: 8px; + width: 12px; + height: 12px; + /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ + /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +} + +QMenu::indicator:non-exclusive:unchecked { + image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); +} + +QMenu::indicator:non-exclusive:unchecked:hover, QMenu::indicator:non-exclusive:unchecked:focus, QMenu::indicator:non-exclusive:unchecked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); +} + +QMenu::indicator:non-exclusive:unchecked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_unchecked_disabled.png"); +} + +QMenu::indicator:non-exclusive:checked { + image: url(":/qss_icons/dark/rc/checkbox_checked.png"); +} + +QMenu::indicator:non-exclusive:checked:hover, QMenu::indicator:non-exclusive:checked:focus, QMenu::indicator:non-exclusive:checked:pressed { + border: none; + image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); +} + +QMenu::indicator:non-exclusive:checked:disabled { + image: url(":/qss_icons/dark/rc/checkbox_checked_disabled.png"); +} + +QMenu::indicator:non-exclusive:indeterminate { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); +} + +QMenu::indicator:non-exclusive:indeterminate:disabled { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate_disabled.png"); +} + +QMenu::indicator:non-exclusive:indeterminate:focus, QMenu::indicator:non-exclusive:indeterminate:hover, QMenu::indicator:non-exclusive:indeterminate:pressed { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); +} + +QMenu::indicator:exclusive:unchecked { + image: url(":/qss_icons/dark/rc/radio_unchecked.png"); +} + +QMenu::indicator:exclusive:unchecked:hover, QMenu::indicator:exclusive:unchecked:focus, QMenu::indicator:exclusive:unchecked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_unchecked_focus.png"); +} + +QMenu::indicator:exclusive:unchecked:disabled { + image: url(":/qss_icons/dark/rc/radio_unchecked_disabled.png"); +} + +QMenu::indicator:exclusive:checked { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked.png"); +} + +QMenu::indicator:exclusive:checked:hover, QMenu::indicator:exclusive:checked:focus, QMenu::indicator:exclusive:checked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked_focus.png"); +} + +QMenu::indicator:exclusive:checked:disabled { + outline: none; + image: url(":/qss_icons/dark/rc/radio_checked_disabled.png"); +} + +QMenu::right-arrow { + margin: 5px; + padding-left: 12px; + image: url(":/qss_icons/dark/rc/arrow_right.png"); + height: 12px; + width: 12px; +} + +/* QAbstractItemView ------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QAbstractItemView { + alternate-background-color: #19232D; + color: #DFE1E2; + border: 1px solid #455364; + border-radius: 4px; +} + +QAbstractItemView QLineEdit { + padding: 2px; +} + +/* QAbstractScrollArea ---------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QAbstractScrollArea { + background-color: #19232D; + border: 1px solid #455364; + border-radius: 4px; + /* fix #159 */ + padding: 2px; + /* remove min-height to fix #244 */ + color: #DFE1E2; +} + +QAbstractScrollArea:disabled { + color: #788D9C; +} + +/* QScrollArea ------------------------------------------------------------ + +--------------------------------------------------------------------------- */ +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; +} + +/* QScrollBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar + +--------------------------------------------------------------------------- */ +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #455364; + border-radius: 4px; + background-color: #19232D; +} + +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #455364; + border-radius: 4px; +} + +QScrollBar::handle:horizontal { + background-color: #60798B; + border: 1px solid #455364; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #346792; + border: #346792; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:focus { + border: 1px solid #1A72BB; +} + +QScrollBar::handle:vertical { + background-color: #60798B; + border: 1px solid #455364; + min-height: 8px; + border-radius: 4px; +} + +QScrollBar::handle:vertical:hover { + background-color: #346792; + border: #346792; + border-radius: 4px; + min-height: 8px; +} + +QScrollBar::handle:vertical:focus { + border: 1px solid #1A72BB; +} + +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + border-image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { + border-image: url(":/qss_icons/dark/rc/arrow_right.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { + border-image: url(":/qss_icons/dark/rc/arrow_down.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + border-image: url(":/qss_icons/dark/rc/arrow_left.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { + border-image: url(":/qss_icons/dark/rc/arrow_up.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { + background: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/* QTextEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets + +--------------------------------------------------------------------------- */ +QTextEdit { + background-color: #19232D; + color: #DFE1E2; + border-radius: 4px; + border: 1px solid #455364; +} + +QTextEdit:focus { + border: 1px solid #1A72BB; +} + +QTextEdit:selected { + background: #346792; + color: #455364; +} + +/* QPlainTextEdit --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QPlainTextEdit { + background-color: #19232D; + color: #DFE1E2; + border-radius: 4px; + border: 1px solid #455364; +} + +QPlainTextEdit:focus { + border: 1px solid #1A72BB; +} + +QPlainTextEdit:selected { + background: #346792; + color: #455364; +} + +/* QSizeGrip -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip + +--------------------------------------------------------------------------- */ +QSizeGrip { + background: transparent; + width: 12px; + height: 12px; + image: url(":/qss_icons/dark/rc/window_grip.png"); +} + +/* QToolBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar + +--------------------------------------------------------------------------- */ +QToolBar { + background-color: #19232D; + border-bottom: 1px solid #19232D; + padding: 1px; + font-weight: bold; + spacing: 2px; +} + +QToolBar:disabled { + /* Fixes #272 */ + background-color: #19232D; +} + +QToolBar::handle:horizontal { + width: 16px; + image: url(":/qss_icons/dark/rc/toolbar_move_horizontal.png"); +} + +QToolBar::handle:vertical { + height: 16px; + image: url(":/qss_icons/dark/rc/toolbar_move_vertical.png"); +} + +QToolBar::separator:horizontal { + width: 16px; + image: url(":/qss_icons/dark/rc/toolbar_separator_horizontal.png"); +} + +QToolBar::separator:vertical { + height: 16px; + image: url(":/qss_icons/dark/rc/toolbar_separator_vertical.png"); +} + +QToolButton#qt_toolbar_ext_button { + background: #19232D; + border: 0px; + color: #DFE1E2; + image: url(":/qss_icons/dark/rc/arrow_right.png"); +} + +/* QAbstractSpinBox ------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractSpinBox { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + border-radius: 4px; + /* min-width: 5px; removed to fix 109 */ +} + +QAbstractSpinBox:up-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: top right; + border-left: 1px solid #455364; + border-bottom: 1px solid #455364; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-bottom: -1px; +} + +QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { + image: url(":/qss_icons/dark/rc/arrow_up_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::up-arrow:hover { + image: url(":/qss_icons/dark/rc/arrow_up.png"); +} + +QAbstractSpinBox:down-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: bottom right; + border-left: 1px solid #455364; + border-top: 1px solid #455364; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-top: -1px; +} + +QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { + image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::down-arrow:hover { + image: url(":/qss_icons/dark/rc/arrow_down.png"); +} + +QAbstractSpinBox:hover { + border: 1px solid #346792; + color: #DFE1E2; +} + +QAbstractSpinBox:focus { + border: 1px solid #1A72BB; +} + +QAbstractSpinBox:selected { + background: #346792; + color: #455364; +} + +/* ------------------------------------------------------------------------ */ +/* DISPLAYS --------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QLabel ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe + +--------------------------------------------------------------------------- */ +QLabel { + background-color: #19232D; + border: 0px solid #455364; + padding: 2px; + margin: 0px; + color: #DFE1E2; +} + +QLabel:disabled { + background-color: #19232D; + border: 0px solid #455364; + color: #788D9C; +} + +/* QTextBrowser ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QTextBrowser { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + border-radius: 4px; +} + +QTextBrowser:disabled { + background-color: #19232D; + border: 1px solid #455364; + color: #788D9C; + border-radius: 4px; +} + +QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { + border: 1px solid #455364; +} + +/* QGraphicsView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QGraphicsView { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + border-radius: 4px; +} + +QGraphicsView:disabled { + background-color: #19232D; + border: 1px solid #455364; + color: #788D9C; + border-radius: 4px; +} + +QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { + border: 1px solid #455364; +} + +/* QCalendarWidget -------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCalendarWidget { + border: 1px solid #455364; + border-radius: 4px; +} + +QCalendarWidget:disabled { + background-color: #19232D; + color: #788D9C; +} + +/* QLCDNumber ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QLCDNumber { + background-color: #19232D; + color: #DFE1E2; +} + +QLCDNumber:disabled { + background-color: #19232D; + color: #788D9C; +} + +/* QProgressBar ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar + +--------------------------------------------------------------------------- */ +QProgressBar { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + border-radius: 4px; + text-align: center; +} + +QProgressBar:disabled { + background-color: #19232D; + border: 1px solid #455364; + color: #788D9C; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #346792; + color: #19232D; + border-radius: 4px; +} + +QProgressBar::chunk:disabled { + background-color: #26486B; + color: #788D9C; + border-radius: 4px; +} + +/* ------------------------------------------------------------------------ */ +/* BUTTONS ---------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QPushButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton + +--------------------------------------------------------------------------- */ +QPushButton { + background-color: #455364; + color: #DFE1E2; + border-radius: 4px; + padding: 2px; + outline: none; + border: none; +} + +QPushButton:disabled { + background-color: #455364; + color: #788D9C; + border-radius: 4px; + padding: 2px; +} + +QPushButton:checked { + background-color: #60798B; + border-radius: 4px; + padding: 2px; + outline: none; +} + +QPushButton:checked:disabled { + background-color: #60798B; + color: #788D9C; + border-radius: 4px; + padding: 2px; + outline: none; +} + +QPushButton:checked:selected { + background: #60798B; +} + +QPushButton:hover { + background-color: #54687A; + color: #DFE1E2; +} + +QPushButton:pressed { + background-color: #60798B; +} + +QPushButton:selected { + background: #60798B; + color: #DFE1E2; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + bottom: 4px; +} + +QDialogButtonBox QPushButton { + /* Issue #194 #248 - Special case of QPushButton inside dialogs, for better UI */ + min-width: 80px; +} + +/* QToolButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton + +--------------------------------------------------------------------------- */ +QToolButton { + background-color: #19232D; + color: #DFE1E2; + border-radius: 4px; + padding: 2px; + outline: none; + border: none; + /* The subcontrols below are used only in the DelayedPopup mode */ + /* The subcontrols below are used only in the MenuButtonPopup mode */ + /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +} + +QToolButton:disabled { + background-color: #19232D; + color: #788D9C; + border-radius: 4px; + padding: 2px; +} + +QToolButton:checked { + background-color: #60798B; + border-radius: 4px; + padding: 2px; + outline: none; +} + +QToolButton:checked:disabled { + background-color: #60798B; + color: #788D9C; + border-radius: 4px; + padding: 2px; + outline: none; +} + +QToolButton:checked:hover { + background-color: #54687A; + color: #DFE1E2; +} + +QToolButton:checked:pressed { + background-color: #60798B; +} + +QToolButton:checked:selected { + background: #60798B; + color: #DFE1E2; +} + +QToolButton:hover { + background-color: #54687A; + color: #DFE1E2; +} + +QToolButton:pressed { + background-color: #60798B; +} + +QToolButton:selected { + background: #60798B; + color: #DFE1E2; +} + +QToolButton[popupMode="0"] { + /* Only for DelayedPopup */ + padding-right: 2px; +} + +QToolButton[popupMode="1"] { + /* Only for MenuButtonPopup */ + padding-right: 20px; +} + +QToolButton[popupMode="1"]::menu-button { + border: none; +} + +QToolButton[popupMode="1"]::menu-button:hover { + border: none; + border-left: 1px solid #455364; + border-radius: 0; +} + +QToolButton[popupMode="2"] { + /* Only for InstantPopup */ + padding-right: 2px; +} + +QToolButton::menu-button { + padding: 2px; + border-radius: 4px; + width: 12px; + border: none; + outline: none; +} + +QToolButton::menu-button:hover { + border: 1px solid #346792; +} + +QToolButton::menu-button:checked:hover { + border: 1px solid #346792; +} + +QToolButton::menu-indicator { + image: url(":/qss_icons/dark/rc/arrow_down.png"); + height: 8px; + width: 8px; + top: 0; + /* Exclude a shift for better image */ + left: -2px; + /* Shift it a bit */ +} + +QToolButton::menu-arrow { + image: url(":/qss_icons/dark/rc/arrow_down.png"); + height: 8px; + width: 8px; +} + +QToolButton::menu-arrow:hover { + image: url(":/qss_icons/dark/rc/arrow_down_focus.png"); +} + +/* QCommandLinkButton ----------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCommandLinkButton { + background-color: transparent; + border: 1px solid #455364; + color: #DFE1E2; + border-radius: 4px; + padding: 0px; + margin: 0px; +} + +QCommandLinkButton:disabled { + background-color: transparent; + color: #788D9C; +} + +/* ------------------------------------------------------------------------ */ +/* INPUTS - NO FIELDS ----------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QComboBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QComboBox { + border: 1px solid #455364; + border-radius: 4px; + selection-background-color: #346792; + padding-left: 4px; + padding-right: 4px; + /* padding-right = 36; 4 + 16*2 See scrollbar size */ + /* changed to 4px to fix #239 */ + /* Fixes #103, #111 */ + min-height: 1.5em; + /* padding-top: 2px; removed to fix #132 */ + /* padding-bottom: 2px; removed to fix #132 */ + /* min-width: 75px; removed to fix #109 */ + /* Needed to remove indicator - fix #132 */ +} + +QComboBox QAbstractItemView { + border: 1px solid #455364; + border-radius: 0; + background-color: #19232D; + selection-background-color: #346792; +} + +QComboBox QAbstractItemView:hover { + background-color: #19232D; + color: #DFE1E2; +} + +QComboBox QAbstractItemView:selected { + background: #346792; + color: #455364; +} + +QComboBox QAbstractItemView:alternate { + background: #19232D; +} + +QComboBox:disabled { + background-color: #19232D; + color: #788D9C; +} + +QComboBox:hover { + border: 1px solid #346792; +} + +QComboBox:focus { + border: 1px solid #1A72BB; +} + +QComboBox:on { + selection-background-color: #346792; +} + +QComboBox::indicator { + border: none; + border-radius: 0; + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; + /* Needed to remove indicator - fix #132 */ +} + +QComboBox::indicator:alternate { + background: #19232D; +} + +QComboBox::item { + /* Remove to fix #282, #285 and MR #288*/ + /*&:checked { + font-weight: bold; + } + + &:selected { + border: 0px solid transparent; + } + */ +} + +QComboBox::item:alternate { + background: #19232D; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #455364; +} + +QComboBox::down-arrow { + image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { + image: url(":/qss_icons/dark/rc/arrow_down.png"); +} + +/* QSlider ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider + +--------------------------------------------------------------------------- */ +QSlider:disabled { + background: #19232D; +} + +QSlider:focus { + border: none; +} + +QSlider::groove:horizontal { + background: #455364; + border: 1px solid #455364; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::groove:vertical { + background: #455364; + border: 1px solid #455364; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical { + background: #346792; + border: 1px solid #455364; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical :disabled { + background: #26486B; +} + +QSlider::sub-page:horizontal { + background: #346792; + border: 1px solid #455364; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { + background: #26486B; +} + +QSlider::handle:horizontal { + background: #9DA9B5; + border: 1px solid #455364; + width: 8px; + height: 8px; + margin: -8px 0px; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #346792; + border: 1px solid #346792; +} + +QSlider::handle:horizontal:focus { + border: 1px solid #1A72BB; +} + +QSlider::handle:vertical { + background: #9DA9B5; + border: 1px solid #455364; + width: 8px; + height: 8px; + margin: 0 -8px; + border-radius: 4px; +} + +QSlider::handle:vertical:hover { + background: #346792; + border: 1px solid #346792; +} + +QSlider::handle:vertical:focus { + border: 1px solid #1A72BB; +} + +/* QLineEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit + +--------------------------------------------------------------------------- */ +QLineEdit { + background-color: #19232D; + padding-top: 2px; + /* This QLineEdit fix 103, 111 */ + padding-bottom: 2px; + /* This QLineEdit fix 103, 111 */ + padding-left: 4px; + padding-right: 4px; + border-style: solid; + border: 1px solid #455364; + border-radius: 4px; + color: #DFE1E2; +} + +QLineEdit:disabled { + background-color: #19232D; + color: #788D9C; +} + +QLineEdit:hover { + border: 1px solid #346792; + color: #DFE1E2; +} + +QLineEdit:focus { + border: 1px solid #1A72BB; +} + +QLineEdit:selected { + background-color: #346792; + color: #455364; +} + +/* QTabWiget -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabWidget { + padding: 2px; + selection-background-color: #455364; +} + +QTabWidget QWidget { + /* Fixes #189 */ + border-radius: 4px; +} + +QTabWidget::pane { + border: 1px solid #455364; + border-radius: 4px; + margin: 0px; + /* Fixes double border inside pane with pyqt5 */ + padding: 0px; +} + +QTabWidget::pane:selected { + background-color: #455364; + border: 1px solid #346792; +} + +/* QTabBar ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar, QDockWidget QTabBar { + qproperty-drawBase: 0; + border-radius: 4px; + margin: 0px; + padding: 2px; + border: 0; + /* left: 5px; move to the right by 5px - removed for fix */ +} + +QTabBar::close-button, QDockWidget QTabBar::close-button { + border: 0; + margin: 0; + padding: 4px; + image: url(":/qss_icons/dark/rc/window_close.png"); +} + +QTabBar::close-button:hover, QDockWidget QTabBar::close-button:hover { + image: url(":/qss_icons/dark/rc/window_close_focus.png"); +} + +QTabBar::close-button:pressed, QDockWidget QTabBar::close-button:pressed { + image: url(":/qss_icons/dark/rc/window_close_pressed.png"); +} + +QTabBar::tab, QDockWidget QTabBar::tab { + /* !selected and disabled ----------------------------------------- */ + /* selected ------------------------------------------------------- */ +} + +QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { + border-bottom: 3px solid #26486B; + color: #788D9C; + background-color: #455364; +} + +QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { + border-top: 3px solid #26486B; + color: #788D9C; + background-color: #455364; +} + +QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { + border-right: 3px solid #26486B; + color: #788D9C; + background-color: #455364; +} + +QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { + border-left: 3px solid #26486B; + color: #788D9C; + background-color: #455364; +} + +QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { + border-bottom: 3px solid #19232D; + color: #788D9C; + background-color: #19232D; +} + +QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { + border-top: 3px solid #19232D; + color: #788D9C; + background-color: #19232D; +} + +QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { + border-right: 3px solid #19232D; + color: #788D9C; + background-color: #19232D; +} + +QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { + border-left: 3px solid #19232D; + color: #788D9C; + background-color: #19232D; +} + +QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { + border-bottom: 2px solid #19232D; + margin-top: 2px; +} + +QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { + border-top: 2px solid #19232D; + margin-bottom: 2px; +} + +QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { + border-left: 2px solid #19232D; + margin-right: 2px; +} + +QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { + border-right: 2px solid #19232D; + margin-left: 2px; +} + +QTabBar::tab:top, QDockWidget QTabBar::tab:top { + background-color: #455364; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + min-width: 5px; + border-bottom: 3px solid #455364; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { + background-color: #54687A; + border-bottom: 3px solid #259AE9; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { + border: 1px solid #1A72BB; + border-bottom: 3px solid #1A72BB; + /* Fixes spyder-ide/spyder#9766 and #243 */ + padding-left: 3px; + padding-right: 3px; +} + +QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { + border-top: 3px solid #455364; + background-color: #455364; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + min-width: 5px; +} + +QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { + background-color: #54687A; + border-top: 3px solid #259AE9; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; +} + +QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { + border: 1px solid #1A72BB; + border-top: 3px solid #1A72BB; + /* Fixes spyder-ide/spyder#9766 and #243 */ + padding-left: 3px; + padding-right: 3px; +} + +QTabBar::tab:left, QDockWidget QTabBar::tab:left { + background-color: #455364; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + min-height: 5px; +} + +QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { + background-color: #54687A; + border-right: 3px solid #259AE9; +} + +QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { + border: 1px solid #1A72BB; + border-right: 3px solid #1A72BB; + /* Fixes different behavior #271 */ + margin-right: 0px; + padding-right: -1px; +} + +QTabBar::tab:right, QDockWidget QTabBar::tab:right { + background-color: #455364; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + min-height: 5px; +} + +QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { + background-color: #54687A; + border-left: 3px solid #259AE9; +} + +QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { + border: 1px solid #1A72BB; + border-left: 3px solid #1A72BB; + /* Fixes different behavior #271 */ + margin-left: 0px; + padding-left: 0px; +} + +QTabBar QToolButton, QDockWidget QTabBar QToolButton { + /* Fixes #136 */ + background-color: #455364; + height: 12px; + width: 12px; +} + +QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { + background-color: #455364; +} + +QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { + border: 1px solid #346792; +} + +QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { + image: url(":/qss_icons/dark/rc/arrow_left.png"); +} + +QTabBar QToolButton::left-arrow:disabled, QDockWidget QTabBar QToolButton::left-arrow:disabled { + image: url(":/qss_icons/dark/rc/arrow_left_disabled.png"); +} + +QTabBar QToolButton::right-arrow:enabled, QDockWidget QTabBar QToolButton::right-arrow:enabled { + image: url(":/qss_icons/dark/rc/arrow_right.png"); +} + +QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::right-arrow:disabled { + image: url(":/qss_icons/dark/rc/arrow_right_disabled.png"); +} + +/* QDockWiget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDockWidget { + outline: 1px solid #455364; + background-color: #19232D; + border: 1px solid #455364; + border-radius: 4px; + titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); + titlebar-normal-icon: url(":/qss_icons/dark/rc/transparent.png"); +} + +QDockWidget::title { + /* Better size for title bar */ + padding: 3px; + spacing: 4px; + border: none; + background-color: #455364; +} + +QDockWidget::close-button { + icon-size: 12px; + border: none; + background: transparent; + background-image: transparent; + border: 0; + margin: 0; + padding: 0; + image: url(":/qss_icons/dark/rc/window_close.png"); +} + +QDockWidget::close-button:hover { + image: url(":/qss_icons/dark/rc/window_close_focus.png"); +} + +QDockWidget::close-button:pressed { + image: url(":/qss_icons/dark/rc/window_close_pressed.png"); +} + +QDockWidget::float-button { + icon-size: 12px; + border: none; + background: transparent; + background-image: transparent; + border: 0; + margin: 0; + padding: 0; + image: url(":/qss_icons/dark/rc/window_undock.png"); +} + +QDockWidget::float-button:hover { + image: url(":/qss_icons/dark/rc/window_undock_focus.png"); +} + +QDockWidget::float-button:pressed { + image: url(":/qss_icons/dark/rc/window_undock_pressed.png"); +} + +/* QTreeView QListView QTableView ----------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview + +--------------------------------------------------------------------------- */ +QTreeView:branch:selected, QTreeView:branch:hover { + background: url(":/qss_icons/dark/rc/transparent.png"); +} + +QTreeView:branch:has-siblings:!adjoins-item { + border-image: url(":/qss_icons/dark/rc/branch_line.png") 0; +} + +QTreeView:branch:has-siblings:adjoins-item { + border-image: url(":/qss_icons/dark/rc/branch_more.png") 0; +} + +QTreeView:branch:!has-children:!has-siblings:adjoins-item { + border-image: url(":/qss_icons/dark/rc/branch_end.png") 0; +} + +QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/dark/rc/branch_closed.png"); +} + +QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/dark/rc/branch_open.png"); +} + +QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { + image: url(":/qss_icons/dark/rc/branch_closed_focus.png"); +} + +QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { + image: url(":/qss_icons/dark/rc/branch_open_focus.png"); +} + +QTreeView::indicator:checked, +QListView::indicator:checked, +QTableView::indicator:checked, +QColumnView::indicator:checked { + image: url(":/qss_icons/dark/rc/checkbox_checked.png"); +} + +QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, +QListView::indicator:checked:hover, +QListView::indicator:checked:focus, +QListView::indicator:checked:pressed, +QTableView::indicator:checked:hover, +QTableView::indicator:checked:focus, +QTableView::indicator:checked:pressed, +QColumnView::indicator:checked:hover, +QColumnView::indicator:checked:focus, +QColumnView::indicator:checked:pressed { + image: url(":/qss_icons/dark/rc/checkbox_checked_focus.png"); +} + +QTreeView::indicator:unchecked, +QListView::indicator:unchecked, +QTableView::indicator:unchecked, +QColumnView::indicator:unchecked { + image: url(":/qss_icons/dark/rc/checkbox_unchecked.png"); +} + +QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, +QListView::indicator:unchecked:hover, +QListView::indicator:unchecked:focus, +QListView::indicator:unchecked:pressed, +QTableView::indicator:unchecked:hover, +QTableView::indicator:unchecked:focus, +QTableView::indicator:unchecked:pressed, +QColumnView::indicator:unchecked:hover, +QColumnView::indicator:unchecked:focus, +QColumnView::indicator:unchecked:pressed { + image: url(":/qss_icons/dark/rc/checkbox_unchecked_focus.png"); +} + +QTreeView::indicator:indeterminate, +QListView::indicator:indeterminate, +QTableView::indicator:indeterminate, +QColumnView::indicator:indeterminate { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate.png"); +} + +QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, +QListView::indicator:indeterminate:hover, +QListView::indicator:indeterminate:focus, +QListView::indicator:indeterminate:pressed, +QTableView::indicator:indeterminate:hover, +QTableView::indicator:indeterminate:focus, +QTableView::indicator:indeterminate:pressed, +QColumnView::indicator:indeterminate:hover, +QColumnView::indicator:indeterminate:focus, +QColumnView::indicator:indeterminate:pressed { + image: url(":/qss_icons/dark/rc/checkbox_indeterminate_focus.png"); +} + +QTreeView, +QListView, +QTableView, +QColumnView { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + gridline-color: #455364; + border-radius: 4px; +} + +QTreeView:disabled, +QListView:disabled, +QTableView:disabled, +QColumnView:disabled { + background-color: #19232D; + color: #788D9C; +} + +QTreeView:selected, +QListView:selected, +QTableView:selected, +QColumnView:selected { + background-color: #346792; + color: #455364; +} + +QTreeView:focus, +QListView:focus, +QTableView:focus, +QColumnView:focus { + border: 1px solid #1A72BB; +} + +QTreeView::item:pressed, +QListView::item:pressed, +QTableView::item:pressed, +QColumnView::item:pressed { + background-color: #346792; +} + +QTreeView::item:selected:active, +QListView::item:selected:active, +QTableView::item:selected:active, +QColumnView::item:selected:active { + background-color: #346792; +} + +QTreeView::item:selected:!active, +QListView::item:selected:!active, +QTableView::item:selected:!active, +QColumnView::item:selected:!active { + color: #DFE1E2; + background-color: #37414F; +} + +QTreeView::item:!selected:hover, +QListView::item:!selected:hover, +QTableView::item:!selected:hover, +QColumnView::item:!selected:hover { + outline: 0; + color: #DFE1E2; + background-color: #37414F; +} + +QTableCornerButton::section { + background-color: #19232D; + border: 1px transparent #455364; + border-radius: 0px; +} + +/* QHeaderView ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview + +--------------------------------------------------------------------------- */ +QHeaderView { + background-color: #455364; + border: 0px transparent #455364; + padding: 0; + margin: 0; + border-radius: 0; +} + +QHeaderView:disabled { + background-color: #455364; + border: 1px transparent #455364; +} + +QHeaderView::section { + background-color: #455364; + color: #DFE1E2; + border-radius: 0; + text-align: left; + font-size: 13px; +} + +QHeaderView::section::horizontal { + padding-top: 0; + padding-bottom: 0; + padding-left: 4px; + padding-right: 4px; + border-left: 1px solid #19232D; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { + border-left: 1px solid #455364; +} + +QHeaderView::section::horizontal:disabled { + color: #788D9C; +} + +QHeaderView::section::vertical { + padding-top: 0; + padding-bottom: 0; + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #19232D; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { + border-top: 1px solid #455364; +} + +QHeaderView::section::vertical:disabled { + color: #788D9C; +} + +QHeaderView::down-arrow { + /* Those settings (border/width/height/background-color) solve bug */ + /* transparent arrow background and size */ + background-color: #455364; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/dark/rc/arrow_down.png"); +} + +QHeaderView::up-arrow { + background-color: #455364; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/dark/rc/arrow_up.png"); +} + +/* QToolBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox + +--------------------------------------------------------------------------- */ +QToolBox { + padding: 0px; + border: 0px; + border: 1px solid #455364; +} + +QToolBox:selected { + padding: 0px; + border: 2px solid #346792; +} + +QToolBox::tab { + background-color: #19232D; + border: 1px solid #455364; + color: #DFE1E2; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QToolBox::tab:disabled { + color: #788D9C; +} + +QToolBox::tab:selected { + background-color: #60798B; + border-bottom: 2px solid #346792; +} + +QToolBox::tab:selected:disabled { + background-color: #455364; + border-bottom: 2px solid #26486B; +} + +QToolBox::tab:!selected { + background-color: #455364; + border-bottom: 2px solid #455364; +} + +QToolBox::tab:!selected:disabled { + background-color: #19232D; +} + +QToolBox::tab:hover { + border-color: #1A72BB; + border-bottom: 2px solid #1A72BB; +} + +QToolBox QScrollArea { + padding: 0px; + border: 0px; + background-color: #19232D; +} + +/* QFrame ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe +https://doc.qt.io/qt-5/qframe.html#-prop +https://doc.qt.io/qt-5/qframe.html#details +https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color + +--------------------------------------------------------------------------- */ +/* (dot) .QFrame fix #141, #126, #123 */ +.QFrame { + border-radius: 4px; + border: 1px solid #455364; + /* No frame */ + /* HLine */ + /* HLine */ +} + +.QFrame[frameShape="0"] { + border-radius: 4px; + border: 1px transparent #455364; +} + +.QFrame[frameShape="4"] { + max-height: 2px; + border: none; + background-color: #455364; +} + +.QFrame[frameShape="5"] { + max-width: 2px; + border: none; + background-color: #455364; +} + +/* QSplitter -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter + +--------------------------------------------------------------------------- */ +QSplitter { + background-color: #455364; + spacing: 0px; + padding: 0px; + margin: 0px; +} + +QSplitter::handle { + background-color: #455364; + border: 0px solid #19232D; + spacing: 0px; + padding: 1px; + margin: 0px; +} + +QSplitter::handle:hover { + background-color: #9DA9B5; +} + +QSplitter::handle:horizontal { + width: 5px; + image: url(":/qss_icons/dark/rc/line_vertical.png"); +} + +QSplitter::handle:vertical { + height: 5px; + image: url(":/qss_icons/dark/rc/line_horizontal.png"); +} + +/* QDateEdit, QDateTimeEdit ----------------------------------------------- + +--------------------------------------------------------------------------- */ +QDateEdit, QDateTimeEdit { + selection-background-color: #346792; + border-style: solid; + border: 1px solid #455364; + border-radius: 4px; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + min-width: 10px; +} + +QDateEdit:on, QDateTimeEdit:on { + selection-background-color: #346792; +} + +QDateEdit::drop-down, QDateTimeEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #455364; +} + +QDateEdit::down-arrow, QDateTimeEdit::down-arrow { + image: url(":/qss_icons/dark/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus { + image: url(":/qss_icons/dark/rc/arrow_down.png"); +} + +QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { + background-color: #19232D; + border-radius: 4px; + border: 1px solid #455364; + selection-background-color: #346792; +} + +/* QAbstractView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractView:hover { + border: 1px solid #346792; + color: #DFE1E2; +} + +QAbstractView:selected { + background: #346792; + color: #455364; +} + +/* PlotWidget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +PlotWidget { + /* Fix cut labels in plots #134 */ + padding: 0px; +} diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 4d02e2601..afe3a9469 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #ifdef QT_STATIC /* Static builds need plugin imports */ @@ -154,6 +156,10 @@ main_thread_fn() static std::thread *main_thread; +#ifdef Q_OS_WINDOWS +extern bool windows_is_light_theme(); +#endif + int main(int argc, char *argv[]) { @@ -168,6 +174,22 @@ main(int argc, char *argv[]) QApplication app(argc, argv); QLocale::setDefault(QLocale::C); +#ifdef Q_OS_WINDOWS + Q_INIT_RESOURCE(darkstyle); + + if (!windows_is_light_theme()) { + QFile f(":qdarkstyle/dark/darkstyle.qss"); + + if (!f.exists()) { + printf("Unable to set stylesheet, file not found\n"); + } else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + } +#endif + qt_set_sequence_auto_mnemonic(false); Q_INIT_RESOURCE(qt_resources); Q_INIT_RESOURCE(qt_translations); diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp index 7ec5a341c..fab111172 100644 --- a/src/qt/qt_styleoverride.cpp +++ b/src/qt/qt_styleoverride.cpp @@ -19,6 +19,13 @@ #include #include +#ifdef Q_OS_WINDOWS +#include +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif +#endif + int StyleOverride::styleHint( StyleHint hint, @@ -48,6 +55,10 @@ StyleOverride::polish(QWidget *widget) widget->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, true); } widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false); +#ifdef Q_OS_WINDOWS + BOOL DarkMode = TRUE; + DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); +#endif } if (qobject_cast(widget)) { diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 3ca091ae6..57fd44126 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -34,10 +34,17 @@ #include "qt_winrawinputfilter.hpp" #include +#include +#include +#include #include #include +#include +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif #include <86box/keyboard.h> #include <86box/mouse.h> @@ -49,6 +56,34 @@ #include "qt_rendererstack.hpp" +bool windows_is_light_theme() { + // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application + + // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian + auto buffer = std::vector(4); + auto cbData = static_cast(buffer.size() * sizeof(char)); + auto res = RegGetValueW( + HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", + L"AppsUseLightTheme", + RRF_RT_REG_DWORD, // expected value type + nullptr, + buffer.data(), + &cbData); + + if (res != ERROR_SUCCESS) { + return 1; + } + + // convert bytes written to our buffer to an int, assuming little-endian + auto i = int(buffer[3] << 24 | + buffer[2] << 16 | + buffer[1] << 8 | + buffer[0]); + + return i == 1; +} + extern "C" void win_joystick_handle(PRAWINPUT); std::unique_ptr WindowsRawInputFilter::Register(MainWindow *window) @@ -124,6 +159,24 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess } return true; + } else if (msg && msg->message == WM_SETTINGCHANGE && msg->lParam != NULL && wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0) { + if (!windows_is_light_theme()) { + QFile f(":qdarkstyle/dark/darkstyle.qss"); + + if (!f.exists()) { + printf("Unable to set stylesheet, file not found\n"); + } else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + // From Dolphin emulator code: + // TODO: When switching from light to dark, the window decorations remain light. Qt seems very + // convinced that it needs to change these in response to this message, so even if we set them + // to dark here, Qt sets them back to light afterwards. + } else { + qApp->setStyleSheet(""); + } } /* Stop processing of Alt-F4 */ From 8389021508d1b758a29c3f95497c9a810e2929d9 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 16 Jan 2024 01:51:39 +0600 Subject: [PATCH 0002/1190] Forgot icon files --- src/qt/qdarkstyle/dark/rc/.keep | 1 + src/qt/qdarkstyle/dark/rc/arrow_down.png | Bin 0 -> 518 bytes src/qt/qdarkstyle/dark/rc/arrow_down@2x.png | Bin 0 -> 1023 bytes .../qdarkstyle/dark/rc/arrow_down_disabled.png | Bin 0 -> 546 bytes .../dark/rc/arrow_down_disabled@2x.png | Bin 0 -> 1068 bytes src/qt/qdarkstyle/dark/rc/arrow_down_focus.png | Bin 0 -> 523 bytes .../qdarkstyle/dark/rc/arrow_down_focus@2x.png | Bin 0 -> 992 bytes src/qt/qdarkstyle/dark/rc/arrow_down_pressed.png | Bin 0 -> 567 bytes .../qdarkstyle/dark/rc/arrow_down_pressed@2x.png | Bin 0 -> 1070 bytes src/qt/qdarkstyle/dark/rc/arrow_left.png | Bin 0 -> 555 bytes src/qt/qdarkstyle/dark/rc/arrow_left@2x.png | Bin 0 -> 1127 bytes .../qdarkstyle/dark/rc/arrow_left_disabled.png | Bin 0 -> 557 bytes .../dark/rc/arrow_left_disabled@2x.png | Bin 0 -> 1141 bytes src/qt/qdarkstyle/dark/rc/arrow_left_focus.png | Bin 0 -> 551 bytes .../qdarkstyle/dark/rc/arrow_left_focus@2x.png | Bin 0 -> 1119 bytes src/qt/qdarkstyle/dark/rc/arrow_left_pressed.png | Bin 0 -> 574 bytes .../qdarkstyle/dark/rc/arrow_left_pressed@2x.png | Bin 0 -> 1155 bytes src/qt/qdarkstyle/dark/rc/arrow_right.png | Bin 0 -> 532 bytes src/qt/qdarkstyle/dark/rc/arrow_right@2x.png | Bin 0 -> 1131 bytes .../qdarkstyle/dark/rc/arrow_right_disabled.png | Bin 0 -> 545 bytes .../dark/rc/arrow_right_disabled@2x.png | Bin 0 -> 1143 bytes src/qt/qdarkstyle/dark/rc/arrow_right_focus.png | Bin 0 -> 541 bytes .../qdarkstyle/dark/rc/arrow_right_focus@2x.png | Bin 0 -> 1112 bytes .../qdarkstyle/dark/rc/arrow_right_pressed.png | Bin 0 -> 574 bytes .../dark/rc/arrow_right_pressed@2x.png | Bin 0 -> 1162 bytes src/qt/qdarkstyle/dark/rc/arrow_up.png | Bin 0 -> 517 bytes src/qt/qdarkstyle/dark/rc/arrow_up@2x.png | Bin 0 -> 999 bytes src/qt/qdarkstyle/dark/rc/arrow_up_disabled.png | Bin 0 -> 549 bytes .../qdarkstyle/dark/rc/arrow_up_disabled@2x.png | Bin 0 -> 1074 bytes src/qt/qdarkstyle/dark/rc/arrow_up_focus.png | Bin 0 -> 532 bytes src/qt/qdarkstyle/dark/rc/arrow_up_focus@2x.png | Bin 0 -> 990 bytes src/qt/qdarkstyle/dark/rc/arrow_up_pressed.png | Bin 0 -> 554 bytes .../qdarkstyle/dark/rc/arrow_up_pressed@2x.png | Bin 0 -> 1053 bytes src/qt/qdarkstyle/dark/rc/base_icon.png | Bin 0 -> 1256 bytes src/qt/qdarkstyle/dark/rc/base_icon@2x.png | Bin 0 -> 3286 bytes src/qt/qdarkstyle/dark/rc/base_icon_disabled.png | Bin 0 -> 1256 bytes .../qdarkstyle/dark/rc/base_icon_disabled@2x.png | Bin 0 -> 3286 bytes src/qt/qdarkstyle/dark/rc/base_icon_focus.png | Bin 0 -> 1256 bytes src/qt/qdarkstyle/dark/rc/base_icon_focus@2x.png | Bin 0 -> 3286 bytes src/qt/qdarkstyle/dark/rc/base_icon_pressed.png | Bin 0 -> 1256 bytes .../qdarkstyle/dark/rc/base_icon_pressed@2x.png | Bin 0 -> 3286 bytes src/qt/qdarkstyle/dark/rc/branch_closed.png | Bin 0 -> 394 bytes src/qt/qdarkstyle/dark/rc/branch_closed@2x.png | Bin 0 -> 837 bytes .../dark/rc/branch_closed_disabled.png | Bin 0 -> 426 bytes .../dark/rc/branch_closed_disabled@2x.png | Bin 0 -> 862 bytes .../qdarkstyle/dark/rc/branch_closed_focus.png | Bin 0 -> 395 bytes .../dark/rc/branch_closed_focus@2x.png | Bin 0 -> 810 bytes .../qdarkstyle/dark/rc/branch_closed_pressed.png | Bin 0 -> 415 bytes .../dark/rc/branch_closed_pressed@2x.png | Bin 0 -> 867 bytes src/qt/qdarkstyle/dark/rc/branch_end.png | Bin 0 -> 147 bytes src/qt/qdarkstyle/dark/rc/branch_end@2x.png | Bin 0 -> 203 bytes .../qdarkstyle/dark/rc/branch_end_disabled.png | Bin 0 -> 152 bytes .../dark/rc/branch_end_disabled@2x.png | Bin 0 -> 205 bytes src/qt/qdarkstyle/dark/rc/branch_end_focus.png | Bin 0 -> 149 bytes .../qdarkstyle/dark/rc/branch_end_focus@2x.png | Bin 0 -> 203 bytes src/qt/qdarkstyle/dark/rc/branch_end_pressed.png | Bin 0 -> 152 bytes .../qdarkstyle/dark/rc/branch_end_pressed@2x.png | Bin 0 -> 204 bytes src/qt/qdarkstyle/dark/rc/branch_line.png | Bin 0 -> 132 bytes src/qt/qdarkstyle/dark/rc/branch_line@2x.png | Bin 0 -> 238 bytes .../qdarkstyle/dark/rc/branch_line_disabled.png | Bin 0 -> 135 bytes .../dark/rc/branch_line_disabled@2x.png | Bin 0 -> 240 bytes src/qt/qdarkstyle/dark/rc/branch_line_focus.png | Bin 0 -> 134 bytes .../qdarkstyle/dark/rc/branch_line_focus@2x.png | Bin 0 -> 238 bytes .../qdarkstyle/dark/rc/branch_line_pressed.png | Bin 0 -> 135 bytes .../dark/rc/branch_line_pressed@2x.png | Bin 0 -> 239 bytes src/qt/qdarkstyle/dark/rc/branch_more.png | Bin 0 -> 162 bytes src/qt/qdarkstyle/dark/rc/branch_more@2x.png | Bin 0 -> 260 bytes .../qdarkstyle/dark/rc/branch_more_disabled.png | Bin 0 -> 167 bytes .../dark/rc/branch_more_disabled@2x.png | Bin 0 -> 263 bytes src/qt/qdarkstyle/dark/rc/branch_more_focus.png | Bin 0 -> 164 bytes .../qdarkstyle/dark/rc/branch_more_focus@2x.png | Bin 0 -> 260 bytes .../qdarkstyle/dark/rc/branch_more_pressed.png | Bin 0 -> 161 bytes .../dark/rc/branch_more_pressed@2x.png | Bin 0 -> 262 bytes src/qt/qdarkstyle/dark/rc/branch_open.png | Bin 0 -> 407 bytes src/qt/qdarkstyle/dark/rc/branch_open@2x.png | Bin 0 -> 803 bytes .../qdarkstyle/dark/rc/branch_open_disabled.png | Bin 0 -> 422 bytes .../dark/rc/branch_open_disabled@2x.png | Bin 0 -> 872 bytes src/qt/qdarkstyle/dark/rc/branch_open_focus.png | Bin 0 -> 396 bytes .../qdarkstyle/dark/rc/branch_open_focus@2x.png | Bin 0 -> 791 bytes .../qdarkstyle/dark/rc/branch_open_pressed.png | Bin 0 -> 421 bytes .../dark/rc/branch_open_pressed@2x.png | Bin 0 -> 860 bytes src/qt/qdarkstyle/dark/rc/checkbox_checked.png | Bin 0 -> 650 bytes .../qdarkstyle/dark/rc/checkbox_checked@2x.png | Bin 0 -> 1238 bytes .../dark/rc/checkbox_checked_disabled.png | Bin 0 -> 731 bytes .../dark/rc/checkbox_checked_disabled@2x.png | Bin 0 -> 1334 bytes .../dark/rc/checkbox_checked_focus.png | Bin 0 -> 655 bytes .../dark/rc/checkbox_checked_focus@2x.png | Bin 0 -> 1269 bytes .../dark/rc/checkbox_checked_pressed.png | Bin 0 -> 704 bytes .../dark/rc/checkbox_checked_pressed@2x.png | Bin 0 -> 1319 bytes .../dark/rc/checkbox_indeterminate.png | Bin 0 -> 481 bytes .../dark/rc/checkbox_indeterminate@2x.png | Bin 0 -> 919 bytes .../dark/rc/checkbox_indeterminate_disabled.png | Bin 0 -> 545 bytes .../rc/checkbox_indeterminate_disabled@2x.png | Bin 0 -> 1003 bytes .../dark/rc/checkbox_indeterminate_focus.png | Bin 0 -> 466 bytes .../dark/rc/checkbox_indeterminate_focus@2x.png | Bin 0 -> 930 bytes .../dark/rc/checkbox_indeterminate_pressed.png | Bin 0 -> 518 bytes .../rc/checkbox_indeterminate_pressed@2x.png | Bin 0 -> 995 bytes src/qt/qdarkstyle/dark/rc/checkbox_unchecked.png | Bin 0 -> 385 bytes .../qdarkstyle/dark/rc/checkbox_unchecked@2x.png | Bin 0 -> 847 bytes .../dark/rc/checkbox_unchecked_disabled.png | Bin 0 -> 391 bytes .../dark/rc/checkbox_unchecked_disabled@2x.png | Bin 0 -> 868 bytes .../dark/rc/checkbox_unchecked_focus.png | Bin 0 -> 387 bytes .../dark/rc/checkbox_unchecked_focus@2x.png | Bin 0 -> 850 bytes .../dark/rc/checkbox_unchecked_pressed.png | Bin 0 -> 403 bytes .../dark/rc/checkbox_unchecked_pressed@2x.png | Bin 0 -> 862 bytes src/qt/qdarkstyle/dark/rc/line_horizontal.png | Bin 0 -> 120 bytes src/qt/qdarkstyle/dark/rc/line_horizontal@2x.png | Bin 0 -> 137 bytes .../dark/rc/line_horizontal_disabled.png | Bin 0 -> 121 bytes .../dark/rc/line_horizontal_disabled@2x.png | Bin 0 -> 139 bytes .../qdarkstyle/dark/rc/line_horizontal_focus.png | Bin 0 -> 119 bytes .../dark/rc/line_horizontal_focus@2x.png | Bin 0 -> 137 bytes .../dark/rc/line_horizontal_pressed.png | Bin 0 -> 120 bytes .../dark/rc/line_horizontal_pressed@2x.png | Bin 0 -> 138 bytes src/qt/qdarkstyle/dark/rc/line_vertical.png | Bin 0 -> 133 bytes src/qt/qdarkstyle/dark/rc/line_vertical@2x.png | Bin 0 -> 246 bytes .../dark/rc/line_vertical_disabled.png | Bin 0 -> 135 bytes .../dark/rc/line_vertical_disabled@2x.png | Bin 0 -> 249 bytes .../qdarkstyle/dark/rc/line_vertical_focus.png | Bin 0 -> 133 bytes .../dark/rc/line_vertical_focus@2x.png | Bin 0 -> 246 bytes .../qdarkstyle/dark/rc/line_vertical_pressed.png | Bin 0 -> 134 bytes .../dark/rc/line_vertical_pressed@2x.png | Bin 0 -> 248 bytes src/qt/qdarkstyle/dark/rc/radio_checked.png | Bin 0 -> 1260 bytes src/qt/qdarkstyle/dark/rc/radio_checked@2x.png | Bin 0 -> 2718 bytes .../dark/rc/radio_checked_disabled.png | Bin 0 -> 1336 bytes .../dark/rc/radio_checked_disabled@2x.png | Bin 0 -> 2871 bytes .../qdarkstyle/dark/rc/radio_checked_focus.png | Bin 0 -> 1232 bytes .../dark/rc/radio_checked_focus@2x.png | Bin 0 -> 2656 bytes .../qdarkstyle/dark/rc/radio_checked_pressed.png | Bin 0 -> 1288 bytes .../dark/rc/radio_checked_pressed@2x.png | Bin 0 -> 2804 bytes src/qt/qdarkstyle/dark/rc/radio_unchecked.png | Bin 0 -> 1007 bytes src/qt/qdarkstyle/dark/rc/radio_unchecked@2x.png | Bin 0 -> 2167 bytes .../dark/rc/radio_unchecked_disabled.png | Bin 0 -> 1045 bytes .../dark/rc/radio_unchecked_disabled@2x.png | Bin 0 -> 2277 bytes .../qdarkstyle/dark/rc/radio_unchecked_focus.png | Bin 0 -> 979 bytes .../dark/rc/radio_unchecked_focus@2x.png | Bin 0 -> 2127 bytes .../dark/rc/radio_unchecked_pressed.png | Bin 0 -> 1027 bytes .../dark/rc/radio_unchecked_pressed@2x.png | Bin 0 -> 2263 bytes .../dark/rc/toolbar_move_horizontal.png | Bin 0 -> 154 bytes .../dark/rc/toolbar_move_horizontal@2x.png | Bin 0 -> 307 bytes .../dark/rc/toolbar_move_horizontal_disabled.png | Bin 0 -> 155 bytes .../rc/toolbar_move_horizontal_disabled@2x.png | Bin 0 -> 309 bytes .../dark/rc/toolbar_move_horizontal_focus.png | Bin 0 -> 154 bytes .../dark/rc/toolbar_move_horizontal_focus@2x.png | Bin 0 -> 305 bytes .../dark/rc/toolbar_move_horizontal_pressed.png | Bin 0 -> 155 bytes .../rc/toolbar_move_horizontal_pressed@2x.png | Bin 0 -> 308 bytes .../qdarkstyle/dark/rc/toolbar_move_vertical.png | Bin 0 -> 140 bytes .../dark/rc/toolbar_move_vertical@2x.png | Bin 0 -> 212 bytes .../dark/rc/toolbar_move_vertical_disabled.png | Bin 0 -> 140 bytes .../rc/toolbar_move_vertical_disabled@2x.png | Bin 0 -> 214 bytes .../dark/rc/toolbar_move_vertical_focus.png | Bin 0 -> 139 bytes .../dark/rc/toolbar_move_vertical_focus@2x.png | Bin 0 -> 211 bytes .../dark/rc/toolbar_move_vertical_pressed.png | Bin 0 -> 143 bytes .../dark/rc/toolbar_move_vertical_pressed@2x.png | Bin 0 -> 209 bytes .../dark/rc/toolbar_separator_horizontal.png | Bin 0 -> 151 bytes .../dark/rc/toolbar_separator_horizontal@2x.png | Bin 0 -> 292 bytes .../rc/toolbar_separator_horizontal_disabled.png | Bin 0 -> 151 bytes .../toolbar_separator_horizontal_disabled@2x.png | Bin 0 -> 291 bytes .../rc/toolbar_separator_horizontal_focus.png | Bin 0 -> 149 bytes .../rc/toolbar_separator_horizontal_focus@2x.png | Bin 0 -> 288 bytes .../rc/toolbar_separator_horizontal_pressed.png | Bin 0 -> 151 bytes .../toolbar_separator_horizontal_pressed@2x.png | Bin 0 -> 294 bytes .../dark/rc/toolbar_separator_vertical.png | Bin 0 -> 137 bytes .../dark/rc/toolbar_separator_vertical@2x.png | Bin 0 -> 197 bytes .../rc/toolbar_separator_vertical_disabled.png | Bin 0 -> 136 bytes .../toolbar_separator_vertical_disabled@2x.png | Bin 0 -> 200 bytes .../dark/rc/toolbar_separator_vertical_focus.png | Bin 0 -> 135 bytes .../rc/toolbar_separator_vertical_focus@2x.png | Bin 0 -> 197 bytes .../rc/toolbar_separator_vertical_pressed.png | Bin 0 -> 138 bytes .../rc/toolbar_separator_vertical_pressed@2x.png | Bin 0 -> 196 bytes src/qt/qdarkstyle/dark/rc/transparent.png | Bin 0 -> 104 bytes src/qt/qdarkstyle/dark/rc/transparent@2x.png | Bin 0 -> 117 bytes .../qdarkstyle/dark/rc/transparent_disabled.png | Bin 0 -> 104 bytes .../dark/rc/transparent_disabled@2x.png | Bin 0 -> 117 bytes src/qt/qdarkstyle/dark/rc/transparent_focus.png | Bin 0 -> 104 bytes .../qdarkstyle/dark/rc/transparent_focus@2x.png | Bin 0 -> 117 bytes .../qdarkstyle/dark/rc/transparent_pressed.png | Bin 0 -> 104 bytes .../dark/rc/transparent_pressed@2x.png | Bin 0 -> 117 bytes src/qt/qdarkstyle/dark/rc/window_close.png | Bin 0 -> 733 bytes src/qt/qdarkstyle/dark/rc/window_close@2x.png | Bin 0 -> 1620 bytes .../qdarkstyle/dark/rc/window_close_disabled.png | Bin 0 -> 820 bytes .../dark/rc/window_close_disabled@2x.png | Bin 0 -> 1717 bytes src/qt/qdarkstyle/dark/rc/window_close_focus.png | Bin 0 -> 728 bytes .../qdarkstyle/dark/rc/window_close_focus@2x.png | Bin 0 -> 1659 bytes .../qdarkstyle/dark/rc/window_close_pressed.png | Bin 0 -> 744 bytes .../dark/rc/window_close_pressed@2x.png | Bin 0 -> 1777 bytes src/qt/qdarkstyle/dark/rc/window_grip.png | Bin 0 -> 412 bytes src/qt/qdarkstyle/dark/rc/window_grip@2x.png | Bin 0 -> 712 bytes .../qdarkstyle/dark/rc/window_grip_disabled.png | Bin 0 -> 434 bytes .../dark/rc/window_grip_disabled@2x.png | Bin 0 -> 764 bytes src/qt/qdarkstyle/dark/rc/window_grip_focus.png | Bin 0 -> 408 bytes .../qdarkstyle/dark/rc/window_grip_focus@2x.png | Bin 0 -> 730 bytes .../qdarkstyle/dark/rc/window_grip_pressed.png | Bin 0 -> 455 bytes .../dark/rc/window_grip_pressed@2x.png | Bin 0 -> 747 bytes src/qt/qdarkstyle/dark/rc/window_minimize.png | Bin 0 -> 203 bytes src/qt/qdarkstyle/dark/rc/window_minimize@2x.png | Bin 0 -> 333 bytes .../dark/rc/window_minimize_disabled.png | Bin 0 -> 207 bytes .../dark/rc/window_minimize_disabled@2x.png | Bin 0 -> 336 bytes .../qdarkstyle/dark/rc/window_minimize_focus.png | Bin 0 -> 206 bytes .../dark/rc/window_minimize_focus@2x.png | Bin 0 -> 333 bytes .../dark/rc/window_minimize_pressed.png | Bin 0 -> 210 bytes .../dark/rc/window_minimize_pressed@2x.png | Bin 0 -> 337 bytes src/qt/qdarkstyle/dark/rc/window_undock.png | Bin 0 -> 521 bytes src/qt/qdarkstyle/dark/rc/window_undock@2x.png | Bin 0 -> 880 bytes .../dark/rc/window_undock_disabled.png | Bin 0 -> 536 bytes .../dark/rc/window_undock_disabled@2x.png | Bin 0 -> 924 bytes .../qdarkstyle/dark/rc/window_undock_focus.png | Bin 0 -> 503 bytes .../dark/rc/window_undock_focus@2x.png | Bin 0 -> 866 bytes .../qdarkstyle/dark/rc/window_undock_pressed.png | Bin 0 -> 539 bytes .../dark/rc/window_undock_pressed@2x.png | Bin 0 -> 905 bytes 209 files changed, 1 insertion(+) create mode 100644 src/qt/qdarkstyle/dark/rc/.keep create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_down_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_left_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_right_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/arrow_up_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/base_icon_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_closed_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_end_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_line_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_more_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/branch_open_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/line_vertical_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_checked_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/radio_unchecked_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/transparent_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_close_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_grip_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_minimize_pressed@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_disabled.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_disabled@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_focus.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_focus@2x.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_pressed.png create mode 100644 src/qt/qdarkstyle/dark/rc/window_undock_pressed@2x.png diff --git a/src/qt/qdarkstyle/dark/rc/.keep b/src/qt/qdarkstyle/dark/rc/.keep new file mode 100644 index 000000000..8d1c8b69c --- /dev/null +++ b/src/qt/qdarkstyle/dark/rc/.keep @@ -0,0 +1 @@ + diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down.png b/src/qt/qdarkstyle/dark/rc/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..412b76e6fe53b0228445c158b5d5f23bf6f06c88 GIT binary patch literal 518 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vm@PZ!6Kh}O4LY`cX6McU?nZ<{LWxMiZ_86TnV>_52QxJ-1F)@6+ry!n4Yy~CCb zTQ&w9@!~#u$;tce^_28QLfWcQe;Q_9SCZ^>GoSfm<5?SnGjom8?|m;gx0l(})YR0v z=aj4Y*?XMd{_+PO{_Q99o}DB3RQ>K$i9u3_0Kc%EUyLA{1Q>to6qZ3{nLp1Ppy z(vUh^!l2N#=;DjRA4Ce$U;X8G z4KrVEvfuWXg^g`)oZ6X$-5aNVTd%Bl!|jsM+zD?LIM4KkUD~6f`QP&8bZP&fdtS4| zRo8iFeO^`Kbl`?eyj=F#S<^djU-G`pd*SNG$-G+I{vTpAx%k!1+H>96)g^j&O>EUm zgfk@8e0(-%tC^#dLte?g$tL+{FURdztADw~cERogTE{Y$brku`=dSryFv%vuW&0(* z_h~l+XZ}7A*Ya@*hoAvdo7n5Q7Im9eq&-!>_Ij_C(+T-TzJ{C_zCXII78mp6tKwYq zR~qlT`F_1Ampxn5lc5u)0>)iR`yn0Y?xdqvp+Iy^|EEl(%gTt Z?RY=8a@VIeQw9bG22WQ%mvv4FO#tau>vaGC literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_down@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..74d0099ec760fba42c33c4de86b8ec088e55676f GIT binary patch literal 1023 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEU?9Q6)_f2~?bx1Br@*uLd+;OMr7L}nSQl`B| zwdO_TJ9f$Bx-x;XWX5klzVz}lb-p*1Zce_o?vSzW@J|1Px zXP)rn(+uy=TQg34_xV$V#*?L?ORk*^JH2<_{Fo>P29CoY3LEcpR~V!VHI$Uh-5TIA z?*P}r$Mc^54ceA)nu+1SrAwc9-ag@CFi*eL@2c_6=3;2hd4GTF{rOunZZk0)c=Tyg z_VJhe4QZRTH9dYW=2*h2Ii0)STk2ZP?ZQQGr@gD--Xg31%5+UKOWipM6{lH$N;PjD zeNwpi`i8!@Q)~>Lm|8rx(9SOBv*rA7yr;2+q561o2=^ie=`(KP6{UaAEnJ=^lb$M} z@BE!{^XB&OiO19(YHTh182%p1oKvdcuv%ckjwxTR`JFi@7k9UH@!dk-tct*r#zQL) ze*AZK#-?X-PSUfuPj>IPQFQmR%H+F0ZeL#KnRMf=9*0eE(z?%o9j45Sn)`kB*>aC} zR_{EHZxeRQXN=M)oXxaq7e}rLs_3Hd)nG!Exn;8n2I{ z_sjMBo>WgcI-AAu%bXSZ3_iSl+yd@7GgKl{9Mk(BaqoK{Cw0_3;9>nc`$Hcxx&N>o zsI|O&?;gMOb??aR-~0>HZO`wvYP#by<5Wb~BJ~-sq8a#~_*7@k^_DaJVXZo^a>va* z8^e1mwf66BR;UQsvW}skXd(-5Y|Ey(`+1js-uM3g8n>7Ajao;)|DEmiXt6+ED$lKq zxKDGV88_|td}yu8w*IiWHe8KbDTRd}6@MSNQqCZET0*5EEa;Y&N9#4Q1M5FtX?)x- zWBDmu)++nA%C)@h|9h%m7Yo##lJIcIeD=3s``mNt{xSX4uZv4n_e<^$vzmL(G2+{F z20y;O{B7rI1yiL9B{M(OtiBqxI{1EsoWb=aZTEZam_Iz4;BCi0>)q+%l$hmu2|fB2 zo?!xR@{JX>zbk+2c)BzF*M83{=Wf__Pxh%jU)y}-=Gyd^cc(qyXSwc4dW)Kzud9a=UFmegP(*RgAJ>O;D=jVp4Xac>LO(p0|}nC>dtz``sD`G VFK-vP!N9=4;OXk;vd$@?2>|rT-f;i` literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down_disabled.png b/src/qt/qdarkstyle/dark/rc/arrow_down_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..972df9cd1661f7ff195c02b529491f8e71b92eb2 GIT binary patch literal 546 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vm~PZ!6Kh}O4LHf9S4${e@9FW$01q42^%&rS|6Hq{+gm0LYt2JrSZ<)-~-a=iP8 zTV~RZusv)GOFvXOv$K~9z7-JH)#K9JnzC`>vpT-%#>;b)CyDL8BhGj4?(co?zyGd# z|DDe$<-~-C4GU8q#LoZCC-QIdd$${F=*u7B}) z?vB8@M#l0dgu@lR&M!Y>t{OT`JnMY>McI`H)zZ@RXWtRJ5om0zx$k~$@z%LHS`jPu z%Y+p_;rp(2mD@#(L7m5^v+YNliR7=X<%?hRmL6RfmUiAnQ1L~`pQCox?czUr`xj^R z{+<1CS^oSd6Mi#Qoe%pSwd2Q+*E^yljZ#h&Ecn5?zopr E00z7RyZ`_I literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_down_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b0fb4ad11d0e40af005fd1b70eb6909db0990b64 GIT binary patch literal 1068 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE3@bp7WhbETjO!~NA&VrF4wwAft z^$QienKLs$!X~D; z=XPn`n=3gR9kcxy9Ikh}muJnL%rfuG%qeF#%QiLrcP;w4E+y&7uPWy2Dl;W^&Rc8# z_P}|&$qiPH$yx0i79EuTb2MjfX1sod#z%=WbL8gbpV)O?F-Aja!7~ny9exf%{$?q6 znP*-;{CVjQ&B#A*-h8>VZm)ms>l9z@3y&r;Eo-?O;_A{>V;on$eBt*yJN4gBd6ntB z`upprr+3Eo?=3i%8I!>@k26TrtmymoZ4+K7KYM>&xO3tgw!c%CFWy}KAi2?;S!S2i zHAzhlDS~vZBBxGbH4| zv$SRPS$Vm?WuH{;xfya*Qb0hL=bmV)foOkS+`{*#UcQliBl<;p!M*fVKjIw&g(n1g zYwelU=lW>sk2bA!R~qLX^i!@9t2mJz*!t<8lxUAg)}G!M-YX+YHrXtVTQzG{`>(#Y zrLjNdDy}34h}=w2(_quQP<}bo(niw0a--4G|3P1~uKxVw&@B<Td4&sq*Jam4Dscdp>;H4ME2gQ|&#G`V&s%otB*^A-h*}*|7`x zMW?^FD;q8^d|3D(bABX;&XHfC-=6hdH%j-{XLn#T70^5FeS^Vk00R<|qv zdtdU*GXZ)vsay9RW;$^&ob8_DPlF39e&rd-{q2x4lgYk!X2x!#ugS&Px8=3Jx9?t| zk+1UjqVU#h#qql=i^G@cn{I!XnX>bIMf8-#Co7)3{=E>En_!u0!AJg-GIOE)D~Zeu P3=9mOu6{1-oD!Mh3ZfCEFD%p!QgCcKeM5wNqIN|Qz<4I|EQy0&k`BnL>jll<_JC@Jy{N7i- zV8Ma~3G)ND&zRFK-K6~g@RbcW*R(HYc$hBq^;Ny^{_yn~FI6^7QezQrJa@k$XHoUP z(<{S;mf7EY>Dn**>mA#&rry9Q2K8+R7+W4b{WfFWy3j3KU$Zb=)4KKR)}_=Z>K-0^ z&5EBBl$||P{``oJzFPM=mXYDw@~y`AxUT1(Uv}@{Ir&2hoeBrOy{WLi6EXkVxd*%M zbKlmo?=Ih%r{2_cXy&a%m4_w8`?g1Mmrtns`F5VQ_W5eI-*x7q8hqyE0zpdaW=`ED z#}hsOWyWdV`!01HQ`%Zz7{6Dz8@2Z3#kgBDtF0}cYd&0lz;V)SD~Uzc8*aN@pH;f| z#G={RJJh7?Yhd6k*3A|-;eA$&r&UD(PnV*?zH;8OGnL3 z_nuvBeo5AT_k-Y#k5wPI{CefA@$yhn==;xEy?-WKZh!FjZJ#~Ud%h_pFH1w`yIs}N g(9pOMUdOQH$40h_?&CWc7#J8lUHx3vIVCg!04lQdFaQ7m literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down_focus@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_down_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..06b80be4bc306ff88da171474703a52f2c3362ea GIT binary patch literal 992 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE%v=eUxdYMPf=Q#5#lx5>5`|y1FtRr8nf#i zUDhP*y0Es3HGJKyo|B72y-a7H^0_2Za(VvTqp2>Jc63-3$BQpC+WB2==FB@YU8?3i z{rS%FdF}qs#pf*rI9Qk(9TZ^Hj_m=v5(RZp1a$fsvvuMB6<38be1ACAn zv#0nIQBRj^*Jmx+m=($WvcFiEAz;-HgKystEDYg&{C6gc^O7~oMVCC@x@p?yS2;5o z8kCFcZ1R2xeaKj)oW1`ni{Qhvbt-w+m1TEZt(zSkdb><`kJY-_o=XxR9DBBJ!q$4T zfaf#V^Gud3zCE*DHtj$x-}&DG@rT6?-GgG8v$iO2tB_fq%Q5ZW%gZl5%?K-7b@!5n zUVr9N{Y#q<@XuCe>In3%)Dg+=shIckbm5xkQHK1vbC}olWalP?szfBh9SNq2L;9;edN-TX;xQfEcS^LXWeh<3so=KYq2%9LSUuei>e%6=Iud>8xwQfeJ!8mUwtj5cgv>arR$63o`0nl zFK@_RIiY8JWnS@|;*~qg7OY!*I(S#?hBLg5cQd}|E#v`!Ay(pU>Lwvb;J`uBxJy^}w|U zI`2LIsl@l*TR->FWj{UBxtD%V=Se6yw%+^SqLn8+@~@owwd#7*Hx)((XXD;X@8ykb r*Jf|^oO@qe7b!=8@<(-NJ>%?aCfx7eoLR=ez`)??>gTe~DWM4flsDcU literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down_pressed.png b/src/qt/qdarkstyle/dark/rc/arrow_down_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..50f41cc6f8cde3807de153052bade435d007083c GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VnrPZ!6Kh}O4L3^RliMUL0M?+fTvC=KYEtocY~(b7V}J1!IZx`G|sZ!PfbYM#vT z>Q#boboT293l>Biab#Z_To|yTH|ogAgRToZ!d$(#?)+`7l72p6_U?!`MfMgy`l{dm z|M&jh_u2^)CQR6HDq_P6o48p=Gydv_9(|s^_$V)f--)ixDTlm-SADIXxGKbm&A+)^ zQT{{NBf%dFKluku^-8OCAzD-bD2wLy36Ib=WRGW(VlG$qsv~-naw8~D(}xZ{B-qC_P~r3yM3RgPR@UnWm`qA3RnOD literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_down_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_down_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ef20f2cb07f9934ce792a502ce9ad103d4cde38f GIT binary patch literal 1070 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hESOn&OU|?V^pj6lM32GRHrCujh~>Z``9Jzex8L4;I4`^WRqQvB z6MWxeg3rEZoD=81sM^pFj#M=(@!7M|`5Weayv4F{%b}LA!$FzSB75dletG|lc`6HkD0f(=yx&}g zdt3q%H~%h-xc-~B>XN7W{iR*@8+2k6@R$MJ6*Bwd{~6?iAOJCJgxp5r!oLG^R zA%3d-fb+b>RXbc*+3eNV{dW4+{Vzw?%G-_ebl}8k%Jc0MTYbe@Yi}g4O0Z;M``?}| zertLA{Xdp0GynICEZeN)|8-8?k$=bcGT4MA1q43vt8ZeE+VZSExOD#crN7s=>6q?1 z^z`JB6W3zka+{XGJ+|4Sv#zrO5r^&zeP_0OgAP4`Zl`68w#DE>+R zqM4oNjvmV`{_Xn2d%f?pxPlrf5jCmV&*OTnDpqV1iqQ^Vw(QPK@$%Z;wg2|93*L-< z_SwJaY_a=#9=>1SJ2_T-4vka2H?@lY;o=0tUv*_VKMPH#&&rCN{(VkG(hGxAFS^uR zO&>1#ed+79py{d)Qjg6%lbio`hy293OxzC3C%^lhWxEBDqre&Ko#{VT{dbPD?ejhU RF)%PNc)I$ztaD0e0szc>_cs6l literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_left.png b/src/qt/qdarkstyle/dark/rc/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..b7aeac5f8dc9d68f9704dfdb783eb36118ccc821 GIT binary patch literal 555 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 A82|tP literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_left_focus.png b/src/qt/qdarkstyle/dark/rc/arrow_left_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..ef028499477b3c5008d9266018d9cb3dda17bee3 GIT binary patch literal 551 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VntPZ!6Kh}Ngm46{QVMOyb8N4j!qMcs&qxEaymdt=E)9|z7Io$IDDT1zY1JLou7 z39@)AuB_SBDWJ1xZg1pe4=!m(7T@Ibl)y=EWV%xidfne+uJK~!^LfATT7N%R{b9fN zPF{7c`5nCbw|{sYX7O+L=iWId&#$dE`Syp$LT!3C=gvv5kV{966QE*kk|IoVoz-~bgE~WU(U!mIQ};IM zHf)lg@rEHWUc8atV`=gxraf8NvsZXNFm?;G>$v20SG!7lsb+$^+p$Q6Nj_%LRl;jC zAM6eg>qu!n8@V?mK>7v0Ldfgw>w;LNr*Ca5Wp-%R3u#+%=g_+~(%_?mCG z?%l(2ECH?^x16ucte)@#+oPAHe{44*;+djY^3Wf#HjG2xgviclC5#9m;dIdg(eBt*$af zEsZ9wja!mf54LuQu@oj=oS@Gf)$670G213L(=kTGB}QXWLdXWU+2+TOW~ZdZ9dvp2 zIO=}nJm%v6-^<_M*;)R~_Qk5z>;9b&y2`pHq*hoi^vUv6?XoSqZ(cC2jQMWQxS;-! zbmt#KyV&)z=gq6CKJ6%*a@@5mGyL@6Qe=Nfvrck-ebQrg{x)i<3-a$B^Yx4?h|-#+LIz26Z2eA zfZ=cO$IlC@gO?ew_WjwU#cp8mQr)3n-FEx?Ux%#uMVTdLeEEB6);>5DqOkkbIp>4M2?b}eAI(ZPxW1GraZQk!)&C`j(hgi;y#8p` zeWpC0UwVo4`=vyg6Ruo*@AK1b$FJ=dB1MBQ_#Is80%qTm@Y0JIlA3fXl?N-$)<$}ug<)_S*&sv@5+&{yp^w)=wCN1`cCp#ZsOg@yq z@Q2E5Si~jyx+xjKv js%h!f(D3y3e@y)w0>j>%74KzWU|{fc^>bP0l+XkK%Zm;1 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_left_pressed.png b/src/qt/qdarkstyle/dark/rc/arrow_left_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..c723d3bff7b4c169c6ef7cfdc565638df60d2d02 GIT binary patch literal 574 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vm+PZ!6Kh}Ngm3^RfQMcVe;*RBn6G;HF~)6?U7bYVfPjCRN_j+Mczg1*zXtbCx> z^+;`tul9}h<^*-=0!_YG&lY{M@?aNtlofGYk+9J9_7mCmC4Nos@5Ly+xG8t%^Z)y{ z@9z}r|9QXgLQ}K&vQN>0@2w4@`;LGAmsu-v>CcNBZ)1Bks(7}kXZz_*`8n~?*M0l` z$@cU3?RdhfM?^GstBhM?J z{WiSLxZarR~pg#QhUxXqein{W@@Qp;QEOE%(a5 c?~nNl8cpHJ&sMm{z`(%Z>FVdQ&MBb@04QShzyJUM literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_left_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_left_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f0bcb5229b1ceb85a30395d4255d258641f1dbdc GIT binary patch literal 1155 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk93_7!K#{f`Ta`y=;a*7-Bp93@*z~ znpfr^SaZRwb4J6D7iP<HiLQi}zdAzPAm%dLcZ%cJA3tYlMF+*XlFNPOI`t@QAh+zMB4M$2#%j zu9LzNzdW67kkw=};qaT6JJ!9mX}G#H?cy0V$AekDy7|i)McihG|ICozVDp0e&yHgS zVh)L4mYzOi!n&sG7>~$xi=R96M3%R?Nj;x!$Qm>2OT@X*1H7-duRo#t(DuP8lVinP z2R=BjpKolwp+rA`=U3OpCyR^N4iv1N_P_SS54nS9Cr;2g=Blsd&Tyhn-g15Ji+3CH zl@6Y4R%Ym0`mC(ytE2x6hfY5^8HNB2Q#p3I?qAamJyA?%xIRrFKS1aDIPGhN+wBvmDy?%KJ zV@!BfOz#bLo$i*J;9ry5MHqQ5*vOIRMv`gD$a59@zt=jkl9 zjq>T~-}9$bm`6zD&d;{`X;%_}_; z1a+oK`zuKE&lH+bJ-K~`_JV+{X%lmKXEGUkuia@Ge3WfLL{^UR7UNf^KN#PC?YH=c zmcl0o=Bl}KxvT%a6p?3Gdj0V6l{Xk>tn_-4C;e>azh9frlL==k{`;O( z30eO;qkyHtT*&Z=Sj&+~mL`F-rn9|gw&P>vVJ>EKTGS~sOJiWkSQs`|M$1+LnE*l+c(rS0YH1xg|lDwU);R_eQ4etUNQkF@U$pB?WT_)CU3scCais| z!-MW?$L8;@%nh?{55wm0Qc$=bBtNPi!tLL%{~yZ=%Pd63kxQzWHgo zWP@LJj@10!B0uU3&h=}~WoNihnfpfhg4l+2oqEq~XP5fbe!Y7AzjHm)^fJ5Vq|Ux( Q1_lNOPgg&ebxsLQ0C~X_i~s-t literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right.png b/src/qt/qdarkstyle/dark/rc/arrow_right.png new file mode 100644 index 0000000000000000000000000000000000000000..78d67f2dbc062ac17c8b16e76145bb2a21b033ee GIT binary patch literal 532 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VnRPZ!6Kh}O5)ZL>uJMUH*^zjLu0r<=8SY1$;yr3==!E?v?&wWD{z+SVt+9Ubuw zB5PcAST;txY}~RzY+KLGGd(A6X$Uq;-T57HMrT>^^VZo;{-xcP-+!K+8GWa*es9jS zcDKlXM-M2a|F!6|FXt>Uwkr=QcryKa^T!IC{o)O)-rV^<-}-#};fIZT89f-ZKevm^ zd3PORJ}_JH!Kt(`n+YbDC13F+sBuos&P#DERM%Oc!x$$dwB0Roo0t@Xg7N34m)_;3 z9KCv>fvb_-;LD5JX=~fq6bx;JCmx=c`{d`(1q=;YTugkkBzoNB&#|$Fn7Zmb_;dQ} zq6j|T8@(1{m3z;9{!@{`z_!n1gGHnGK}LtE{2j&z8JXH852U5c;ovQp^1a(%I9+^_ z%1;R)1K#_Wj;z%={;_KAv1v;)fAC9+|NcAq{i~AgtP)S%=U0^MoUfAqDsRL3*ovP_ zht|#an(R2)cb4A)mC(IWua|$E-1ggKRs-X?GX{^}B~7}QFU7a@ear4+dUDGOYj*oq z)HZ}Bi~CQ%^kdn~m-@1@%%}d(2)})QU)=9v<*abi^9}dpX3gHcWy-vJFO~MNIYdvo o`R~NqZ&iEWt~>N!{6PNl*VD}=+m^L3FfcH9y85}Sb4q9e0Af1u#{d8T literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_right@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ce0a8faeb375dbdf7e63775ce59c2e4d6ea23ae3 GIT binary patch literal 1131 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE+FdR*C{-9FEYheDa4zz4@;Joid7xW?L$2wfWcsdUvX0jUcm##F@1EB_vt{Y( z@UktdcJX~~w)ByG_5W4;`qi(#vKu5GYT;y?5VY^+EJU)x&^nL9j0qs$CmByG2@xG|-T zw?~qp!CT5KNO%7gNgk$VD>uW;170j!eRTgANaU0(Fg4TTVK~r#W%HjyTeG{R@4Q$m zH=C{C;rW=q`))74{kH7xqGva5m^d(oM2J_s4%z$fXzDY~?p?`=KZO!pj~<<9D8KY& zVVYSP+fVz5cxH(UJ_^UUJ@^0b%YA$GL5g6C!^Ul%mk!SJ;oo)Pzq!m?rUr#4RoeS+ z`(6@{JsQwv%v|v!_-L8ZKMl`ImEnaVg=q{1I+G5};%w^l|D*EMZ2HDK!sY8c5?;*Q z5Z2&Ve))^x^@lsm6Fg>ezV`h1Q^nJ4H_s9+W`+jGS)BX^o!)oz%!@=_rn2#bvxuC| z$Wb!fdf{b>T#2C5RyGEPiY<;h%^w1C&)(vGTlTx|_A5CF28IA-6NZPDgv+MkmZzK=tw zaluksE3MP>a<)d*-?+BkiaEpN_vxRlq5JmU%=!09sX@!QVS)bvUdDTZM++Zmb*$pi zkp442;L%ErdHY@&34EWe7I$ps3Fw)1?^M3Y;up!`hEpCMVNl}Gn)7kS$2w&m?Rwv1yBJwG(%yFb zj+9|#&k-?yoOF{xXwCfh=T#CvOyX~5e@y-)whr zy1&fv?Ydcgy|Z&Cd`zDAcW-f7*|%lFdkqUVa{OEK>DITIGiTn<$^I+uBNg!N!6&PT zw;5Z_zVg13IC@Imn8D$IuIr7P87BM8mnJet&p%_(_X>84)*w_xogXR{K^HWUV$XzHZcH+p>F z?r7@0sqjwB$xQEr(z#>j4&AzU$ZJDk=Yk5w=No5m-k5pXK=aF5zmIWsbBdqw{CT~w zaMGiyWbpuzpDDLuf5)gONEzoduBck^_UP29&Yu|=5(>}V|Mq>7%1v`|2f3|x18Qff zcrGnz2r!5!NEKMcFZr2Il+9q9N_uwQ(dp7_gBWKXVq;}EGIz(l7+vuR+ANCk_xoS> zu2y9}kdWE(;N+vC;*}u`4ZX(PqPOqfDthd+vcblQ&r)E`TZ_zjy3!71B4$4fzO9Zb z`W&*dVU8d}a$k#s{l1dN87CPSnvBnIehZ5`$Nb^=PVoFCskVtlq+y;oZ~Ur>RQQ^L#Z z(%EmbJ+03$2~>pC*QS5|_|3$38EZy}cEsE7x1@u=&E!&;bA4vD_17OlOS)w(}boNq$q>Sp^_ zck{ld3m#5mj A>i_@% literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_right_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5351587e3d495ec44cd014107ef0a55b5b074885 GIT binary patch literal 1143 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEmt_K9Hu8m^h0C6g=VHbq~$ z|A%Y#yEDIeP3GS|_ptVU&CE*Ud}I5B6B888jZ(A&jI4iJ3GQXmNPDKdwrXjL_BQV+ zYaLu(g*GHH9Cy@ED{gIBdqZzynnS$~6Gu<$7nj8Lqd)vMWH!9}-`o)R?$MRQ!jsD* zuWab^WxgSynDaL4s?U4d9d{S?h2}^V=x!^vx#nT>@k*naO3LErGE>R0(*8}k`=ig?Ql4T z^X9~j#g{i!aNg#4m+f%Fi{aDCJ6C3(+j_k*MDWTnj?WK6%<3aN{?GD|WMGI*Zh5gb zL@!?8%t41s4O`z9nEJ@86t}L)kgGi*b>NIbvb9E1&8L7eEzMb{XYJUb)SP&&#kZ@X z?z>Cf@)E00Y+n+LwjW*_bvgWGZELlPaObIpt+SIZv=|0uygT*m{e)A>M$BP}M%jn9 zNdzkIeSaZWh|?vPVaCCR!stE0tIs8+{r{)C?yIu-g7(U2l?VI$em`qH(#SkJR;xOR zfx+Q>n6rEfySv^oyV9FBKT{YwJT_l+y!7M5jh$W_BT6Q%4rgQFc{P{k;H(cnocxB8#$=Of|L5|yCm)>L-!U)uiq`v^ zK_4nuXG~^)xb;}f&09|x>v;nd%jZ2lyYrMFyOW(G!{#Q--~Dns%5Q(>_{~_>ToJ~+ zg()`nyX22ghi1&und+su{c!K&vs@4EZQ}R)H`_bw%SQS1w6K_$Rf!D7A~Qwbr)z9| zzWaRt*4Qlf{j41w2M*f)pB?w`t~dA7`k2%1yO}yNw!Zk<`|x~(`Mjv86@OGGI;F6E zkqcr~JHKPWj7!U(Ew7(`N?D7!!}qN>kIkpjwKZ-=f|bl1B8zr2UAh^z_tV}It4nMG zTNa+=soG@uJ<-`hoZ%Cj#^VjiGFewo&F6ex$a*r_KukvA*>vfzuX+;r*n+eb)-11I z9=P7^pU<(qj0?~5o;SEY zcU~!6YOSFs@5N@ld;X)@x2vb8r~fZrT50PcdN6)!U%Ht8oFCyH`FA}e3Z_l^3X5&8fC literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right_focus.png b/src/qt/qdarkstyle/dark/rc/arrow_right_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..92271a8ed9454067555798b44d143257b53b1b6c GIT binary patch literal 541 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VoEPZ!6Kh}O5)Y`cRUC60dlKhxzSYrK`Cw4gTkR>MR=Z_mw}B2%xsUAX4-O}Im+ zjxlh9*v1K>XZ2VLH;Qz6E)@$C%T~Uj(fy-Ityt%on@;g$1F>Hs)1%Lv`FZwE`h!FJ zW(?00aF@h+$-67?^947gV4A9 zmi#Nx`zDAoC~UYWP`LctiOrFWoQcxXD>&>|to;=d=HR3;N#M4~UAv2)KCWqK5}Z4$ zxO~I>Gi!bpq%mliE^VwWe6U>o`W}1j1p!CCm|EPB|4~@y;KcJfqOO6nHDPho#l|%Z z-40&=1+=XG*7&_QW|B!^$&oU(Dz37Ab>`KPixwQ5Ki(}c-n%Sr>P-8KoHv35?F^z` zn0{UJMk;xJL$AtmUXSTjpR@WmpWC6XuymPo#!Bn;)yeCEGdG;N*K}^Xtkw5r w3*|3!=riAN3Hu?L7H|F~HR|Di?g!%h^OiVF|2XFr0|Nttr>mdKI;Vst03IRmZ~y=R literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right_focus@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_right_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c31bdda91b138d926aa03db2cd4695e6c6a3f8 GIT binary patch literal 1112 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEDMu@u()!=kTdOo%VrIS zSyuyH3yuf%b}u~E-^yurDe4o0LcpavN49KZk+v5)$Rm*8J>AUVSIO%&c^pdxn-kas zCOrRiY@^fh{J9sO1z0WQ+|KfE=GkLeiKpk7sa=qoA;QLRp!acW-(9=ayq#b4W@NCf z*rU?2cCVB1~=fC|EvcwrOxt`DZ;zb4WgS>%2veU*LJ6JfHKr*p)-u zrkO46NI1d9P%9i_ryCdVa9r(KX==__9v%jUsO6PRd4b`@x9?xvHRIGwi4C`Grurxp z9N)S6OX8Vln$pZ+A5Hzgmz}?{{X@^9BeP~RHmt8?l3#HrC%)&Rj*CsT$7mgsdHOX6l{WW{UruHjwq{sfP}743y4o6Hy( zUg%dJ+;(&i?~C;JM>Jl%4G_9%Gxw`f@6PK#ZWJBfBju&^Sn`4Izn5jr2Pd%?nKU$T zJl?nS`sue;eJ#^YpJU)`(@J0e{g(Qf#|pLj3HqITcocZNx6eDEzBl-pqfFU6X%b?Ci7dHJ`GucvHO zS+?_T+DSZzV7&Z+N$1ffvJIF{frN`2miM|ST|L(PTou1<~wB`QFtQsS^n)QLF#Gbt5uU|i7fBWC%r^G&_BNk=*aC;nj0 Y`{!5p;FxMK0|Nttr>mdKI;Vst007JZjsO4v literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_right_pressed.png b/src/qt/qdarkstyle/dark/rc/arrow_right_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..22902cf4fc4d8f629374abbd7064bee09f9da5f7 GIT binary patch literal 574 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vm+PZ!6Kh}O5)>@$QDC60f5|2ZycX;YW1NUX~onLom39z4*9eWh~H^`h&gTPCar z1HB4L0wzUeI|!5tbVmyuy|{2e?vbM>7f#mj@NVxiJ^5GW-6o5>v3;i(@ZTvr|NHlc zJHPMA{&}4mm}eEcF25mi-)+lHe_kA`n#Cagao^qrwsT|FmHzoOH}){Ym)B=byf|?> zdFf8s!%PYi@^{U@EeWZ5n93*cBY{b8U2ko6gVNiDR~XoY_A#g|>ze#EYFPtA;-rV{ z9J@nx%+rin8D>lfXmI%6_4L?MAI1;YRW3X}^yH7rG6oK{Mu7*GKfPO5{<`VI*vMq> z@}|UY?W3)`)i<-YaGYd$GwpMn_`3V{vve5@g8$2IykE6<`*N+`=9x@QTz+i_6R%%f zt;oRO(qUo9(qL)8lD&72Y}ciU-r7+QbbgrCOn*N2w}t&*Q?K|a;R3NgcXF&G^7Vb{ zJMYYJvvB;Of4}hG-@~t#TbymSW8z*vFMr*Yx`0aY^2Q^=6Hfm6+ZLOv9~R|#&C`m} zcqa3N8L^q?Y`k~)P2xP^pcir{E;sD8=iy}L7M`!?cZu2Qggs~D?B_KokWi@JSCvq! zR`Z=d#PEAV;)k^C$Hzrynbuz@=-AIbZF_xQ{Es~$zvsGHxXfutxP0K#-FHV$U7j7C f+4^6R)KD5(h@wAWFRV=V}2S6};N z-Z(IWk;x!=hrE`>j;hD6SNpu2aqNkph4AVbD#6W9r~j7CDDCBDW_VCF@ls>-_4hA| zmy}TU+9>_g|+*-aa`d}b^3w?2L0`uo=Z-q}hTKHoVSPF&k?>&`2e|M3N1MHm`f zq!r6~rm4%7OEkB6GjH1E+ToF1sw!0`d3>dXX~N2ApV!9#aMemEEag48FlqancMAd`i#XNWM6G`s7F*UEA!*_e_>PT+hg) zv1r1*`o^5B?OFLVCVjlZ!04I#afyw&@a$-t2l>1lTjq+p%&qurcG*cTt%0TL>EqjP zwd?Lo`q=w$&qr-$j@*w-bsp;?`ac%#RX1pGXY*ii%=%~%vd5rufpEB3&dOhfEFBC* zzs?E&m=ja?eYy4P{Wqt4Q)E`z`&nV1p4zK(elb69ZmU?wRD9;j zc6KP9S5{b*f587x!rO{?&YQq3cDVrY`rU0dp}iX`6DA{u9u9A^XGNCC$}4B zSQs`$TJ!I@ly|lG|ID6dWraqE*Pp(XMQv5jjmg_}w2Up~&YKU8_op5=|FNOsKoZ*o z4wbu)m@bR|zxe&Zmx{kjbnoVE{ONr1%cFE|)jQUEzhAtcn>mkrom_ML+0&a!-DfH9 zx42}T9V78UcI7ph%-%l_99C!h{7Y1N&HAq})Z<#&qmB8#FJ~N!0NL}*Wo7B+wYu@M zE^TN$$n)d5u$ZFAhkf7PZQQoJ+H4l^(?FnGH9xvXVFFUZaV$w>2rVi_hq~9$_uly zH6J|m{ox1EN56Ou@u!|>Z2Xv~=b5)HYHfZ!N5%W|u6Nj8cv)tC45VBSMRFRMO(rJ!o?|+GS6TX;t-7Ige2XFEfCqFOw_UCJGRz^mKg=Za; Z%j=D4d>OOt85kHCJYD@<);T3K0RSkD?ic_7 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_up@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_up@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8c73c3be316a2cafdcad38e67316bc56eebc48fa GIT binary patch literal 999 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hElEj|>;dO2xK5sXckPwpQ@^P9buw?3e0%rc#<_QDD?ac3 z*?WJ_`@NOM^E?^4k0x!5&=G@Dr&qVigeI(AEXq~SvcRQa`MXN0>~|_$(vFDw$oiqSUhdH!ri1N=za9Lf*4(e9 z>{1|KShMtE#-HFN`<%`68ol2cU`x_Fi)l>w}Q275hJ3PSiSdzw^PR=y~5O!g`k}>=a-*=-OVv68y=i z^pnJoCErhJwr6Coy+1!Ntu2OYLFtxR4st>khB@l&+V-cXE_*+j=b41r`~@qfUAuVd zOjEl>3FDT&bwNM08+In{<`9~h`ZV~@ahqb1dzY>L{MhhWeig%Qt6y^tnI5*8In|oy z_gs^%MGxL><2xR=mOp8k^MoZY4F2#5Tz-6XOZjJ~gcy^b``+o+S)Tr#_=;(Z=XNpI z?JYa9B=n4a+V;2#6s&z#Ils%p=531bmWS*xBte)wp)F?9VPn=Gpgq7om==}2U zUYl>;nOm}|^L&F}`g4^jzZK@z*e6e$Zo|Ogad~f3MCr3<%d6~tt}sg9eRt^f-W{$F z?qoPH1#gR)$H5?VkDsBg{+-qI^C4R2)n+E^)R*oKT|Rvcv(4;JbDm{IYbXVzs7<%8 z?u*LP)3cL&ZJl@F``^t0=d2pCPMy5d#XN|x4r)FKTxO~ w+~D#-SK)ZY{PSHZfA7Ha1tfc{H~Y`jKP@=!KxT#`0|Nttr>mdKI;Vst0Oo<(!~g&Q literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_up_disabled.png b/src/qt/qdarkstyle/dark/rc/arrow_up_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..48054a8ae9e7f05f9353e37fd033916b6a5bf56c GIT binary patch literal 549 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VoAPZ!6Kh}O4LZ8L-eWe(K;FaLY!poXqhiRLZ7R{|SnFAX@NGUeF8XMP{J52{_$ zyE~_OcJ+3iOJ|QR^m19#&Hhs9MxeUA+VM-C7U!$$+hcN^R{8R;7J0W_ru_T=AA76c z-)o*SWy+NQJu1F?p4^o$&H2J);+^3hZ(sk%)Khk{ie`A!oPwMi3}=}x=u5NaC;pkw z@np}b$_^=oWG)Q`qqI<|*45>k*|h=+PG63wdBC!OX`%y*#wpM2p7?^(m)Vsjlxw@L zUehdh_1S^k+u7W!9FA$dp8j0?*}qi|>q7P|U6p-6V3pR~v&lzREjlov!{+qvsk8T9 zDf`BCV*07m4!j0kt2*9XvI!HI@@#%;!_VM!we5DbH)>{wI20{C<@_M9CVT1DXa9P- zj@TV~^J6FXr;mS^?bmP2+M31YrWV$~Ubym_%=ex*F=>AD=gRD>eS1p#{`cKkCAlv1 zp7ZA1KBHA&%XhQ<^R`b+x1!Shx3!&}TfQ~wM|5M-$9oeK463+{x|!T`W^MVY&mI_h zIcJGJJM;0i*R${MVtJOQBl};jrSw74pA(mE&w2m0q2pamXRpDpz?#k5cJW@g&c)UA zVY9Isd{Ba5@O1TaS?83{ F1OQ)?04x9i literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_up_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_up_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e99960594edd1d0456281c193cec5c17ad540e7c GIT binary patch literal 1074 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE~Gb52v!+?053`o_KF->))F@y02lI|q{m0tc4uAJPdg%My zp5>F7CQLoEhyTONTgn>Sz8^S|y!6qlrG2bdJAIWV?o4=ba%-i)GAYUP3tB(L`|sbl z=~Ld#_cv<96^txz3h$AQQu^T894*XvCZO%azI!jU_irnDcW2l9k3Y2zZ0zj3EB(5E zp8AKt-E+;&*M;;yYuK&(!0SD8?WadaTX)wTeKDKi__5{lw8EJz1^A@zh&J;Yd|xuZ zc~z0k^w>X#4}aM9(Y4{lk2i7|bJY{(-#wS0HesFl^n+avA-RWnL)RVoBrcX;DZBbP zlgs0mi9sirD~>%(Vkn*bzg$IIz%qHaYe3k)(?8>FIEtmqKW8>yba}=aw1X@C(;b&j z3=T^e)7ncXEL?wd(q;Esd{^4inT`Y*FYfxm)$lKi-*`pmlkJLUXNM*)mk&4{X7jgb zb)nTqmxc_jxeS-h8GgMfV>2$Z`21DD!FadJi{#cAor#^>cdeVdEx##D$(H#+F@xjo zxeUA$jDIXsWXk{QQti*tVDRrxxU~XOUyHB~@Yo}%0 zZ)dRD_&woA+{>zm?P1q*Lm9f38og(%IR3V=?fA*t;_co!o7&nA?_HYou;{e5nX`(K zIM3JhwLA&O9(*(Wnai>4-cgI+E)UMlzL~S_n(AqfU{QgYbKY>WzSCu#QIPZQvw41l zV;{5OrgOIK-)w(BYMpIfpA*s2rk#+J^Xud9-B&6NV)_;A&($!`&}Q6mXZOO#z5DD< zR2-gMz1etyc`kFpj+TI>pLd2Qu6i`ztZe0DZST+Z?@TJ)8P^C0H_PxmVSKZ`$RKLZ zgC9*z*3*+FBtG3|RlWP(kzGs?CvX1cnaggFvEBHxFL!y@xa3*r5Aeh ze^%{qRp80!eVU;qYv@~GI^m+rFA-r~p${F2f9&UePyDx|?`xRedV6!5MfKY2>e9dO z)N&AfwxYX!#t&A;B^qbFVZ|*>O$Il#W z@(uw4PGy@XcFfRw(8R&`m352Ikz-yFn~UqaXSS&9zW8QCmT`P(d-c1Y|BKJ`}XDjqy^VL^(+c+ za27k}GRNDwWSdm@7q7K1yOm7?;=lMlG&5k^=5t3Mthk=e4n?sN9`GAR81c)S0h-R8fnUnDII-`BEF{=rgmH*%QfU*vw~tMQhnT%$lz4{-lnqYMlT44$rjF6*2UngA67>hJ&n literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_up_focus@2x.png b/src/qt/qdarkstyle/dark/rc/arrow_up_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f6998104b5dd6e9b760533c616fc819f09084927 GIT binary patch literal 990 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE-x^{);mzLtz*_s|J>`<&tadxMYNZa3#J ztxP;2)y24U*P^ZW-&Qsp-yOZs+ut_(-d@wgy*X2P4>nv%?Op%&YPiC)N#|7}%tS5h zU74!`7XnT<+U*rIKIXG*&kuTo0HDJFlyhTPYi|f#v2%auJYs9 z#g?$9HfDkBh96>EiXQh&jM6$%m44v`v*d*SuZ&BNrp!tEcy9J+@$O1RhuiAl>!k;_KM}lL=1}JuY_f`RM!}`G%O2hSSbm6k zLcYnVJ

by=`!EH8xqL9Jr^f_#?xGJz473iA+IzBSKGZKk~A{$#r>R$+5>z3by}b zEIcCI^z?WyYu%>Ddy;a@S$_PR_v^fK!sl~)I&U4fQD3Dl9-sS8&S75e+g1KzO{|q= jSB&6!0g^KoKa;oV52&@izW6Hx0|SGntDnm{r-UW|r_<3q literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/arrow_up_pressed.png b/src/qt/qdarkstyle/dark/rc/arrow_up_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..22332010697f4eaa2390c2449306c349538772ef GIT binary patch literal 554 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vn7PZ!6Kh}O4L_h$zOiX6AUKRd&VeKnib*427VA(PkwU*>erbzu)IFtQiX{>Q2~ zd-73<*0fj89xYf9vYYiykkpm^4$D_HKT_G^`>ycB=9QVN&SoEZTKjBllT4WqW>&SShLfAalZEU@WW3E6Px^=%gMxV{~>))qT%+2rB}|n zA3yZu)lTM_(wmnTY`o5PST;CbW={OP*_HRb_sz4KpfyGP%+V~i!xC&J(fvFYj}}hT znxg)%(?KhKX4yQ~2MvviHPzSl%;b?Mns>BhTg}4tOf&Bs&OZ0YIDx@ny4axaQ*0irY+w1r9NayB|~EU%P656rW~-*YioLoz({$ z_*wq-7zlHyn3S3rue>_7RccCE#J%36i@o)J(;B0_=FwkCR@-$~8STd!1Kq zseNt5?iZu?PTpqD9QJh#Gd^s(*Ol+Zanfx6X7#kr*I%>plHD6i%JKs8-fA8bVN?5@ zCA;y$pKF{O6YL6C#-06pL#<%bhaUllr1TBWu{Bof-J9l+HGjv_V^PJw?*6&^p5bGB zx6r?ZhC5!YHxthiq1^;>1{`**01WEG=pKK$o;=D22(5R zt>)I}FMISodSCv#z0c?D{C@5`TY!jbARPUR-w@3G{W;fRw+gNX*9VJl^1Jt!IJMvH zbiKUu5u;!oQv!2?9>e+Eva)}lvR^*h{`T6XZwzyCJ{mMIIqmL$(rx>4Ve8MGCuf$u z%1mZ(Qomh0=fLeyyDf{4-~D=`Ci9VY!W!LGw~E+#o_yxN`z!acWP`FPufUwww`!ED zQ*++DZ&|7;f8c=jbNPK+zdcK5C~MDVGGuT(&~@#{(_hxH)$40)K7~*ECB*w+=Jjsr zKdvzh8*I~3<%{B5Io@oLV45CWE?#zij&+T(W^X6!hc6x<1FLz}94!uZF)WZ@?Q*1V zqRDgpq!+tCFW#@d(0C%loHHkNmzc69WUo+R@F}%SI{IRl-|c&bzyD?1Zw*oxDE>BU z>H7!O{u8h9yfWMWMNpzaNGnJ5{`^9td)vZZ#w=ROxP*U>PxQW8(F4K& z)Ry_XcRt#ewmg58XqoZR?G6yFY)cdHLvi@44Fv3{K{o zKT4b^R}ww2;pnr*O~qUcZHJyE^zY8TTa)=HNclZ~>37Db`~I06`1^2{gOH(oM6-fw zRf*@E+E2%lcYgdheX(zt=qs)TcdplSCHRNTknq~{O#7NrYvK3n;`Pfmd}q)9;B8?L|cpqN6wVV6!)_wL@L>eYrUi4k2#>g^T zKybpB+plbTI%M~X8EB^!t|)nSL0+3T-mu}z!Qj1*eg`u+joRGwH4jbsT>I{Hn%cmyB2A{k=OE{?C*;0zb=vsmuFyLVDNPHb6Mw<&;$Sr C@$qE< literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/base_icon.png b/src/qt/qdarkstyle/dark/rc/base_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bb00857a4e170543e97fc60ae991b409ca94fb6d GIT binary patch literal 1256 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 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_closed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_closed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a641a550b67320b67fad7b9e5e6f8672f3b4bf9f GIT binary patch literal 837 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hED0B3Fx$x{|tlCK*1JcbodEXw5-stpo0Y{U#sG}gi7Dto9 z-U{I_3(P<23v6N6jAIGZXv(ndV9)PTP@VPnYDI?jEU{kS^6#&Y-cq?M#Xa|C(`UIV`@IVItM*2ByybXFF-OK{j8eQZ{X^Oq=%ZKHp2m4h^1H-L{3s$3HvY{P#BC6KmJeM>QD%hIwISd&9Mi z*0gR?y`g`^ow;U3sCvSYk9(q56>V8m!XGv5>ztW-+h3j8@yOzzS+D`9z^RZ|7$)o|&_X{h>vJZLd}1`v|9)@QI2SnPl>RnKdl-ReHQK zch>X{jc=2-TvQ2bc)M#cL%&&P%l2;j&FcIDtgDJtiUf;f{#yv!=X_C5uu8oUr|9CE zD)yB1#y?`M92r;B4qMC;or_TEl`67BQD*ZQte?26*qo>Np(z?qxDvFnx?tCZvY1)k?FTvA^V zQov=@+ZH9VWM9LDCsVG7T$~W>{L0ohs`q=$4)5p?|K z`kF(Fr5P6s+LcG_CRH4X>ny*WccmnPR!OrQRc&)t2*;jLG`b&;5*L6icJu`bC!KgDqoN51mf#q+pQ zHnl3fkbMx`()+FS>Cw!#kJ=|9e#Z8OFh;wW&Hj36t!Ljw`w8csU3bWGV0g0Osz&UL zCk+P$*F^s=++xxoprpRm?d6p%J3AY01TZT}=}rE4RN4G2qtm(VFT#2ECRXfNK4sHg gt{*>s{HS4GdOhyobZwDs3=9kmp00i_>zopr04KS?mjD0& literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_closed_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/branch_closed_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..421e8e094f77dcf27757f6e67149f8e5399ca985 GIT binary patch literal 862 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEWJRcu2hOys;c$8e&NzH*h<%Pawp zdWQ>guXGpP>)NR+f2nD!WVg=tAo)WI8&;eV+9G$V>4Z^u-yG}Z>X~utc@Gw^yYSPd zu71P&?{)8Qp4(a8;IuG6LxigpOm+R|Rl0Rx^-EcXK4u1sOrN9Cw_U3B*cP(NWMpV) zdfhhuDfRSCLb=T)?Mvl`0So8N1 zk#!6Vt6%n4u4Z5`axF0u;NbYK-|~UsVune&{>e2)v%m89J$3ml?sQ6a$NhVDo|^Zw z%syxRN|uxqbGjw;rmxN2pcWG$13(of0T<(1S{_gGXWz-c++b-_YP2KJ8 z);@3Vq?zm!HgL~)c=d}JgL;qE(mi{urRubdyH!~k8p1ETGoG>MPr2C^qV&l#jPEoT zgP5K2pC#I{{)?s?r)^$(>{9KI+fh+D%ho5n)b!Y8IZez!fG2J9(UQ40&#ZoVKQ(2; zAC+t6#y_SS>^q#YWtG?E{LXLN_b@Pcl(n&2I?fGLKVW$A-swdQ3=8J)ML)`JT`71z zvDTLTwUOl4?r+=nG~BwCCcagfG2!zZ#^XOjbV3ww-M_^2r*41lt%Ft$8`R^~AFN$j zp`oDMyp+{v!zFJSi%IJRo7gWumiA{huvO7D6_ab7eU9PJshFvI3et+F8r>I({A>_% zzeJ?vIL|-%;w$^Mt5@avq=~&`4aq+HRA!BMLvh$+hgrI4V0EL%wK3MV+s}7?({K5}^eeu9?$I~(&Gj!g`&*WJ z+TQk(bUPA|BAY^k?Jz4Q#t%pA(HNq05(;voHLU)6o3weHGU|?YIboFyt I=akR{053~_8~^|S literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_closed_focus.png b/src/qt/qdarkstyle/dark/rc/branch_closed_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..ccc249a59a715084e9174ce3d7a7eadebea227ca GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|TS2r;B4qMC;qh_WI6=BJJ~wqYqx_$iEPqwENb{BohzqoI`0JI8}tKB5D}xFCAR< zrOeP;gK67ENxs^4mDTH|P7_ld*Twtxs0hJwJJ}Qc+p?@&4qEao%BBCmHw5 z_PrOfW_pN1$JeTK4I8b!dZtsn!xyCa-T1Vi=FIB(>liMqytVSey9Ii#>t?Syu-zq( zd&dvW<)<$`-?!djkMbX9%_1qan^n7$+zXBOm>Dd%yY-=AyInY;k_(}jD1;ygip-ga((5k#`hn7Fim1@lsdq&Z1U^d z3C1T28fxyaHLE|!TO+YI7#KWV{an^LB{Ts5VC1RR literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_closed_focus@2x.png b/src/qt/qdarkstyle/dark/rc/branch_closed_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..88dd0a62b1d340cfb4443a5d9ae85b06fd7fb76e GIT binary patch literal 810 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hETGqZ}0?z~Q(h zQ~b%IGQlnUms~v}`kp0mDCI8fJzo^aqA23>UrbeuOY_IQzfmoQ_49a}zVBP`JGzej z*&NIFcJJm|Hylmc7@;H94W_33=Y3`Np(s)QKrn;Dr#mifdw1D}H(z7o`{q%!&{52* z?T~XFyL;)cb!_ghm#=S+HeB5Erdr|l)?e$GnAbNw~X(~ja(-22F}{ZL%Fr-9_&r0&9QHdb+k2M(JQ~t>gNq@|PT7L-HTT?@j!V~OMSOqwKstNTvr|*& z3mASXNYYJM)$QGQ+Ba~PxyF6pl#ahDW~DvGiaWHOvOcgKuHN-GS)YL+F6F0GLUpTx z&C1)q=W8%9$h5wUsCjIld%Rj>wy0{no%liHyZ1JVZzzv=C3wo9BUhE_>8+IZ%WH1i zUt{w7;(dsB3BN<|N~P_8%a-4EX^Y_g@nF?#hD%3{8Rf3#mgqI~*r=>E{V3bY{#3{% zZ)$J+F3xQ;_Gor3ZCJ*5a)MF7v;QYKXK0mt+I&*y7`F#+r@EIL;}y}~=L;(i*q;ku z_F2Ve*57@+(*&80hNmzd*mD11(@CAvE^!gB66*JxXt{r4ICbvdn@^i-a_h!*6#tT7OCt~ei$6S3E&-#|NVs~Nc&;19L z=9#I@{k-hkul);4#WT)&zkRdl55oi8Z^qJMe*jFE|qZl9TnPu&ix>|Vm%}b?A zm>AAx0ks zbAO9a=Rdy{7U>tc81~rIYu>p%tz9JGrL5FC&K^epw@Zx0wm7foKN9OD>hQ_ow1rji z&iVT}Zyo+6>XX*}St*FUM=<@{qCG`Pm(??ar+n+W+;xRPByyW9pP2Q8xI5C}Pb54R z?W&DCIW@OEnq!5;agzqe2OBJZZIes0h=^%C(7a%K?R;kLACbP0l+XkKa`mz> literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_closed_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_closed_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3849a7ff020677c35f8036ac33660edf3202a81e GIT binary patch literal 867 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE1#w{niRzyce(_b;9y@UI7*Reom=9I4Lf<$M)i^TV9o~*0Bi6Ga9YBo%HbQ`Q7Kv zf4+8}?K&qz!z6iE$zTQs!R&i7HgfNN-F%R@VEua!r?Zax0{wsQQ#=@LFYUDMfcE@q zy_Kt?d#h%>t5rL6xQIjg;KbR>k4a|CcU*mG;qP@FpCCkl zch}sjkA)AqFIM`ilhu9v=8M;giylkzwskGI|2JxhcrX(KgYWlR7L8Rv!&N@ z2HN>>Gep$6Z@BgN+rsR%iHq-LCBLejabj9>NWX4`7=utzp%1Tu$c1E=i@t8QzTf|f zJUsZtS4YIcoY(C(Z`99O@Ae*!zW;@RLE%MyCI1D-=4*lXZe=SmFen5aJ98mcm@(wa z_WZP-U&c~A`W4x;B^=C-_LROqd=t&tL20U1izyd!65sf9&ZK zj|z^~^r+;BD*9ouKt}Fm0k^%4!Uyky=O?#0sp$Sy(7F3p@=L<=m&X^?EKyEjIu#Qa zZPWFeVcXJck_DAF-oF!im}vRKzv1{|5toa;4p%R+-IaS+68mJ`eAai27HZ~k2OiZo zYud~`oA`CnyRZM7UdJvt^K`4Iiy^nd_xy=B+B;T-^_7`$|J*yDcb)JA`HiZKNB-?e zJ21ty^ZJ^phneRvbFhAqV1C8m!z|%!wDJGa|8Kx!>x4kxT;#c)I$ztaD0e0s#E{M1}wW literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_end_disabled.png b/src/qt/qdarkstyle/dark/rc/branch_end_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..bb4344c7854ebb1c449d033cf37ff0096b7f2f23 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGXr;B4qMC;pg2YC+|aIiQw#Yl?=FxAeO6|`WklAh4~x&P;0^AU)Yja*x^!{{F~ zBa46o10zchyUy1KaknR$3V)EPKigl#$iVQdmS-EM|E9ugJPZsB44$rjF6*2UngCj{ BENlP( literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_end_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/branch_end_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8feb46d464beb9de0fa1d27a2e4ae1435bfd6b91 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEgRH+|*7zpk;!?X)S|Gvc1PM}<<(5TwpDN8W?%?-%UI&V_1CdhVJ-s$1B0ilpUXO@geCyljVliT literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_end_focus@2x.png b/src/qt/qdarkstyle/dark/rc/branch_end_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd0e4ba33f340e999a7985715a0d2b7f84e5510 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE|NN$MYV zCJu!L1||*FVdQ&MBb@0MB(U AXaE2J literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_end_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_end_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5c4fabf6dbdd4257b2d83b14c2885426f5e0db GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEPFugh9Bb1?no$`T;Ke>s%+;&z5f4= z3||{&k%4c0WL)>D;;*Tl+kd8eKkOJFV9o>PTkF~T7OWR#0SS1z`njxgN@xNA^KVS6 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_line.png b/src/qt/qdarkstyle/dark/rc/branch_line.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8c72ab63678bd9a5f3d29818a1f71d129a7e30 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGZr;B4qMC;pg2YDF`IG7EuoV+QLI+>5r|Gxdi)ndMvCVzSMIQN)1BLfPkiC@mv TI4v{cJxJ8k)z4*}Q$iB}(pe%G literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_line@2x.png b/src/qt/qdarkstyle/dark/rc/branch_line@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f07af31dd1a465d042de5981b7d531b1f68780 GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE-vU^r~Rm#=Yv>7Q;x&xZ`2HQNmrY&{?QJLaar(;xg+4(u7S z3z)a?U0{r2f5EVpxuoG5qm{#J2H6Fr4SW}9CT%0QE~3yZJ#5H-mHAH^6c^3J^D-xDB#DM VN>=9kVTLC`qMojPF6*2UngC>-vU^r~R7retwNkQ30iurXePsZEg>vrL0K9>KQ`7SU60S&FfcGMc)I$ztaD0e0su!J BN>Bg* literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_line_pressed.png b/src/qt/qdarkstyle/dark/rc/branch_line_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..3ca15c5d0b97a1acc143844169b21a2428a8bc62 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGlr;B4qMC;pghJp+R94wA%vjkdsbRJkJEx7agf4Z_*s&Be)zTLgF8bJmWaDd&? Vo_VIFwVFIg*wfX|Wt~$(69AY^9*Y0~ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_line_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_line_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3685531020c5d683c3ca9d5b394d006431b5cc44 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE-vU^r~R=UZ`zzs=FD!i4SGZHWuFp0BH2moua254-FF<}G{| z7^B!`Me BFWvwE literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_more@2x.png b/src/qt/qdarkstyle/dark/rc/branch_more@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1ab07d0456f6d92c406a4e953677a316498ea1 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEgflQOFnGH9xvX}6nJVDNPHb6Mw< G&;$VCsxY_! literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_more_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/branch_more_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aba830362c3072046a2dcba5304ffa389101a128 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE^ihK4m!E0~Tn_FR5)R^rCVC;#5^Jh52+++w}E zRn3!+^$QrH9D*5i7icz!T@Z2L&fr?WYQlPfX%#fB10E2 p#^!#rZsBiM0-A70Z?0{S7f++J z%V?~e)b7e5V_~ekzcJ=4vmDc6K4gVFJD3@EPUe{Fu6ymdKI;Vst0KQZ% A5C8xG literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_more_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_more_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f18f83415213205e3c9069f9ae6a74662b26efa GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hETi2Z@yug>GrveGSC0YJ^$;~ z?ko47oofNB3F`%>Sxgy>zKmNMmN7&*1T*L^&}#HQ_Kb?I(l%uT>m3o@ePiVPIfj@O1TaS?83{1OR-nRp$Tz literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_open.png b/src/qt/qdarkstyle/dark/rc/branch_open.png new file mode 100644 index 0000000000000000000000000000000000000000..fdf0f8b43db3ae12a28d8ce17885235ba0c30c58 GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|TR{r;B4qMC;p&`@NVQC0IWEG+W}S*tEcR(>+#shmN^(Ljx{zhHVV}Ae)n;Q^Uf^ zp{cWm#W9D)b%TfUjjG?z;|>&b^gfU1Xmu*u8PfDydwSxGr_4`0ZdBq<{T=I2UM?pxK=(dTQ8+5`usUi|-n7bwV*}Tzn81An z4xua8IhlQKgx;@SfyuRJFfM-2RDC_2w)VP1wU*Ta9g#pG{Ro|dD?RO9bJxYU3Y#*o^_)f(~3{Acj9v;axZ3-sGZrf zkUzomSgF3?3h{=A+P2Px4{MYr&d`nh^LM87Zq^TPLzBMU_;|xqDT>27{U#d&LsWY7 zj31T_vo4jg1zl~klI=dK#;7pYFZ}wIcRTnWG_7Z4t}#uFw0(Li;u<4E!?h~=$yK}y z&V@@Ea_Ii7sXNpW^3|~5O!$1&Wt+FrsN$Z1d_Ucu&Szm{@HBowvd5=fx*+&&t;ucLK6Vx;bEfy literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_open_disabled.png b/src/qt/qdarkstyle/dark/rc/branch_open_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..8328e84d72d7c6572d7cbd8711be7c825b21fb4f GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|R4(r;B4qMC;p2hWgHd630INw-jaW6mZ%lIJ09=hhL-t2Pf$-UoEk`}l0gr1w*SDyQ<#;$XE)0+Q&Gnp3d*v!kL z9Us)%{N--Gm$I?;-nav2ne>nT`DUVUKXq&6!Y$0ri@v5>JnNbL>ERONH>NvP6GWC= zo?_0o;?*{hE*X#68GY(P=l+!6?7VqY^P{Ev3&ATlcRzRi@vy3)A=BaMz9-8jU95Tf za;vCBu)u41iAkRhfBpG9Mq}TWMIw<4Bu|vRn7(uI-@E3)`#hy_>V9JzUJ&mX}znuWaWvx=>ka` zm)&;rv5^qYU-r?hX<|X9(|;8f-;ibX78)<6sZCkZ;dW}RT*E95MK^(i6D|aOtKCy@ zgU@w?@$QxnHGQAY{Q35M-{#Gm6M77fNhHIF8OK{&cyG+8-hNK|7+=>0mLGdA-2W`O z;Nj}CdQ&rRYb~l~5cs*^!u47cpSTyi9;u&|5B!>RLO*LycIEx=`K@R9CWHjvKEC3e zo@LqJS5EI|UXG2uT+I8`>3R@vO2+5=>z@5S60K{xaPxZ)6{}T2H*3-pJ~p)MYg}mV zFeUcDeB-`_`A3pJUgVv5?fKzn>P7GEMdM3e8hnULFj3vH{qUXIjt7Da9?w7NTOAK< z6m9%q@3OZ|o^98$XOnhoUf#Du<6U&)uLCc%R^{{Ye(5{6^NZ|5dBz0~zW)*XT%udB z=*x~n#eR1>QX zwYS?3>M|@o+o|Y zcI+Vc^!yO!_0xM?79>{2{{8bTxA(BJvhw#DU$xnvtOfZP{m)5oH2eD;-6mssr`q<^ zxru++&Zx~jxqbD8lXqv=WK?G<+d7M`Klm&2d3Rm-`Dk{Y`~P!nUmq>;RTbkG+|T;&^pPJgS6&ahT4%fR z^EAfwcOGwIAVd z>uaiZD}C%*bVe+7;|19z@AmdLG9G<>&-YxqjjgTi@?r&!CWRmGr-+`&pE_N)bn3+; zu8!vWHP7bnKKsq;k*4f5g-QEQyG5qD`8uS_+I0$lPkUN?``xBmwl4t-Ew$%cDrjXh z-C&Vw{r>pKzI8P^_o=)Gj${Jj6G8J8zl`K>qQi(`4!dcCOg`38I2_&F6( zpY$#;#OY7FQf|8F_?mxb>^}tRedMWlnY$z0oB!gKr?yXbEZ(GG!rfpyUu@CNHM6gq zFevPQtQfwB(S+f6hte{6jmBk{n!;ASTwTTBu;*o->pkYEd;MJ=i(hu|t$MpElfhxn z>$0ge+;=2-=ZcraW{1Dcsr}pID8O=X{%0;;?IP9*U*0z{FfcH9y85}Sb4q9e0Nr}3 Aga7~l literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_open_focus@2x.png b/src/qt/qdarkstyle/dark/rc/branch_open_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b38e17a33ce26a234a77a1ff487304352e780deb GIT binary patch literal 791 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEJX|l__CLDo3d1T<2ANMD zs~W!-ojhI3aPom+gRi|%>F3isHvg||x?gnmoRZ~g>eFPYiY@;0GzcZ}inR+j1jj!pan>j_NcW=3}G>iE` zvnxq4Fnm${Q5eX%opIOHPz5i~uSaZU=VgZJtkmsW9LJd&$-1zo`>S9M+pWjMOfZExZ9-NvPVq*8ZZz(lI=sJ9mVqIpEGzcG3%-V>3oj)IMjD&- zDQ=ILE3mEY)ncLYrP42-Zr;C#pMl}j?a*htc5x?s<>}{fymRsXi4eQrOiF)5f6Vo1 z%CDI(&1o~^;5WzR9aCF(*aR$KWN=VB`0%{lcHv$BR@(~A`=z(~*Q=kK0%}E{aHdR@ z@MqIiigudncRW2fzDc4b7*i$LkfoPujG3mVtGuY1l05Lmj<$*Q6|6 zwzJ$=xpHM>M1-cQw5!s(MQd`W52TsHCj{XQh% zz$Rnugc&Q6&YV6M6B=}Dx<~mBp;OIOpNfJHFIW`-w!gb?5##ZfJHyw% ztqTe8c97k0G1*#kg8upRTX{~J+Zqi#{ylwYSG3XYx5O3sAMAFUAImdKI;Vst0I|2Y=l}o! literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/branch_open_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/branch_open_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0e43e8b733a90f3835db0d458e9eade622aab3e7 GIT binary patch literal 860 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEwa>3M?cbyC zP_q6&?)8_a8&4hh(00u^d(W}!@2&ULdL zc-=+a(B+kDw(D-6ai?I-;xLs0z8f#3d=)-j%P23ZFx+{x<_DL%(_FH1c{$e{rd3_%MI{}Yql?_5-~YUMbNc;;R+pr?hAz7b zbR!>L>H5=EUT?E4JL{jU7VpP1$GP6V({Z)F?sui`!u|i>*4(%C-p0^yVxEt1-#2E( z>lrsz7Hmu5-`>l7CEuG>K0fra@`Xpc{8%ghd--qL93tzzi=n|oX)ohbn}Fz=bp^6Z zIknz*Ot$a+H0$*>P4|-OZNCpVX#SpB!^rUP#`IF9bL9tiweNZAcQCQ|-HCtROW&}j zMlm>8T-zL^QqNZL)$zJ!%yowcXJf)&_ZEHm^fms0W1Xz^^!0Jlf7K#HS217Hub5aM zIJeIB`rmu{PhW*@^FLr8qSRT!HFZjMK~?0{Gv_AuHSeFk`K*vmf}gX}-Q}nB92(EN zhxgaJR97di{H4=*EM(Q9jZa@6pSG(VH6?cZ5Z)DV|6q3LPEdAX@O1TaS?83{1OVeY BpsWA@ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_checked.png b/src/qt/qdarkstyle/dark/rc/checkbox_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..3687e56c00abd9949171f28c831d56737ae1f14f GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|S$dr;B4qMC;q>w%HqCa;?J{O_5?SrTpA*DYS5b3(4*@`C zXYKv}R(kf~4B5G!6PXh@71(xKzmqi1Gwcqzy23Di(xb^*<_zL(`hjxaSz71rXG&PB zyK>WQ>8pzme6~9$o6z!g`l4N$N`bdNubgi1HmrX`o%V<3Un=?&UOB|nutpf3XxzGO z%9^uDe~&QKMg>hgzbY$jt6ku)a)%p^H{WyFY)t&&MP!?{K&(_B@fU7CB7I_y+57O#H)Hy`=khag zs54v-44Ef>Aau3pd)?)pYl>Oe*1DY7rBH49JY{3RihnO3rUh@l8M7~I>#3$a%u3B+ zleQ){d$!6*Pqpin^ARd_GcMV>yLzr~6+%!_x~AwW)kfzNo8PQVDNPHb6Mw< G&;$S}iXKe> literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_checked@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_checked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a6b1afebb28e00f68002787be4863dd9d1353e GIT binary patch literal 1238 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEvYr!F<*U!y5+qfcV;;d-@i4ES~`U;GT*8URQ z5irq1MNw$W6z-a)uq>8U8q>A*vMiZ;E4#{ZLyXzETleG+HOj4Kxvk&+j${4xb$dVl z@SpY9v--oC8=rsOd@kF+Rx;t#6wTw3r!K8Hyk_g0gQ{x(I1Vs1TxN*VH`#RZCi@4G z17?PIZ<|W-i*@eVGC7EKL(cD5roRjibU7WTc}_n#e`edq*Qcd4Jw?y>)El`=%W*qIm2 zz2VRU{x;X|p@(*@du?60KDL_u&5n0-q&_IK#WQ|5_M!Z0y3MaUzN zx~JLC>s)bb;9UEE`I@?HMF-Jq;vSXa1v1Zl=WlF!c%;Q)e+AdI+h^1CPyf`tzW1DJ zbo_+djJDTvfA<_`SeIlGp8i49^ntteI_v3Gb*|UMpNKhdZ)ke5^H;y@GneV1nYE62 zj85xU7?wuND4lbD@~hPnUl&g?;J6fZzVMuj_v&r?9NHMZ2fy;q=(+tcWJU8=)}5>Y z2ktXjR7B3s(7JN)SJNFPiMETXhr(a##xHS-U86t2i0zHp?Cla2lPa}s7!>!;2YhTx=c(SgoHXWRM*o)gXxK2XeXo^#7f%~LiAX$H8X3EP<`sq4%T~T;Jmbx~ zw!$cPmerYUJBuqezS`Ay`xzUUZ~slV-+4w;9z@Kkj{znPs0}vu#EG*Lypk z&wF2ef9Lda{Xg#~JUVby`eUBUJEmBNUcE_vHZ=iI*i<5%HTSq%$;PTn|?dM`lOF!LU zowA|s{3ermUQ2zJ{uC8YTpAjC=-0$MZ?2@7$_HFzY~Lf95q5QEhK`_Khjr6ey+3(} z*^*Tz`=}{1XurN~8Xdotq1CXF^Ly+C?bEMsZ`T!k$Z>7=iW^Pu&Rz3#owmoYku$Wm zV#b~MUqiV)mIfW$WWx7ms^{n2+N(?qVrk3GTvN7O*>UJZlmF{lPKF%?%bo@nYV)1Q z-h6L+gV5R)H>>V5Jy;-mYz6Nw)?KMRx3)&TKlJ^5MWNnjHjZ$gH9~RhWe*=PNQQh& z`tpU}#H!!AUT6bb!ly5C(-}Cg?%ry@W8;0@0AJ-x?I$XZ_;oz{{@gZwhw{SZ^$P-> zzV2OQ!@#rZWs^pJ(vd#?Zm(Gk{93LC8jE+nxl(Ih@FH!?$ETOQqL1Hnb(z&LnWfzN p7UR8zvreQM>oc$V+5bR%JwNA)$BzphGB7YOc)I$ztaD0e0suH$Q0@Q# literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_checked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0c8c28a245d8e611165f6719580fa9fd9e382d86 GIT binary patch literal 1334 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 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed.png b/src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..f104bb240315fcdd6104f7d5dfbab95df3538510 GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Qf$r;B4qMC;S(=lz5eMUK{g&)%(M7zvwt!u=L6%N8-BdPDpI;Mx-9g3fzsJO#n|pq;cu#%#$m`QdP3GF< z^LgDfwjbbknY=J)=ZD0%56kUC^84)e263^r1)OA>F0k{lir^Y6L1SKyMJMhkW`hL~HWEyvLRxX1q!?ua{+^)}XbM^OF+9P`5 zd0)lq4`&^oY|v)p*<~4;_P?t!Lq|NUWL?`mt#2~=@p~FKFSa*Kl~kR(ZC32PF9K%P zS0^4`*RrTN&u{8+>(!Hgulz%*2J&)l=$a*y{xkCVFyp9mj| zY^He?`#k&OyH5wtcG!`b++DCf#XTTW;qR_W-9?YN=Zb3Xn`gElhk1%q_PT_yKs=6*+&uo%C6Umnl<&sWE&S;VOCcVN*e1_lNOPgg&e IbxsLQ0I9Y)g8%>k literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_checked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bb972d68f3d57671c07a7ed11b38a599a4fcb6dc GIT binary patch literal 1319 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEX*F>O<0Qnvohgd%Rz`+vUsZvHu~fP6#g9m-Fk) z`m2wYXf0om@!i9Ifq(wCZgvKyZ;Zdb%-QVjmt( z;966gQD%pQ-b(k@I)75XY@=89vPbCWp9h-Q6eWQ=~7wH%yWvmse!J@CK*o^BJo{F0eUN zuu<|}A{+c_cT6{wk zS6yWMgIA{~v<7`R`->@@6=csYrFxD7Ig^g=(K{{wGqtwy_4>ox_2=$W&$jS*pviEa z(MJ8llr;|*T=h@Odvx+o!FF7p>W=If=8y?@>>9Z!=!e_yv#)z9+54togJ8?;6#y=C2w^u|mYm7TTyidtI+*8O_1j@{p zZtPli+BjmWX{OeR%TG-s?Kk~9pP#d9kHRh6Pxg@pi~>9A&1%2xxw)_Fal@Ob{^x~v z+~2#!rg7%WJ2|_)ul8b`CgyAS<>6LSi`nd}yO)`5$l-e%F}qauKx%PBLc+Rvsl~if eCO2;VVg9l9({CwHvug|t3=E#GelF{r5}E*s@^CW% literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate.png b/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate.png new file mode 100644 index 0000000000000000000000000000000000000000..8159551deae3ee04044e37873b47fa5795b08a65 GIT binary patch literal 481 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vn^PZ!6Kh}O5${rwIF2prpADO$E;f`;_JrPCW+9EwZ?MUm43IQR# zge0c+4^zW;F)r#%WY0X_%F3&&>cOq{Eqb5%%=go0o;)r6V1M^B{wYE2dM~7Uv^aiG z++onBu!Z%8##AqTZpM`ByHpOv3PiXRbry!|iNCL9SnnmvdBM1WpY3|E(-yAQL)9Yd z_QvJsKiXx=WXkY{>%+$y)da28nOfaTgO&%*VDr=}P1EZ3O*LJfo>X>v1(SnUM_3F) zrtjyX;-mZzcw<6R`Gf4{*MC04_lF@mh-m^tj%-4Dq{H=1=VtyCTW}_8Wu=RY`O~D2 znmSrrn1W8p7|Vs5vooABSgg48%wMSlVJ_ASrF;EbxEtJ8FMlQ|_-fa>?}rynJJ)di z@CCbdi}&AcVo_kcp~H~OQB$k%*l2UE_3N3ue;8WK7<^*3i-{k&QMl*Mm6`L-$|*6L z#a!TQlnT=H%8q*dn}7SfoZIL6WS6@wU}spzAbolFf}=+qYBq1IFr1mSZC0bUef|2^ io$L&yO<|i|=5suma7tbMt}X)u1B0ilpUXO@geCyrbHHB! literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..75864b46d895c8ec3244738bfdbf1a027a5b5c29 GIT binary patch literal 919 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hESX+VS86tf8(tYy2+PX{I_w(;%Vef?42j@{eU%dK~tKRA2&?3+7xjQ8K3 zJNE!jf`LSpWY+SFe8u;sJ&jbW<49mSz|fFAb5`j&$p&SH-AA^(>paN+y+cd9_QfHF z7)^PB7rG76njU47nc3{iT7LXk@3u2ce8x<#eeo(6%+}p|z?d+_;r6^K-DmE6YR{8w zu(63rIo6$XXBX#QouB_MPYZvnCB6M`*^*x^Gv_@GxGUoH!zIM`YOrA1wk1 zDNm|@&AR!>;+$dgw5HOF8yP=Ne&DjhvD7$q`?`sbU%4&G+OyL4%yYITR>hY2%RX}SK^%pit&&+oE)hznJ+{Ic%h1c{{#9iPe>cdfhBu4Mj-@8rv$o&lN+ z&rYQ?EZ5wr@^A}SMb7PioFAIJD$ZgSQE+ zUNv{=Cccb4{ZsFsv@)2y0Ke;f7z|6(4>B1?#};|cmH56nWA+Y)z9v@9R7KyFc|wol z`nGj)Czwa9I5^8Mc-8DHCuVhqymh^8!s_7jdZE$BO|N(T)!d!h_j=b~mO8mL-F>_r zoCk!P2cZ+e!pvQ-rB2&lNa%5iu5vU>~?zM;C+x2#O2 xKDlwn;??eT`j0p6G-}xE*LPNur|sS|{?ZmHcjK7+2nGfQ22WQ%mvv4FO#s4YqI&=U literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png b/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..181625a000a24b0e60542115c779527f560cca22 GIT binary patch literal 545 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Vn_PZ!6Kh}O5$H)aP1iX5wtk9(;ky5-0}Mp-ZSSRD<$%2xuMA#vB0p1f3;u`=X8 zi?M~o!J{b`_*|!OwDL$jQdm)X(Rcg1+`tJBf=<}-?Gv9L6xUgs>H69C``l`a`|s}+ zSKi_Nzxzw|gFjC{NiLavKxV@E6Y0_s$JgA-GmBGK-}9the#-Qgutv!T9&XQEwx&&3 z=W~AEuWcV+{=HqXXg~A6Lt8f&y%YT)y4ma8;;(-^AA5_v6Bj>qJhopch}WX)=FSTB zW4~0+=`tT$b1Ba(Y?DEssBX$pey5Wa5?gn$Oz?hkmhp*AROBr6)V*_ee0ymzjpc-T zM*E_3o89Lxe%N`JfzMUBLGZvr=AO4x3lw)$-JN+?%!eoF#)8?C^Y&K!dQcY?_li%% z>*17{ccrh$I2a_RZFSO|^DDWbIY7%HeeFKYmu-&a7Y?z-dQLqTRcox9f8JQ&tHIX( z-xu%SZ4x}d@n8Ytwui@Aiz3ome;z%Vv16?w%g*{XZMsa*Ig|k zpPK`&-Of~fSMWP1v92)aUPa)s*aL}SZ=F?z|1Q|05y*bLoELRX_V*Sg+FVDVE`Yb8i z&kKKKmXvIH({!g)xYy0r^~X0!w)rZ{vK2~Z%%9x2;qLQ*WCw)_7xr3n%P0JL##s>< zcjQ5d)y@Z9RqdQ^Npt1&gGrO*?_;C9p_4d-OJgdvtzC{(k;aPF(VeXcj`y_L=Tz?by zmM24d3gaf$6K;|U(G5A+nI-C7Eo^!%2j@jI$RCmVpDob9xQAUbeA&D^=hw{I%XKK< zVaNYRl^edvJa8_k|FGiEvBVAEZ0^*5+>>Fb$jnshY|V2aHc;?&>%zO7UwGdNtW-=n zAa=L9ry*C#^vHv^(IxKac%~&}Ex1*^!5T2^uL_TYj3H5F@lw zk?G)$DRX6hY6dy~5I)hfRIZ^%nBiVxWoMBz+Y8$h7851CZ3T3nov>T5NsfE{Nuz+t z3vw7Y1+twGQ;<$=z|QntlalAM_@dkMPID8pTi(}XteLr3AXtq5#gr|PL-UxllGw3bons`H5;?-oiC#dgkG1#&D+hQywQ(|e|GY+kC$zBdhyGGS>)or7yjJ; z$6Q>EL7>>ic;2qW?`z%(eK-7Gwrut8mXIHiJ6lLb-;KwK1c{g7RI#rX~*KqID%GbQ*xqS`idG=&JyEVsYVMhKx1~w6C V0mr!!91IK$44$rjF6*2UngGV}zH$Hn literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png b/src/qt/qdarkstyle/dark/rc/checkbox_indeterminate_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..d7b19f61ad27439c20b676074f86faacae79fb52 GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|R4=r;B4qMC;q>XT6jiMOyb?-gULr=$G0{o-X|fi7d=^EeT;s&ji()xRrOv-{HOS zKuO;~VOg!PD7#Ab?=y$iDR|}>mX#c^Tm9(T(sSYVBHs_CPj_SfYP>#mNAC*meNz&X zb{zepeC4Hi=|>%hITidh2ApeDQX_t62Dc|O6h12bApbyawW#fd-FL3tH;UQ+?^}?W zJM&I%om00s)D7h)<-GUiSUuIOG^(vIVBf^cQAwQtPZdc2;1l58>>{gBwIF=i&yFev zp+XKG#zW28uWzWo%ogIPzR{BiMmKi&^=S}Y#srM+9Zd6q>~H(d2HFO8k@<&pG>_ZvRQ-Cy+o zH{$3Ab!Y_uKGQE+E2Oi%t%jDp(U&K+`vtO}1yOZ_H zyekFyLHj+IO>g`94if+0&+<(_Z{J_|-ABxmRX|{$l_5q^0c@ TXZTMB1_lOCS3j3^P61#f#s+U3+O>b+yB}&2zucoA>YD zecSlV^Nj6>H%^{-Hssa3tJ8`)jYYMZn@Tj_h~JpHWk*%O55*6W7k`SZY@ey)A1^@dx<* zIMls+bCHUTVHj^?QKvD>@jutMocj58l8wVg|1gh}0s)^|t@qqv3Xu$0X!JsV^@$s^ zn`%1a(>96xPH_!6_Ge>3oLd6hrIZf1eH-c^7hL ziwWMkeYjMq%Aufr`_;7HRUFyW{T2FmcT-+ZwL@M|dtfc2jN;EHANMU5zAC=cQ`Ri^%!!6`ns?P- z)CLRoD!tfyPV;X1rM8KTk``=l3^NZ;*gLPS?dHeH3nntAR&dvJdwMI^d^R!ZnaIff zchjm9tdq@r0-hXl+P`MjmP8wtXIw^o9{L*&yjRuAG@Ewt-p;0;*=Ay=?G8lu_g+tt z-r;#+8^di2<{a(~y~YQyG8JS3emvCY_sQ5*S@cMCjqMz17x_uQ-ssn#Dp07)JgeyR zyJ&}>3;%_m4heIEKc32xTWRXYuKa7=D!)>NuNUIQu4ezt%1J-plu9=fBzU zhi&I^t6%XkGZ+LUb-$fHyTaY{J7Y0xo|4h5Ijfc}P*6U)`Od1)#Ld%}yX(q8!>+vI=OQT7b4_(cb&WVvaoeiM{hs5YCuv`NJi1fsEp$^|>kh|1<`TR5p2r|H~DVR@a-_f8(@?)UXjY{MLBC zW7fj3-9T>vexvfr(B3fbwttV>A)tlCJN?1Awm}X0#PPIR9*Frw1FHMKB zEFhLOj!7bK>I4>!t+zz&AMQ15ay#lavEcZf$ma)sZhdS1^!f9p#?nV0*ELq3a!F7s zc+Yh3HdoTjOVY0P3=gf>-4%KAcm3Hn;_H>p%X%!~Htw3n*1+5%x>e}qp)&`V9(OEv zD9wKAGC}8pOv2k`3TdU;PmipAan1O_mkXQw4?lUIchDt4$smq#A>%jJqL2+g9{t+V z`)EtNgC$c&E7QtA&JsNThARYwbylG@96z9yfoSD(({ X+}3VCXTg641_lOCS3j3^P6 zKl}Op`~Lsl?(dWCaBGNkz2;G!6!P->Yxmu(U)e5rDCi$>Wyo6+8NEq{dCTDkqP#Os z>G7Pcd-akt{>wsc-VfV&!y79Fj+D>2I8##MhC;?%ZDoJ^In$TV4Q|@AZ(-hnh&@?z z*%_F;7?VH7-G0E`@c3Rv_#W=Kct>-N^_P_OCtqk*dVlHT_5;7qZwr6hbZ^^3tpgET zTE06}tZdEP_vFA{Q{&GXk9LGHN=Yq?oxSs5lJoN@gDS=+?&%p<%ho&hFix%8|L^th zwO>~ppZDRSsM)M($E=#qd6&=Yy2e=Ua$W6UMTJ;$g7R{MkTh9|1GPw*LRw ze3M-K)N{-SE=8nY5H*{{@Mi8&4h`E|x+}InJ0_99&>P6uRR8zxWcil@v;06t@_d_} zY*^de%c%Z&kEWu}=X0k|^Q`MIOV1O2u<_XqpXQj9ys0ufw$BlprkS(l{& ztC*g<#h*?3t>NnH#bQp^nNu5b7&is7oe)!y#?HLksU&wlz?37OV@Eg3|7?K<#;D|H z&l@k6y?#Hz&3`P8q6u&6MBsturd#*mF47_nD`vO>sNhq@9{4L$n z(!%F!*wZ-K*dn~$h2M8+K@OkXoHx7nwH$x8;jDwg%;aLO)<;#J#m(2tt(jstn}dOY Ofx*+&&t;ucLK6U6jKc*0 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_unchecked.png b/src/qt/qdarkstyle/dark/rc/checkbox_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..e363ed6200510a57a017a3e012489733586ffa18 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|TS6r;B4qMC;q>d;JatNI0B#U(hp+b-UYSy;{b32VCwoE?=?P>I9$vL1PKw`3>SP zikO$==v7_^w!#ndK7Lbsz9n`a|3B*>yBWtn+MZ&*z|X@Tyc563>w>t}j)I(7cueO!CqZ+m&*``=L2Pcq3q z+iw=Bag}rYJv=?5=I)Jbj+|E$n1Afse=GMg{v-))0t2{ z0XK);H;dFtUCyL!ew}uDCIjE0AJNeXg2(k&*)VE4P2r!ge|h8V{X2`x3@s#gG&5iO{q|RP%9mSy|FZX`&O25evD2k) zuROKHx?`6XRSG?^aB=ha!hPXlMqxd3qq3lgL!Lv*Qe(OQuPn|zbp1Xzo5Azrr=OV) zam+7v8*M$C*#6+o-GvKX1s_Iwrb}(uwykWl^~KM82Yj5LnD+Ox|E|_|b9b+I*LBN# z{5Zbuwe5lBjZ1kt@&z;}t%=!rrQX3MNkNuFj=@9P+xTv$+=Lpjt-?y>2l`|3q7>%$ zTxbkPi!CpBx##T_t_f3O@?HzJ<};RDfAnDTl-G59&)Ru3K#q=o`hLZ{O2)dTslQLA z6fK{4XuZ_=&%YElmNIQ$z0m3T+8=u#G#iTT*%+edf2ig`VBEIoj|>xh)XE(yQ(Jy{ zKmFulpr68UqVTcS<6X_(yce#E#FT&FZt&4{xR%&(;zXuhSoGgB^V>Tn9C?+gVkUEj zQ_^A4{U1$t-8!?y(s)_en_eq2pE2JP_Iveio;2RT{Pho&3(js}%iz9nOlpCygLHPo zHiq0ajJKG!Y@~vq+8q^EnYlG$6StY4SaWdA+m?dKQx*j5ZhVtFXUnsMYYG$IKBx*= z{KV}o+d+wwyVAI#1ScsqZM^J}YCJ>us>aTwn5DM&=jXKSNPF<}pYx2lkCjdzoWnhP zspFf?MN|Bi2IXEgnRzx%_C#+fhtSo4+OwDX9?J;LSOj`5`YbPwZsK@AmTOwcQ~uNh;N=)9qv<;yn27R>pll!15u!_l%Cr zoA+nunHm*8ybxkGzg}m8dB*;QE13@d^yc@S8FKuYTHo)t$%k3kql$9)Ht~j-DQ>zW m*{^@y*ercx#5(hOhJp=3Wew9_bTcq8FnGH9xvXJ6D{E~(z|#?6XS7nhk3n2xVadJtdGE>@rdDlE>)FHA6DcOOII(_`=TEJx zRl9p4c|>YlvtG_Oc*&aV!*J%42D=3BZ{caJYzE>cKVJRaw@6OlY2dy_2PKhweg^f; z=KnQU86Ns*cVPYzCY=K?lprgxe%bXJ+{xM-dv3M$&uzOn9`ZRXccFOUt9Gz lbc&|a3XlA1)6G9w4y&f=Kke7HWnf@n@O1TaS?83{1OUa=nx+5% literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9c80ad75a564587acf3f9c57d3ad56067ff535d1 GIT binary patch literal 868 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEs$OgOEA-4`d#`i+wc3nRqxyT{q9ql z14$cWQYvP-K8(EI!g|7wPh(AzkNXTq5x;U4e!KU@R--o-53p0{> zn)p)}+6vB$imv;A^S$>ho;IbA?keewUn(3G<<_T)*@fwtF+YsZQP^))cfk5{(;nvM zzfKipE$>@&es1-|Ck@=?%r5#24JS6fezEFjQpp+iyUl%qQ}%vf`LyTiB=&}>Pp|OF z?$cmpX%2cJV|G1MB4E!en@vY^?@wBjcCVIcf-bAZR^9_AZTT4lCYGA~pZQ-p=*+?7 z6EP3c4=gZO*ci<<2a*;fK`f$Q9=^-OWTg`xlw^F*{HEk+J*sHpT_# zxw#A;Uv~=DRlL{Rv;X5uv6EdVtUB+etyU7<)yJVHe!k|yjCucmr9PCbc{Oi!Y0rr| zef8a+8xox+qhJH+eBCh9Cg)}CzT{n=HP}<75Manv?ach)^{^|w6JyQ)gniZNI zkjpp_GO(ccOfwQE#WJv`?)~Zi z>6P=gGR8lhOb!ej42%j4EDa0-3}%een$oVeMXmkS9m}v%@txn@b*E}-%X>WbGg@5l zT`=+FWGw|Ne!DYII0MR;6$bv7@_Dy8dyV&l=1_ykX^H#fs(G$_XPfMFa&2{&P0adp oYu|p3&ua9To4H5!Y?B>h#>Ra88b@_I1_lNOPgg&ebxsLQ0J~P87XSbN literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab217356ec7678b69022302d17ae5d1521590d4 GIT binary patch literal 850 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEQMXw(-|B~ zXL%e-*IBtyLB&KT$@iTR`xVVDP7Q9DC@B3)UAJ0l{)7%#CDuM?y2+ci(&muXK`r-!_94mPWg;m z?oPQRRj5#qwOW3@biEtuD^Mm*-(AePW;d?2d9^c+Jr<27ms3a2}K z{L+5q2V3j60G{WIbBkQo3H{K$Ix*Dw+`B~kIeptsGVY$*uy?{bli+~q9xXSb`#Sd) zcz)^VKHaGCH$zl8R4|;m>e>gE#&d;D-VbMWFdp~RVbb`{_WMfC`Eb)ap%pt;ggF{F zE{$0zIbC|g<>Pw}th_wK!E682vuiT8D6VTha;D2|<^{gSkV?rpebNg%?@u@~&-B0Z znJpe-SJ+n?!a3R^lB#a z!KfwQpT*nBvxY?X$F@o*FbXOCn&-9m6z2+V5tl8$U&Y^j%eZQ-qw_@dmgyZe#gDcx zUpXZ|_?w&R?57e>YjiJl>~Hzn>0)(2sk^A5^Zq=yC$k-<1iw8}oc(;Rl*bI$pL$M; zSI++5%3cs;{W)Lhkc@^L(;rWs0}OCf#`yW{ThrSs9x-foZeX~gTfI0a>}hI#h)@A* zlkI`1CF~+O(;n*xq>J+}H#=>Zu-@g@$3L%=9`U{leJa)=a_BAVr|W@71q&E|zeo~V z{)qRr<<)cFUd8y>{ZC9|I_R}ze#}`PJBH;oc}BPQrnoXNFfe$!`njxgN@xNAp6;t% literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/checkbox_unchecked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2b0515e788fefaf0759f9e721aaf56df382db3 GIT binary patch literal 862 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE`*ctJ`?tJzj67_I zQ{8S!iumfZtZn?~$@HD^9-9Hz0{t5q|Ia8ka4F1YT660+`)O%!{qIq=SDYABr=9WZ zKB3K^EIxU2@*9R3(fUiKGbC5w3_q^qtNvKmP@!eb`=I&pRsSHP zrH?kBPuE@ku0hEAnS7T4_k&%FKVB#3 z2GfUf&jkalUr9~LKE2QU=dKz5SQga$nLXti)2rt-Z#iRL|Ff+ZJ9JCt)r91Cf_6*> zRY6nkCN!1y1s4n4`EqTqN#C(N>sRNRv-##F-}gVT^bp4dz6HI43uGOnl^v`b%-kBv z7;<|U-ZI>hV7$e+#gJ(Wb4D^t2K$9$q$!-=;OxHfIqS}61uufX2UymvXmWOJd8M-a znM2O**LF-Pn?JJbWZ$rMUemjlpxMr{6Lr6H^fNGq$=WMFUil}*;9-;cKb7AMeX}1c z#T52`-Bn6$%2qs)xBadXFXKWji;(-D zCteQKTPJR0T=#w6?2;aiPN%4h!>Wo(6F4rWZ4YH%nfl55sOu*C%Wp1~pI)}ILTft1 z2dTZ+Ok6`0X4scso-#QjNinB&EoYFLL*Lc>*z)+>G8=g(>I$yAQT@%!I=7gu`C-v# a@h=;mswK(^x-u{@FnGH9xvX#lwVo8zdKXM>XltJKH^*LX@H7PO-KMpaQPheiU U@r(LG1_lNOPgg&ebxsLQ06!NXLI3~& literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_horizontal@2x.png b/src/qt/qdarkstyle/dark/rc/line_horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..63be00c16164f95fbc46cc18c95b355113450966 GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE?>>C#6{_oNXup d3o$S-?79B0m3gHD?;1srh^MQc%Q~loCIGQpB@qAs literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_horizontal_disabled.png b/src/qt/qdarkstyle/dark/rc/line_horizontal_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..941f14a3859bc35e7616a391a976263c5d2552eb GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SG$r;B4qMC;pgj*JWnJV!S0=4;Gg{S(a~d0g4>LKq`M;@;96(=%_k0NLORi`3}A5J|FK)omnlz5vr;(Q fPy!ZWU|`sDeODqAbL9G-e2|EztDnm{r-UW|3?e1) literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_horizontal_focus.png b/src/qt/qdarkstyle/dark/rc/line_horizontal_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..221fd4607f550b911111bc52ce98cd12d72b0f01 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGmr;B4qMC;pgj*JWnJV!S02Je{X;&AMv2hWyJ28W3EmgbflCKWO~;O4))iRoEZ Ti`xta1_lOCS3j3^P6mdKI;Vst0A*Al`v3p{ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/line_horizontal_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..465680c3b0243987662baf76b0999c61237fe71b GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEi eU?BzuhI`pgtC>tLGs`A`L_A&nT-G@yGywp3uOeCi literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical.png b/src/qt/qdarkstyle/dark/rc/line_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..6ee62c156fd1947f3d3821d6b25d7e259d517c07 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SG(r;B4qMC;pg2YDF`IG7Eu{4ICcz#+>tZ(qHVyUwXsCtuyH*>m=X5(5fo;J2H} U-uUty&r*=Er>mdKI;Vst02<#TM*si- literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical@2x.png b/src/qt/qdarkstyle/dark/rc/line_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d65e74c6209c87034ed09bdcd73a655073f83cdf GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEhIdyytrr_*fiiRJNopKerK_dD`_tz0ojf9#xp zolF^wzKmNMmN7&*1T*L^&}erO7Id=EbY6KZjzybCr W$5>3II;ZM^ggssTT-G@yGywn;=OO$6 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/line_vertical_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b052de522eb00b5831483e57d0b20cefc5848357 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEq%nYU|C53gZ=aqaiwc;|{Y zkG}YeIB;ihEnqcay}&e!DTC3MaZAH8hA4+%2Hgdk4PqB)CSA!GdXc3;&U)7?1_lNO MPgg&ebxsLQ00a<9(f|Me literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical_focus.png b/src/qt/qdarkstyle/dark/rc/line_vertical_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..36baa09362f46d3c46de7a6a3666fac434ab423c GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SG(r;B4qMC;pg8wD8*IG7Ffyf>OEJGC_g-M_uO!!^=2(sp+LcFA}a1{Cmtu{)EE TxxMD$S&*=&tDnm{r-UW|hL0d6 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical_focus@2x.png b/src/qt/qdarkstyle/dark/rc/line_vertical_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..24a2b771c30a916357902567cbbcd16ebdd0f2ac GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hESxgy>zBH5OO>tytIQeAKS_TFN22WQ% Jmvv4FO#ryBOCJCL literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical_pressed.png b/src/qt/qdarkstyle/dark/rc/line_vertical_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..60e3574460ca9f195a82c715e66a3299820d1485 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGFr;B4qMC;pghJp+R94wA%vp%%Q^9TzDy!-lpvtak8s!dg9^7+R5I2cgC1Lhw| VEYsty4`+jfJzf1=);T3K0RX@1ApQUV literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/line_vertical_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/line_vertical_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c9494051cdf9dc8168f4e3792523d4fba392b80c GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE`UAL literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked.png b/src/qt/qdarkstyle/dark/rc/radio_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..acb8901556460474f328be0e2900ef1bfd5702ca GIT binary patch literal 1260 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|U!EPZ!6Kh}NgmVmqd!iX5+hUi)2p+f|K7o$|DMb4w4Vyv`Edv*D79JIB=lm_*&bZjZ0Ic*j^tk@k(oMoi*#> zZm!k^0UA0}o}9d6dO$5;&5L!DwM4cZef%*#O?QF)?ASMKR(v)bJlwaZcW$fMc1g#6 zYKEtu)$Cfnk9-2hKTIt*JN8(2dYX>H2vM+ zmFx0OIm~%8nndS4kDU|dU^H`1cyRcC+YKUb8pLxe&z@TRKZPqdNtJh3rM54I9__^G(HxViP{PS(wTH&rH){dSBEzSihJ_%`)uFU=TcgKde zGpa)_Wf@;?(KdMSdv4#31_@5C?YC~rjGOaLraW4(mmzI)rN!IW``_gyUeDxgdd%=lY~CuNgiXg8 z1>)N;i=2sL%t}8P1p7aF4KbNRQAV6XL4jj7rOAvss|WIh{k^B5J2 zHT)?!UwXIb-Rh_8dL1f2LAMO(RFLqoc_FLqjad%1!+c( zJM**{FJ^qvx*>V6>G!PJ+uMWVqgdoB0Zh zhmD!#nL@uOoqV!q)85USKVREAapKto_8CdmER~&l`cgNA)-CFES#<7HDcjqbTcntH z(u~}BtK}@7xhngIPffo6z93=tE~I0U&f9c;X8q(jUzH|? z26IVBNX&SD<;q`%D5Z~%**crDH}Q9>h#xq^HMuAH*7>(gd--EZd)>RDYo&$5reCW6 zU{j!fY`VFW)V4Ac^Z%9;-=}z}2$hzbo63r8W8NVt(ZAJoaqZ*3YBf*A+?D<|zSd!n zb+ozr9J=grK{dUM=PoM6nVt)|qTx$o)9kXLdt--92_ zoK)<$D12G49*Gl9#dNoWA7&{vTfV8ZU1Z}kN0rZSj~;r%Ffe$!`njxgN@xNA{y0>| literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked@2x.png b/src/qt/qdarkstyle/dark/rc/radio_checked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e190476212f1d5a496f444d581232f975e8d6189 GIT binary patch literal 2718 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 B3%mdT literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_disabled.png b/src/qt/qdarkstyle/dark/rc/radio_checked_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..49df43922d4acc2f7913fc5ecb35e3b5de09a92e GIT binary patch literal 1336 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Uz|PZ!6Kh}NgmqjN$+McVdnO}A1|d8*{bqIID`lf{Qcm9c5jg=<|7nwC;QO5d0i z)qW*3H3_Kma(z9@;yUG)SnsDpUl!$RTwuJkuYo1o`G8ZBj=1+~Lji-XEpu<4Zl9@{ zUX}l`_iM?wTd)88-+%pP_WIffj^>hH1-D+!QF;9_t!v}yKu@M+3~mp0IdQN0+Ogdz zV&DJi|3e*iP2R4MMrK+mG^FC0NepzDUx8j7@D_55VROyVCl4J(E1c$pfazZ&xKxUHY6&Hz6|2Z_~kIw#23b-{(#Izpw1cgM<5j zDZk5;l+5pYAyZmDf5FZJ_Fa0GadDR{7Buv{d2{5#-N5CJ>CNvVP0~-@W@Tk9(|D5i zXUm#BYqd6UXBcLQ$*k7MDrT?PyA#vhw3(Nb#f zH9dNlW6QQhOAJi4?IjiOOa0c}Aafzkc)~8T@0kYajrLb(%skHQx;?qLZvXu`cK1K6 z>)ONL^CtP|e~vxj(Q$uP&OTBob6?l`nal*HH5}8#uOE5l6SL1?H)BX@diked@pbjG zzNzs~7#53uTe9x#{pWEp3IZmxisW2hJAGi~fCg#d5tZZy2uK zj}EpM>%2KkWq4(nUBx9ZjcLWL#d$W#Hu(&k%?sY;ExwvQfQvD zPx{NTiqCuj#xt5dl(d+-pZnc=`E7YxZj5AZkv%(eeA!*zM`b&0Ajo z^ycgOH8vsf@#`6Kd3m?}OnQ7#Qqw^dhO?rhlt3`;-ANOj9GNHoSjt=TT*Pys&0_?xQ$YGp6zbcH%nve>Yag ztXIFf-nZ9$`SLUW`4oKHC zzH!T~u19V69{s+1-P<@`es;nhR}Q}`SCs;It6U7uO5DD7PjZ`GfBquZaFsFfe$!`njxgN@xNA DQZssA literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/radio_checked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ffd40ced86722e3d27df06c813b781268d3d52 GIT binary patch literal 2871 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 DYrR2> literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_focus.png b/src/qt/qdarkstyle/dark/rc/radio_checked_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd472e160a5c7e26dbfee8ce8ee94e4af48665a GIT binary patch literal 1232 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|QHwr;B4qMC;S(u^m@ZC63lVpZigJrHRU#nANJkBeYmc!#eFu0xy-6XW#BnauiwG zt=Ht`eQS}?Zq79qx)fN}pD7DF`<9t&FUQ>2vt}M$2QGwd=V4L3ob${!_RJfL$LH2r zUz__p?T7vU=eE!H#Q%RTx#P;htVzqa?^c_*_~Iv-ZmBaYjtqSYRXt^z?pBxA%>N(G zY<$_zwOZF8yJJbLWoBsj7q9oe~;?ZwHcm9_kAuIa6DXSAzwU+!MixN`mv zsWX2Me4K1~PygxK`Dd~&2+vSFnBiJ$?LYn4H7T1>AaM-WmfyMeBmxs0wlCloooWUbM&AO|Y zJ1hRXv4PIXGKR&h!S~BQ-b$4!W%&6v>#FYBmoZC<%}Z`SkXh8V_QUbH_djN3rnpISH(EVtU+31f*YPH2|Fu(lBDY^F|IxMY$G)e( z)T@1ZAC&U!lZ||6D!lpO#!FgJ+ixCTTQfKC!YanqiVmxEw|l-QOvqjq%|AE3Z~4}r z-&hJ+uhkrJInd^OX#O*y#KZU4{)X(62&=WqW6)(UOPgg<9l-q4?m~4#bnpFFZ}`sh zU729B=_Y4GfAo~qJLI+ny|vN)?fW3ZXyMD&wR($^DmA|}OFqzAkQ)-#UB2zb`7R}9 zh5O7$${kNP?3XFcPv87)-hA_fTJNnt(;ns?&^;jNy>@zU;^Tl>mn4HT%Jyl_W%+U< z>&E8|`_@je%V?ZC>Dvs!KKTYY&6cX1eE!Z4k$R^OrY!mX#o*Bjna9NiwH$@>KIc~6 zXMcWr#??pb#QvI1I5t76X4P5a*6U2)c~tKw?Z0r!XY#&10ePYIXVaF{HY@j@C~lDY vBx=I=MWM=Jw^QGjcWHkkc;7GWt!E5=eY;}Ej|XN93=9mOu6{1-oD!M<+h$L1 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_focus@2x.png b/src/qt/qdarkstyle/dark/rc/radio_checked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aed5e0c94d5361564b31f53d50cb7476957bc2e9 GIT binary patch literal 2656 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEpjLXEtG9*(^93WDGB8ax`C^YY!$c}8<+L-fKi~JlZn_HZ{P24fB%rOXkfNz_@7=-Z&KtH)c(G6;lyiw zQx1L<=@%^EXmDguV%YZf?_Tv6ya)F5X-xa>_t1LkwXls0J>D;8_ierG=*MWVD&DW9 zJYma~sLvl(iLGH<`Dv9-IfIJXl7d~W>zEBT&RNH~N2?(0nX}EdXI#rpzu0c$QIet5 z^N-`X&BF`Q+JU|i*WZH>9$pJ2(HjbgX? zndZ!8Gc`=uz~jbY!56^XAkWmn{v#$&H+{{lW7oYd#s@J-1xaNub!FH$Z*hh73U$rT zJ6Pwv%6)j;^{1cKJC_2f%=1hZs{YcuUE(g?KC}OuyM2HY!?Cg#HUa#CE53CvD#_n+ z>(0kRDRr0P|L0v%3k?-M>d$bO<#n6 z@{BUgxMscI7W{*+JoDd8Pgkz5p#==DtiL38m{&=)$aUsFJz~1{Px->SQ>{~T@7%nd zqbKk)njwAul@P8FNLuUE1pyv$ow< z`>^Pqn4MIZxd}tEwds@#ry2T+W>!CruFSfA^iF8cgCAMKbIRwk~LmE#qhSt{O<%>D5B0dJ=ItG5rOwoVZ4E>)4)%k^MGty$Cc zlI|%*sg;y?HS;WuX<0l=I!D4VP)yw+YmiA7G|1E7t_^tl_&YGK_c)3Pz<$6Yo!>L}{S$Vuu)C&`?++$y0I3b*?(1n@Rjp5I0X}Pzs#WzHjZST3-FvnUB~Vd)34q)-+9T?bMdtv$AesQCXV2 z*p`cmTMh)DzR_J&Sj^^dAyTgS>7)g0$8|0;c$Bjgp5l}|%Qg3%)Z@!%Ja@iIVNH17 z@v?5Z(&Go63$`Wkt!ph`6q4C1bK+SoEXQ?v4)g=Y19BW(t@AKR7-*$OYz$?170!qm>* zwUWn8P3%>)Ba8Rri+Z<&|IT@1=C|FFEt zsIdRxzAX+9cFQL%EpKd=I$yQy?uj=aGsWG0SVl5VaP95?khy^E-Sva#`x6~o+3Tk* z-Fxi(NiK$$s*y_n<)ZJe(Yc=Y_McM%!>(n?<_zDxHmow!{LV06nPH!(lJ2Lx3ZEGa zlTRP7b6FF@ezTup!`<4q`<3t9*nN&~j$)WZjqa&D##D^72D{?+VVVQ~>p(}y=J zZtV-cqwq(2$(~6ZJO|D>8{SC2_3n8J`+=TpvF%}up^B9@#iA+7*_D*aK zw~|2Fp6|C(?ixlicBF3*YWV%<@9s{%r?q!WV$Z}*k>i^ho#s(vP~g2UmhC}GzG}(O z%t*!?)!VjR3htlr=J`&+;xoDo+t{@9^v&F4&hRN+={+P-@m%BfqxPh&^QWiVH_Qta zS*YpQtDFD0ouRqB=M?9swyC*yBwY+Q$enGPcWSHcJY$B99M2Z(uT0EOom1u&)Tq7h zhrk`?M=u>7K4manpRV)GQeZpk2({0}$ve3mp_f8cO`u7La@ zdBH!jMLzc32i%#`znIMae2C4KL1ME@d*COTht7LyU4=hqam1V~HQ&sA#fCrLOI7Uk z2?N7e;h8V<9?li~5aC(OP$L(1ymf8EyAvrDIr-f0^`CI;Gh4aJ!;SmlS;Z>V&w`)k zaWk>b;p=~WMUd|cSA)Kl?!%)C3+HVs5h`!LdcWP!+eBg7LCFQVQ!RvQcb{lyYG~l+ z%wgLy&4hc~(vNHEuZp$(@=NbKpdGtxi{kP2)O8|L6ehk1*teJJ<`Up7+z*WSI3{=*9k{ml~eAB;-|ZZ2hl!EnhLiL+hQ(M`Ne!%o2~Z<7S=w zaK|)PCoAyU|B#zg^iuD?KD*y=XY-}IU9%&Ps_3vK9xCp7cdO~;qBN!Bl1mmux~HEh zZG9%ZGcagVNo>0m?^Vu(jJ`+y47PkTj|(0*KFYQj7#J8lUHx3vIVCg!02+bxCjbBd literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_pressed.png b/src/qt/qdarkstyle/dark/rc/radio_checked_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb323b8c5a49080d03eb46a13e16c4f7aa3f5e2 GIT binary patch literal 1288 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|U!0PZ!6Kh}NgmqjRRXiX5*`-*-u?LQ%J~yC~OTW8mVF?Jt_mRVFmVn1nf-Byp5@ zCvwkPu;9p6#*OFpXDei-zyJ4iD2#kkH}PIoLhk&P+)E;-3cp%%?zR20 z>`N)hrj5tD<|gxaU)>~?SQh{5v7gq~eM=K>Pc7t*h$u{$=Xq;!haFc*r@)*~2e#__ zhlZ-U&j~Wf*mIXPzu^s|E{mRIM5$U(W!V{~J+r@wCKX3DWF8PypT0dhOZ&gn#0rLI ztWK4|)hnGN_+#8F%*r-w$_-)cW?J}r5@(%=M$i_ucP}gZS7}+xeYzd+@u#!3$W88& z70bLHT`b>yN6wPjIcRT-s|M4ob|wG$EmznYpE7M0(K+E7+UK}wp?zaUw#(|;r(0WB z4NCS6W1QkG<@8*ZP9$j6|dekKDqbqk8`cJrHthP5y7lI{{mz) z%8K6hhH^Ic|9TelR_-*HhTd&^*{7-to~QZyADMggdh7=7Cu;>eVgnpb)&473di$0X zrwQZphU4CUw)*o3Da@GKus|j|e~nkln|r>$xkSr)du`@w>N?xkW_iDD*4w?PO5{M- zJ|hnXCH*DLPjA<~G+E9x!=#Kc(x*@;r$l;<;r*q>ryd<-N>FQ1E;=Z?7gvgZ++aB5;2LuhPZjMz!J-P1f$ ztp%ja_nx|E%-hJF*Blzjnvk<9b3((mf(5~sPAzkM-&VKNtF8|F8U&&(;NQX`5K@E|mEG&b*h|cSE1?n(2q*YoKdzxQd@@c>QsY0R5F;{S<@{&nlQcKp@$ zzg7vRN20@``ya6T9aU;Ps?6>2z0sbLyP?+b{MNUJO;wgIjkjdz?OngTElxl*zp}!5 z)%?XJ%ZiR(7vn40W!si>QY=hnMtaanF$MV_zuF$J$zFf^&-V)|&Wl%=%&0D}bBst( zE;y`ketsuQ67%1-TrY34Hu-JGBSBaof#fw^BPI?_TF+ zo+ENR@_N+voz)h7hPFOle;%gmMDhN*6Y;0fEVS&%;;HKH#WL3~zj^uTZ}FsSk#vCjm3{oR;NFXk9&XJmU~mY69WSSgQu&X%Q~loCIGkOR4o7i literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_checked_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/radio_checked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe0fd851766602001de17df7851895d16896b80 GIT binary patch literal 2804 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 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_unchecked@2x.png b/src/qt/qdarkstyle/dark/rc/radio_unchecked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2160a32ed532593c6ed5b88651e64a56f5a54704 GIT binary patch literal 2167 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE>T{>;65vA1_8EpWYj_vYNayQ3~8C0X`PSQaJJJZoEk zN}vIg=E@*bH_j^wOxNT?R|M6~2;gZF%QSFYxUo(CZ}Ya5Ud$4`df!gOmZz6}zqNRp zQts7v{gwOwUA%Vg%(-`O@14^N-+R9P^Pcm+&y>%r{XTc*_gc0YiEWbq=1=sSlk(-m z!^+sBr;56EiA->12x8D%`?hVW3e!*XYCK5O zTGRG`Ihbd%>PH*XKQ^NM`_+_qLRFmn7(6#}wXR-ph0P(XMKZdL@&Xa1)odLY8sk!wpH-tV9p=dLFJ&>JhwH#AGz{%+U*9f3tkrX_d!y;Jxbxb}zRT zj~6iYWllZS>E+)qtUL9W$2r!L$&198iYy!YnP03GE}qY}&R<1n{q{xsm$IaM`pMt@ zh>zj@>b$3%4)cUho%3*s>o}T}Zz^m(|NM8WzG79^Xx4<%50(X7OQaQ zu;vf1h#lX8-CiO;Ca~R^?4fdRURI6y%MvTAbie;rT<_UZ_U)g0M9o-mf3!=;=8d!c z7(CCOdb*$efnWS&p${K7t*fur5Ysl1-Y)3o_V3>HyVbAE81vN)j%)K+|Fc~E{ImD7 z^Y%A=&MXsh2-^JSPZ@{Z>uf6*-)l=AeGH$~X&&mv-5N1{@w~P33ZD8;y|l8QmzP&I z-(=dgGo5d1>XNS><^INfwP3lP979{u#-?>Ai<)ll)%}wYz9rq-bMM6n-u{Lhz3-9& z`@hWG?r6Dv*0Rb~7cCN7zLPKz0*d9#n$G1xx0`gF1- z@y?CD<(tz^-uiZ(Vdwo^<%(dfi4{qk_D%lB%GG+PRca&ix^DIlTvMaWW%cA3CbfN3 z=$OAVm#Ol~rZr0^f1PW>n7Y)AIpTql>?PLhdutQrTRJub>8)db!mn36Ws&W!**#ZY zN1HRU=T=L0Y}FH9xW!+(t#F0t!M6z+87n-N*Q{l5kA1fEWXwD7ufMMPFnC^6v@f{L zawl)r#=p8*xzZ~`Uimi7zGK#S$JEf!aCg}JS)3cVTA#8^+v$_axKFg{+_yznlm(ug zlM~wUB4p*4qfzg+x;Gq>eU~iwM`fZ%%AvrUcIVFc&XeytlDl;tFH?T=&75z0FMMHY z*gW@CiPpyut*>b-vTn0@-aYk{pF!f+`oIsImkr{+{ATN8xcF7N;N2s}2TMOceZ=VC zA|vEq-NR+h`jbtq;eb}Y!yh%1Qdy^xk6B_hS}*bgrZ#kTcHUH2S8#jIrhm6Dh;Eyi zqVr9Q;roiYvvo!EKK~9?T@ayD$Kvp1PHVlKM8t&8zkSPHTmm2beCV=rRq3f!EE)-& z%Y`@S*Hq4R^yn{Z+;-!=umSrC)pyFQxh6S@bDccqm&HB$&N+)^vK+hB<$w3$xhKiJ zW%1eXe}Uu0XPM4F$~lR$N7nB>|6X7ML)9D^_x!BhT&sybYTYbadch`h{oL=`g>nk~ zznmz({HS&P?iF4P2Zi4y$F5wJSiCPGGHg4;yRQwGCaHRR<;`DUd0_J*uTM?eR=j3d zUOwAq&WGPDst3yCHD81pKmXaZ%r*F3GE>-8|5EeP1GOrTsuo+F4|w!rOYsqqlMiga zc_OuL{%6*+yB9DsUShP1`*-#BZzG29|9)S(=%gsNZ_hWUAmx;$$5(u@t=qqfWzNm$ z>YKUU8e1>DH@|!G$>-?@cQ3BFUEb-@3j5-Tcw)K}-$u9k{J8tzId6PelR-6Vrk5wDq zoixy@N=fFBx_xSmW$}K7_u20^KH6Ws?b@gHGZ_RGr+o9B|I_XEw$<0JF5}Mc>5o@g z^seZ3%a4DHTtBapYdjxRo`1pQaW%^)?(O@VY-XQK(aQ_WezD~8%Zx2={+tSScKP%4 z#YJWQtFO&pzAIQ7vq$#c)vG&R#Gdcz>-*Kc_+Dt*_pkOG2i;?r8I?wwM+QD!!YLsm zW5cvGmU%(Nxl`Iockl8~e&ezBV@kyG@`n7<+bx^+P24oMEvv=Hc-#C3R{awrvY&GG z{|Jw;;`BUu>sz?zpBvY|I2cLRubC*}`?o3b_CE0mym6v8qF-HFU;V#{)jhi;n;TTp zt=|7XQ8DkM>D~;>A%`mr}ku*!;Vm_Q-eY#*G_)PF(k5 zeeLb<3?HnfY(8UhwoSZfd634+=(2z90yTH9hp?rr4%W+)l992wlyk@J#PiR4Q`zGM zAI@dC_c&9;X8ozBui4qy?q#Z_X)oQhJz$5Z!*u-zo=x9Fy_V{p716ntY%b|}qjk3H z4#9g>stgRBx@k)L99`z5C2tSYnR{AS{E;MsIGf3S-URi7bNyCsS$#7F6u$ZK_ltOM zX)%N|^HlNZbEnoW7LF6py?^Z3vEz?-J+@(ZbjvC)mGPU?25GN*0ba*Kw#&R;72-F| zOLh73<;(pwO{XvM^o{0tRKyU@_+q{A=c~p~Kh@{B)_2JJJhAtDxR*hXS38ZDkMWP+ zC4)MvsfzE_-}tAQ+}4XZdwKGe_Cr0q3d%>sE>-HBkvh7~_TWe(K;fB!1>^TAxjGhR2z4X))i?jYob&$A{{Qd4%bv5m|Np>Txkdt#(m8FGN6hv+7+$ztcuhO0-!p3VQ;;yz= z&2F_lE`1 zIl7tGOV2J{9ekeoJwxgN{bRQli~riaeogd(J^w0Z9xRqz=<%TVeC+={7FRBRejfGU z%Zhb%wccA2{`D;IJ#fEEPKvLj_kP%dT?-c)n8klEebKz&z5U04lhV1lxn|N8S+()C z#jCsaaJ%%(Y8L-xl@=uI^Q-4Z&B2!}a}M$zVl=sN{c7JO&M6Ve_NuuTwf(f_XIJr@ zk@(OqRs4U${^UI74^InZj$3DMk7fME=f~y;sxf`*FL{B!DtpB&}f6_Wu z2G6%NhzK9In=FXm6)_*HEv-CXkW%5Yk_Y|IRB%$t# z^<+b1cSY`>-do=*|5Qk;VgI+jAl5wAVHrb`TG*b*3$1I-CvPpSddWQf7tbFqg+ues z3Y~C2Eu^F5o&29u;?T*(tIi4q7}_x$i8&(@apmBWyAzppb$`x2Anw|yw(_qe)56Ag znJwKMuGZ^rPcQaezs5dr@|`F9_AkGM~-Pc{K?#8`mzp_wK=4q0PTctGB(o zde=~RwXm}2qNr7!xmTH88ah_=Db4$rupn7!_O9}>Kisd4Qm%v?a%N{>U|{fc^>bP0 Hl+XkK>yPoi literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_unchecked_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/radio_unchecked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4de5d0d2d8411305a232bf65c59408ce6d9b7e75 GIT binary patch literal 2277 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 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_unchecked_focus.png b/src/qt/qdarkstyle/dark/rc/radio_unchecked_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e62b996b1c3c0c6e0faa17eece8bda43db2f31a4 GIT binary patch literal 979 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Rrbr;B4qMC;S(z8P~uMcU?nPrD?)aO>1Xnr2(r*3Rl}yyCg(!}6tDLNX`Mk`P?k zx@bp%I)|p-A`Pj6r6R6^E*E_>j58Ol6w`U>bSrbsQf_C*js=t51gB(ewLeoHFK+BP z*>93s%A;lJ#rEgQ_kFheUibZZ%#NGBpE>I`T)!&HsXJ|ZR7mnQP9}q{6OyvwPHMN8 z$)D!BFs0DyR_uXimTIzIOa40V{(82F;nnWiY%S6I?6$Eby@}tgTa>*dB84P(Pg1f9 zQr+m-b=%?WfnQ1A7@NMO&i;CP592Jp-|uGZ;NKxHA^a+4+pKNwKK5JfKh-1n z=Vn}iq|agR)o{_OCdv9>MFYQue&qDt-BU7^X7ot;j)hd*Lm zaBW$=<0FPin{`Vh>si)#pPZlQ|MH7S!xzW=L${KD*m`bBcYHKiLGRh&?gN$y-iH;- z&TuT?+RrMm=DPp(*N2*pcAMQjN)a`=SNxT^UUIDe{#dWydid?GC_RP+ z2J%L7Z10R$Nym!{D^K8h!_x96_2yAVmDBH-Ir?@Vzk9u|@$uqTwVKefkBeMe*E8zm zYO*?9ZEc$`#;wpH$Z%#?CIi7gG5z7#F2str@q2~6Q&j$<>e4oCx3D5g`Osj8deU7ss#!C{VDthhG3%aQnS zs;KjNS#@WqMY_lq`IDEKc(!Jp_)+|TPw#iI)!q-OS=p{y`@9!^Z&siEGwIW7p~fe- zF5a9|r?79Y0!Q@AxHz`G40HTLU(7tYw_Va}Qm2+kd!w;s)dzKp-iuxJ8s8noIY+oXR+b> zz0Plcm8$hx#`;{c%@caZBsb4{&r!*ReQ)w)_XfV%vo5VyGQVI6Yo&I8??aZg3`HF> oFDg7v%*nXC^XHSjJKx%Ox+gE2s3vrQfq{X+)78&qol`;+00>pRsQ>@~ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png b/src/qt/qdarkstyle/dark/rc/radio_unchecked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf7bc26b9e24e84a85420e7aafbb2d726c2cbc4 GIT binary patch literal 2127 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 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/radio_unchecked_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/radio_unchecked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ba4f83b91ede00725dd5c1a73aecc39315b49d3d GIT binary patch literal 2263 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE z1{Fnzu!J?Tb1r&Et^BI3wmX4?g-h$QPNhmzG~--ez`w|L-}^_x!$7e%`kFo#lHbW{Cp~|K>Z^epD2G&bB_tXobLp z?G2eS9LX~b=QJ#25NSBaXukX zhh-8!@F`X%Ki+lxFvG^RYKhfMGip>1?w0(b((v-zv19Elt0uguTAZ2dd1T#!ZK?;N zV@&6E#4!XUgrBKMc%U&O++;29p0wi~FG`t~oms!fYE{Q{&L6HqGgThg3S9TrGLP#JKO>J{QVstSjog^+KNjEn@jjG^ON>Rm zd84R9-kfJ<47WQs^ondO{{QNz`r0G&c5O*2cplzo%{hbf&>EKcg^UOG6!<>izjn8L z;c?CnV(oHDk9Zl3e3s2=M)-c3Kh zU{6d`Z>}xlDy=>0Zg$=ep06_=gikCP7G!1|2yJM+=j zOx}eDc7`N#YRkXLJ{y;~r;_QLVG?U?>1T!u0n!%lO5C|6Z{%dm(y*@FeE_d2(kb=rN7>nw7f$6uY%;_7PlcBnY&U@x_fbI-Nd`+4$> zC%eNclMaNv$dmhRY~3dIwS6{w!-rd&v>NL37hJFG4)=YvE`K}c1i_z7jq7*17|crc zn-#mi@Ez;xu*zb%2fFL_$hK5UbuDe0U$D_AAKY1&DR(#mMwI%y1Q_ zPp`d}-Ja?8_t;MHj)WhJj%;$tZr;K9K{sYDb3$8Nmqw6X_Vkk_kJ~0&t~dVh(fm5g zzGuPyuVX)MDHK*nzSzDXQbq7Xp7YyDVYlZl<18)xe!L@K`BRq9i$Mw;7R+RO=3h4R zwf2T7Zs+a$zDvvyDkwa*C-k&u-`?Eyd%rB!{9dBW@OFi4*^%Ny*;i%?O?X&V%ir+Y z$oYRp)b1xU0uTOwSf6p&DhU$(vh&-lmda;) zf(~>g_slyGxLEC+%8B+Z(^+bcr^VN@ajyJ)uH~>>uO*{ONqg^^UA_~wxpe4+#}0=%1F<`nuOBm}%F!YZ>dOb!(OM2VTGbFk9|n z>pz#DcP<2~A9joVqic9=zpLO!o#?w?Sz9htrX{4;R#sk7>Ar6MY|&W;J$X~(cXKSv zE2iF+yUZ3U%Jav^Td*S7Ci4zU%$@J|mo79CS^m;u&;3K!UsVbmu;49KGJbw#UB#`I z-G^A}JpC^$>g*1S&F?;JqI7@#t{EStWj()m?Rm(r;^~m=`yiI#*2xR1i;7xh)h=^x zKOW5UH~am{o^#(`x%^U5cRr#}<#n8)-$!e$(c9Hu#Vfkwr969)$O6zdiANc&tiH{gtZ%hI|Z?2UGs;vXy-&a!!50 z{n)*F&jj-ChKQMnx!0~PNKX%MENpM~z_?#bc-23d=p84`jUOG4IH`d?9Z6?bsRCFWK|A zo4n2PH=QPX;`{1#ulLt4XxpXs%G=!kfb~pE_2+VT_gXKV<>(!nRJpu(e$oXo*^@h% zpJaUzYtP##wAy^eh6PnqtZ#o7Z;&%KsTFzIVLRc4xxJi@{o%U*vrkPF)YWgwSh-Ns zspS=)MYvo<@UPaZJ60yVy3}=W;(D2G#|XZJmUR<1G^ZYG_RaP_7u9+5vFDlvDqkcH zTxFQkw(PS)U1VWU>(r*BDKnO>>f1K$jitgyr||V9lA@K%i{`Caz5D*Bm@BIz?}P_M zo)E}q{BR`GjyFNNA-9Wr_Zl_j`|EezIc(dyBtgyl4!6^u)C!gbmkNAu{*t@Fp5VN5 zPyWMKuPww@vlPS&MY6Qqo$y1O<*&Cv{h_X+S4@{Hw<}8tPt2H>a(sh^az9Hi>*;1f5sa~8_ZSQ!YcBA9`##Gm|=NG<~UDH^WtNL6!$~2B^p7Vo9hGX9h&TtxR6F%wN zYq|XYwaNdPOWN%sPsPnqU)Ee{AF literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..fa449d6ee0b1130a904cb056bf8dccc2076cb16d GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGPr;B4qMC;q@2RRuOcvubw>zp~n>MeMwW14_}%{x1Orq8`DY1&EaIx2Ukn?`TA ry4H5(KAFEf49MWk`4t|AZ)(0~I8r3Id#}#w9+0G`tDnm{r-UW|!#OQv literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..682575ee24619be08bf856409bbcb15048889ee4 GIT binary patch literal 307 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEG>z?)rP%uJ;T&T_Ab<@!IFLs}oPl`%n66SnBcWLtVuA-(j=aBji87+hGv*7-8EgyKFYq|^nS`` qhOJjDr&>BEx0gc*O}6p``-mF tPMC4>Z`693zdQ`c;L`j+;hQt(F5Qp3K)=T))A79{FVdQ&MBb@02lQ#djJ3c literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..23e06a0152f4b8c8a742a145648763b717bd97fc GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEdtP%@mx|MG@w%Sv{&;MTQS6yf08P_j4iRXR$*FE>MzBAmE`~33G>$=Ix zOn*$6FED4YEnvUEy*b{~5ev nR~dz;o(r1(?z`&BgTk#$YC7q)M;#d$7#KWV{an^LB{Ts5j7e>M literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..9ce6f8d89d7ae7dbbdc62afb62a68a1057bb1f1d GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGvr;B4qMC;q@2RRuOINTDu-HIBv70!Rg8MBtxXzAnXs3!*q%$Cc3IBU$y}9D&$Zoln^Qq-pUO$ker>mdKI;Vst0C|ru3jhEB literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_horizontal_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8e53e8e72d39fac4379796f804699ef7bc105e GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hES{M~)@tGREC6 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..bbc8abb1f95e83f96efdcc7e263e253d15f7fc03 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGdr;B4qMC;qj3waq71XvC>J2eCul=wPns@&($(D`)#&5GjHeoPE3-uXG3mo9!M pGI#AXMbDec9DhDAF)$p8&7RA{F2Ol}F#`hwgQu&X%Q~loCIDiIC|Lji literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..136ebae2cfae25550de157e420476a787a190921 GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEz%!-4-FxUU4O$J!mz|1diqWE2BKgI^89!`~YGk5*k50Eu|I`njxg HN@xNAq%BLS literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..37453ac258dde75dfd42ab72f78e5e7820a2bc46 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGdr;B4qMC;qj8wD8z7+4N2HtOWsvOq^SPZ!6KiaBquZ{$7XAi#2ia=vF)%P#e`LHKEXObMXT1PO#M9N! JWt~$(699+HO!NQ% literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b548771816311b42f03f8c2a8df528b78dd436db GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGtr;B4qMC;qjib4zm46GNQ2CaI;p!bR;EoHjVB(0!tOYfW2PEe^8JLi$ht6;zC oTVyh0hkw(hR{aSoFL(3qj^JW%HcI7ZU|?YIboFyt=akR{09xuOdH?_b literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d4dd49dec9b18ff2afc1843b720f83449e1a8bdd GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEPP7Rqm$o!&gmv zPwO!};d|aiSuXdWr)7W+W-aG5tcb8=?J*|FnFVdQ I&MBb@0OB)C(f|Me literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png b/src/qt/qdarkstyle/dark/rc/toolbar_move_vertical_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..768ebaf4ca4d2eb8cf15b00d918ea43c1d6295c0 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGjr;B4qMC;qj3k44-h_GC2ou$DrIjTUU*~@U|!bXwSLrOo>=38xlKTJ9R literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..01e3501324a5b0302e32440035c27221a8cbfe91 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGnr;B4qMC;q@8+jQNc$giVC3+4{lu(@{-l*tvyk7qGEf0~9Z+g}0(#k?IXJ5nx n`Li=10|nh*J+rpNIsSXg6r#cL``hBq8j!T7tDnm{r-UW|ZZ;^a literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..68d768e5e13abf35760f1b23954c0031ad92a188 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE#lUW%D1w}8inntQE09fgLqpdue{C`EebRBynyApNviF@s`R5BTac_|Q|8}pw!~=Vk2Dt^Q zG{z?x&da}#-N>-_TS%;TsqWryOUhi1Y~0HzpDPlwYZ|9G0|Nttr>mdKI;Vst0KgJz Awg3PC literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..f8796f9e6be5332d43ff24a1c7dcf7c95a71f223 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGnr;B4qMC;q@8+jQNc$giVC3@6^Q(AjEr(BgdRPyKh#&x|eZWFIgyn61K5%29i o*Gt$Lkimhozk1qA;vE0IWxD&CW!)mrvil%uPgg&ebxsLQ0Ita|CjbBd literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1d9f20421c8b76e0431bfde488092a91350b64b8 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEjSlj#ie^yh!S8I-;0@n)QMy#K%t-oy(`A1eRcstitRm>bP0l+XkKYZz-# literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_horizontal_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b592e61c161f720b2348a369b1dd52a9b0a66184 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SG*r;B4qMC;q@8+jQNc$giVZ)oZYr!y_d5i@Lg`Qv?ZtaN9O(r%^Qb9z&ywpFfw l$;W^U8fJf&jkVz+MBpvZQxT{&A@DOdCF_cGre`+(&Iy2 z=0vXUU;o)GZ|mLfg0w%xMgA2UO*{{FFWRhvIYBkPL4Kl0x@pJb?4WcL)g#S?a3tu1_lOCS3j3^P6`w0pYK*H^!eA@>#ok^lW3Q}zgJ2$zAC3c78By#C2?Z~KAdMbDF zQt?;2_)4{t#?^u1`}fw%rajxTx2|Tsy?)a1)jLXxqtd69rp=7*xVw?zcKiLg-_`y% zvXtn?V literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..2a14f5cbd0cf823964f405146395eb9f1057ad8a GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SG#r;B4qMC;qL3waMHh%j7ic5DbV$nm`tIO~tA!&N22z01$ZdQAFK{<7QrQQ}2? m-}Kd~3{Rw;Jtr-h%)9qG8;h!9s1gGM1B0ilpUXO@geCxlT`A!J literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..35371feeab2f481fa6eeb39ca2bfbeb31430a15e GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEgbhG=GB*#DhTP*sGZF8DYnNXXOG&t;ucLK6T&Vn1;J literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..48b2657f5025ba7c7fd6d22c4fff8b3c44ecb60c GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGVr;B4qMC;qL8wD8z7!DjTn0bsP%wU?R&VxIVzDq;1o~$lm^qf>D?)M}}e1e?s l^B20zN5q{yCoP%H%dm!(MYgUZnSp_U!PC{xWt~$(69DV5Cl~+# literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a2173c5eef07938886ce6c7853121601fafbf40e GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE>FVdQ&MBb@0C+P=rT_o{ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e31c694b05f39da714a97ffccb64b11de637ffb5 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGlr;B4qMC;qL3q=_O7#J=lYla#&xcWY@y%{ubNmtkJm$w>KJoj^}2SqcV=wDZR kErQ|ER03t7;>>PVdHT z76vf5(e$eM^4hu4w`M%q;51*=xAOYe!j-?vcf4Nz@5@gW%WM03Yb~S`veTGDvOGS; pEIfT_*|$}RZ-u~m85j<{uVwK2C&Zy;|GW_-{&CM-~78 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png b/src/qt/qdarkstyle/dark/rc/toolbar_separator_vertical_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4ee7aaaabd6a1d4ebcc276259a2de91fd38a4548 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGNr;B4qMC;qLilPjP3jRWEi*wvp00i_>zopr0LV5*@Bjb+ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/transparent.png b/src/qt/qdarkstyle/dark/rc/transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..67753617fec23bbc57360e16d16bdd82ab984743 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|SGUr;B4qMC;pwjEoEn3{49E*XMaSfSB*u1QZw;-5D2jFfcGMc)I$ztaD0e0sss+ B7CHa` literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/transparent@2x.png b/src/qt/qdarkstyle/dark/rc/transparent@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4012944b58252423bd3c84fbf6f5e698b1a39bf0 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEjMWFrw(J!hYS-fm`}fnaClbf z;4!Ds_`oS!&jRKI$6uR2T*>^N@s;hPc-YtQtM%viuiBmaRh;nq0baP|C&?aMN4 z66P>mu-<4YcB)gFW$v$s4KMZ@W=xr^tFS8g5O32t78#|`yR!re<{UFU6x4O(qlpmn zkCQAiFSqsVoFl-HaqC-V*Abu4&NKOaCDF?YMdoKu>{ymNzw6X$lg@eX&x;?d-e+&$ za9-q~Vwt$g;m?O$MQwdN?rH40Vf0LiTknJ?)4DF5iGS#$}iVT4{qg37Dt5ap5oAVd{MnA`W(Q~HF8@DJeKA(7}!|QmV)b-R?(_T5K$;5_Uo%*jr#8|89UFE}=nYU8q zT>O9wi{rhf(-JMlSttQ@X^x3h&tcCf@@m*evgeSg;3{?LV=XSH;_C4?D z$7~0=PWkOwcSznlRdKcON~Syko4}`=xc0QTsK0H0cSP*Tf$QB57<_NvbB<8oCd;%r z@PER#$)EE}5AZe}Ulo&jpuGD*XVhv9d5sq?f9ek|_E_Uzdf>Qev#IDkbybJky2*CV zIou&@-m1h*>CJq|(3kwaW0PZ&HOo!8xaE7J+zXCxEML|t?s3P5qa$jz1OJbO8Qb|P qVw@(XKCphU=we#z*8hKha8G;R5Lotdz9<6&1B0ilpUXO@geCx@c2D~N literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_close@2x.png b/src/qt/qdarkstyle/dark/rc/window_close@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ac7da5e1effb673af3b7f611cf244b133546f GIT binary patch literal 1620 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEtadICrpY094!p2M>sb+oBb2>D`;Sz z$}HaZp*+B0#S!i51rc3ayR?$B-5xtD2y{4i%-!^>uw#nRq@1r2#@jUh$X3UF-*f+Y zUZx87wTR^2|HhZ{KHS+^Z2s4_`YWqoACt7hxsGdb+)WEM9r~-=ZNSs5Rjc3hjy28E zFYexse_v&zxBt5ub6e@b^7-fPZ>oFzhJC^AS$eTYP9$9XY>{Q0waxAxWkK65DX@}2{`c*Emzgyj;1!`ihA_o!d(3r@NCf#DSM&Qj^PEV(?v zgqCFQJB#;+tLjMpv#Q!txx}^M&@sO6ua3X^5F%qgYs<+sGuDKam-F!-XnWQu#&|%T z@B16^)yjJn7RuF4IrmU-i)wT?L-rGvf{PFDt=3cYtVmdvc4qb2W?iOJ^S*DEvh3L1 z5^BlExy|+f&o!QDw(p-mgQS;mfiXlf%yJj2EJXF7fg6F)?Tr?qOejc!#$|fS$;{lE~Xr z4S3{(3>P0*J9qWhNg4MO1fHBPSydv$uv%Mj^@j`pEEnjyp8qYA&DJ=x@92h;8jB}i zeU*3ptGIGyg=`ToKWCXkvsdabL!VrUCt~fN>|d|vJbjDP^APu+)>{V^IP83j`j0Rv z>||+{`%wFTwaWL1&JSOAo>uneOq6&RWSE>Hv(K*nXUoGcaZ_)-G*MOI)qgSJ{cpYb z@nX@7tuIa4aOt7q!QBUvSRDWLtl(>mE7G{1GjXB;k9^j?0RHzi&$3@E%sYJjx>vga zkG%Vt%+}emr~V6UWp7gWA+;cAW}QIt@djPKV*Tin6>omamtQTIdxhn|CzTb?-ek45 zPhoX%;yl%}sH5Zb<VLMCIKgo#=r?qURhgO^@U^ki3vq+t{h--)D!z*q-_&2{;?f8sofu3Wk z#LFL3tD7T5**5d>OUgC2b{HCSgbVxZ)G~eiY2)r}BXI-K)ZnXZGUwjg4NZ zzYebXl{Mj|V1&TGZK-;NjM?AByMN|idXud<^KHXQi+h=C`ZoUgzz}UvmXnqBt8vS( zEVaq929n3We~*+6-(kB{RX^h_&lInp`N2`|tyaEoXnFWNWM=V-+e)=J-?W6Vs_@ja zYCB8tG1XgNxj(J7hJ+HkU zdbl)5@Ph9Tw$-W&Un@_r*<*W2MsC52O8JDR2J4O=eDxzl=Dp9I0^wLri|DoQUTn6Q z|1&`qtZL{QX2+zei5xJpN%bo9!d1eFwcfJ#-RO51Dfuep##aO-0hnLq(x$ z(Qloe=A2TE_gXd0ON5@a)_xb^vfr`p{U4Pt=B3oFmCDCF*(mmCub1wusT>8)@r~UI^hjVVyB8^-5 z6Uz%GG!*SilX#($=*hTOq|VX*x9%ss+`6wfo0?l(S!1~MA0L>@S9^9( zr*zI2>$k?_eYd^6?I^c<^gXucYxkY0SFmxo`Q2T&N@T{{7~SaN&!5+u^lz)=yO1vP z&h|Lhyq`-oe*ass=y<_|1t<1B+i1qL93$VrA<_CQGD=6Bxc?!$K;Iq!UOnEPi)f-NlU0&b%ea|%4s@9-|276jsPW{<+ zr}NoCF~*-Y|Gux@x$k&L1+xm%U(t%_D|YuzKa`%r)tb2GX7?wt58NJ0PR;)OI`78j ozwdURUtd;w8C>vOkCoo6)q#}b;$px!V?JN%n*}JyO)B-e_OX z`}BVMb$PbuZ7emNZ*m?sceto*`gut@zsKd~mh+eH|BR?u;}E~-vzDLJ0SVPWv$va@ z_zs(L&eM3{{p6WfY=U9$k(#Y#ZVw81YAiYJf*2OO-Xg4;_Ka)Y^AZ{PzEejEm^|H& z?a7Q~3FEx~!q!FqOQ2!F)v0U49v|FsXC=!d6_%=7@@z+g4kw-wWI0@XTR;7iYyU$# z!FxwsK6J7$3EfrfWQ=L`zJ2yf0mpQ`P>oNM|FLqnccfMQnPGC@MO0(nyVC+mb8x2MsbP0l+XkKb=Gyw literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_close_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/window_close_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8e4cd15d860f94e0f9b8aae2455440dd1e6e602d GIT binary patch literal 1717 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE+P<6m{&toi@x>hspm|J3jMZfE;a^4r$+wSVosZ}BdhSNmv-w_$Ybw{UHXL|+*E`qABfYr) z+r@MhuQavuUyS0fAAHt$O?1JYi@TS|ZM!z*J5x(a+9#eFTzk(lue}$=u;PdwrBTJ`eNCGPiI&y?&^nS0hY zYprIpT-l4~vqC+89o>1~;t1cGkg`{TTSFSGtB-2MxO;|n{fyr}`#lH4H?;^(}`iWhQ98er;~1nzU-XYuDh+NAbfp9>+7tXTlzXNZ$)3T zFqDZqg*;n$_jv=~r)g>TL#}>#_IAngzJ`@K^R6^&uBcQtdXpu`w5Fj=NH{p&^#jYh z0*?RUH&XU%D|S>q5Ek^T?k?WX6{Kvyz`^Ip!?}LK|J(^u)`@bzSQsukd88CAcRkvF z%Z7)6L1Et9nwT|_e8NrvpI7ir@BYkpUjMDB00W2kA-~z}4CRe}pSZchdrxdQRNDT* zdaIkIt>Nc_&n`-nt#vy-&kIjJ$D1YR6v4>5RL`g0H*|XA`R_bo|1u3apFVo?o?+6> zm%$NV8yE8}&0Ar3cPL`5czOPdeN^X;dB01iqx8lSTd||UJ=Rv^6S*<*h9M_eBE>9 zlpdnjE~wI2S4a9XKdGb3>pwHNZ+x}h)=^ObQd{S|*Cf zKb$9UNp|b8ki|^`Rt+v?&swhJTs^wyK--}<=Ua=f&F~0wTEWmXgZtl(w6UUy&B$l-ZJL*##Y68&Hv{dc(03cH8`Fz z-x4jr#wKuOPsF+Er8QgcraU@yMR-w68oMG-3EPrm#mBF9e4h6{O>V)a8TGNP%L{CT zdmbG(4pyHlows-&W6sR>YS}~A1!P~Q?OT{DaIGp$^qpbX{1fNq6uemI++{cAoR59R zMbSHF)+<--+hg&beP!T%zV(+r&sBB!x%=3efTae%^Cn1LU~iafus<|A>C+m~;+Y(Z zEKC9B@vQHPIpk0L2|L>$;PQ1%_^khnv+L3s9M48i72IzTUU>Gt@5+xW6;1azu?WoJ zJ6Q4U(Z;(*{12vn3f(y8_{W5hiBqpsyxZaZZXUyx#fK5d10dn?Xl=p1NF zKfcI}KOk<-cR^eJHP$WnSG%oxdFD&=T&7#=8gxIO`pf5PCSV;E7xO_T$vODK)PxC} zPkR^FXU)rCG??=Dn>gQ%=zL9^2NNp7&zOtMpW!EQasDH=hxtXT%Z~j%*)5+ZpL3IG zW7ON~|J=_Q|2&F0x~k{FHraQVBi{Tz+ngIW?V7sGq+AW7ZL^&e!Xjrym*pErRW7Z$$=c-9y*-R!(cOQmq_4fYTz#^}IZiX)?Ty4; z#h6UF490-fclW4#sGHqwzUJ!kzn5yfC+%JI=~2^l)s|P*4PUO?|Nr+_U%vjyrd2iyv)@bCu34pjUu^UFJz*6e m7vFuCAOHK-^?R50Grntf3HmZ;mNf$d1B0ilpUXO@geCxi3p2m~ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_close_focus.png b/src/qt/qdarkstyle/dark/rc/window_close_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..bb7d8c5110eae15b13f177cb4d6469e5c3e3f86f GIT binary patch literal 728 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|Qf+r;B4qMC;ROwndj6B--v@_hg*YEEMHkz{<7A^oXKL;lH#)j7EngH7*CLFj_yk z?s1MMJ>l3j#RbjM46N6@A8MS?J~_!IOJbi_RPArO{&LmxO#iD5_f?dvJs!AZyTH3i zHMS-^uUK|A_AD`1sdKC`&G~4|VDhL<{A-%TEOytya*W>{pUs#d)GA;Th%JN}$KHougv8>#p`pIA`4 z)phR8f(dgkY?v>^&~V{#W!n*_&`#-!SJRu{^w`vSd^1Z3eep5oQPr{|4yRi`G)~KZ z!0lR~@KN&C)h}DUULBbvGdV`KYR{=w?{u*k1@lc0j9D2D@O}vjSl{Dfe4*IsdFX>y zrp+oW`#R#6RX$wG!f-$`gEz?BJ4t8~qqy~AG5@Yj-keW7Jvtm3E+;L0IF&_6Xs_gF zt%KU!cf1&EJ-)?o-r?b`4*eALpIP}?Lp4#@p~zcIA=Zj{YnEWfuTP&I zEKD>vdBb^UR(R4fhs)F5U!7{3e20&B_eY0}8)ql((3o^WbOx(@RZaf)_O{qbx2GLR zn&|S(`-V(LXV88fo5*(#vnTbfeRH4Xb|m}VD_leHU`;+395PWX0^78rLpWbiW_-f7^q%cAgT9J*q~JFnj>3H zd7K494^KbiyF>T-Hu621y+8fyOXCC{`+4GV3Wk214tJP8upTJym}~VQSm+5`L%zVi ht~;x>f8Sqk|DmIKM?+tfHUk3#gQu&X%Q~loCIEI+HLCys literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_close_focus@2x.png b/src/qt/qdarkstyle/dark/rc/window_close_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..692ce24f2f1d6632e0edd5d9e1a1eda38aa3ce50 GIT binary patch literal 1659 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE96&`auY*j>#bS0mhtW&!BQ~L%k z?udZ64JU>Eb%d-|on(=kZNj-gj>lCZOjB!WlB?Q=oMcV6?;Bp^y(roK<=yK#|5qZv zrhT7h_q}Gn)$^~fm#bS`Xyp6yU*~I-P3d8|+8=uMQ{HSkD0t@D+w6DgTQzHUTxb2Z z_{{8YvbG=AD?VkN9k=V-3Ff%{KUcjgJ66V6@p1aM8_fCpCl&5We!Xpun%3o2%fc#| zq-Jk6RF7urE6dq?Ua)q5m810A?sdioziq2u+g{nQ_*t&u_Jo@(uYE&y&tR`;^Zmd0 z+)+J-1uJ9ENl1oq2tJ#AY3jMDdJJ-MeHPhA_UJx)t}DF##FiKqRZwj=GRy$?WuxoE=e?xhA<88+D_tq^D&k~v6*WKEAgLQ$`YW_JT zeFYr9jre>&U(CIKfo)mmt2K5n?!2g!XP7X5dyjcElN%G?j<>$+uXL|sKf<@>%^utS zn?@fh9Dd09JYVG+T9x~bgP~2>Y0@)ACI%kymL+GM85kPwG^L)st<)%R=5GzSj-%C>Rcq>O{EVJ4nOSAzMfiVt+?#x?sJ(*wNd+fi`{Y<1mu}6 z-F($kC;q%=uK~ZI+k)7ui?n8(V=QMnB!4`|(mMZq`?K@Y-+YOi(Qe1+z}&QuQ>bl% z{>{wyIjs(#jeNgl%l(pREK5B#O}wm`<=8^`&r=sU)$Mt^VxRSbrBRNr&t*>f;1_Y~ z?9Jl2(!QS$=JH$Fuc-7`z#Mf-{|5KH+q@56Gd}!3;bqR!75ABY&fea9E{D}Z?5F2r zxl1Wq7sT_26*_k^HvCh_vHnvxv%Q7U!G=T4EXCo(-Bhk;imVI_J1wg(rd;QI-I5{s z{mq1P*Oz^bQ~G&p3KxTifK%5q#m4-`xmR{Ly|%gV^>{~uLl&g`|=JauDbwb|ZNQeLGjx6asKOz%3s_e)W&TfN7ob!AK0 z7G&13RumlwnJ+E1Ui3?yP-&^wRKXMaH%_*kVU`izHcRuiG3S$4L5~jM_Zof~HTVS+!_9Q(a3%(r(k1u@B zmoZb^MpU5gzW4Ok#!;Ln@4jg%@2HDqe-QlKWS`wy`_?D#LgE>Yd6mVSyT)`jzv^Ys zil5WIaXGyayutnXf&{ydc;j!zhyGRhtADauOMagdA!`t}>G8V4{Qo5m75AUro;r84 z@riYUH#l#9 zj5FJ>w0tlt+5h$CN&yb*IObW;n$zW8dfj@)_{uoy<0aJuW38|cQx1n6_bRKIJ|l1I z%>QXu6xpIDEn8(A)zjr0RA_y0&$%n?VFLs z-^3UN8v6HM&Zv#5&yIgn7yW0$f5Ujj&kR!|bx*%GVtmYCqx-)8(#{*N|Fgz*ol4oz zdVT6&llwuBUxx*=I9`}}ZfczP!MAsVww$@1R;s+^#Fnc&ez-XY@aNxUkjk(BI_2Os zMH5?}XVI&~wzQPA#wyRjetY;-<6oH{96ux~F3*gUNc*fCn!e@5Qk!E;AIcvnr|hrDh`#wf?yCCl*!zuq fB?}&2s%I#=}w}I(*z!9&M*qqaahYPeaxBjl5AGZ2t>;Jtfdko^N__r#^ zor)EV+gkhkv58|_WNgq=(?j_#YYu4FGitQRZc%VQz}#ZlIxTV6(#(V1(>5==;538z z-Qp?RWN^5zbSb@Hxf)cw!{w$%km(zkC*oInqaInPvWZp1Q zsnDvkC2^Ok>+HfE3ej_;c1{&w;Hden(l-bH?1MX}?yTXjEUx2&HK^!fL@T^;j| zFzr&>b?=+jbmxcDHm}n1O-K{52~G&=g0+y z8(B7~Z24cA5|EQqq1V{ql6+!E%!fNn=0YY8kCR1j@YU>|sILE6|Adxko#v{}Z`zIX zD?b-;is+V0UM=>Nyq<5ZKkMr9N~2<(L$4+sVl|M?nl&^=Rl#EOot!jp0AUBe}84@E2THbRMOl%Q*w{{yKFJlvx#a8y&Lw_V%lH#1yjl{ z_;REinkb&T|4*94pQuA6{GOYR?@7-sc7yjti!#{OjCvwbR#>l@qBeXn_ zFIZ*Tt$lwb+5C=L6j~g*x1^xqz~+9zZymZmtm=C_bJhk{Jh*v$@}YJwjk_%jtJF?} zKRAAMT2*yLh|>h$Den(#k8?benfm|tS8;EKqK~ydCulG*Ffe$!`njxgN@xNA;Sxih literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_close_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/window_close_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e02b12292d7420b5b829e77b75fc8562923f6738 GIT binary patch literal 1777 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEwquEB))$$JJbN$3++a$fX3umc$eW;E& zVcwyAvub@welDB+>F@KZ?|uILa!&ZAsR`3#%YN3oz0#HY_3iw(yBo{Te?OX`e@bqG zciPhBBf8BM+I=B4O*{3mSYpd@55T5e>&TpZu zj~Kso&)Dhm|Hi`rZN7m%Kq?nUl zNIvK~eD8LilflO|M;{#jcT|db+UJ|!1$PygCq^Gjbgp^4ZT*Hc-n*xNzWM!+`>R{S zqms1L!!28@uGhYCpXt5yco5&lg#z+Y{y81{Z!7*;Wm+5xY%gK zzr{MI#C1*WG6Ur-Xz@Ux?rOrW@K1-QOR-u>252Vy_UZ7l$tmKvmRy=va#Lzo zp^b#@t_y|}ymvjj-?QM+(X9T}6&x2B%m)AM&; z6*wHx3zrg;`++XVbdOr7Y9^r!VYYe?@@tUjaS_(c;@}~ zDeuiDN-!*(B`~vs#UCg4>>{>8(s@}y6iLWA>TE-YTo9} zJi*(+-z#f$O{Z~}&EB;Owyf^dU3N*|UNAA!;fV4F`Hy#Qr*!!rT_>-7rtbY)gV(Fn zjF`=i=reuaI^$I^^IYwpXRH&iJXIHB7W%vMxJyarwWHN8X-+TF9RxmdrM7NzzE!QG zQ^wz!1Gh8gZfXW9OcXWARw3 zzHez;@qy_w@BSWJ8Gmx0ey48MtA>!OPYDbk&6_&fZ_h0d+VM`H zZhnWJ>aXJdozK>*6|gV4G@0ErO`lDmUaR9rmeAkF?ygUC1k0Qhn1f!PY?j!)Iq&>Jv&|1?)oVX$-s!jamz3a)2Pp?0Hg>w}#N6Tg zC>J>M!Uq8!9l2twoR17kUrtnYtS+>XaGa*~J|uc`D!YlQoxRO_f!ii48$Tv@?P0s} z=k;c`hshVtt+h(L%x7U^@bQF|#rZv2wSnF28c#NNH_c zwTh4Jm-wvzXKBH^U*ST><3u~(I#&j?%+~1c`sr7wwktmK@T2vs_y2tGu;O~;5gQg6 yho3I4@mtNG{@h+S^=HNI*SAxr$CioxXN!9yzu;S(+FAw%1_n=8KbLh*2~7Z1pkucH literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_grip.png b/src/qt/qdarkstyle/dark/rc/window_grip.png new file mode 100644 index 0000000000000000000000000000000000000000..db9ccb8775bf9c6a85affd83d04f8e1460b94592 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|TRd(g?t;z=d*6P5@2La%bJ{2|Bn{`Aj3d<<8XREUTx#4J3% z($3!V03Z7~hCPM%@4d)A7=KWIPj-0btU4c|ghS12Hy#{h%K50kD0HW~LFBvCgQjZk z4M$IJvgzwf>v#CSHAbiCz+t6H4^K)x@Mcr}^~aI1NJgB+=DTn0>h+fUnZozvzIv^5 z+K!*=L#s6_$490EmJQR_t^BO0$M>PPo5|_HHO6f}%JOo%qgh*y^fLDS$i9AMwPDN_ z&chF;%{CB-JCG*KRcO0i+`LxW#7O7Z&g|mr{FB)Z?<;&P9K>+oOxL0xCtHk-14Zm- ze0X@ru15Srv3MGTS)08ilj6;Dy^oTM&3-eSSu^A2ju|s%)|~tM^CNFq%C*|lOIku0 Q7#J8lUHx3vIVCg!09diF%K!iX literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_grip@2x.png b/src/qt/qdarkstyle/dark/rc/window_grip@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..30b0639f4404579d03831ca220e0a448e84f505b GIT binary patch literal 712 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE-bY{i;#W&Aa{@5@0#jP}N z0@JGpjrX-|R-fbZb5ORi@_qcnyRzg>fe65r_r;Hn4dPjm(#N5u=x>g#=ZyQ zTECW9-TobQM|95$8=uKPl1ukpFK_Vvq0-6sdfrRl2L2BhCNso8Sjf(3cd$8`ao@pa zXGXh2&B}~?59L)nztm0Dd(BkS#(tWqrk%Z;$*Fotw$2iTyB>Q!{%rlT!=3 zGm}#*JM(Xb@DCj9CsnMXw!Yt?QRe!THR1;6t``5tJ6Qj`Y+SJZ|JRv!IN8|mPY7eG zX}7nuyt}^9e6uhQW1Q>#kl#ITSe)D5?-Ax<__wcX-`a1nU#?baGCH@mdvg?U?4N(^ zV|(cDT?Y=cGPUvXd$auDn}7a!@RV}XTJ74NEY>yLHdi<-^txgl`wUp_U$`z+=NZ3R z{DmcBZx%Yb)Gd>OJ@0w4lq^Uv60Tdx4UI@8$Um z{2SvJ*o)kK{b~N3S^F}lAD;Ct`%I46?Q@%QPG8?=bAJ8IH@8zJo1T-8o>h`KUt;!N Q1_lNOPgg&ebxsLQ0G_2c&j0`b literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_grip_disabled.png b/src/qt/qdarkstyle/dark/rc/window_grip_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..97c0e0f90b2e337a2105c9ece6fad1e0e9af082a GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|R4y@Up%>p*{YyvT4(3Z-Xjq#F$H62vyY-pSlT;h2c?>J63YRJT zPAHr7Gm2?V!L0+uHq#HMto@|z@wnvu`nL63Sxy|*=1pi07ds%fUZsKioo$2mJ5vY2 zJJAf$e;&LjxxJ!ax_Qt2-gDIt77AKE5>D_pIGeIBq=D&&-Up4sf;nqM_caMslvEdf z3)5=Q-xI)KUSr65nQ@*9U)Ad!#SHg%1UG0EZ1}^K^KpfJ#?A)`g-m)oxKbZAJ!jKs zJMHtxtz7us6;AC#!E+5(@W=Z!@@3E65XhIlGt*4&E4wb|ne**4?{acK$ej>rW4?D0 zf3R8pEAIHKsdFbVU5L^aH9B{gF;MY(<&UaZv464&mfITI@Bd5La*gTIpH-)i1ecoq nWmvoQ&^puZ=ezdH&i}b@+0@qmd-@m{7#KWV{an^LB{Ts5T`j!_ literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_grip_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/window_grip_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..7a3d8de6de36c412fb1e00e453faced3dd1b83be GIT binary patch literal 764 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEgbv-M&Nmjcs0f_gxUfO`LJ{)> zhU2XDP0Sm6GdA0~sOTMFRZ`^Y;`oy>q2Sm(iTCHuoXh!h>g({7$o{!Q?}L z0AuFEg$zua4mdwx+H}bI0F%!F=LJkY2b~+3d=5D$F!>yIc3{dm;H6uHR${AyU*13+F$p*p!z3q`A+k9^X{kb};PD|L!Xe{BLV!cZhXfCY6(15FNGpbaIFPpgdY1p}?LjN=hn^@t@WVfhfMO*hB)Yvm~W&+0trB7k!jg5qPB<()? zTqyrB_4d|kua)Ih_m+e|ujkazvN;fQ>gcT*PjZgjz56%w^QHrbThtGL{P9vo?wkeZ zFTVIyZ`Lp?fAFbHlKIWT!t_7xyz)^wBc%uLZ|>|>{L!-KOMk7CoTmAOV5Vu(y+2PM zZ%$_IcAg%5SpCV;HuJgcw>%3zK1uOAc<91XpZQCBPM+Qpak+BAUbg+RvVV6KeZ9s1 zVA+B59yhvnul2iCV9S4{dB^QPFTCTD)~>UQjL0*2R(p2$#=W%{Q|_%vEA4yD&rthH Va{q$%a?=7~sF}i~3`YEl1?H?JqKRQ$?Dc;~Xl&8KV?*E(v zPTKq%9!9ok962&``rOXe;Bz)V{>-SfVf*)clIF%WS1he{1>;sL?PT##JDPo0Aw}c( z+kYyI`wA==<7S*(W!wFa#r{Lcw5wkC)Hoj;TFmz0;9}MfM;EhfcyN$8;^P9wV-F58 z{dn};ylRW^Ug4*UwI<0h@hEY}EzS-+*U(&6Z>GvOhs#FI(3;QZK_gHyKG#ZOlWXnW!06{{m-BhqbOI& z(GqTQrKBOcj$KHI*Qv;kt0l$kwZ*-;Gv`MBp0>H%{;cJ#*ywQP(^1zpiS1nTj`znp zzh%0U=Xw0e*#7q5bKT!&m9Uz+)al`SS_m1sl5-Q^a3TzcCJRNjC1T;6y zc%ZnU;l=~S1q~7p6(=+Ve3*1s^6jmUHj(#OkMQu%V?DyhFUPusfqx#$5+;5*mL)9w zeXL8^`1x3uaParBEaBqkV_|7Fx0cDheR5CbUZ3jpOTh>J`WTe`$Xn*@sUDZsq0^-jW0mp28xO7Dm)`bSfBxy&A20VzX;^mX zuHNIWJiAoTCGUq!_Z2Zt{oW`6UnntXotcT+8q4H_R9-u`jY zzbyAc!u><=C$GcbjovQ&T$yUW;J+>7Z05D=a$Z<(u-h0TRp%9#S#iB`!f*8*b**L_ z%r=I+jPP=dTY7fax#l?y{@>qBPwa2Ff51QGuU2}|r^>W#@u{2FeO`9$Y=6{knGDlw nd!+SCuBP7GG;QmFuk6y@zj<~MvsFP;Q_GPnJD)Om6twbf2)UymvrszZkx&OK z=gOHAtpYXF6B;^qDw;ZrF5H%xyxdRXLx%m&?cc;k|XU01Oxn^Z|4eNuxE%{CNyVRcI)~C z?ms_%K6_NWnql7uC&ri$2aZfUVE4gl>VnNZ*6bg8tywjg*)Q0A4BLKR!0?(y#GD51 ze`~K^U_H+pz+!IDshW}g&~NSrm71l(Y5zD+A7B=CKeIl4q3}8zCvlrVE1{b`={9Ft z)0S*9+j>;+vWdY;)y-$v(?1)iW(SAgS(bN~^Q^xDPw1kn$^X(1c?1Q2ul!MT*Xob? zftoiAk9+NBe(>s9$k%iI@#<2uzYK>08aHN~b^CMe@5djEv$`2qzwla+!N9=4;OXk; Jvd$@?2>`xk#Y6xA literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_grip_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/window_grip_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c1a0e4b1789b65757565e53bf3401ca863a065 GIT binary patch literal 747 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEiWePJYBZHpjN^`PEKe&-dmR1l-d~gF8D(XrQa7$FGb^3x{YkFj zwU#;icEMV$L;Q2Sj3l@3KYMTgr0WN2LR4Q~4YXzP((v$XKXCTuydXR0;`sCrMQs1q zPkEgdugJRO&|&!t>S_58;~HH*thzL#$6EgEKPTO$=ZCl7Uv3*L!T9=svm?tIZhlsQ z39NET;uA#Wl*AI4<&;DdxaE{Y5`^WHgcGFYl!P8I$tejw;F41kcpxOlB>q53j!EnR zvmBG?18zAckp$^|cVzBNoMgwYv2gAA!|&Q}{&sxJakFi`%HCZa^A@~W_{MkQ#GArB z4B{U&D~m;282mp3JIc@8yOa9^oBo~uMsM~R|1OSY`Fp6G@AABpz78B8CQNP!c%aD6 zsCckBopIs8W_L!#L(S@p`yPZoy_a&wE=u+E&V~sO4{mI@@bKWm28jm;CpJVpIM~=Q zLWhDgFjr6<;VY~G|UVP130_TYtwr_UaY6|7Bu zru(}j&ch+_;X|hE2J?!Gwf8@4NMWmJl`r!TJA0ao|M?%zHoo}GuhItm=ez2ARvIht zRopxGbnV8roSEXQJlD6K5}fux{K;D0c;6~hkCV~GjDPdlrp#WPJMsSg#=A35OY*5N zd6ru7{Oz;GkD@nh_wHhSb0+3giH@qO{^f++=Z%UFE}w4SA5zIPhsnONYMQZS+Pn_4 zO+44i?j727@!k6=vlqV&_?%~3QFu1(-ZHb&&e!_kcJ=d268CIjU|?YIboFyt=akR{ E0D#L%s{jB1 literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_minimize.png b/src/qt/qdarkstyle/dark/rc/window_minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c54ebf21606cbae2de731e1f341a9138736c3c GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|P^?r;B4qMC;p2ihRuu0<910+pJAiI($*P!xDISqSggl=1t~~3LZP0%U3P%^?0S0 zeeZeN+5bnHIyyX3zg4@m>|Jn@r|g5-W((dK&zBy4%o$_M?vS(N`}S>f8U9p!|8%0C z`9`bIFVdQ&MBb@ E0E+@mp#T5? literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_minimize@2x.png b/src/qt/qdarkstyle/dark/rc/window_minimize@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5421a369068b0eaf05f975f0270deb1cdd9a208e GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEmUyaiHnBcPU|hp|n2CdXhVO%kDi3Zj zO}diM*3#oVp>fOJh)+=kdsV*tf3j0_`SC463@~88{c!u@nXT-aR;4qKY`oGg@N53N z#mqKq!*;vg)>WPBd28N^+0%PZ=6x18cY0HeXMZ!}tYtS(b{}25q_)2-&nNr!?dDah z;`Sep{1p?Yv+m3NxVTA8-$Wi8^|CX2SQW1Ltlo4eb5<{}fp#+Uo!#3Dk~Zx&k>Cy)N5)(r2TBl2Vbu?Q@1<%Wau=uajf=uNg2W|Kc3>3GX8rUL3!u|Ni-3R)J|- zFRO5{pK#hxCUH0ATiX8n|tohJ;!GX<;lelV*i`ukZQ8v_BFq5@}-Ivu$KgFt9dZ|K0AS8z(OTN6YP|-F|9cQ|WnYdui_@1IYuie{E_%8DB1(qsqL+*QjCUv-&_4_VT+& zBaIx=Ki6vf44&pzsav!3w1p4bj=6sE&MW%Ql&Zee_1>BmseRXM?esQ~n5V0s%Q~loCIIcNg)smC literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_minimize_focus.png b/src/qt/qdarkstyle/dark/rc/window_minimize_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcd083c004be54194760c37db2ff619d15cb5a8 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|P^Yr;B4qMC;p2ihPG0L|Pu!PqUs-ApB%rBe#Nq3}@r9Yf7&zxIEuGuwPZ<DvE3lY9nfZo+fq}u()z4*} HQ$iB}pw>$q literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_minimize_focus@2x.png b/src/qt/qdarkstyle/dark/rc/window_minimize_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2a4c868e09d8e5fc744b5e1beff193ed918b8027 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hELUBesZH{LgN4|Q$R zZ0p_EnCY0qCh7RzFycwv*0YfX|Mpj$Yk6Py@Z3}e7-(?ZV88uc*_~Bd*JNU|GzBsFn`nN}$oKNbj?rmH0I$ZtwRkz&VKjj@BDYC$v$-r|| XU3{DMLEf5x`5-Y*S3j3^P6bP0l+XkKnP^Yk literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_minimize_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/window_minimize_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5a515c806bac1fa3038baaf2747be22f8ded802f GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEWi5CWX5mq(_fzr(pSq(T{*owQ*KsX zby@MRf3|v$p5I#fs{Z?@Nl$L&I2ranPGQ(7o2I#iNlo@>q}71~OPFWauUp_Qre}L3 z(#T4F_4{0|k>z->D{tAwoO?|tmKwi%?vNREeR?g2?wWNUubtt) zE5p!n=lAjSd-L0vw%oRp>O9eAZ+7T()B75|Y}aS06IS&-%CBxOf6#Bj_+w&Y(a(cI zi?`mY-y5|0eOvCL%r7lEk<&`mmF9agFdbZV<%%84aUscb9(OtR`rh6q|2v<>`37(4 zbJ38gw}cLQauqW~EX?UA;)8<;KV7^VB!)U$?QoO}K&czzxPrbE*~!B`$om!pWueasRPP zjFVjJZ6@)#cm>Qd{Gwd{t6f&0{Yd0{`NG-HqeI{8=EEDHK<~4bF^JFtjmPwen9pGsA$5L`Mae8AYlYZ{=qR-0B&CzqUjvFnA zT7Tcjft%;a<0BKB7_Kw>PxJj;yW7g`%7d-5j6D~Wt8e|taKK@ngZ8$^K3i4`uVfFA zeQstLCUE#b^0Jc;E-siSaI4|3;r`E}2cEhtkrigy5xw)x)oYfDU+gU|WcVyRF2(Z;k zaf{(9Q^;c809^-DFmrMh^RB#>tgW|HC5|bl?PC0JH1F%%U7O`Xc^J>IOt+27d-rzF ziV&^(MaQ@%Znh0QzSFyhmErl)R+far#_uA-{uQr~FTKb4t87(ndqeE~8LG#mS7h2S zL>TPx-}cyMijPo6!&{5T4F29~c1n^4&vI_>)th=Cy&?CuszIEWYL5e3+xM*8+_!UF z3hMa{ex)&VsB||@wVYh5Ab2C4q4B+kN*A}J(XJY{Iah+?k|bjn^1IAp3sq@JX-KTt zbLpM6dO@eKO9pcrck2o1xqfT%a}<;XcW|$~&y~#_!X40S=CGCFY6e!OOQrmRF73O1 zHT?(jvK?1dF)*)Qo4V4d;ehwr)Rl$}4CU6-XXoqscQg9(+em)N+c913;0hDR9r1c> z`^D|9+BPsuKe#w-9N1nZ}CyxuSMxo0`UHzwgW zds+23YVEG;Cq67=yuzopr0IU^%ZU6uP literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_undock_disabled.png b/src/qt/qdarkstyle/dark/rc/window_undock_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..6a609492b3c210874af9e9a0d5280d3b1b1da87b GIT binary patch literal 536 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VnJPZ!6Kh}O5$>^%-Uh#cELolBGBYV6AH9c7}9F+J-pMI2GoTdTKA#3g2ql?8|1 z(WPNBF;gZrU2xsZp=5FE;=zR$J2?JHayN7$JhrcQynGXMg@qv}D*51{&o5v7Hk4uDVfe*&q3C+CaO0(} zSp_+F8N9+SEa%#g=Nh}RVfPA+@Flj{S59+HVX#}XUy!-A5zvL7}H_26L#<(cbG%=BuvgQju7nd)v5dy}tkaz00oa@%i`j&z~GTv3QaOkH=$% ql=y896FVlg&9nXX@vg%Uru5qlOHUR>on&BOVDNPHb6Mw<&;$Uc+~#2b literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_undock_disabled@2x.png b/src/qt/qdarkstyle/dark/rc/window_undock_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c2e1b8fa72ffb5b98fe2e47e0445f629cea7ac34 GIT binary patch literal 924 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE{y$;O$tMqp1m1e_G!6;v?Ee{TM%eO1pMhKo++SNX-Yo%wJjRec)*}j{1Pc}UJ zr*HG&&vw64jEvu$W8!LEG)-|gQ|`h>HuLj5O&V|BP{g=KH_$r{oXyw99N%W@di>l>I~c%GG{6d#*=LFpPaZ`QwVW zds}7q9ON+Hx#n}6?&ci^Aq<;%Pq?uv+-}GLGnYMM*4QcdiGAIhw1mG3b5s(h-_&Df zs5yATeRZ0}0mda9Gs<#*SLUY`6+<#0cj>QMz#8LHapB_KyBbb0;ttoQ?qw@bJeqT1j`#I=QN=af z4Gou-xNf#`e@ZoB|Fgb-N9zx*-;Ev1KK@neN!k1%L+Y%^Za=;~M+_IeVTe0&OeeqO z%!l@>12Z^Mi?iyq*Dy`UbuiOnxXG5X7%MaRX-$KO#f6|pcmKOZ=;y3hD|ldIz>Sb- z#tf0mrYAorc80XwS=`ziYRrB^#hvHj&K>{m6zH-{c-(R?W#Z>Uvuzth3|qSI+HA07 z{!tw>@6~1H&dyHxw7I4Ivt%Q(TOAGrDan1cSew0ttEPBYhj2kcWXrlhhRsS`H`^XB z<%o=BkV-aZNO2L_e6XDNmaO2RUHWd*#O~`>^T|arpU_{lK$PQ8Qj*p$x0Y=W{XSG= zU-lJ{>(q$QW8qPMlziUhrF5OKiM{=K{nm3wg5$%(8LR@=%ufijcu`~|w^wzO$4T>b z|IU3#T$bs~aEtMcNT!;97xU%Pox5J2pMU3XOk)*S>!P-wyqbI$z8uSW-Os?lz~JfX K=d#Wzp$P!)D4Dka literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_undock_focus.png b/src/qt/qdarkstyle/dark/rc/window_undock_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..d6eebbdc272a109c820bdc7711cbbac286921d9f GIT binary patch literal 503 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}oCO|{#S9F5M?jcysy3fA z0|VnqPZ!6Kh}O5$HhLWn5NZ2AIb|bjyu%gq6$uLk9c!31d9`9|7-Lxkr~ApuxJ-W} zY!T^cB`)sB)fTj&Kfrp&4vi}-cOGA;X0~;^uTOT{xA}RKiqHRldZ(ISd`9WT75yu< z)P-dOQv&!7WVx&tYxZ>y=IWLGCBr>oRZ-Ex!=?<`g1zil-(+oh>7=n~g^Rn$@&rDH z?5uE+yX=|=%5N@LVv>9pAuaeky4ZSo&mH~8OQM_FpH2&Vu-}CJ$5!@Bsc{!Wa+u## z&tLgrq7Ek~2h*(6eDmIYJMq)FA@3vSf#-)0bnH|)>tuUJoVP!7@^@*ry=<%>rYQtJ zv^gMt_>6OgxAMNbx|^k>8fN$_OZ-;2rDfK{_Wl1`hwG1DKbSX#b;FahZ=SAdW&L0( zWxd?X{O*F1(~J)7at%U%N{-g?JZC6wxWTxn#CB!J&Lz=K_jWZ-v+h{R#AEiDCBte~ zPzUpZqYqa9lQz6?y{^=I4|Bwv4$;evxfgsVT$s;g@J>C6ucWoBeZfJwhJcq62clD| zmu;?^c55NytH>*5n-tBsPLW{WT|Ffe$!`njxg HN@xNAO0(1b literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_undock_focus@2x.png b/src/qt/qdarkstyle/dark/rc/window_undock_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1aef06053dae8b69236fd2d7d30b6b560798d0de GIT binary patch literal 866 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE zL|@@__|8z`deP8B@_~ou`Qu;JEE1<~cI{=TYB^i|iQxikhGO)Ug1wvz*EPIZ;3V&G0)aX>IM4?co(GzReW)VZUS6F^z5aPBJ@O-}Swo zL#AQD!D~Mdz0(#Z9f%!N5Yd~8}AJ@ z&I8*RZ>uogFiV(ygZ;u5L93t(_qIHan|eA~;hV|q`I@`(56xPrAduSl`OSg3LH7IG zuHGs*>&9NpI#;li|A5|QHye)k3~@TV1%@Z)o4#UU%wHb$UF?L&YT-rC5*|NcY&9`a67GMTBXk-n-yz2VN9Z{54HS0!)+HM~oIzV&j;4t0i| z?<^RUk2*P*WQ$Js^{CEg+;rb%;R*qxN2lLQZmz zN_kb( z+Sh+g*lMy$Cr(qSF;RTY*>FKvxOI_}yT9*?Uonj5d>Quph;$!#-u3#9nc^GH1kLlQ zxqW*X>lYk;IGy=Vg46Bo{1H*dbQ$=4M0ont#Lj}1ao{ma*=&=|ev+4LWS<{zXq~xuqv7#csOU`ui*|WPHtPGkbElU9^qr4j#0Vdbw4R z$*=KYTfw4R&ls2jC(drMEoWhPxqe$^+^Ggz9?Re2?<>tj%hyido-$+FzHQsQ+3eg( z8^ld7*zUWa#`v>QEZ$sgjpuS#m#1;9fBU-gtzW-(E>C6tGNaqL>yJ~sreEsGOhH%2 zhZ~-jtgim^zCh2m_K~QKnX`HIYf zH|w5jrJgjeb!O$7sYHL=BtwUwhM9OR`H%=_RuilofH0Q-Kjh8ir(BXKk%;TO+?c{y%6IA rQ{&?&*t)nEz5J0s|9oAMEra^Z%8B2~BX2S=Ffe$!`njxgN@xNAtt#hF literal 0 HcmV?d00001 diff --git a/src/qt/qdarkstyle/dark/rc/window_undock_pressed@2x.png b/src/qt/qdarkstyle/dark/rc/window_undock_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..677ded425131dfc7f4fa9d81bea8f81097e4b1de GIT binary patch literal 905 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEQiO_h$;rlXoHTRWaK8_%rORTA4?UAN9f4?dIeDoaySF6&g4GWmu*^GD3w(vJ{l9%XX%HTN|F3_c*BY5~r+q!hS9@X%> zR_t5~X+85;*Jv`Vbu3{CV%Sn)SN%D3C*Q32r#BiT+1E_Jv6G*lVQs_I*JhWlpDz7i z%Czg(+2S6>b_T|45_}orbKIJqGi-al=j+5qzLv*p(?qV7{w;Vp>%mX?oJTg1?I69r zbJV@1ZP^cS)IR*N($??Z-t!ONu3cwW_~G6I=VPVw&!-1Bo)>fMkW}0GC+BmV{^}hD zAq<;%Pq?uv+-}GLGu1vZhS+eFe(isA-9*he8(_U&u&5^hPlBfSAMi11B7re7m$> zFvo8G@Z^YYaX&|4G(+^20{MmsNsJkfT_u!SWS22~?a~mDU{l;T=UT(upVOuv`SIzG z(~(PGot1iC)U0kkP?T!D;emYNoDVVw9z|UG?|8iR+(90bbFLn{g?=vHz~!)w@#YGK z6zK`Q*qQTxGj7UQ|KaU^sjj8G7o`|mmR?%s!Ro+sd1-DS*MbcTU(dXBYz4~!M%{NM z`4(J^1#D%D@6zy8$xdiUb@^7o^QU*}X`l{plr-F5zF z&MM`cz~52_KG?odT6kcCj?*kZrvf4+HzJMh;wK?a5y zbC>3e_uFSj-rmaeAmnCUQe Date: Tue, 16 Jan 2024 13:40:40 +0600 Subject: [PATCH 0003/1190] Fixed active menu items in QMenuBar being vertically offset --- src/qt/qdarkstyle/dark/darkstyle.qss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index d785d6078..96e883b2b 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -140,6 +140,7 @@ QStatusBar QToolTip { QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; + padding: 0px; } /* QCheckBox -------------------------------------------------------------- @@ -376,8 +377,6 @@ QMenuBar::item:pressed { border: 0px solid #455364; background-color: #1A72BB; color: #DFE1E2; - margin-bottom: 0px; - padding-bottom: 0px; } /* QMenu ------------------------------------------------------------------ From b4bdfa70b6a49fe159c71c118a021858650e35cd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 16 Jan 2024 14:58:41 +0600 Subject: [PATCH 0004/1190] Finalize dynamic dark mode switching Make QMenuBar items spaced identically --- src/qt/qdarkstyle/dark/darkstyle.qss | 3 ++- src/qt/qt_mainwindow.hpp | 1 + src/qt/qt_styleoverride.cpp | 3 ++- src/qt/qt_winrawinputfilter.cpp | 29 ++++++++++++++++++++++++---- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 96e883b2b..4c433c2a9 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -362,7 +362,8 @@ QMenuBar:focus { QMenuBar::item { background: transparent; - padding: 4px; + padding-left: 7px; + padding-right: 7px; } QMenuBar::item:selected { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 553f9602c..049747130 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -178,6 +178,7 @@ private: friend class ProgSettings; friend class RendererCommon; friend class RendererStack; // For UI variable access by non-primary renderer windows. + friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. }; #endif // QT_MAINWINDOW_HPP diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp index fab111172..60a7162a5 100644 --- a/src/qt/qt_styleoverride.cpp +++ b/src/qt/qt_styleoverride.cpp @@ -56,7 +56,8 @@ StyleOverride::polish(QWidget *widget) } widget->setWindowFlag(Qt::WindowContextHelpButtonHint, false); #ifdef Q_OS_WINDOWS - BOOL DarkMode = TRUE; + extern bool windows_is_light_theme(); + BOOL DarkMode = !windows_is_light_theme(); DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); #endif } diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 57fd44126..6032c9fca 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -50,11 +51,13 @@ #include <86box/mouse.h> #include <86box/plat.h> #include <86box/86box.h> +#include <86box/video.h> #include #include #include "qt_rendererstack.hpp" +#include "ui_qt_mainwindow.h" bool windows_is_light_theme() { // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application @@ -170,13 +173,31 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess QTextStream ts(&f); qApp->setStyleSheet(ts.readAll()); } - // From Dolphin emulator code: - // TODO: When switching from light to dark, the window decorations remain light. Qt seems very - // convinced that it needs to change these in response to this message, so even if we set them - // to dark here, Qt sets them back to light afterwards. + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = TRUE; + DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); + window->ui->stackedWidget->switchRenderer((RendererStack::Renderer) vid_api); + for (int i = 1; i < MONITORS_NUM; i++) { + if (window->renderers[i] && !window->renderers[i]->isHidden()) + window->renderers[i]->switchRenderer((RendererStack::Renderer) vid_api); + } + }); } else { qApp->setStyleSheet(""); + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = FALSE; + DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); + }); } + + QTimer::singleShot(1000, [this] () { + window->resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { + if (window->renderers[i] && !window->renderers[i]->isHidden()) { + window->resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + } + } + }); } /* Stop processing of Alt-F4 */ From b6582383337e926c719c96a9ee36b9100d42d074 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 16 Jan 2024 17:11:33 +0600 Subject: [PATCH 0005/1190] Force all widgets to be embedded windows on Windows --- src/qt/qt_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index afe3a9469..b9e608103 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -176,6 +176,7 @@ main(int argc, char *argv[]) #ifdef Q_OS_WINDOWS Q_INIT_RESOURCE(darkstyle); + QApplication::SetAttribute(Qt::AA_NativeWindows); if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); From 25ec6f65c45001bb4669b584e4722df6688c1a6c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 00:40:35 +0600 Subject: [PATCH 0006/1190] Fix incorrect casing --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index b9e608103..23fafc3ce 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -176,7 +176,7 @@ main(int argc, char *argv[]) #ifdef Q_OS_WINDOWS Q_INIT_RESOURCE(darkstyle); - QApplication::SetAttribute(Qt::AA_NativeWindows); + QApplication::setAttribute(Qt::AA_NativeWindows); if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); From fe3aab2a0e6c32b0ef377a676b601dec1de479e6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 00:56:07 +0600 Subject: [PATCH 0007/1190] Only the main window and its childs should be native widgets --- src/qt/qt_main.cpp | 1 - src/qt/qt_styleoverride.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 23fafc3ce..afe3a9469 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -176,7 +176,6 @@ main(int argc, char *argv[]) #ifdef Q_OS_WINDOWS Q_INIT_RESOURCE(darkstyle); - QApplication::setAttribute(Qt::AA_NativeWindows); if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp index 60a7162a5..43a9d9980 100644 --- a/src/qt/qt_styleoverride.cpp +++ b/src/qt/qt_styleoverride.cpp @@ -16,6 +16,8 @@ */ #include "qt_styleoverride.hpp" +#include "qt_mainwindow.hpp" + #include #include @@ -26,6 +28,8 @@ #endif #endif +extern MainWindow* main_window; + int StyleOverride::styleHint( StyleHint hint, @@ -59,6 +63,9 @@ StyleOverride::polish(QWidget *widget) extern bool windows_is_light_theme(); BOOL DarkMode = !windows_is_light_theme(); DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); + if (main_window->isAncestorOf(widget)) { + widget->setAttribute(Qt::WA_NativeWindow); + } #endif } From 50e1a8846362d4bb94d87a1ebcea58ae53d9a2b1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 01:26:11 +0600 Subject: [PATCH 0008/1190] Revert "Only the main window and its childs should be native widgets" This reverts commit fe3aab2a0e6c32b0ef377a676b601dec1de479e6. --- src/qt/qt_main.cpp | 1 + src/qt/qt_styleoverride.cpp | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index afe3a9469..23fafc3ce 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -176,6 +176,7 @@ main(int argc, char *argv[]) #ifdef Q_OS_WINDOWS Q_INIT_RESOURCE(darkstyle); + QApplication::setAttribute(Qt::AA_NativeWindows); if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp index 43a9d9980..60a7162a5 100644 --- a/src/qt/qt_styleoverride.cpp +++ b/src/qt/qt_styleoverride.cpp @@ -16,8 +16,6 @@ */ #include "qt_styleoverride.hpp" -#include "qt_mainwindow.hpp" - #include #include @@ -28,8 +26,6 @@ #endif #endif -extern MainWindow* main_window; - int StyleOverride::styleHint( StyleHint hint, @@ -63,9 +59,6 @@ StyleOverride::polish(QWidget *widget) extern bool windows_is_light_theme(); BOOL DarkMode = !windows_is_light_theme(); DwmSetWindowAttribute((HWND)widget->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); - if (main_window->isAncestorOf(widget)) { - widget->setAttribute(Qt::WA_NativeWindow); - } #endif } From dd37f51aace6a0a99a6bee425e1069c114b014d3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 01:28:33 +0600 Subject: [PATCH 0009/1190] Grayscale colors --- src/qt/qdarkstyle/dark/darkstyle.qss | 715 ++++++++++++++------------- 1 file changed, 359 insertions(+), 356 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 4c433c2a9..d119b5410 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -22,6 +22,9 @@ See Qt documentation: Resetting everything helps to unify styles across different operating systems --------------------------------------------------------------------------- */ + +/* Changed to be fully grayscale. */ + * { padding: 0px; margin: 0px; @@ -41,27 +44,27 @@ QToolBar * { --------------------------------------------------------------------------- */ QWidget { - background-color: #19232D; - border: 0px solid #455364; + background-color: #222222; + border: 0px solid #525252; padding: 0px; - color: #DFE1E2; - selection-background-color: #346792; - selection-color: #DFE1E2; + color: #E3E3E3; + selection-background-color: #616161; + selection-color: #E3E3E3; } QWidget:disabled { - background-color: #19232D; - color: #788D9C; - selection-background-color: #26486B; - selection-color: #788D9C; + background-color: #222222; + color: #8B8B8B; + selection-background-color: #444444; + selection-color: #8B8B8B; } QWidget::item:selected { - background-color: #346792; + background-color: #616161; } QWidget::item:hover:!selected { - background-color: #1A72BB; + background-color: #666666; } /* QMainWindow ------------------------------------------------------------ @@ -71,15 +74,15 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { - background-color: #455364; - border: 0px solid #19232D; + background-color: #525252; + border: 0px solid #222222; spacing: 0px; padding: 2px; } QMainWindow::separator:hover { - background-color: #60798B; - border: 0px solid #1A72BB; + background-color: #767676; + border: 0px solid #666666; } QMainWindow::separator:horizontal { @@ -102,8 +105,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip --------------------------------------------------------------------------- */ QToolTip { - background-color: #346792; - color: #DFE1E2; + background-color: #616161; + color: #E3E3E3; /* If you remove the border property, background stops working on Windows */ border: none; /* Remove padding, for fix combo box tooltip */ @@ -117,9 +120,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { - border: 1px solid #455364; + border: 1px solid #525252; /* Fixes Spyder #9120, #9121 */ - background: #455364; + background: #525252; /* Fixes #205, white vertical borders separating items */ } @@ -128,9 +131,9 @@ QStatusBar::item { } QStatusBar QToolTip { - background-color: #1A72BB; - border: 1px solid #19232D; - color: #19232D; + background-color: #666666; + border: 1px solid #222222; + color: #222222; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ @@ -149,8 +152,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; spacing: 4px; outline: none; padding-top: 4px; @@ -162,8 +165,8 @@ QCheckBox:focus { } QCheckBox QWidget:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } QCheckBox::indicator { @@ -217,7 +220,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { font-weight: bold; - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; padding: 2px; margin-top: 6px; @@ -275,8 +278,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; spacing: 4px; padding-top: 4px; padding-bottom: 4px; @@ -289,15 +292,15 @@ QRadioButton:focus { } QRadioButton:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; border: none; outline: none; } QRadioButton QWidget { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; spacing: 0px; padding: 0px; outline: none; @@ -349,15 +352,15 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { - background-color: #19232D; + background-color: #222222; padding: 2px; - border: 1px solid #455364; - color: #DFE1E2; - selection-background-color: #1A72BB; + border: 1px solid #525252; + color: #E3E3E3; + selection-background-color: #666666; } QMenuBar:focus { - border: 1px solid #346792; + border: 1px solid #616161; } QMenuBar::item { @@ -369,15 +372,15 @@ QMenuBar::item { QMenuBar::item:selected { padding: 4px; background: transparent; - border: 0px solid #455364; - background-color: #1A72BB; + border: 0px solid #525252; + background-color: #666666; } QMenuBar::item:pressed { padding: 4px; - border: 0px solid #455364; - background-color: #1A72BB; - color: #DFE1E2; + border: 0px solid #525252; + background-color: #666666; + color: #E3E3E3; } /* QMenu ------------------------------------------------------------------ @@ -386,33 +389,33 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu --------------------------------------------------------------------------- */ QMenu { - border: 0px solid #455364; - color: #DFE1E2; + border: 0px solid #525252; + color: #E3E3E3; margin: 0px; - background-color: #37414F; - selection-background-color: #1A72BB; + background-color: #414141; + selection-background-color: #666666; } QMenu::separator { height: 1px; - background-color: #60798B; - color: #DFE1E2; + background-color: #767676; + color: #E3E3E3; } QMenu::item { - background-color: #37414F; + background-color: #414141; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ - border: 1px transparent #455364; + border: 1px transparent #525252; } QMenu::item:selected { - color: #DFE1E2; - background-color: #1A72BB; + color: #E3E3E3; + background-color: #666666; } QMenu::item:pressed { - background-color: #1A72BB; + background-color: #666666; } QMenu::icon { @@ -512,9 +515,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { - alternate-background-color: #19232D; - color: #DFE1E2; - border: 1px solid #455364; + alternate-background-color: #222222; + color: #E3E3E3; + border: 1px solid #525252; border-radius: 4px; } @@ -528,24 +531,24 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { - background-color: #19232D; - border: 1px solid #455364; + background-color: #222222; + border: 1px solid #525252; border-radius: 4px; /* fix #159 */ padding: 2px; /* remove min-height to fix #244 */ - color: #DFE1E2; + color: #E3E3E3; } QAbstractScrollArea:disabled { - color: #788D9C; + color: #8B8B8B; } /* QScrollArea ------------------------------------------------------------ --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { - background-color: #19232D; + background-color: #222222; } /* QScrollBar ------------------------------------------------------------- @@ -556,53 +559,53 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar QScrollBar:horizontal { height: 16px; margin: 2px 16px 2px 16px; - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; - background-color: #19232D; + background-color: #222222; } QScrollBar:vertical { - background-color: #19232D; + background-color: #222222; width: 16px; margin: 16px 2px 16px 2px; - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; } QScrollBar::handle:horizontal { - background-color: #60798B; - border: 1px solid #455364; + background-color: #767676; + border: 1px solid #525252; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:hover { - background-color: #346792; - border: #346792; + background-color: #616161; + border: #616161; border-radius: 4px; min-width: 8px; } QScrollBar::handle:horizontal:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QScrollBar::handle:vertical { - background-color: #60798B; - border: 1px solid #455364; + background-color: #767676; + border: 1px solid #525252; min-height: 8px; border-radius: 4px; } QScrollBar::handle:vertical:hover { - background-color: #346792; - border: #346792; + background-color: #616161; + border: #616161; border-radius: 4px; min-height: 8px; } QScrollBar::handle:vertical:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QScrollBar::add-line:horizontal { @@ -695,38 +698,38 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; border-radius: 4px; - border: 1px solid #455364; + border: 1px solid #525252; } QTextEdit:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QTextEdit:selected { - background: #346792; - color: #455364; + background: #616161; + color: #525252; } /* QPlainTextEdit --------------------------------------------------------- --------------------------------------------------------------------------- */ QPlainTextEdit { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; border-radius: 4px; - border: 1px solid #455364; + border: 1px solid #525252; } QPlainTextEdit:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QPlainTextEdit:selected { - background: #346792; - color: #455364; + background: #616161; + color: #525252; } /* QSizeGrip -------------------------------------------------------------- @@ -747,8 +750,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { - background-color: #19232D; - border-bottom: 1px solid #19232D; + background-color: #222222; + border-bottom: 1px solid #222222; padding: 1px; font-weight: bold; spacing: 2px; @@ -756,7 +759,7 @@ QToolBar { QToolBar:disabled { /* Fixes #272 */ - background-color: #19232D; + background-color: #222222; } QToolBar::handle:horizontal { @@ -780,9 +783,9 @@ QToolBar::separator:vertical { } QToolButton#qt_toolbar_ext_button { - background: #19232D; + background: #222222; border: 0px; - color: #DFE1E2; + color: #E3E3E3; image: url(":/qss_icons/dark/rc/arrow_right.png"); } @@ -790,9 +793,9 @@ QToolButton#qt_toolbar_ext_button { --------------------------------------------------------------------------- */ QAbstractSpinBox { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; /* This fixes 103, 111 */ padding-top: 2px; /* This fixes 103, 111 */ @@ -804,11 +807,11 @@ QAbstractSpinBox { } QAbstractSpinBox:up-button { - background-color: transparent #19232D; + background-color: transparent #222222; subcontrol-origin: border; subcontrol-position: top right; - border-left: 1px solid #455364; - border-bottom: 1px solid #455364; + border-left: 1px solid #525252; + border-bottom: 1px solid #525252; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; @@ -827,11 +830,11 @@ QAbstractSpinBox::up-arrow:hover { } QAbstractSpinBox:down-button { - background-color: transparent #19232D; + background-color: transparent #222222; subcontrol-origin: border; subcontrol-position: bottom right; - border-left: 1px solid #455364; - border-top: 1px solid #455364; + border-left: 1px solid #525252; + border-top: 1px solid #525252; border-top-left-radius: 0; border-bottom-left-radius: 0; margin: 1px; @@ -850,17 +853,17 @@ QAbstractSpinBox::down-arrow:hover { } QAbstractSpinBox:hover { - border: 1px solid #346792; - color: #DFE1E2; + border: 1px solid #616161; + color: #E3E3E3; } QAbstractSpinBox:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QAbstractSpinBox:selected { - background: #346792; - color: #455364; + background: #616161; + color: #525252; } /* ------------------------------------------------------------------------ */ @@ -872,17 +875,17 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { - background-color: #19232D; - border: 0px solid #455364; + background-color: #222222; + border: 0px solid #525252; padding: 2px; margin: 0px; - color: #DFE1E2; + color: #E3E3E3; } QLabel:disabled { - background-color: #19232D; - border: 0px solid #455364; - color: #788D9C; + background-color: #222222; + border: 0px solid #525252; + color: #8B8B8B; } /* QTextBrowser ----------------------------------------------------------- @@ -891,68 +894,68 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; border-radius: 4px; } QTextBrowser:disabled { - background-color: #19232D; - border: 1px solid #455364; - color: #788D9C; + background-color: #222222; + border: 1px solid #525252; + color: #8B8B8B; border-radius: 4px; } QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { - border: 1px solid #455364; + border: 1px solid #525252; } /* QGraphicsView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QGraphicsView { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; border-radius: 4px; } QGraphicsView:disabled { - background-color: #19232D; - border: 1px solid #455364; - color: #788D9C; + background-color: #222222; + border: 1px solid #525252; + color: #8B8B8B; border-radius: 4px; } QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { - border: 1px solid #455364; + border: 1px solid #525252; } /* QCalendarWidget -------------------------------------------------------- --------------------------------------------------------------------------- */ QCalendarWidget { - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; } QCalendarWidget:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } /* QLCDNumber ------------------------------------------------------------- --------------------------------------------------------------------------- */ QLCDNumber { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; } QLCDNumber:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } /* QProgressBar ----------------------------------------------------------- @@ -961,30 +964,30 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; border-radius: 4px; text-align: center; } QProgressBar:disabled { - background-color: #19232D; - border: 1px solid #455364; - color: #788D9C; + background-color: #222222; + border: 1px solid #525252; + color: #8B8B8B; border-radius: 4px; text-align: center; } QProgressBar::chunk { - background-color: #346792; - color: #19232D; + background-color: #616161; + color: #222222; border-radius: 4px; } QProgressBar::chunk:disabled { - background-color: #26486B; - color: #788D9C; + background-color: #444444; + color: #8B8B8B; border-radius: 4px; } @@ -997,8 +1000,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { - background-color: #455364; - color: #DFE1E2; + background-color: #525252; + color: #E3E3E3; border-radius: 4px; padding: 2px; outline: none; @@ -1006,43 +1009,43 @@ QPushButton { } QPushButton:disabled { - background-color: #455364; - color: #788D9C; + background-color: #525252; + color: #8B8B8B; border-radius: 4px; padding: 2px; } QPushButton:checked { - background-color: #60798B; + background-color: #767676; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:disabled { - background-color: #60798B; - color: #788D9C; + background-color: #767676; + color: #8B8B8B; border-radius: 4px; padding: 2px; outline: none; } QPushButton:checked:selected { - background: #60798B; + background: #767676; } QPushButton:hover { - background-color: #54687A; - color: #DFE1E2; + background-color: #666666; + color: #E3E3E3; } QPushButton:pressed { - background-color: #60798B; + background-color: #767676; } QPushButton:selected { - background: #60798B; - color: #DFE1E2; + background: #767676; + color: #E3E3E3; } QPushButton::menu-indicator { @@ -1062,8 +1065,8 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; border-radius: 4px; padding: 2px; outline: none; @@ -1074,53 +1077,53 @@ QToolButton { } QToolButton:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; border-radius: 4px; padding: 2px; } QToolButton:checked { - background-color: #60798B; + background-color: #767676; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:disabled { - background-color: #60798B; - color: #788D9C; + background-color: #767676; + color: #8B8B8B; border-radius: 4px; padding: 2px; outline: none; } QToolButton:checked:hover { - background-color: #54687A; - color: #DFE1E2; + background-color: #666666; + color: #E3E3E3; } QToolButton:checked:pressed { - background-color: #60798B; + background-color: #767676; } QToolButton:checked:selected { - background: #60798B; - color: #DFE1E2; + background: #767676; + color: #E3E3E3; } QToolButton:hover { - background-color: #54687A; - color: #DFE1E2; + background-color: #666666; + color: #E3E3E3; } QToolButton:pressed { - background-color: #60798B; + background-color: #767676; } QToolButton:selected { - background: #60798B; - color: #DFE1E2; + background: #767676; + color: #E3E3E3; } QToolButton[popupMode="0"] { @@ -1139,7 +1142,7 @@ QToolButton[popupMode="1"]::menu-button { QToolButton[popupMode="1"]::menu-button:hover { border: none; - border-left: 1px solid #455364; + border-left: 1px solid #525252; border-radius: 0; } @@ -1157,11 +1160,11 @@ QToolButton::menu-button { } QToolButton::menu-button:hover { - border: 1px solid #346792; + border: 1px solid #616161; } QToolButton::menu-button:checked:hover { - border: 1px solid #346792; + border: 1px solid #616161; } QToolButton::menu-indicator { @@ -1189,8 +1192,8 @@ QToolButton::menu-arrow:hover { --------------------------------------------------------------------------- */ QCommandLinkButton { background-color: transparent; - border: 1px solid #455364; - color: #DFE1E2; + border: 1px solid #525252; + color: #E3E3E3; border-radius: 4px; padding: 0px; margin: 0px; @@ -1198,7 +1201,7 @@ QCommandLinkButton { QCommandLinkButton:disabled { background-color: transparent; - color: #788D9C; + color: #8B8B8B; } /* ------------------------------------------------------------------------ */ @@ -1210,9 +1213,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QComboBox { - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; - selection-background-color: #346792; + selection-background-color: #616161; padding-left: 4px; padding-right: 4px; /* padding-right = 36; 4 + 16*2 See scrollbar size */ @@ -1226,41 +1229,41 @@ QComboBox { } QComboBox QAbstractItemView { - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 0; - background-color: #19232D; - selection-background-color: #346792; + background-color: #222222; + selection-background-color: #616161; } QComboBox QAbstractItemView:hover { - background-color: #19232D; - color: #DFE1E2; + background-color: #222222; + color: #E3E3E3; } QComboBox QAbstractItemView:selected { - background: #346792; - color: #455364; + background: #616161; + color: #525252; } QComboBox QAbstractItemView:alternate { - background: #19232D; + background: #222222; } QComboBox:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } QComboBox:hover { - border: 1px solid #346792; + border: 1px solid #616161; } QComboBox:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QComboBox:on { - selection-background-color: #346792; + selection-background-color: #616161; } QComboBox::indicator { @@ -1274,7 +1277,7 @@ QComboBox::indicator { } QComboBox::indicator:alternate { - background: #19232D; + background: #222222; } QComboBox::item { @@ -1290,14 +1293,14 @@ QComboBox::item { } QComboBox::item:alternate { - background: #19232D; + background: #222222; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; - border-left: 1px solid #455364; + border-left: 1px solid #525252; } QComboBox::down-arrow { @@ -1316,7 +1319,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { - background: #19232D; + background: #222222; } QSlider:focus { @@ -1324,48 +1327,48 @@ QSlider:focus { } QSlider::groove:horizontal { - background: #455364; - border: 1px solid #455364; + background: #525252; + border: 1px solid #525252; height: 4px; margin: 0px; border-radius: 4px; } QSlider::groove:vertical { - background: #455364; - border: 1px solid #455364; + background: #525252; + border: 1px solid #525252; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical { - background: #346792; - border: 1px solid #455364; + background: #616161; + border: 1px solid #525252; width: 4px; margin: 0px; border-radius: 4px; } QSlider::add-page:vertical :disabled { - background: #26486B; + background: #444444; } QSlider::sub-page:horizontal { - background: #346792; - border: 1px solid #455364; + background: #616161; + border: 1px solid #525252; height: 4px; margin: 0px; border-radius: 4px; } QSlider::sub-page:horizontal:disabled { - background: #26486B; + background: #444444; } QSlider::handle:horizontal { - background: #9DA9B5; - border: 1px solid #455364; + background: #A9A9A9; + border: 1px solid #525252; width: 8px; height: 8px; margin: -8px 0px; @@ -1373,17 +1376,17 @@ QSlider::handle:horizontal { } QSlider::handle:horizontal:hover { - background: #346792; - border: 1px solid #346792; + background: #616161; + border: 1px solid #616161; } QSlider::handle:horizontal:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QSlider::handle:vertical { - background: #9DA9B5; - border: 1px solid #455364; + background: #A9A9A9; + border: 1px solid #525252; width: 8px; height: 8px; margin: 0 -8px; @@ -1391,12 +1394,12 @@ QSlider::handle:vertical { } QSlider::handle:vertical:hover { - background: #346792; - border: 1px solid #346792; + background: #616161; + border: 1px solid #616161; } QSlider::handle:vertical:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } /* QLineEdit -------------------------------------------------------------- @@ -1405,7 +1408,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { - background-color: #19232D; + background-color: #222222; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; @@ -1413,28 +1416,28 @@ QLineEdit { padding-left: 4px; padding-right: 4px; border-style: solid; - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; - color: #DFE1E2; + color: #E3E3E3; } QLineEdit:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } QLineEdit:hover { - border: 1px solid #346792; - color: #DFE1E2; + border: 1px solid #616161; + color: #E3E3E3; } QLineEdit:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QLineEdit:selected { - background-color: #346792; - color: #455364; + background-color: #616161; + color: #525252; } /* QTabWiget -------------------------------------------------------------- @@ -1444,7 +1447,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabb --------------------------------------------------------------------------- */ QTabWidget { padding: 2px; - selection-background-color: #455364; + selection-background-color: #525252; } QTabWidget QWidget { @@ -1453,7 +1456,7 @@ QTabWidget QWidget { } QTabWidget::pane { - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; margin: 0px; /* Fixes double border inside pane with pyqt5 */ @@ -1461,8 +1464,8 @@ QTabWidget::pane { } QTabWidget::pane:selected { - background-color: #455364; - border: 1px solid #346792; + background-color: #525252; + border: 1px solid #616161; } /* QTabBar ---------------------------------------------------------------- @@ -1500,104 +1503,104 @@ QTabBar::tab, QDockWidget QTabBar::tab { } QTabBar::tab:top:selected:disabled, QDockWidget QTabBar::tab:top:selected:disabled { - border-bottom: 3px solid #26486B; - color: #788D9C; - background-color: #455364; + border-bottom: 3px solid #444444; + color: #8B8B8B; + background-color: #525252; } QTabBar::tab:bottom:selected:disabled, QDockWidget QTabBar::tab:bottom:selected:disabled { - border-top: 3px solid #26486B; - color: #788D9C; - background-color: #455364; + border-top: 3px solid #444444; + color: #8B8B8B; + background-color: #525252; } QTabBar::tab:left:selected:disabled, QDockWidget QTabBar::tab:left:selected:disabled { - border-right: 3px solid #26486B; - color: #788D9C; - background-color: #455364; + border-right: 3px solid #444444; + color: #8B8B8B; + background-color: #525252; } QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:disabled { - border-left: 3px solid #26486B; - color: #788D9C; - background-color: #455364; + border-left: 3px solid #444444; + color: #8B8B8B; + background-color: #525252; } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { - border-bottom: 3px solid #19232D; - color: #788D9C; - background-color: #19232D; + border-bottom: 3px solid #222222; + color: #8B8B8B; + background-color: #222222; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { - border-top: 3px solid #19232D; - color: #788D9C; - background-color: #19232D; + border-top: 3px solid #222222; + color: #8B8B8B; + background-color: #222222; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { - border-right: 3px solid #19232D; - color: #788D9C; - background-color: #19232D; + border-right: 3px solid #222222; + color: #8B8B8B; + background-color: #222222; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { - border-left: 3px solid #19232D; - color: #788D9C; - background-color: #19232D; + border-left: 3px solid #222222; + color: #8B8B8B; + background-color: #222222; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { - border-bottom: 2px solid #19232D; + border-bottom: 2px solid #222222; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { - border-top: 2px solid #19232D; + border-top: 2px solid #222222; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { - border-left: 2px solid #19232D; + border-left: 2px solid #222222; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { - border-right: 2px solid #19232D; + border-right: 2px solid #222222; margin-left: 2px; } QTabBar::tab:top, QDockWidget QTabBar::tab:top { - background-color: #455364; + background-color: #525252; margin-left: 2px; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; min-width: 5px; - border-bottom: 3px solid #455364; + border-bottom: 3px solid #525252; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:selected, QDockWidget QTabBar::tab:top:selected { - background-color: #54687A; - border-bottom: 3px solid #259AE9; + background-color: #666666; + border-bottom: 3px solid #898989; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:top:!selected:hover, QDockWidget QTabBar::tab:top:!selected:hover { - border: 1px solid #1A72BB; - border-bottom: 3px solid #1A72BB; + border: 1px solid #666666; + border-bottom: 3px solid #666666; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { - border-top: 3px solid #455364; - background-color: #455364; + border-top: 3px solid #525252; + background-color: #525252; margin-left: 2px; padding-left: 4px; padding-right: 4px; @@ -1609,22 +1612,22 @@ QTabBar::tab:bottom, QDockWidget QTabBar::tab:bottom { } QTabBar::tab:bottom:selected, QDockWidget QTabBar::tab:bottom:selected { - background-color: #54687A; - border-top: 3px solid #259AE9; + background-color: #666666; + border-top: 3px solid #898989; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } QTabBar::tab:bottom:!selected:hover, QDockWidget QTabBar::tab:bottom:!selected:hover { - border: 1px solid #1A72BB; - border-top: 3px solid #1A72BB; + border: 1px solid #666666; + border-top: 3px solid #666666; /* Fixes spyder-ide/spyder#9766 and #243 */ padding-left: 3px; padding-right: 3px; } QTabBar::tab:left, QDockWidget QTabBar::tab:left { - background-color: #455364; + background-color: #525252; margin-top: 2px; padding-left: 2px; padding-right: 2px; @@ -1636,20 +1639,20 @@ QTabBar::tab:left, QDockWidget QTabBar::tab:left { } QTabBar::tab:left:selected, QDockWidget QTabBar::tab:left:selected { - background-color: #54687A; - border-right: 3px solid #259AE9; + background-color: #666666; + border-right: 3px solid #898989; } QTabBar::tab:left:!selected:hover, QDockWidget QTabBar::tab:left:!selected:hover { - border: 1px solid #1A72BB; - border-right: 3px solid #1A72BB; + border: 1px solid #666666; + border-right: 3px solid #666666; /* Fixes different behavior #271 */ margin-right: 0px; padding-right: -1px; } QTabBar::tab:right, QDockWidget QTabBar::tab:right { - background-color: #455364; + background-color: #525252; margin-top: 2px; padding-left: 2px; padding-right: 2px; @@ -1661,13 +1664,13 @@ QTabBar::tab:right, QDockWidget QTabBar::tab:right { } QTabBar::tab:right:selected, QDockWidget QTabBar::tab:right:selected { - background-color: #54687A; - border-left: 3px solid #259AE9; + background-color: #666666; + border-left: 3px solid #898989; } QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hover { - border: 1px solid #1A72BB; - border-left: 3px solid #1A72BB; + border: 1px solid #666666; + border-left: 3px solid #666666; /* Fixes different behavior #271 */ margin-left: 0px; padding-left: 0px; @@ -1675,17 +1678,17 @@ QTabBar::tab:right:!selected:hover, QDockWidget QTabBar::tab:right:!selected:hov QTabBar QToolButton, QDockWidget QTabBar QToolButton { /* Fixes #136 */ - background-color: #455364; + background-color: #525252; height: 12px; width: 12px; } QTabBar QToolButton:pressed, QDockWidget QTabBar QToolButton:pressed { - background-color: #455364; + background-color: #525252; } QTabBar QToolButton:pressed:hover, QDockWidget QTabBar QToolButton:pressed:hover { - border: 1px solid #346792; + border: 1px solid #616161; } QTabBar QToolButton::left-arrow:enabled, QDockWidget QTabBar QToolButton::left-arrow:enabled { @@ -1708,9 +1711,9 @@ QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::righ --------------------------------------------------------------------------- */ QDockWidget { - outline: 1px solid #455364; - background-color: #19232D; - border: 1px solid #455364; + outline: 1px solid #525252; + background-color: #222222; + border: 1px solid #525252; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); titlebar-normal-icon: url(":/qss_icons/dark/rc/transparent.png"); @@ -1721,7 +1724,7 @@ QDockWidget::title { padding: 3px; spacing: 4px; border: none; - background-color: #455364; + background-color: #525252; } QDockWidget::close-button { @@ -1867,10 +1870,10 @@ QTreeView, QListView, QTableView, QColumnView { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; - gridline-color: #455364; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; + gridline-color: #525252; border-radius: 4px; } @@ -1878,45 +1881,45 @@ QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { - background-color: #19232D; - color: #788D9C; + background-color: #222222; + color: #8B8B8B; } QTreeView:selected, QListView:selected, QTableView:selected, QColumnView:selected { - background-color: #346792; - color: #455364; + background-color: #616161; + color: #525252; } QTreeView:focus, QListView:focus, QTableView:focus, QColumnView:focus { - border: 1px solid #1A72BB; + border: 1px solid #666666; } QTreeView::item:pressed, QListView::item:pressed, QTableView::item:pressed, QColumnView::item:pressed { - background-color: #346792; + background-color: #616161; } QTreeView::item:selected:active, QListView::item:selected:active, QTableView::item:selected:active, QColumnView::item:selected:active { - background-color: #346792; + background-color: #616161; } QTreeView::item:selected:!active, QListView::item:selected:!active, QTableView::item:selected:!active, QColumnView::item:selected:!active { - color: #DFE1E2; - background-color: #37414F; + color: #E3E3E3; + background-color: #414141; } QTreeView::item:!selected:hover, @@ -1924,13 +1927,13 @@ QListView::item:!selected:hover, QTableView::item:!selected:hover, QColumnView::item:!selected:hover { outline: 0; - color: #DFE1E2; - background-color: #37414F; + color: #E3E3E3; + background-color: #414141; } QTableCornerButton::section { - background-color: #19232D; - border: 1px transparent #455364; + background-color: #222222; + border: 1px transparent #525252; border-radius: 0px; } @@ -1940,21 +1943,21 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview --------------------------------------------------------------------------- */ QHeaderView { - background-color: #455364; - border: 0px transparent #455364; + background-color: #525252; + border: 0px transparent #525252; padding: 0; margin: 0; border-radius: 0; } QHeaderView:disabled { - background-color: #455364; - border: 1px transparent #455364; + background-color: #525252; + border: 1px transparent #525252; } QHeaderView::section { - background-color: #455364; - color: #DFE1E2; + background-color: #525252; + color: #E3E3E3; border-radius: 0; text-align: left; font-size: 13px; @@ -1965,15 +1968,15 @@ QHeaderView::section::horizontal { padding-bottom: 0; padding-left: 4px; padding-right: 4px; - border-left: 1px solid #19232D; + border-left: 1px solid #222222; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { - border-left: 1px solid #455364; + border-left: 1px solid #525252; } QHeaderView::section::horizontal:disabled { - color: #788D9C; + color: #8B8B8B; } QHeaderView::section::vertical { @@ -1981,21 +1984,21 @@ QHeaderView::section::vertical { padding-bottom: 0; padding-left: 4px; padding-right: 4px; - border-top: 1px solid #19232D; + border-top: 1px solid #222222; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { - border-top: 1px solid #455364; + border-top: 1px solid #525252; } QHeaderView::section::vertical:disabled { - color: #788D9C; + color: #8B8B8B; } QHeaderView::down-arrow { /* Those settings (border/width/height/background-color) solve bug */ /* transparent arrow background and size */ - background-color: #455364; + background-color: #525252; border: none; height: 12px; width: 12px; @@ -2005,7 +2008,7 @@ QHeaderView::down-arrow { } QHeaderView::up-arrow { - background-color: #455364; + background-color: #525252; border: none; height: 12px; width: 12px; @@ -2022,54 +2025,54 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox QToolBox { padding: 0px; border: 0px; - border: 1px solid #455364; + border: 1px solid #525252; } QToolBox:selected { padding: 0px; - border: 2px solid #346792; + border: 2px solid #616161; } QToolBox::tab { - background-color: #19232D; - border: 1px solid #455364; - color: #DFE1E2; + background-color: #222222; + border: 1px solid #525252; + color: #E3E3E3; border-top-left-radius: 4px; border-top-right-radius: 4px; } QToolBox::tab:disabled { - color: #788D9C; + color: #8B8B8B; } QToolBox::tab:selected { - background-color: #60798B; - border-bottom: 2px solid #346792; + background-color: #767676; + border-bottom: 2px solid #616161; } QToolBox::tab:selected:disabled { - background-color: #455364; - border-bottom: 2px solid #26486B; + background-color: #525252; + border-bottom: 2px solid #444444; } QToolBox::tab:!selected { - background-color: #455364; - border-bottom: 2px solid #455364; + background-color: #525252; + border-bottom: 2px solid #525252; } QToolBox::tab:!selected:disabled { - background-color: #19232D; + background-color: #222222; } QToolBox::tab:hover { - border-color: #1A72BB; - border-bottom: 2px solid #1A72BB; + border-color: #666666; + border-bottom: 2px solid #666666; } QToolBox QScrollArea { padding: 0px; border: 0px; - background-color: #19232D; + background-color: #222222; } /* QFrame ----------------------------------------------------------------- @@ -2083,7 +2086,7 @@ https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color /* (dot) .QFrame fix #141, #126, #123 */ .QFrame { border-radius: 4px; - border: 1px solid #455364; + border: 1px solid #525252; /* No frame */ /* HLine */ /* HLine */ @@ -2091,19 +2094,19 @@ https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color .QFrame[frameShape="0"] { border-radius: 4px; - border: 1px transparent #455364; + border: 1px transparent #525252; } .QFrame[frameShape="4"] { max-height: 2px; border: none; - background-color: #455364; + background-color: #525252; } .QFrame[frameShape="5"] { max-width: 2px; border: none; - background-color: #455364; + background-color: #525252; } /* QSplitter -------------------------------------------------------------- @@ -2112,22 +2115,22 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter --------------------------------------------------------------------------- */ QSplitter { - background-color: #455364; + background-color: #525252; spacing: 0px; padding: 0px; margin: 0px; } QSplitter::handle { - background-color: #455364; - border: 0px solid #19232D; + background-color: #525252; + border: 0px solid #222222; spacing: 0px; padding: 1px; margin: 0px; } QSplitter::handle:hover { - background-color: #9DA9B5; + background-color: #A9A9A9; } QSplitter::handle:horizontal { @@ -2144,9 +2147,9 @@ QSplitter::handle:vertical { --------------------------------------------------------------------------- */ QDateEdit, QDateTimeEdit { - selection-background-color: #346792; + selection-background-color: #616161; border-style: solid; - border: 1px solid #455364; + border: 1px solid #525252; border-radius: 4px; /* This fixes 103, 111 */ padding-top: 2px; @@ -2158,14 +2161,14 @@ QDateEdit, QDateTimeEdit { } QDateEdit:on, QDateTimeEdit:on { - selection-background-color: #346792; + selection-background-color: #616161; } QDateEdit::drop-down, QDateTimeEdit::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 12px; - border-left: 1px solid #455364; + border-left: 1px solid #525252; } QDateEdit::down-arrow, QDateTimeEdit::down-arrow { @@ -2179,23 +2182,23 @@ QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:foc } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { - background-color: #19232D; + background-color: #222222; border-radius: 4px; - border: 1px solid #455364; - selection-background-color: #346792; + border: 1px solid #525252; + selection-background-color: #616161; } /* QAbstractView ---------------------------------------------------------- --------------------------------------------------------------------------- */ QAbstractView:hover { - border: 1px solid #346792; - color: #DFE1E2; + border: 1px solid #616161; + color: #E3E3E3; } QAbstractView:selected { - background: #346792; - color: #455364; + background: #616161; + color: #525252; } /* PlotWidget ------------------------------------------------------------- From 0aebb62726e1cbf090ea3596a7bfd5277792d9e6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 01:34:09 +0600 Subject: [PATCH 0010/1190] Avoid QToolBar spacing --- src/qt/qdarkstyle/dark/darkstyle.qss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index d119b5410..865ce9e66 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -754,7 +754,6 @@ QToolBar { border-bottom: 1px solid #222222; padding: 1px; font-weight: bold; - spacing: 2px; } QToolBar:disabled { From 3374ff4eb2a8c8ed5f323f0a5e07a5b310454160 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 17 Jan 2024 13:37:19 +0600 Subject: [PATCH 0011/1190] Use Windows 11 Notepad's background color --- src/qt/qdarkstyle/dark/darkstyle.qss | 146 +++++++++++++-------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 865ce9e66..2cbd2e257 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -44,7 +44,7 @@ QToolBar * { --------------------------------------------------------------------------- */ QWidget { - background-color: #222222; + background-color: #272727; border: 0px solid #525252; padding: 0px; color: #E3E3E3; @@ -53,7 +53,7 @@ QWidget { } QWidget:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; selection-background-color: #444444; selection-color: #8B8B8B; @@ -75,7 +75,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow --------------------------------------------------------------------------- */ QMainWindow::separator { background-color: #525252; - border: 0px solid #222222; + border: 0px solid #272727; spacing: 0px; padding: 2px; } @@ -120,9 +120,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar --------------------------------------------------------------------------- */ QStatusBar { - border: 1px solid #525252; + border: 1px solid #272727; /* Fixes Spyder #9120, #9121 */ - background: #525252; + background: #272727; /* Fixes #205, white vertical borders separating items */ } @@ -132,8 +132,8 @@ QStatusBar::item { QStatusBar QToolTip { background-color: #666666; - border: 1px solid #222222; - color: #222222; + border: 1px solid #272727; + color: #272727; /* Remove padding, for fix combo box tooltip */ padding: 0px; /* Reducing transparency to read better */ @@ -152,7 +152,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox --------------------------------------------------------------------------- */ QCheckBox { - background-color: #222222; + background-color: #272727; color: #E3E3E3; spacing: 4px; outline: none; @@ -165,7 +165,7 @@ QCheckBox:focus { } QCheckBox QWidget:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -278,7 +278,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton --------------------------------------------------------------------------- */ QRadioButton { - background-color: #222222; + background-color: #272727; color: #E3E3E3; spacing: 4px; padding-top: 4px; @@ -292,14 +292,14 @@ QRadioButton:focus { } QRadioButton:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; border: none; outline: none; } QRadioButton QWidget { - background-color: #222222; + background-color: #272727; color: #E3E3E3; spacing: 0px; padding: 0px; @@ -352,7 +352,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar --------------------------------------------------------------------------- */ QMenuBar { - background-color: #222222; + background-color: #272727; padding: 2px; border: 1px solid #525252; color: #E3E3E3; @@ -515,7 +515,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox --------------------------------------------------------------------------- */ QAbstractItemView { - alternate-background-color: #222222; + alternate-background-color: #272727; color: #E3E3E3; border: 1px solid #525252; border-radius: 4px; @@ -531,7 +531,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QAbstractScrollArea { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; border-radius: 4px; /* fix #159 */ @@ -548,7 +548,7 @@ QAbstractScrollArea:disabled { --------------------------------------------------------------------------- */ QScrollArea QWidget QWidget:disabled { - background-color: #222222; + background-color: #272727; } /* QScrollBar ------------------------------------------------------------- @@ -561,11 +561,11 @@ QScrollBar:horizontal { margin: 2px 16px 2px 16px; border: 1px solid #525252; border-radius: 4px; - background-color: #222222; + background-color: #272727; } QScrollBar:vertical { - background-color: #222222; + background-color: #272727; width: 16px; margin: 16px 2px 16px 2px; border: 1px solid #525252; @@ -698,7 +698,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets --------------------------------------------------------------------------- */ QTextEdit { - background-color: #222222; + background-color: #272727; color: #E3E3E3; border-radius: 4px; border: 1px solid #525252; @@ -717,7 +717,7 @@ QTextEdit:selected { --------------------------------------------------------------------------- */ QPlainTextEdit { - background-color: #222222; + background-color: #272727; color: #E3E3E3; border-radius: 4px; border: 1px solid #525252; @@ -750,15 +750,15 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar --------------------------------------------------------------------------- */ QToolBar { - background-color: #222222; - border-bottom: 1px solid #222222; + background-color: #272727; + border-bottom: 1px solid #272727; padding: 1px; font-weight: bold; } QToolBar:disabled { /* Fixes #272 */ - background-color: #222222; + background-color: #272727; } QToolBar::handle:horizontal { @@ -782,7 +782,7 @@ QToolBar::separator:vertical { } QToolButton#qt_toolbar_ext_button { - background: #222222; + background: #272727; border: 0px; color: #E3E3E3; image: url(":/qss_icons/dark/rc/arrow_right.png"); @@ -792,7 +792,7 @@ QToolButton#qt_toolbar_ext_button { --------------------------------------------------------------------------- */ QAbstractSpinBox { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; /* This fixes 103, 111 */ @@ -806,7 +806,7 @@ QAbstractSpinBox { } QAbstractSpinBox:up-button { - background-color: transparent #222222; + background-color: transparent #272727; subcontrol-origin: border; subcontrol-position: top right; border-left: 1px solid #525252; @@ -829,7 +829,7 @@ QAbstractSpinBox::up-arrow:hover { } QAbstractSpinBox:down-button { - background-color: transparent #222222; + background-color: transparent #272727; subcontrol-origin: border; subcontrol-position: bottom right; border-left: 1px solid #525252; @@ -874,7 +874,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe --------------------------------------------------------------------------- */ QLabel { - background-color: #222222; + background-color: #272727; border: 0px solid #525252; padding: 2px; margin: 0px; @@ -882,7 +882,7 @@ QLabel { } QLabel:disabled { - background-color: #222222; + background-color: #272727; border: 0px solid #525252; color: #8B8B8B; } @@ -893,14 +893,14 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea --------------------------------------------------------------------------- */ QTextBrowser { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; border-radius: 4px; } QTextBrowser:disabled { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #8B8B8B; border-radius: 4px; @@ -914,14 +914,14 @@ QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pre --------------------------------------------------------------------------- */ QGraphicsView { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; border-radius: 4px; } QGraphicsView:disabled { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #8B8B8B; border-radius: 4px; @@ -940,7 +940,7 @@ QCalendarWidget { } QCalendarWidget:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -948,12 +948,12 @@ QCalendarWidget:disabled { --------------------------------------------------------------------------- */ QLCDNumber { - background-color: #222222; + background-color: #272727; color: #E3E3E3; } QLCDNumber:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -963,7 +963,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar --------------------------------------------------------------------------- */ QProgressBar { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; border-radius: 4px; @@ -971,7 +971,7 @@ QProgressBar { } QProgressBar:disabled { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #8B8B8B; border-radius: 4px; @@ -980,7 +980,7 @@ QProgressBar:disabled { QProgressBar::chunk { background-color: #616161; - color: #222222; + color: #272727; border-radius: 4px; } @@ -1064,7 +1064,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton --------------------------------------------------------------------------- */ QToolButton { - background-color: #222222; + background-color: #272727; color: #E3E3E3; border-radius: 4px; padding: 2px; @@ -1076,7 +1076,7 @@ QToolButton { } QToolButton:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; border-radius: 4px; padding: 2px; @@ -1230,12 +1230,12 @@ QComboBox { QComboBox QAbstractItemView { border: 1px solid #525252; border-radius: 0; - background-color: #222222; + background-color: #272727; selection-background-color: #616161; } QComboBox QAbstractItemView:hover { - background-color: #222222; + background-color: #272727; color: #E3E3E3; } @@ -1245,11 +1245,11 @@ QComboBox QAbstractItemView:selected { } QComboBox QAbstractItemView:alternate { - background: #222222; + background: #272727; } QComboBox:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -1276,7 +1276,7 @@ QComboBox::indicator { } QComboBox::indicator:alternate { - background: #222222; + background: #272727; } QComboBox::item { @@ -1292,7 +1292,7 @@ QComboBox::item { } QComboBox::item:alternate { - background: #222222; + background: #272727; } QComboBox::drop-down { @@ -1318,7 +1318,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider --------------------------------------------------------------------------- */ QSlider:disabled { - background: #222222; + background: #272727; } QSlider:focus { @@ -1407,7 +1407,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit --------------------------------------------------------------------------- */ QLineEdit { - background-color: #222222; + background-color: #272727; padding-top: 2px; /* This QLineEdit fix 103, 111 */ padding-bottom: 2px; @@ -1421,7 +1421,7 @@ QLineEdit { } QLineEdit:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -1526,46 +1526,46 @@ QTabBar::tab:right:selected:disabled, QDockWidget QTabBar::tab:right:selected:di } QTabBar::tab:top:!selected:disabled, QDockWidget QTabBar::tab:top:!selected:disabled { - border-bottom: 3px solid #222222; + border-bottom: 3px solid #272727; color: #8B8B8B; - background-color: #222222; + background-color: #272727; } QTabBar::tab:bottom:!selected:disabled, QDockWidget QTabBar::tab:bottom:!selected:disabled { - border-top: 3px solid #222222; + border-top: 3px solid #272727; color: #8B8B8B; - background-color: #222222; + background-color: #272727; } QTabBar::tab:left:!selected:disabled, QDockWidget QTabBar::tab:left:!selected:disabled { - border-right: 3px solid #222222; + border-right: 3px solid #272727; color: #8B8B8B; - background-color: #222222; + background-color: #272727; } QTabBar::tab:right:!selected:disabled, QDockWidget QTabBar::tab:right:!selected:disabled { - border-left: 3px solid #222222; + border-left: 3px solid #272727; color: #8B8B8B; - background-color: #222222; + background-color: #272727; } QTabBar::tab:top:!selected, QDockWidget QTabBar::tab:top:!selected { - border-bottom: 2px solid #222222; + border-bottom: 2px solid #272727; margin-top: 2px; } QTabBar::tab:bottom:!selected, QDockWidget QTabBar::tab:bottom:!selected { - border-top: 2px solid #222222; + border-top: 2px solid #272727; margin-bottom: 2px; } QTabBar::tab:left:!selected, QDockWidget QTabBar::tab:left:!selected { - border-left: 2px solid #222222; + border-left: 2px solid #272727; margin-right: 2px; } QTabBar::tab:right:!selected, QDockWidget QTabBar::tab:right:!selected { - border-right: 2px solid #222222; + border-right: 2px solid #272727; margin-left: 2px; } @@ -1711,7 +1711,7 @@ QTabBar QToolButton::right-arrow:disabled, QDockWidget QTabBar QToolButton::righ --------------------------------------------------------------------------- */ QDockWidget { outline: 1px solid #525252; - background-color: #222222; + background-color: #272727; border: 1px solid #525252; border-radius: 4px; titlebar-close-icon: url(":/qss_icons/dark/rc/transparent.png"); @@ -1869,7 +1869,7 @@ QTreeView, QListView, QTableView, QColumnView { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; gridline-color: #525252; @@ -1880,7 +1880,7 @@ QTreeView:disabled, QListView:disabled, QTableView:disabled, QColumnView:disabled { - background-color: #222222; + background-color: #272727; color: #8B8B8B; } @@ -1931,7 +1931,7 @@ QColumnView::item:!selected:hover { } QTableCornerButton::section { - background-color: #222222; + background-color: #272727; border: 1px transparent #525252; border-radius: 0px; } @@ -1967,7 +1967,7 @@ QHeaderView::section::horizontal { padding-bottom: 0; padding-left: 4px; padding-right: 4px; - border-left: 1px solid #222222; + border-left: 1px solid #272727; } QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { @@ -1983,7 +1983,7 @@ QHeaderView::section::vertical { padding-bottom: 0; padding-left: 4px; padding-right: 4px; - border-top: 1px solid #222222; + border-top: 1px solid #272727; } QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { @@ -2033,7 +2033,7 @@ QToolBox:selected { } QToolBox::tab { - background-color: #222222; + background-color: #272727; border: 1px solid #525252; color: #E3E3E3; border-top-left-radius: 4px; @@ -2060,7 +2060,7 @@ QToolBox::tab:!selected { } QToolBox::tab:!selected:disabled { - background-color: #222222; + background-color: #272727; } QToolBox::tab:hover { @@ -2071,7 +2071,7 @@ QToolBox::tab:hover { QToolBox QScrollArea { padding: 0px; border: 0px; - background-color: #222222; + background-color: #272727; } /* QFrame ----------------------------------------------------------------- @@ -2122,7 +2122,7 @@ QSplitter { QSplitter::handle { background-color: #525252; - border: 0px solid #222222; + border: 0px solid #272727; spacing: 0px; padding: 1px; margin: 0px; @@ -2181,7 +2181,7 @@ QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:foc } QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView { - background-color: #222222; + background-color: #272727; border-radius: 4px; border: 1px solid #525252; selection-background-color: #616161; From aea2e4c4a2c872ade297730d6da0a2246d2a93cd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 18 Jan 2024 01:47:12 +0600 Subject: [PATCH 0012/1190] Make it more similar to Windows 10/11 --- src/qt/qdarkstyle/dark/darkstyle.qss | 43 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 2cbd2e257..6e1ec4b06 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -373,13 +373,13 @@ QMenuBar::item:selected { padding: 4px; background: transparent; border: 0px solid #525252; - background-color: #666666; + background-color: #383838; } QMenuBar::item:pressed { padding: 4px; border: 0px solid #525252; - background-color: #666666; + background-color: #383838; color: #E3E3E3; } @@ -392,7 +392,7 @@ QMenu { border: 0px solid #525252; color: #E3E3E3; margin: 0px; - background-color: #414141; + background-color: #2C2C2C; selection-background-color: #666666; } @@ -403,7 +403,7 @@ QMenu::separator { } QMenu::item { - background-color: #414141; + background-color: #2C2C2C; padding: 4px 24px 4px 28px; /* Reserve space for selection border */ border: 1px transparent #525252; @@ -411,11 +411,11 @@ QMenu::item { QMenu::item:selected { color: #E3E3E3; - background-color: #666666; + background-color: #353535; } QMenu::item:pressed { - background-color: #666666; + background-color: #353535; } QMenu::icon { @@ -999,51 +999,54 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton --------------------------------------------------------------------------- */ QPushButton { - background-color: #525252; + background-color: #333333; color: #E3E3E3; border-radius: 4px; - padding: 2px; + padding: 4px; outline: none; - border: none; + border: 1px solid white; } QPushButton:disabled { - background-color: #525252; + background-color: #333333; color: #8B8B8B; border-radius: 4px; - padding: 2px; + padding: 4px; + border: 1px solid #9B9B9B; } QPushButton:checked { - background-color: #767676; + background-color: #666666; border-radius: 4px; - padding: 2px; + padding: 4px; outline: none; } QPushButton:checked:disabled { - background-color: #767676; + background-color: #525252; color: #8B8B8B; border-radius: 4px; - padding: 2px; + padding: 4px; outline: none; } QPushButton:checked:selected { - background: #767676; + background: #454545; } QPushButton:hover { - background-color: #666666; + background-color: #454545; color: #E3E3E3; + border: 1px solid #9B9B9B; } QPushButton:pressed { - background-color: #767676; + background-color: #666666; + border: 1px solid #9B9B9B; } QPushButton:selected { - background: #767676; + background: #333333; color: #E3E3E3; } @@ -1255,6 +1258,7 @@ QComboBox:disabled { QComboBox:hover { border: 1px solid #616161; + background-color: #454545; } QComboBox:focus { @@ -1263,6 +1267,7 @@ QComboBox:focus { QComboBox:on { selection-background-color: #616161; + background-color: #666666; } QComboBox::indicator { From a8c75fb0af3c4d1dac3ee49b26dc2d7c9aa0239a Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:34:51 +0900 Subject: [PATCH 0013/1190] added IBM ESDI Integrated Fixed Disk --- src/disk/hdc.c | 1 + src/disk/hdc_esdi_mca.c | 233 ++++++++++++++++++++++++++++++++++------ 2 files changed, 203 insertions(+), 31 deletions(-) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 908cbce07..3ec6358d8 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -77,6 +77,7 @@ static const struct { { &xtide_acculogic_device }, { &xtide_device }, { &esdi_ps2_device }, + { &esdi_integrated_device }, { &ide_pci_device }, { &ide_pci_2ch_device }, { &ide_vlb_device }, diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index c906c7ca1..047089a1e 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -150,6 +150,11 @@ typedef struct esdi_t { uint8_t pos_regs[8]; } esdi_t; +enum { + ESDI_IS_ADAPTER, + ESDI_IS_INTEGRATED +}; + #define STATUS_DMA_ENA (1 << 7) #define STATUS_IRQ_PENDING (1 << 6) #define STATUS_CMD_IN_PROGRESS (1 << 5) @@ -635,32 +640,48 @@ esdi_callback(void *priv) break; case CMD_GET_DEV_CONFIG: - ESDI_DRIVE_ONLY(); - - if (!drive->present) { - device_not_present(dev); - return; + if (dev->cmd_dev == ATTN_HOST_ADAPTER) + { + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + /* INT 13, AX=1C0B - ESDI FIXED DISK - GET ADAPTER CONFIGURATION */ + /* The PS/55 will test sector buffer after this request is done. */ + dev->status_len = 6; + dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0; + dev->status_data[2] = 0; + /* bit 15-12: chip revision = 0011b, bit 11-8: sector buffer size = n * 256 bytes (n must be < 6) */ + dev->status_data[3] = 0x3200; + dev->status_data[4] = 0; + dev->status_data[5] = 0; } + else + { + ESDI_DRIVE_ONLY(); + if (!drive->present) { + device_not_present(dev); + return; + } - if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) - fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); - - dev->status_len = 6; - dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; - dev->status_data[1] = 0x10; /*Zero defect*/ - dev->status_data[2] = drive->sectors & 0xffff; - dev->status_data[3] = drive->sectors >> 16; - dev->status_data[4] = drive->tracks; - dev->status_data[5] = drive->hpc | (drive->spt << 16); + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + dev->status_len = 6; + dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0x10; /*Zero defect*/ + dev->status_data[2] = drive->sectors & 0xffff; + dev->status_data[3] = drive->sectors >> 16; + dev->status_data[4] = drive->tracks; + dev->status_data[5] = drive->hpc | (drive->spt << 16); + } esdi_mca_log("CMD_GET_DEV_CONFIG %i %04x %04x %04x %04x %04x %04x\n", - drive->sectors, - dev->status_data[0], dev->status_data[1], - dev->status_data[2], dev->status_data[3], - dev->status_data[4], dev->status_data[5]); + drive->sectors, + dev->status_data[0], dev->status_data[1], + dev->status_data[2], dev->status_data[3], + dev->status_data[4], dev->status_data[5]); - dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; - dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); @@ -674,7 +695,7 @@ esdi_callback(void *priv) dev->status_len = 5; dev->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER; - dev->status_data[1] = 0xffdd; /*MCA ID*/ + dev->status_data[1] = dev->pos_regs[1] | (dev->pos_regs[0] << 8); /*MCA ID*/ dev->status_data[2] = dev->pos_regs[3] | (dev->pos_regs[2] << 8); dev->status_data[3] = 0xff; dev->status_data[4] = 0xff; @@ -1171,6 +1192,62 @@ esdi_mca_write(int port, uint8_t val, void *priv) } } +static void +esdi_integrated_mca_write(int port, uint8_t val, void* priv) +{ + esdi_t* dev = (esdi_t*)priv; + + esdi_mca_log("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n", + port, val, dev->pos_regs[2], dev->pos_regs[3]); + + if (port < 0x102) + return; + + /* Save the new value. */ + dev->pos_regs[port & 7] = val; + + io_removehandler(ESDI_IOADDR_PRI, 8, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, dev); + + switch (dev->pos_regs[2] & 0x3c) { + case 0x14: + dev->dma = 5; + break; + case 0x18: + dev->dma = 6; + break; + case 0x1c: + dev->dma = 7; + break; + case 0x00: + dev->dma = 0; + break; + case 0x04: + dev->dma = 1; + break; + case 0x0c: + dev->dma = 3; + break; + case 0x10: + dev->dma = 4; + break; + + default: + break; + } + + if (dev->pos_regs[2] & 1) { + io_sethandler(ESDI_IOADDR_PRI, 8, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, dev); + + /* Say hello. */ + esdi_mca_log("ESDI: I/O=3510, IRQ=14, DMA=%d\n", + dev->dma); + } +} + static uint8_t esdi_mca_feedb(void *priv) { @@ -1179,6 +1256,14 @@ esdi_mca_feedb(void *priv) return (dev->pos_regs[2] & 1); } +static void esdi_reset(void* priv) +{ + esdi_t* dev = (esdi_t*)priv; + dev->in_reset = 1; + esdi_mca_set_callback(dev, ESDI_TIME * 50); + dev->status = STATUS_BUSY; +} + static void * esdi_init(UNUSED(const device_t *info)) { @@ -1195,10 +1280,12 @@ esdi_init(UNUSED(const device_t *info)) /* Mark as unconfigured. */ dev->irq_status = 0xff; - rom_init_interleaved(&dev->bios_rom, - BIOS_FILE_H, BIOS_FILE_L, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&dev->bios_rom.mapping); + if (info->local == ESDI_IS_ADAPTER) { + rom_init_interleaved(&dev->bios_rom, + BIOS_FILE_H, BIOS_FILE_L, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&dev->bios_rom.mapping); + } dev->drives[0].present = dev->drives[1].present = 0; @@ -1231,12 +1318,28 @@ esdi_init(UNUSED(const device_t *info)) break; } - /* Set the MCA ID for this controller, 0xFFDD. */ - dev->pos_regs[0] = 0xff; - dev->pos_regs[1] = 0xdd; + /* Set the MCA ID for this controller. */ + if (info->local == ESDI_IS_ADAPTER) { + dev->pos_regs[0] = 0xff; + dev->pos_regs[1] = 0xdd; + } + else if (info->local == ESDI_IS_INTEGRATED) + { + dev->pos_regs[0] = 0x9f; + dev->pos_regs[1] = 0xdf; + } /* Enable the device. */ - mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev); + if (info->local == ESDI_IS_INTEGRATED) { + /* The slot number of this controller is fixed by the planar. IBM PS/55 5551-T assigns it #5. */ + int slotno = device_get_config_int("in_esdi_slot"); + if (slotno) + mca_add_to_slot(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, NULL, dev, slotno - 1); + else + mca_add(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, NULL, dev); + } + else + mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev); /* Mark for a reset. */ dev->in_reset = 1; @@ -1276,7 +1379,7 @@ const device_t esdi_ps2_device = { .name = "IBM PS/2 ESDI Fixed Disk Adapter (MCA)", .internal_name = "esdi_mca", .flags = DEVICE_MCA, - .local = 0, + .local = ESDI_IS_ADAPTER, .init = esdi_init, .close = esdi_close, .reset = NULL, @@ -1285,3 +1388,71 @@ const device_t esdi_ps2_device = { .force_redraw = NULL, .config = NULL }; + +static device_config_t +esdi_integrated_config[] = +{ + { + .name = "in_esdi_slot", + .description = "Slot #", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Auto", + .value = 0 + }, + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "3", + .value = 3 + }, + { + .description = "4", + .value = 4 + }, + { + .description = "5", + .value = 5 + }, + { + .description = "6", + .value = 6 + }, + { + .description = "7", + .value = 7 + }, + { + .description = "8", + .value = 8 + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + +const device_t +esdi_integrated_device = { + .name = "IBM Integrated Fixed Disk Controller (MCA)", + .internal_name = "esdi_integrated_mca", + .flags = DEVICE_MCA, + .local = ESDI_IS_INTEGRATED, + .init = esdi_init, + .close = esdi_close, + .reset = esdi_reset, + {.available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = esdi_integrated_config +}; From bb9b4dc64fe079a9edfb0e0e7670303a5c85d50a Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:38:48 +0900 Subject: [PATCH 0014/1190] Added IBM-J 5576 keyboard and scancode set 8Ah --- src/device/keyboard.c | 116 ++++++++ src/device/keyboard_at.c | 555 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 668 insertions(+), 3 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index ea81e7525..4b8bc7365 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -18,10 +18,13 @@ * Copyright 2015-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ +#include #include #include #include +#include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/machine.h> #include <86box/keyboard.h> @@ -49,6 +52,24 @@ uint16_t key_uncapture_1 = 0x04f; /* Numpad End */ uint16_t key_uncapture_2 = 0x14f; /* End */ #endif +#ifdef ENABLE_KBC_AT_LOG +int kbc_at_do_log = ENABLE_KBC_AT_LOG; + +static void +kbc_at_log(const char* fmt, ...) +{ + va_list ap; + + if (kbc_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define kbc_at_log(fmt, ...) +#endif + void (*keyboard_send)(uint16_t val); static int recv_key[512] = { 0 }; /* keyboard input buffer */ @@ -64,6 +85,64 @@ static uint8_t num_lock = 0; static uint8_t scroll_lock = 0; static uint8_t shift = 0; +static int key5576mode = 0; + +typedef struct { + const uint16_t sc; + const uint8_t mk[4]; + const uint8_t brk[4]; +} scconvtbl; + +static scconvtbl scconv55_82[18 + 1] = +{ + // clang-format off + {.sc = 0x02 , .mk = { 0x5f, 0 }, .brk = { 0xf0, 0x5f, 0 } }, /* '1' -> 'Clear/ /SysRq' */ + {.sc = 0x03 , .mk = { 0x48, 0 }, .brk = { 0xf0, 0x48, 0 } }, /* '2' -> '終了 (Exit)' */ + {.sc = 0x04 , .mk = { 0x38, 0 }, .brk = { 0xf0, 0x38, 0 } }, /* '3' -> 'メッセージ (Message)/ /応答 (Respond)' */ + {.sc = 0x05 , .mk = { 0x30, 0 }, .brk = { 0xf0, 0x30, 0 } }, /* '4' -> 'サイズ変換 (Change Size)/ /横倍角 (2x Width)' */ + {.sc = 0x06 , .mk = { 0x20, 0 }, .brk = { 0xf0, 0x20, 0 } }, /* '5' -> '単語登録 (Register Word)/ /再交換 (Re-change)' */ + {.sc = 0x07 , .mk = { 0x28, 0 }, .brk = { 0xf0, 0x28, 0 } }, /* '6' -> '漢字 (Kanji)/ /番号 (Number)' */ + {.sc = 0x08 , .mk = { 0x60, 0 }, .brk = { 0xf0, 0x60, 0 } }, /* '7' -> '取消 (Cancel)' */ + {.sc = 0x09 , .mk = { 0x40, 0 }, .brk = { 0xf0, 0x40, 0 } }, /* '8' -> 'コピー (Copy)/ /移動 (Move)' */ + {.sc = 0x3d , .mk = { 0x1f, 0 }, .brk = { 0xf0, 0x1f, 0 } }, /* 'F3' -> 'Cr Bnk/領域呼出 (Call Range)/All Cr/登録 (Register)' */ + {.sc = 0x3e , .mk = { 0x27, 0 }, .brk = { 0xf0, 0x27, 0 } }, /* 'F4' -> '割込み (Interrupt)' */ + {.sc = 0x3f , .mk = { 0x2f, 0 }, .brk = { 0xf0, 0x2f, 0 } }, /* 'F5' -> 'UF1' */ + {.sc = 0x40 , .mk = { 0x5e, 0 }, .brk = { 0xf0, 0x5e, 0 } }, /* 'F6' -> 'UF2' */ + {.sc = 0x41 , .mk = { 0x08, 0 }, .brk = { 0xf0, 0x08, 0 } }, /* 'F7' -> 'UF3' */ + {.sc = 0x42 , .mk = { 0x10, 0 }, .brk = { 0xf0, 0x10, 0 } }, /* 'F8' -> 'UF4' */ + {.sc = 0x43 , .mk = { 0x50, 0 }, .brk = { 0xf0, 0x50, 0 } }, /* 'F9' -> 'EOF/Erase/ErInp' */ + {.sc = 0x44 , .mk = { 0x18, 0 }, .brk = { 0xf0, 0x18, 0 } }, /* 'F10' -> 'Attn/ /CrSel' */ + {.sc = 0x57 , .mk = { 0x17, 0 }, .brk = { 0xf0, 0x17, 0 } }, /* 'F11' -> 'PA1/ /DvCncl' */ + {.sc = 0x58 , .mk = { 0x37, 0 }, .brk = { 0xf0, 0x37, 0 } }, /* 'F12' -> 'PA2/ /PA3' */ + {.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */ + // clang-format on +}; + +static scconvtbl scconv55_8a[18 + 1] = +{ + // clang-format off + {.sc = 0x02 , .mk = { 0x48 }, .brk = { 0 } }, /* '1' -> 'Clear/ /SysRq' */ + {.sc = 0x03 , .mk = { 0x49 }, .brk = { 0 } }, /* '2' -> '終了 (Exit)' */ + {.sc = 0x04 , .mk = { 0x46 }, .brk = { 0 } }, /* '3' -> 'メッセージ (Message)/ /応答 (Respond)' */ + {.sc = 0x05 , .mk = { 0x44 }, .brk = { 0 } }, /* '4' -> 'サイズ変換 (Change Size)/ /横倍角 (2x Width)' */ + {.sc = 0x06 , .mk = { 0x42 }, .brk = { 0 } }, /* '5' -> '単語登録 (Register Word)/ /再交換 (Re-change)' */ + {.sc = 0x07 , .mk = { 0x43 }, .brk = { 0 } }, /* '6' -> '漢字 (Kanji)/ /番号 (Number)' */ + {.sc = 0x08 , .mk = { 0x40 }, .brk = { 0 } }, /* '7' -> '取消 (Cancel)' */ + {.sc = 0x09 , .mk = { 0x51 }, .brk = { 0 } }, /* '8' -> 'コピー (Copy)/ /移動 (Move)' */ + {.sc = 0x3d , .mk = { 0x76 }, .brk = { 0 } }, /* 'F3' -> 'Cr Bnk/領域呼出 (Call Range)/All Cr/登録 (Register)' */ + {.sc = 0x3e , .mk = { 0x77 }, .brk = { 0 } }, /* 'F4' -> '割込み (Interrupt)' */ + {.sc = 0x3f , .mk = { 0x78 }, .brk = { 0 } }, /* 'F5' -> 'UF1' */ + {.sc = 0x40 , .mk = { 0x79 }, .brk = { 0 } }, /* 'F6' -> 'UF2' */ + {.sc = 0x41 , .mk = { 0x7a }, .brk = { 0 } }, /* 'F7' -> 'UF3' */ + {.sc = 0x42 , .mk = { 0x7b }, .brk = { 0 } }, /* 'F8' -> 'UF4' */ + {.sc = 0x43 , .mk = { 0x7c }, .brk = { 0 } }, /* 'F9' -> 'EOF/Erase/ErInp' */ + {.sc = 0x44 , .mk = { 0x7d }, .brk = { 0 } }, /* 'F10' -> 'Attn/ /CrSel' */ + {.sc = 0x57 , .mk = { 0x7e }, .brk = { 0 } }, /* 'F11' -> 'PA1/ /DvCncl' */ + {.sc = 0x58 , .mk = { 0x7f }, .brk = { 0 } }, /* 'F12' -> 'PA2/ /PA3' */ + {.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */ + // clang-format on +}; + void keyboard_init(void) { @@ -119,6 +198,36 @@ key_process(uint16_t scan, int down) oldkey[scan] = down; + pclog("keyboard : %04X,%d in process\n", scan, down); + + c = 0; + /* According to Japanese DOS K3.3 manual (N:SC18-2194-1), + IBM 5576-002, -003 keyboards have the one-time key conversion mode + that emulates 18 out of 131 keys on IBM 5576-001 keyboard. + It is triggered by pressing L-Shift (⇧) + L-Ctrl + R-Alt (前面キー) + when the scancode set is 82h or 8ah. + */ + if (key5576mode) { + int i = 0; + if (!down) { + /* Do and exit the 5576-001 emulation when a key is pressed other than trigger keys. */ + if (scan != 0x1d && scan != 0x2a && scan != 0x138) + { + key5576mode = 0; + pclog("keyboard : 5576-001 key emulation disabled.\n"); + } + } + while (scconv55_8a[i].sc != 0) + { + if (scconv55_8a[i].sc == scan) { + while (scconv55_8a[i].mk[c] != 0) + keyboard_send(scconv55_8a[i].mk[c++]); + return; + } + i++; + } + } + if (down && (codes[scan].mk[0] == 0)) return; @@ -145,6 +254,13 @@ key_process(uint16_t scan, int down) if (fake_shift_needed(scan)) keyboard_send(0x101); } + + /* Enter the 5576-001 emulation mode. */ + if (keyboard_mode == 0x8a && down && ((keyboard_get_shift() & 0x43) == 0x43)) + { + key5576mode = 1; + pclog("keyboard : 5576-001 key emulation enabled.\n"); + } } /* Handle a keystroke event from the UI layer. */ diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index bcb4d646b..2900ec17a 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -53,10 +53,10 @@ const uint8_t id_bytes[16][4] = { { 0x00, 0x00, 0x00, 0x00 }, /* AT 84-key */ { 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00 }, - { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 }, /* FLAG_PS2 = 0x08 */ { 0xab, 0x83, 0x00, 0x00 }, /* PS/2 101-key */ { 0xab, 0x83, 0x00, 0x00 }, /* PS/2 102-key */ - { 0xab, 0x90, 0x00, 0x00 }, /* PS/2 106-key JIS */ + { 0xab, 0x90, 0x00, 0x00 }, /* PS/55 106-key JIS (IBM-J 5576-002) */ /* Japanese keyboard ID - TODO: Find the actual Korean one. */ { 0xab, 0x90, 0x00, 0x00 }, /* PS/2 Korean */ { 0x00, 0x00, 0x00, 0x00 }, @@ -1630,6 +1630,548 @@ static const scancode scancode_set3[512] = { // clang-format on }; +/* IBM Japan 5576-001, 002 and 003 keyboards have three extra scancode sets; 81h, 82h, 8ah. + Scancode set 81h and 82h are not implemented yet. + To implement them, we need take the following into consideration. + * Add a UI to switch the type of keyboards and keyboard IDs. + * Add modified scancode set 1 and 2 (in these modes, language input keys are used as an alternative key). + * Japanese keyboards traditionally use a typewriter layout. Its key mapping doesn't match with foreign keyboards. + + 5576 keyboards kept 101-key compatible scancode sets because PS/55 had to support western (PS/2) versions of operating systems. + The default scancode set is 2. + In Japanese DOS, the keyboard driver confirms its keyboard ID, and sends a command to switch the scancode set to 8Ah. + + The OADG standard and modern Japanese keyboards use the same keyboard ID and scancode set number as PS/2 keyboards use. + Three extra scancode sets are no longer available. Instead, language input keys are available in scancode set 1 and 2. + However, it has a different key mapping. + Users have to choose the correct keyboard layout on setup, and the driver needs to remap keys. + + [Japanese DOS and keyboard scancode set] + | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | PC DOS 5 | + |---------------------------|:----:|:----:|:----:|:------:|:------:|:---------:|:--------:| + | IBM 101-key | n/a | n/a | n/a | n/a | 2 | n/a | 2 | + | IBM-J 5576-00x (obsolete) | 8A | 8A | 8A | 82 | 82 | 82 | 2 | + | OADG (modern JA standard) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | */ + +/* Scancode set 8Ah : 5556 keyboard compatible scancode set used by J-DOS */ +static scancode scancode_set8a[512] = +{ + // clang-format off + {.mk = { 0 }, .brk = { 0 } }, /* 000 */ + {.mk = { 0x3d, 0 }, .brk = { 0 } }, /* 001 */ + {.mk = { 0x24, 0 }, .brk = { 0 } }, /* 002 */ + {.mk = { 0x25, 0 }, .brk = { 0 } }, /* 003 */ + {.mk = { 0x26, 0 }, .brk = { 0 } }, /* 004 */ + {.mk = { 0x27, 0 }, .brk = { 0 } }, /* 005 */ + {.mk = { 0x28, 0 }, .brk = { 0 } }, /* 006 */ + {.mk = { 0x29, 0 }, .brk = { 0 } }, /* 007 */ + {.mk = { 0x2a, 0 }, .brk = { 0 } }, /* 008 */ + {.mk = { 0x2b, 0 }, .brk = { 0 } }, /* 009 */ + {.mk = { 0x2c, 0 }, .brk = { 0 } }, /* 00a */ + {.mk = { 0x2d, 0 }, .brk = { 0 } }, /* 00b */ + {.mk = { 0x2e, 0 }, .brk = { 0 } }, /* 00c */ + {.mk = { 0x2f, 0 }, .brk = { 0 } }, /* 00d */ + {.mk = { 0x3e, 0 }, .brk = { 0 } }, /* 00e */ + {.mk = { 0x3c, 0 }, .brk = { 0 } }, /* 00f */ + {.mk = { 0x18, 0 }, .brk = { 0 } }, /* 010 */ + {.mk = { 0x19, 0 }, .brk = { 0 } }, /* 011 */ + {.mk = { 0x1a, 0 }, .brk = { 0 } }, /* 012 */ + {.mk = { 0x1b, 0 }, .brk = { 0 } }, /* 013 */ + {.mk = { 0x1c, 0 }, .brk = { 0 } }, /* 014 */ + {.mk = { 0x1d, 0 }, .brk = { 0 } }, /* 015 */ + {.mk = { 0x1e, 0 }, .brk = { 0 } }, /* 016 */ + {.mk = { 0x1f, 0 }, .brk = { 0 } }, /* 017 */ + {.mk = { 0x20, 0 }, .brk = { 0 } }, /* 018 */ + {.mk = { 0x21, 0 }, .brk = { 0 } }, /* 019 */ + {.mk = { 0x22, 0 }, .brk = { 0 } }, /* 01a */ + {.mk = { 0x23, 0 }, .brk = { 0 } }, /* 01b */ + {.mk = { 0x3b, 0 }, .brk = { 0 } }, /* 01c */ + {.mk = { 0x41, 0 }, .brk = { 0xc1, 0 } }, /* 01d LCTRL */ + {.mk = { 0x0c, 0 }, .brk = { 0 } }, /* 01e */ + {.mk = { 0x0d, 0 }, .brk = { 0 } }, /* 01f */ + {.mk = { 0x0e, 0 }, .brk = { 0 } }, /* 020 */ + {.mk = { 0x0f, 0 }, .brk = { 0 } }, /* 021 */ + {.mk = { 0x10, 0 }, .brk = { 0 } }, /* 022 */ + {.mk = { 0x11, 0 }, .brk = { 0 } }, /* 023 */ + {.mk = { 0x12, 0 }, .brk = { 0 } }, /* 024 */ + {.mk = { 0x13, 0 }, .brk = { 0 } }, /* 025 */ + {.mk = { 0x14, 0 }, .brk = { 0 } }, /* 026 */ + {.mk = { 0x15, 0 }, .brk = { 0 } }, /* 027 */ + {.mk = { 0x16, 0 }, .brk = { 0 } }, /* 028* */ + {.mk = { 0x45, 0 }, .brk = { 0 } }, /* 029 Hankaku, Zenkaku */ + {.mk = { 0x38, 0 }, .brk = { 0xb8, 0 } }, /* 02a LSHIFT */ + {.mk = { 0x17, 0 }, .brk = { 0 } }, /* 02b Mu */ + {.mk = { 0x01, 0 }, .brk = { 0 } }, /* 02c */ + {.mk = { 0x02, 0 }, .brk = { 0 } }, /* 02d */ + {.mk = { 0x03, 0 }, .brk = { 0 } }, /* 02e */ + {.mk = { 0x04, 0 }, .brk = { 0 } }, /* 02f */ + {.mk = { 0x05, 0 }, .brk = { 0 } }, /* 030 */ + {.mk = { 0x06, 0 }, .brk = { 0 } }, /* 031 */ + {.mk = { 0x07, 0 }, .brk = { 0 } }, /* 032 */ + {.mk = { 0x08, 0 }, .brk = { 0 } }, /* 033 */ + {.mk = { 0x09, 0 }, .brk = { 0 } }, /* 034 */ + {.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */ + {.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */ + {.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */ + {.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 LALT = Kanji */ + {.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */ + {.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */ + {.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */ + {.mk = { 0x69, 0 }, .brk = { 0 } }, /* 03c */ + {.mk = { 0x6a, 0 }, .brk = { 0 } }, /* 03d */ + {.mk = { 0x6b, 0 }, .brk = { 0 } }, /* 03e */ + {.mk = { 0x6c, 0 }, .brk = { 0 } }, /* 03f */ + {.mk = { 0x6d, 0 }, .brk = { 0 } }, /* 040 */ + {.mk = { 0x6e, 0 }, .brk = { 0 } }, /* 041 */ + {.mk = { 0x6f, 0 }, .brk = { 0 } }, /* 042 */ + {.mk = { 0x70, 0 }, .brk = { 0 } }, /* 043 */ + {.mk = { 0x71, 0 }, .brk = { 0 } }, /* 044 F10 */ + {.mk = { 0 }, .brk = { 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */ + {.mk = { 0x75, 0 }, .brk = { 0 } }, /* 046 SCROLLLOCK */ + {.mk = { 0x5d, 0 }, .brk = { 0 } }, /* 047 KP7 */ + {.mk = { 0x5e, 0 }, .brk = { 0 } }, /* 048 */ + {.mk = { 0x5f, 0 }, .brk = { 0 } }, /* 049 */ + {.mk = { 0x67, 0 }, .brk = { 0 } }, /* 04a KP_MINUS */ + {.mk = { 0x5a, 0 }, .brk = { 0 } }, /* 04b */ + {.mk = { 0x5b, 0 }, .brk = { 0 } }, /* 04c */ + {.mk = { 0x5c, 0 }, .brk = { 0 } }, /* 04d */ + {.mk = { 0x63, 0 }, .brk = { 0 } }, /* 04e */ + {.mk = { 0x57, 0 }, .brk = { 0 } }, /* 04f */ + {.mk = { 0x58, 0 }, .brk = { 0 } }, /* 050 */ + {.mk = { 0x59, 0 }, .brk = { 0 } }, /* 051 */ + {.mk = { 0x55, 0 }, .brk = { 0 } }, /* 052 KP0 */ + {.mk = { 0x56, 0 }, .brk = { 0 } }, /* 053 KP_PERIOD */ + {.mk = { 0 }, .brk = { 0 } }, /* 054 */ + {.mk = { 0 }, .brk = { 0 } }, /* 055 */ + {.mk = { 0 }, .brk = { 0 } }, /* 056 */ + {.mk = { 0x72, 0 }, .brk = { 0 } }, /* 057 F11 */ + {.mk = { 0x73, 0 }, .brk = { 0 } }, /* 058 F12 */ + {.mk = { 0 }, .brk = { 0 } }, /* 059 */ + {.mk = { 0 }, .brk = { 0 } }, /* 05a */ + {.mk = { 0 }, .brk = { 0 } }, /* 05b */ + {.mk = { 0 }, .brk = { 0 } }, /* 05c */ + {.mk = { 0 }, .brk = { 0 } }, /* 05d */ + {.mk = { 0 }, .brk = { 0 } }, /* 05e */ + {.mk = { 0 }, .brk = { 0 } }, /* 05f */ + {.mk = { 0 }, .brk = { 0 } }, /* 060 */ + {.mk = { 0 }, .brk = { 0 } }, /* 061 */ + {.mk = { 0 }, .brk = { 0 } }, /* 062 */ + {.mk = { 0 }, .brk = { 0 } }, /* 063 */ + {.mk = { 0 }, .brk = { 0 } }, /* 064 */ + {.mk = { 0 }, .brk = { 0 } }, /* 065 */ + {.mk = { 0 }, .brk = { 0 } }, /* 066 */ + {.mk = { 0 }, .brk = { 0 } }, /* 067 */ + {.mk = { 0 }, .brk = { 0 } }, /* 068 */ + {.mk = { 0 }, .brk = { 0 } }, /* 069 */ + {.mk = { 0 }, .brk = { 0 } }, /* 06a */ + {.mk = { 0 }, .brk = { 0 } }, /* 06b */ + {.mk = { 0 }, .brk = { 0 } }, /* 06c */ + {.mk = { 0 }, .brk = { 0 } }, /* 06d */ + {.mk = { 0 }, .brk = { 0 } }, /* 06e */ + {.mk = { 0 }, .brk = { 0 } }, /* 06f */ + {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 070 Kana */ + {.mk = { 0 }, .brk = { 0 } }, /* 071 */ + {.mk = { 0 }, .brk = { 0 } }, /* 072 */ + {.mk = { 0x0b, 0 }, .brk = { 0 } }, /* 073 Ro, Underline */ + {.mk = { 0 }, .brk = { 0 } }, /* 074 */ + {.mk = { 0 }, .brk = { 0 } }, /* 075 */ + {.mk = { 0 }, .brk = { 0 } }, /* 076 */ + {.mk = { 0 }, .brk = { 0 } }, /* 077 */ + {.mk = { 0 }, .brk = { 0 } }, /* 078 */ + {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 079 Henkan */ + {.mk = { 0 }, .brk = { 0 } }, /* 07a */ + {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 07b Muhenkan */ + {.mk = { 0 }, .brk = { 0 } }, /* 07c */ + {.mk = { 0x30, 0 }, .brk = { 0 } }, /* 07d Yen, Vertical line */ + {.mk = { 0 }, .brk = { 0 } }, /* 07e */ + {.mk = { 0 }, .brk = { 0 } }, /* 07f */ + {.mk = { 0 }, .brk = { 0 } }, /* 080 */ + {.mk = { 0 }, .brk = { 0 } }, /* 081 */ + {.mk = { 0 }, .brk = { 0 } }, /* 082 */ + {.mk = { 0 }, .brk = { 0 } }, /* 083 */ + {.mk = { 0 }, .brk = { 0 } }, /* 084 */ + {.mk = { 0 }, .brk = { 0 } }, /* 085 */ + {.mk = { 0 }, .brk = { 0 } }, /* 086 */ + {.mk = { 0 }, .brk = { 0 } }, /* 087 */ + {.mk = { 0 }, .brk = { 0 } }, /* 088 */ + {.mk = { 0 }, .brk = { 0 } }, /* 089 */ + {.mk = { 0 }, .brk = { 0 } }, /* 08a */ + {.mk = { 0 }, .brk = { 0 } }, /* 08b */ + {.mk = { 0 }, .brk = { 0 } }, /* 08c */ + {.mk = { 0 }, .brk = { 0 } }, /* 08d */ + {.mk = { 0 }, .brk = { 0 } }, /* 08e */ + {.mk = { 0 }, .brk = { 0 } }, /* 08f */ + {.mk = { 0 }, .brk = { 0 } }, /* 090 */ + {.mk = { 0 }, .brk = { 0 } }, /* 091 */ + {.mk = { 0 }, .brk = { 0 } }, /* 092 */ + {.mk = { 0 }, .brk = { 0 } }, /* 093 */ + {.mk = { 0 }, .brk = { 0 } }, /* 094 */ + {.mk = { 0 }, .brk = { 0 } }, /* 095 */ + {.mk = { 0 }, .brk = { 0 } }, /* 096 */ + {.mk = { 0 }, .brk = { 0 } }, /* 097 */ + {.mk = { 0 }, .brk = { 0 } }, /* 098 */ + {.mk = { 0 }, .brk = { 0 } }, /* 099 */ + {.mk = { 0 }, .brk = { 0 } }, /* 09a */ + {.mk = { 0 }, .brk = { 0 } }, /* 09b */ + {.mk = { 0 }, .brk = { 0 } }, /* 09c */ + {.mk = { 0 }, .brk = { 0 } }, /* 09d */ + {.mk = { 0 }, .brk = { 0 } }, /* 09e */ + {.mk = { 0 }, .brk = { 0 } }, /* 09f */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0a9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0aa */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ab */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ac */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ad */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ae */ + {.mk = { 0 }, .brk = { 0 } }, /* 0af */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0b9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ba */ + {.mk = { 0 }, .brk = { 0 } }, /* 0bb */ + {.mk = { 0 }, .brk = { 0 } }, /* 0bc */ + {.mk = { 0 }, .brk = { 0 } }, /* 0bd */ + {.mk = { 0 }, .brk = { 0 } }, /* 0be */ + {.mk = { 0 }, .brk = { 0 } }, /* 0bf */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0c9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ca */ + {.mk = { 0 }, .brk = { 0 } }, /* 0cb */ + {.mk = { 0 }, .brk = { 0 } }, /* 0cc */ + {.mk = { 0 }, .brk = { 0 } }, /* 0cd */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ce */ + {.mk = { 0 }, .brk = { 0 } }, /* 0cf */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0d9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0da */ + {.mk = { 0 }, .brk = { 0 } }, /* 0db */ + {.mk = { 0 }, .brk = { 0 } }, /* 0dc */ + {.mk = { 0 }, .brk = { 0 } }, /* 0dd */ + {.mk = { 0 }, .brk = { 0 } }, /* 0de */ + {.mk = { 0 }, .brk = { 0 } }, /* 0df */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0e9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ea */ + {.mk = { 0 }, .brk = { 0 } }, /* 0eb */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ec */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ed */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ee */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ef */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0f9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 0fa */ + {.mk = { 0 }, .brk = { 0 } }, /* 0fb */ + {.mk = { 0 }, .brk = { 0 } }, /* 0fc */ + {.mk = { 0 }, .brk = { 0 } }, /* 0fd */ + {.mk = { 0 }, .brk = { 0 } }, /* 0fe */ + {.mk = { 0 }, .brk = { 0 } }, /* 0ff */ + {.mk = { 0x47, 0 }, .brk = { 0 } }, /* 100 Pause */ + {.mk = { 0 }, .brk = { 0 } }, /* 101 */ + {.mk = { 0 }, .brk = { 0 } }, /* 102 */ + {.mk = { 0 }, .brk = { 0 } }, /* 103 */ + {.mk = { 0 }, .brk = { 0 } }, /* 104 */ + {.mk = { 0 }, .brk = { 0 } }, /* 105 */ + {.mk = { 0 }, .brk = { 0 } }, /* 106 */ + {.mk = { 0 }, .brk = { 0 } }, /* 107 */ + {.mk = { 0 }, .brk = { 0 } }, /* 108 */ + {.mk = { 0 }, .brk = { 0 } }, /* 109 */ + {.mk = { 0 }, .brk = { 0 } }, /* 10a */ + {.mk = { 0 }, .brk = { 0 } }, /* 10b */ + {.mk = { 0 }, .brk = { 0 } }, /* 10c */ + {.mk = { 0 }, .brk = { 0 } }, /* 10d */ + {.mk = { 0 }, .brk = { 0 } }, /* 10e */ + {.mk = { 0 }, .brk = { 0 } }, /* 10f */ + {.mk = { 0 }, .brk = { 0 } }, /* 110 */ + {.mk = { 0 }, .brk = { 0 } }, /* 112 */ + {.mk = { 0 }, .brk = { 0 } }, /* 113 */ + {.mk = { 0 }, .brk = { 0 } }, /* 113 */ + {.mk = { 0 }, .brk = { 0 } }, /* 114 */ + {.mk = { 0 }, .brk = { 0 } }, /* 115 */ + {.mk = { 0 }, .brk = { 0 } }, /* 116 */ + {.mk = { 0 }, .brk = { 0 } }, /* 117 */ + {.mk = { 0 }, .brk = { 0 } }, /* 118 */ + {.mk = { 0 }, .brk = { 0 } }, /* 119 */ + {.mk = { 0 }, .brk = { 0 } }, /* 11a */ + {.mk = { 0 }, .brk = { 0 } }, /* 11b */ + {.mk = { 0x60, 0 }, .brk = { 0 } }, /* 11c KP_Enter */ + {.mk = { 0x37, 0 }, .brk = { 0xb7, 0 } }, /* 11d R-Ctrl */ + {.mk = { 0 }, .brk = { 0 } }, /* 11e */ + {.mk = { 0 }, .brk = { 0 } }, /* 11f */ + {.mk = { 0 }, .brk = { 0 } }, /* 120 */ + {.mk = { 0 }, .brk = { 0 } }, /* 121 */ + {.mk = { 0 }, .brk = { 0 } }, /* 122 */ + {.mk = { 0 }, .brk = { 0 } }, /* 123 */ + {.mk = { 0 }, .brk = { 0 } }, /* 124 */ + {.mk = { 0 }, .brk = { 0 } }, /* 125 */ + {.mk = { 0 }, .brk = { 0 } }, /* 126 */ + {.mk = { 0 }, .brk = { 0 } }, /* 127 */ + {.mk = { 0 }, .brk = { 0 } }, /* 128 */ + {.mk = { 0 }, .brk = { 0 } }, /* 129 */ + {.mk = { 0 }, .brk = { 0 } }, /* 12a */ + {.mk = { 0 }, .brk = { 0 } }, /* 12b */ + {.mk = { 0 }, .brk = { 0 } }, /* 12c */ + {.mk = { 0 }, .brk = { 0 } }, /* 12d */ + {.mk = { 0 }, .brk = { 0 } }, /* 12e */ + {.mk = { 0 }, .brk = { 0 } }, /* 12f */ + {.mk = { 0 }, .brk = { 0 } }, /* 130 */ + {.mk = { 0 }, .brk = { 0 } }, /* 131 */ + {.mk = { 0 }, .brk = { 0 } }, /* 132 */ + {.mk = { 0 }, .brk = { 0 } }, /* 133 */ + {.mk = { 0 }, .brk = { 0 } }, /* 134 */ + {.mk = { 0x65, 0 }, .brk = { 0 } }, /* 135 KP_DIVIDE */ + {.mk = { 0 }, .brk = { 0 } }, /* 136 */ + {.mk = { 0x74, 0 }, .brk = { 0 } }, /* 137 PRINTSCREEN */ + {.mk = { 0x31, 0 }, .brk = { 0xb1, 0 } }, /* 138* R-Alt */ + {.mk = { 0 }, .brk = { 0 } }, /* 139 */ + {.mk = { 0 }, .brk = { 0 } }, /* 13a */ + {.mk = { 0 }, .brk = { 0 } }, /* 13b */ + {.mk = { 0 }, .brk = { 0 } }, /* 13c */ + {.mk = { 0 }, .brk = { 0 } }, /* 13d */ + {.mk = { 0 }, .brk = { 0 } }, /* 13e */ + {.mk = { 0 }, .brk = { 0 } }, /* 13f */ + {.mk = { 0 }, .brk = { 0 } }, /* 140 */ + {.mk = { 0 }, .brk = { 0 } }, /* 141 */ + {.mk = { 0 }, .brk = { 0 } }, /* 142 */ + {.mk = { 0 }, .brk = { 0 } }, /* 143 */ + {.mk = { 0 }, .brk = { 0 } }, /* 144 */ + {.mk = { 0 }, .brk = { 0 } }, /* 145 */ + {.mk = { 0 }, .brk = { 0 } }, /* 146 */ + {.mk = { 0x4c, 0 }, .brk = { 0 } }, /* 147 Home */ + {.mk = { 0x4e, 0 }, .brk = { 0 } }, /* 148 Up */ + {.mk = { 0x52, 0 }, .brk = { 0 } }, /* 149 PageUp */ + {.mk = { 0 }, .brk = { 0 } }, /* 14a */ + {.mk = { 0x4b, 0 }, .brk = { 0 } }, /* 14b Left */ + {.mk = { 0 }, .brk = { 0 } }, /* 14c */ + {.mk = { 0x4d, 0 }, .brk = { 0 } }, /* 14d Right */ + {.mk = { 0 }, .brk = { 0 } }, /* 14e */ + {.mk = { 0x53, 0 }, .brk = { 0 } }, /* 14f End */ + {.mk = { 0x4a, 0 }, .brk = { 0 } }, /* 150 Down */ + {.mk = { 0x54, 0 }, .brk = { 0 } }, /* 151 PageDown */ + {.mk = { 0x4f, 0 }, .brk = { 0 } }, /* 152 Ins */ + {.mk = { 0x50, 0 }, .brk = { 0 } }, /* 153 Del */ + {.mk = { 0 }, .brk = { 0 } }, /* 154 */ + {.mk = { 0 }, .brk = { 0 } }, /* 155 */ + {.mk = { 0 }, .brk = { 0 } }, /* 156 */ + {.mk = { 0 }, .brk = { 0 } }, /* 157 */ + {.mk = { 0 }, .brk = { 0 } }, /* 158 */ + {.mk = { 0 }, .brk = { 0 } }, /* 159 */ + {.mk = { 0 }, .brk = { 0 } }, /* 15a */ + {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 15b LGUI->Muhenkan (in emulator only) */ + {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 15c RGUI->Henkan (in emulator only) */ + {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 15d APPLICATION->Kana (in emulator only) */ + {.mk = { 0 }, .brk = { 0 } }, /* 15e */ + {.mk = { 0 }, .brk = { 0 } }, /* 15f */ + {.mk = { 0 }, .brk = { 0 } }, /* 160 */ + {.mk = { 0 }, .brk = { 0 } }, /* 161 */ + {.mk = { 0 }, .brk = { 0 } }, /* 162 */ + {.mk = { 0 }, .brk = { 0 } }, /* 163 */ + {.mk = { 0 }, .brk = { 0 } }, /* 164 */ + {.mk = { 0 }, .brk = { 0 } }, /* 165 */ + {.mk = { 0 }, .brk = { 0 } }, /* 166 */ + {.mk = { 0 }, .brk = { 0 } }, /* 167 */ + {.mk = { 0 }, .brk = { 0 } }, /* 168 */ + {.mk = { 0 }, .brk = { 0 } }, /* 169 */ + {.mk = { 0 }, .brk = { 0 } }, /* 16a */ + {.mk = { 0 }, .brk = { 0 } }, /* 16b */ + {.mk = { 0 }, .brk = { 0 } }, /* 16c */ + {.mk = { 0 }, .brk = { 0 } }, /* 16d */ + {.mk = { 0 }, .brk = { 0 } }, /* 16e */ + {.mk = { 0 }, .brk = { 0 } }, /* 16f */ + {.mk = { 0 }, .brk = { 0 } }, /* 170 */ + {.mk = { 0 }, .brk = { 0 } }, /* 171 */ + {.mk = { 0 }, .brk = { 0 } }, /* 172 */ + {.mk = { 0 }, .brk = { 0 } }, /* 173 */ + {.mk = { 0 }, .brk = { 0 } }, /* 174 */ + {.mk = { 0 }, .brk = { 0 } }, /* 175 */ + {.mk = { 0 }, .brk = { 0 } }, /* 176 */ + {.mk = { 0 }, .brk = { 0 } }, /* 177 */ + {.mk = { 0 }, .brk = { 0 } }, /* 178 */ + {.mk = { 0 }, .brk = { 0 } }, /* 179 */ + {.mk = { 0 }, .brk = { 0 } }, /* 17a */ + {.mk = { 0 }, .brk = { 0 } }, /* 17b */ + {.mk = { 0 }, .brk = { 0 } }, /* 17c */ + {.mk = { 0 }, .brk = { 0 } }, /* 17d */ + {.mk = { 0 }, .brk = { 0 } }, /* 17e */ + {.mk = { 0 }, .brk = { 0 } }, /* 17f */ + {.mk = { 0 }, .brk = { 0 } }, /* 180 */ + {.mk = { 0 }, .brk = { 0 } }, /* 181 */ + {.mk = { 0 }, .brk = { 0 } }, /* 182 */ + {.mk = { 0 }, .brk = { 0 } }, /* 183 */ + {.mk = { 0 }, .brk = { 0 } }, /* 184 */ + {.mk = { 0 }, .brk = { 0 } }, /* 185 */ + {.mk = { 0 }, .brk = { 0 } }, /* 186 */ + {.mk = { 0 }, .brk = { 0 } }, /* 187 */ + {.mk = { 0 }, .brk = { 0 } }, /* 188 */ + {.mk = { 0 }, .brk = { 0 } }, /* 189 */ + {.mk = { 0 }, .brk = { 0 } }, /* 18a */ + {.mk = { 0 }, .brk = { 0 } }, /* 18b */ + {.mk = { 0 }, .brk = { 0 } }, /* 18c */ + {.mk = { 0 }, .brk = { 0 } }, /* 18d */ + {.mk = { 0 }, .brk = { 0 } }, /* 18e */ + {.mk = { 0 }, .brk = { 0 } }, /* 18f */ + {.mk = { 0 }, .brk = { 0 } }, /* 190 */ + {.mk = { 0 }, .brk = { 0 } }, /* 191 */ + {.mk = { 0 }, .brk = { 0 } }, /* 192 */ + {.mk = { 0 }, .brk = { 0 } }, /* 193 */ + {.mk = { 0 }, .brk = { 0 } }, /* 194 */ + {.mk = { 0 }, .brk = { 0 } }, /* 195 */ + {.mk = { 0 }, .brk = { 0 } }, /* 196 */ + {.mk = { 0 }, .brk = { 0 } }, /* 197 */ + {.mk = { 0 }, .brk = { 0 } }, /* 198 */ + {.mk = { 0 }, .brk = { 0 } }, /* 199 */ + {.mk = { 0 }, .brk = { 0 } }, /* 19a */ + {.mk = { 0 }, .brk = { 0 } }, /* 19b */ + {.mk = { 0 }, .brk = { 0 } }, /* 19c */ + {.mk = { 0 }, .brk = { 0 } }, /* 19d */ + {.mk = { 0 }, .brk = { 0 } }, /* 19e */ + {.mk = { 0 }, .brk = { 0 } }, /* 19f */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1a9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1aa */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ab */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ac */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ad */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ae */ + {.mk = { 0 }, .brk = { 0 } }, /* 1af */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1b9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ba */ + {.mk = { 0 }, .brk = { 0 } }, /* 1bb */ + {.mk = { 0 }, .brk = { 0 } }, /* 1bc */ + {.mk = { 0 }, .brk = { 0 } }, /* 1bd */ + {.mk = { 0 }, .brk = { 0 } }, /* 1be */ + {.mk = { 0 }, .brk = { 0 } }, /* 1bf */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1c9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ca */ + {.mk = { 0 }, .brk = { 0 } }, /* 1cb */ + {.mk = { 0 }, .brk = { 0 } }, /* 1cv */ + {.mk = { 0 }, .brk = { 0 } }, /* 1cd */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ce */ + {.mk = { 0 }, .brk = { 0 } }, /* 1cf */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1d9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1da */ + {.mk = { 0 }, .brk = { 0 } }, /* 1db */ + {.mk = { 0 }, .brk = { 0 } }, /* 1dc */ + {.mk = { 0 }, .brk = { 0 } }, /* 1dd */ + {.mk = { 0 }, .brk = { 0 } }, /* 1de */ + {.mk = { 0 }, .brk = { 0 } }, /* 1df */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1e9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ea */ + {.mk = { 0 }, .brk = { 0 } }, /* 1eb */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ec */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ed */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ee */ + {.mk = { 0 }, .brk = { 0 } }, /* 1ef */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f0 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f1 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f2 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f3 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f4 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f5 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f6 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f7 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f8 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1f9 */ + {.mk = { 0 }, .brk = { 0 } }, /* 1fa */ + {.mk = { 0 }, .brk = { 0 } }, /* 1fb */ + {.mk = { 0 }, .brk = { 0 } }, /* 1fc */ + {.mk = { 0 }, .brk = { 0 } }, /* 1fd */ + {.mk = { 0 }, .brk = { 0 } }, /* 1fe */ + {.mk = { 0 }, .brk = { 0 } } /* 1ff */ + // clang-format on +}; + #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -1664,6 +2206,10 @@ keyboard_at_set_scancode_set(void) case 0x03: keyboard_set_table(scancode_set3); break; + + case 0x8a: + keyboard_set_table(scancode_set8a); + break; } } @@ -1922,19 +2468,22 @@ keyboard_at_write(void *priv) break; case 0xf0: /* Get/set scancode set */ - kbc_at_dev_queue_add(dev, (val > 3) ? 0xfe : 0xfa, 0); switch (val) { case 0x00: + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK */ keyboard_at_log("%s: Get scan code set [%02X]\n", dev->name, keyboard_mode); kbc_at_dev_queue_add(dev, keyboard_mode, 0); break; case 0x01 ... 0x03: + case 0x8a: + kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK */ keyboard_mode = val; keyboard_at_log("%s: Set scan code set [%02X]\n", dev->name, keyboard_mode); keyboard_at_set_scancode_set(); break; default: /* Fatal so any instance of anything attempting to set scan code > 3 can be reported to us. */ + kbc_at_dev_queue_add(dev, 0xfe, 0); /* Resend */ fatal("%s: Scan code set [%02X] invalid, resend\n", dev->name, val); dev->flags |= FLAG_CTRLDAT; dev->state = DEV_STATE_MAIN_WANT_IN; From 048a9409809b1dbefb1b424a817d6a0b52dfce57 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:41:08 +0900 Subject: [PATCH 0015/1190] Added a machine PS/55 model 5551T --- src/machine/m_ps2_mca.c | 260 +++++++++++++++++++++++++++++++++++- src/machine/machine_table.c | 40 ++++++ 2 files changed, 297 insertions(+), 3 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index cb83d9be7..fc2e3313b 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -67,6 +67,8 @@ #include <86box/port_92.h> #include <86box/serial.h> #include <86box/video.h> +#include <86box/vid_svga.h> +#include <86box/vid_vga.h> #include <86box/machine.h> #include <86box/plat_unused.h> @@ -103,6 +105,8 @@ static struct ps2_t { int pending_cache_miss; serial_t *uart; + + vga_t* mb_vga; } ps2; /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any @@ -140,6 +144,7 @@ static struct ps2_t { static uint8_t ps2_cache[65536]; static int ps2_cache_valid[65536 / 8]; +static void mem_encoding_update(void); #ifdef ENABLE_PS2_MCA_LOG int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; @@ -358,6 +363,61 @@ model_80_read(uint16_t port) return 0xff; } +static uint8_t +ps55_model_50t_read(uint16_t port) +{ + ps2_mca_log(" Read SysBrd %04X xx %04X:%04X\n", port, cs >> 4, cpu_state.pc); + switch (port) + { + case 0x100: + return ps2.planar_id & 0xff; + case 0x101: + return ps2.planar_id >> 8; + case 0x102: + return ps2.option[0]; + case 0x103: + uint8_t val = 0xff; + /* + I/O 103h - Bit 7-4: Memory Card ID (Connector 1 or 3) + Bit 3-0: Memory Card ID (Connector 2) + + Memory Card ID: 7h = 2 MB Memory Card 2 or 3 Installed + 5h = 4 MB Memory Card 2 Installed + */ + switch (mem_size / 1024) + { + case 2: + if (ps2.option[1] & 0x04) val = 0xff; + else val = 0x7f; + break; + case 4: + if (ps2.option[1] & 0x04) val = 0xff; + else val = 0x77; + break; + case 6: + if (ps2.option[1] & 0x04) val = 0x7f; + else val = 0x77; + break; + case 8: + default: + if (ps2.option[1] & 0x04) val = 0x5f; + else val = 0x77; + break; + } + ps2_mca_log(" Read MCA %04X %02X %04X:%04X mem_size = %d, ps2option1 = %2X\n", port, val, cs >> 4, cpu_state.pc, mem_size, ps2.option[1]); + return val; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + static void model_50_write(uint16_t port, uint8_t val) { @@ -655,6 +715,78 @@ model_80_write(uint16_t port, uint8_t val) } } +static void +ps55_model_50t_write(uint16_t port, uint8_t val)//pcem55 +{ + ps2_mca_log(" Write SysBrd %04X %02X %04X:%04X\n", port, val, cs >> 4, cpu_state.pc); + switch (port) + { + case 0x102: + lpt1_remove(); + serial_remove(ps2.uart); + if (val & 0x04) + { + if (val & 0x08) + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); + else + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); + } + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(LPT_MDA_ADDR); + break; + case 1: + lpt1_init(LPT1_ADDR); + break; + case 2: + lpt1_init(LPT2_ADDR); + break; + default: + break; + } + } + ps2.option[0] = val; + break; + case 0x103: + ps2.option[1] = val; + break; + case 0x104: + if ((ps2.option[2] ^ val) & 1) { + mem_encoding_update(); + if (val & 1)/* Disable E0000 - E0FFF(Make 2 KB hole for Display Adapter) */ + { + ps2_mca_log("ROM E0000-E0FFF is disabled.\n"); + //mem_mapping_set_addr(&bios_mapping 0xe1000, 0x1f000); + mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + //mem_mapping_disable(&bios_mapping[0]); + } + else/* Enable E0000 - E0FFF for BIOS */ + { + ps2_mca_log("ROM E0000-E0FFF is enabled.\n"); + //mem_mapping_set_addr(&bios_mapping 0xe0000, 0x20000); + //mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); + //mem_mapping_enable(&bios_mapping[0]); + } + } + ps2.option[2] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + default: + break; + } +} + uint8_t ps2_mca_read(uint16_t port, UNUSED(void *priv)) { @@ -793,7 +925,16 @@ ps2_mca_write(uint16_t port, uint8_t val, UNUSED(void *priv)) if (!(ps2.setup & PS2_SETUP_IO)) ps2.planar_write(port, val); else if (!(ps2.setup & PS2_SETUP_VGA)) + { + if (ps2.mb_vga) + { + if (vga_isenabled(ps2.mb_vga)) + vga_disable(ps2.mb_vga); + if (val & 1) + vga_enable(ps2.mb_vga); + } ps2.pos_vga = val; + } else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) mca_write(port, val); break; @@ -1150,7 +1291,27 @@ mem_encoding_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) } mem_encoding_update(); } - +static void +mem_encoding_write_ps55(uint16_t addr, uint8_t val, void* p) +{ + //ps2_mca_log(" Write Memory Encoding %04X %02X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + switch (addr) + { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + default: + break; + } + mem_encoding_update(); + if (ps2.option[2] & 1) /* reset memstate for E0000 - E0FFFh hole */ + { + mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } +} static uint8_t mem_encoding_read_cached(uint16_t addr, UNUSED(void *priv)) { @@ -1311,7 +1472,7 @@ ps2_mca_board_model_70_type34_init(int is_type4, int slots) } if (gfxcard[0] == VID_INTERNAL) - device_add(&ps1vga_mca_device); + ps2.mb_vga = device_add(&ps1vga_mca_device); } static void @@ -1385,7 +1546,7 @@ ps2_mca_board_model_80_type2_init(void) } if (gfxcard[0] == VID_INTERNAL) - device_add(&ps1vga_mca_device); + ps2.mb_vga = device_add(&ps1vga_mca_device); ps2.split_size = 0; } @@ -1576,3 +1737,96 @@ machine_ps2_model_70_type4_init(const machine_t *model) return ret; } + +void +ps55_mca_board_model_50t_init() +{ + ps2_mca_board_common_init(); + + //mem_remap_top(256); + ps2.split_addr = mem_size * 1024; + /* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */ + mca_init(5); + device_add(&keyboard_ps2_mca_1_device); + + ps2.planar_read = ps55_model_50t_read; + ps2.planar_write = ps55_model_50t_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write_ps55, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + ps2.option[2] &= 0xfe; /* Bit 0: Disable E0000-E0FFFh (4 KB) */ + + //resize bios_mapping 0,1 + //mem_mapping_set_addr(&bios_mapping[0], 0xe0000, 0x1000); + //mem_mapping_set_exec(&bios_mapping[0], rom + (0x20000 & biosmask)); + //mem_mapping_set_addr(&bios_mapping[1], 0xe1000, 0x7000); + //mem_mapping_set_exec(&bios_mapping[1], rom + (0x21000 & biosmask)); + //mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x20000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0); + //mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x23000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0); + + mem_mapping_add(&ps2.split_mapping, + (mem_size + 256) * 1024, + 256 * 1024, + ps2_read_split_ram, + ps2_read_split_ramw, + ps2_read_split_raml, + ps2_write_split_ram, + ps2_write_split_ramw, + ps2_write_split_raml, + &ram[0xa0000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.split_mapping); + + if (mem_size > 8192) { + /* Only 8 MB supported on planar, create a memory expansion card for the rest */ + ps2_mca_mem_fffc_init(8); + } + + if (gfxcard[0] == VID_INTERNAL) + ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device); +} + +int +machine_ps55_model_50t_init(const machine_t* model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ibmps55_m50t/38F6933.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + /* begin ps2 common init */ + machine_common_init(model); + + device_add(&fdc_at_ps55_device); + + dma16_init(); + ps2_dma_init(); + device_add(&ps_no_nmi_nvr_device); + pic2_init(); + + int pit_type = ((pit_mode == -1 && is486) || pit_mode == 1) ? PIT_8254_FAST : PIT_8254; + pit_ps2_init(pit_type); + + nmi_mask = 0x80; + + ps2.uart = device_add_inst(&ns16550_device, 1); + /* end ps2 common init */ + + /* + * Planar ID + * FFFAh - PS/55 model 5551-S0x, T0x (stage 1?) + * FFEEh - PS/55 model 5551-S1x, T1x (stage 2?) + * POST (P/N 38F6933) determination: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error) + */ + ps2.planar_id = 0xffee; + ps55_mca_board_model_50t_init(); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index a9d83f241..c005c9282 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5468,6 +5468,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has IBM PS/55 5551-Sxx, Txx stage 2 firmware. */ + { + .name = "[MCA] IBM PS/55 model 5550-T", + .internal_name = "ibmps55_m50t", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps55_model_50t_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO | MACHINE_APM, + .ram = { + .min = 2048, + .max = 16384, + .step = 2048 + }, + .nvrmask = 63, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 386DX/486 machines */ /* Has AMIKey F KBC firmware. */ From d46121497c111acf42ac02c661d47fb229baa0b5 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:42:43 +0900 Subject: [PATCH 0016/1190] Added IBM Display Adapter II for PS/55 emulation --- src/video/CMakeLists.txt | 2 +- src/video/vid_ps55da2.c | 3153 ++++++++++++++++++++++++++++++++++++++ src/video/vid_svga.c | 22 +- src/video/vid_table.c | 2 + src/video/vid_vga.c | 34 + 5 files changed, 3209 insertions(+), 4 deletions(-) create mode 100644 src/video/vid_ps55da2.c diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 2f7607ad6..96d669ae1 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c - vid_bochs_vbe.c) + vid_bochs_vbe.c vid_ps55da2.c ) if(G100) target_compile_definitions(vid PRIVATE USE_G100) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c new file mode 100644 index 000000000..13f823c83 --- /dev/null +++ b/src/video/vid_ps55da2.c @@ -0,0 +1,3153 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PS/55 Display Adapter II emulation. + * + * Authors: Akamaki. + * + * Copyright 2024 Akamaki. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/mca.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_ps55da2.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include "cpu.h" + +#define DA2_FONTROM_PATH "roms/video/da2/PS55FNTJ.BIN" +#define DA2_FONTROM_SIZE 1024*1024 +#define DA2_MASK_MMIO 0x1ffff +#define DA2_MASK_GRAM 0x1ffff +#define DA2_MASK_CRAM 0xfff +#define DA2_MASK_GAIJIRAM 0x3ffff +#define DA2_PIXELCLOCK 58000000.0 +#define DA2_BLT_MEMSIZE 0x80 +#define DA2_BLT_REGSIZE 0x40 +#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) +#define DA2_DEBUG_BLTLOG_MAX 256*1024 +#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe +#define DA2_DEBUG_BLT_USEDRESET 0xfefefe + +#define DA2_BLT_CIDLE 0 +#define DA2_BLT_CFILLRECT 1 +#define DA2_BLT_CFILLTILE 2 +#define DA2_BLT_CCOPYF 3 +#define DA2_BLT_CCOPYR 4 +#define DA2_BLT_CDONE 5 +#define DA2_BLT_CLOAD 6 +/* POS ID = 0xeffe : Display Adapter II, III, V */ +#define DA2_POSID_H 0xef +#define DA2_POSID_L 0xfe +/* + [Identification] + POS ID SYS ID + EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] + E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] + EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] + |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) + |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) + |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) + ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] + |- * Display Adapter IV + ECCEh * Display Adapter IV + 901Fh * Display Adapter A2 + 901Dh * Display Adapter A1 [Atlas II] + 901Eh * Plasma Display Adapter + EFD8h * Display Adapter/J [Atlas-SP2] + + [Japanese DOS and Display Adapter compatibility] + | POS ID | Adapter Name | K3.31 | J4.04 | J5.02 | OS2 J1.3 | Win3 | + |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| + | EFFFh | Display Adapter | X | | | ? | | + | FFEDh | ? [Atlas EVT] | X | | | ? | | + | FFFDh | ? [LDT EVT] | X | | | ? | | + | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | + | E013h | ? [LDT] | X | X | X | X | | + | ECCEh | Display Adapter IV | | X | X | X | | + | ECECh | Display Adapter IV,B1 | | X | X | X | X | + | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | + | EFD8h | Display Adapter /J | | | X | X | X | +*/ +/* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ +#define OldLSI 0x20 /* DA-2 or DA-3,5 */ +#define Mon_ID3 0x10 +#define FontCard 0x08 /* ? */ +/* IO 3E0/3E1:0Ah Hardware Configuration Value H (imported from OS/2 DDK) */ +#define AddPage 0x08 /* ? */ +#define Mon_ID2 0x04 +#define Mon_ID1 0x02 +#define Mon_ID0 0x01 +/* Monitor ID (imported from OS/2 DDK 1.2) */ +//#define StarbuckC 0x0A //1010b IBM 8514, 9518 color 1040x768 +//#define StarbuckM 0x09 //1001b x grayscale +//#define Lark_B 0x02 //0010b IBM 9517 color 1040x768 +//#define Dallas 0x0B //1011b IBM 8515, 9515 color 1040x740 B palette +/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ +#define Page_One 0x06 /* 80000h 110b */ +#define Page_Two 0x05 /* 100000h 101b */ +#define Page_Four 0x03 /* 200000h 011b */ + +/* DA2 Registers (imported from OS/2 DDK) */ +#define AC_REG 0x3EE +#define AC_DMAE 0x80 +#define AC_FONT_SEL 0x40 +#define FONT_BANK 0x3EF +#define LS_INDEX 0x3E0 +#define LS_DATA 0x3E1 +#define LS_RESET 0x00 +#define LS_MODE 0x02 +#define LS_STATUS 0x03 /* added */ +#define LS_MMIO 0x08 /* added */ +#define LS_CONFIG1 0x0a +#define LS_CONFIG2 0x0b /* added */ +#define LF_INDEX 0x3e2 +#define LF_DATA 0x3e3 +#define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_ADDR 0x0A /* added */ +#define LF_MMIO_MODE 0x0B /* added */ +#define LC_INDEX 0x3E4 +#define LC_DATA 0x3E5 +#define LC_HORIZONTAL_TOTAL 0x00 +#define LC_H_DISPLAY_ENABLE_END 0x01 +#define LC_START_H_BLANKING 0x02 +#define LC_END_H_BLANKING 0x03 +#define LC_START_HSYNC_PULSE 0x04 +#define LC_END_HSYNC_PULSE 0x05 +#define LC_VERTICAL_TOTALJ 0x06 +#define LC_CRTC_OVERFLOW 0x07 +#define LC_PRESET_ROW_SCANJ 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_ROW_CURSOR_LOC 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_COLUMN_CURSOR_LOC 0x0F +#define LC_VERTICAL_SYNC_START 0x10 +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_VERTICAL_SYNC_END 0x11 +#define LC_LIGHT_PEN_LOW 0x11 +#define LC_V_DISPLAY_ENABLE_END 0x12 +#define LC_OFFSET 0x13 +#define LC_UNDERLINE_LOCATION 0x14 +#define LC_START_VERTICAL_BLANK 0x15 +#define LC_END_VERTICAL_BLANK 0x16 +#define LC_LC_MODE_CONTROL 0x17 +#define LC_LINE_COMPAREJ 0x18 +#define LC_START_H_DISPLAY_ENAB 0x19 +#define LC_START_V_DISPLAY_ENAB 0x1A +#define LC_VIEWPORT_COMMAND 0x1B +#define LC_VIEWPORT_SELECT 0x1C +#define LC_VIEWPORT_PRIORITY 0x1D +#define LC_COMMAND 0x1E +#define LC_COMPATIBILITY 0x1F +#define LC_VIEWPORT_NUMBER 0x1F +#define LV_PORT 0x3E8 +#define LV_PALETTE_0 0x00 +#define LV_MODE_CONTROL 0x10 +#define LV_OVERSCAN_COLOR 0x11 +#define LV_COLOR_PLANE_ENAB 0x12 +#define LV_PANNING 0x13 +#define LV_VIEWPORT1_BG 0x14 +#define LV_VIEWPORT2_BG 0x15 +#define LV_VIEWPORT3_BG 0x16 +#define LV_BLINK_COLOR 0x17 +#define LV_BLINK_CODE 0x18 +#define LV_GR_CURSOR_ROTATION 0x19 +#define LV_GR_CURSOR_COLOR 0x1A +#define LV_GR_CURSOR_CONTROL 0x1B +#define LV_COMMAND 0x1C +#define LV_VP_BORDER_LINE 0x1D +#define LV_SYNC_POLARITY 0x1F +#define LV_CURSOR_CODE_0 0x20 +#define LV_GRID_COLOR_0 0x34 +#define LV_GRID_COLOR_1 0x35 +#define LV_GRID_COLOR_2 0x36 +#define LV_GRID_COLOR_3 0x37 +#define LV_ATTRIBUTE_CNTL 0x38 +#define LV_CURSOR_COLOR 0x3A +#define LV_CURSOR_CONTROL 0x3B +#define LV_RAS_STATUS_VIDEO 0x3C +#define LV_PAS_STATUS_CNTRL 0x3D +#define LV_IDENTIFICATION 0x3E +#define LV_OUTPUT 0x3E +#define LV_COMPATIBILITY 0x3F +#define LG_INDEX 0x3EA +#define LG_DATA 0x3EB +#define LG_SET_RESETJ 0x00 +#define LG_ENABLE_SRJ 0x01 +#define LG_COLOR_COMPAREJ 0x02 +#define LG_DATA_ROTATION 0x03 +#define LG_READ_MAP_SELECT 0x04 +#define LG_MODE 0x05 +#define LG_COMPLEMENT 0x06 +#define LG_COLOR_DONT_CARE 0x07 +#define LG_BIT_MASK_LOW 0x08 +#define LG_BIT_MASK_HIGH 0x09 +#define LG_MAP_MASKJ 0x0A +#define LG_COMMAND 0x0B +#define LG_SET_RESET_2 0x10 + +#ifdef ENABLE_DA2_LOG +int da2_do_log = ENABLE_DA2_LOG; + +static void +da2_log(const char* fmt, ...) +{ + va_list ap; + + if (da2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define da2_log(fmt, ...) +#endif +#ifndef RELEASE_BUILD +# define ENABLE_DA2_DEBUGBLT 1 +#endif + +typedef struct da2_t +{ + //mem_mapping_t vmapping; + mem_mapping_t cmapping; + + //uint8_t crtcreg; + uint8_t ioctl[16]; + uint8_t fctl[32]; + uint16_t crtc[128]; + uint8_t gdcreg[64]; + uint8_t reg3ee[16]; + int gdcaddr; + uint8_t attrregs[0x40]; + int attraddr, attrff; + int attr_palette_enable; + //uint8_t seqregs[64]; + int outflipflop; + int inflipflop; + int iolatch; + + int ioctladdr; + int fctladdr; + int crtcaddr; + + uint8_t miscout; + //int vidclock; + + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint32_t gdcla[8]; + //int gdcramlatched; + uint32_t gdcinput[8]; + uint32_t gdcsrc[8]; + uint32_t debug_vramold[8]; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; + + //IO 3DAh Input Status Register 2 + uint8_t cgastat; + + uint8_t plane_mask; + + int fb_only; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t pallook[512]; + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int rowcount; + double clock; + uint32_t ma_latch, ca_adj; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + uint64_t da2const; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink, blinkconf; + int scrollcache; + int char_width; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + /* Attribute Buffer E0000-E0FFFh (4 KB) */ + uint8_t *cram; + /* (cram size - 1) >> 3 = 0xFFF */ + //uint32_t cram_display_mask; + /* APA Buffer A0000-BFFFFh (128 KB) */ + uint8_t *vram; + /* addr >> 12 = xx000h */ + uint8_t *changedvram; + /* (vram size - 1) >> 3 = 0x1FFFF */ + uint32_t vram_display_mask; + uint32_t banked_mask; + + uint32_t write_bank, read_bank; + + int fullchange; + + //int video_res_x, video_res_y, video_bpp; + //int video_res_override; /*If clear then SVGA code will set above variables, if + // set then card code will*/ + //int frames, writelines; + + void (*render)(struct da2_t* da2); + //void (*recalctimings_ex)(struct da2_t* da2); + + //void (*video_out)(uint16_t addr, uint8_t val, void* p); + //uint8_t(*video_in) (uint16_t addr, void* p); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + //void* p; + + /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ + //int hsync_divisor; + + /* end VGA compatible regs*/ + struct + { + int enable; + mem_mapping_t mapping; + uint8_t ram[256 * 1024]; + uint8_t font[DA2_FONTROM_SIZE]; + } mmio; + + mem_mapping_t linear_mapping; + + uint32_t bank[2]; + uint32_t mask; + + int type; + + struct { + int bitshift_destr; + int raster_op; + uint8_t payload[DA2_BLT_MEMSIZE]; + int32_t reg[DA2_BLT_REGSIZE];//must be signed int + int32_t* debug_reg;//for debug + int debug_reg_ip;//for debug + int payload_addr; + pc_timer_t timer; + int64_t timerspeed; + int exec; + int indata; + int32_t destaddr; + int32_t srcaddr; + int32_t size_x, tile_w; + int32_t size_y; + int16_t destpitch; + int16_t srcpitch; + int32_t fcolor; + int32_t maskl, maskr; + int x, y; + } bitblt; + + FILE* mmdbg_fp; + FILE* mmrdbg_fp; + uint32_t mmdbg_vidaddr; + uint32_t mmrdbg_vidaddr; + + uint8_t pos_regs[8]; + svga_t *mb_vga; + + int vidsys_ena; + + int old_pos2; +} da2_t; + +void da2_recalctimings(da2_t* da2); +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p); +void da2_bitblt_exec(void* p); +void da2_updatevidselector(da2_t* da2); +void da2_reset_ioctl(da2_t* da2); +static void da2_reset(void* priv); + +typedef union { + uint32_t d; + uint8_t b[4]; +} DA2_VidSeq32; + +typedef struct { + uint32_t p8[8]; +} pixel32; + +/* safety read for internal functions */ +uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) +{ + if (addr & ~da2->vram_mask) return -1; + return da2->vram[addr]; +} + +void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32* srcpx, da2_t* da2) +{ + uint32_t writepx[8]; + destaddr &= 0xfffffffe;/* align to word address to work bit shift correctly */ + //da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); + da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; + da2->changedvram[(da2->vram_display_mask & (destaddr+1)) >> 12] = changeframecount; + destaddr <<= 3; + /* read destination data with big endian order */ + for (int i = 0; i < 8; i++) + writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) + | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); + + DA2_VidSeq32 mask32in; mask32in.d = (uint32_t)mask; + DA2_VidSeq32 mask32; mask32.d = 0; + mask32.b[3] = mask32in.b[0]; + mask32.b[2] = mask32in.b[1]; + mask32.d &= 0xffff0000; + for (int i = 0; i < 8; i++) + { + if (da2->bitblt.bitshift_destr > 0) + srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; + switch (da2->bitblt.raster_op) { + case 0x00: /* None */ + writepx[i] &= ~mask32.d; + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x01: /* AND */ + writepx[i] &= srcpx->p8[i] | ~mask32.d; + break; + case 0x02: /* OR */ + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x03: /* XOR */ + writepx[i] ^= srcpx->p8[i] & mask32.d; + break; + } + } + for (int i = 0; i < 8; i++) { + da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; + da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; + } +} + +void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + //fill data with input color + for (int i = 0; i < 8; i++) + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +/* +Param Desc +01 Color +03 Bit Shift +04 Select plane? +05 Dir(10 or 11) + Command?(40 or 48) +08 Mask Left +09 Mask Right +0A Plane Mask? +0B ROP?(8h or 200h + 0-3h) +0D +20 Exec (1) +21 ? +22 ? +23 Tile W +28 Tile H +29 Dest Addr +2A Src Addr +2B Tile Addr +33 Size W +35 Size H + +*/ +void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + srcaddr &= 0xfffffffe; + srcaddr <<= 3; + for (int i = 0; i < 8; i++) + srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) + | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { + uint8_t pixeldata = 0; + for (int j = 0; j < 8; j++) { + if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) pixeldata++; + } + return pixeldata; +} +void print_pixelbyte(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) + { + da2_log("%X", pixel1tohex(addr, i, da2)); + } +} + +void da2_bitblt_load(da2_t* da2) +{ + uint32_t value32; + uint64_t value64; + //da2_log("BITBLT loading params\n"); + //da2_log("BitBlt memory:\n"); + //if (da2->bitblt.payload[0] != 0) + // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) + // { + // int i = j * 8; + // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + // } + int i = 0; + while (i < DA2_BLT_MEMSIZE) + { + if (da2->bitblt.reg[0x20] & 0x1) + break; + switch (da2->bitblt.payload[i]) { + case 0x88: + case 0x89: + case 0x95: + value32 = da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + //da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 3; + break; + case 0x91: + value32 = da2->bitblt.payload[i + 5]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 4]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + //da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 5; + break; + case 0x99: + value64 = da2->bitblt.payload[i + 7]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 6]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 2]; + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + //da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + //da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + i += 7; + break; + case 0x00: + break; + default: + da2_log("da2_ParseBLT: Unknown PreOP!\n"); + break; + } + i++; + } + da2->bitblt.exec = DA2_BLT_CIDLE; + /* clear payload memory */ + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; + /* [89] 20: 0001 (1) then execute payload */ + if (da2->bitblt.reg[0x20] & 0x1) + { +#ifdef ENABLE_DA2_DEBUGBLT + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + //if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); + } + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; + } + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; + da2->bitblt.debug_reg_ip++; + if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);//set bit shift + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;//01 AND, 03 XOR + da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); + for (int i = 0; i <= 0xb; i++) + da2_log("%02x ", da2->gdcreg[i]); + da2_log("\n"); + + da2->bitblt.destaddr = da2->bitblt.reg[0x29]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + da2->bitblt.size_y = da2->bitblt.reg[0x35]; + da2->bitblt.destpitch = da2->bitblt.reg[0x21]; + da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + { + da2->bitblt.destaddr -= 2; + da2->bitblt.size_x += 1; + da2->bitblt.destpitch -= 2; + da2->bitblt.srcpitch -= 2; + } + da2->bitblt.fcolor = da2->bitblt.reg[0x0]; + da2->bitblt.maskl = da2->bitblt.reg[0x8]; + da2->bitblt.maskr = da2->bitblt.reg[0x9]; + da2->bitblt.x = 0; + da2->bitblt.y = 0; + da2->bitblt.exec = DA2_BLT_CDONE; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + + if (da2->bitblt.reg[0x2f] < 0x80)//MS Paint 3.1 will cause hang up in 256 color mode + { + da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); + da2->bitblt.exec = DA2_BLT_CDONE; + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {//Fill a rectangle (or draw a line) + da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); + da2->bitblt.exec = DA2_BLT_CFILLRECT; + da2->bitblt.destaddr += 2; + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle ??(transfer tile data multiple times) os/2 only + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle (transfer tile data multiple times) + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {//Block transfer (range copy) + da2->bitblt.exec = DA2_BLT_CCOPYF; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr += 2; + da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {//Block copy but reversed direction + da2->bitblt.exec = DA2_BLT_CCOPYR; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); + } + //do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle + while (timer_is_enabled(&da2->bitblt.timer) && da2->bitblt.exec != DA2_BLT_CDONE) + { + da2_bitblt_exec(da2); + } + } +} +void da2_bitblt_exec(void* p) +{ + da2_t* da2 = (da2_t*)p; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + switch (da2->bitblt.exec) + { + case DA2_BLT_CIDLE: + timer_disable(&da2->bitblt.timer); + break; + case DA2_BLT_CLOAD: + da2_bitblt_load(da2); + da2->bitblt.indata = 0; + break; + case DA2_BLT_CFILLRECT: + //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CFILLTILE: + int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CCOPYF: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr += 2; + break; + case DA2_BLT_CCOPYR: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr -= da2->bitblt.destpitch; + da2->bitblt.srcaddr -= da2->bitblt.srcpitch; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + break; + case DA2_BLT_CDONE: + //initialize regs with fefefefeh, clear regs with fefeh for debug dump + for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + } + if(da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; + else da2->bitblt.exec = DA2_BLT_CIDLE; + break; + } +} +void da2_out(uint16_t addr, uint16_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + int oldval; +/* +3E0 3E1 Sequencer Registers (undoc) +3E2 3E3 Font Registers (undoc) +3E4 3E5 CRT Control Registers (undoc) +3E8 3E9 Attribute Controller Registers (undoc) +3EA 3EB 3EC Graphics Contoller Registers +*/ + switch (addr) + { + case 0x3c6: /* PEL Mask */ + da2->dac_mask = val; + break; + case 0x3C7: /* Read Address */ + da2->dac_read = val; + da2->dac_pos = 0; + break; + case 0x3C8: /* Write Address */ + da2->dac_write = val; + da2->dac_read = val - 1; + da2->dac_pos = 0; + break; + case 0x3C9: /* Data */ + //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); + //da2_log("DS %X\n",DS); + da2->dac_status = 0; + da2->fullchange = changeframecount; + switch (da2->dac_pos) + { + case 0: + da2->dac_r = val; + da2->dac_pos++; + break; + case 1: + da2->dac_g = val; + da2->dac_pos++; + break; + case 2: + da2->vgapal[da2->dac_write].r = da2->dac_r; + da2->vgapal[da2->dac_write].g = da2->dac_g; + da2->vgapal[da2->dac_write].b = val; + //if (da2->ramdac_type == RAMDAC_8BIT) + // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); + //else + da2->pallook[da2->dac_write] = makecol32((da2->vgapal[da2->dac_write].r & 0x3f) * 4, (da2->vgapal[da2->dac_write].g & 0x3f) * 4, (da2->vgapal[da2->dac_write].b & 0x3f) * 4); + da2->dac_pos = 0; + da2->dac_write = (da2->dac_write + 1) & 255; + break; + } + break; + case LS_INDEX: + da2->ioctladdr = val; + break; + case LS_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); + if (da2->ioctladdr > 0xf) return; + //if (da2->ioctl[da2->ioctladdr & 15] != val) + // da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); + oldval = da2->ioctl[da2->ioctladdr]; + //if (da2->ioctladdr == 0x3) return;//monitor color + da2->ioctl[da2->ioctladdr] = val; + if (oldval != val) { + if (da2->ioctladdr == LS_RESET && val & 0x01) /* Mode register */ + da2_reset_ioctl(da2); + else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + da2_updatevidselector(da2); + } + else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ + { + da2->bitblt.indata = 1; + if (da2->bitblt.exec == DA2_BLT_CIDLE) + { + da2->bitblt.exec = DA2_BLT_CLOAD; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + } + } + } + break; + case LF_INDEX: + da2->fctladdr = val; + break; + case LF_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + if (da2->fctladdr > 0x1f) return; + oldval = da2->fctl[da2->fctladdr]; + da2->fctl[da2->fctladdr] = val; + if (da2->fctladdr == 0 && oldval != val) + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + } + break; + case LC_INDEX: + da2->crtcaddr = val; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return; + if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + if (!(da2->crtc[da2->crtcaddr] ^ val)) return; + switch (da2->crtcaddr) { + case LC_CRTC_OVERFLOW: + //return; + break; + case LC_MAXIMUM_SCAN_LINE: + if (!(da2->ioctl[LS_MODE] & 0x01)) val = 0; + break; + case LC_START_ADDRESS_HIGH: + //if (da2->crtc[0x1c] & 0x40) return; + break; + case LC_VERTICAL_TOTALJ: /* Vertical Total */ + case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ + case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ + case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ + //val = 0x400; //for debugging bitblt + break; + case LC_VIEWPORT_SELECT: /* ViewPort Select? */ + //return; + break; + case LC_VIEWPORT_NUMBER: /* Compatibility? */ + break; + } + da2->crtc[da2->crtcaddr] = val; + switch (da2->crtcaddr) { + case LC_H_DISPLAY_ENABLE_END: + case LC_VERTICAL_TOTALJ: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + case LC_VERTICAL_SYNC_START: + case LC_V_DISPLAY_ENABLE_END: + case LC_START_VERTICAL_BLANK: + case LC_END_VERTICAL_BLANK: + case LC_VIEWPORT_PRIORITY: + da2->fullchange = changeframecount; + da2_recalctimings(da2); + break; + default: + break; + } + break; + case LV_PORT: + da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + if (!da2->attrff) + { + // da2->attraddr = val & 31; + da2->attraddr = val & 0x3f; + if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) + { + da2->fullchange = 3; + da2->attr_palette_enable = val & 0x20; + da2_recalctimings(da2); + } + //da2_log("set attraddr: %X\n", da2->attraddr); + } + else + { + if ((da2->attraddr == LV_PANNING) && (da2->attrregs[LV_PANNING] != val)) + da2->fullchange = changeframecount; + if (da2->attrregs[da2->attraddr & 0x3f] != val) + da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrregs[da2->attraddr & 0x3f], val); + da2->attrregs[da2->attraddr & 0x3f] = val; + //da2_log("set attrreg %x: %x\n", da2->attraddr & 31, val); + if (da2->attraddr < 16) + da2->fullchange = changeframecount; + //if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr == 0x14 || da2->attraddr < 0x10) + if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) + { + for (int c = 0; c < 16; c++) + { + //if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrregs[c] & 0xf) | ((da2->attrregs[0x14] & 0xf) << 4); + //else da2->egapal[c] = (da2->attrregs[c] & 0x3f) | ((da2->attrregs[0x14] & 0xc) << 4); + if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrregs[c] & 0xf; + else da2->egapal[c] = da2->attrregs[c] & 0x3f; + } + } + if (da2->attraddr == LV_COLOR_PLANE_ENAB) + { + if ((val & 0xff) != da2->plane_mask) + da2->fullchange = changeframecount; + da2->plane_mask = val & 0xff; + } + if (da2->attraddr == LV_CURSOR_CONTROL) + { + switch (val & 0x18) { + case 0x08://fast blink + da2->blinkconf = 0x10; + break; + case 0x18://slow blink + da2->blinkconf = 0x20; + break; + default://no blink + da2->blinkconf = 0xff; + break; + } + } + switch (da2->attraddr) + { + case LV_MODE_CONTROL: + case LV_ATTRIBUTE_CNTL: + case LV_COMPATIBILITY: + da2_recalctimings(da2); + break; + default: + break; + } + } + da2->attrff ^= 1; + break; + case LG_INDEX: + da2->gdcaddr = val; + break; + case LG_DATA: + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + switch (da2->gdcaddr & 0x1f) + { + case LG_READ_MAP_SELECT: + da2->readplane = val & 0x7; + break; + case LG_MODE: + da2->writemode = val & 3; + break; + case LG_MAP_MASKJ: + da2->writemask = val & 0xff; + break; + case LG_COMMAND: + break; + case LG_SET_RESET_2: + da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); + return; + } + da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; + break; + //case 0x3ed: /* used by Windows 3.1 display driver */ + // da2->gdcreg[5] = val & 0xff; + // break; + default: + da2_log("DA2? Out addr %03X val %02X\n", addr, val); + break; + } +} + +uint16_t da2_in(uint16_t addr, void *p) +{ + da2_t * da2 = (da2_t *)p; + //svga_t *svga = &da2->svga; + uint16_t temp; + +// if (addr != 0x3da) da2_log("IN gd5429 %04X\n", addr); + switch (addr) + { + case 0x3c3: + temp = 0; + break; + case 0x3c6: temp = da2->dac_mask; + break; + case 0x3c7: temp = da2->dac_status; + break; + case 0x3c8: temp = da2->dac_write; + break; + case 0x3c9: + da2->dac_status = 3; + switch (da2->dac_pos) + { + case 0: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].r & 0x3f; + break; + case 1: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].g & 0x3f; + break; + case 2: + da2->dac_pos = 0; + da2->dac_read = (da2->dac_read + 1) & 255; + temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case LS_INDEX: + temp = da2->ioctladdr; + break; + case LS_DATA: + //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) + if (da2->ioctladdr > 0xf) return 0xff; + temp = da2->ioctl[da2->ioctladdr]; + if (da2->ioctladdr == LS_STATUS) { /* Status register */ + //da2_log("Read 3E1 DAC status: %d, %d, %d\n", da2->vgapal[0].r, da2->vgapal[0].g, da2->vgapal[0].b); + //da2_log("attr palette: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->attrregs[i]); + //da2_log("\n"); + //da2_log("vram A0000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[i]); + //da2_log("\n"); + //da2_log("vram B8000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[0x18000 + i]); + //da2_log("\n"); + //da2_log("vram E0000h: "); + //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->cram[i]); + //da2_log("\n"); + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrregs[LV_COMPATIBILITY] & 0x08) + temp &= 0x7F; /* Inactive when the RGB output voltage is high(or the cable is not connected to the color monitor). */ + else + temp |= 0x80; /* Active when the RGB output voltage is lowand the cable is connected to the color monitor. + If the cable or the monitor is wrong, it becomes inactive. */ + temp &= 0xf6;//idle + if (da2->bitblt.exec != DA2_BLT_CIDLE) + { + //da2_log("exec:%d\n", da2->bitblt.exec); + temp |= 0x08;//wait(bit 3 + bit 0) + //if (!da2->bitblt.timer.enabled) + //{ + // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); + // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //} + } + if (da2->bitblt.indata) + temp |= 0x01; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + } + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + break; + case LF_INDEX: + temp = da2->fctladdr; + break; + case LF_DATA: + if (da2->fctladdr > 0x1f) return 0xff; + temp = da2->fctl[da2->fctladdr]; + break; + case LC_INDEX: + temp = da2->crtcaddr; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return 0xff; + temp = da2->crtc[da2->crtcaddr]; + break; + case LV_PORT: + temp = da2->attraddr | da2->attr_palette_enable; + break; + case 0x3E9: + if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this may equiv to 3ba / 3da Input Status Register 1 */ + { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + else + temp = da2->attrregs[da2->attraddr]; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); + da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ + break; + case LG_INDEX: + temp = da2->gdcaddr; + break; + case LG_DATA: + temp = da2->gdcreg[da2->gdcaddr & 0x1f]; + da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + break; + } + //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +/* +* Write I/O +* out b(idx), out b(data), out b(data) +* out b(idx), out w(data) +* out b(idx), out w(data), out b(data) +* out w(idx) +* Read I/O +* out b(idx), in b(data) +* out b(idx), in b, in b(data) +* out b(idx), in w(data) +*/ +void da2_outb(uint16_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + da2->inflipflop = 0; + switch (addr) + { + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + if (da2->outflipflop) + { + /* out b(idx), out b(data), out b(data) */ + da2->iolatch |= (uint16_t)val << 8; + da2->outflipflop = 0; + } + else + {// + da2->iolatch = val; + da2->outflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + default: + da2->iolatch = val; + da2->outflipflop = 0; + break; + } + da2_out(addr, da2->iolatch, da2); +} +void da2_outw(uint16_t addr, uint16_t val, void* p) +{ + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + switch (addr) + { + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + da2_out(addr, val & 0xff, da2); + da2->iolatch = val >> 8; + da2_out(addr + 1, da2->iolatch, da2); + da2->outflipflop = 1; + break; + case LV_PORT: + da2->attrff = 0; + da2_out(addr, val & 0xff, da2); + da2_out(addr, val >> 8, da2); + da2->outflipflop = 0; + break; + case 0x3EC: + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_out(LG_DATA, val >> 8, da2); + break; + case 0x3ED: + da2->gdcaddr = LG_MODE; + da2_out(LG_DATA, val, da2); + break; + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + default: + da2_out(addr, val, da2); + da2->outflipflop = 0; + break; + case 0x3EE: + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2->reg3ee[val & 0xff] = val >> 8; + break; + } +} +uint8_t da2_inb(uint16_t addr, void* p) +{ + uint8_t temp; + da2_t* da2 = (da2_t*)p; + da2->outflipflop = 0; + switch (addr) + { + case LC_DATA: + if (da2->inflipflop) + { + /* out b(idx), in b(low data), in b(high data) */ + temp = da2->iolatch >> 8; + da2->inflipflop = 0; + } + else + {// + da2->iolatch = da2_in(addr, da2); + temp = da2->iolatch & 0xff; + da2->inflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + case LS_DATA: + case LF_DATA: + case LG_DATA: + default: + temp = da2_in(addr, da2) & 0xff; + da2->inflipflop = 0; + break; + } + //da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +uint16_t da2_inw(uint16_t addr, void* p) +{ + //uint16_t temp; + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + da2->outflipflop = 0; + return da2_in(addr, da2); +} +/* IO 03DAh : Input Status Register 2 for DOSSHELL in DOS J4.0 */ +uint8_t da2_in_ISR(uint16_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t temp = 0; + if (addr == 0x3da) { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + //da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} + +void da2_out_ISR(uint16_t addr, uint8_t val, void* p) +{ + //da2_t* da2 = (da2_t*)p; + da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); +} + +/* +The IBM 5550 character mode addresses video memory between E0000h and E0FFFh. + [Character drawing] + SBCS: + 1 2 ... 13 + 1 | H.Grid + |---------------- + 2 | Space + 3 V| + .| + G| Font Pattern + r| (12x24 pixels) + i| + d| +26 |________________ +27 Space + ---------------- +28 Underscore ] + ---------------- >Cursor Position +29 ] + + DBCS: + 1 2 ... 13 1 2 ... 12 13 + 1 | H.Grid | H.Grid | + -|--------------------------|- + 2 | Space | Space | + -|--------------------------|- + 3 V| | |S + .| | |p + G| Font Pattern |a + r| (24x24 pixels) |c + i| | |e + d| | | +26 |_____________|____________| +27 | Space | Space + ------------------------------ +28 | Underscore | Underscore ] + ------------------------------ >Cursor Position +29 | | ] + + [Attributes] + Video mode 08h: + 7 6 5 4 3 2 1 0 + Blink |Under |HGrid |VGrid |Bright|Revers|FntSet|DBCS/SBCS| + + Video mode 0Eh: + -Blue |-Green|HGrid |VGrid |-Red |Revers|FntSet|DBCS/SBCS| + + Bit 1 switches the font bank to the Extended SBCS. DOS K3.x loads APL characters from $SYSEX24.FNT into it. + DOS Bunsho Program transfers 1/2 and 1/4 fonts fron the font ROM to the Extended SBCS. + This bit is not used for DBCS, but some apps set it as that column is right half of DBCS. + +[Font ROM Map (DA2)] +The Font ROM is accessed via 128 KB memory window located on A0000-BFFFFh. +I don't know how much data the actual Font ROM has. +Here information, I researched it by disassembling J-DOS. + +Bank 0 + 4800- * +Bank 1, 2, 3 + * - * +Bank 4 + * -0DB6Fh ( 4800-8DB6Fh;IBMJ 100-1F7Dh) : JIS X 0208 DBCS (24 x 24) +10000-16D1Fh (90000-96D1Fh;IBMJ 2000-2183h) : IBM Extended Characters +18000-1BFFFh (98000-9BFFFh;around IBMJ 21C7-22AAh) : JIS X 0201 SBCS (13 x 30) +1FD20- * +Bank 5 + * -0D09Fh (9FD20-AD09Fh;IBMJ 2384-2673h) : Gaiji 752 chs (maybe blank) +10000-13FFFh (B0000-B3FFFh;around IBMJ 271C-27FFh) : Extended SBCS (13 x 30) +14000-146FFh (B4000-B46FFh;IBMJ 2800-2818h) : Half-width box drawing characters (7 lines * 4 parts * 64 bytes) used by DOS Bunsho + (B9580-?;IBMJ 2930-295e?) : Full-width box drawing characters + + The signature 80h, 01h must be placed at Bank 0:1AFFEh to run OS/2 J1.3. + +[Gaiji RAM Map (DA2)] + Bank 0 00000-1FFFFh placed between A0000h-BFFFFh + 00000-1F7FFh(A0000-BF7FFh): Gaiji Non-resident (Kuten 103-114 ku,IBM: 2674-2ADBh) 1008 chs 128 bytes + 1F800-1FFFFh(BF800-BFFFFh): Gaiji Resident (SJIS: F040-F04Fh, IBM: 2384-2393h) 16 chs + + Bank 1 20000-3FFFFh placed between A0000h-BFFFFh + 20000-33FFFh(A0000-B3FFFh): Gaiji Resident (SJIS: F050-F39Ch, IBM: 2394-2613h) 640 chs + 34000-37FFFh(B4000-B7FFFh): Basic SBCS(00-FFh, ATTR bit 1 = off) + 38000-3AFFFh(B8000-BAFFFh): Gaiji Resident (SJIS: F39D-F3FCh, IBM: 2614-2673h) 96 chs + 3C000-3FFFFh(BC000-BFFFFh): Extended SBCS(00-FFh, ATTR bit 1 = on) + +[IBMJ code to Gaiji address conv tbl from DOS K3.3] + A B C + 2ADC, 2C5F, +5524 --> 8000 + 2614, 2673, +90EC --> B700 + 2384, 2613, +906C --> B3F0 + 0682, 1F7D, +0000 + + 8000 - 8183h 184h(388 characters) IBM Extended Characters + B3F0 - B75Fh 370h(880 characters) User-defined Characters +*/ + +/* Get character line pattern from jfont rom or gaiji volatile memory */ +uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { + da2_t* da2 = (da2_t*)p; + uint32_t font = 0; + int32_t fline = line - 2;//Start line of drawing character (line >= 1 AND line < 24 + 1 ) + if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) + if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { + font = da2->mmio.font[code * 72 + fline * 3]; //1111 1111 + font <<= 8; //1111 1111 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; //1111 1111 2222 0000 + font >>= 1; //0111 1111 1222 2000 + font <<= 4; //0111 1111 1222 2000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; //0111 1111 1222 2000 2222 + font <<= 8; //0111 1111 1222 2000 2222 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; //0111 1111 1222 2000 2222 3333 3333 + font <<= 4; //0111 1111 1222 2000 2222 3333 3333 0000 + //font >>= 1;//put blank at column 1 (and 26) + } + else if (code >= 0xb000 && code <= 0xb75f) + { + //convert code->address in gaiji memory + code -= 0xb000; + code *= 0x80; + //code += 0xf800; + font = da2->mmio.ram[code + line * 4]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 1]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 2]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 3]; + } + else if (code > DA2_FONTROM_SIZE) + font = 0xffffffff; + else + font = 0; + return font; +} + +/* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ +uint8_t IRGBtoBGRI(uint8_t attr) +{ + attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); + return attr >>= 4; +} +/* Get the foreground color from the attribute byte */ +uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) +{ + uint8_t foreground = ~attr & 0x08;// 0000 1000 + foreground <<= 2; //0010 0000 + foreground |= ~attr & 0xc0;// 1110 0000 + foreground >>= 4;//0000 1110 + if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette + return foreground; +} + +void da2_render_blank(da2_t* da2) +{ + int x, xx; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + for (x = 0; x < da2->hdisp; x++) + { + for (xx = 0; xx < 13; xx++) ((uint32_t*)buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; + } +} +/* Display Adapter Mode 8, E Drawing */ +static void da2_render_text(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->cram[(da2->ma) & da2->vram_display_mask]; + attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; + //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); + if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh + {//--Parse attribute byte in color mode-- + bg = 0;//bg color is always black (the only way to change background color is programming PAL) + fg = getPS55ForeColor(attr, da2); + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + } + else + {//--Parse attribute byte in monochrome mode-- + if (attr & 0x08) fg = 3;//Highlight 0000 1000 + else fg = 2; + bg = 0;//Background is always color #0 (default is black) + if (!(~attr & 0xCC))//Invisible 11xx 11xx -> 00xx 00xx + { + fg = bg; + attr &= 0x33;//disable blinkking, underscore, highlight and reverse + } + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + // Blinking 1000 0000 + fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; + //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); + } + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + //draw -= 13; + // SBCS or DBCS left half + if (chr_wide == 0) { + if (attr & 0x01) chr_wide = 1; + //chr_wide = 0; + // Stay drawing If the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + if (attr & 0x02)//second map of SBCS font + fontbase = 0x3c000; + else + fontbase = 0x34000; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. + if (da2->sc == 27 && attr & 0x40 && ~da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + } + //Column 1 (Vertical Line) + if (attr & 0x10) { + p[0] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + } + if (da2->sc == 0 && attr & 0x20 && ~da2->attrregs[LV_PAS_STATUS_CNTRL]) {//HGrid + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); + int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) {//Color 0 if reverse + bg = fg; + fg = 0; + } + for (uint32_t n = 0; n < cursorwidth; n++) + if (p[n] == da2->pallook[da2->egapal[cursorcolor]] || da2->egapal[bg] == da2->egapal[cursorcolor]) + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[fg]] : da2->pallook[da2->egapal[bg]]; + else + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[cursorcolor]] : p[n]; + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +/* Display Adapter Mode 3 Drawing */ +static void da2_render_textm3(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr, extattr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; + attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; + extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; + //if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); + bg = attr >> 4; + //if (da2->blink) bg &= ~0x8; + //fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; + fg = attr & 0xf; + fg = IRGBtoBGRI(fg); + bg = IRGBtoBGRI(bg); + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + // SBCS or DBCS left half + if (chr_wide == 0) { + if (extattr & 0x01) chr_wide = 1; + // Stay drawing if the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + fontbase = 0x34000; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); + //int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[0x1a]) : 2;//Choose color 2 if mode 8 + //fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + //bg = 0; + //if (attr & 0x04) {//Color 0 if reverse + // bg = fg; + // fg = 0; + //} + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +void da2_render_color_4bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + da2->plane_mask &= 0x0f;//safety + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); + p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); + p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); + p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); + p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); + p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); + p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); + p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); + p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_render_color_8bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + *(uint32_t*)(&edat[4]) = *(uint32_t*)(&da2->vram[(da2->ma << 3) + 4]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | + ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); + p[0] = da2->pallook[dat]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | + ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); + p[1] = da2->pallook[dat]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | + ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); + p[2] = da2->pallook[dat]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | + ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); + p[3] = da2->pallook[dat]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | + ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); + p[4] = da2->pallook[dat]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | + ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); + p[5] = da2->pallook[dat]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | + ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); + p[6] = da2->pallook[dat]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | + ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); + p[7] = da2->pallook[dat]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_updatevidselector(da2_t* da2) { + /* if VGA passthrough mode */ + da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); + if (da2->ioctl[LS_MODE] & 0x02) + { + da2->override = 1; + svga_set_override(da2->mb_vga, 0); + } + else + { + svga_set_override(da2->mb_vga, 1); + da2->override = 0; + } +} + + +void da2_recalctimings(da2_t* da2) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + + da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff;//w + da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff;//w + da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff;//w + da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff;//w Line Compare + da2->split = 0xfff; + da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;//w + da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; + + if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { + da2->hdisp--; + da2->dispend -= 29; + } + else { + //da2->vtotal += 2; + da2->dispend--; + //da2->vsyncstart++; + //da2->split++; + //da2->vblankstart++; + //da2->hdisp--; + } + + da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; + da2->htotal += 1; + + da2->rowoffset = da2->crtc[LC_OFFSET];//number of bytes in a scanline + + da2->clock = da2->da2const; + + da2->lowres = da2->attrregs[LC_VERTICAL_SYNC_START] & 0x40; + + da2->interlace = 0; + + //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b + da2->ca_adj = 0; + + da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; + + da2->hdisp_time = da2->hdisp; + da2->render = da2_render_blank; + //determine display mode + //if (da2->attr_palette_enable && (da2->attrregs[0x1f] & 0x08)) + if (da2->attrregs[LV_COMPATIBILITY] & 0x08) + { + //if (da2->ioctl[0] & 0x01)//256 color mode + //{ + // da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + // da2->vram_display_mask = 0x1ffff; + // da2->render = da2_render_color_8bpp; + //} + //else + if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode + da2->hdisp *= 16; + da2->char_width = 13; + da2->hdisp_old = da2->hdisp; + //if (da2->plane_mask == 0x01) {//PS/55 monochrome + // da2_log("Set videomode to PS/55 Monochrome graphics.\n"); + // //da2->render = da2_render_mono; + // da2->render = da2_render_color_4bpp; + // da2->vram_display_mask = 0x1ffff; + //} + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) {//PS/55 256 color + da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + da2->render = da2_render_color_8bpp; + da2->vram_display_mask = DA2_MASK_GRAM; + } + else {//PS/55 8-color + da2_log("Set videomode to PS/55 4 bpp graphics.\n"); + da2->vram_display_mask = DA2_MASK_GRAM; + da2->render = da2_render_color_4bpp; + } + } + else {//text mode + if (da2->attrregs[LV_ATTRIBUTE_CNTL] & 1) {//PS/55 Mode 03 + da2_log("Set videomode to PS/55 Mode 03 text.\n"); + da2->render = da2_render_textm3; + da2->vram_display_mask = DA2_MASK_CRAM; + } + else {//PS/55 text(color/mono) + da2_log("Set videomode to PS/55 Mode 8/E text.\n"); + da2->render = da2_render_text; + da2->vram_display_mask = DA2_MASK_CRAM; + } + da2->hdisp *= 13; + da2->hdisp_old = da2->hdisp; + da2->char_width = 13; + } + } + else + { + da2_log("Set videomode to blank.\n"); + } + //if (!da2->scrblank && da2->attr_palette_enable) + //{ + //da2->render = da2_draw_text; + //} + + // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + + /*da2->char_width = 13;*///PS55TEXT = 13, GFX = 16 + //if (da2->recalctimings_ex) + // da2->recalctimings_ex(da2); + + if (da2->vblankstart < da2->dispend) + da2->dispend = da2->vblankstart; + + crtcconst = da2->clock * da2->char_width; + + disptime = da2->htotal; + _dispontime = da2->hdisp_time; + + da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); + //if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + da2->dispontime = (uint64_t)_dispontime; + da2->dispofftime = (uint64_t)_dispofftime; + if (da2->dispontime < TIMER_USEC) + da2->dispontime = TIMER_USEC; + if (da2->dispofftime < TIMER_USEC) + da2->dispofftime = TIMER_USEC; + da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); + // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + + // da2_log("da2->render %08X\n", da2->render); +} + +uint8_t da2_mca_read(int port, void *p) +{ + da2_t *da2 = (da2_t *)p; + return da2->pos_regs[port & 7]; +} + +static void da2_mapping_update(da2_t *da2) +{ + if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) return; + da2->old_pos2 = da2->pos_regs[2]; + //da2_recalc_mapping(da2); + if (da2->pos_regs[2] & 0x01) + { + da2_log("DA2 enable registers\n"); + for (int i = 0; i < 8; i++) + da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); + io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + mem_mapping_enable(&da2->cmapping); + mem_mapping_enable(&da2->mmio.mapping); + timer_enable(&da2->timer); + } + else + { + da2_log("DA2 disable registers\n"); + timer_disable(&da2->timer); + mem_mapping_disable(&da2->cmapping); + mem_mapping_disable(&da2->mmio.mapping); + io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + } +} + +void da2_mca_write(int port, uint8_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + + da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); + + if (port < 0x102) + return; + da2->pos_regs[port & 7] = val; + + da2_mapping_update(da2); +} + +static uint8_t da2_mca_feedb(void* priv) +{ + const da2_t* da2 = (da2_t*)priv; + + return da2->pos_regs[2] & 0x01; +} + +static void da2_mca_reset(void *p) +{ + da2_t *da2 = (da2_t *)p; + da2_reset(da2); + da2_mca_write(0x102, 0, da2); +} +// +static void da2_gdcropB(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + } + } + } +} +static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t* da2) { + uint8_t bitmask_l = bitmask & 0xff; + uint8_t bitmask_h = bitmask >> 8; + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); + da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + } + } + } +} + +static uint8_t da2_mmio_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + if (da2->fctl[LF_MMIO_SEL] == 0x80) + //linear access + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); + else + { + //64k bank switch access + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { + case 0xb0://Gaiji RAM + addr &= DA2_MASK_GAIJIRAM;//safety access + //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); + return da2->mmio.ram[addr]; + break; + case 0x10://Font ROM + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + if (addr > DA2_FONTROM_SIZE) return 0xff; + return da2->mmio.font[addr]; + break; + default: + return 0xff;//invalid memory access + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode + { + cycles -= video_timing_read_b; + //readmode 1 + //da2_log("da2_rp: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->readplane, addr); + for (int i = 0; i < 8; i++) + da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte + //da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read in word + //da2->gdcramlatched = 1; + //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint8_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); + } + return ~ret; + } + else return da2->gdcla[da2->readplane]; + } + else //text mode 3 + { + cycles -= video_timing_read_b; + return da2->vram[addr]; + } +} +static uint16_t da2_mmio_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + if (da2->ioctl[LS_MMIO] & 0x10) { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + cycles -= video_timing_read_w; + addr &= DA2_MASK_MMIO; + for (int i = 0; i < 8; i++) + da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch + //da2->gdcramlatched = 1; + ////debug + //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) + //{ + // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 16; i++) + //{ + // int pixeldata = 0; + // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; + // fprintf(da2->mmrdbg_fp, "%X", pixeldata); + //} + //da2->mmrdbg_vidaddr = addr; + //// + + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint16_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); + } + return ~ret; + } + else + { + //da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); + return da2->gdcla[da2->readplane]; + } + } + else { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } +} + +static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("da2_mmio_write %x %x\n", addr, val); + if ((addr & ~DA2_MASK_MMIO) != 0xA0000) return; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); + //Gaiji RAM + if (da2->fctl[LF_MMIO_SEL] == 0x80) + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);//xxxy yyyy yyyy yyyy yyyy + else + { + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + switch (da2->fctl[LF_MMIO_MODE]) { + case 0xb0://Gaiji RAM 1011 0000 + addr &= DA2_MASK_GAIJIRAM;//safety access + da2->mmio.ram[addr] = val; + break; + case 0x10://Font ROM 0001 0000 + //Read-Only + break; + case 0x00: + //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx + if (addr >= DA2_BLT_MEMSIZE) + { + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + return; + } + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + break; + default: + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + uint8_t wm = da2->writemask; + //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + //{ + // fprintf(da2->mmdbg_fp, "\nB %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 8; i++) + //{ + // int pixeldata = 0; + // if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); + // fprintf(da2->mmdbg_fp, "%X", pixeldata); + //} + //da2->mmdbg_vidaddr = addr; + //} + + cycles -= video_timing_write_b; + + da2->changedvram[addr >> 12] = changeframecount; + addr <<= 3; + + //if (GCLATCHCOND) { + //if (da2->writemode == 2) { + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + //} + //else { + // for (int i = 0; i < 8; i++) + // da2->gdcsrc[i] = da2->vram[addr | i];//read in byte from vram + //} + //da2->gdcramlatched = 0; + //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); + //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropB(addr, da2); + return; + } + + switch (da2->writemode) + { + case 2: + //case 1: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else da2->gdcinput[i] = val; + + for (int i = 0; i < 8; i++) + da2->debug_vramold[i] = da2->vram[addr | i];//use latch + da2_gdcropB(addr, da2); + //for (int i = 0; i < 8; i++) + // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch + //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + //case 2: + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); + da2_gdcropB(addr, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + wm = da2->gdcreg[LG_BIT_MASK_LOW]; + da2->gdcreg[LG_BIT_MASK_LOW] &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + da2_gdcropB(addr, da2); + da2->gdcreg[LG_BIT_MASK_LOW] = wm; + break; + } + //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + } + else// mode 3h text + { + cycles -= video_timing_write_b; + da2->vram[addr] = val; + da2->fullchange = 2; + } +} +uint16_t rightRotate(uint16_t data, uint8_t count) +{ + return (data >> count) | (data << (sizeof(data) * 8 - count)); +} +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t wm = da2->writemask; + uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + bitmask <<= 8; + bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + //{ + // fprintf(da2->mmdbg_fp, "\nW %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 16; i++) + //{ + // int pixeldata = 0; + // if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); + // fprintf(da2->mmdbg_fp, "%X", pixeldata); + //} + //da2->mmdbg_vidaddr = addr; + //} + //cycles -= video_timing_write_w; + //cycles_lost += video_timing_write_w; + + //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); + //da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + + da2->changedvram[addr >> 12] = changeframecount; + da2->changedvram[(addr + 1) >> 12] = changeframecount; + addr <<= 3; + + //if (((da2->gdcreg[LG_COMMAND] & 0x03) || da2->writemode == 2) && da2->writemode != 1) { + //if (GCLATCHCOND) { + //if (da2->writemode == 2) { + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + //} + //else { + // for (int i = 0; i < 8; i++) + // da2->gdcsrc[i] = (uint16_t)(da2->vram[addr | i]) | ((uint16_t)(da2->vram[(addr + 8) | i]) << 8);//read in word + //} + //da2->gdcramlatched = 0; + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropW(addr, bitmask, da2); + return; + } + //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); + switch (da2->writemode)// writemode 0 or 2 rop(0b) 0 or 3 + { + case 2: + //case 1: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; + da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + } + break; + //case 2:win + + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work + if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = val & 0xff; + da2->vram[(addr + 8) | i] = val >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else da2->gdcinput[i] = val; + + //for (int i = 0; i < 8; i++)//draft20240722 0211 + // da2->gdcla[i] = 0;//read in word + da2_gdcropW(addr, bitmask, da2); + // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + //case 2: + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + da2->vram[addr | i] = wdata & 0xff; + da2->vram[(addr + 8) | i] = wdata >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); + da2_gdcropW(addr, bitmask, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work + wm = bitmask; + bitmask &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + da2_gdcropW(addr, bitmask, da2); + bitmask = wm; + break; + } + //da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); +} +static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0x1ffff) != 0xA0000) return; + if (da2->ioctl[LS_MMIO] & 0x10) { + //da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + addr &= DA2_MASK_MMIO; + //return; + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_gc_writeW(addr, val, da2); + } + else {//mode 3h text + //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } +} + +static void da2_code_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0xfff) != 0xE0000) return; + addr &= DA2_MASK_CRAM; + da2->cram[addr] = val; + da2->fullchange = 2; +} +static void da2_code_writeb(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + da2_code_write(addr, val, da2); +} +static void da2_code_writew(uint32_t addr, uint16_t val, void* p) +{ + //da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_write_w; + da2_code_write(addr, val & 0xff, da2); + da2_code_write(addr + 1, val >> 8, da2); +} + +static uint8_t da2_code_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return 0xff; + addr &= DA2_MASK_CRAM; + return da2->cram[addr]; +} +static uint8_t da2_code_readb(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_b; + return da2_code_read(addr, da2); +} +static uint16_t da2_code_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_w; + return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); + //return 0; +} + +void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) +{ + if (wx != xsize || wy != ysize) { + xsize = wx; + ysize = wy; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(32, 0, xsize, ysize); + frames++; + + video_res_x = wx; + video_res_y = wy; + video_bpp = 8; +} + +void da2_poll(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + int x; + + if (!da2->linepos) + { + timer_advance_u64(&da2->timer, da2->dispofftime); + // if (output) printf("Display off %f\n",vidtime); + da2->cgastat |= 1; + da2->linepos = 1; + + if (da2->dispon) + { + da2->hdisp_on = 1; + + da2->ma &= da2->vram_display_mask; + if (da2->firstline == 2000) + { + da2->firstline = da2->displine; + video_wait_for_buffer(); + } + + //RENDER + if (!da2->override) + da2->render(da2); + + if (da2->lastline < da2->displine) + da2->lastline = da2->displine; + } + + //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); + da2->displine++; + if (da2->interlace) + da2->displine++; + if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) + { + //da2_log("Vsync off at line %i\n",displine); + da2->cgastat &= ~8; + } + da2->vslines++; + if (da2->displine > 1200) + da2->displine = 0; + // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], + // displine, vc, ma); + } + else + { + // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + timer_advance_u64(&da2->timer, da2->dispontime); + + // if (output) printf("Display on %f\n",vidtime); + if (da2->dispon) + da2->cgastat &= ~1; + da2->hdisp_on = 0; + + da2->linepos = 0; + if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_END] & 31)) + da2->con = 0; + if (da2->dispon) + { + if (da2->sc == da2->rowcount) + { + da2->linecountff = 0; + da2->sc = 0; + + da2->maback += (da2->rowoffset << 1);// color = 0x50(80), mono = 0x40(64) + if (da2->interlace) + da2->maback += (da2->rowoffset << 1); + da2->maback &= da2->vram_display_mask; + da2->ma = da2->maback; + } + else + { + da2->sc++; + da2->sc &= 31; + da2->ma = da2->maback; + } + } + //da2->hsync_divisor = !da2->hsync_divisor; + + //disable for 256 color mode + //if (da2->hsync_divisor && (da2->crtc[0x17] & 4)) + // return; + + da2->vc++; + da2->vc &= 2047; + + if (da2->vc == da2->dispend) + { + //if (da2->vblank_start) + // da2->vblank_start(da2); + // da2_log("VC dispend\n"); + da2->dispon = 0; + //if (da2->crtc[10] & 0x20) da2->cursoron = 0; + //else da2->cursoron = da2->blink & 16; + if (da2->ioctl[LS_MODE] & 1) {//in text mode + if (da2->attrregs[LV_CURSOR_CONTROL] & 0x01)//cursor blinking + { + da2->cursoron = (da2->blink | 1) & da2->blinkconf; + } + else + { + da2->cursoron = 0; + } + if (!(da2->blink & (0x10 - 1)))//force redrawing for cursor and blink attribute + da2->fullchange = 2; + } + da2->blink++; + + for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) + { + if (da2->changedvram[x]) + da2->changedvram[x]--; + } + // memset(changedvram,0,2048); del + if (da2->fullchange) + { + da2->fullchange--; + //da2->fps++; + } + } + if (da2->vc == da2->vsyncstart) + { + int wx, wy; + // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); + da2->dispon = 0; + da2->cgastat |= 8; + x = da2->hdisp; + + if (da2->interlace && !da2->oddeven) da2->lastline++; + if (da2->interlace && da2->oddeven) da2->firstline--; + + wx = x; + wy = da2->lastline - da2->firstline; + + da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); + + //readflash = 0; + + da2->firstline = 2000; + da2->lastline = 0; + + da2->firstline_draw = 2000; + da2->lastline_draw = 0; + + da2->oddeven ^= 1; + + changeframecount = da2->interlace ? 3 : 2; + da2->vslines = 0; + + //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); + //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); + //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; + if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; + else da2->ma = da2->maback = da2->ma_latch; + da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; + + da2->ma <<= 1; + da2->maback <<= 1; + da2->ca <<= 1; + + //if (!da2->video_res_override) + //{ + //da2->video_res_x = wx; + //da2->video_res_y = wy + 1; + + if (da2->ioctl[LS_MODE] & 1) /*Text mode*/ + { + //da2->video_res_x /= da2->char_width; + //da2->video_res_y /= (da2->crtc[9] & 31) + 1; + //da2->video_bpp = 0; + } + else + { + //if (da2->crtc[9] & 0x80) + // da2->video_res_y /= 2; + //if (!(da2->crtc[0x17] & 2)) + // da2->video_res_y *= 4; + //else if (!(da2->crtc[0x17] & 1)) + // da2->video_res_y *= 2; + //da2->video_res_y /= (da2->crtc[9] & 31) + 1; + //if (da2->render == da2_render_8bpp_lowres || + // da2->render == da2_render_15bpp_lowres || + // da2->render == da2_render_16bpp_lowres || + // da2->render == da2_render_24bpp_lowres || + // da2->render == da2_render_32bpp_lowres) + //da2->video_res_x /= 2; + + //switch (da2->gdcreg[5] & 0x60) + //{ + //case 0x00: da2->video_bpp = 4; break; + //case 0x20: da2->video_bpp = 2; break; + //case 0x40: case 0x60: da2->video_bpp = da2->bpp; break; + //} + //da2->video_bpp = da2->bpp; + } + //} + //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma + (da2->rowoffset << 1); + + // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + + //if (da2->vsync_callback) + // da2->vsync_callback(da2); + } + if (da2->vc == da2->vtotal) + { + // da2_log("VC vtotal\n"); + + + // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); + da2->vc = 0; + da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; + da2->dispon = 1; + da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; + da2->scrollcache = da2->attrregs[LV_PANNING] & 7; + //da2->linecountff = 0; + + //da2->hwcursor_on = 0; + //da2->hwcursor_latch = da2->hwcursor; + + //da2->overlay_on = 0; + //da2->overlay_latch = da2->overlay; + // da2_log("Latch HWcursor addr %08X\n", da2_hwcursor_latch.addr); + + // da2_log("ADDR %08X\n",hwcursor_addr); + } + if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_START] & 31)) + da2->con = 1; + } + // printf("2 %i\n",da2_vsyncstart); + //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); + //da2_log("r"); +} + +static void da2_loadfont(char* fname, void* p) { + da2_t* da2 = (da2_t*)p; + uint8_t buf; + //uint32_t code = 0; + uint64_t fsize; + if (!fname) return; + if (*fname == '\0') return; + FILE* mfile = rom_fopen(fname, "rb"); + if (!mfile) { + //da2_log("MSG: Can't open binary ROM font file: %s\n", fname); + return; + } + fseek(mfile, 0, SEEK_END); + fsize = ftell(mfile);//get filesize + fseek(mfile, 0, SEEK_SET); + if (fsize > DA2_FONTROM_SIZE) { + fsize = DA2_FONTROM_SIZE;//truncate read data + //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); + //fclose(mfile); + //return 1; + } + uint32_t j = 0; + while (ftell(mfile) < fsize) { + fread(&buf, sizeof(uint8_t), 1, mfile); + da2->mmio.font[j] = buf; + j++; + } + fclose(mfile); + return; +} + +/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ +static uint8_t ps55_palette_color[64][3] = +{ +{0x00,0x00,0x00},{0x00,0x00,0x2A},{0x00,0x2A,0x00},{0x00,0x2A,0x2A},{0x2A,0x00,0x00},{0x2A,0x00,0x2A},{0x2A,0x2A,0x00},{0x2A,0x2A,0x2A}, +{0x00,0x00,0x15},{0x00,0x00,0x3F},{0x00,0x2A,0x15},{0x00,0x2A,0x3F},{0x2A,0x00,0x15},{0x2A,0x00,0x3F},{0x2A,0x2A,0x15},{0x2A,0x2A,0x3F}, +{0x00,0x15,0x00},{0x00,0x15,0x2A},{0x00,0x3F,0x00},{0x00,0x3F,0x2A},{0x2A,0x15,0x00},{0x2A,0x15,0x2A},{0x2A,0x3F,0x00},{0x2A,0x3F,0x2A}, +{0x00,0x15,0x15},{0x00,0x15,0x3F},{0x00,0x3F,0x15},{0x00,0x3F,0x3F},{0x2A,0x15,0x15},{0x2A,0x15,0x3F},{0x2A,0x3F,0x15},{0x2A,0x3F,0x3F}, +{0x15,0x00,0x00},{0x15,0x00,0x2A},{0x15,0x2A,0x00},{0x15,0x2A,0x2A},{0x3F,0x00,0x00},{0x3F,0x00,0x2A},{0x3F,0x2A,0x00},{0x3F,0x2A,0x2A}, +{0x15,0x00,0x15},{0x15,0x00,0x3F},{0x15,0x2A,0x15},{0x15,0x2A,0x3F},{0x3F,0x00,0x15},{0x3F,0x00,0x3F},{0x3F,0x2A,0x15},{0x3F,0x2A,0x3F}, +{0x15,0x15,0x00},{0x15,0x15,0x2A},{0x15,0x3F,0x00},{0x15,0x3F,0x2A},{0x3F,0x15,0x00},{0x3F,0x15,0x2A},{0x3F,0x3F,0x00},{0x3F,0x3F,0x2A}, +{0x15,0x15,0x15},{0x15,0x15,0x3F},{0x15,0x3F,0x15},{0x15,0x3F,0x3F},{0x3F,0x15,0x15},{0x3F,0x15,0x3F},{0x3F,0x3F,0x15},{0x3F,0x3F,0x3F} +}; + +void da2_reset_ioctl(da2_t* da2) +{ + da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ + da2_outw(LS_INDEX, 0x0302, da2); /* Index 02, Bit 1: VGA passthrough, Bit 0: Character Mode */ + da2_outw(LS_INDEX, 0x0008, da2); /* Index 08, Bit 0: Enable MMIO */ +} + +static void +da2_reset(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + + /* Initialize drawing */ + da2->bitblt.exec = DA2_BLT_CIDLE; + da2->render = da2_render_blank; + da2_reset_ioctl(da2); + + da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ + da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ + da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ + da2->ioctl[LS_CONFIG1] = OldLSI | Mon_ID3 | Page_Two; /* Configuration(Low) : DA - 2, Monitor ID 3, 1024 KB */ + da2->ioctl[LS_CONFIG2] = Mon_ID1; /* Configuration (High): Monitor ID 0-2 */ + da2->fctl[0] = 0x2b; /* 3E3h:0 */ + da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ + da2->attrregs[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ + da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ + da2->ma_latch = 0; + //da2->gdcramlatched = 0; + da2->interlace = 0; + da2->attrregs[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attr_palette_enable = 0; /* disable attribute generator */ + + /* Set default color palette (Display driver of Win 3.1 won't reset palette) */ + da2_out(0x3c8, 0, da2); + for (int i = 0; i < 256; i++) { + da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][1], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][2], da2); + } +} + +static void *da2_init() +{ + //Todo: init regs, gaiji memory, video memory, I/O handlers, font ROM + + if (svga_get_pri() == NULL) + return NULL; + svga_t *mb_vga = svga_get_pri(); + mb_vga->cable_connected = 0; + + da2_t* da2 = malloc(sizeof(da2_t)); + da2->mb_vga = mb_vga; + + da2->dispontime = 1000ull << 32; + da2->dispofftime = 1000ull << 32; + int memsize = 1024 * 1024; + da2->vram = malloc(memsize); + da2->vram_mask = memsize - 1; + //da2->gram_display_mask = (memsize - 1) >> 3; + da2->cram = malloc(0x1000); + //da2->cram_display_mask = 0x1000 - 1; + da2->vram_display_mask = DA2_MASK_CRAM; + da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2_loadfont(DA2_FONTROM_PATH, da2); + + mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ +#ifdef ENABLE_DA2_DEBUGBLT + da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); + da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); + da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); + da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.payload_addr = 0; + da2_reset(da2); + + mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + //da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); + + mem_mapping_disable(&da2->mmio.mapping); + + mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + + mem_mapping_disable(&da2->cmapping); + + timer_add(&da2->timer, da2_poll, da2, 0); + da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ + timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + + return da2; +} +static int da2_available() +{ + return rom_present(DA2_FONTROM_PATH); +} + +void da2_close(void *p) +{ + da2_t *da2 = (da2_t *)p; + + /* dump mem for debug */ +#ifndef RELEASE_BUILD + FILE* f; + f = fopen("da2_cram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->cram, 0x1000, 1, f); + fclose(f); + } + f = fopen("da2_vram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vram, 1024*1024, 1, f); + fclose(f); + } + f = fopen("da2_gram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->mmio.ram, 256*1024, 1, f); + fclose(f); + } + f = fopen("da2_attrpal.dmp", "wb"); + if (f != NULL) { + fwrite(da2->attrregs, 32, 1, f); + fclose(f); + } + f = fopen("da2_dacrgb.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vgapal, 3*256, 1, f); + fclose(f); + } + f = fopen("da2_daregs.txt", "w"); + if (f != NULL) { + for (int i=0;i<0x10;i++) + fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); + for (int i = 0; i < 0x40; i++) + fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrregs[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); + fclose(f); + } +#ifdef ENABLE_DA2_DEBUGBLT + f = fopen("da2_bltdump.csv", "w"); + if (f != NULL && da2->bitblt.debug_reg_ip > 0) { + /* print header */ + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) + fprintf(f, "\"%02X\"\t", y); + } + fprintf(f, "\n"); + /* print data */ + for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) + ; + else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) + fprintf(f, "\"\"\t"); + else + fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); + } + fprintf(f, "\n"); + } + fclose(f); + } + if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); + if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); + free(da2->bitblt.debug_reg); +#endif +#endif + free(da2->cram); + free(da2->vram); + free(da2->changedvram); + free(da2); +} + +void da2_speed_changed(void *p) +{ + da2_t* da2 = (da2_t*)p; + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + da2_recalctimings(da2); +} + +void da2_force_redraw(void *p) +{ + da2_t* da2 = (da2_t*)p; + + da2->fullchange = changeframecount; +} + +//void da2_add_status_info(char *s, int max_len, void *p) +//{ +// da2_t* da2 = (da2_t*)p; +// char temps[128]; +// if (!(da2->pos_regs[2] & 0x01)) strcpy(temps, "Render: DA2 disabled\n"); +// else if (da2->render == da2_render_blank) strcpy(temps, "Render: DA2 blank\n"); +// else if (da2->render == da2_render_text) strcpy(temps, "Render: DA2 text (mode 8 or E)\n"); +// else if (da2->render == da2_render_textm3) strcpy(temps, "Render: DA2 EGA compatible text (mode 3)\n"); +// else if (da2->render == da2_render_color_4bpp) strcpy(temps, "Render: DA2 4 bpp graphics (mode A or D)\n"); +// else if (da2->render == da2_render_color_8bpp) strcpy(temps, "Render: DA2 8 bpp graphics (mode F)\n"); +// else strcpy(temps, "Render: DA2 unknown render\n"); +// strncat(s, temps, max_len); +// +// sprintf(temps, "Resolution : %i x %i\n", da2->video_res_x, da2->video_res_y); +// strncat(s, temps, max_len); +// +// sprintf(temps, "Refresh rate : %i Hz\n", da2->frames); +// da2->frames = 0; +// strncat(s, temps, max_len); +// +// sprintf(temps, "Render lines : %i\n\n", da2->writelines); +// da2->writelines = 0; +// strncat(s, temps, max_len); +//} + +const device_t ps55da2_device = { + .name = "IBM Display Adapter II (MCA)", + .internal_name = "ps55da2", + .flags = DEVICE_MCA, + .local = 0, + .init = da2_init, + .close = da2_close, + .reset = da2_reset, + { .available = da2_available }, + .speed_changed = da2_speed_changed, + .force_redraw = da2_force_redraw, + .config = NULL +}; + +void +da2_device_add(void) +{ + if (!da2_standalone_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&ps55da2_device); + else + return; +} diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 93c1eb669..6d952ddb7 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -431,10 +431,24 @@ svga_in(uint16_t addr, void *priv) ret = svga->attrregs[svga->attraddr]; break; case 0x3c2: - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) - ret = 0; + if (svga->cable_connected) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + } else - ret = 0x10; + { + // The Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). + // When the monitor cable is connected to the Display Adapter, this port returns the value as no cable connection. + // The Power-on Self Test of PS/55 tries detecting the monitor on the planar VGA. + // If it fails, then the POST reads the NVRAM set by the reference diskette, and sets the BIOS Data Area (Mem 487h, 489h). + if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10) + ret = 0; + else + ret = 0x10; + } break; case 0x3c3: ret = vga_on; @@ -1359,6 +1373,8 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; + + svga->cable_connected = 1; svga->ksc5601_english_font_type = 0; vga_on = 1; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index b6e1bd2f9..cda3f95e0 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -367,6 +367,8 @@ video_post_reset(void) if (xga_standalone_enabled) xga_device_add(); + if (da2_standalone_enabled) + da2_device_add(); /* Reset the graphics card (or do nothing if it was already done by the machine's init function). */ video_reset(gfxcard[0]); diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 8b2e761a3..699cfe85e 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -103,6 +103,39 @@ vga_in(uint16_t addr, void *priv) return temp; } +void vga_disable(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + pclog("vga_disable %04X:%04X\n", cs >> 4, cpu_state.pc); + io_removehandler(0x03a0, 0x0040, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + mem_mapping_disable(&svga->mapping); + svga->vga_enabled = 0; +} + +void vga_enable(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + pclog("vga_enable %04X:%04X\n", cs >> 4, cpu_state.pc); + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + if (!(svga->miscout & 1)) + io_sethandler(0x03a0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + mem_mapping_enable(&svga->mapping); + svga->vga_enabled = 1; +} + +int vga_isenabled(void* p) +{ + vga_t* vga = (vga_t*)p; + svga_t* svga = &vga->svga; + + return svga->vga_enabled; +} + static void * vga_init(const device_t *info) { @@ -149,6 +182,7 @@ ps1vga_init(const device_t *info) vga->svga.bpp = 8; vga->svga.miscout = 1; + vga->svga.vga_enabled = 1; return vga; } From 7c5e82b2abf58ea514998113976beb8404604f53 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:44:11 +0900 Subject: [PATCH 0017/1190] Added PS/55 fdc emulation, fixed a bug in MT read --- src/floppy/fdc.c | 110 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 3fd492bd2..a878853e4 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -734,6 +734,20 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) drive = real_drive(fdc, fdc->dor & 3); fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); } + /* FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) + The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. + If it fails, then floppy drives will be treated as DD drives. */ + if (fdc->flags & FDC_FLAG_PS55) { + if (val & 0x04) + { + fdc->tfifo = 8; + fdc->fifointest = 1; + } + else { + fdc->tfifo = 1; + fdc->fifointest = 0; + } + } return; case 4: if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) { @@ -761,6 +775,14 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->dsr = val; return; case 5: /*Command register*/ + if (fdc->fifointest) + { + pclog("FIFO buffer position = %X\n", ((fifo_t *)fdc->fifo_p)->end); + fifo_write(val, fdc->fifo_p); + if (fifo_get_full(fdc->fifo_p)) + fdc->stat &= ~0x80; + break; + } if ((fdc->stat & 0xf0) == 0xb0) { if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { fdc->dat = val; @@ -1249,7 +1271,27 @@ fdc_read(uint16_t addr, void *priv) ret |= 0x40; if (fdc->fintr || fdc->reset_stat) /* INTR */ ret |= 0x80; - } else + } + else if (fdc->flags & FDC_FLAG_PS55) { + /* Status Register A (PS/2, PS/55) */ + /* | INT PEND | nDRV2 | STEP | nTRK0 | HDSEL | nIDX | nWP | DIR | */ + ret = 0x04; + if (!fdc->seek_dir) /* DIRECTION */ + ret |= 0x01; + if (!writeprot[drive]) /* nWRITEPROT */ + ret |= 0x02; + if (fdd_get_head(drive)) /* HDSEL */ + ret |= 0x08; + if (!fdd_track0(drive)) /* nTRK0 */ + ret |= 0x10; + if (fdc->step) /* STEP */ + ret |= 0x20; + if (!fdd_get_type(1)) /* -Drive 2 Installed */ + ret |= 0x40; + if (fdc->fintr || fdc->reset_stat) /* INTR */ + ret |= 0x80; + } + else ret = 0xff; break; case 1: /* STB */ @@ -1277,7 +1319,19 @@ fdc_read(uint16_t addr, void *priv) default: break; } - } else { + } + else if (fdc->flags & FDC_FLAG_PS55) { + /* Status Register B (PS/2, PS/55) */ + /* | 1 | 1 | DS0 | WD TOGGLE | RD TOGGLE | WE | MOT EN1 | MOT EN0 | */ + ret = 0xc0; + if (motoron[0]) /* Bit 0: MOT EN0 */ + ret |= 1; + if (motoron[1]) /* Bit 1: MOT EN1 */ + ret |= 2; + if(real_drive(fdc, fdc->dor & 3) == 0) /* Bit 5: Drive Select 0 */ + ret |= 0x20; + } + else { if (is486 || !fdc->enable_3f1) ret = 0xff; else { @@ -1326,7 +1380,12 @@ fdc_read(uint16_t addr, void *priv) ret = 0x10; else ret = 0x00; - } else if (!fdc->enh_mode) + } + else if (fdc->flags & FDC_FLAG_PS55) { + /* error when ret = 1, 2*/ + ret = (fdc->fifointest) ? 4 : 0; + } + else if (!fdc->enh_mode) ret = 0x20; else ret = fdc->rwc[drive] << 4; @@ -1335,6 +1394,11 @@ fdc_read(uint16_t addr, void *priv) ret = fdc->stat; break; case 5: /*Data*/ + if (fdc->fifointest) + { + ret = fifo_read(fdc->fifo_p); + break; + } if ((fdc->stat & 0xf0) == 0xf0) { fdc->stat &= ~0x80; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { @@ -1377,7 +1441,18 @@ fdc_read(uint16_t addr, void *priv) ret |= (fdc->rate & 0x03); } else ret = 0x00; - } else { + } + else if (fdc->flags & FDC_FLAG_PS55) { + /* Digital Input Register (PS/2, PS/55) */ + /* | DSKCHG | 1 | 1 | 1 | 1 | DRATE1 | DRATE0 | nHDEN | */ + ret = 0x78; + ret |= (fdc->rate & 0x03) << 1; + if (fdc->rate == 1 || fdc->rate == 2) + ret |= 0x01; + if (fdc->dor & (0x10 << drive)) + ret |= (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; + } + else { if (fdc->dor & (0x10 << drive)) { if ((drive == 1) && (fdc->flags & FDC_FLAG_TOSHIBA)) ret = 0x00; @@ -1409,7 +1484,7 @@ static void fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) { fdc_int(fdc, 1); - if (!(fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; @@ -1635,6 +1710,8 @@ fdc_callback(void *priv) return; } if (fdd_get_head(real_drive(fdc, fdc->drive)) == 0) { + fdc->sector = 1; + fdc->head |= 1; fdd_set_head(real_drive(fdc, fdc->drive), 1); if (!fdd_is_double_sided(real_drive(fdc, fdc->drive))) { fdc_noidam(fdc); @@ -1646,6 +1723,7 @@ fdc_callback(void *priv) else if (fdc->params[5] == 0) fdc->sector++; ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + //fdc_log("cb_rwsect: %d %d %d %d %d %xh\n", real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); switch (fdc->interrupt) { case 5: case 9: @@ -1708,7 +1786,7 @@ fdc_callback(void *priv) } else { fdc->interrupt = -2; fdc_int(fdc, 1); - if (!(fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; @@ -1800,7 +1878,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) timer_disable(&fdc->timer); fdc_int(fdc, 1); - if (!(fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; @@ -1964,6 +2042,7 @@ fdc_noidam(fdc_t *fdc) void fdc_nosector(fdc_t *fdc) { + pclog("nosector error\n"); fdc_error(fdc, 4, 0); } @@ -2209,7 +2288,7 @@ fdc_reset(void *priv) fdc->enable_3f1 = 1; fdc_update_enh_mode(fdc, 0); - if (fdc->flags & FDC_FLAG_PS1) + if (fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55)) fdc_update_densel_polarity(fdc, 0); else fdc_update_densel_polarity(fdc, 1); @@ -2230,6 +2309,7 @@ fdc_reset(void *priv) fdc->fifo = 0; fdc->tfifo = 1; + fdc->fifointest = 0; if (fdc->flags & FDC_FLAG_PCJR) { fdc->dma = 0; @@ -2551,6 +2631,20 @@ const device_t fdc_at_ps1_2121_device = { .config = NULL }; +const device_t fdc_at_ps55_device = { + .name = "PC/AT Floppy Drive Controller (PS/55)", + .internal_name = "fdc_at_ps55", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_PS55, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + {.available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t fdc_at_smc_device = { .name = "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", .internal_name = "fdc_at_smc", From 4b5943dd7d05cc060245af0889e7a3e8b7ffebb9 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:46:15 +0900 Subject: [PATCH 0018/1190] Added a display configuration for IBM DA2 --- src/qt/qt_settingsdisplay.cpp | 6 ++++++ src/qt/qt_settingsdisplay.ui | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index db8c30e5d..42617c4be 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -25,6 +25,7 @@ extern "C" { #include <86box/machine.h> #include <86box/video.h> #include <86box/vid_xga_device.h> +#include <86box/vid_ps55da2.h> } #include "qt_deviceconfig.hpp" @@ -56,6 +57,7 @@ SettingsDisplay::save() voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0; ibm8514_standalone_enabled = ui->checkBox8514->isChecked() ? 1 : 0; xga_standalone_enabled = ui->checkBoxXga->isChecked() ? 1 : 0; + da2_standalone_enabled = ui->checkBoxDa2->isChecked() ? 1 : 0; } void @@ -162,6 +164,7 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) bool machineSupports8514 = ((machineHasIsa16 || machineHasMca) && !videoCardHas8514); bool machineSupportsXga = (((machineHasIsa16 && device_available(&xga_isa_device)) || (machineHasMca && device_available(&xga_device))) && !videoCardHasXga); + bool machineSupportsDa2 = machineHasMca && device_available(&ps55da2_device); ui->checkBox8514->setEnabled(machineSupports8514); ui->checkBox8514->setChecked(ibm8514_standalone_enabled && machineSupports8514); @@ -169,6 +172,9 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) ui->checkBoxXga->setEnabled(machineSupportsXga); ui->checkBoxXga->setChecked(xga_standalone_enabled && machineSupportsXga); + ui->checkBoxDa2->setEnabled(machineSupportsDa2); + ui->checkBoxDa2->setChecked(da2_standalone_enabled && machineSupportsDa2); + ui->pushButtonConfigureXga->setEnabled(ui->checkBoxXga->isEnabled() && ui->checkBoxXga->isChecked()); int c = 2; diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui index a9b7e6e2c..e3e081848 100644 --- a/src/qt/qt_settingsdisplay.ui +++ b/src/qt/qt_settingsdisplay.ui @@ -113,6 +113,13 @@ + + + + IBM PS/55 Display Adapter Graphics + + + @@ -133,7 +140,7 @@ - + Qt::Vertical From 44ce0dc2827216f2f240970ed642ba09722b330c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:52:16 +0900 Subject: [PATCH 0019/1190] Added DA2 config, Changed ca keys for PS/55 --- src/86box.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/86box.c b/src/86box.c index 5e1f58413..82eedbd78 100644 --- a/src/86box.c +++ b/src/86box.c @@ -186,6 +186,7 @@ int voodoo_enabled = 0; /* (C) video o int lba_enhancer_enabled = 0; /* (C) enable Vision Systems LBA Enhancer */ int ibm8514_standalone_enabled = 0; /* (C) video option */ int xga_standalone_enabled = 0; /* (C) video option */ +int da2_standalone_enabled = 0; /* (C) video option */ uint32_t mem_size = 0; /* (C) memory size (Installed on system board)*/ uint32_t isa_mem_size = 0; /* (C) memory size (ISA Memory Cards) */ @@ -1061,12 +1062,13 @@ pc_init_modules(void) void pc_send_ca(uint16_t sc) { + /* Use R-Alt because 5576-002 keyboard assigns L-Alt as */ keyboard_input(1, 0x1D); /* Ctrl key pressed */ - keyboard_input(1, 0x38); /* Alt key pressed */ + keyboard_input(1, 0x138); /* R-Alt key pressed */ keyboard_input(1, sc); usleep(50000); keyboard_input(0, sc); - keyboard_input(0, 0x38); /* Alt key released */ + keyboard_input(0, 0x138); /* R-Alt key released */ keyboard_input(0, 0x1D); /* Ctrl key released */ } From a241a3ae8fdcbe716fd27d3a83b29fbdb8b1ee68 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 10:54:08 +0900 Subject: [PATCH 0020/1190] added/updated headers --- src/include/86box/86box.h | 1 + src/include/86box/fdc.h | 4 +++- src/include/86box/hdc.h | 1 + src/include/86box/machine.h | 1 + src/include/86box/mca.h | 1 + src/include/86box/vid_ps55da2.h | 24 ++++++++++++++++++++++++ src/include/86box/vid_svga.h | 5 +++++ src/include/86box/vid_vga.h | 4 ++++ src/include/86box/video.h | 3 +++ 9 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/include/86box/vid_ps55da2.h diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index c91b8d406..d21bba49c 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -137,6 +137,7 @@ extern int sound_is_float; /* (C) sound uses FP values */ extern int voodoo_enabled; /* (C) video option */ extern int ibm8514_standalone_enabled; /* (C) video option */ extern int xga_standalone_enabled; /* (C) video option */ +extern int da2_standalone_enabled; /* (C) video option */ extern uint32_t mem_size; /* (C) memory size (Installed on system board) */ extern uint32_t isa_mem_size; /* (C) memory size (ISA Memory Cards) */ extern int cpu; /* (C) cpu type */ diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index ef78239cd..0d71dd374 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -52,6 +52,7 @@ #define FDC_FLAG_ALI 0x800 /* ALi M512x / M1543C */ #define FDC_FLAG_NO_DSR_RESET 0x1000 /* Has no DSR reset */ #define FDC_FLAG_NEC 0x2000 /* Is NEC upd765-compatible */ +#define FDC_FLAG_PS55 0x4000 /* PS/55 */ #define FDC_FLAG_SEC 0x10000 /* Is Secondary */ #define FDC_FLAG_TER 0x20000 /* Is Tertiary */ #define FDC_FLAG_QUA 0x40000 /* Is Quaternary */ @@ -100,7 +101,6 @@ typedef struct fdc_t { uint8_t densel_force; uint8_t fifo; uint8_t tfifo; - uint8_t fifobufpos; uint8_t drv2en; uint8_t gap; @@ -145,6 +145,7 @@ typedef struct fdc_t { int drvrate[4]; void *fifo_p; + int fifointest; sector_id_t read_track_sector; sector_id_t format_sector_id; @@ -252,6 +253,7 @@ extern const device_t fdc_at_qua_device; extern const device_t fdc_at_actlow_device; extern const device_t fdc_at_ps1_device; extern const device_t fdc_at_ps1_2121_device; +extern const device_t fdc_at_ps55_device; extern const device_t fdc_at_smc_device; extern const device_t fdc_at_ali_device; extern const device_t fdc_at_winbond_device; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 48235bb1e..734cdf37a 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -53,6 +53,7 @@ extern const device_t st506_xt_toshiba_t1200_device; /* st506_xt_toshiba_t1 extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ +extern const device_t esdi_integrated_device; /* esdi_mca */ extern const device_t ide_isa_device; /* isa_ide */ extern const device_t ide_isa_2ch_device; /* isa_ide_2ch */ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 8afd5e28f..fe867a4dc 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -887,6 +887,7 @@ extern int machine_ps2_model_70_type3_init(const machine_t *); extern int machine_ps2_model_80_init(const machine_t *); extern int machine_ps2_model_80_axx_init(const machine_t *); extern int machine_ps2_model_70_type4_init(const machine_t *); +extern int machine_ps55_model_50t_init(const machine_t*); /* m_tandy.c */ extern int tandy1k_eeprom_read(void); diff --git a/src/include/86box/mca.h b/src/include/86box/mca.h index e048a6131..2d31fe33d 100644 --- a/src/include/86box/mca.h +++ b/src/include/86box/mca.h @@ -3,6 +3,7 @@ extern void mca_init(int nr_cards); extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void (*reset)(void *priv), void *priv); +extern void mca_add_to_slot(uint8_t(*read)(int addr, void* priv), void (*write)(int addr, uint8_t val, void* priv), uint8_t(*feedb)(void* priv), void (*reset)(void* priv), void* priv, int c); extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); extern uint8_t mca_read_index(uint16_t port, int index); diff --git a/src/include/86box/vid_ps55da2.h b/src/include/86box/vid_ps55da2.h new file mode 100644 index 000000000..70007be19 --- /dev/null +++ b/src/include/86box/vid_ps55da2.h @@ -0,0 +1,24 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PS/55 Display Adapter II emulation. + * + * + * + * Authors: Akamaki. + * + * Copyright 2024 Akamaki. + */ + +#ifndef VIDEO_DA2_DEVICE_H +#define VIDEO_DA2_DEVICE_H + +#ifdef EMU_DEVICE_H +extern const device_t ps55da2_device; +#endif +#endif /*VIDEO_DA2_DEVICE_H*/ diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 3d68c1a34..72b755cf1 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -216,6 +216,11 @@ typedef struct svga_t { int override; void *priv; + int vga_enabled; + /* The PS/55 POST BIOS has a special monitor detection for its internal VGA + when the monitor is connected to the Display Adapter. */ + int cable_connected; + uint8_t crtc[256]; uint8_t gdcreg[256]; uint8_t attrregs[32]; diff --git a/src/include/86box/vid_vga.h b/src/include/86box/vid_vga.h index bc552b285..62cee8e9f 100644 --- a/src/include/86box/vid_vga.h +++ b/src/include/86box/vid_vga.h @@ -33,4 +33,8 @@ static video_timings_t timing_vga = { VIDEO_ISA, 8, 16, 32, 8, 16, 32 }; void vga_out(uint16_t addr, uint8_t val, void *priv); uint8_t vga_in(uint16_t addr, void *priv); +void vga_disable(void* p); +void vga_enable(void* p); +int vga_isenabled(void* p); + #endif /*VIDEO_VGA_H*/ diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 9cbd0399f..3db41d2ab 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -313,6 +313,9 @@ extern const device_t mach32_mca_device; extern const device_t mach32_pci_device; extern const device_t mach32_onboard_pci_device; +/* IBM Display Adapter (PS/55) */ +extern void da2_device_add(void); + /* ATi Mach64 */ extern const device_t mach64gx_isa_device; extern const device_t mach64gx_vlb_device; From 84f49c355344eece68892faffe8c57e5816864a0 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 15 Aug 2024 23:30:16 +0900 Subject: [PATCH 0021/1190] Fixed text cursor size changing --- src/video/vid_ps55da2.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 13f823c83..0378cbc3c 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1568,7 +1568,6 @@ static void da2_render_text(da2_t* da2) } //Draw character for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank - //draw -= 13; // SBCS or DBCS left half if (chr_wide == 0) { if (attr & 0x01) chr_wide = 1; @@ -1742,7 +1741,7 @@ static void da2_render_textm3(da2_t* da2) // fg = 0; //} for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + p[n] = da2->pallook[da2->egapal[fg]]; } da2->ma += 2; p += 13; @@ -2684,7 +2683,7 @@ void da2_poll(void* priv) da2->hdisp_on = 0; da2->linepos = 0; - if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_END] & 31)) + if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) da2->con = 0; if (da2->dispon) { @@ -2854,7 +2853,7 @@ void da2_poll(void* priv) // da2_log("ADDR %08X\n",hwcursor_addr); } - if (da2->sc == (da2->crtc[LC_VERTICAL_SYNC_START] & 31)) + if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; } // printf("2 %i\n",da2_vsyncstart); From 935c8b6ed893e08f52a69e55a99f0fed719aede7 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:04:42 +0900 Subject: [PATCH 0022/1190] cleanup code --- src/video/vid_ps55da2.c | 192 +++------------------------------------- 1 file changed, 12 insertions(+), 180 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 0378cbc3c..c5e64694d 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -259,14 +259,12 @@ typedef struct da2_t int crtcaddr; uint8_t miscout; - //int vidclock; uint32_t decode_mask; uint32_t vram_max; uint32_t vram_mask; uint32_t gdcla[8]; - //int gdcramlatched; uint32_t gdcinput[8]; uint32_t gdcsrc[8]; uint32_t debug_vramold[8]; @@ -275,7 +273,6 @@ typedef struct da2_t int dac_read, dac_write, dac_pos; int dac_r, dac_g; - //IO 3DAh Input Status Register 2 uint8_t cgastat; uint8_t plane_mask; @@ -336,24 +333,11 @@ typedef struct da2_t int fullchange; - //int video_res_x, video_res_y, video_bpp; - //int video_res_override; /*If clear then SVGA code will set above variables, if - // set then card code will*/ - //int frames, writelines; - void (*render)(struct da2_t* da2); - //void (*recalctimings_ex)(struct da2_t* da2); - - //void (*video_out)(uint16_t addr, uint8_t val, void* p); - //uint8_t(*video_in) (uint16_t addr, void* p); /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ - int override; - //void* p; - - /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ - //int hsync_divisor; + int override; /* end VGA compatible regs*/ struct @@ -852,7 +836,6 @@ void da2_out(uint16_t addr, uint16_t val, void *p) break; case 0x3C9: /* Data */ //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); - //da2_log("DS %X\n",DS); da2->dac_status = 0; da2->fullchange = changeframecount; switch (da2->dac_pos) @@ -887,10 +870,9 @@ void da2_out(uint16_t addr, uint16_t val, void *p) //if (da2->ioctl[da2->ioctladdr & 15] != val) // da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); oldval = da2->ioctl[da2->ioctladdr]; - //if (da2->ioctladdr == 0x3) return;//monitor color da2->ioctl[da2->ioctladdr] = val; if (oldval != val) { - if (da2->ioctladdr == LS_RESET && val & 0x01) /* Mode register */ + if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset register */ da2_reset_ioctl(da2); else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ { @@ -1077,10 +1059,8 @@ void da2_out(uint16_t addr, uint16_t val, void *p) uint16_t da2_in(uint16_t addr, void *p) { da2_t * da2 = (da2_t *)p; - //svga_t *svga = &da2->svga; uint16_t temp; -// if (addr != 0x3da) da2_log("IN gd5429 %04X\n", addr); switch (addr) { case 0x3c3: @@ -1119,19 +1099,6 @@ uint16_t da2_in(uint16_t addr, void *p) if (da2->ioctladdr > 0xf) return 0xff; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ - //da2_log("Read 3E1 DAC status: %d, %d, %d\n", da2->vgapal[0].r, da2->vgapal[0].g, da2->vgapal[0].b); - //da2_log("attr palette: "); - //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->attrregs[i]); - //da2_log("\n"); - //da2_log("vram A0000h: "); - //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[i]); - //da2_log("\n"); - //da2_log("vram B8000h: "); - //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->vram[0x18000 + i]); - //da2_log("\n"); - //da2_log("vram E0000h: "); - //for (int i = 0; i < 16; i++) da2_log("%02x ", da2->cram[i]); - //da2_log("\n"); if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrregs[LV_COMPATIBILITY] & 0x08) temp &= 0x7F; /* Inactive when the RGB output voltage is high(or the cable is not connected to the color monitor). */ else @@ -1872,7 +1839,6 @@ void da2_updatevidselector(da2_t* da2) { } } - void da2_recalctimings(da2_t* da2) { double crtcconst; @@ -1921,24 +1887,11 @@ void da2_recalctimings(da2_t* da2) //if (da2->attr_palette_enable && (da2->attrregs[0x1f] & 0x08)) if (da2->attrregs[LV_COMPATIBILITY] & 0x08) { - //if (da2->ioctl[0] & 0x01)//256 color mode - //{ - // da2_log("Set videomode to PS/55 8 bpp graphics.\n"); - // da2->vram_display_mask = 0x1ffff; - // da2->render = da2_render_color_8bpp; - //} - //else if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode da2->hdisp *= 16; da2->char_width = 13; da2->hdisp_old = da2->hdisp; - //if (da2->plane_mask == 0x01) {//PS/55 monochrome - // da2_log("Set videomode to PS/55 Monochrome graphics.\n"); - // //da2->render = da2_render_mono; - // da2->render = da2_render_color_4bpp; - // da2->vram_display_mask = 0x1ffff; - //} - if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) {//PS/55 256 color + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { da2_log("Set videomode to PS/55 8 bpp graphics.\n"); da2->render = da2_render_color_8bpp; da2->vram_display_mask = DA2_MASK_GRAM; @@ -1950,7 +1903,7 @@ void da2_recalctimings(da2_t* da2) } } else {//text mode - if (da2->attrregs[LV_ATTRIBUTE_CNTL] & 1) {//PS/55 Mode 03 + if (da2->attrregs[LV_ATTRIBUTE_CNTL] & 1) { da2_log("Set videomode to PS/55 Mode 03 text.\n"); da2->render = da2_render_textm3; da2->vram_display_mask = DA2_MASK_CRAM; @@ -1976,7 +1929,6 @@ void da2_recalctimings(da2_t* da2) // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - /*da2->char_width = 13;*///PS55TEXT = 13, GFX = 16 //if (da2->recalctimings_ex) // da2->recalctimings_ex(da2); @@ -2174,12 +2126,8 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode { cycles -= video_timing_read_b; - //readmode 1 - //da2_log("da2_rp: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->readplane, addr); for (int i = 0; i < 8; i++) da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte - //da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read in word - //da2->gdcramlatched = 1; //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 uint8_t ret = 0; @@ -2212,7 +2160,7 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) addr &= DA2_MASK_MMIO; for (int i = 0; i < 8; i++) da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch - //da2->gdcramlatched = 1; + ////debug //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) //{ @@ -2320,16 +2268,9 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) da2->changedvram[addr >> 12] = changeframecount; addr <<= 3; - //if (GCLATCHCOND) { - //if (da2->writemode == 2) { - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - //} - //else { - // for (int i = 0; i < 8; i++) - // da2->gdcsrc[i] = da2->vram[addr | i];//read in byte from vram - //} - //da2->gdcramlatched = 0; + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); @@ -2346,7 +2287,6 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) switch (da2->writemode) { case 2: - //case 1: for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; break; @@ -2372,7 +2312,6 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; - //case 2: case 1: if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { @@ -2445,17 +2384,8 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) da2->changedvram[(addr + 1) >> 12] = changeframecount; addr <<= 3; - //if (((da2->gdcreg[LG_COMMAND] & 0x03) || da2->writemode == 2) && da2->writemode != 1) { - //if (GCLATCHCOND) { - //if (da2->writemode == 2) { - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - //} - //else { - // for (int i = 0; i < 8; i++) - // da2->gdcsrc[i] = (uint16_t)(da2->vram[addr | i]) | ((uint16_t)(da2->vram[(addr + 8) | i]) << 8);//read in word - //} - //da2->gdcramlatched = 0; + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch if (!(da2->gdcreg[LG_COMMAND] & 0x08)) { @@ -2468,10 +2398,9 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) } //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); - switch (da2->writemode)// writemode 0 or 2 rop(0b) 0 or 3 + switch (da2->writemode) { case 2: - //case 1: for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) { @@ -2479,8 +2408,6 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; } break; - //case 2:win - case 0: if (da2->gdcreg[LG_DATA_ROTATION] & 15) val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work @@ -2498,14 +2425,10 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) for (int i = 0; i < 8; i++) if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; else da2->gdcinput[i] = val; - - //for (int i = 0; i < 8; i++)//draft20240722 0211 - // da2->gdcla[i] = 0;//read in word da2_gdcropW(addr, bitmask, da2); // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; - //case 2: case 1: if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { @@ -2649,7 +2572,6 @@ void da2_poll(void* priv) video_wait_for_buffer(); } - //RENDER if (!da2->override) da2->render(da2); @@ -2705,20 +2627,12 @@ void da2_poll(void* priv) da2->ma = da2->maback; } } - //da2->hsync_divisor = !da2->hsync_divisor; - - //disable for 256 color mode - //if (da2->hsync_divisor && (da2->crtc[0x17] & 4)) - // return; da2->vc++; da2->vc &= 2047; if (da2->vc == da2->dispend) { - //if (da2->vblank_start) - // da2->vblank_start(da2); - // da2_log("VC dispend\n"); da2->dispon = 0; //if (da2->crtc[10] & 0x20) da2->cursoron = 0; //else da2->cursoron = da2->blink & 16; @@ -2745,7 +2659,6 @@ void da2_poll(void* priv) if (da2->fullchange) { da2->fullchange--; - //da2->fps++; } } if (da2->vc == da2->vsyncstart) @@ -2764,8 +2677,6 @@ void da2_poll(void* priv) da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); - //readflash = 0; - da2->firstline = 2000; da2->lastline = 0; @@ -2788,48 +2699,7 @@ void da2_poll(void* priv) da2->maback <<= 1; da2->ca <<= 1; - //if (!da2->video_res_override) - //{ - //da2->video_res_x = wx; - //da2->video_res_y = wy + 1; - - if (da2->ioctl[LS_MODE] & 1) /*Text mode*/ - { - //da2->video_res_x /= da2->char_width; - //da2->video_res_y /= (da2->crtc[9] & 31) + 1; - //da2->video_bpp = 0; - } - else - { - //if (da2->crtc[9] & 0x80) - // da2->video_res_y /= 2; - //if (!(da2->crtc[0x17] & 2)) - // da2->video_res_y *= 4; - //else if (!(da2->crtc[0x17] & 1)) - // da2->video_res_y *= 2; - //da2->video_res_y /= (da2->crtc[9] & 31) + 1; - //if (da2->render == da2_render_8bpp_lowres || - // da2->render == da2_render_15bpp_lowres || - // da2->render == da2_render_16bpp_lowres || - // da2->render == da2_render_24bpp_lowres || - // da2->render == da2_render_32bpp_lowres) - //da2->video_res_x /= 2; - - //switch (da2->gdcreg[5] & 0x60) - //{ - //case 0x00: da2->video_bpp = 4; break; - //case 0x20: da2->video_bpp = 2; break; - //case 0x40: case 0x60: da2->video_bpp = da2->bpp; break; - //} - //da2->video_bpp = da2->bpp; - } - //} - //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma + (da2->rowoffset << 1); - // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); - - //if (da2->vsync_callback) - // da2->vsync_callback(da2); } if (da2->vc == da2->vtotal) { @@ -2842,16 +2712,6 @@ void da2_poll(void* priv) da2->dispon = 1; da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; da2->scrollcache = da2->attrregs[LV_PANNING] & 7; - //da2->linecountff = 0; - - //da2->hwcursor_on = 0; - //da2->hwcursor_latch = da2->hwcursor; - - //da2->overlay_on = 0; - //da2->overlay_latch = da2->overlay; - // da2_log("Latch HWcursor addr %08X\n", da2_hwcursor_latch.addr); - - // da2_log("ADDR %08X\n",hwcursor_addr); } if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; @@ -2933,7 +2793,6 @@ da2_reset(void* priv) da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ da2->ma_latch = 0; - //da2->gdcramlatched = 0; da2->interlace = 0; da2->attrregs[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ da2->attr_palette_enable = 0; /* disable attribute generator */ @@ -2964,9 +2823,7 @@ static void *da2_init() int memsize = 1024 * 1024; da2->vram = malloc(memsize); da2->vram_mask = memsize - 1; - //da2->gram_display_mask = (memsize - 1) >> 3; da2->cram = malloc(0x1000); - //da2->cram_display_mask = 0x1000 - 1; da2->vram_display_mask = DA2_MASK_CRAM; da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h da2_loadfont(DA2_FONTROM_PATH, da2); @@ -3052,6 +2909,7 @@ void da2_close(void *p) fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); fclose(f); } +#endif #ifdef ENABLE_DA2_DEBUGBLT f = fopen("da2_bltdump.csv", "w"); if (f != NULL && da2->bitblt.debug_reg_ip > 0) { @@ -3078,7 +2936,6 @@ void da2_close(void *p) if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); free(da2->bitblt.debug_reg); -#endif #endif free(da2->cram); free(da2->vram); @@ -3100,31 +2957,6 @@ void da2_force_redraw(void *p) da2->fullchange = changeframecount; } -//void da2_add_status_info(char *s, int max_len, void *p) -//{ -// da2_t* da2 = (da2_t*)p; -// char temps[128]; -// if (!(da2->pos_regs[2] & 0x01)) strcpy(temps, "Render: DA2 disabled\n"); -// else if (da2->render == da2_render_blank) strcpy(temps, "Render: DA2 blank\n"); -// else if (da2->render == da2_render_text) strcpy(temps, "Render: DA2 text (mode 8 or E)\n"); -// else if (da2->render == da2_render_textm3) strcpy(temps, "Render: DA2 EGA compatible text (mode 3)\n"); -// else if (da2->render == da2_render_color_4bpp) strcpy(temps, "Render: DA2 4 bpp graphics (mode A or D)\n"); -// else if (da2->render == da2_render_color_8bpp) strcpy(temps, "Render: DA2 8 bpp graphics (mode F)\n"); -// else strcpy(temps, "Render: DA2 unknown render\n"); -// strncat(s, temps, max_len); -// -// sprintf(temps, "Resolution : %i x %i\n", da2->video_res_x, da2->video_res_y); -// strncat(s, temps, max_len); -// -// sprintf(temps, "Refresh rate : %i Hz\n", da2->frames); -// da2->frames = 0; -// strncat(s, temps, max_len); -// -// sprintf(temps, "Render lines : %i\n\n", da2->writelines); -// da2->writelines = 0; -// strncat(s, temps, max_len); -//} - const device_t ps55da2_device = { .name = "IBM Display Adapter II (MCA)", .internal_name = "ps55da2", From 6aec2f04dd548e97a55a71968cca8f912744295c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:07:24 +0900 Subject: [PATCH 0023/1190] Fixed ESDI hung-up issue when ctrl+alt+del reset --- src/disk/hdc_esdi_mca.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 047089a1e..bdb037fee 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1259,9 +1259,12 @@ esdi_mca_feedb(void *priv) static void esdi_reset(void* priv) { esdi_t* dev = (esdi_t*)priv; - dev->in_reset = 1; - esdi_mca_set_callback(dev, ESDI_TIME * 50); - dev->status = STATUS_BUSY; + pclog("esdi reset %d %x\n", dev->in_reset, dev->status); + if (!dev->in_reset) { + dev->in_reset = 1; + esdi_mca_set_callback(dev, ESDI_TIME * 50); + dev->status = STATUS_BUSY; + } } static void * @@ -1272,6 +1275,7 @@ esdi_init(UNUSED(const device_t *info)) uint8_t c; uint8_t i; + pclog("esdi init\n"); dev = malloc(sizeof(esdi_t)); if (dev == NULL) return (NULL); @@ -1334,9 +1338,9 @@ esdi_init(UNUSED(const device_t *info)) /* The slot number of this controller is fixed by the planar. IBM PS/55 5551-T assigns it #5. */ int slotno = device_get_config_int("in_esdi_slot"); if (slotno) - mca_add_to_slot(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, NULL, dev, slotno - 1); + mca_add_to_slot(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev, slotno - 1); else - mca_add(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, NULL, dev); + mca_add(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev); } else mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev); @@ -1348,6 +1352,7 @@ esdi_init(UNUSED(const device_t *info)) /* Set the reply timer. */ timer_add(&dev->timer, esdi_callback, dev, 0); + pclog("esdi init finish\n"); return dev; } From 3c6695cdeafb5b6fbf5a1e98c2747f4e9054d861 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:08:51 +0900 Subject: [PATCH 0024/1190] Removed debug logging --- src/disk/hdc_esdi_mca.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index bdb037fee..adc5cd6a0 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1259,7 +1259,6 @@ esdi_mca_feedb(void *priv) static void esdi_reset(void* priv) { esdi_t* dev = (esdi_t*)priv; - pclog("esdi reset %d %x\n", dev->in_reset, dev->status); if (!dev->in_reset) { dev->in_reset = 1; esdi_mca_set_callback(dev, ESDI_TIME * 50); @@ -1275,7 +1274,6 @@ esdi_init(UNUSED(const device_t *info)) uint8_t c; uint8_t i; - pclog("esdi init\n"); dev = malloc(sizeof(esdi_t)); if (dev == NULL) return (NULL); @@ -1352,7 +1350,6 @@ esdi_init(UNUSED(const device_t *info)) /* Set the reply timer. */ timer_add(&dev->timer, esdi_callback, dev, 0); - pclog("esdi init finish\n"); return dev; } From c3b2ddfcb18d0414b06b03ee161e3ec6a1eee4b7 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:56:25 +0900 Subject: [PATCH 0025/1190] added comment for 5576 keyb --- src/device/keyboard_at.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 2900ec17a..161a13e0c 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1631,21 +1631,23 @@ static const scancode scancode_set3[512] = { }; /* IBM Japan 5576-001, 002 and 003 keyboards have three extra scancode sets; 81h, 82h, 8ah. - Scancode set 81h and 82h are not implemented yet. To implement them, we need take the following into consideration. * Add a UI to switch the type of keyboards and keyboard IDs. * Add modified scancode set 1 and 2 (in these modes, language input keys are used as an alternative key). - * Japanese keyboards traditionally use a typewriter layout. Its key mapping doesn't match with foreign keyboards. + * Japanese keyboards traditionally use a bit-paired layout. Its key mapping doesn't match with foreign keyboards. 5576 keyboards kept 101-key compatible scancode sets because PS/55 had to support western (PS/2) versions of operating systems. The default scancode set is 2. In Japanese DOS, the keyboard driver confirms its keyboard ID, and sends a command to switch the scancode set to 8Ah. + Japanese OS/2 and Windows use the scancode set 82h. - The OADG standard and modern Japanese keyboards use the same keyboard ID and scancode set number as PS/2 keyboards use. + The OADG standard (1991-) and modern Japanese keyboards use the same keyboard ID and scancode set number as PS/2 keyboards use. Three extra scancode sets are no longer available. Instead, language input keys are available in scancode set 1 and 2. - However, it has a different key mapping. + However, their physical key layout is a bit-paired layout. Users have to choose the correct keyboard layout on setup, and the driver needs to remap keys. + Currently, scancode set 81h and 82h are not implemented yet. Also, the key layout is designed to match with the Japanese keyboard. + [Japanese DOS and keyboard scancode set] | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | PC DOS 5 | |---------------------------|:----:|:----:|:----:|:------:|:------:|:---------:|:--------:| From 351d8c8441b5d32a88b601a2fd306595933dcbe4 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:37:19 +0900 Subject: [PATCH 0026/1190] added i/o port 3e9 write --- src/video/vid_ps55da2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index c5e64694d..143c478dc 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1022,6 +1022,10 @@ void da2_out(uint16_t addr, uint16_t val, void *p) } da2->attrff ^= 1; break; + case 0x3E9: + /* VZ Editor's CURSOR.COM writes via this port */ + da2->attrregs[da2->attraddr & 0x3f] = val; + break; case LG_INDEX: da2->gdcaddr = val; break; From 2c8c519b82135c7e3332a4621b9718c06cbe8f83 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:38:32 +0900 Subject: [PATCH 0027/1190] Removed debug logging --- src/video/vid_vga.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 699cfe85e..8d4439f95 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -108,7 +108,6 @@ void vga_disable(void* p) vga_t* vga = (vga_t*)p; svga_t* svga = &vga->svga; - pclog("vga_disable %04X:%04X\n", cs >> 4, cpu_state.pc); io_removehandler(0x03a0, 0x0040, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); mem_mapping_disable(&svga->mapping); svga->vga_enabled = 0; @@ -119,7 +118,6 @@ void vga_enable(void* p) vga_t* vga = (vga_t*)p; svga_t* svga = &vga->svga; - pclog("vga_enable %04X:%04X\n", cs >> 4, cpu_state.pc); io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); if (!(svga->miscout & 1)) io_sethandler(0x03a0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); From ee280e10f1da6bfb5798593c1c8f90d00e23c154 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:39:40 +0900 Subject: [PATCH 0028/1190] removed debug logging --- src/floppy/fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index a878853e4..af1aa37c6 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -777,7 +777,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 5: /*Command register*/ if (fdc->fifointest) { - pclog("FIFO buffer position = %X\n", ((fifo_t *)fdc->fifo_p)->end); + fdc_log("FIFO buffer position = %X\n", ((fifo_t *)fdc->fifo_p)->end); fifo_write(val, fdc->fifo_p); if (fifo_get_full(fdc->fifo_p)) fdc->stat &= ~0x80; From 05e663a5c30c715bb47d733c1e06bb57c031a016 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 23 Aug 2024 09:34:26 +0900 Subject: [PATCH 0029/1190] merged ps55 fdc with ps2 fdc --- src/floppy/fdc.c | 27 +++++++++++++-------------- src/machine/m_ps2_mca.c | 20 ++------------------ 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index af1aa37c6..f317fd948 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -734,10 +734,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) drive = real_drive(fdc, fdc->dor & 3); fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); } - /* FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) + /* Bit 2: FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. If it fails, then floppy drives will be treated as DD drives. */ - if (fdc->flags & FDC_FLAG_PS55) { + if (fdc->flags & FDC_FLAG_PS2) { if (val & 0x04) { fdc->tfifo = 8; @@ -1272,7 +1272,7 @@ fdc_read(uint16_t addr, void *priv) if (fdc->fintr || fdc->reset_stat) /* INTR */ ret |= 0x80; } - else if (fdc->flags & FDC_FLAG_PS55) { + else if (fdc->flags & FDC_FLAG_PS2) { /* Status Register A (PS/2, PS/55) */ /* | INT PEND | nDRV2 | STEP | nTRK0 | HDSEL | nIDX | nWP | DIR | */ ret = 0x04; @@ -1320,7 +1320,7 @@ fdc_read(uint16_t addr, void *priv) break; } } - else if (fdc->flags & FDC_FLAG_PS55) { + else if (fdc->flags & FDC_FLAG_PS2) { /* Status Register B (PS/2, PS/55) */ /* | 1 | 1 | DS0 | WD TOGGLE | RD TOGGLE | WE | MOT EN1 | MOT EN0 | */ ret = 0xc0; @@ -1381,7 +1381,7 @@ fdc_read(uint16_t addr, void *priv) else ret = 0x00; } - else if (fdc->flags & FDC_FLAG_PS55) { + else if (fdc->flags & FDC_FLAG_PS2) { /* error when ret = 1, 2*/ ret = (fdc->fifointest) ? 4 : 0; } @@ -1442,7 +1442,7 @@ fdc_read(uint16_t addr, void *priv) } else ret = 0x00; } - else if (fdc->flags & FDC_FLAG_PS55) { + else if (fdc->flags & FDC_FLAG_PS2) { /* Digital Input Register (PS/2, PS/55) */ /* | DSKCHG | 1 | 1 | 1 | 1 | DRATE1 | DRATE0 | nHDEN | */ ret = 0x78; @@ -1484,7 +1484,7 @@ static void fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) { fdc_int(fdc, 1); - if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS2))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; @@ -1786,7 +1786,7 @@ fdc_callback(void *priv) } else { fdc->interrupt = -2; fdc_int(fdc, 1); - if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS2))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; @@ -1878,7 +1878,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) timer_disable(&fdc->timer); fdc_int(fdc, 1); - if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55))) + if (!(fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS2))) fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; @@ -2042,7 +2042,6 @@ fdc_noidam(fdc_t *fdc) void fdc_nosector(fdc_t *fdc) { - pclog("nosector error\n"); fdc_error(fdc, 4, 0); } @@ -2288,7 +2287,7 @@ fdc_reset(void *priv) fdc->enable_3f1 = 1; fdc_update_enh_mode(fdc, 0); - if (fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS55)) + if (fdc->flags & (FDC_FLAG_PS1 | FDC_FLAG_PS2)) fdc_update_densel_polarity(fdc, 0); else fdc_update_densel_polarity(fdc, 1); @@ -2631,11 +2630,11 @@ const device_t fdc_at_ps1_2121_device = { .config = NULL }; -const device_t fdc_at_ps55_device = { - .name = "PC/AT Floppy Drive Controller (PS/55)", +const device_t fdc_at_ps2_device = { + .name = "PC/AT Floppy Drive Controller (PS/2 internal)", .internal_name = "fdc_at_ps55", .flags = 0, - .local = FDC_FLAG_AT | FDC_FLAG_PS55, + .local = FDC_FLAG_AT | FDC_FLAG_PS2, .init = fdc_init, .close = fdc_close, .reset = fdc_reset, diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index fc2e3313b..72776b22d 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1557,7 +1557,7 @@ machine_ps2_common_init(const machine_t *model) machine_common_init(model); if (fdc_current[0] == FDC_INTERNAL) - device_add(&fdc_at_device); + device_add(&fdc_at_ps2_device); dma16_init(); ps2_dma_init(); @@ -1801,23 +1801,7 @@ machine_ps55_model_50t_init(const machine_t* model) if (bios_only || !ret) return ret; - /* begin ps2 common init */ - machine_common_init(model); - - device_add(&fdc_at_ps55_device); - - dma16_init(); - ps2_dma_init(); - device_add(&ps_no_nmi_nvr_device); - pic2_init(); - - int pit_type = ((pit_mode == -1 && is486) || pit_mode == 1) ? PIT_8254_FAST : PIT_8254; - pit_ps2_init(pit_type); - - nmi_mask = 0x80; - - ps2.uart = device_add_inst(&ns16550_device, 1); - /* end ps2 common init */ + machine_ps2_common_init(model); /* * Planar ID From dd1d835e152fd90dcb0b4154eda1e6678c483952 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 2 Sep 2024 13:23:00 -0700 Subject: [PATCH 0030/1190] Use F8+F12 to release mouse on all platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that Ctrl+End was used on non-Win32 platforms because WxWidgets couldn’t use non-modifier keys as a keyboard sequence. Qt can, and F8+F12 interferes with the operation of software a lot less than Ctrl+End does (try doing some text editing!). 86Box hasn’t used WxWidgets for quite some time and this platform limitation hack has long outlived its necessity. --- src/device/keyboard.c | 12 +----------- src/include/86box/plat.h | 4 ++-- src/qt/qt_platform.cpp | 4 ++-- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index ea81e7525..de384c81e 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -31,23 +31,13 @@ int keyboard_scan; -#ifdef _WIN32 -/* Windows: F8+F12 */ +/* F8+F12 */ uint16_t key_prefix_1_1 = 0x042; /* F8 */ uint16_t key_prefix_1_2 = 0x000; /* Invalid */ uint16_t key_prefix_2_1 = 0x000; /* Invalid */ uint16_t key_prefix_2_2 = 0x000; /* Invalid */ uint16_t key_uncapture_1 = 0x058; /* F12 */ uint16_t key_uncapture_2 = 0x000; /* Invalid */ -#else -/* WxWidgets cannot do two regular keys.. CTRL+END */ -uint16_t key_prefix_1_1 = 0x01d; /* Left Ctrl */ -uint16_t key_prefix_1_2 = 0x11d; /* Right Ctrl */ -uint16_t key_prefix_2_1 = 0x000; /* Invalid */ -uint16_t key_prefix_2_2 = 0x000; /* Invalid */ -uint16_t key_uncapture_1 = 0x04f; /* Numpad End */ -uint16_t key_uncapture_2 = 0x14f; /* End */ -#endif void (*keyboard_send)(uint16_t val); diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 4a310ab44..225c45ae1 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -32,8 +32,8 @@ /* String ID numbers. */ enum { STRING_MOUSE_CAPTURE, /* "Click to capture mouse" */ - STRING_MOUSE_RELEASE, /* "Press F8+F12/Ctrl+End to release mouse" */ - STRING_MOUSE_RELEASE_MMB, /* "Press F8+F12/Ctrl+End or middle button to release mouse" */ + STRING_MOUSE_RELEASE, /* "Press F8+F12 to release mouse" */ + STRING_MOUSE_RELEASE_MMB, /* "Press F8+F12 or middle button to release mouse" */ STRING_INVALID_CONFIG, /* "Invalid configuration" */ STRING_NO_ST506_ESDI_CDROM, /* "MFM/RLL or ESDI CD-ROM drives never existed" */ STRING_NET_ERROR, /* "Failed to initialize network driver" */ diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a200e38ec..f22b0f388 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -583,6 +583,8 @@ c16stombs(char dst[], const uint16_t src[], int len) } #endif +# define MOUSE_CAPTURE_KEYSEQ "F8+F12" + #ifdef _WIN32 # if defined(__amd64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) # define LIB_NAME_GS "gsdll64.dll" @@ -592,12 +594,10 @@ c16stombs(char dst[], const uint16_t src[], int len) # define LIB_NAME_GPCL "gpcl6dll32.dll" # endif # define LIB_NAME_PCAP "Npcap" -# define MOUSE_CAPTURE_KEYSEQ "F8+F12" #else # define LIB_NAME_GS "libgs" # define LIB_NAME_GPCL "libgpcl6" # define LIB_NAME_PCAP "libpcap" -# define MOUSE_CAPTURE_KEYSEQ "Ctrl+End" #endif QMap ProgSettings::translatedstrings; From 60a84cfb5bc948dbfa71a7f62354ea21b885ffb0 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 15 Nov 2024 21:53:20 +0900 Subject: [PATCH 0031/1190] +character drawing in bitblt (experimental) * Changed comment format. * Updated Font ROM map written in comment --- src/video/vid_ps55da2.c | 514 ++++++++++++++++++++++++++-------------- 1 file changed, 337 insertions(+), 177 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 143c478dc..6a90a3dc3 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -39,16 +39,19 @@ #define DA2_FONTROM_PATH "roms/video/da2/PS55FNTJ.BIN" #define DA2_FONTROM_SIZE 1024*1024 +#define DA2_FONTROM_BASESBCS 0x98000 +#define DA2_GAIJIRAM_SBCS 0x34000 +#define DA2_GAIJIRAM_SBEX 0x3c000 #define DA2_MASK_MMIO 0x1ffff #define DA2_MASK_GRAM 0x1ffff #define DA2_MASK_CRAM 0xfff #define DA2_MASK_GAIJIRAM 0x3ffff #define DA2_PIXELCLOCK 58000000.0 -#define DA2_BLT_MEMSIZE 0x80 +#define DA2_BLT_MEMSIZE 0x100 #define DA2_BLT_REGSIZE 0x40 #define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) -#define DA2_DEBUG_BLTLOG_MAX 256*1024 -#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe +#define DA2_DEBUG_BLTLOG_MAX 256*1024 +#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe #define DA2_DEBUG_BLT_USEDRESET 0xfefefe #define DA2_BLT_CIDLE 0 @@ -56,8 +59,9 @@ #define DA2_BLT_CFILLTILE 2 #define DA2_BLT_CCOPYF 3 #define DA2_BLT_CCOPYR 4 -#define DA2_BLT_CDONE 5 -#define DA2_BLT_CLOAD 6 +#define DA2_BLT_CPUTCHAR 5 +#define DA2_BLT_CDONE 6 +#define DA2_BLT_CLOAD 7 /* POS ID = 0xeffe : Display Adapter II, III, V */ #define DA2_POSID_H 0xef #define DA2_POSID_L 0xfe @@ -124,9 +128,9 @@ #define LS_CONFIG1 0x0a #define LS_CONFIG2 0x0b /* added */ #define LF_INDEX 0x3e2 -#define LF_DATA 0x3e3 -#define LF_MMIO_SEL 0x08 /* added */ -#define LF_MMIO_ADDR 0x0A /* added */ +#define LF_DATA 0x3e3 +#define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_ADDR 0x0A /* added */ #define LF_MMIO_MODE 0x0B /* added */ #define LC_INDEX 0x3E4 #define LC_DATA 0x3E5 @@ -212,27 +216,31 @@ #define LG_MAP_MASKJ 0x0A #define LG_COMMAND 0x0B #define LG_SET_RESET_2 0x10 - -#ifdef ENABLE_DA2_LOG -int da2_do_log = ENABLE_DA2_LOG; - -static void -da2_log(const char* fmt, ...) -{ - va_list ap; - - if (da2_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -# define da2_log(fmt, ...) + +#ifndef RELEASE_BUILD +#define ENABLE_DA2_LOG 1 +#endif + +#ifdef ENABLE_DA2_LOG +int da2_do_log = ENABLE_DA2_LOG; + +static void +da2_log(const char* fmt, ...) +{ + va_list ap; + + if (da2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define da2_log(fmt, ...) +#endif +#ifndef RELEASE_BUILD +# define ENABLE_DA2_DEBUGBLT 1 #endif -#ifndef RELEASE_BUILD -# define ENABLE_DA2_DEBUGBLT 1 -#endif typedef struct da2_t { @@ -246,7 +254,7 @@ typedef struct da2_t uint8_t gdcreg[64]; uint8_t reg3ee[16]; int gdcaddr; - uint8_t attrregs[0x40]; + uint8_t attrc[0x40]; int attraddr, attrff; int attr_palette_enable; //uint8_t seqregs[64]; @@ -300,7 +308,7 @@ typedef struct da2_t pc_timer_t timer; uint64_t da2const; - uint8_t scrblank; + //uint8_t scrblank; int dispon; int hdisp_on; @@ -329,7 +337,7 @@ typedef struct da2_t uint32_t vram_display_mask; uint32_t banked_mask; - uint32_t write_bank, read_bank; + //uint32_t write_bank, read_bank; int fullchange; @@ -337,7 +345,7 @@ typedef struct da2_t /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ - int override; + int override; /* end VGA compatible regs*/ struct @@ -348,12 +356,12 @@ typedef struct da2_t uint8_t font[DA2_FONTROM_SIZE]; } mmio; - mem_mapping_t linear_mapping; + //mem_mapping_t linear_mapping; - uint32_t bank[2]; - uint32_t mask; + //uint32_t bank[2]; + //uint32_t mask; - int type; + //int type; struct { int bitshift_destr; @@ -386,7 +394,7 @@ typedef struct da2_t uint8_t pos_regs[8]; svga_t *mb_vga; - int vidsys_ena; + //int vidsys_ena; int old_pos2; } da2_t; @@ -406,7 +414,7 @@ typedef union { typedef struct { uint32_t p8[8]; } pixel32; - + /* safety read for internal functions */ uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) { @@ -505,6 +513,22 @@ void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } +void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + if (srcaddr >= DA2_FONTROM_SIZE) { + da2_log("DA2 Putchar Addr Error %x\n", srcaddr); + return; + } + for (int i = 0; i < 8; i++) + srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) + | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) + | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) + | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +#ifdef ENABLE_DA2_DEBUGBLT uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { uint8_t pixeldata = 0; for (int j = 0; j < 8; j++) { @@ -515,15 +539,58 @@ uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { void print_pixelbyte(uint32_t addr, da2_t* da2) { for (int i = 0; i < 8; i++) { - da2_log("%X", pixel1tohex(addr, i, da2)); + pclog("%X", pixel1tohex(addr, i, da2)); } } - +void print_bytetobin(uint8_t b) { + for (int i = 0; i < 8; i++) + { + if(b & 0x80) + pclog("1"); + else + pclog("0"); + b <<= 1; + } +} +//Convert internal char code to Shift JIS code +inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } +inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } +uint16_t IBMJtoSJIS(uint16_t knj) +{ + if (knj < 0x100) return 0xffff; + knj -= 0x100; + if (knj <= 0x1f7d) + ;/* do nothing */ + else if (knj >= 0xb700 && knj <= 0xb75f) { + knj -= 0x90ec; + } + else if (knj >= 0xb3f0 && knj <= 0xb67f) { + knj -= 0x906c; + } + else if (knj >= 0x8000 && knj <= 0x8183) + { + knj -= 0x5524; + } + else + return 0xffff; + uint32_t knj1 = knj / 0xBC; + uint32_t knj2 = knj - (knj1 * 0xBC); + knj1 += 0x81; + if (knj1 > 0x9F) knj1 += 0x40; + knj2 += 0x40; + if (knj2 > 0x7E) knj2++; + //if (!isKanji1(knj1)) return 0xffff; + //if (!isKanji2(knj2)) return 0xffff; + knj = knj1 << 8; + knj |= knj2; + return knj; +} +#endif void da2_bitblt_load(da2_t* da2) { uint32_t value32; uint64_t value64; - //da2_log("BITBLT loading params\n"); + da2_log("BITBLT loading params\n"); //da2_log("BitBlt memory:\n"); //if (da2->bitblt.payload[0] != 0) // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) @@ -544,7 +611,7 @@ void da2_bitblt_load(da2_t* da2) value32 = da2->bitblt.payload[i + 3]; value32 <<= 8; value32 |= da2->bitblt.payload[i + 2]; - //da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; i += 3; break; @@ -556,7 +623,7 @@ void da2_bitblt_load(da2_t* da2) value32 |= da2->bitblt.payload[i + 3]; value32 <<= 8; value32 |= da2->bitblt.payload[i + 2]; - //da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; i += 5; break; @@ -573,8 +640,8 @@ void da2_bitblt_load(da2_t* da2) value64 <<= 8; value64 |= da2->bitblt.payload[i + 2]; da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; - //da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - //da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); i += 7; break; case 0x00: @@ -635,14 +702,50 @@ void da2_bitblt_load(da2_t* da2) da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); da2->bitblt.exec = DA2_BLT_CDONE; } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {//Fill a rectangle (or draw a line) + else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + /* Todo: addressing */ + //if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + //{ + // da2->bitblt.destaddr += 2; + // da2->bitblt.size_x -= 1; + // da2->bitblt.destpitch += 2; + // da2->bitblt.srcpitch += 2; + //} + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {/* Fill a rectangle(or draw a line) */ da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); da2->bitblt.exec = DA2_BLT_CFILLRECT; da2->bitblt.destaddr += 2; } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle ??(transfer tile data multiple times) os/2 only + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; @@ -653,7 +756,7 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {//Tiling a rectangle (transfer tile data multiple times) + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle (transfer tile data multiple times) */ da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; @@ -664,7 +767,7 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {//Block transfer (range copy) + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {/* Block transfer (range copy) */ da2->bitblt.exec = DA2_BLT_CCOPYF; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr += 2; @@ -674,7 +777,7 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {//Block copy but reversed direction + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {/* Block copy but reversed direction */ da2->bitblt.exec = DA2_BLT_CCOPYR; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr -= 2; @@ -686,11 +789,6 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.size_x, da2->bitblt.size_y); //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); } - //do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle - while (timer_is_enabled(&da2->bitblt.timer) && da2->bitblt.exec != DA2_BLT_CDONE) - { - da2_bitblt_exec(da2); - } } } void da2_bitblt_exec(void* p) @@ -704,8 +802,8 @@ void da2_bitblt_exec(void* p) timer_disable(&da2->bitblt.timer); break; case DA2_BLT_CLOAD: - da2_bitblt_load(da2); da2->bitblt.indata = 0; + da2_bitblt_load(da2); break; case DA2_BLT_CFILLRECT: //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); @@ -799,8 +897,47 @@ void da2_bitblt_exec(void* p) da2->bitblt.destaddr -= 2; da2->bitblt.srcaddr -= 2; break; + case DA2_BLT_CPUTCHAR: + //da2->bitblt.y += 2; + da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; + pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + //da2->bitblt.srcaddr += 2; + if(da2->bitblt.reg[0x12] < 0x100) + da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; + else + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); + pclog("\n"); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + //if (1) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 3) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += 130; + //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + //da2->bitblt.srcaddr += -1; + } + else if (da2->bitblt.x == 0) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + else { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; + ////da2->bitblt.srcaddr += 2; + //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; + break; case DA2_BLT_CDONE: - //initialize regs with fefefefeh, clear regs with fefeh for debug dump + /* initialize regs for debug dump */ for (int i = 0; i < DA2_BLT_REGSIZE; i++) { if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; } @@ -809,6 +946,21 @@ void da2_bitblt_exec(void* p) break; } } +void da2_bitblt_dopayload(da2_t* da2) { + if (da2->bitblt.exec == DA2_BLT_CIDLE) + { + da2->bitblt.exec = DA2_BLT_CLOAD; + //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ + da2_log("da2 Do bitblt\n"); + while (da2->bitblt.exec != DA2_BLT_CIDLE) + { + da2_bitblt_exec(da2); + } + da2_log("da2 End bitblt %x\n", da2->bitblt.exec); + } +} + void da2_out(uint16_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *)p; @@ -867,8 +1019,8 @@ void da2_out(uint16_t addr, uint16_t val, void *p) case LS_DATA: //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); if (da2->ioctladdr > 0xf) return; - //if (da2->ioctl[da2->ioctladdr & 15] != val) - // da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); + if (da2->ioctl[da2->ioctladdr & 15] != val) + da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); oldval = da2->ioctl[da2->ioctladdr]; da2->ioctl[da2->ioctladdr] = val; if (oldval != val) { @@ -882,12 +1034,7 @@ void da2_out(uint16_t addr, uint16_t val, void *p) } else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ { - da2->bitblt.indata = 1; - if (da2->bitblt.exec == DA2_BLT_CIDLE) - { - da2->bitblt.exec = DA2_BLT_CLOAD; - timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - } + //da2->bitblt.indata = 1; } } break; @@ -910,8 +1057,8 @@ void da2_out(uint16_t addr, uint16_t val, void *p) break; case LC_DATA: if (da2->crtcaddr > 0x1f) return; - if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) - da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + //if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); if (!(da2->crtc[da2->crtcaddr] ^ val)) return; switch (da2->crtcaddr) { case LC_CRTC_OVERFLOW: @@ -955,10 +1102,10 @@ void da2_out(uint16_t addr, uint16_t val, void *p) } break; case LV_PORT: - da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + //da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); if (!da2->attrff) { - // da2->attraddr = val & 31; + // da2->attraddr = val & 31; da2->attraddr = val & 0x3f; if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) { @@ -970,47 +1117,44 @@ void da2_out(uint16_t addr, uint16_t val, void *p) } else { - if ((da2->attraddr == LV_PANNING) && (da2->attrregs[LV_PANNING] != val)) + if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val)) da2->fullchange = changeframecount; - if (da2->attrregs[da2->attraddr & 0x3f] != val) - da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrregs[da2->attraddr & 0x3f], val); - da2->attrregs[da2->attraddr & 0x3f] = val; - //da2_log("set attrreg %x: %x\n", da2->attraddr & 31, val); + if (da2->attrc[da2->attraddr & 0x3f] != val) + da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); + da2->attrc[da2->attraddr & 0x3f] = val; + //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); if (da2->attraddr < 16) da2->fullchange = changeframecount; - //if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr == 0x14 || da2->attraddr < 0x10) if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) { for (int c = 0; c < 16; c++) { - //if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrregs[c] & 0xf) | ((da2->attrregs[0x14] & 0xf) << 4); - //else da2->egapal[c] = (da2->attrregs[c] & 0x3f) | ((da2->attrregs[0x14] & 0xc) << 4); - if (da2->attrregs[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrregs[c] & 0xf; - else da2->egapal[c] = da2->attrregs[c] & 0x3f; - } - } - if (da2->attraddr == LV_COLOR_PLANE_ENAB) - { - if ((val & 0xff) != da2->plane_mask) - da2->fullchange = changeframecount; - da2->plane_mask = val & 0xff; - } - if (da2->attraddr == LV_CURSOR_CONTROL) - { - switch (val & 0x18) { - case 0x08://fast blink - da2->blinkconf = 0x10; - break; - case 0x18://slow blink - da2->blinkconf = 0x20; - break; - default://no blink - da2->blinkconf = 0xff; - break; + //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); + //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); + if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; + else da2->egapal[c] = da2->attrc[c] & 0x3f; } } switch (da2->attraddr) { + case LV_COLOR_PLANE_ENAB: + if ((val & 0xff) != da2->plane_mask) + da2->fullchange = changeframecount; + da2->plane_mask = val & 0xff; + break; + case LV_CURSOR_CONTROL: + switch (val & 0x18) { + case 0x08://fast blink + da2->blinkconf = 0x10; + break; + case 0x18://slow blink + da2->blinkconf = 0x20; + break; + default://no blink + da2->blinkconf = 0xff; + break; + } + break; case LV_MODE_CONTROL: case LV_ATTRIBUTE_CNTL: case LV_COMPATIBILITY: @@ -1022,9 +1166,9 @@ void da2_out(uint16_t addr, uint16_t val, void *p) } da2->attrff ^= 1; break; - case 0x3E9: - /* VZ Editor's CURSOR.COM writes via this port */ - da2->attrregs[da2->attraddr & 0x3f] = val; + case 0x3E9: + /* VZ Editor's CURSOR.COM writes data via this port */ + da2->attrc[da2->attraddr & 0x3f] = val; break; case LG_INDEX: da2->gdcaddr = val; @@ -1103,15 +1247,17 @@ uint16_t da2_in(uint16_t addr, void *p) if (da2->ioctladdr > 0xf) return 0xff; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ - if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrregs[LV_COMPATIBILITY] & 0x08) + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrc[LV_COMPATIBILITY] & 0x08) temp &= 0x7F; /* Inactive when the RGB output voltage is high(or the cable is not connected to the color monitor). */ else temp |= 0x80; /* Active when the RGB output voltage is lowand the cable is connected to the color monitor. If the cable or the monitor is wrong, it becomes inactive. */ temp &= 0xf6;//idle + if (da2->bitblt.indata) /* for OS/2 J1.3 */ + da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { - //da2_log("exec:%d\n", da2->bitblt.exec); + //da2_log("exec:%x\n", da2->bitblt.exec); temp |= 0x08;//wait(bit 3 + bit 0) //if (!da2->bitblt.timer.enabled) //{ @@ -1152,7 +1298,7 @@ uint16_t da2_in(uint16_t addr, void *p) temp = da2->cgastat; } else - temp = da2->attrregs[da2->attraddr]; + temp = da2->attrc[da2->attraddr]; //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ break; @@ -1161,7 +1307,7 @@ uint16_t da2_in(uint16_t addr, void *p) break; case LG_DATA: temp = da2->gdcreg[da2->gdcaddr & 0x1f]; - da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); break; } //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); @@ -1386,12 +1532,18 @@ Bank 1, 2, 3 Bank 4 * -0DB6Fh ( 4800-8DB6Fh;IBMJ 100-1F7Dh) : JIS X 0208 DBCS (24 x 24) 10000-16D1Fh (90000-96D1Fh;IBMJ 2000-2183h) : IBM Extended Characters -18000-1BFFFh (98000-9BFFFh;around IBMJ 21C7-22AAh) : JIS X 0201 SBCS (13 x 30) -1FD20- * +18000-1BFCFh (98000-9BFCFh;around IBMJ 21C7-22AAh) : JIS X 0201 SBCS (13 x 30) +1C000-1FFFFh (9C000-9FFFFh;around IBMJ 22AA-238Eh) : Codepage 437 characters (13 x 30) Bank 5 +00000-0C68Fh (A0000-AC68Fh;around IBMJ 238E-2650h) : Gaiji (24 x 24) + * -0D09Fh (9FD20-AD09Fh;IBMJ 2384-2673h) : Gaiji 752 chs (maybe blank) 10000-13FFFh (B0000-B3FFFh;around IBMJ 271C-27FFh) : Extended SBCS (13 x 30) -14000-146FFh (B4000-B46FFh;IBMJ 2800-2818h) : Half-width box drawing characters (7 lines * 4 parts * 64 bytes) used by DOS Bunsho + +14000-147FFh (B4000-B46FFh;IBMJ 2800-2818h) : Half-width box drawing characters (7 lines * 4 parts * 64 bytes) used by DOS Bunsho +16000-17FFFh (B6000-B7FFFh;around IBMJ h) : Codepage 850 characters (13 x 30) +18000-1A3FFh (B8000-BA3FFh;around IBMJ h) : Shape Icons? (32 x 32) + (B9580-?;IBMJ 2930-295e?) : Full-width box drawing characters The signature 80h, 01h must be placed at Bank 0:1AFFEh to run OS/2 J1.3. @@ -1470,7 +1622,7 @@ uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) foreground <<= 2; //0010 0000 foreground |= ~attr & 0xc0;// 1110 0000 foreground >>= 4;//0000 1110 - if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette return foreground; } @@ -1510,7 +1662,7 @@ static void da2_render_text(da2_t* da2) chr = da2->cram[(da2->ma) & da2->vram_display_mask]; attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); - if (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh {//--Parse attribute byte in color mode-- bg = 0;//bg color is always black (the only way to change background color is programming PAL) fg = getPS55ForeColor(attr, da2); @@ -1561,9 +1713,9 @@ static void da2_render_text(da2_t* da2) // the char code is SBCS (ANK) uint32_t fontbase; if (attr & 0x02)//second map of SBCS font - fontbase = 0x3c000; + fontbase = DA2_GAIJIRAM_SBEX; else - fontbase = 0x34000; + fontbase = DA2_GAIJIRAM_SBCS; uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font font <<= 8; font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font @@ -1587,25 +1739,25 @@ static void da2_render_text(da2_t* da2) chr_wide = 0; } //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. - if (da2->sc == 27 && attr & 0x40 && ~da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode + if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[fg]];//under line (white) } //Column 1 (Vertical Line) if (attr & 0x10) { - p[0] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrregs[LV_PAS_STATUS_CNTRL]) {//HGrid + if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) + p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) } //Drawing text cursor drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); - int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 - fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); bg = 0; if (attr & 0x04) {//Color 0 if reverse bg = fg; @@ -1677,7 +1829,7 @@ static void da2_render_textm3(da2_t* da2) else { // the char code is SBCS (ANK) uint32_t fontbase; - fontbase = 0x34000; + fontbase = DA2_FONTROM_BASESBCS; uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font font <<= 8; font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font @@ -1704,8 +1856,8 @@ static void da2_render_textm3(da2_t* da2) if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); - //int cursorcolor = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrregs[0x1a]) : 2;//Choose color 2 if mode 8 - //fg = (da2->attrregs[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 + //fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; //bg = 0; //if (attr & 0x04) {//Color 0 if reverse // bg = fg; @@ -1876,9 +2028,9 @@ void da2_recalctimings(da2_t* da2) da2->clock = da2->da2const; - da2->lowres = da2->attrregs[LC_VERTICAL_SYNC_START] & 0x40; + //da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; - da2->interlace = 0; + //da2->interlace = 0; //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b da2->ca_adj = 0; @@ -1888,8 +2040,8 @@ void da2_recalctimings(da2_t* da2) da2->hdisp_time = da2->hdisp; da2->render = da2_render_blank; //determine display mode - //if (da2->attr_palette_enable && (da2->attrregs[0x1f] & 0x08)) - if (da2->attrregs[LV_COMPATIBILITY] & 0x08) + //if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) + if (da2->attrc[LV_COMPATIBILITY] & 0x08) { if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode da2->hdisp *= 16; @@ -1907,7 +2059,7 @@ void da2_recalctimings(da2_t* da2) } } else {//text mode - if (da2->attrregs[LV_ATTRIBUTE_CNTL] & 1) { + if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { da2_log("Set videomode to PS/55 Mode 03 text.\n"); da2->render = da2_render_textm3; da2->vram_display_mask = DA2_MASK_CRAM; @@ -2118,7 +2270,7 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.ram[addr]; break; case 0x10://Font ROM - //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); if (addr > DA2_FONTROM_SIZE) return 0xff; return da2->mmio.font[addr]; break; @@ -2165,6 +2317,7 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) for (int i = 0; i < 8; i++) da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch +#ifdef ENABLE_DA2_DEBUGBLT ////debug //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) //{ @@ -2179,7 +2332,7 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) // fprintf(da2->mmrdbg_fp, "%X", pixeldata); //} //da2->mmrdbg_vidaddr = addr; - //// +#endif if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 uint16_t ret = 0; @@ -2200,7 +2353,7 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) else { return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); } -} +} static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) { @@ -2231,12 +2384,15 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) break; case 0x00: //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx - if (addr >= DA2_BLT_MEMSIZE) - { - da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - return; - } + //addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx + //if (addr >= DA2_BLT_MEMSIZE) + //{ + // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + // return; + //} + da2->bitblt.indata = 1; + if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); da2->bitblt.payload[da2->bitblt.payload_addr] = val; da2->bitblt.payload_addr++; break; @@ -2249,23 +2405,25 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) { uint8_t wm = da2->writemask; //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); +#ifdef ENABLE_DA2_DEBUGBLT //debug //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ - //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - //{ - // fprintf(da2->mmdbg_fp, "\nB %x ", addr); - // for (int i = 0; i <= 0xb; i++) - // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); - //} - //for (int i = 0; i < 8; i++) - //{ - // int pixeldata = 0; - // if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); - // fprintf(da2->mmdbg_fp, "%X", pixeldata); - //} - //da2->mmdbg_vidaddr = addr; + if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + { + fprintf(da2->mmdbg_fp, "\nB %x ", addr); + for (int i = 0; i <= 0xb; i++) + fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + } + for (int i = 0; i < 8; i++) + { + int pixeldata = 0; + if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); + fprintf(da2->mmdbg_fp, "%X", pixeldata); + } + da2->mmdbg_vidaddr = addr; //} +#endif cycles -= video_timing_write_b; @@ -2273,7 +2431,7 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) addr <<= 3; for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch + da2->gdcsrc[i] = da2->gdcla[i];//use latch //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); @@ -2361,24 +2519,26 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; bitmask <<= 8; bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; +#ifdef ENABLE_DA2_DEBUGBLT //debug //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ - //if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - //{ - // fprintf(da2->mmdbg_fp, "\nW %x ", addr); - // for (int i = 0; i <= 0xb; i++) - // fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); - //} - //for (int i = 0; i < 16; i++) - //{ - // int pixeldata = 0; - // if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); - // fprintf(da2->mmdbg_fp, "%X", pixeldata); - //} - //da2->mmdbg_vidaddr = addr; + if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + { + fprintf(da2->mmdbg_fp, "\nW %x ", addr); + for (int i = 0; i <= 0xb; i++) + fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + } + for (int i = 0; i < 16; i++) + { + int pixeldata = 0; + if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); + fprintf(da2->mmdbg_fp, "%X", pixeldata); + } + da2->mmdbg_vidaddr = addr; //} - //cycles -= video_timing_write_w; +#endif + cycles -= video_timing_write_w; //cycles_lost += video_timing_write_w; //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); @@ -2585,8 +2745,8 @@ void da2_poll(void* priv) //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); da2->displine++; - if (da2->interlace) - da2->displine++; + //if (da2->interlace) + // da2->displine++; if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) { //da2_log("Vsync off at line %i\n",displine); @@ -2641,7 +2801,7 @@ void da2_poll(void* priv) //if (da2->crtc[10] & 0x20) da2->cursoron = 0; //else da2->cursoron = da2->blink & 16; if (da2->ioctl[LS_MODE] & 1) {//in text mode - if (da2->attrregs[LV_CURSOR_CONTROL] & 0x01)//cursor blinking + if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)//cursor blinking { da2->cursoron = (da2->blink | 1) & da2->blinkconf; } @@ -2673,8 +2833,8 @@ void da2_poll(void* priv) da2->cgastat |= 8; x = da2->hdisp; - if (da2->interlace && !da2->oddeven) da2->lastline++; - if (da2->interlace && da2->oddeven) da2->firstline--; + //if (da2->interlace && !da2->oddeven) da2->lastline++; + //if (da2->interlace && da2->oddeven) da2->firstline--; wx = x; wy = da2->lastline - da2->firstline; @@ -2695,8 +2855,8 @@ void da2_poll(void* priv) //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; - if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; - else da2->ma = da2->maback = da2->ma_latch; +/* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; + else*/ da2->ma = da2->maback = da2->ma_latch; da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; da2->ma <<= 1; @@ -2715,7 +2875,7 @@ void da2_poll(void* priv) da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; da2->dispon = 1; da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; - da2->scrollcache = da2->attrregs[LV_PANNING] & 7; + da2->scrollcache = da2->attrc[LV_PANNING] & 7; } if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; @@ -2793,12 +2953,12 @@ da2_reset(void* priv) da2->ioctl[LS_CONFIG2] = Mon_ID1; /* Configuration (High): Monitor ID 0-2 */ da2->fctl[0] = 0x2b; /* 3E3h:0 */ da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ - da2->attrregs[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ da2->ma_latch = 0; da2->interlace = 0; - da2->attrregs[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ da2->attr_palette_enable = 0; /* disable attribute generator */ /* Set default color palette (Display driver of Win 3.1 won't reset palette) */ @@ -2889,7 +3049,7 @@ void da2_close(void *p) } f = fopen("da2_attrpal.dmp", "wb"); if (f != NULL) { - fwrite(da2->attrregs, 32, 1, f); + fwrite(da2->attrc, 32, 1, f); fclose(f); } f = fopen("da2_dacrgb.dmp", "wb"); @@ -2906,7 +3066,7 @@ void da2_close(void *p) for (int i = 0; i < 0x20; i++) fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); for (int i = 0; i < 0x40; i++) - fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrregs[i]); + fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrc[i]); for (int i = 0; i < 0x10; i++) fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); for (int i = 0; i < 0x10; i++) @@ -2939,7 +3099,7 @@ void da2_close(void *p) } if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); - free(da2->bitblt.debug_reg); + free(da2->bitblt.debug_reg); #endif free(da2->cram); free(da2->vram); From 738087ae132c677735d2b277ab5cc3cdd4e6ce1c Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 Jan 2025 23:28:08 -0500 Subject: [PATCH 0032/1190] Cleanups in device --- src/device.c | 249 +++++++++++++++++++------------------ src/include/86box/device.h | 26 ++-- 2 files changed, 138 insertions(+), 137 deletions(-) diff --git a/src/device.c b/src/device.c index 9a904f550..5b733df46 100644 --- a/src/device.c +++ b/src/device.c @@ -19,7 +19,7 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2008-2019 Sarah Walker. * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -89,38 +89,38 @@ device_init(void) } void -device_set_context(device_context_t *c, const device_t *dev, int inst) +device_set_context(device_context_t *ctx, const device_t *dev, int inst) { - memset(c, 0, sizeof(device_context_t)); - c->dev = dev; - c->instance = inst; + memset(ctx, 0, sizeof(device_context_t)); + ctx->dev = dev; + ctx->instance = inst; if (inst) { - sprintf(c->name, "%s #%i", dev->name, inst); + sprintf(ctx->name, "%s #%i", dev->name, inst); /* If a numbered section is not present, but a non-numbered of the same name is, rename the non-numbered section to numbered. */ - const void *sec = config_find_section(c->name); + const void *sec = config_find_section(ctx->name); void * single_sec = config_find_section((char *) dev->name); if ((sec == NULL) && (single_sec != NULL)) - config_rename_section(single_sec, c->name); + config_rename_section(single_sec, ctx->name); } else if (!strcmp(dev->name, "PS/2 Mouse")) { - sprintf(c->name, "%s", dev->name); + sprintf(ctx->name, "%s", dev->name); /* Migrate the old "Standard PS/2 Mouse" section */ - const void *sec = config_find_section(c->name); + const void *sec = config_find_section(ctx->name); void * old_sec = config_find_section("Standard PS/2 Mouse"); if ((sec == NULL) && (old_sec != NULL)) - config_rename_section(old_sec, c->name); + config_rename_section(old_sec, ctx->name); } else if (!strcmp(dev->name, "Microsoft RAMCard")) { - sprintf(c->name, "%s", dev->name); + sprintf(ctx->name, "%s", dev->name); - /* Migrate the old "Standard PS/2 Mouse" section */ - const void *sec = config_find_section(c->name); + /* Migrate the old "Microsoft RAMCard for IBM PC" section */ + const void *sec = config_find_section(ctx->name); void * old_sec = config_find_section("Microsoft RAMCard for IBM PC"); if ((sec == NULL) && (old_sec != NULL)) - config_rename_section(old_sec, c->name); + config_rename_section(old_sec, ctx->name); } else - sprintf(c->name, "%s", dev->name); + sprintf(ctx->name, "%s", dev->name); } static void @@ -153,7 +153,7 @@ device_add_common(const device_t *dev, void *p, void *params, int inst) { device_t *init_dev = NULL; void *priv = NULL; - int c; + int16_t c; if (params != NULL) { init_dev = calloc(1, sizeof(device_t)); @@ -162,7 +162,7 @@ device_add_common(const device_t *dev, void *p, void *params, int inst) } else init_dev = (device_t *) dev; - for (c = 0; c < 256; c++) { + for (c = 0; c < DEVICE_MAX; c++) { if (!inst && (devices[c] == dev)) { device_log("DEVICE: device already exists!\n"); return (NULL); @@ -244,6 +244,7 @@ void * device_add_linked(const device_t *dev, void *priv) { void *ret; + device_common_priv = priv; ret = device_add_common(dev, NULL, NULL, 0); device_common_priv = NULL; @@ -311,7 +312,8 @@ device_close_all(void) #endif if (devices[c]->close != NULL) devices[c]->close(device_priv[c]); - devices[c] = device_priv[c] = NULL; + devices[c] = NULL; + device_priv[c] = NULL; } } } @@ -372,7 +374,7 @@ device_available(const device_t *dev) if (dev != NULL) { config = dev->config; if (config != NULL) { - while (config->type != -1) { + while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { int roms_present = 0; @@ -414,7 +416,7 @@ device_get_bios_file(const device_t *dev, const char *internal_name, int file_no if (dev != NULL) { config = dev->config; if (config != NULL) { - while (config->type != -1) { + while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { bios = config->bios; @@ -452,7 +454,7 @@ device_has_config(const device_t *dev) config = dev->config; - while (config->type != -1) { + while (config->type != CONFIG_END) { c++; config++; } @@ -543,8 +545,7 @@ device_get_name(const device_t *dev, int bus, char *name) strcat(pbus, ")"); /* Allocate the temporary device name string and set it to all zeroes. */ - tname = (char *) malloc(strlen(dev->name) + 1); - memset(tname, 0x00, strlen(dev->name) + 1); + tname = (char *) calloc(1, strlen(dev->name) + 1); /* First strip the bus string with parentheses. */ fbus = strstr(dev->name, pbus); @@ -612,256 +613,256 @@ device_get_instance(void) } const char * -device_get_config_string(const char *s) +device_get_config_string(const char *str) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_string((char *) device_current.name, (char *) s, (char *) c->default_string)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_string((char *) device_current.name, (char *) str, (char *) cfg->default_string)); - c++; + cfg++; } return (NULL); } int -device_get_config_int(const char *s) +device_get_config_int(const char *str) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_int((char *) device_current.name, (char *) s, c->default_int)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); - c++; + cfg++; } return 0; } int -device_get_config_int_ex(const char *s, int def) +device_get_config_int_ex(const char *str, int def) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_int((char *) device_current.name, (char *) s, def)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, def)); - c++; + cfg++; } return def; } int -device_get_config_hex16(const char *s) +device_get_config_hex16(const char *str) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_hex16((char *) device_current.name, (char *) s, c->default_int)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); - c++; + cfg++; } return 0; } int -device_get_config_hex20(const char *s) +device_get_config_hex20(const char *str) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_hex20((char *) device_current.name, (char *) s, c->default_int)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); - c++; + cfg++; } return 0; } int -device_get_config_mac(const char *s, int def) +device_get_config_mac(const char *str, int def) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_mac((char *) device_current.name, (char *) s, def)); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_mac((char *) device_current.name, (char *) str, def)); - c++; + cfg++; } return def; } void -device_set_config_int(const char *s, int val) +device_set_config_int(const char *str, int val) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) { - config_set_int((char *) device_current.name, (char *) s, val); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) { + config_set_int((char *) device_current.name, (char *) str, val); break; } - c++; + cfg++; } } void -device_set_config_hex16(const char *s, int val) +device_set_config_hex16(const char *str, int val) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) { - config_set_hex16((char *) device_current.name, (char *) s, val); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) { + config_set_hex16((char *) device_current.name, (char *) str, val); break; } - c++; + cfg++; } } void -device_set_config_hex20(const char *s, int val) +device_set_config_hex20(const char *str, int val) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) { - config_set_hex20((char *) device_current.name, (char *) s, val); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) { + config_set_hex20((char *) device_current.name, (char *) str, val); break; } - c++; + cfg++; } } void -device_set_config_mac(const char *s, int val) +device_set_config_mac(const char *str, int val) { - const device_config_t *c = device_current.dev->config; + const device_config_t *cfg = device_current.dev->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) { - config_set_mac((char *) device_current.name, (char *) s, val); + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) { + config_set_mac((char *) device_current.name, (char *) str, val); break; } - c++; + cfg++; } } int -device_is_valid(const device_t *device, int m) +device_is_valid(const device_t *device, int mch) { if (device == NULL) return 1; - if ((device->flags & DEVICE_PCJR) && !machine_has_bus(m, MACHINE_BUS_PCJR)) + if ((device->flags & DEVICE_PCJR) && !machine_has_bus(mch, MACHINE_BUS_PCJR)) return 0; - if ((device->flags & DEVICE_XTKBC) && machine_has_bus(m, MACHINE_BUS_ISA16) && !machine_has_bus(m, MACHINE_BUS_DM_KBC)) + if ((device->flags & DEVICE_XTKBC) && machine_has_bus(mch, MACHINE_BUS_ISA16) && !machine_has_bus(mch, MACHINE_BUS_DM_KBC)) return 0; - if ((device->flags & DEVICE_AT) && !machine_has_bus(m, MACHINE_BUS_ISA16)) + if ((device->flags & DEVICE_AT) && !machine_has_bus(mch, MACHINE_BUS_ISA16)) return 0; - if ((device->flags & DEVICE_ATKBC) && !machine_has_bus(m, MACHINE_BUS_ISA16) && !machine_has_bus(m, MACHINE_BUS_DM_KBC)) + if ((device->flags & DEVICE_ATKBC) && !machine_has_bus(mch, MACHINE_BUS_ISA16) && !machine_has_bus(mch, MACHINE_BUS_DM_KBC)) return 0; - if ((device->flags & DEVICE_PS2) && !machine_has_bus(m, MACHINE_BUS_PS2_PORTS)) + if ((device->flags & DEVICE_PS2) && !machine_has_bus(mch, MACHINE_BUS_PS2_PORTS)) return 0; - if ((device->flags & DEVICE_ISA) && !machine_has_bus(m, MACHINE_BUS_ISA)) + if ((device->flags & DEVICE_ISA) && !machine_has_bus(mch, MACHINE_BUS_ISA)) return 0; - if ((device->flags & DEVICE_CBUS) && !machine_has_bus(m, MACHINE_BUS_CBUS)) + if ((device->flags & DEVICE_CBUS) && !machine_has_bus(mch, MACHINE_BUS_CBUS)) return 0; - if ((device->flags & DEVICE_PCMCIA) && !machine_has_bus(m, MACHINE_BUS_PCMCIA) && !machine_has_bus(m, MACHINE_BUS_ISA)) + if ((device->flags & DEVICE_PCMCIA) && !machine_has_bus(mch, MACHINE_BUS_PCMCIA) && !machine_has_bus(mch, MACHINE_BUS_ISA)) return 0; - if ((device->flags & DEVICE_MCA) && !machine_has_bus(m, MACHINE_BUS_MCA)) + if ((device->flags & DEVICE_MCA) && !machine_has_bus(mch, MACHINE_BUS_MCA)) return 0; - if ((device->flags & DEVICE_HIL) && !machine_has_bus(m, MACHINE_BUS_HIL)) + if ((device->flags & DEVICE_HIL) && !machine_has_bus(mch, MACHINE_BUS_HIL)) return 0; - if ((device->flags & DEVICE_EISA) && !machine_has_bus(m, MACHINE_BUS_EISA)) + if ((device->flags & DEVICE_EISA) && !machine_has_bus(mch, MACHINE_BUS_EISA)) return 0; - if ((device->flags & DEVICE_AT32) && !machine_has_bus(m, MACHINE_BUS_AT32)) + if ((device->flags & DEVICE_AT32) && !machine_has_bus(mch, MACHINE_BUS_AT32)) return 0; - if ((device->flags & DEVICE_OLB) && !machine_has_bus(m, MACHINE_BUS_OLB)) + if ((device->flags & DEVICE_OLB) && !machine_has_bus(mch, MACHINE_BUS_OLB)) return 0; - if ((device->flags & DEVICE_VLB) && !machine_has_bus(m, MACHINE_BUS_VLB)) + if ((device->flags & DEVICE_VLB) && !machine_has_bus(mch, MACHINE_BUS_VLB)) return 0; - if ((device->flags & DEVICE_PCI) && !machine_has_bus(m, MACHINE_BUS_PCI)) + if ((device->flags & DEVICE_PCI) && !machine_has_bus(mch, MACHINE_BUS_PCI)) return 0; - if ((device->flags & DEVICE_CARDBUS) && !machine_has_bus(m, MACHINE_BUS_CARDBUS) && !machine_has_bus(m, MACHINE_BUS_PCI)) + if ((device->flags & DEVICE_CARDBUS) && !machine_has_bus(mch, MACHINE_BUS_CARDBUS) && !machine_has_bus(mch, MACHINE_BUS_PCI)) return 0; - if ((device->flags & DEVICE_USB) && !machine_has_bus(m, MACHINE_BUS_USB)) + if ((device->flags & DEVICE_USB) && !machine_has_bus(mch, MACHINE_BUS_USB)) return 0; - if ((device->flags & DEVICE_AGP) && !machine_has_bus(m, MACHINE_BUS_AGP)) + if ((device->flags & DEVICE_AGP) && !machine_has_bus(mch, MACHINE_BUS_AGP)) return 0; - if ((device->flags & DEVICE_AC97) && !machine_has_bus(m, MACHINE_BUS_AC97)) + if ((device->flags & DEVICE_AC97) && !machine_has_bus(mch, MACHINE_BUS_AC97)) return 0; return 1; } int -machine_get_config_int(char *s) +machine_get_config_int(char *str) { - const device_t *d = machine_get_device(machine); - const device_config_t *c; + const device_t *dev = machine_get_device(machine); + const device_config_t *cfg; - if (d == NULL) + if (dev == NULL) return 0; - c = d->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_int((char *) d->name, s, c->default_int)); + cfg = dev->config; + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) dev->name, str, cfg->default_int)); - c++; + cfg++; } return 0; } char * -machine_get_config_string(char *s) +machine_get_config_string(char *str) { - const device_t *d = machine_get_device(machine); - const device_config_t *c; + const device_t *dev = machine_get_device(machine); + const device_config_t *cfg; - if (d == NULL) + if (dev == NULL) return 0; - c = d->config; - while (c && c->type != -1) { - if (!strcmp(s, c->name)) - return (config_get_string((char *) d->name, s, (char *) c->default_string)); + cfg = dev->config; + while (cfg && cfg->type != CONFIG_END) { + if (!strcmp(str, cfg->name)) + return (config_get_string((char *) dev->name, str, (char *) cfg->default_string)); - c++; + cfg++; } return NULL; @@ -881,7 +882,7 @@ const device_t device_none = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -895,7 +896,7 @@ const device_t device_internal = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 67a30b1c8..1c2ec5203 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -18,7 +18,7 @@ * Copyright 2016-2019 Miran Grca. * Copyright 2008-2019 Sarah Walker. * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -197,12 +197,12 @@ extern "C" { #endif extern void device_init(void); -extern void device_set_context(device_context_t *c, const device_t *dev, int inst); +extern void device_set_context(device_context_t *ctx, const device_t *dev, int inst); extern void device_context(const device_t *dev); extern void device_context_inst(const device_t *dev, int inst); extern void device_context_restore(void); -extern void *device_add(const device_t *d); -extern void *device_add_linked(const device_t *d, void *priv); +extern void *device_add(const device_t *dev); +extern void *device_add_linked(const device_t *dev, void *priv); extern void *device_add_params(const device_t *dev, void *params); extern void device_add_ex(const device_t *dev, void *priv); extern void device_add_ex_params(const device_t *dev, void *priv, void *params); @@ -223,27 +223,27 @@ extern void device_get_name(const device_t *dev, int bus, char *name); extern int device_has_config(const device_t *dev); extern const char *device_get_bios_file(const device_t *dev, const char *internal_name, int file_no); -extern int device_is_valid(const device_t *, int m); +extern int device_is_valid(const device_t *, int mch); extern const device_t* device_context_get_device(void); extern int device_get_config_int(const char *name); -extern int device_get_config_int_ex(const char *s, int dflt_int); +extern int device_get_config_int_ex(const char *str, int def); extern int device_get_config_hex16(const char *name); extern int device_get_config_hex20(const char *name); -extern int device_get_config_mac(const char *name, int dflt_int); -extern void device_set_config_int(const char *s, int val); -extern void device_set_config_hex16(const char *s, int val); -extern void device_set_config_hex20(const char *s, int val); -extern void device_set_config_mac(const char *s, int val); +extern int device_get_config_mac(const char *name, int def); +extern void device_set_config_int(const char *str, int val); +extern void device_set_config_hex16(const char *str, int val); +extern void device_set_config_hex20(const char *str, int val); +extern void device_set_config_mac(const char *str, int val); extern const char *device_get_config_string(const char *name); extern int device_get_instance(void); #define device_get_config_bios device_get_config_string extern const char *device_get_internal_name(const device_t *dev); -extern int machine_get_config_int(char *s); -extern char *machine_get_config_string(char *s); +extern int machine_get_config_int(char *str); +extern char *machine_get_config_string(char *str); extern const device_t device_none; extern const device_t device_internal; From 1ee305d0f3979ab8b04ee777f2cc0a1d3da8e3ff Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Thu, 9 Jan 2025 23:22:00 -0500 Subject: [PATCH 0033/1190] devices -> midi_out_devices in sound/midi.c --- src/sound/midi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sound/midi.c b/src/sound/midi.c index 78794ef24..e9b4a82b6 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -71,7 +71,7 @@ typedef struct const device_t *device; } MIDI_OUT_DEVICE, MIDI_IN_DEVICE; -static const MIDI_OUT_DEVICE devices[] = { +static const MIDI_OUT_DEVICE midi_out_devices[] = { // clang-format off { &device_none }, #ifdef USE_FLUIDSYNTH @@ -106,8 +106,8 @@ static const MIDI_IN_DEVICE midi_in_devices[] = { int midi_out_device_available(int card) { - if (devices[card].device) - return device_available(devices[card].device); + if (midi_out_devices[card].device) + return device_available(midi_out_devices[card].device); return 1; } @@ -115,21 +115,21 @@ midi_out_device_available(int card) const device_t * midi_out_device_getdevice(int card) { - return devices[card].device; + return midi_out_devices[card].device; } int midi_out_device_has_config(int card) { - if (!devices[card].device) + if (!midi_out_devices[card].device) return 0; - return devices[card].device->config ? 1 : 0; + return midi_out_devices[card].device->config ? 1 : 0; } const char * midi_out_device_get_internal_name(int card) { - return device_get_internal_name(devices[card].device); + return device_get_internal_name(midi_out_devices[card].device); } int @@ -137,8 +137,8 @@ midi_out_device_get_from_internal_name(char *s) { int c = 0; - while (devices[c].device != NULL) { - if (!strcmp(devices[c].device->internal_name, s)) + while (midi_out_devices[c].device != NULL) { + if (!strcmp(midi_out_devices[c].device->internal_name, s)) return c; c++; } @@ -149,8 +149,8 @@ midi_out_device_get_from_internal_name(char *s) void midi_out_device_init(void) { - if ((midi_output_device_current > 0) && devices[midi_output_device_current].device) - device_add(devices[midi_output_device_current].device); + if ((midi_output_device_current > 0) && midi_out_devices[midi_output_device_current].device) + device_add(midi_out_devices[midi_output_device_current].device); midi_output_device_last = midi_output_device_current; } From cbbf91b790d585421b8b97697a442789f1a35674 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 01:09:09 -0500 Subject: [PATCH 0034/1190] Add other BIOS versions to ibmpc --- src/machine/m_xt.c | 60 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index db511c332..b31e58bdf 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -61,6 +61,29 @@ machine_xt_common_init(const machine_t *model, int fixed_floppy) static const device_config_t ibmpc_config[] = { // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ibm5150_5700671", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "5700671 (10/19/81)", .internal_name = "ibm5150_5700671", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc/BIOS_IBM5150_19OCT81_5700671_U33.BIN", "" } }, + { .name = "5700051 (04/24/81)", .internal_name = "ibm5150_5700051", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc/BIOS_IBM5150_24APR81_5700051_U33.BIN", "" } }, + // The following are Diagnostic ROMs. + { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, + { .name = "Ruud's Diagnostic Rom", .internal_name = "diag_ruuds", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/diagnostic/ruuds_diagnostic_rom_v5.3_8kb.bin", "" } }, + { .name = "XT RAM Test", .internal_name = "diag_xtramtest", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/diagnostic/xtramtest_8k.bin", "" } }, + { .files_no = 0 } + }, + }, { .name = "enable_5161", .description = "IBM 5161 Expansion Unit", @@ -94,27 +117,36 @@ const device_t ibmpc_device = { int machine_pc_init(const machine_t *model) { - int ret; - uint8_t enable_5161; - uint8_t enable_basic; + int ret = 0; + int ret2; + uint8_t enable_5161; + uint8_t enable_basic; + const char *fn; + + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; device_context(model->device); enable_5161 = machine_get_config_int("enable_5161"); enable_basic = machine_get_config_int("enable_basic"); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fe000, 40960, 0); device_context_restore(); - ret = bios_load_linear("roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", - 0x000fe000, 40960, 0); - if (enable_basic && ret) { - bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", - 0x000f6000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", - 0x000f8000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", - 0x000fa000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", - 0x000fc000, 8192, 0); + ret2 = bios_load_aux_linear("roms/machines/ibmpc/ibm-basic-1.00.rom", + 0x000f6000, 32768, 0); + if (!ret2) { + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", + 0x000f6000, 8192, 0); + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", + 0x000f8000, 8192, 0); + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", + 0x000fa000, 8192, 0); + bios_load_aux_linear("roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", + 0x000fc000, 8192, 0); + } } if (bios_only || !ret) From 312536f51e14bc8f924521b71b2edb815e707c9b Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 01:09:27 -0500 Subject: [PATCH 0035/1190] A few updates to ibmpc82 --- src/machine/m_xt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index b31e58bdf..d38dd6bc6 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -224,7 +224,7 @@ machine_pc82_init(const machine_t *model) int ret2; uint8_t enable_5161; uint8_t enable_basic; - const char* fn; + const char *fn; /* No ROMs available. */ if (!device_available(model->device)) @@ -241,13 +241,13 @@ machine_pc82_init(const machine_t *model) ret2 = bios_load_aux_linear("roms/machines/ibmpc82/ibm-basic-1.10.rom", 0x000f6000, 32768, 0); if (!ret2) { - bios_load_aux_linear("roms/machines/ibmpc82/basicc11.f6", + bios_load_aux_linear("roms/machines/ibmpc82/IBM 5150 - Cassette BASIC version C1.10 - U29 - 5000019.bin", 0x000f6000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc82/basicc11.f8", + bios_load_aux_linear("roms/machines/ibmpc82/IBM 5150 - Cassette BASIC version C1.10 - U30 - 5000021.bin", 0x000f8000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc82/basicc11.fa", + bios_load_aux_linear("roms/machines/ibmpc82/IBM 5150 - Cassette BASIC version C1.10 - U31 - 5000022.bin", 0x000fa000, 8192, 0); - bios_load_aux_linear("roms/machines/ibmpc82/basicc11.fc", + bios_load_aux_linear("roms/machines/ibmpc82/IBM 5150 - Cassette BASIC version C1.10 - U32 - 5000023.bin", 0x000fc000, 8192, 0); } } From c01022db46ec2a78ca9142798770ccc60dc09d31 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 02:33:13 -0500 Subject: [PATCH 0036/1190] Add other BIOS versions to ibmxt (82) --- src/machine/m_xt.c | 65 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index d38dd6bc6..9a56c4870 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -267,12 +267,45 @@ machine_pc82_init(const machine_t *model) static const device_config_t ibmxt_config[] = { // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ibm5160_1501512_5000027", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "1501512 (11/08/82)", .internal_name = "ibm5160_1501512_5000027", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_08NOV82_U18_1501512.BIN", "roms/machines/ibmxt/BIOS_5160_08NOV82_U19_5000027.BIN", "" } }, +#if 0 + { .name = "1501512 (11/08/82) (Alt)", .internal_name = "ibm5160_1501512_6359116", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_08NOV82_U18_1501512.BIN", "roms/machines/ibmxt/BIOS_5160_08NOV82_U19_6359116.BIN", "" } }, + { .name = "5000026 (08/16/82)", .internal_name = "ibm5160_5000026_5000027", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_16AUG82_U18_5000026.BIN", "roms/machines/ibmxt/BIOS_5160_16AUG82_U19_5000027.BIN", "" } }, + // The following are Diagnostic ROMs. + { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, + { .name = "Ruud's Diagnostic Rom", .internal_name = "diag_ruuds", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/ruuds_diagnostic_rom_v5.3_8kb.bin", "" } }, + { .name = "XT RAM Test", .internal_name = "diag_xtramtest", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/xtramtest_8k.bin", "" } }, +#endif + { .files_no = 0 } + }, + }, { .name = "enable_5161", .description = "IBM 5161 Expansion Unit", .type = CONFIG_BINARY, .default_int = 1 }, + { + .name = "enable_basic", + .description = "IBM Cassette Basic", + .type = CONFIG_BINARY, + .default_int = 1 + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -294,26 +327,28 @@ const device_t ibmxt_device = { int machine_xt_init(const machine_t *model) { - int ret; - uint8_t enable_5161; - uint8_t enable_basic; + int ret; + uint8_t enable_5161; + uint8_t enable_basic; + const char *fn; + + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; device_context(model->device); enable_5161 = machine_get_config_int("enable_5161"); - device_context_restore(); + enable_basic = machine_get_config_int("enable_basic"); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fe000, 65536, 0x6000); - ret = bios_load_linear("roms/machines/ibmxt/xt.rom", - 0x000f0000, 65536, 0); - if (!ret) { - ret = bios_load_linear("roms/machines/ibmxt/1501512.u18", - 0x000fe000, 65536, 0x6000); - if (ret) { - bios_load_aux_linear("roms/machines/ibmxt/1501512.u18", - 0x000f8000, 24576, 0); - bios_load_aux_linear("roms/machines/ibmxt/5000027.u19", - 0x000f0000, 32768, 0); - } + if (enable_basic && ret) { + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + (void) bios_load_aux_linear(fn, 0x000f8000, 24576, 0); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); + (void) bios_load_aux_linear(fn, 0x000f0000, 32768, 0); } + device_context_restore(); if (bios_only || !ret) return ret; From a6b8f826fee27d55710c2e3019e68e550a8e17cc Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 03:24:12 -0500 Subject: [PATCH 0037/1190] Fixes --- src/machine/m_xt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 9a56c4870..1977c88df 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -278,11 +278,11 @@ static const device_config_t ibmxt_config[] = { .bios = { { .name = "1501512 (11/08/82)", .internal_name = "ibm5160_1501512_5000027", .bios_type = BIOS_NORMAL, .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_08NOV82_U18_1501512.BIN", "roms/machines/ibmxt/BIOS_5160_08NOV82_U19_5000027.BIN", "" } }, -#if 0 { .name = "1501512 (11/08/82) (Alt)", .internal_name = "ibm5160_1501512_6359116", .bios_type = BIOS_NORMAL, .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_08NOV82_U18_1501512.BIN", "roms/machines/ibmxt/BIOS_5160_08NOV82_U19_6359116.BIN", "" } }, { .name = "5000026 (08/16/82)", .internal_name = "ibm5160_5000026_5000027", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_16AUG82_U18_5000026.BIN", "roms/machines/ibmxt/BIOS_5160_16AUG82_U19_5000027.BIN", "" } }, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_16AUG82_U18_5000026.BIN", "roms/machines/ibmxt/BIOS_5160_16AUG82_U19_5000027.BIN", "" } }, +#if 0 // The following are Diagnostic ROMs. { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, @@ -327,7 +327,7 @@ const device_t ibmxt_device = { int machine_xt_init(const machine_t *model) { - int ret; + int ret = 0; uint8_t enable_5161; uint8_t enable_basic; const char *fn; From 3ffaf21f605a00046af145d17bc40db238d8fd69 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 03:24:38 -0500 Subject: [PATCH 0038/1190] Add other BIOS versions to ibmxt (86) --- src/machine/m_xt.c | 50 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 1977c88df..7b59686d6 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -383,6 +383,33 @@ machine_genxt_init(const machine_t *model) static const device_config_t ibmxt86_config[] = { // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ibm5160_050986", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "1501512 (05/09/86)", .internal_name = "ibm5160_050986", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", "roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", "" } }, + { .name = "5000026 (01/10/86)", .internal_name = "ibm5160_011086", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt86/BIOS_5160_10JAN86_U18_62X0851_27256_F800.BIN", "roms/machines/ibmxt86/BIOS_5160_10JAN86_U19_62X0854_27256_F000.BIN", "" } }, + { .name = "1501512 (01/10/86) (Alt)", .internal_name = "ibm5160_011086_alt", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt86/BIOS_5160_10JAN86_U18_62X0852_27256_F800.BIN", "roms/machines/ibmxt86/BIOS_5160_10JAN86_U19_62X0853_27256_F000.BIN", "" } }, +#if 0 + // The following are Diagnostic ROMs. + { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, + { .name = "Ruud's Diagnostic Rom", .internal_name = "diag_ruuds", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/ruuds_diagnostic_rom_v5.3_8kb.bin", "" } }, + { .name = "XT RAM Test", .internal_name = "diag_xtramtest", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/xtramtest_8k.bin", "" } }, +#endif + { .files_no = 0 } + }, + }, { .name = "enable_5161", .description = "IBM 5161 Expansion Unit", @@ -410,21 +437,26 @@ const device_t ibmxt86_device = { int machine_xt86_init(const machine_t *model) { - int ret; - uint8_t enable_5161; + int ret = 0; + uint8_t enable_5161; + const char *fn; + + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; device_context(model->device); enable_5161 = machine_get_config_int("enable_5161"); - device_context_restore(); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fe000, 65536, 0x6000); - ret = bios_load_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", - 0x000fe000, 65536, 0x6000); if (ret) { - (void) bios_load_aux_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", - 0x000f8000, 24576, 0); - (void) bios_load_aux_linear("roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", - 0x000f0000, 32768, 0); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + (void) bios_load_aux_linear(fn, 0x000f8000, 24576, 0); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); + (void) bios_load_aux_linear(fn, 0x000f0000, 32768, 0); } + device_context_restore(); if (bios_only || !ret) return ret; From 78a81b0d7fda7223400dc0eb424d54bab893e6d2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 10 Jan 2025 21:56:04 +0100 Subject: [PATCH 0039/1190] AT / PS/2 keyboard: It turns out a few other commands also cancel the pending command, fixes #4981. --- src/device/keyboard_at.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 882174e4e..af3d5d5fc 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1961,18 +1961,24 @@ keyboard_at_write(void *priv) } } else { if (dev->flags & FLAG_CTRLDAT) { - /* Special case - another command during another command that wants input - proceed + /* + Special case - another command during another command that wants input - proceed as normal but do not cancel the command (so keep waiting for input), unless the - command in progress is ED (Set/reset LEDs). */ - if (val == 0xed) { - keyboard_scan = 1; + command in progress is ED (Set/reset LEDs). + + It appears to also apply to command EE (Echo), F4 (Enable), F5 (Diable and Set + Default), and F6 (SetDefault). + */ + if ((val == 0xed) || (val == 0xee) || (val == 0xf4) || (val == 0xf5) || (val == 0xf6)) dev->flags &= ~FLAG_CTRLDAT; - } else + else dev->state = DEV_STATE_MAIN_WANT_IN; } switch (val) { case 0xed: /* set/reset LEDs */ + if ((dev->flags & FLAG_CTRLDAT) && (dev->command == 0xed)) + keyboard_scan = 1; dev->command = val; keyboard_at_log("%s: set/reset LEDs\n", dev->name); dev->flags |= FLAG_CTRLDAT; From f774618b1eb59df04a6b56b2053e65b3cd7db2f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 10 Jan 2025 23:40:54 +0100 Subject: [PATCH 0040/1190] SiS 5513 PCI to ISA bridge: fix a typo in a revision check. --- src/chipset/sis_5513_p2i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/sis_5513_p2i.c b/src/chipset/sis_5513_p2i.c index ef9a6746d..4205db161 100644 --- a/src/chipset/sis_5513_p2i.c +++ b/src/chipset/sis_5513_p2i.c @@ -106,7 +106,7 @@ sis_5513_apc_reset(sis_5513_pci_to_isa_t *dev) { memset(dev->apc_regs, 0x00, sizeof(dev->apc_regs)); - if (dev->rev == 0b0) { + if (dev->rev == 0xb0) { dev->apc_regs[0x03] = 0x80; dev->apc_regs[0x04] = 0x38; dev->apc_regs[0x07] = 0x01; From 28c296fc753046b7455a97265ae58b4bf9bcbc4d Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 11 Jan 2025 00:12:13 +0100 Subject: [PATCH 0041/1190] More case ranges in src/chipset/ali1531.c. --- src/chipset/ali1531.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index 9eb75f7cd..06d0a0a60 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -225,12 +225,8 @@ ali1531_write(UNUSED(int func), int addr, uint8_t val, void *priv) ali1531_shadow_recalc(val, dev); break; - case 0x50: - case 0x51: - case 0x52: - case 0x54: - case 0x55: - case 0x56: + case 0x50 ... 0x52: + case 0x54 ... 0x56: dev->pci_conf[addr] = val; break; @@ -247,8 +243,7 @@ ali1531_write(UNUSED(int func), int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x86; break; - case 0x59: - case 0x5a: + case 0x59 ... 0x5a: case 0x5c: dev->pci_conf[addr] = val; break; @@ -270,8 +265,7 @@ ali1531_write(UNUSED(int func), int addr, uint8_t val, void *priv) spd_write_drbs_interleaved(dev->pci_conf, 0x60, 0x6f, 1); break; - case 0x70: - case 0x71: + case 0x70 ... 0x71: dev->pci_conf[addr] = val; break; @@ -283,8 +277,7 @@ ali1531_write(UNUSED(int func), int addr, uint8_t val, void *priv) dev->pci_conf[addr] = val & 0x2b; break; - case 0x76: - case 0x77: + case 0x76 ... 0x77: dev->pci_conf[addr] = val; break; From 035b8deee2cf2b9ed6ad34d5ee0c220b6090a7fa Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 22:53:52 -0500 Subject: [PATCH 0042/1190] Random warning fixes --- src/cdrom/cdrom_image_backend.c | 4 +-- src/cdrom/cdrom_mitsumi.c | 47 +++++++++++++++------------------ src/qt/dummy_cdrom_ioctl.c | 7 ++++- src/unix/dummy_cdrom_ioctl.c | 7 ++++- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index 9d065a0cb..ad1756055 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -1195,7 +1195,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) for (int i = 0; i < 3; i++) { lead[i] = cdi->tracks_num; - (void *) cdi_insert_track(cdi, session, 0xa0 + i); + (void) cdi_insert_track(cdi, session, 0xa0 + i); } cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); @@ -1393,7 +1393,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) for (int i = 0; i < 3; i++) { lead[i] = cdi->tracks_num; - (void *) cdi_insert_track(cdi, session, 0xa0 + i); + (void) cdi_insert_track(cdi, session, 0xa0 + i); } cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); diff --git a/src/cdrom/cdrom_mitsumi.c b/src/cdrom/cdrom_mitsumi.c index 0cebfe7f6..c3c362b1b 100644 --- a/src/cdrom/cdrom_mitsumi.c +++ b/src/cdrom/cdrom_mitsumi.c @@ -156,9 +156,9 @@ mitsumi_cdrom_is_ready(const cdrom_t *dev) static void mitsumi_cdrom_reset(mcd_t *dev) { - cdrom_t cdrom; - - dev->stat = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | STAT_CHANGE) : 0; + cdrom_t *cdrom = calloc(1, sizeof(cdrom_t)); + + dev->stat = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | STAT_CHANGE) : 0; dev->cmdrd_count = 0; dev->cmdbuf_count = 0; dev->buf_count = 0; @@ -176,12 +176,12 @@ mitsumi_cdrom_reset(mcd_t *dev) static int mitsumi_cdrom_read_sector(mcd_t *dev, int first) { - cdrom_t cdrom; + cdrom_t *cdrom = calloc(1, sizeof(cdrom_t)); uint8_t status; - int ret; + int ret = 0; if (dev->drvmode == DRV_MODE_CDDA) { - status = cdrom_mitsumi_audio_play(&cdrom, dev->readmsf, dev->readcount); + status = cdrom_mitsumi_audio_play(cdrom, dev->readmsf, dev->readcount); if (status == 1) return status; else @@ -195,15 +195,15 @@ mitsumi_cdrom_read_sector(mcd_t *dev, int first) dev->data = 0; return 0; } - cdrom_stop(&cdrom); - ret = cdrom_readsector_raw(&cdrom, dev->buf, cdrom.seek_pos, 0, 2, 0x10, (int *) &dev->readcount, 0); + cdrom_stop(cdrom); + ret = cdrom_readsector_raw(cdrom, dev->buf, cdrom->seek_pos, 0, 2, 0x10, (int *) &dev->readcount, 0); if (ret <= 0) return 0; if (dev->mode & 0x40) { dev->buf[12] = CD_BCD((dev->readmsf >> 16) & 0xff); dev->buf[13] = CD_BCD((dev->readmsf >> 8) & 0xff); } - dev->readmsf = cdrom_lba_to_msf_accurate(cdrom.seek_pos + 1); + dev->readmsf = cdrom_lba_to_msf_accurate(cdrom->seek_pos + 1); dev->buf_count = dev->dmalen + 1; dev->buf_idx = 0; dev->data = 1; @@ -224,7 +224,7 @@ static uint8_t mitsumi_cdrom_in(uint16_t port, void *priv) { mcd_t *dev = (mcd_t *) priv; - uint8_t ret; + uint8_t ret = 0xff; pclog("Mitsumi CD-ROM IN=%03x\n", port); switch (port & 1) { @@ -259,14 +259,14 @@ mitsumi_cdrom_in(uint16_t port, void *priv) break; } - return 0xff; + return ret; } static void mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) { mcd_t *dev = (mcd_t *) priv; - cdrom_t cdrom; + cdrom_t *cdrom = calloc(1, sizeof(cdrom_t)); pclog("Mitsumi CD-ROM OUT=%03x, val=%02x\n", port, val); switch (port & 1) { @@ -348,19 +348,19 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) break; } if (!dev->cmdrd_count) - dev->stat = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0; + dev->stat = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0; return; } dev->cmd = val; dev->cmdbuf_idx = 0; dev->cmdrd_count = 0; dev->cmdbuf_count = 1; - dev->cmdbuf[0] = mitsumi_cdrom_is_ready(&cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0; + dev->cmdbuf[0] = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0; dev->data = 0; switch (val) { case CMD_GET_INFO: - if (mitsumi_cdrom_is_ready(&cdrom)) { - cdrom_get_track_buffer(&cdrom, &(dev->cmdbuf[1])); + if (mitsumi_cdrom_is_ready(cdrom)) { + cdrom_get_track_buffer(cdrom, &(dev->cmdbuf[1])); dev->cmdbuf_count = 10; dev->readcount = 0; } else { @@ -369,8 +369,8 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) } break; case CMD_GET_Q: - if (mitsumi_cdrom_is_ready(&cdrom)) { - cdrom_get_q(&cdrom, &(dev->cmdbuf[1]), &dev->cur_toc_track, dev->mode & MODE_GET_TOC); + if (mitsumi_cdrom_is_ready(cdrom)) { + cdrom_get_q(cdrom, &(dev->cmdbuf[1]), &dev->cur_toc_track, dev->mode & MODE_GET_TOC); dev->cmdbuf_count = 11; dev->readcount = 0; } else { @@ -386,7 +386,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) break; case CMD_STOPCDDA: case CMD_STOP: - cdrom_stop(&cdrom); + cdrom_stop(cdrom); dev->drvmode = DRV_MODE_STOP; dev->cur_toc_track = 0; break; @@ -395,7 +395,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) break; case CMD_READ1X: case CMD_READ2X: - if (mitsumi_cdrom_is_ready(&cdrom)) { + if (mitsumi_cdrom_is_ready(cdrom)) { dev->readcount = 0; dev->drvmode = (val == CMD_READ1X) ? DRV_MODE_CDDA : DRV_MODE_READ; dev->cmdrd_count = 6; @@ -411,7 +411,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) dev->cmdbuf_count = 3; break; case CMD_EJECT: - cdrom_stop(&cdrom); + cdrom_stop(cdrom); cdrom_eject(0); dev->readcount = 0; break; @@ -440,10 +440,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv) static void * mitsumi_cdrom_init(UNUSED(const device_t *info)) { - mcd_t *dev; - - dev = malloc(sizeof(mcd_t)); - memset(dev, 0x00, sizeof(mcd_t)); + mcd_t *dev = calloc(1, sizeof(mcd_t)); dev->irq = MCD_DEFAULT_IRQ; dev->dma = MCD_DEFAULT_DMA; diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index 4ed0333a7..fb0224bc6 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -134,9 +134,14 @@ plat_cdrom_get_last_block(void *local) } int -plat_cdrom_ext_medium_changed(void *local) +plat_cdrom_ext_medium_changed(UNUSED(void *local)) { +#if 0 dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + + plat_cdrom_read_toc(ioctl); +#endif + int ret = 0; dummy_cdrom_ioctl_log("plat_cdrom_ext_medium_changed(): %i\n", ret); diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 4ed0333a7..fb0224bc6 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -134,9 +134,14 @@ plat_cdrom_get_last_block(void *local) } int -plat_cdrom_ext_medium_changed(void *local) +plat_cdrom_ext_medium_changed(UNUSED(void *local)) { +#if 0 dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + + plat_cdrom_read_toc(ioctl); +#endif + int ret = 0; dummy_cdrom_ioctl_log("plat_cdrom_ext_medium_changed(): %i\n", ret); From 0931e82bd195fd4b8fe0bc774f7ba27ad043e7e1 Mon Sep 17 00:00:00 2001 From: GetDizzy Date: Sat, 11 Jan 2025 00:10:38 -0500 Subject: [PATCH 0043/1190] Add BIOS selection to Packard Bell PB450. --- src/machine/m_at_386dx_486.c | 51 +++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 3 ++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 1c35d7290..2a4b6f3c6 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -684,20 +684,64 @@ machine_at_403tg_d_mr_init(const machine_t *model) return ret; } +static const device_config_t pb450_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "pci10a", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "PCI 1.0A", .internal_name = "pci10a", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/OPTI802.bin", "" } }, + { .name = "PNP 1.1A", .internal_name = "pnp11a", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/PNP11A.bin", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t pb450_device = { + .name = "Packard Bell PB450 Devices", + .internal_name = "pb450_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pb450_config +}; + int machine_at_pb450_init(const machine_t *model) { - int ret; + int ret = 0; + const char* fn; - ret = bios_load_linear("roms/machines/pb450/OPTI802.bin", - 0x000e0000, 131072, 0); + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + device_context(model->device); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + if (bios_only || !ret) return ret; machine_at_common_init_ex(model, 2); device_add(&ide_vlb_2ch_device); + /* TODO: Detect if we're using the PNP and not the PCI ROM and don't add these? */ pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); @@ -713,6 +757,7 @@ machine_at_pb450_init(const machine_t *model) device_add(&fdc37c665_ide_device); device_add(&ide_opti611_vlb_sec_device); device_add(&intel_flash_bxt_device); + /* TODO: Detect if we're using the PNP and not the PCI ROM and don't add this? */ device_add(&phoenix_486_jumper_pci_device); return ret; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3fc3bcc8a..06aea8597 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -63,6 +63,7 @@ extern const device_t ibmxt_device; extern const device_t ibmxt86_device; extern const device_t ibmat_device; extern const device_t ibmxt286_device; +extern const device_t pb450_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -6888,7 +6889,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &pb450_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = &gd5428_vlb_onboard_device, From 3b092bcdb2ec8e2b9194c4c509a99ac9fed4b607 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 11 Jan 2025 01:31:57 -0500 Subject: [PATCH 0044/1190] Cleaning --- src/config.c | 100 ++++++++++++++---------------- src/game/joystick_standard.c | 21 +++---- src/game/joystick_sw_pad.c | 25 ++++---- src/qt/qt_settingsinput.cpp | 16 ++--- src/qt/sdl_joystick.c | 108 ++++++++++++++++----------------- src/qt/win_joystick_rawinput.c | 59 +++++++++--------- 6 files changed, 155 insertions(+), 174 deletions(-) diff --git a/src/config.c b/src/config.c index 2f1561f18..5119d45ff 100644 --- a/src/config.c +++ b/src/config.c @@ -475,8 +475,6 @@ load_input_devices(void) { ini_section_t cat = ini_find_section(config, "Input devices"); char temp[512]; - int c; - int d; char *p; p = ini_section_get_string(cat, "mouse_type", NULL); @@ -495,8 +493,8 @@ load_input_devices(void) /* Workaround for ini_section_get_int returning 0 on non-integer data */ joystick_type = joystick_get_from_internal_name("2axis_2button"); else { - c = ini_section_get_int(cat, "joystick_type", 8); - switch (c) { + int js = ini_section_get_int(cat, "joystick_type", 8); + switch (js) { case JS_TYPE_2AXIS_4BUTTON: joystick_type = joystick_get_from_internal_name("2axis_4button"); break; @@ -527,25 +525,25 @@ load_input_devices(void) } else joystick_type = JS_TYPE_NONE; - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { - sprintf(temp, "joystick_%i_nr", c); - joystick_state[c].plat_joystick_nr = ini_section_get_int(cat, temp, 0); + for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { + sprintf(temp, "joystick_%i_nr", js); + joystick_state[js].plat_joystick_nr = ini_section_get_int(cat, temp, 0); - if (joystick_state[c].plat_joystick_nr) { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) { - sprintf(temp, "joystick_%i_axis_%i", c, d); - joystick_state[c].axis_mapping[d] = ini_section_get_int(cat, temp, d); + if (joystick_state[js].plat_joystick_nr) { + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) { + sprintf(temp, "joystick_%i_axis_%i", js, axis_nr); + joystick_state[js].axis_mapping[axis_nr] = ini_section_get_int(cat, temp, axis_nr); } - for (d = 0; d < joystick_get_button_count(joystick_type); d++) { - sprintf(temp, "joystick_%i_button_%i", c, d); - joystick_state[c].button_mapping[d] = ini_section_get_int(cat, temp, d); + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) { + sprintf(temp, "joystick_%i_button_%i", js, button_nr); + joystick_state[js].button_mapping[button_nr] = ini_section_get_int(cat, temp, button_nr); } - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) { - sprintf(temp, "joystick_%i_pov_%i", c, d); + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { + sprintf(temp, "joystick_%i_pov_%i", js, pov_nr); p = ini_section_get_string(cat, temp, "0, 0"); - joystick_state[c].pov_mapping[d][0] = joystick_state[c].pov_mapping[d][1] = 0; - sscanf(p, "%i, %i", &joystick_state[c].pov_mapping[d][0], - &joystick_state[c].pov_mapping[d][1]); + joystick_state[js].pov_mapping[js][pov_nr] = joystick_state[js].pov_mapping[pov_nr][1] = 0; + sscanf(p, "%i, %i", &joystick_state[js].pov_mapping[pov_nr][0], + &joystick_state[js].pov_mapping[pov_nr][1]); } } } @@ -743,11 +741,9 @@ load_ports(void) ini_section_t cat = ini_find_section(config, "Ports (COM & LPT)"); char *p; char temp[512]; - int c; - memset(temp, 0, sizeof(temp)); - for (c = 0; c < SERIAL_MAX; c++) { + for (int c = 0; c < SERIAL_MAX; c++) { sprintf(temp, "serial%d_enabled", c + 1); com_ports[c].enabled = !!ini_section_get_int(cat, temp, (c >= 2) ? 0 : 1); @@ -758,7 +754,7 @@ load_ports(void) config_log("Serial Port %d: passthrough enabled.\n\n", c + 1); } - for (c = 0; c < PARALLEL_MAX; c++) { + for (int c = 0; c < PARALLEL_MAX; c++) { sprintf(temp, "lpt%d_enabled", c + 1); lpt_ports[c].enabled = !!ini_section_get_int(cat, temp, (c == 0) ? 1 : 0); @@ -776,11 +772,10 @@ load_storage_controllers(void) ini_section_t migration_cat; char *p; char temp[512]; - int c; int min = 0; int free_p = 0; - for (c = min; c < SCSI_CARD_MAX; c++) { + for (int c = min; c < SCSI_CARD_MAX; c++) { sprintf(temp, "scsicard_%d", c + 1); p = ini_section_get_string(cat, temp, NULL); @@ -932,7 +927,7 @@ load_storage_controllers(void) ini_section_delete_var(cat, "cassette_ui_writeprot"); } - for (c = 0; c < 2; c++) { + for (int c = 0; c < 2; c++) { sprintf(temp, "cartridge_%02i_fn", c + 1); p = ini_section_get_string(cat, temp, ""); @@ -2140,50 +2135,49 @@ save_input_devices(void) ini_section_t cat = ini_find_or_create_section(config, "Input devices"); char temp[512]; char tmp2[512]; - int c; - int d; ini_section_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); if (!joystick_type) { ini_section_delete_var(cat, "joystick_type"); - for (c = 0; c < 16; c++) { - sprintf(tmp2, "joystick_%i_nr", c); + for (int js = 0; js < MAX_PLAT_JOYSTICKS; js++) { + sprintf(tmp2, "joystick_%i_nr", js); ini_section_delete_var(cat, tmp2); - for (d = 0; d < 16; d++) { - sprintf(tmp2, "joystick_%i_axis_%i", c, d); + for (int axis_nr = 0; axis_nr < 16; axis_nr++) { + sprintf(tmp2, "joystick_%i_axis_%i", js, axis_nr); ini_section_delete_var(cat, tmp2); } - for (d = 0; d < 16; d++) { - sprintf(tmp2, "joystick_%i_button_%i", c, d); + for (int button_nr = 0; button_nr < 16; button_nr++) { + sprintf(tmp2, "joystick_%i_button_%i", js, button_nr); ini_section_delete_var(cat, tmp2); } - for (d = 0; d < 16; d++) { - sprintf(tmp2, "joystick_%i_pov_%i", c, d); + for (int pov_nr = 0; pov_nr < 16; pov_nr++) { + sprintf(tmp2, "joystick_%i_pov_%i", js, pov_nr); ini_section_delete_var(cat, tmp2); } } } else { ini_section_set_string(cat, "joystick_type", joystick_get_internal_name(joystick_type)); - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { - sprintf(tmp2, "joystick_%i_nr", c); - ini_section_set_int(cat, tmp2, joystick_state[c].plat_joystick_nr); + for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { + sprintf(tmp2, "joystick_%i_nr", js); + ini_section_set_int(cat, tmp2, joystick_state[js].plat_joystick_nr); - if (joystick_state[c].plat_joystick_nr) { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) { - sprintf(tmp2, "joystick_%i_axis_%i", c, d); - ini_section_set_int(cat, tmp2, joystick_state[c].axis_mapping[d]); + if (joystick_state[js].plat_joystick_nr) { + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) { + sprintf(tmp2, "joystick_%i_axis_%i", js, axis_nr); + ini_section_set_int(cat, tmp2, joystick_state[js].axis_mapping[axis_nr]); } - for (d = 0; d < joystick_get_button_count(joystick_type); d++) { - sprintf(tmp2, "joystick_%i_button_%i", c, d); - ini_section_set_int(cat, tmp2, joystick_state[c].button_mapping[d]); + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) { + sprintf(tmp2, "joystick_%i_button_%i", js, button_nr); + ini_section_set_int(cat, tmp2, joystick_state[js].button_mapping[button_nr]); } - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) { - sprintf(tmp2, "joystick_%i_pov_%i", c, d); - sprintf(temp, "%i, %i", joystick_state[c].pov_mapping[d][0], joystick_state[c].pov_mapping[d][1]); + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { + sprintf(tmp2, "joystick_%i_pov_%i", js, pov_nr); + sprintf(temp, "%i, %i", joystick_state[js].pov_mapping[pov_nr][0], + joystick_state[js].pov_mapping[pov_nr][1]); ini_section_set_string(cat, tmp2, temp); } } @@ -2341,10 +2335,8 @@ save_ports(void) { ini_section_t cat = ini_find_or_create_section(config, "Ports (COM & LPT)"); char temp[512]; - int c; - int d; - for (c = 0; c < SERIAL_MAX; c++) { + for (int c = 0; c < SERIAL_MAX; c++) { sprintf(temp, "serial%d_enabled", c + 1); if (((c < 2) && com_ports[c].enabled) || ((c >= 2) && !com_ports[c].enabled)) ini_section_delete_var(cat, temp); @@ -2358,9 +2350,9 @@ save_ports(void) ini_section_delete_var(cat, temp); } - for (c = 0; c < PARALLEL_MAX; c++) { + for (int c = 0; c < PARALLEL_MAX; c++) { sprintf(temp, "lpt%d_enabled", c + 1); - d = (c == 0) ? 1 : 0; + int d = (c == 0) ? 1 : 0; if (lpt_ports[c].enabled == d) ini_section_delete_var(cat, temp); else diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index 1d1568738..201574126 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -62,17 +62,13 @@ joystick_standard_read(UNUSED(void *priv)) { uint8_t ret = 0xf0; - if (JOYSTICK_PRESENT(0)) { - if (joystick_state[0].button[0]) - ret &= ~0x10; - if (joystick_state[0].button[1]) - ret &= ~0x20; - } - if (JOYSTICK_PRESENT(1)) { - if (joystick_state[1].button[0]) - ret &= ~0x40; - if (joystick_state[1].button[1]) - ret &= ~0x80; + for (int js = 0; js < 2; js++) { + if (JOYSTICK_PRESENT(js)) { + if (joystick_state[js].button[0]) + ret &= ~0x10; + if (joystick_state[js].button[1]) + ret &= ~0x20; + } } return ret; @@ -140,9 +136,7 @@ joystick_standard_read_axis_4button(UNUSED(void *priv), int axis) case 1: return joystick_state[0].axis[1]; case 2: - return 0; case 3: - return 0; default: return 0; } @@ -162,7 +156,6 @@ joystick_standard_read_axis_3axis(UNUSED(void *priv), int axis) case 2: return joystick_state[0].axis[2]; case 3: - return 0; default: return 0; } diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index cab008d0a..711a5fa1e 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -119,8 +119,7 @@ sw_parity(uint16_t data) static void * sw_init(void) { - sw_data *sw = (sw_data *) malloc(sizeof(sw_data)); - memset(sw, 0, sizeof(sw_data)); + sw_data *sw = (sw_data *) calloc(1, sizeof(sw_data)); timer_add(&sw->poll_timer, sw_timer_over, sw, 0); timer_add(&sw->trigger_timer, sw_trigger_timer_over, sw, 0); @@ -191,24 +190,24 @@ sw_write(void *priv) sw->poll_data = 1; } - for (uint8_t c = 0; c < 4; c++) { + for (uint8_t js = 0; js < MAX_JOYSTICKS; js++) { uint16_t data = 0x3fff; - if (!JOYSTICK_PRESENT(c)) + if (!JOYSTICK_PRESENT(js)) break; - if (joystick_state[c].axis[1] < -16383) + if (joystick_state[js].axis[1] < -16383) data &= ~1; - if (joystick_state[c].axis[1] > 16383) + if (joystick_state[js].axis[1] > 16383) data &= ~2; - if (joystick_state[c].axis[0] > 16383) + if (joystick_state[js].axis[0] > 16383) data &= ~4; - if (joystick_state[c].axis[0] < -16383) + if (joystick_state[js].axis[0] < -16383) data &= ~8; - for (uint8_t b = 0; b < 10; b++) { - if (joystick_state[c].button[b]) - data &= ~(1 << (b + 4)); + for (uint8_t button_nr = 0; button_nr < 10; button_nr++) { + if (joystick_state[js].button[button_nr]) + data &= ~(1 << (button_nr + 4)); } if (sw_parity(data)) @@ -216,10 +215,10 @@ sw_write(void *priv) if (sw->poll_mode) { sw->poll_left += 5; - sw->poll_data |= (data << (c * 15 + 3)); + sw->poll_data |= (data << (js * 15 + 3)); } else { sw->poll_left += 15; - sw->poll_data |= (data << (c * 15 + 1)); + sw->poll_data |= (data << (js * 15 + 1)); } } } diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 05e44c2c0..d7b69442c 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -178,15 +178,17 @@ updateJoystickConfig(int type, int joystick_nr, QWidget *parent) joystick_state[joystick_nr].plat_joystick_nr = jc.selectedDevice(); if (joystick_state[joystick_nr].plat_joystick_nr) { - for (int c = 0; c < joystick_get_axis_count(type); c++) { - joystick_state[joystick_nr].axis_mapping[c] = get_axis(jc, c, joystick_nr); + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(type); axis_nr++) { + joystick_state[joystick_nr].axis_mapping[axis_nr] = get_axis(jc, axis_nr, joystick_nr); } - for (int c = 0; c < joystick_get_button_count(type); c++) { - joystick_state[joystick_nr].button_mapping[c] = jc.selectedButton(c); + + for (int button_nr = 0; button_nr < joystick_get_button_count(type); button_nr++) { + joystick_state[joystick_nr].button_mapping[button_nr] = jc.selectedButton(button_nr); } - for (int c = 0; c < joystick_get_pov_count(type) * 2; c += 2) { - joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(jc, c, joystick_nr); - joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(jc, c + 1, joystick_nr); + + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(type) * 2; pov_nr += 2) { + joystick_state[joystick_nr].pov_mapping[pov_nr][0] = get_pov(jc, pov_nr, joystick_nr); + joystick_state[joystick_nr].pov_mapping[pov_nr][1] = get_pov(jc, pov_nr + 1, joystick_nr); } } } diff --git a/src/qt/sdl_joystick.c b/src/qt/sdl_joystick.c index d56612872..221e12078 100644 --- a/src/qt/sdl_joystick.c +++ b/src/qt/sdl_joystick.c @@ -54,28 +54,26 @@ joystick_init(void) joysticks_present = SDL_NumJoysticks(); memset(sdl_joy, 0, sizeof(sdl_joy)); - for (int c = 0; c < joysticks_present; c++) { - sdl_joy[c] = SDL_JoystickOpen(c); + for (int js = 0; js < joysticks_present; js++) { + sdl_joy[js] = SDL_JoystickOpen(js); - if (sdl_joy[c]) { - int d; + if (sdl_joy[js]) { + strncpy(plat_joystick_state[js].name, SDL_JoystickNameForIndex(js), 64); + plat_joystick_state[js].nr_axes = MIN(SDL_JoystickNumAxes(sdl_joy[js]), MAX_JOY_AXES); + plat_joystick_state[js].nr_buttons = MIN(SDL_JoystickNumButtons(sdl_joy[js]), MAX_JOY_BUTTONS); + plat_joystick_state[js].nr_povs = MIN(SDL_JoystickNumHats(sdl_joy[js]), MAX_JOY_POVS); - strncpy(plat_joystick_state[c].name, SDL_JoystickNameForIndex(c), 64); - plat_joystick_state[c].nr_axes = MIN(SDL_JoystickNumAxes(sdl_joy[c]), MAX_JOY_AXES); - plat_joystick_state[c].nr_buttons = MIN(SDL_JoystickNumButtons(sdl_joy[c]), MAX_JOY_BUTTONS); - plat_joystick_state[c].nr_povs = MIN(SDL_JoystickNumHats(sdl_joy[c]), MAX_JOY_POVS); - - for (d = 0; d < plat_joystick_state[c].nr_axes; d++) { - snprintf(plat_joystick_state[c].axis[d].name, sizeof(plat_joystick_state[c].axis[d].name), "Axis %i", d); - plat_joystick_state[c].axis[d].id = d; + for (int axis_nr = 0; axis_nr < plat_joystick_state[js].nr_axes; axis_nr++) { + snprintf(plat_joystick_state[js].axis[axis_nr].name, sizeof(plat_joystick_state[js].axis[axis_nr].name), "Axis %i", axis_nr); + plat_joystick_state[js].axis[axis_nr].id = axis_nr; } - for (d = 0; d < plat_joystick_state[c].nr_buttons; d++) { - snprintf(plat_joystick_state[c].button[d].name, sizeof(plat_joystick_state[c].button[d].name), "Button %i", d); - plat_joystick_state[c].button[d].id = d; + for (int buttons_nr = 0; buttons_nr < plat_joystick_state[js].nr_buttons; buttons_nr++) { + snprintf(plat_joystick_state[js].button[buttons_nr].name, sizeof(plat_joystick_state[js].button[buttons_nr].name), "Button %i", buttons_nr); + plat_joystick_state[js].button[buttons_nr].id = buttons_nr; } - for (d = 0; d < plat_joystick_state[c].nr_povs; d++) { - snprintf(plat_joystick_state[c].pov[d].name, sizeof(plat_joystick_state[c].pov[d].name), "POV %i", d); - plat_joystick_state[c].pov[d].id = d; + for (int pov_nr = 0; pov_nr < plat_joystick_state[js].nr_povs; pov_nr++) { + snprintf(plat_joystick_state[js].pov[pov_nr].name, sizeof(plat_joystick_state[js].pov[pov_nr].name), "POV %i", pov_nr); + plat_joystick_state[js].pov[pov_nr].id = pov_nr; } } } @@ -84,11 +82,9 @@ joystick_init(void) void joystick_close(void) { - int c; - - for (c = 0; c < joysticks_present; c++) { - if (sdl_joy[c]) - SDL_JoystickClose(sdl_joy[c]); + for (int js = 0; js < joysticks_present; js++) { + if (sdl_joy[js]) + SDL_JoystickClose(sdl_joy[js]); } } @@ -132,57 +128,55 @@ joystick_get_axis(int joystick_nr, int mapping) void joystick_process(void) { - int c; - int d; - if (!joystick_type) return; SDL_JoystickUpdate(); - for (c = 0; c < joysticks_present; c++) { - int b; + for (int js = 0; js < joysticks_present; js++) { + for (int axis_nr = 0; axis_nr < plat_joystick_state[js].nr_axes; axis_nr++) + plat_joystick_state[js].a[axis_nr] = SDL_JoystickGetAxis(sdl_joy[js], axis_nr); - for (b = 0; b < plat_joystick_state[c].nr_axes; b++) - plat_joystick_state[c].a[b] = SDL_JoystickGetAxis(sdl_joy[c], b); + for (int button_nr = 0; button_nr < plat_joystick_state[js].nr_buttons; button_nr++) + plat_joystick_state[js].b[button_nr] = SDL_JoystickGetButton(sdl_joy[js], button_nr); - for (b = 0; b < plat_joystick_state[c].nr_buttons; b++) - plat_joystick_state[c].b[b] = SDL_JoystickGetButton(sdl_joy[c], b); + for (int pov_nr = 0; pov_nr < plat_joystick_state[js].nr_povs; pov_nr++) + plat_joystick_state[js].p[pov_nr] = SDL_JoystickGetHat(sdl_joy[js], pov_nr); - for (b = 0; b < plat_joystick_state[c].nr_povs; b++) - plat_joystick_state[c].p[b] = SDL_JoystickGetHat(sdl_joy[c], b); - // pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); +#if 0 + pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", js, joystick_state[js].x, joystick_state[js].y, joystick_state[js].b[0], joystick_state[js].b[1], joysticks_present); +#endif } - for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { - if (joystick_state[c].plat_joystick_nr) { - int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { + if (joystick_state[js].plat_joystick_nr) { + int joystick_nr = joystick_state[js].plat_joystick_nr - 1; - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) { - int x, y; - double angle, magnitude; + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) + joystick_state[js].axis[axis_nr] = joystick_get_axis(joystick_nr, joystick_state[js].axis_mapping[axis_nr]); - x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); - y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) + joystick_state[js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[js].button_mapping[button_nr]]; - angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); - magnitude = sqrt((double) x * (double) x + (double) y * (double) y); + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { + int x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); + int y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); + double angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); + double magnitude = sqrt((double) x * (double) x + (double) y * (double) y); if (magnitude < 16384) - joystick_state[c].pov[d] = -1; + joystick_state[js].pov[pov_nr] = -1; else - joystick_state[c].pov[d] = ((int) angle + 90 + 360) % 360; + joystick_state[js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; } } else { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = 0; - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = 0; - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - joystick_state[c].pov[d] = -1; + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) + joystick_state[js].axis[axis_nr] = 0; + + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) + joystick_state[js].button[button_nr] = 0; + + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) + joystick_state[js].pov[pov_nr] = -1; } } } diff --git a/src/qt/win_joystick_rawinput.c b/src/qt/win_joystick_rawinput.c index bb05c3f5c..811425a98 100644 --- a/src/qt/win_joystick_rawinput.c +++ b/src/qt/win_joystick_rawinput.c @@ -412,7 +412,7 @@ win_joystick_handle(PRAWINPUT raw) /* Read buttons */ USAGE usage_list[128] = { 0 }; ULONG usage_length = plat_joystick_state[j].nr_buttons; - memset(plat_joystick_state[j].b, 0, 32 * sizeof(int)); + memset(plat_joystick_state[j].b, 0, MAX_JOY_BUTTONS * sizeof(int)); r = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usage_list, &usage_length, raw_joystick_state[j].data, (PCHAR) raw->data.hid.bRawData, raw->data.hid.dwSizeHid); @@ -425,8 +425,8 @@ win_joystick_handle(PRAWINPUT raw) } /* Read axes */ - for (int a = 0; a < plat_joystick_state[j].nr_axes; a++) { - const struct raw_axis_t *axis = &raw_joystick_state[j].axis[a]; + for (int axis_nr = 0; axis_nr < plat_joystick_state[j].nr_axes; axis_nr++) { + const struct raw_axis_t *axis = &raw_joystick_state[j].axis[axis_nr]; ULONG uvalue = 0; LONG value = 0; LONG center = (axis->max - axis->min + 1) / 2; @@ -453,15 +453,15 @@ win_joystick_handle(PRAWINPUT raw) value = value * 32768 / center; } - plat_joystick_state[j].a[a] = value; + plat_joystick_state[j].a[axis_nr] = value; #if 0 - joystick_log("%s %-06d ", plat_joystick_state[j].axis[a].name, plat_joystick_state[j].a[a]); + joystick_log("%s %-06d ", plat_joystick_state[j].axis[axis_nr].name, plat_joystick_state[j].a[axis_nr]); #endif } /* read povs */ - for (int p = 0; p < plat_joystick_state[j].nr_povs; p++) { - const struct raw_pov_t *pov = &raw_joystick_state[j].pov[p]; + for (int pov_nr = 0; pov_nr < plat_joystick_state[j].nr_povs; pov_nr++) { + const struct raw_pov_t *pov = &raw_joystick_state[j].pov[pov_nr]; ULONG uvalue = 0; LONG value = -1; @@ -474,10 +474,10 @@ win_joystick_handle(PRAWINPUT raw) value %= 36000; } - plat_joystick_state[j].p[p] = value; + plat_joystick_state[j].p[pov_nr] = value; #if 0 - joystick_log("%s %-3d ", plat_joystick_state[j].pov[p].name, plat_joystick_state[j].p[p]); + joystick_log("%s %-3d ", plat_joystick_state[j].pov[pov_nr].name, plat_joystick_state[j].p[pov_nr]); #endif } #if 0 @@ -508,44 +508,45 @@ joystick_get_axis(int joystick_nr, int mapping) void joystick_process(void) { - int d; - if (joystick_type == JS_TYPE_NONE) return; - for (int c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { - if (joystick_state[c].plat_joystick_nr) { - int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { + if (joystick_state[js].plat_joystick_nr) { + int joystick_nr = joystick_state[js].plat_joystick_nr - 1; - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) + joystick_state[js].axis[axis_nr] = joystick_get_axis(joystick_nr, joystick_state[js].axis_mapping[axis_nr]); - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) { + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) + joystick_state[js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[js].button_mapping[button_nr]]; + + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { int x; int y; double angle; double magnitude; - x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); - y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); + y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); magnitude = sqrt((double) x * (double) x + (double) y * (double) y); if (magnitude < 16384) - joystick_state[c].pov[d] = -1; + joystick_state[js].pov[pov_nr] = -1; else - joystick_state[c].pov[d] = ((int) angle + 90 + 360) % 360; + joystick_state[js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; } } else { - for (d = 0; d < joystick_get_axis_count(joystick_type); d++) - joystick_state[c].axis[d] = 0; - for (d = 0; d < joystick_get_button_count(joystick_type); d++) - joystick_state[c].button[d] = 0; - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - joystick_state[c].pov[d] = -1; + for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) + joystick_state[js].axis[axis_nr] = 0; + + for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) + joystick_state[js].button[button_nr] = 0; + + for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) + joystick_state[js].pov[pov_nr] = -1; } } } From 6ec9c33940bbe864fb58f670fb1925d28cc32241 Mon Sep 17 00:00:00 2001 From: GetDizzy Date: Sat, 11 Jan 2025 02:19:32 -0500 Subject: [PATCH 0045/1190] Formatting fixes. --- src/machine/m_at_386dx_486.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 2a4b6f3c6..43ba9a6d9 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -707,10 +707,10 @@ static const device_config_t pb450_config[] = { }; const device_t pb450_device = { - .name = "Packard Bell PB450 Devices", + .name = "Packard Bell PB450 Devices", .internal_name = "pb450_device", - .flags = 0, - .local = 0, + .flags = 0, + .local = 0, .init = NULL, .close = NULL, .reset = NULL, From 8cb220d84b249851202489ee3f69e7c12492d5ba Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 11 Jan 2025 03:39:15 -0500 Subject: [PATCH 0046/1190] Corrections --- src/config.c | 8 ++++---- src/qt/sdl_joystick.c | 13 +++++++++---- src/qt/win_joystick_rawinput.c | 14 ++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/config.c b/src/config.c index 5119d45ff..24efcf264 100644 --- a/src/config.c +++ b/src/config.c @@ -541,7 +541,7 @@ load_input_devices(void) for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { sprintf(temp, "joystick_%i_pov_%i", js, pov_nr); p = ini_section_get_string(cat, temp, "0, 0"); - joystick_state[js].pov_mapping[js][pov_nr] = joystick_state[js].pov_mapping[pov_nr][1] = 0; + joystick_state[js].pov_mapping[pov_nr][0] = joystick_state[js].pov_mapping[pov_nr][1] = 0; sscanf(p, "%i, %i", &joystick_state[js].pov_mapping[pov_nr][0], &joystick_state[js].pov_mapping[pov_nr][1]); } @@ -2145,15 +2145,15 @@ save_input_devices(void) sprintf(tmp2, "joystick_%i_nr", js); ini_section_delete_var(cat, tmp2); - for (int axis_nr = 0; axis_nr < 16; axis_nr++) { + for (int axis_nr = 0; axis_nr < MAX_JOY_AXES; axis_nr++) { sprintf(tmp2, "joystick_%i_axis_%i", js, axis_nr); ini_section_delete_var(cat, tmp2); } - for (int button_nr = 0; button_nr < 16; button_nr++) { + for (int button_nr = 0; button_nr < MAX_JOY_BUTTONS; button_nr++) { sprintf(tmp2, "joystick_%i_button_%i", js, button_nr); ini_section_delete_var(cat, tmp2); } - for (int pov_nr = 0; pov_nr < 16; pov_nr++) { + for (int pov_nr = 0; pov_nr < MAX_JOY_POVS; pov_nr++) { sprintf(tmp2, "joystick_%i_pov_%i", js, pov_nr); ini_section_delete_var(cat, tmp2); } diff --git a/src/qt/sdl_joystick.c b/src/qt/sdl_joystick.c index 221e12078..03159ba7f 100644 --- a/src/qt/sdl_joystick.c +++ b/src/qt/sdl_joystick.c @@ -67,9 +67,9 @@ joystick_init(void) snprintf(plat_joystick_state[js].axis[axis_nr].name, sizeof(plat_joystick_state[js].axis[axis_nr].name), "Axis %i", axis_nr); plat_joystick_state[js].axis[axis_nr].id = axis_nr; } - for (int buttons_nr = 0; buttons_nr < plat_joystick_state[js].nr_buttons; buttons_nr++) { - snprintf(plat_joystick_state[js].button[buttons_nr].name, sizeof(plat_joystick_state[js].button[buttons_nr].name), "Button %i", buttons_nr); - plat_joystick_state[js].button[buttons_nr].id = buttons_nr; + for (int button_nr = 0; button_nr < plat_joystick_state[js].nr_buttons; button_nr++) { + snprintf(plat_joystick_state[js].button[button_nr].name, sizeof(plat_joystick_state[js].button[button_nr].name), "Button %i", button_nr); + plat_joystick_state[js].button[button_nr].id = button_nr; } for (int pov_nr = 0; pov_nr < plat_joystick_state[js].nr_povs; pov_nr++) { snprintf(plat_joystick_state[js].pov[pov_nr].name, sizeof(plat_joystick_state[js].pov[pov_nr].name), "POV %i", pov_nr); @@ -143,7 +143,12 @@ joystick_process(void) plat_joystick_state[js].p[pov_nr] = SDL_JoystickGetHat(sdl_joy[js], pov_nr); #if 0 - pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", js, joystick_state[js].x, joystick_state[js].y, joystick_state[js].b[0], joystick_state[js].b[1], joysticks_present); + pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", js, + joystick_state[js].x, + joystick_state[js].y, + joystick_state[js].b[0], + joystick_state[js].b[1], + joysticks_present); #endif } diff --git a/src/qt/win_joystick_rawinput.c b/src/qt/win_joystick_rawinput.c index 811425a98..c293dcaca 100644 --- a/src/qt/win_joystick_rawinput.c +++ b/src/qt/win_joystick_rawinput.c @@ -522,16 +522,10 @@ joystick_process(void) joystick_state[js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[js].button_mapping[button_nr]]; for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { - int x; - int y; - double angle; - double magnitude; - - x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); - y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); - - angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); - magnitude = sqrt((double) x * (double) x + (double) y * (double) y); + int x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); + int y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); + double angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); + double magnitude = sqrt((double) x * (double) x + (double) y * (double) y); if (magnitude < 16384) joystick_state[js].pov[pov_nr] = -1; From f9ac37decd8cafc870a6927dd0a68ce1dd005872 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 11 Jan 2025 04:04:39 -0500 Subject: [PATCH 0047/1190] Missed fix --- src/game/joystick_sw_pad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index 711a5fa1e..238e84d11 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -190,7 +190,7 @@ sw_write(void *priv) sw->poll_data = 1; } - for (uint8_t js = 0; js < MAX_JOYSTICKS; js++) { + for (uint8_t js = 0; js < 4; js++) { uint16_t data = 0x3fff; if (!JOYSTICK_PRESENT(js)) From 7d3d15853de68f8fbcb37844498cae3839b608c4 Mon Sep 17 00:00:00 2001 From: GetDizzy Date: Sat, 11 Jan 2025 04:11:54 -0500 Subject: [PATCH 0048/1190] Remove outdated TODOs. --- src/machine/m_at_386dx_486.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 43ba9a6d9..d3c7a21d2 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -741,7 +741,6 @@ machine_at_pb450_init(const machine_t *model) machine_at_common_init_ex(model, 2); device_add(&ide_vlb_2ch_device); - /* TODO: Detect if we're using the PNP and not the PCI ROM and don't add these? */ pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); @@ -757,7 +756,6 @@ machine_at_pb450_init(const machine_t *model) device_add(&fdc37c665_ide_device); device_add(&ide_opti611_vlb_sec_device); device_add(&intel_flash_bxt_device); - /* TODO: Detect if we're using the PNP and not the PCI ROM and don't add this? */ device_add(&phoenix_486_jumper_pci_device); return ret; From 49f5c358d85feb6850a5d656b23afcef809ceae8 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 11 Jan 2025 04:37:18 -0500 Subject: [PATCH 0049/1190] Revert two fixes as batty has that covered --- src/cdrom/cdrom_image_backend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index ad1756055..9d065a0cb 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -1195,7 +1195,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) for (int i = 0; i < 3; i++) { lead[i] = cdi->tracks_num; - (void) cdi_insert_track(cdi, session, 0xa0 + i); + (void *) cdi_insert_track(cdi, session, 0xa0 + i); } cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); @@ -1393,7 +1393,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) for (int i = 0; i < 3; i++) { lead[i] = cdi->tracks_num; - (void) cdi_insert_track(cdi, session, 0xa0 + i); + (void *) cdi_insert_track(cdi, session, 0xa0 + i); } cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); From af12421a5baea3ac8d6448ee21bb8283279e94f7 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:45:17 +0100 Subject: [PATCH 0050/1190] Update machine.h --- src/include/86box/machine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ad8b47638..0cd3564ee 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -807,6 +807,7 @@ extern int machine_at_p2bls_init(const machine_t *); extern int machine_at_lgibmx7g_init(const machine_t *); extern int machine_at_p3bf_init(const machine_t *); extern int machine_at_bf6_init(const machine_t *); +extern int machine_at_bx6_init(const machine_t *); extern int machine_at_ax6bc_init(const machine_t *); extern int machine_at_atc6310bxii_init(const machine_t *); extern int machine_at_686bx_init(const machine_t *); From c64c5bcbcdf509b55e54c5ac0c06b653c681dccb Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:04:17 +0100 Subject: [PATCH 0051/1190] Update m_at_slot1.c --- src/machine/m_at_slot1.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 415998364..a3ff921e3 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -359,6 +359,37 @@ machine_at_bf6_init(const machine_t *model) return ret; } +int +machine_at_bx6_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/bx6/BX6_EG.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83977f_device); + device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + + return ret; +} + int machine_at_ax6bc_init(const machine_t *model) { From e00d7b8e1d1ad1044f0dbbc2803acf2c7ffec646 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:18:49 +0100 Subject: [PATCH 0052/1190] Update machine_table.c --- src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 06aea8597..4947b8898 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14632,6 +14632,47 @@ const machine_t machines[] = { }, /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ + +{ + .name = "[i440LX] ABIT BX6", + .internal_name = "bx6", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_bx6_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 133333333, + .min_voltage = 1500, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + { .name = "[i440BX] ABIT BF6", .internal_name = "bf6", From fabe71150cb600ef7c290f93f5416c4b6c64e7d9 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 11 Jan 2025 18:13:56 -0500 Subject: [PATCH 0053/1190] Various improvements & Cleanups Some ported from ANightly's work --- src/device/CMakeLists.txt | 2 +- src/device/serial_passthrough.c | 8 ++--- src/device/unittester.c | 6 ++-- src/disk/hdc_xta.c | 8 ++--- src/disk/hdc_xtide.c | 4 +-- src/floppy/fdd_pcjs.c | 4 +++ src/include/86box/86box.h | 5 +++ src/machine/m_at_286_386sx.c | 4 --- src/machine/m_ps1.c | 2 +- src/network/CMakeLists.txt | 5 ++- src/network/net_rtl8139.c | 7 ++-- src/network/network.c | 2 ++ src/qt/qt_harddiskdialog.cpp | 12 +++++-- src/qt/qt_vulkanrenderer.cpp | 9 ++--- src/qt/qt_vulkanrenderer.hpp | 6 +++- src/qt/qt_vulkanwindowrenderer.cpp | 38 ++++++++++++++++++-- src/qt/qt_vulkanwindowrenderer.hpp | 2 +- src/qt/qt_winrawinputfilter.cpp | 40 ++++++++++++--------- src/qt/win_serial_passthrough.c | 2 +- src/scsi/scsi_aha154x.c | 2 +- src/scsi/scsi_ncr53c400.c | 2 +- src/sound/midi_fluidsynth.c | 33 ++++++----------- src/sound/resid-fp/siddefs-fp.h | 4 +++ src/sound/snd_opl2board.c | 4 +-- src/sound/snd_pas16.c | 1 + src/video/vid_et3000.c | 23 ++++++------ src/video/vid_et4000.c | 4 +-- src/video/vid_ht216.c | 57 +++++++++++------------------- src/video/vid_mga.c | 22 ++++-------- 29 files changed, 178 insertions(+), 140 deletions(-) diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index ae3fbf3f2..c9da627ef 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -57,7 +57,7 @@ add_library(dev OBJECT mouse_microtouch_touchscreen.c ) -if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") +if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT MSVC) target_link_libraries(86Box atomic) endif() diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index eec9fa62a..ed5abe618 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -282,8 +282,8 @@ static const device_config_t serial_passthrough_config[] = { .type = CONFIG_SERPORT, .default_string = "", .file_filter = NULL, - .spinner = {}, - .selection = {} + .spinner = { 0 }, + .selection = { { 0 } } }, #ifdef _WIN32 { @@ -292,8 +292,8 @@ static const device_config_t serial_passthrough_config[] = { .type = CONFIG_STRING, .default_string = "\\\\.\\pipe\\86Box\\test", .file_filter = NULL, - .spinner = {}, - .selection = {} + .spinner = { 0 }, + .selection = { { 0 } } }, #endif { diff --git a/src/device/unittester.c b/src/device/unittester.c index e52f3b56f..614438fcb 100644 --- a/src/device/unittester.c +++ b/src/device/unittester.c @@ -104,8 +104,8 @@ struct unittester_state { /* 0x04: Exit */ uint8_t exit_code; }; -static struct unittester_state unittester; -static const struct unittester_state unittester_defaults = { +static struct unittester_state unittester; +static struct unittester_state unittester_defaults = { .trigger_port = 0x0080, .iobase_port = 0xFFFF, .fsm1 = UT_FSM1_WAIT_8, @@ -589,7 +589,7 @@ unittester_trigger_write(UNUSED(uint16_t port), uint8_t val, UNUSED(void *priv)) static void * unittester_init(UNUSED(const device_t *info)) { - unittester = (struct unittester_state) unittester_defaults; + unittester = unittester_defaults; unittester_exit_enabled = !!device_get_config_int("exit_enabled"); diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index a4ef45c43..a65ab5c69 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1114,7 +1114,7 @@ static const device_config_t wdxt150_config[] = { .default_string = "", .default_int = 0x0320, .file_filter = "", - .spinner = { 0 }, /*W2*/ + .spinner = { 0 }, .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, @@ -1128,7 +1128,7 @@ static const device_config_t wdxt150_config[] = { .default_string = "", .default_int = 5, .file_filter = "", - .spinner = { 0 }, /*W3*/ + .spinner = { 0 }, .selection = { { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 4", .value = 4 }, @@ -1142,7 +1142,7 @@ static const device_config_t wdxt150_config[] = { .default_string = "", .default_int = 0xc8000, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .selection = { { .description = "C800H", .value = 0xc8000 }, { .description = "CA00H", .value = 0xca000 }, @@ -1156,7 +1156,7 @@ static const device_config_t wdxt150_config[] = { .default_string = "rev_1", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Revision 1.0", .internal_name = "rev_1", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 8192, .files = { WD_REV_1_BIOS_FILE, "" } }, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 9899e2a0f..b324b4d32 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -238,7 +238,7 @@ static const device_config_t xtide_config[] = { .default_string = "xt", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Regular XT", .internal_name = "xt", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_XT, "" } }, @@ -260,7 +260,7 @@ static const device_config_t xtide_at_config[] = { .default_string = "at", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Regular AT", .internal_name = "at", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_AT, "" } }, diff --git a/src/floppy/fdd_pcjs.c b/src/floppy/fdd_pcjs.c index b7b3cc69d..76f8ca7dc 100644 --- a/src/floppy/fdd_pcjs.c +++ b/src/floppy/fdd_pcjs.c @@ -20,7 +20,11 @@ #include #include #include +#ifndef _MSC_VER #include +#else +#include +#endif #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index ffa670b7e..503518a2b 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -191,8 +191,13 @@ extern void pclog_ex(const char *fmt, va_list); extern void fatal_ex(const char *fmt, va_list); #endif extern void pclog_toggle_suppr(void); +#ifdef _MSC_VER +extern void pclog(const char *fmt, ...); +extern void fatal(const char *fmt, ...); +#else extern void pclog(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void fatal(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +#endif extern void set_screen_size(int x, int y); extern void set_screen_size_monitor(int x, int y, int monitor_index); extern void reset_screen_size(void); diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index ead31c21c..c3dc5c772 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -222,10 +222,6 @@ machine_at_ataripc4_init(const machine_t *model) ret = bios_load_interleaved("roms/machines/ataripc4/AMI_PC4X_1.7_EVEN.BIN", "roms/machines/ataripc4/AMI_PC4X_1.7_ODD.BIN", -#if 0 - ret = bios_load_interleaved("roms/machines/ataripc4/ami_pc4x_1.7_even.bin", - "roms/machines/ataripc4/ami_pc4x_1.7_odd.bin", -#endif 0x000f0000, 65536, 0); if (bios_only || !ret) diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 42bc49de2..3c9f1819f 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -252,7 +252,7 @@ static const device_config_t ps1_2011_config[] = { .default_string = "english_us", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "English (US)", .internal_name = "english_us", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 262144, .files = { "roms/machines/ibmps1es/FC0000_US.BIN", "" } }, diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 0d42cbd8d..71f41f059 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -41,7 +41,10 @@ pkg_check_modules(SLIRP REQUIRED IMPORTED_TARGET slirp) target_link_libraries(86Box PkgConfig::SLIRP) if(WIN32) - target_link_libraries(PkgConfig::SLIRP INTERFACE wsock32 ws2_32 iphlpapi iconv) + target_link_libraries(PkgConfig::SLIRP INTERFACE wsock32 ws2_32 iphlpapi) + if (NOT MSVC) + target_link_libraries(PkgConfig::SLIRP INTERFACE iconv) + endif() if(STATIC_BUILD) add_compile_definitions(LIBSLIRP_STATIC) endif() diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index f04f9b7a3..0dac29a8c 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef _MVC_VER +#include +#endif #include #define HAVE_STDARG_H #include <86box/86box.h> @@ -531,14 +534,14 @@ rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) if (size > wrapped) { dma_bm_write(s->RxBuf + s->RxBufAddr, - buf, size - wrapped, 1); + (uint8_t *) buf, size - wrapped, 1); } /* reset buffer pointer */ s->RxBufAddr = 0; dma_bm_write(s->RxBuf + s->RxBufAddr, - buf + (size - wrapped), wrapped, 1); + (uint8_t *) buf + (size - wrapped), wrapped, 1); s->RxBufAddr = wrapped; diff --git a/src/network/network.c b/src/network/network.c index e60f50eb1..f4b03ee79 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -54,7 +54,9 @@ #include #include #include +#ifndef _MSC_VER #include +#endif #include #define HAVE_STDARG_H #include <86box/86box.h> diff --git a/src/qt/qt_harddiskdialog.cpp b/src/qt/qt_harddiskdialog.cpp index f2326ef8b..2acaaeacc 100644 --- a/src/qt/qt_harddiskdialog.cpp +++ b/src/qt/qt_harddiskdialog.cpp @@ -230,7 +230,11 @@ static HarddiskDialog *callbackPtr = nullptr; static MVHDGeom create_drive_vhd_fixed(const QString &fileName, HarddiskDialog *p, uint16_t cyl, uint8_t heads, uint8_t spt) { - MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom _86box_geometry = { + .cyl = cyl, + .heads = heads, + .spt = spt + }; MVHDGeom vhd_geometry; adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); @@ -256,7 +260,11 @@ create_drive_vhd_fixed(const QString &fileName, HarddiskDialog *p, uint16_t cyl, static MVHDGeom create_drive_vhd_dynamic(const QString &fileName, uint16_t cyl, uint8_t heads, uint8_t spt, int blocksize) { - MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom _86box_geometry = { + .cyl = cyl, + .heads = heads, + .spt = spt + }; MVHDGeom vhd_geometry; adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); int vhd_error = 0; diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp index 9227cdcb3..13728b82e 100644 --- a/src/qt/qt_vulkanrenderer.cpp +++ b/src/qt/qt_vulkanrenderer.cpp @@ -30,10 +30,11 @@ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ +#include "qt_vulkanrenderer.hpp" #include #include -#include "qt_vulkanrenderer.hpp" + #if QT_CONFIG(vulkan) # include @@ -676,7 +677,7 @@ VulkanRenderer2::initResources() v_texcoord = texcoord; gl_Position = ubuf.mvp * position; } -#endif +#endif /* 0 */ VkShaderModule vertShaderModule = createShader(QStringLiteral(":/texture_vert.spv")); #if 0 #version 440 @@ -691,7 +692,7 @@ VulkanRenderer2::initResources() { fragColor = texture(tex, v_texcoord); } -#endif +#endif /* 0 */ VkShaderModule fragShaderModule = createShader(QStringLiteral(":/texture_frag.spv")); // Graphics pipeline @@ -1009,4 +1010,4 @@ VulkanRenderer2::startNextFrame() m_window->frameReady(); m_window->requestUpdate(); // render continuously, throttled by the presentation rate } -#endif +#endif /* QT_CONFIG(vulkan) */ diff --git a/src/qt/qt_vulkanrenderer.hpp b/src/qt/qt_vulkanrenderer.hpp index d4580d848..2c131e5d7 100644 --- a/src/qt/qt_vulkanrenderer.hpp +++ b/src/qt/qt_vulkanrenderer.hpp @@ -31,6 +31,8 @@ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ****************************************************************************/ +#ifndef VULKANRENDERER_HPP +#define VULKANRENDERER_HPP #include #include @@ -90,4 +92,6 @@ private: QMatrix4x4 m_proj; }; -#endif +#endif // QT_CONFIG(vulkan) + +#endif // VULKANRENDERER_HPP diff --git a/src/qt/qt_vulkanwindowrenderer.cpp b/src/qt/qt_vulkanwindowrenderer.cpp index 60ad5be96..ab46b5961 100644 --- a/src/qt/qt_vulkanwindowrenderer.cpp +++ b/src/qt/qt_vulkanwindowrenderer.cpp @@ -1,3 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2022 Cacodemon345 +** Copyright (C) 2017 The Qt Company Ltd. +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ #include "qt_vulkanwindowrenderer.hpp" #include @@ -697,7 +729,7 @@ public: # if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162 case VK_ERROR_INCOMPATIBLE_VERSION_KHR: return "VK_ERROR_INCOMPATIBLE_VERSION_KHR"; -# endif +# endif /* VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162 */ case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; case VK_ERROR_NOT_PERMITTED_EXT: @@ -788,7 +820,7 @@ public: m_devFuncs->vkDeviceWaitIdle(m_window->device()); } }; -# endif +# endif /* 0*/ VulkanWindowRenderer::VulkanWindowRenderer(QWidget *parent) : QVulkanWindow(parent->windowHandle()) @@ -851,4 +883,4 @@ VulkanWindowRenderer::getBuffers() { return std::vector { std::make_tuple((uint8_t *) renderer->mappedPtr, &this->buf_usage[0]) }; } -#endif +#endif /* QT_CONFIG(vulkan) */ diff --git a/src/qt/qt_vulkanwindowrenderer.hpp b/src/qt/qt_vulkanwindowrenderer.hpp index 828d091e6..de9f46b6f 100644 --- a/src/qt/qt_vulkanwindowrenderer.hpp +++ b/src/qt/qt_vulkanwindowrenderer.hpp @@ -35,6 +35,6 @@ private: VulkanRenderer2 *renderer; }; -#endif +#endif // QT_CONFIG(vulkan) #endif // VULKANWINDOWRENDERER_HPP diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index a1da0af61..73e8a2995 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -56,14 +56,18 @@ std::unique_ptr WindowsRawInputFilter::Register(MainWindow *window) { RAWINPUTDEVICE rid[2] = { - {.usUsagePage = 0x01, - .usUsage = 0x06, - .dwFlags = RIDEV_NOHOTKEYS, - .hwndTarget = nullptr}, - { .usUsagePage = 0x01, - .usUsage = 0x02, - .dwFlags = 0, - .hwndTarget = nullptr} + { + .usUsagePage = 0x01, + .usUsage = 0x06, + .dwFlags = RIDEV_NOHOTKEYS, + .hwndTarget = nullptr + }, + { + .usUsagePage = 0x01, + .usUsage = 0x02, + .dwFlags = 0, + .hwndTarget = nullptr + } }; if (hook_enabled && (RegisterRawInputDevices(&(rid[1]), 1, sizeof(rid[0])) == FALSE)) @@ -89,14 +93,18 @@ WindowsRawInputFilter::WindowsRawInputFilter(MainWindow *window) WindowsRawInputFilter::~WindowsRawInputFilter() { RAWINPUTDEVICE rid[2] = { - {.usUsagePage = 0x01, - .usUsage = 0x06, - .dwFlags = RIDEV_REMOVE, - .hwndTarget = NULL}, - { .usUsagePage = 0x01, - .usUsage = 0x02, - .dwFlags = RIDEV_REMOVE, - .hwndTarget = NULL} + { + .usUsagePage = 0x01, + .usUsage = 0x06, + .dwFlags = RIDEV_REMOVE, + .hwndTarget = NULL + }, + { + .usUsagePage = 0x01, + .usUsage = 0x02, + .dwFlags = RIDEV_REMOVE, + .hwndTarget = NULL + } }; if (hook_enabled) diff --git a/src/qt/win_serial_passthrough.c b/src/qt/win_serial_passthrough.c index 2b77bd219..c1802ce73 100644 --- a/src/qt/win_serial_passthrough.c +++ b/src/qt/win_serial_passthrough.c @@ -88,7 +88,7 @@ plat_serpt_set_params(void *priv) const serial_passthrough_t *dev = (serial_passthrough_t *) priv; if (dev->mode == SERPT_MODE_HOSTSER) { - DCB serialattr = {}; + DCB serialattr = { 0 }; GetCommState((HANDLE) dev->master_fd, &serialattr); #define BAUDRATE_RANGE(baud_rate, min, max) \ if (baud_rate >= min && baud_rate < max) { \ diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 58779e7ac..937213b85 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -1421,7 +1421,7 @@ static const device_config_t aha_154xcp_config[] = { .default_string = "v1_02_en", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Version 1.02 (English)", .internal_name = "v1_02_en", .bios_type = BIOS_NORMAL, .files_no = 2, .local = 0, .size = 32768, .files = { "roms/scsi/adaptec/aha1542cp102.bin", diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index bea918660..6622ec59a 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -841,7 +841,7 @@ static const device_config_t rt1000b_config[] = { .default_string = "v8_10r", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Version 8.10R", .internal_name = "v8_10r", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 8192, .files = { RT1000B_810R_ROM, "" } }, diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index ccedb8c41..51383bdcf 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -330,8 +330,7 @@ static const device_config_t fluidsynth_config[] = { .name = "output_gain", .description = "Output Gain", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 100 }, @@ -347,8 +346,7 @@ static const device_config_t fluidsynth_config[] = { .name = "chorus_voices", .description = "Chorus Voices", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 99 }, @@ -358,8 +356,7 @@ static const device_config_t fluidsynth_config[] = { .name = "chorus_level", .description = "Chorus Level", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 100 }, @@ -369,8 +366,7 @@ static const device_config_t fluidsynth_config[] = { .name = "chorus_speed", .description = "Chorus Speed", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 10, .max = 500 }, @@ -380,8 +376,7 @@ static const device_config_t fluidsynth_config[] = { .name = "chorus_depth", .description = "Chorus Depth", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 2560 }, @@ -391,8 +386,7 @@ static const device_config_t fluidsynth_config[] = { .name = "chorus_waveform", .description = "Chorus Waveform", .type = CONFIG_SELECTION, - .selection = - { + .selection = { { .description = "Sine", .value = 0 @@ -414,8 +408,7 @@ static const device_config_t fluidsynth_config[] = { .name = "reverb_room_size", .description = "Reverb Room Size", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 100 }, @@ -425,8 +418,7 @@ static const device_config_t fluidsynth_config[] = { .name = "reverb_damping", .description = "Reverb Damping", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 100 }, @@ -436,8 +428,7 @@ static const device_config_t fluidsynth_config[] = { .name = "reverb_width", .description = "Reverb Width", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 1000 }, @@ -447,8 +438,7 @@ static const device_config_t fluidsynth_config[] = { .name = "reverb_level", .description = "Reverb Level", .type = CONFIG_SPINNER, - .spinner = - { + .spinner = { .min = 0, .max = 100 }, @@ -458,8 +448,7 @@ static const device_config_t fluidsynth_config[] = { .name = "interpolation", .description = "Interpolation Method", .type = CONFIG_SELECTION, - .selection = - { + .selection = { { .description = "None", .value = 0 diff --git a/src/sound/resid-fp/siddefs-fp.h b/src/sound/resid-fp/siddefs-fp.h index 9411b1694..22e40f4fb 100644 --- a/src/sound/resid-fp/siddefs-fp.h +++ b/src/sound/resid-fp/siddefs-fp.h @@ -24,7 +24,11 @@ #define RESID_BRANCH_HINTS true // Compiler specifics. +#ifndef _MSC_VER #define HAVE_BUILTIN_EXPECT true +#else +#define HAVE_BUILTIN_EXPECT false +#endif // Branch prediction macros, lifted off the Linux kernel. #if RESID_BRANCH_HINTS && HAVE_BUILTIN_EXPECT diff --git a/src/sound/snd_opl2board.c b/src/sound/snd_opl2board.c index dea7752d0..f1bda3398 100644 --- a/src/sound/snd_opl2board.c +++ b/src/sound/snd_opl2board.c @@ -173,8 +173,8 @@ static const device_config_t opl2board_config[] = { .type = CONFIG_SERPORT, .default_string = "", .file_filter = NULL, - .spinner = {}, - .selection = {} + .spinner = { 0 }, + .selection = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index fab2a6a75..ed82afebf 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -86,6 +86,7 @@ * Copyright 2008-2024 Sarah Walker. * Copyright 2024 Miran Grca. */ +#define _USE_MATH_DEFINES #include #include #include diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index a7d2a749f..45a2fc199 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -548,17 +548,20 @@ et3000_available(void) } static const device_config_t et3000_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { .description = "256 KB", - .value = 256 }, - { .description = "512 KB", - .value = 512 }, - { .description = "" } } }, + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + } + }, { .type = CONFIG_END } + // clang-format on }; const device_t et3000_isa_device = { diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index caf8d03c7..ad8cf5c46 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -972,7 +972,7 @@ static const device_config_t et4000_tc6058af_config[] = { .default_string = "v1_10", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Version 1.10", .internal_name = "v1_10", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 32768, .files = { TC6058AF_BIOS_ROM_PATH, "" } }, @@ -1019,7 +1019,7 @@ static const device_config_t et4000_bios_config[] = { .default_string = "v8_01", .default_int = 0, .file_filter = "", - .spinner = { 0 }, /*W1*/ + .spinner = { 0 }, .bios = { { .name = "Version 8.01", .internal_name = "v8_01", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 32768, .files = { BIOS_ROM_PATH, "" } }, diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index c1f5cbeaf..a249631ee 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1701,52 +1701,37 @@ ht216_force_redraw(void *priv) ht216->svga.fullchange = changeframecount; } +// clang-format off static const device_config_t v7_vga_1024i_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { .description = "256 KB", - .value = 256 }, - { .description = "512 KB", - .value = 512 }, - { .description = "" } } }, + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 512, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + } + }, { .type = CONFIG_END } }; -// clang-format off static const device_config_t ht216_32_standalone_config[] = { { - .name = "monitor_type", + .name = "monitor_type", .description = "Monitor type", - .type = CONFIG_SELECTION, + .type = CONFIG_SELECTION, .default_int = 0x18, - .selection = { - { - .description = "Mono Interlaced", - .value = 0x00 - }, - { - .description = "Mono Non-Interlaced", - .value = 0x08 - }, - { - .description = "Color Interlaced", - .value = 0x10 - }, - { - .description = "Color Non-Interlaced", - .value = 0x18 - }, - { - .description = "" - } + .selection = { + { .description = "Mono Interlaced", .value = 0x00 }, + { .description = "Mono Non-Interlaced", .value = 0x08 }, + { .description = "Color Interlaced", .value = 0x10 }, + { .description = "Color Non-Interlaced", .value = 0x18 }, + { .description = "" } } }, - { - .type = CONFIG_END - } + { .type = CONFIG_END } }; // clang-format on diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 1bdbecdf6..2b9e63af4 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -6851,8 +6851,7 @@ static const device_config_t mystique_config[] = { .name = "memory", .description = "Memory size", .type = CONFIG_SELECTION, - .selection = - { + .selection = { { .description = "2 MB", .value = 2 @@ -6865,15 +6864,11 @@ static const device_config_t mystique_config[] = { .description = "8 MB", .value = 8 }, - { - .description = "" - } + { .description = "" } }, .default_int = 8 }, - { - .type = CONFIG_END - } + { .type = CONFIG_END } // clang-format on }; @@ -6883,8 +6878,7 @@ static const device_config_t millennium_ii_config[] = { .name = "memory", .description = "Memory size", .type = CONFIG_SELECTION, - .selection = - { + .selection = { { .description = "4 MB", .value = 4 @@ -6897,15 +6891,11 @@ static const device_config_t millennium_ii_config[] = { .description = "16 MB", .value = 16 }, - { - .description = "" - } + { .description = "" } }, .default_int = 8 }, - { - .type = CONFIG_END - } + { .type = CONFIG_END } // clang-format on }; From abb066f6ef2efa9c83daad8ec50bcfb1fbcc29d8 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 21 Dec 2022 04:17:04 -0500 Subject: [PATCH 0054/1190] Initial Micro Solutions CompatiCard support --- src/floppy/CMakeLists.txt | 1 + src/floppy/fdc.c | 21 ++- src/floppy/fdc_compaticard.c | 355 +++++++++++++++++++++++++++++++++++ src/include/86box/fdc_ext.h | 4 + 4 files changed, 372 insertions(+), 9 deletions(-) create mode 100644 src/floppy/fdc_compaticard.c diff --git a/src/floppy/CMakeLists.txt b/src/floppy/CMakeLists.txt index d86ff4bc2..c16ca06f4 100644 --- a/src/floppy/CMakeLists.txt +++ b/src/floppy/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(fdd OBJECT fdd.c fdc.c + fdc_compaticard.c fdc_magitronic.c fdc_monster.c fdc_pii15xb.c diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 546174c57..4cb2a8491 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -103,15 +103,18 @@ typedef const struct { static fdc_cards_t fdc_cards[] = { // clang-format off - { &device_none }, - { &device_internal }, - { &fdc_xt_device }, - { &fdc_at_device }, - { &fdc_b215_device }, - { &fdc_pii151b_device }, - { &fdc_pii158b_device }, - { &fdc_monster_device }, - { NULL } + { &device_none }, + { &device_internal }, + { &fdc_b215_device }, + { &fdc_pii151b_device }, + { &fdc_pii158b_device }, + { &fdc_compaticard_i_device }, + { &fdc_compaticard_ii_device }, +#if 0 + { &fdc_compaticard_iv_device }, +#endif + { &fdc_monster_device }, + { NULL } // clang-format on }; diff --git a/src/floppy/fdc_compaticard.c b/src/floppy/fdc_compaticard.c new file mode 100644 index 000000000..a693c9cb2 --- /dev/null +++ b/src/floppy/fdc_compaticard.c @@ -0,0 +1,355 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of Micro Solutions CompatiCard I/II/IV. + * + * Authors: Jasmine Iwanek, + * + * Copyright 2022-2025 Jasmine Iwanek. + */ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/machine.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> + +#define DEVICE_COMPATICARD_I 0 +#define DEVICE_COMPATICARD_II 1 +#define DEVICE_COMPATICARD_IV 2 + +#define BIOS_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff) +#define ROM_COMPATICARD_IV "roms/floppy/compaticard/ccivbios1.05.bin" + +#define CR_2_MASK 0x2f /* 00101111b */ + +typedef struct compaticard_s { + rom_t bios_rom; + fdc_t *fdc; + /* + * 7 - Reserved - Set to 0 + * 6 - Reserved - Set to 0 + * 5 - Programmable Pin 2 Logic I sets Pin 2 low (TODO) + * 4 - Reserved - Set to 0 + * 3-0 - Data Transfer Rate Select (TODO) + * 0000---250 Kbps + * 0001-300 Kbps + * 1111-500 Kbps + */ + uint8_t cr_2; +} compaticard_t; + +static void +compaticard_out(uint16_t port, uint8_t val, void *priv) +{ + compaticard_t *dev = (compaticard_t *) priv; + + dev->cr_2 = (val & CR_2_MASK); +} + +static uint8_t +compaticard_in(uint16_t port, void *priv) +{ + compaticard_t *dev = (compaticard_t *) priv; + uint8_t ret = (dev->cr_2 &CR_2_MASK); + + return ret; +} + +static void +compaticard_close(void *priv) +{ + compaticard_t *dev = (compaticard_t *) priv; + + free(dev); +} + +static void * +compaticard_init(const device_t *info) +{ + compaticard_t *dev = calloc(1, sizeof(compaticard_t)); + uint16_t base_addr = device_get_config_hex16("base"); + uint8_t irq = 6; + uint8_t dma = 2; + uint16_t cr2_addr = 0x7f2; // Control Register 2 + + // CompatiCard II & IV have configurable IRQ and DMA + if (info->local >= DEVICE_COMPATICARD_II) { + irq = device_get_config_int("irq"); + dma = device_get_config_int("dma"); + } + + // Only on CompatiCard IV + if ((info->local == DEVICE_COMPATICARD_IV) && (BIOS_ADDR != 0)) + rom_init(&dev->bios_rom, ROM_COMPATICARD_IV, BIOS_ADDR, 0x2000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); + + // TODO: Make this neater + switch (base_addr) { + case FDC_SECONDARY_ADDR: + cr2_addr = 0x772; + if (info->local == DEVICE_COMPATICARD_IV) + dev->fdc = device_add(&fdc_at_sec_device); + else + dev->fdc = device_add(&fdc_xt_sec_device); + break; + + case FDC_TERTIARY_ADDR: + cr2_addr = 0x762; + if (info->local == DEVICE_COMPATICARD_IV) + dev->fdc = device_add(&fdc_at_ter_device); + else + dev->fdc = device_add(&fdc_xt_ter_device); + break; + + case FDC_QUATERNARY_ADDR: + cr2_addr = 0x7e2; + if (info->local == DEVICE_COMPATICARD_IV) + dev->fdc = device_add(&fdc_at_qua_device); + else + dev->fdc = device_add(&fdc_xt_qua_device); + break; + + default: + if (info->local == DEVICE_COMPATICARD_IV) + dev->fdc = device_add(&fdc_at_device); + else + dev->fdc = device_add(&fdc_xt_device); + break; + } + + fdc_set_irq(dev->fdc, irq); + fdc_set_dma_ch(dev->fdc, dma); + + io_sethandler(cr2_addr, 0x0001, + compaticard_in, NULL, NULL, + compaticard_out, NULL, NULL, + dev); + + return dev; +} + +static int compaticard_iv_available(void) +{ + return rom_present(ROM_COMPATICARD_IV); +} + +static const device_config_t compaticard_i_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x3f0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x3f0", .value = 0x3f0 }, + { .description = "0x370", .value = 0x370 }, + { .description = "0x360", .value = 0x360 }, + { .description = "0x3e0", .value = 0x3e0 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_config_t compaticard_ii_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x3f0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x3f0", .value = 0x3f0 }, + { .description = "0x370", .value = 0x370 }, + { .description = "0x360", .value = 0x360 }, + { .description = "0x3e0", .value = 0x3e0 }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 6", .value = 6 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 2", .value = 2 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_config_t compaticard_iv_config[] = { +// clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x3f0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "0x3f0", .value = 0x3f0 }, + { .description = "0x370", .value = 0x370 }, + { .description = "0x360", .value = 0x360 }, + { .description = "0x3e0", .value = 0x3e0 }, + { .description = "" } + } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 6, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 6", .value = 6 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + } + }, + { + .name = "dma", + .description = "DMA channel", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 2, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 2", .value = 2 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + } + }, + { + .name = "bios_addr", + .description = "BIOS Address:", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xce000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DE00H", .value = 0xde000 }, + { .description = "E000H", .value = 0xe0000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EE00H", .value = 0xee000 }, + { .description = "" } + } + }, +#if 0 + { + .name = "autoboot_enabled", + .description = "Enable Autoboot", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, +#endif + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +const device_t fdc_compaticard_i_device = { + .name = "Micro Solutions CompatiCard I", + .internal_name = "compaticard_i", + .flags = DEVICE_ISA, + .local = 0, + .init = compaticard_init, + .close = compaticard_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = compaticard_i_config +}; + +const device_t fdc_compaticard_ii_device = { + .name = "Micro Solutions CompatiCard II", + .internal_name = "compaticard_ii", + .flags = DEVICE_ISA, + .local = 1, + .init = compaticard_init, + .close = compaticard_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = compaticard_ii_config +}; + +const device_t fdc_compaticard_iv_device = { + .name = "Micro Solutions CompatiCard IV", + .internal_name = "compaticard_iv", + .flags = DEVICE_ISA, + .local = 2, + .init = compaticard_init, + .close = compaticard_close, + .reset = NULL, + .available = compaticard_iv_available, + .speed_changed = NULL, + .force_redraw = NULL, + .config = compaticard_iv_config +}; diff --git a/src/include/86box/fdc_ext.h b/src/include/86box/fdc_ext.h index 4b33ed7a1..e6348139b 100644 --- a/src/include/86box/fdc_ext.h +++ b/src/include/86box/fdc_ext.h @@ -34,6 +34,10 @@ extern const device_t fdc_b215_device; extern const device_t fdc_pii151b_device; extern const device_t fdc_pii158b_device; +extern const device_t fdc_compaticard_i_device; +extern const device_t fdc_compaticard_ii_device; +extern const device_t fdc_compaticard_iv_device; + extern const device_t fdc_monster_device; extern void fdc_card_init(void); From 2d0f03a708d7ac4ba0f4b7ae719b56f82d8ac99e Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Sun, 12 Jan 2025 10:47:23 +0100 Subject: [PATCH 0055/1190] Fixed a BX6-related typo --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 4947b8898..330b7d52a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14634,7 +14634,7 @@ const machine_t machines[] = { firmware. */ { - .name = "[i440LX] ABIT BX6", + .name = "[i440BX] ABIT BX6", .internal_name = "bx6", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_INTEL_440BX, From 204b24022f291ce7b4a5f3af9fee8d644f4f4c00 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 15:21:31 +0000 Subject: [PATCH 0056/1190] Implement the rivatimer and cyclical logging from my main NV3 branch so that we can get it reviewed and merged. --- src/86box.c | 152 ++++++++++++- src/include/86box/86box.h | 5 +- src/include/86box/nv/vid_nv_rivatimer.h | 84 ++++++++ src/video/nv/nv_rivatimer.c | 274 ++++++++++++++++++++++++ 4 files changed, 502 insertions(+), 13 deletions(-) create mode 100644 src/include/86box/nv/vid_nv_rivatimer.h create mode 100644 src/video/nv/nv_rivatimer.c diff --git a/src/86box.c b/src/86box.c index 8fa74fd4b..8450c8b6b 100644 --- a/src/86box.c +++ b/src/86box.c @@ -103,6 +103,7 @@ #include <86box/machine_status.h> #include <86box/apm.h> #include <86box/acpi.h> +#include <86box/nv/vid_nv_rivatimer.h> // Disable c99-designator to avoid the warnings about int ng #ifdef __clang__ @@ -252,12 +253,37 @@ static volatile atomic_int do_pause_ack = 0; static volatile atomic_int pause_ack = 0; #ifndef RELEASE_BUILD -static char buff[1024]; -static int seen = 0; + +#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ +#define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ +#define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ + +static char buff[LOG_SIZE_BUFFER]; +static char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; +static int32_t cyclic_last_line = 0; +static int32_t log_cycles = 0; + +static int seen = 0; static int suppr_seen = 1; #endif +/* + Ensures STDLOG is open for pclog_ex and pclog_ex_cyclic +*/ +void +pclog_ensure_stdlog_open() +{ + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } +} + /* * Log something to the logfile or stdout. * @@ -269,19 +295,12 @@ void pclog_ex(const char *fmt, va_list ap) { #ifndef RELEASE_BUILD - char temp[1024]; + char temp[LOG_SIZE_BUFFER]; if (strcmp(fmt, "") == 0) return; - if (stdlog == NULL) { - if (log_path[0] != '\0') { - stdlog = plat_fopen(log_path, "w"); - if (stdlog == NULL) - stdlog = stdout; - } else - stdlog = stdout; - } + pclog_ensure_stdlog_open(); vsprintf(temp, fmt, ap); if (suppr_seen && !strcmp(buff, temp)) @@ -298,6 +317,114 @@ pclog_ex(const char *fmt, va_list ap) #endif } + +/* +Starfrost, 7-8 January 2025: + +For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. + +Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm +*/ +void +pclog_ex_cyclic(const char* fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + char temp[LOG_SIZE_BUFFER]; + + cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; + + vsprintf(temp, fmt, ap); + + pclog_ensure_stdlog_open(); + + strncpy(cyclic_buff[cyclic_last_line], temp, LOG_SIZE_BUFFER); + + uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; + + // Random numbers + uint32_t base = 257; + uint32_t mod = 1000000007; + + uint32_t repeat_order = 0; + bool is_cycle = false; + + // compute the set of hashes for the current log buffer + for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) + { + if (cyclic_buff[log_line][0] == '\0') + continue; // skip + + for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) + { + hashes[log_line] = hashes[log_line] * base + cyclic_buff[log_line][log_line_char] % mod; + } + } + + + // Now see if there are real cycles... + // We implement a minimum repeat size. + for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) + { + //TODO: Log what we need for cycle 1. + //TODO: Command line option that lets us turn off this behaviour. + for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) + { + if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) + { + repeat_order = check_size; + break; + } + } + + is_cycle = (repeat_order != 0); + + // if there still is a cycle.. + if (is_cycle) + break; + + } + + if (is_cycle) + { + if (cyclic_last_line % repeat_order == 0) + { + log_cycles++; + + if (log_cycles == 1) + { + // 'Replay' the last few log entries so they actually show up + // Todo: is this right? + + for (uint32_t index = cyclic_last_line - 1; index > (cyclic_last_line - repeat_order); index--) + { + // *very important* to prevent out of bounds index + uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; + fprintf(stdlog, "%s", temp); + + } + + fprintf(stdlog, "%s", temp); // allow normal logging + } + + + if (log_cycles > 1 && log_cycles < 100) + fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log_cycles); + else if (log_cycles == 100) + fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); + } + } + else + { + log_cycles = 0; + fprintf(stdlog, "%s", temp); + } + + cyclic_last_line++; + +#endif + +} + void pclog_toggle_suppr(void) { @@ -1427,6 +1554,9 @@ pc_run(void) pc_reset_hard_init(); } + /* Update the guest-CPU independent timer for devices with independent clock speed */ + rivatimer_update_all(); + /* Run a block of code. */ startblit(); cpu_exec((int32_t) cpu_s->rspeed / 100); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 503518a2b..05c2a901e 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -187,8 +187,9 @@ extern int config_changed; /* config has changed */ /* Function prototypes. */ #ifdef HAVE_STDARG_H -extern void pclog_ex(const char *fmt, va_list); -extern void fatal_ex(const char *fmt, va_list); +extern void pclog_ex(const char *fmt, va_list ap); +extern void fatal_ex(const char *fmt, va_list ap); +extern void pclog_ex_cyclic(const char* fmt, va_list ap); #endif extern void pclog_toggle_suppr(void); #ifdef _MSC_VER diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h new file mode 100644 index 000000000..d5bb86b90 --- /dev/null +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -0,0 +1,84 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Fast, high-frequency, guest CPU-independent timer for Riva emulation. + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +/* +RivaTimer + +This is a fast, high-frequency, guest CPU-independent timer. + +The main 86box timer is dependent on the TSC (time-stamp counter) register of the emulated CPU core. +This is fine for most purposes and has advantages in the fields of synchronisation and integrates neatly with +the clock dividers of the PC architecture, but in the case of the RIVA 128 it does not particularly suffice +(although it can be made to work with various techniques) since the clock source on the RIVA 128 is on the board itself +and the GPU has several different clocks that control different parts of the GPU (e.g., PTIMER runs on the memory clock but the core gpu is using the pixel clock). + +As faster graphics cards that offload more and more of the 3D graphics pipeline are emulated in the future, more and more work needs to be done by the emulator and +issues of synchronisation with a host CPU will simply make that work harder. Some features that are required for + +Architecture Brand Name 3D Features +NV1 (1995) NV1 Some weird URBS rectangle crap but feature set generally similar to nv3 but a bit worse +NV3 (1997) RIVA 128 (ZX) Triangle setup, edge-slope calculations, edge interpolation, span-slope calculations, span interpolation (Color-buffer, z-buffer, texture mapping, filtering) +NV4 (1998) RIVA TNT NV3 + 2x1 pixel pipelines + 32-bit colour + larger textures + trilinear + more ram (16mb) +NV5 (1999) RIVA TNT2 NV4 + higher clock speed +NV10 (1999) GeForce 256 NV5 + initial geometry transformation + lighting (8x lights) + MPEG-2 motion compensation + 4x1 pixel pipelines +NV15 (2000) GeForce 2 NV10 + First attempt at programmability + 4x2 pixel pipelines +NV20 (2001) GeForce 3 Programmable shaders! + +As you can see, the performance basically exponentially increases over a period of only 4 years. + +So I decided to create this timer that is completely separate from the CPU Core. +*/ + +#pragma once +#include +#include +#include +#include +#include <86Box\86box.h> + +#ifdef _WIN32 +#include +// Linux & MacOS should have the same API since OSX 10.12 +#else +#include +#endif + +typedef struct rivatimer_s +{ + struct rivatimer_s* prev; // Previous Rivatimer + double period; // Period in uS before firing + double value; // The current value of the rivatimer + bool running; // Is this RivaTimer running? + struct rivatimer_s* next; // Next RivaTimer + void (*callback)(); // Callback to call on fire + #ifdef _WIN32 + LARGE_INTEGER starting_time; // Starting time. + #else + struct timespec starting_time; // Starting time. + #endif + double time; // Accumulated time in uS. +} rivatimer_t; + +void rivatimer_init(); // Initialise the Rivatimer. +rivatimer_t* rivatimer_create(double period, void (*callback)(double real_time)); +void rivatimer_destroy(rivatimer_t* rivatimer_ptr); + +void rivatimer_update_all(); +void rivatimer_start(rivatimer_t* rivatimer_ptr); +void rivatimer_stop(rivatimer_t* rivatimer_ptr); +double rivatimer_get_time(rivatimer_t* rivatimer_ptr); +void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)(double real_time)); +void rivatimer_set_period(rivatimer_t* rivatimer_ptr, double period); diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c new file mode 100644 index 000000000..343ec02ff --- /dev/null +++ b/src/video/nv/nv_rivatimer.c @@ -0,0 +1,274 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Fast, high-frequency, CPU-independent timer. + * + * + * + * Authors: Connor Hyde, I need a better email address ;^) + * + * Copyright 2024-2025 starfrost + */ + +/* See vid_nv_rivatimer.h comments for rationale behind not using the regular timer system + +Notes applicable to this file: +Since Windows XP, QueryPerformanceCounter and QueryPerformanceFrequency cannot fail so they are not checked. + +*/ + +#include <86Box/nv/vid_nv_rivatimer.h> + +#ifdef _WIN32 +LARGE_INTEGER performance_frequency; +#endif + +rivatimer_t* rivatimer_head; // The head of the rivatimer list. +rivatimer_t* rivatimer_tail; // The tail of the rivatimer list. + +/* Functions only used in this translation unit */ +bool rivatimer_really_exists(rivatimer_t* rivatimer); // Determine if a rivatimer really exists in the linked list. + +void rivatimer_init() +{ + // Destroy all the rivatimers. + rivatimer_t* rivatimer_ptr = rivatimer_head; + + if (!rivatimer_ptr) + return; + + while (rivatimer_ptr) + { + // since we are destroing it + rivatimer_t* old_next = rivatimer_ptr->next; + rivatimer_destroy(rivatimer_ptr); + + rivatimer_ptr = old_next; + } + + + #ifdef _WIN32 + // Query the performance frequency. + QueryPerformanceFrequency(&performance_frequency); + #endif +} + +// Creates a rivatimer. +rivatimer_t* rivatimer_create(double period, void (*callback)(double real_time)) +{ + rivatimer_t* new_rivatimer = NULL; + + // See i + if (period <= 0 + || !callback) + { + fatal("Invalid rivatimer_create call: period <= 0 or no callback"); + } + + // If there are no rivatimers, create one + if (!rivatimer_head) + { + rivatimer_head = calloc(1, sizeof(rivatimer_t)); + rivatimer_head->prev = NULL; // indicate this is the first in the list even if we don't strictly need to + rivatimer_tail = rivatimer_head; + new_rivatimer = rivatimer_head; + } + else // Otherwise add a new one to the list + { + rivatimer_tail->next = calloc(1, sizeof(rivatimer_t)); + rivatimer_tail = rivatimer_tail->next; + new_rivatimer = rivatimer_tail; + } + + // sanity check + if (new_rivatimer) + { + new_rivatimer->running = false; + new_rivatimer->period = period; + new_rivatimer->next = NULL; // indicate this is the last in the list + new_rivatimer->callback = callback; + } + + return new_rivatimer; +} + +// Determines if a rivatimer really exists. +bool rivatimer_really_exists(rivatimer_t* rivatimer) +{ + rivatimer_t* current = rivatimer_head; + + if (!current) + return false; + + while (current) + { + if (current == rivatimer) + return true; + + current = current->next; + } + + return false; +} + +// Destroy a rivatimer. +void rivatimer_destroy(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_destroy: The timer was already destroyed, or never existed in the first place. Punch starfrost in the face"); + + // Case: We are destroying the head + if (rivatimer_ptr == rivatimer_head) + { + // This is the only rivatimer + if (rivatimer_ptr->next == NULL) + { + rivatimer_head = NULL; + rivatimer_tail = NULL; + } + // This is not the only rivatimer + else + { + rivatimer_head = rivatimer_ptr->next; + rivatimer_head->prev = NULL; + // This is the only rivatimer and now there is only one + if (!rivatimer_head->next) + rivatimer_tail = rivatimer_head; + } + } + // Case: We are destroying the tail + else if (rivatimer_ptr == rivatimer_tail) + { + // We already covered the case where there is only one item above + rivatimer_tail = rivatimer_ptr->prev; + rivatimer_tail->next = NULL; + } + // Case: This is not the first or last rivatimer, so we don't need to set the head or tail + else + { + // Fix the break in the chain that this + if (rivatimer_ptr->next) + rivatimer_ptr->prev->next = rivatimer_ptr->next; + if (rivatimer_ptr->prev) + rivatimer_ptr->next->prev = rivatimer_ptr->prev; + } + + free(rivatimer_ptr); + rivatimer_ptr = NULL; //explicitly set to null +} + +void rivatimer_update_all() +{ + rivatimer_t* rivatimer_ptr = rivatimer_head; + + if (!rivatimer_ptr) + return; + + while (rivatimer_ptr) + { + // if it's not running skip it + if (!rivatimer_ptr->running) + { + rivatimer_ptr = rivatimer_ptr->next; + continue; + } + + #ifdef _WIN32 + LARGE_INTEGER current_time; + + QueryPerformanceCounter(¤t_time); + + double microseconds = ((double)current_time.QuadPart / 1000000.0) - (rivatimer_ptr->starting_time.QuadPart / 1000000.0); + #else + struct timespec current_time; + + clock_gettime(CLOCK_REALTIME, ¤t_time); + + double microseconds = ((double)current_time.tv_sec * 1000000.0) + ((double)current_time.tv_nsec / 1000.0); + #endif + + rivatimer_ptr->time += microseconds; + + // Reset the current time so we can actually restart + #ifdef _WIN32 + QueryPerformanceCounter(&rivatimer_ptr->starting_time); + #else + clock_gettime(CLOCK_REALTIME, &rivatimer_ptr->starting_time); + #endif + + // Time to fire + if (microseconds > rivatimer_ptr->period) + { + if (!rivatimer_ptr->callback) + { + pclog("Eh? No callback in RivaTimer?"); + continue; + } + + rivatimer_ptr->callback(microseconds); + } + + rivatimer_ptr = rivatimer_ptr->next; + } + +} + +void rivatimer_start(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_start: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + if (rivatimer_ptr->period <= 0) + fatal("rivatimer_start: Zero period!"); + + rivatimer_ptr->running = true; + + // Start off so rivatimer_update_all can actually update. + #ifdef _WIN32 + QueryPerformanceCounter(&rivatimer_ptr->starting_time); + #else + clock_gettime(CLOCK_REALTIME, &rivatimer_ptr->starting_time); + #endif +} + +void rivatimer_stop(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_stop: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + rivatimer_ptr->running = false; + rivatimer_ptr->time = 0; +} + +// Get the current time value of a rivatimer +double rivatimer_get_time(rivatimer_t* rivatimer_ptr) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_get_time: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + return rivatimer_ptr->time; +} + +void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)(double real_time)) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_set_callback: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + if (!callback) + fatal("rivatimer_set_callback: No callback!"); + + rivatimer_ptr->callback = callback; +} + +void rivatimer_set_period(rivatimer_t* rivatimer_ptr, double period) +{ + if (!rivatimer_really_exists(rivatimer_ptr)) + fatal("rivatimer_set_period: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + + rivatimer_ptr->period = period; +} \ No newline at end of file From 6eaec5b756fab78c94fcb861155acb7ed2c576fe Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 15:31:54 +0000 Subject: [PATCH 0057/1190] forgot to port over some parts --- src/timer.c | 4 ++++ src/video/CMakeLists.txt | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/timer.c b/src/timer.c index 6ddf8ebb5..2b92a1958 100644 --- a/src/timer.c +++ b/src/timer.c @@ -4,6 +4,7 @@ #include #include <86box/86box.h> #include <86box/timer.h> +#include <86Box/nv/vid_nv_rivatimer.h> uint64_t TIMER_USEC; uint32_t timer_target; @@ -168,6 +169,9 @@ timer_init(void) timer_target = 0ULL; tsc = 0; + /* Initialise the CPU-independent timer */ + rivatimer_init(); + timer_inited = 1; } diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index bbd329b7e..3d8e14c5e 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -27,7 +27,9 @@ add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c - vid_bochs_vbe.c) + vid_bochs_vbe.c + nv/nv_rivatimer.c + ) if(G100) target_compile_definitions(vid PRIVATE USE_G100) From 55f476617d67cc476f48c42cfe04554019afe82b Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 19:07:27 +0000 Subject: [PATCH 0058/1190] Don't punch me in the face, and also fix the compilation, and also fix a stupid bug in log replay. --- src/86box.c | 5 ++--- src/include/86box/nv/vid_nv_rivatimer.h | 6 +++--- src/video/nv/nv_rivatimer.c | 12 ++++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/86box.c b/src/86box.c index 8450c8b6b..b5a4de15e 100644 --- a/src/86box.c +++ b/src/86box.c @@ -271,8 +271,7 @@ static int suppr_seen = 1; /* Ensures STDLOG is open for pclog_ex and pclog_ex_cyclic */ -void -pclog_ensure_stdlog_open() +void pclog_ensure_stdlog_open() { if (stdlog == NULL) { if (log_path[0] != '\0') { @@ -399,7 +398,7 @@ pclog_ex_cyclic(const char* fmt, va_list ap) { // *very important* to prevent out of bounds index uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; - fprintf(stdlog, "%s", temp); + fprintf(stdlog, "%s", cyclic_buff[real_index]); } diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h index d5bb86b90..627bbcdcf 100644 --- a/src/include/86box/nv/vid_nv_rivatimer.h +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -63,7 +63,7 @@ typedef struct rivatimer_s double value; // The current value of the rivatimer bool running; // Is this RivaTimer running? struct rivatimer_s* next; // Next RivaTimer - void (*callback)(); // Callback to call on fire + void (*callback)(void); // Callback to call on fire #ifdef _WIN32 LARGE_INTEGER starting_time; // Starting time. #else @@ -72,11 +72,11 @@ typedef struct rivatimer_s double time; // Accumulated time in uS. } rivatimer_t; -void rivatimer_init(); // Initialise the Rivatimer. +void rivatimer_init(void); // Initialise the Rivatimer. rivatimer_t* rivatimer_create(double period, void (*callback)(double real_time)); void rivatimer_destroy(rivatimer_t* rivatimer_ptr); -void rivatimer_update_all(); +void rivatimer_update_all(void); void rivatimer_start(rivatimer_t* rivatimer_ptr); void rivatimer_stop(rivatimer_t* rivatimer_ptr); double rivatimer_get_time(rivatimer_t* rivatimer_ptr); diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c index 343ec02ff..ee8c13916 100644 --- a/src/video/nv/nv_rivatimer.c +++ b/src/video/nv/nv_rivatimer.c @@ -120,7 +120,7 @@ bool rivatimer_really_exists(rivatimer_t* rivatimer) void rivatimer_destroy(rivatimer_t* rivatimer_ptr) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_destroy: The timer was already destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_destroy: The timer was already destroyed, or never existed in the first place."); // Case: We are destroying the head if (rivatimer_ptr == rivatimer_head) @@ -221,7 +221,7 @@ void rivatimer_update_all() void rivatimer_start(rivatimer_t* rivatimer_ptr) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_start: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_start: The timer has been destroyed, or never existed in the first place."); if (rivatimer_ptr->period <= 0) fatal("rivatimer_start: Zero period!"); @@ -239,7 +239,7 @@ void rivatimer_start(rivatimer_t* rivatimer_ptr) void rivatimer_stop(rivatimer_t* rivatimer_ptr) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_stop: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_stop: The timer has been destroyed, or never existed in the first place."); rivatimer_ptr->running = false; rivatimer_ptr->time = 0; @@ -249,7 +249,7 @@ void rivatimer_stop(rivatimer_t* rivatimer_ptr) double rivatimer_get_time(rivatimer_t* rivatimer_ptr) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_get_time: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_get_time: The timer has been destroyed, or never existed in the first place."); return rivatimer_ptr->time; } @@ -257,7 +257,7 @@ double rivatimer_get_time(rivatimer_t* rivatimer_ptr) void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)(double real_time)) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_set_callback: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_set_callback: The timer has been destroyed, or never existed in the first place."); if (!callback) fatal("rivatimer_set_callback: No callback!"); @@ -268,7 +268,7 @@ void rivatimer_set_callback(rivatimer_t* rivatimer_ptr, void (*callback)(double void rivatimer_set_period(rivatimer_t* rivatimer_ptr, double period) { if (!rivatimer_really_exists(rivatimer_ptr)) - fatal("rivatimer_set_period: The timer has been destroyed, or never existed in the first place. Punch starfrost in the face"); + fatal("rivatimer_set_period: The timer has been destroyed, or never existed in the first place."); rivatimer_ptr->period = period; } \ No newline at end of file From cbfeed7ea46acbc6d2481798b1dc920b8bcbc50d Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 19:09:35 +0000 Subject: [PATCH 0059/1190] Fix incorrect include --- src/include/86box/nv/vid_nv_rivatimer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h index 627bbcdcf..8ccc0f0df 100644 --- a/src/include/86box/nv/vid_nv_rivatimer.h +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -47,7 +47,7 @@ So I decided to create this timer that is completely separate from the CPU Core. #include #include #include -#include <86Box\86box.h> +#include <86Box/86box.h> #ifdef _WIN32 #include From 8c48478706d8b7c53fc6afe0ddc5498fcab8f1f1 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 19:11:20 +0000 Subject: [PATCH 0060/1190] fix the screwed up callbacks --- src/include/86box/nv/vid_nv_rivatimer.h | 2 +- src/video/nv/nv_rivatimer.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h index 8ccc0f0df..a4fe85e92 100644 --- a/src/include/86box/nv/vid_nv_rivatimer.h +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -63,7 +63,7 @@ typedef struct rivatimer_s double value; // The current value of the rivatimer bool running; // Is this RivaTimer running? struct rivatimer_s* next; // Next RivaTimer - void (*callback)(void); // Callback to call on fire + void (*callback)(double real_time); // Callback to call on fire #ifdef _WIN32 LARGE_INTEGER starting_time; // Starting time. #else diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c index ee8c13916..44e5901d1 100644 --- a/src/video/nv/nv_rivatimer.c +++ b/src/video/nv/nv_rivatimer.c @@ -34,7 +34,7 @@ rivatimer_t* rivatimer_tail; // The tail of the rivatimer list. /* Functions only used in this translation unit */ bool rivatimer_really_exists(rivatimer_t* rivatimer); // Determine if a rivatimer really exists in the linked list. -void rivatimer_init() +void rivatimer_init(void) { // Destroy all the rivatimers. rivatimer_t* rivatimer_ptr = rivatimer_head; @@ -162,7 +162,7 @@ void rivatimer_destroy(rivatimer_t* rivatimer_ptr) rivatimer_ptr = NULL; //explicitly set to null } -void rivatimer_update_all() +void rivatimer_update_all(void) { rivatimer_t* rivatimer_ptr = rivatimer_head; From 8dc456cce5c2eb87e744ec1d82858a98f14ffec3 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 12 Jan 2025 20:37:50 +0100 Subject: [PATCH 0061/1190] NCR 5380-based changes of the day (January 12, 2025) 1. Sanity check for the SCSI temp_buffer if it's allocated or not. 2. Data reads and writes in non-DMA mode should be accessible only when DMA mode is Idle (as in, no DMA at all, whereas DMA mode will go to the SCSI controllers' callbacks). --- src/scsi/scsi_ncr5380.c | 47 ++++++++++++++++++++++++++------------- src/scsi/scsi_ncr53c400.c | 38 +++++++++++++++++++++++-------- src/scsi/scsi_t128.c | 2 ++ 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 527ff373f..092cc08e9 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -197,20 +197,29 @@ ncr5380_bus_read(ncr_t *ncr) phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); if (phase == SCSI_PHASE_DATA_IN) { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - ncr->state = STATE_DATAIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + if (ncr->dma_mode == DMA_IDLE) { + ncr5380_log("Phase Data In.\n"); + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + + ncr->state = STATE_DATAIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + } } else if (phase == SCSI_PHASE_DATA_OUT) { if (ncr->new_phase & BUS_IDLE) { ncr->state = STATE_IDLE; ncr->cur_bus &= ~BUS_BSY; - } else - ncr->state = STATE_DATAOUT; + } else { + if (ncr->dma_mode == DMA_IDLE) + ncr->state = STATE_DATAOUT; + } } else if (phase == SCSI_PHASE_STATUS) { + ncr5380_log("Phase Status.\n"); ncr->cur_bus |= BUS_REQ; ncr->state = STATE_STATUS; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; } else if (phase == SCSI_PHASE_MESSAGE_IN) { + ncr5380_log("Phase Message In.\n"); ncr->state = STATE_MESSAGEIN; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; } else if (phase == SCSI_PHASE_MESSAGE_OUT) { @@ -335,19 +344,22 @@ ncr5380_bus_update(ncr_t *ncr, int bus) if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { if (ncr->data_pos >= dev->buffer_length) { ncr->cur_bus &= ~BUS_REQ; + ncr5380_log("CMD Phase1 DataIn.\n"); scsi_device_command_phase1(dev); ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/ ncr->data_wait |= 1; - ncr5380_log("DMA mode idle in\n"); + ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); ncr->timer(ncr->priv, ncr->period); } else { - ncr5380_log("DMA mode IN.\n"); + ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); ncr->clear_req = 3; } @@ -359,7 +371,8 @@ ncr5380_bus_update(ncr_t *ncr, int bus) case STATE_DATAOUT: dev = &scsi_devices[ncr->bus][ncr->target_id]; if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); if (ncr->data_pos >= dev->buffer_length) { ncr->cur_bus &= ~BUS_REQ; @@ -439,12 +452,12 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) switch (port & 7) { case 0: /* Output data register */ - ncr5380_log("Write: Output data register, val = %02x\n", val); + ncr5380_log("[%04X:%08X]: Write: Output data register, val=%02x\n", CS, cpu_state.pc, val); ncr->output_data = val; break; case 1: /* Initiator Command Register */ - ncr5380_log("Write: Initiator command register\n"); + ncr5380_log("[%04X:%08X]: Write: Initiator command register, val=%02x.\n", CS, cpu_state.pc, val); if ((val & 0x80) && !(ncr->icr & 0x80)) { ncr5380_log("Resetting the 5380\n"); ncr5380_reset(ncr); @@ -465,7 +478,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 3: /* Target Command Register */ - ncr5380_log("Write: Target Command register\n"); + ncr5380_log("Write: Target Command register, val=%02x.\n", val); ncr->tcr = val; break; @@ -482,7 +495,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 7: /* start DMA Initiator Receive */ - ncr5380_log("Write: start DMA initiator receive register, dma? = %02x\n", ncr->mode & MODE_DMA); + ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; if (ncr->dma_initiator_receive_ext) @@ -510,13 +523,13 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_log("Read: Current SCSI data register\n"); if (ncr->icr & ICR_DBP) { /*Return the data from the output register if on data bus phase from ICR*/ - ncr5380_log("Data Bus Phase, ret = %02x\n", ncr->output_data); ret = ncr->output_data; + ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data); } else { /*Return the data from the SCSI bus*/ ncr5380_bus_read(ncr); - ncr5380_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->cur_bus)); ret = BUS_GETDATA(ncr->cur_bus); + ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret); } break; @@ -595,7 +608,9 @@ ncr5380_read(uint16_t port, ncr_t *ncr) break; case 6: - ret = ncr->tx_data; + ncr5380_log("Read: Input Data.\n"); + ncr5380_bus_read(ncr); + ret = BUS_GETDATA(ncr->cur_bus); break; case 7: /* reset Parity/Interrupt */ diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 6622ec59a..997e8f152 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -148,6 +148,12 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) ncr400->busy = 1; if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0))) timer_on_auto(&ncr400->timer, ncr->period / 250.0); + else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { + if (scsi_device_get_callback(dev) > 0.0) + timer_on_auto(&ncr400->timer, 100.0); + else + timer_on_auto(&ncr400->timer, 40.0); + } } } break; @@ -181,13 +187,14 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); if (ncr->mode & MODE_MONITOR_BUSY) - timer_on_auto(&ncr400->timer, ncr->period); + timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0); else if (scsi_device_get_callback(dev) > 0.0) timer_on_auto(&ncr400->timer, 40.0); else timer_on_auto(&ncr400->timer, ncr->period); - ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_complete, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); + ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", + ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); } break; @@ -244,6 +251,12 @@ ncr53c400_read(uint32_t addr, void *priv) ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl); if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0)) timer_on_auto(&ncr400->timer, ncr->period / 250.0); + else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { + if (scsi_device_get_callback(dev) > 0.0) + timer_on_auto(&ncr400->timer, 100.0); + else + timer_on_auto(&ncr400->timer, 40.0); + } } } break; @@ -397,16 +410,20 @@ t130b_in(uint16_t port, void *priv) } static void -ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv)) +ncr53c400_dma_mode_ext(void *priv, void *ext_priv) { - ncr_t *ncr = (ncr_t *) priv; + ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; + ncr_t *ncr = (ncr_t *) priv; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!(ncr->mode & MODE_DMA)) { - ncr53c400_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; + ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded); + if (!ncr400->block_count_loaded) { + if (!(ncr->mode & MODE_DMA)) { + ncr53c400_log("No DMA mode\n"); + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } } } @@ -474,6 +491,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count); if (!ncr400->block_count) { + ncr->dma_mode = DMA_IDLE; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -527,6 +545,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); if (!ncr400->block_count) { + ncr->dma_mode = DMA_IDLE; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; @@ -544,6 +563,7 @@ ncr53c400_callback(void *priv) break; } + ncr53c400_log("Bus Read.\n"); ncr5380_bus_read(ncr); if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index c878bbb91..faad87052 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -287,6 +287,7 @@ write_again: t128->block_count = (t128->block_count - 1) & 0xff; t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); if (!t128->block_count) { + ncr->dma_mode = DMA_IDLE; t128->block_loaded = 0; t128_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -343,6 +344,7 @@ read_again: t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]); if (!t128->block_count) { t128->block_loaded = 0; + ncr->dma_mode = DMA_IDLE; t128_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; timer_stop(&t128->timer); From 4f15889638cb38a51e790c49391535040e13d10a Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 23:09:03 +0000 Subject: [PATCH 0062/1190] fix compile by fixing capitalisation --- src/include/86box/nv/vid_nv_rivatimer.h | 2 +- src/timer.c | 2 +- src/video/nv/nv_rivatimer.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/86box/nv/vid_nv_rivatimer.h b/src/include/86box/nv/vid_nv_rivatimer.h index a4fe85e92..59f6cfebf 100644 --- a/src/include/86box/nv/vid_nv_rivatimer.h +++ b/src/include/86box/nv/vid_nv_rivatimer.h @@ -47,7 +47,7 @@ So I decided to create this timer that is completely separate from the CPU Core. #include #include #include -#include <86Box/86box.h> +#include <86box/86box.h> #ifdef _WIN32 #include diff --git a/src/timer.c b/src/timer.c index 2b92a1958..a3a7c9efb 100644 --- a/src/timer.c +++ b/src/timer.c @@ -4,7 +4,7 @@ #include #include <86box/86box.h> #include <86box/timer.h> -#include <86Box/nv/vid_nv_rivatimer.h> +#include <86box/nv/vid_nv_rivatimer.h> uint64_t TIMER_USEC; uint32_t timer_target; diff --git a/src/video/nv/nv_rivatimer.c b/src/video/nv/nv_rivatimer.c index 44e5901d1..12d40c026 100644 --- a/src/video/nv/nv_rivatimer.c +++ b/src/video/nv/nv_rivatimer.c @@ -22,7 +22,7 @@ Since Windows XP, QueryPerformanceCounter and QueryPerformanceFrequency cannot f */ -#include <86Box/nv/vid_nv_rivatimer.h> +#include <86box/nv/vid_nv_rivatimer.h> #ifdef _WIN32 LARGE_INTEGER performance_frequency; From 31207c98d656e2a68fd9c4b1d7d5c4774bdaa6a2 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 23:15:43 +0000 Subject: [PATCH 0063/1190] hopefully the final issue...fix missing prototype --- src/86box.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/86box.c b/src/86box.c index b5a4de15e..219535c84 100644 --- a/src/86box.c +++ b/src/86box.c @@ -266,6 +266,9 @@ static int32_t log_cycles = 0; static int seen = 0; static int suppr_seen = 1; + +// Functions only used in this translation unit +void pclog_ensure_stdlog_open(); #endif /* @@ -273,6 +276,7 @@ static int suppr_seen = 1; */ void pclog_ensure_stdlog_open() { +#ifndef RELEASE_BUILD if (stdlog == NULL) { if (log_path[0] != '\0') { stdlog = plat_fopen(log_path, "w"); @@ -281,6 +285,7 @@ void pclog_ensure_stdlog_open() } else stdlog = stdout; } +#endif } /* From fa3fb7ecccb0c73cb0c33f74865eb65621f911d8 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Sun, 12 Jan 2025 23:22:22 +0000 Subject: [PATCH 0064/1190] explicit void... --- src/86box.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/86box.c b/src/86box.c index 219535c84..85cbb9957 100644 --- a/src/86box.c +++ b/src/86box.c @@ -268,13 +268,13 @@ static int seen = 0; static int suppr_seen = 1; // Functions only used in this translation unit -void pclog_ensure_stdlog_open(); +void pclog_ensure_stdlog_open(void); #endif /* Ensures STDLOG is open for pclog_ex and pclog_ex_cyclic */ -void pclog_ensure_stdlog_open() +void pclog_ensure_stdlog_open(void) { #ifndef RELEASE_BUILD if (stdlog == NULL) { From be878ede582870a70532890b85fbd43e6f242e8d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 13 Jan 2025 00:56:04 +0100 Subject: [PATCH 0065/1190] Okay, maybe for the 53c400 only so. Based on my tests, the former 5380 commit will apply to the 53c400 only, for now... --- src/scsi/scsi_ncr5380.c | 4 ++-- src/scsi/scsi_t128.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 092cc08e9..0c3af9282 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -197,7 +197,7 @@ ncr5380_bus_read(ncr_t *ncr) phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); if (phase == SCSI_PHASE_DATA_IN) { - if (ncr->dma_mode == DMA_IDLE) { + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext) { ncr5380_log("Phase Data In.\n"); if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; @@ -210,7 +210,7 @@ ncr5380_bus_read(ncr_t *ncr) ncr->state = STATE_IDLE; ncr->cur_bus &= ~BUS_BSY; } else { - if (ncr->dma_mode == DMA_IDLE) + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext) ncr->state = STATE_DATAOUT; } } else if (phase == SCSI_PHASE_STATUS) { diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index faad87052..c878bbb91 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -287,7 +287,6 @@ write_again: t128->block_count = (t128->block_count - 1) & 0xff; t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); if (!t128->block_count) { - ncr->dma_mode = DMA_IDLE; t128->block_loaded = 0; t128_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -344,7 +343,6 @@ read_again: t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]); if (!t128->block_count) { t128->block_loaded = 0; - ncr->dma_mode = DMA_IDLE; t128_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; timer_stop(&t128->timer); From f039fce49749779cf70d4f83545fd6d5da761f72 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 04:16:08 +0100 Subject: [PATCH 0066/1190] PIC: Signal to the CPU to end the block on IRR read, fixes stalls in waiting for IRQ, fixes #5108. --- src/pic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pic.c b/src/pic.c index 82905261a..f8e83c40b 100644 --- a/src/pic.c +++ b/src/pic.c @@ -17,6 +17,7 @@ * Copyright 2015-2020 Andrew Jenner. * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include @@ -491,12 +492,13 @@ pic_read(uint16_t addr, void *priv) else dev->data_bus = 0x00; #endif - } + } else + cpu_block_end = 1; /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled, simply read whatever is currently on the data bus. */ } - pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus); + pic_log("pic_read(%04X) = %02X\n", addr, dev->data_bus); return dev->data_bus; } From 123ff3b5e767864e8f1381ed18aeb3fa17966bbd Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 04:35:23 +0100 Subject: [PATCH 0067/1190] Fix NEC Vx0 INS*/OUS* timings calculation. --- src/cpu/808x.c | 53 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index d815551ae..0c1fb0f4d 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1634,28 +1634,55 @@ cpu_data_opff_rm(void) } } +uint8_t +cpu_inb(uint16_t port) +{ + uint8_t ret; + + wait(4, 0); + old_cycles = cycles; + + ret = inb(port); + + resub_cycles(); +} + uint16_t cpu_inw(uint16_t port) { - if (is8086 && !(port & 1)) { - wait(4, 0); - } else { - wait(8, 0); - } + uint16_t ret; - return inw(port); + if (is8086 && !(port & 1)) + wait(4, 0); + else + wait(8, 0); + + ret = inw(port); + + resub_cycles(); +} + +void +cpu_outb(uint16_t port, uint16_t val) +{ + wait(4, 0); + + outb(port, val); + + resub_cycles(); } void cpu_outw(uint16_t port, uint16_t val) { - if (is8086 && !(port & 1)) { + if (is8086 && !(port & 1)) wait(4, 0); - } else { + else wait(8, 0); - } - return outw(port, val); + outw(port, val); + + resub_cycles(); } /* Executes instructions up to the specified number of cycles. */ @@ -1804,8 +1831,7 @@ execx86(int cycs) writememw(es, DI, cpu_inw(DX)); DI += (cpu_state.flags & D_FLAG) ? -2 : 2; } else { - wait(4, 0); - writememb(es, DI, inb(DX)); + writememb(es, DI, cpu_inb(DX)); DI += (cpu_state.flags & D_FLAG) ? -1 : 1; } @@ -1833,8 +1859,7 @@ execx86(int cycs) cpu_outw(DX, readmemw(dest_seg, SI)); SI += (cpu_state.flags & D_FLAG) ? -2 : 2; } else { - wait(4, 0); - outb(DX, readmemb(dest_seg + SI)); + cpu_outb(DX, readmemb(dest_seg + SI)); SI += (cpu_state.flags & D_FLAG) ? -1 : 1; } if (in_rep == 0) From b1f94abc27131792c4b33be5588a736ac1f3c916 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 05:01:00 +0100 Subject: [PATCH 0068/1190] Fixed the fix. --- src/cpu/808x.c | 52 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 0c1fb0f4d..f37672a5c 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1637,52 +1637,72 @@ cpu_data_opff_rm(void) uint8_t cpu_inb(uint16_t port) { + int old_cycles = cycles; uint8_t ret; - wait(4, 0); + wait(is_mazovia ? 5 : 4, 1); old_cycles = cycles; ret = inb(port); - resub_cycles(); + resub_cycles(old_cycles); + + return ret; } uint16_t cpu_inw(uint16_t port) { + int old_cycles = cycles; uint16_t ret; - if (is8086 && !(port & 1)) - wait(4, 0); - else - wait(8, 0); + wait(is_mazovia ? 5 : 4, 1); + if (is8086 && !(port & 1)) { + old_cycles = cycles; + ret = inw(port); + } else { + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + ret = inb(port++); + ret |= (inb(port) << 8); + } - ret = inw(port); + resub_cycles(old_cycles); - resub_cycles(); + return ret; } void cpu_outb(uint16_t port, uint16_t val) { - wait(4, 0); + int old_cycles = cycles; + + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; outb(port, val); - resub_cycles(); + resub_cycles(old_cycles); } void cpu_outw(uint16_t port, uint16_t val) { - if (is8086 && !(port & 1)) - wait(4, 0); - else - wait(8, 0); + int old_cycles = cycles; - outw(port, val); + wait(is_mazovia ? 5 : 4, 1); - resub_cycles(); + if (is8086 && !(port & 1)) { + old_cycles = cycles; + outw(port, val); + } else { + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + outb(port++, val); + outb(port, val >> 8); + } + + resub_cycles(old_cycles); } /* Executes instructions up to the specified number of cycles. */ From ec175738ee48899770c7275179beb2746dc26312 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 05:38:10 +0100 Subject: [PATCH 0069/1190] FIX timings of SYSCALL/SYSRET/SYSENTER/SYSEXIT/FXSAVE/FXSTOR. --- src/cpu/x86_ops_amd.h | 12 ++---------- src/cpu/x86_ops_i686.h | 28 ++++++++++------------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index 9e6bcce55..54da4a79d 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -22,12 +22,8 @@ opSYSCALL(uint32_t fetchdat) ret = syscall_op(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -41,12 +37,8 @@ opSYSRET(uint32_t fetchdat) ret = sysret(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index 5e5dc3c7c..a67571875 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -18,12 +18,8 @@ opSYSENTER(uint32_t fetchdat) { int ret = sysenter(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -33,12 +29,8 @@ opSYSEXIT(uint32_t fetchdat) { int ret = sysexit(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -118,7 +110,8 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) fpu_state.swd &= ~(FPU_SW_Summary | FPU_SW_Backward); } - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(1); } else { /* FXSAVE */ writememw(easeg, cpu_state.eaaddr, i387_get_control_word()); @@ -163,7 +156,7 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) writememw(easeg, cpu_state.eaaddr + (index * 16) + 40, fp.signExp); } - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(1); } return cpu_state.abrt; @@ -327,7 +320,8 @@ fx_save_stor_common(uint32_t fetchdat, int bits) } } - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(1); } else { /* FXSAVE */ if ((twd & 0x0003) != 0x0003) @@ -372,7 +366,7 @@ fx_save_stor_common(uint32_t fetchdat, int bits) cpu_state.eaaddr = old_eaaddr; - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(1); } return cpu_state.abrt; @@ -400,8 +394,7 @@ static int opHINT_NOP_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - CLOCK_CYCLES((is486) ? 1 : 3); - PREFETCH_RUN(3, 1, -1, 0, 0, 0, 0, 0); + CLOCK_CYCLES(1); return 0; } @@ -409,7 +402,6 @@ static int opHINT_NOP_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - CLOCK_CYCLES((is486) ? 1 : 3); - PREFETCH_RUN(3, 1, -1, 0, 0, 0, 0, 0); + CLOCK_CYCLES(1); return 0; } From ad056b136c1413fdf371114d9524186312cde807 Mon Sep 17 00:00:00 2001 From: eddmanx Date: Mon, 13 Jan 2025 17:09:01 +0400 Subject: [PATCH 0070/1190] Update README.md - added the Avalonia86 manager --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ce38632e6..c01a852b5 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ It is also recommended to use a manager application with 86Box for easier handli * [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only) * [86Box Manager X](https://github.com/RetBox/86BoxManagerX) by [xafero](https://github.com/xafero) (Cross platform Port of 86Box Manager using Avalonia) +* [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux) * [sl86](https://github.com/DDXofficial/sl86) by [DDX](https://github.com/DDXofficial) (Command-line 86Box machine manager written in Python) * [Linbox-qt5](https://github.com/Dungeonseeker/linbox-qt5) by [Dungeonseeker](https://github.com/Dungeonseeker/) (Linux focused, should work on Windows though untested) * [MacBox for 86Box](https://github.com/Moonif/MacBox) by [Moonif](https://github.com/Moonif) (MacOS only) From f3016bc93eb3361cc389a30be71cd274da5382e7 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Mon, 13 Jan 2025 22:48:44 +0700 Subject: [PATCH 0071/1190] Added onboard sound to 4 machines --- src/machine/m_at_socket7.c | 4 ++++ src/machine/m_at_socket7_3v.c | 4 ++++ src/machine/m_at_socket8.c | 8 ++++++++ src/machine/machine_table.c | 8 ++++---- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index f80d2d421..52b16c212 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -849,6 +849,10 @@ machine_at_gw2kte_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + + if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available()) + machine_snd = device_add(machine_get_snd_device(machine)); + device_add(&i430vx_device); device_add(&piix3_device); device_add(&fdc37c932fr_device); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 40ae221a0..4b980f2b0 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -694,6 +694,10 @@ machine_at_gw2kma_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + + if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available()) + machine_snd = device_add(machine_get_snd_device(machine)); + device_add(&i430vx_device); device_add(&piix3_device); device_add(&fdc37c932fr_device); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index e6f78f6a2..59c412447 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -249,6 +249,10 @@ machine_at_vs440fx_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); @@ -283,6 +287,10 @@ machine_at_gw2kvenus_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 330b7d52a..b9ee8af40 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13989,7 +13989,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14004,7 +14004,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &cs4236b_device, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ @@ -14113,7 +14113,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14128,7 +14128,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &cs4236b_device, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ From a7472005ba746d9522e8b45657bd728f72577edb Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Mon, 13 Jan 2025 23:00:29 +0700 Subject: [PATCH 0072/1190] Added Maxtium Computer SmartBX --- src/include/86box/machine.h | 1 + src/machine/m_at_socket370.c | 32 ++++++++++++++++++++++++++++ src/machine/machine_table.c | 41 ++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 0cd3564ee..6edcb6ac4 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -839,6 +839,7 @@ extern int machine_at_atc7020bxii_init(const machine_t *); extern int machine_at_m773_init(const machine_t *); extern int machine_at_ambx133_init(const machine_t *); extern int machine_at_awo671r_init(const machine_t *); +extern int machine_at_smartbx_init(const machine_t *); extern int machine_at_63a1_init(const machine_t *); extern int machine_at_s370sba_init(const machine_t *); extern int machine_at_apas3_init(const machine_t *); diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 9be2d45b8..3513859cb 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -402,6 +402,38 @@ machine_at_awo671r_init(const machine_t *model) return ret; } +int +machine_at_smartbx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/smartbx/sbx107.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + device_add(&i440bx_device); + device_add(&piix4e_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83977ef_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + int machine_at_63a1_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b9ee8af40..d3dcd47f4 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15758,6 +15758,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440BX] Maxtium Computer SmartBX", + .internal_name = "smartbx", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_INTEL_440BX, + .init = machine_at_smartbx_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 100000000, + .min_voltage = 1300, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_A97 | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 393216, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 440ZX */ /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC From 49aa0edd2256a5adcad2cace7067281bf5f1b951 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Mon, 13 Jan 2025 23:14:11 +0700 Subject: [PATCH 0073/1190] Added Dell Dimension X30 --- src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 22 ++++++++++++++++++++ src/machine/machine_table.c | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 6edcb6ac4..4e4b2e558 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -519,6 +519,7 @@ extern int machine_at_cs4031_init(const machine_t *); extern int machine_at_pb410a_init(const machine_t *); extern int machine_at_decpclpv_init(const machine_t *); +extern int machine_at_dellx30_init(const machine_t *); extern int machine_at_acerv10_init(const machine_t *); extern int machine_at_acera1g_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index d3c7a21d2..dbe91de51 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -482,6 +482,28 @@ machine_at_decpclpv_init(const machine_t *model) return ret; } +int +machine_at_dellx30_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/dellx30/shk2a03.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&sis_85c461_device); + device_add(&keyboard_ps2_acer_pci_device); + device_add(&fdc37c665_ide_device); + device_add(&ide_opti611_vlb_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + static void machine_at_ali1429_common_init(const machine_t *model, int is_green) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d3dcd47f4..75198b3e3 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6936,6 +6936,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has FDC37C665 SIO with OPTi 82c611 IDE onboard */ + { + .name = "[SiS 461] Dell Dimension X30", + .internal_name = "dellx30", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_SIS_461, /* Chipset relabeled as Micronics MIC 471 */ + .init = machine_at_dellx30_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE | MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. The photo of the board shows an AMIKey KBC which is indeed F. */ From 3b4d6d1f9e708b3599c756c33db238ab33021a7b Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Mon, 13 Jan 2025 23:33:20 +0700 Subject: [PATCH 0074/1190] Forgotten one change --- src/machine/machine_table.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 75198b3e3..cac50fbcf 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11240,7 +11240,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 131072, @@ -11255,7 +11255,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &sb_vibra16c_onboard_device, .net_device = NULL }, @@ -12263,7 +12263,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 131072, @@ -12278,7 +12278,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &sb_vibra16c_onboard_device, .net_device = NULL }, /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix From d39a8b9867cee2879c05cae606ff7715708223a2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 17:36:56 +0100 Subject: [PATCH 0075/1190] Reverted the PIC fix as it was apparently a red herring. --- src/pic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pic.c b/src/pic.c index f8e83c40b..fa7ff3662 100644 --- a/src/pic.c +++ b/src/pic.c @@ -492,8 +492,7 @@ pic_read(uint16_t addr, void *priv) else dev->data_bus = 0x00; #endif - } else - cpu_block_end = 1; + } /* If A0 = 0, VIA shadow is disabled, and poll mode is disabled, simply read whatever is currently on the data bus. */ } From c924a60be7abb1b74644fb7fb375632fc375824f Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Tue, 14 Jan 2025 00:06:25 +0700 Subject: [PATCH 0076/1190] Removed flash device from X30 Fixes BootBlock error --- src/machine/m_at_386dx_486.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index dbe91de51..28e5c8549 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -499,7 +499,6 @@ machine_at_dellx30_init(const machine_t *model) device_add(&keyboard_ps2_acer_pci_device); device_add(&fdc37c665_ide_device); device_add(&ide_opti611_vlb_device); - device_add(&intel_flash_bxt_device); return ret; } From b002fed6023890e0056ea5e54aff74260547938a Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Tue, 14 Jan 2025 00:13:54 +0700 Subject: [PATCH 0077/1190] Removed non-working SmartBX --- src/include/86box/machine.h | 1 - src/machine/m_at_socket370.c | 32 ---------------------------- src/machine/machine_table.c | 41 ------------------------------------ 3 files changed, 74 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 4e4b2e558..48e9be1c3 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -840,7 +840,6 @@ extern int machine_at_atc7020bxii_init(const machine_t *); extern int machine_at_m773_init(const machine_t *); extern int machine_at_ambx133_init(const machine_t *); extern int machine_at_awo671r_init(const machine_t *); -extern int machine_at_smartbx_init(const machine_t *); extern int machine_at_63a1_init(const machine_t *); extern int machine_at_s370sba_init(const machine_t *); extern int machine_at_apas3_init(const machine_t *); diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 3513859cb..9be2d45b8 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -402,38 +402,6 @@ machine_at_awo671r_init(const machine_t *model) return ret; } -int -machine_at_smartbx_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/smartbx/sbx107.bin", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init_ex(model, 2); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); - device_add(&i440bx_device); - device_add(&piix4e_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&w83977ef_device); - device_add(&sst_flash_39sf020_device); - spd_register(SPD_TYPE_SDRAM, 0x7, 256); - - return ret; -} - int machine_at_63a1_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index cac50fbcf..1aeb28526 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15798,47 +15798,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC - firmware. */ - { - .name = "[i440BX] Maxtium Computer SmartBX", - .internal_name = "smartbx", - .type = MACHINE_TYPE_SOCKET370, - .chipset = MACHINE_CHIPSET_INTEL_440BX, - .init = machine_at_smartbx_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET370, - .block = CPU_BLOCK_NONE, - .min_bus = 66666667, - .max_bus = 100000000, - .min_voltage = 1300, - .max_voltage = 3500, - .min_multi = 1.5, - .max_multi = 8.0 - }, - .bus_flags = MACHINE_PS2_A97 | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, - .ram = { - .min = 8192, - .max = 393216, - .step = 8192 - }, - .nvrmask = 255, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* 440ZX */ /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC From ffe6af94cfaa48e16cd6e5921705b58091fc6790 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Tue, 14 Jan 2025 00:26:05 +0700 Subject: [PATCH 0078/1190] Removed non-working X30 --- src/include/86box/machine.h | 1 - src/machine/m_at_386dx_486.c | 21 ------------------- src/machine/machine_table.c | 40 ------------------------------------ 3 files changed, 62 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 48e9be1c3..0cd3564ee 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -519,7 +519,6 @@ extern int machine_at_cs4031_init(const machine_t *); extern int machine_at_pb410a_init(const machine_t *); extern int machine_at_decpclpv_init(const machine_t *); -extern int machine_at_dellx30_init(const machine_t *); extern int machine_at_acerv10_init(const machine_t *); extern int machine_at_acera1g_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 28e5c8549..d3c7a21d2 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -482,27 +482,6 @@ machine_at_decpclpv_init(const machine_t *model) return ret; } -int -machine_at_dellx30_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/dellx30/shk2a03.bin", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - device_add(&sis_85c461_device); - device_add(&keyboard_ps2_acer_pci_device); - device_add(&fdc37c665_ide_device); - device_add(&ide_opti611_vlb_device); - - return ret; -} - static void machine_at_ali1429_common_init(const machine_t *model, int is_green) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 1aeb28526..baba2723c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6936,46 +6936,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has FDC37C665 SIO with OPTi 82c611 IDE onboard */ - { - .name = "[SiS 461] Dell Dimension X30", - .internal_name = "dellx30", - .type = MACHINE_TYPE_486_S3, - .chipset = MACHINE_CHIPSET_SIS_461, /* Chipset relabeled as Micronics MIC 471 */ - .init = machine_at_dellx30_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET3, - .block = CPU_BLOCK_NONE, - .min_bus = 0, - .max_bus = 0, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_PS2_VLB, - .flags = MACHINE_IDE | MACHINE_APM, - .ram = { - .min = 1024, - .max = 65536, - .step = 1024 - }, - .nvrmask = 127, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* The BIOS string ends in -U, unless command 0xA1 (AMIKey get version) returns an 'F', in which case, it ends in -F, so it has an AMIKey F KBC firmware. The photo of the board shows an AMIKey KBC which is indeed F. */ From 29ec9fa9ba5bb383dbda07716a9630e822442e55 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 13 Jan 2025 21:10:12 +0100 Subject: [PATCH 0079/1190] More NCR53c400 fixes (January 13th, 2025) Getting on my nerves, NCR 5380... --- src/include/86box/scsi_ncr5380.h | 1 + src/scsi/scsi_ncr5380.c | 9 +++++---- src/scsi/scsi_ncr53c400.c | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index 55692075b..09307fed6 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -104,6 +104,7 @@ typedef struct ncr_t { int state; int clear_req; int wait_data; + int wait_data_back; int wait_complete; int command_pos; int data_pos; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 0c3af9282..c5fddc801 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -197,7 +197,7 @@ ncr5380_bus_read(ncr_t *ncr) phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); if (phase == SCSI_PHASE_DATA_IN) { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext) { + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext || (ncr->wait_data_back == 1)) { ncr5380_log("Phase Data In.\n"); if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; @@ -210,11 +210,12 @@ ncr5380_bus_read(ncr_t *ncr) ncr->state = STATE_IDLE; ncr->cur_bus &= ~BUS_BSY; } else { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext) + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext || (ncr->wait_data_back == 1)) ncr->state = STATE_DATAOUT; } } else if (phase == SCSI_PHASE_STATUS) { ncr5380_log("Phase Status.\n"); + ncr->wait_data_back = 0; ncr->cur_bus |= BUS_REQ; ncr->state = STATE_STATUS; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; @@ -359,7 +360,7 @@ ncr5380_bus_update(ncr_t *ncr, int bus) ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); ncr->timer(ncr->priv, ncr->period); } else { - ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); + pclog("DMA mode IN=%d.\n", ncr->data_pos); ncr->clear_req = 3; } @@ -495,7 +496,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 7: /* start DMA Initiator Receive */ - ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); + pclog("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; if (ncr->dma_initiator_receive_ext) diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 997e8f152..e028c7b42 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -193,6 +193,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) else timer_on_auto(&ncr400->timer, ncr->period); + ncr->wait_data_back = ncr->wait_data; ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); } From c9985798d3f785ef09c0ac053d25a554b95d15e1 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 13 Jan 2025 22:04:29 +0100 Subject: [PATCH 0080/1190] Remove excess logs. --- src/scsi/scsi_ncr5380.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index c5fddc801..e5dff88f8 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -360,7 +360,7 @@ ncr5380_bus_update(ncr_t *ncr, int bus) ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); ncr->timer(ncr->priv, ncr->period); } else { - pclog("DMA mode IN=%d.\n", ncr->data_pos); + ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); ncr->clear_req = 3; } @@ -496,7 +496,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 7: /* start DMA Initiator Receive */ - pclog("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); + ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; if (ncr->dma_initiator_receive_ext) From 40c52048a60057fcee0e31baa186ca7980881670 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Mon, 13 Jan 2025 23:20:57 +0100 Subject: [PATCH 0081/1190] Added a couple of Quantum Fireball SE/EX drives --- src/disk/hdd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index b861b5e50..5243f016b 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -448,9 +448,13 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1080AT", .internal_name = "TM10A462", .model = "QUANTUM FIREBALL TM1.0A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1.2AT", .internal_name = "TM12A012", .model = "QUANTUM FIREBALL TM1.2A", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 2, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball EX5.1AT", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-2] Samsung PLS-31274A", .internal_name = "PLS31274A", .model = "SAMSUNG PLS-31274A", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 45, .track_seek_ms = 4.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, { .name = "[ATA-2] Samsung Winner-1", .internal_name = "WNR31601A", .model = "SAMSUNG WNR-31601A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Seagate Medalist (ST3780A)", .internal_name = "ST3780A", .model = "ST3780A", .zones = 8, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, From 5b101aad81915c64b677c2e92cd5c60be809bd97 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 13 Jan 2025 23:22:37 +0100 Subject: [PATCH 0082/1190] AT KBC: Fast track command AE (enable keyboard) because the LG MultiNet sends command A7 immediately after it, fixes keyboard lock-ups in its CMOS Setup. --- src/device/kbc_at.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 5c3c9ac6e..74be59017 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2127,6 +2127,13 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) } else if (fast_reset && ((val & 0xf0) == 0xf0)) { pulse_output(dev, val & 0x0f); + dev->state = STATE_MAIN_IBF; + return; + } else if (val == 0xae) { + /* Fast track it because of the LG MultiNet. */ + kbc_at_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + dev->state = STATE_MAIN_IBF; return; } From b1f54b9b84b0a653808fef789be987b34cfcbe03 Mon Sep 17 00:00:00 2001 From: starfrost013 Date: Tue, 14 Jan 2025 00:31:13 +0000 Subject: [PATCH 0083/1190] Move cyclical logging to the new logging system per obat feedback. --- src/86box.c | 113 +------------------------- src/include/86box/86box.h | 1 - src/include/86box/log.h | 7 ++ src/log.c | 167 +++++++++++++++++++++++++++++++++++--- 4 files changed, 162 insertions(+), 126 deletions(-) diff --git a/src/86box.c b/src/86box.c index 85cbb9957..97c211bee 100644 --- a/src/86box.c +++ b/src/86box.c @@ -254,14 +254,9 @@ static volatile atomic_int pause_ack = 0; #ifndef RELEASE_BUILD -#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ -#define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ -#define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ +#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ static char buff[LOG_SIZE_BUFFER]; -static char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; -static int32_t cyclic_last_line = 0; -static int32_t log_cycles = 0; static int seen = 0; @@ -322,112 +317,6 @@ pclog_ex(const char *fmt, va_list ap) } -/* -Starfrost, 7-8 January 2025: - -For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. - -Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm -*/ -void -pclog_ex_cyclic(const char* fmt, va_list ap) -{ -#ifndef RELEASE_BUILD - char temp[LOG_SIZE_BUFFER]; - - cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; - - vsprintf(temp, fmt, ap); - - pclog_ensure_stdlog_open(); - - strncpy(cyclic_buff[cyclic_last_line], temp, LOG_SIZE_BUFFER); - - uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; - - // Random numbers - uint32_t base = 257; - uint32_t mod = 1000000007; - - uint32_t repeat_order = 0; - bool is_cycle = false; - - // compute the set of hashes for the current log buffer - for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) - { - if (cyclic_buff[log_line][0] == '\0') - continue; // skip - - for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) - { - hashes[log_line] = hashes[log_line] * base + cyclic_buff[log_line][log_line_char] % mod; - } - } - - - // Now see if there are real cycles... - // We implement a minimum repeat size. - for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) - { - //TODO: Log what we need for cycle 1. - //TODO: Command line option that lets us turn off this behaviour. - for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) - { - if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) - { - repeat_order = check_size; - break; - } - } - - is_cycle = (repeat_order != 0); - - // if there still is a cycle.. - if (is_cycle) - break; - - } - - if (is_cycle) - { - if (cyclic_last_line % repeat_order == 0) - { - log_cycles++; - - if (log_cycles == 1) - { - // 'Replay' the last few log entries so they actually show up - // Todo: is this right? - - for (uint32_t index = cyclic_last_line - 1; index > (cyclic_last_line - repeat_order); index--) - { - // *very important* to prevent out of bounds index - uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; - fprintf(stdlog, "%s", cyclic_buff[real_index]); - - } - - fprintf(stdlog, "%s", temp); // allow normal logging - } - - - if (log_cycles > 1 && log_cycles < 100) - fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log_cycles); - else if (log_cycles == 100) - fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); - } - } - else - { - log_cycles = 0; - fprintf(stdlog, "%s", temp); - } - - cyclic_last_line++; - -#endif - -} void pclog_toggle_suppr(void) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 05c2a901e..96aeb645c 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -189,7 +189,6 @@ extern int config_changed; /* config has changed */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); extern void fatal_ex(const char *fmt, va_list ap); -extern void pclog_ex_cyclic(const char* fmt, va_list ap); #endif extern void pclog_toggle_suppr(void); #ifdef _MSC_VER diff --git a/src/include/86box/log.h b/src/include/86box/log.h index 9d3568069..7f0b96d60 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -12,9 +12,11 @@ * * Authors: Miran Grca, * Fred N. van Kempen, + * Connor Hyde * * Copyright 2021 Miran Grca. * Copyright 2021 Fred N. van Kempen. + * Copyright 2025 Connor Hyde. */ #ifndef EMU_LOG_H @@ -26,11 +28,16 @@ extern "C" { # endif +#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ +#define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ +#define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ + /* Function prototypes. */ extern void log_set_suppr_seen(void *priv, int suppr_seen); extern void log_set_dev_name(void *priv, char *dev_name); # ifdef HAVE_STDARG_H extern void log_out(void *priv, const char *fmt, va_list); +extern void log_out_cyclic(void* priv, const char *fmt, va_list); extern void log_fatal(void *priv, const char *fmt, ...); # endif extern void *log_open(char *dev_name); diff --git a/src/log.c b/src/log.c index b5267d70b..a4d84e616 100644 --- a/src/log.c +++ b/src/log.c @@ -12,12 +12,15 @@ * * Authors: Miran Grca, * Fred N. van Kempen, - * + * Connor Hyde + * * Copyright 2021 Miran Grca. * Copyright 2021 Fred N. van Kempen. + * Copyright 2025 Connor Hyde. */ #include #include +#include #include #include #include @@ -36,13 +39,31 @@ #ifndef RELEASE_BUILD typedef struct log_t { - char buff[1024]; - char *dev_name; - int seen; - int suppr_seen; + char buff[1024]; + char *dev_name; + int seen; + int suppr_seen; + char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; // Cyclical log buffer. This is 32kb, might calloc? + int32_t cyclic_last_line; + int32_t log_cycles; } log_t; extern FILE *stdlog; /* file to log output to */ +// Functions only used in this translation unit +void log_ensure_stdlog_open(void); + +void +log_ensure_stdlog_open(void) +{ + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } +} void log_set_suppr_seen(void *priv, int suppr_seen) @@ -91,14 +112,7 @@ log_out(void *priv, const char *fmt, va_list ap) if (strcmp(fmt, "") == 0) return; - if (stdlog == NULL) { - if (log_path[0] != '\0') { - stdlog = plat_fopen(log_path, "w"); - if (stdlog == NULL) - stdlog = stdout; - } else - stdlog = stdout; - } + log_ensure_stdlog_open(); vsprintf(temp, fmt, ap); if (log->suppr_seen && !strcmp(log->buff, temp)) @@ -117,6 +131,131 @@ log_out(void *priv, const char *fmt, va_list ap) fflush(stdlog); } + +/* +Starfrost, 7-8 January 2025: + +For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. + +Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm +*/ +void +log_out_cyclic(void* priv, const char* fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + // get our new logging system instance. + log_t* log = (log_t*)priv; + + // does the log actually exist? + if (!log) + return; + + // is the string empty? + if (fmt[0] == '\0') + return; + + // ensure stdlog is open + log_ensure_stdlog_open(); + + char temp[LOG_SIZE_BUFFER] = {0}; + + log->cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; + + vsprintf(temp, fmt, ap); + + log_copy(log, log->cyclic_buff[log->cyclic_last_line], temp, LOG_SIZE_BUFFER); + + uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; + + // Random numbers + uint32_t base = 257; + uint32_t mod = 1000000007; + + uint32_t repeat_order = 0; + bool is_cycle = false; + + // compute the set of hashes for the current log buffer + for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) + { + if (log->cyclic_buff[log_line][0] == '\0') + continue; // skip + + for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) + { + hashes[log_line] = hashes[log_line] * base + log->cyclic_buff[log_line][log_line_char] % mod; + } + } + + + // Now see if there are real cycles... + // We implement a minimum repeat size. + for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) + { + //TODO: Log what we need for cycle 1. + //TODO: Command line option that lets us turn off this behaviour. + for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) + { + if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) + { + repeat_order = check_size; + break; + } + } + + is_cycle = (repeat_order != 0); + + // if there still is a cycle.. + if (is_cycle) + break; + + } + + if (is_cycle) + { + if (log->cyclic_last_line % repeat_order == 0) + { + log->log_cycles++; + + if (log->log_cycles == 1) + { + // 'Replay' the last few log entries so they actually show up + // Todo: is this right? + + for (uint32_t index = log->cyclic_last_line - 1; index > (log->cyclic_last_line - repeat_order); index--) + { + // *very important* to prevent out of bounds index + uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; + log_copy(log, temp, log->cyclic_buff[real_index], LOG_SIZE_BUFFER); + + fprintf(stdlog, "%s", log->cyclic_buff[real_index]); + + } + + // restore the original line + log_copy(log, temp, log->cyclic_buff[log->cyclic_last_line], LOG_SIZE_BUFFER); + + fprintf(stdlog, "%s", temp); // allow normal logging + } + + + if (log->log_cycles > 1 && log->log_cycles < 100) + fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log->log_cycles); + else if (log->log_cycles == 100) + fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); + } + } + else + { + log->log_cycles = 0; + fprintf(stdlog, "%s", temp); + } + + log->cyclic_last_line++; + +#endif + +} + void log_fatal(void *priv, const char *fmt, ...) { @@ -145,6 +284,8 @@ log_open(char *dev_name) log->dev_name = dev_name; log->suppr_seen = 1; + log->cyclic_last_line = 0; + log->log_cycles = 0; return (void *) log; } From 8fda1aca83241f04d02cea5efe2db78d76a539a8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Jan 2025 01:35:22 +0100 Subject: [PATCH 0084/1190] Acer V35N: Do not add the NVR - it is already added by the Super I/O chip. --- src/machine/m_at_socket7.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index f80d2d421..2dbb83684 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -58,10 +58,6 @@ machine_at_acerv35n_init(const machine_t *model) return ret; machine_at_common_init_ex(model, 2); - /* Yes, it's called amstrad_mega_pc_nvr_device, but it's basically the - standard AT NVR, just initialized to 0x00's (perhaps that should be the - default behavior?). */ - device_add(&amstrad_megapc_nvr_device); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); From efd5a6a47483e454d2cf496c87488aee939c2f34 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Jan 2025 02:38:44 +0100 Subject: [PATCH 0085/1190] SCAMP: Fixed EMS memory states, fixes #1966. --- src/chipset/scamp.c | 140 ++++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 52 deletions(-) diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 122318862..00f9798cb 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -101,6 +101,8 @@ typedef struct scamp_t { int ram_interleaved[2]; int ibank_shift[2]; + int ram_flags[24]; + port_92_t *port_92; } scamp_t; @@ -593,6 +595,35 @@ scamp_ems_write(uint32_t addr, uint8_t val, void *priv) ram[addr] = val; } +static void +scamp_mem_update_state(scamp_t *dev, uint32_t addr, uint32_t size) +{ + uint8_t flags; + + if ((addr >= 0x000a0000) && (addr < 0x00100000)) { + flags = dev->ram_flags[(addr - 0x000a0000) >> 14]; + + if (flags & 4) + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else switch (flags & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + default: + break; + } + } +} + static void recalc_ems(scamp_t *dev) { @@ -630,34 +661,48 @@ recalc_ems(scamp_t *dev) if (new_mappings[segment] < (mem_size * 1024)) { mem_mapping_set_exec(&dev->ems_mappings[segment], ram + dev->mappings[segment]); mem_mapping_enable(&dev->ems_mappings[segment]); - } else + dev->ram_flags[segment] |= 0x04; + } else { mem_mapping_disable(&dev->ems_mappings[segment]); + dev->ram_flags[segment] &= 0xfb; + } + + scamp_mem_update_state(dev, 0xa0000 + segment * 0x4000, 0x4000); } } + + flushmmucache_nopc(); } static void -shadow_control(uint32_t addr, uint32_t size, int state, int ems_enable) +shadow_control(scamp_t *dev, uint32_t addr, uint32_t size, int state) { - if (ems_enable) - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else - switch (state) { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - default: - break; - } + dev->ram_flags[(addr - 0x000a0000) >> 14] &= 0xfc; + dev->ram_flags[(addr - 0x000a0000) >> 14] |= state; + + if (size == 0x8000) { + dev->ram_flags[((addr - 0x000a0000) >> 14) + 1] &= 0xfc; + dev->ram_flags[((addr - 0x000a0000) >> 14) + 1] |= state; + } + + switch (state) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + default: + break; + } + + scamp_mem_update_state(dev, addr, size); flushmmucache_nopc(); } @@ -669,47 +714,38 @@ shadow_recalc(scamp_t *dev) uint8_t caxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_CAXS]; uint8_t daxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_DAXS]; uint8_t feaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_FEAXS]; - uint32_t ems_enable; - - if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSENAB) { - if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSMAP) /*Axxx/Bxxx/Dxxx*/ - ems_enable = (dev->cfg_regs[CFG_EMSEN2] & 0xf) | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 4) | ((dev->cfg_regs[CFG_EMSEN2] & 0xf0) << 8); - else /*Cxxx/Dxxx/Exxx*/ - ems_enable = (dev->cfg_regs[CFG_EMSEN2] << 8) | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 16); - } else - ems_enable = 0; /*Enabling remapping will disable all shadowing*/ if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) mem_remap_top(384); - shadow_control(0xa0000, 0x4000, abaxs & 3, ems_enable & 0x00001); - shadow_control(0xa0000, 0x4000, abaxs & 3, ems_enable & 0x00002); - shadow_control(0xa8000, 0x4000, (abaxs >> 2) & 3, ems_enable & 0x00004); - shadow_control(0xa8000, 0x4000, (abaxs >> 2) & 3, ems_enable & 0x00008); + shadow_control(dev, 0xa0000, 0x4000, abaxs & 3); + shadow_control(dev, 0xa0000, 0x4000, abaxs & 3); + shadow_control(dev, 0xa8000, 0x4000, (abaxs >> 2) & 3); + shadow_control(dev, 0xa8000, 0x4000, (abaxs >> 2) & 3); - shadow_control(0xb0000, 0x4000, (abaxs >> 4) & 3, ems_enable & 0x00010); - shadow_control(0xb0000, 0x4000, (abaxs >> 4) & 3, ems_enable & 0x00020); - shadow_control(0xb8000, 0x4000, (abaxs >> 6) & 3, ems_enable & 0x00040); - shadow_control(0xb8000, 0x4000, (abaxs >> 6) & 3, ems_enable & 0x00080); + shadow_control(dev, 0xb0000, 0x4000, (abaxs >> 4) & 3); + shadow_control(dev, 0xb0000, 0x4000, (abaxs >> 4) & 3); + shadow_control(dev, 0xb8000, 0x4000, (abaxs >> 6) & 3); + shadow_control(dev, 0xb8000, 0x4000, (abaxs >> 6) & 3); - shadow_control(0xc0000, 0x4000, caxs & 3, ems_enable & 0x00100); - shadow_control(0xc4000, 0x4000, (caxs >> 2) & 3, ems_enable & 0x00200); - shadow_control(0xc8000, 0x4000, (caxs >> 4) & 3, ems_enable & 0x00400); - shadow_control(0xcc000, 0x4000, (caxs >> 6) & 3, ems_enable & 0x00800); + shadow_control(dev, 0xc0000, 0x4000, caxs & 3); + shadow_control(dev, 0xc4000, 0x4000, (caxs >> 2) & 3); + shadow_control(dev, 0xc8000, 0x4000, (caxs >> 4) & 3); + shadow_control(dev, 0xcc000, 0x4000, (caxs >> 6) & 3); - shadow_control(0xd0000, 0x4000, daxs & 3, ems_enable & 0x01000); - shadow_control(0xd4000, 0x4000, (daxs >> 2) & 3, ems_enable & 0x02000); - shadow_control(0xd8000, 0x4000, (daxs >> 4) & 3, ems_enable & 0x04000); - shadow_control(0xdc000, 0x4000, (daxs >> 6) & 3, ems_enable & 0x08000); + shadow_control(dev, 0xd0000, 0x4000, daxs & 3); + shadow_control(dev, 0xd4000, 0x4000, (daxs >> 2) & 3); + shadow_control(dev, 0xd8000, 0x4000, (daxs >> 4) & 3); + shadow_control(dev, 0xdc000, 0x4000, (daxs >> 6) & 3); - shadow_control(0xe0000, 0x4000, feaxs & 3, ems_enable & 0x10000); - shadow_control(0xe4000, 0x4000, feaxs & 3, ems_enable & 0x20000); - shadow_control(0xe8000, 0x4000, (feaxs >> 2) & 3, ems_enable & 0x40000); - shadow_control(0xec000, 0x4000, (feaxs >> 2) & 3, ems_enable & 0x80000); + shadow_control(dev, 0xe0000, 0x4000, feaxs & 3); + shadow_control(dev, 0xe4000, 0x4000, feaxs & 3); + shadow_control(dev, 0xe8000, 0x4000, (feaxs >> 2) & 3); + shadow_control(dev, 0xec000, 0x4000, (feaxs >> 2) & 3); - shadow_control(0xf0000, 0x8000, (feaxs >> 4) & 3, 0); - shadow_control(0xf8000, 0x8000, (feaxs >> 6) & 3, 0); + shadow_control(dev, 0xf0000, 0x8000, (feaxs >> 4) & 3); + shadow_control(dev, 0xf8000, 0x8000, (feaxs >> 6) & 3); } static void From c36e6be6e248da16b2828a84a76dc57364e912d9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 14 Jan 2025 06:27:41 +0100 Subject: [PATCH 0086/1190] NEAT: Fix EMS and implement Shadow RAM and top 128K of conventional memory on/off, closes #1375. --- src/chipset/neat.c | 367 +++++++++++++++++++++++++++++---------------- 1 file changed, 238 insertions(+), 129 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 97c4b8f1a..94f0d66e1 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -37,6 +37,9 @@ #define EMS_MAXPAGE 4 #define EMS_PGSIZE 16384 +#define EMS_PGMASK 16383 + +#define REG_MASK 0x0f /* CS8221 82C211 controller registers. */ #define REG_RA0 0x60 /* PROCCLK selector */ @@ -194,37 +197,47 @@ #define RB10_P0EXT 0xc0 /* page 0 extension */ #define RB10_P0EXT_SH 6 -#define REG_RB11 0x6f /* Miscellaneous */ -#define RB11_MASK 0xe6 /* 111R R11R */ -#define RB11_GA20 0x02 /* gate for A20 */ -#define RB11_RASTMO 0x04 /* enable RAS timeout counter */ -#define RB11_EMSLEN 0xe0 /* EMS memory chunk size */ -#define RB11_EMSLEN_SH 5 +#define REG_RB12 0x6f /* Miscellaneous */ +#define RB12_MASK 0xe6 /* 111R R11R */ +#define RB12_GA20 0x02 /* gate for A20 */ +#define RB12_RASTMO 0x04 /* enable RAS timeout counter */ +#define RB12_EMSLEN 0xe0 /* EMS memory chunk size */ +#define RB12_EMSLEN_SH 5 -typedef struct emspage_t { - int8_t enabled; /* 1=ENABLED */ +#define RAM_FLAG_EMS 0x08 +#define RAM_FLAG_ROMCS 0x04 +#define RAM_FLAG_SHREAD 0x02 +#define RAM_FLAG_SHWRITE 0x01 +#define RAM_FMASK_EMS 0x08 +#define RAM_FMASK_SHADOW 0x07 + +typedef struct ram_page_t { + int8_t enabled; /* 1=ENABLED */ char pad; - uint16_t page; /* selected page in EMS block */ - uint32_t start; /* start of EMS in RAM */ - uint8_t *addr; /* start addr in EMS RAM */ - mem_mapping_t mapping; /* mapping entry for page */ -} emspage_t; + uint32_t phys_base; + uint32_t virt_base; + mem_mapping_t mapping; /* mapping entry for page */ +} ram_page_t; typedef struct neat_t { - uint8_t regs[128]; /* all the CS8221 registers */ - uint8_t indx; /* programmed index into registers */ + uint8_t ram_flags[32]; + uint8_t regs[128]; /* all the CS8221 registers */ + uint8_t indx; /* programmed index into registers */ - char pad; + char pad; - uint16_t ems_base; /* configured base address */ - uint16_t ems_oldbase; - uint32_t ems_frame; /* configured frame address */ - uint32_t ems_oldframe; - uint16_t ems_size; /* EMS size in KB */ - uint16_t ems_pages; /* EMS size in pages */ - emspage_t ems[EMS_MAXPAGE]; /* EMS page registers */ + uint16_t ems_base; /* configured base address */ + uint32_t ems_frame; /* configured frame address */ + uint16_t ems_size; /* EMS size in KB */ + uint16_t ems_pages; /* EMS size in pages */ + + ram_page_t ems[EMS_MAXPAGE]; /* EMS page registers */ + ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; +static uint8_t defaults[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; + #ifdef ENABLE_NEAT_LOG int neat_do_log = ENABLE_NEAT_LOG; @@ -247,11 +260,11 @@ neat_log(const char *fmt, ...) static uint8_t ems_readb(uint32_t addr, void *priv) { - neat_t *dev = (neat_t *) priv; - uint8_t ret = 0xff; + ram_page_t *dev = (ram_page_t *) priv; + uint8_t ret = 0xff; /* Grab the data. */ - ret = *(uint8_t *) (dev->ems[(addr & 0xffff) >> 14].addr + (addr & 0x3fff)); + ret = *(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]); return ret; } @@ -260,11 +273,11 @@ ems_readb(uint32_t addr, void *priv) static uint16_t ems_readw(uint32_t addr, void *priv) { - neat_t *dev = (neat_t *) priv; - uint16_t ret = 0xffff; + ram_page_t *dev = (ram_page_t *) priv; + uint16_t ret = 0xffff; /* Grab the data. */ - ret = *(uint16_t *) (dev->ems[(addr & 0xffff) >> 14].addr + (addr & 0x3fff)); + ret = *(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]); return ret; } @@ -273,40 +286,113 @@ ems_readw(uint32_t addr, void *priv) static void ems_writeb(uint32_t addr, uint8_t val, void *priv) { - neat_t *dev = (neat_t *) priv; + ram_page_t *dev = (ram_page_t *) priv; /* Write the data. */ - *(uint8_t *) (dev->ems[(addr & 0xffff) >> 14].addr + (addr & 0x3fff)) = val; + *(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val; } /* Write one word to paged RAM. */ static void ems_writew(uint32_t addr, uint16_t val, void *priv) { - neat_t *dev = (neat_t *) priv; + ram_page_t *dev = (ram_page_t *) priv; /* Write the data. */ - *(uint16_t *) (dev->ems[(addr & 0xffff) >> 14].addr + (addr & 0x3fff)) = val; + *(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val; +} + +static void +neat_mem_update_state(neat_t *dev, uint32_t addr, uint32_t size, uint8_t new_flags, uint8_t mask) +{ + if ((addr >= 0x00080000) && (addr < 0x00100000) && + ((new_flags ^ dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE]) & mask)) { + dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE] &= ~mask; + dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE] |= new_flags; + + new_flags = dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE]; + + neat_log("neat_mem_update_state(): %08X-%08X: %02X\n", addr, addr + size - 1, new_flags); + + if (new_flags & RAM_FLAG_EMS) + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else if (new_flags & RAM_FLAG_ROMCS) + mem_set_mem_state(addr, size, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + else switch (new_flags & (RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE)) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + default: + break; + } + } + + flushmmucache_nopc(); +} + +static void +shadow_recalc(neat_t *dev) +{ + for (uint8_t i = 8; i < 32; i++) { + int romcs = 0; + int write = 1; + int shadow_reg = REG_RB3 + ((i - 8) >> 3); + int shadow_bit = i & 7; + int ram_flags; + int read; + + if (i > 16) { + int rb1_romcs_bit = 7 - (i >> 2); + int rb1_write_bit = rb1_romcs_bit + 4; + + romcs = !(dev->regs[REG_RB1] & (1 << rb1_romcs_bit)); + write = !(dev->regs[REG_RB1] & (1 << rb1_write_bit)); + } else if (i <= 8) + shadow_bit ^= 4; + + read = dev->regs[shadow_reg] & (1 << shadow_bit); + write = write && read; + + ram_flags = romcs ? RAM_FLAG_ROMCS : 0x00; + ram_flags |= read ? RAM_FLAG_SHREAD : 0x00; + ram_flags |= write ? RAM_FLAG_SHWRITE : 0x00; + + if ((ram_flags > 0x00) && !(ram_flags & RAM_FLAG_ROMCS)) + mem_mapping_set_addr(&(dev->shadow[i].mapping), dev->shadow[i].virt_base, EMS_PGSIZE); + else + mem_mapping_disable(&(dev->shadow[i].mapping)); + + neat_mem_update_state(dev, dev->shadow[i].virt_base, EMS_PGSIZE, ram_flags, RAM_FMASK_SHADOW); + } } /* Re-calculate the active-page physical address. */ static void -ems_recalc(neat_t *dev, emspage_t *ems) +ems_recalc(neat_t *dev, ram_page_t *ems) { - if (ems->page >= dev->ems_pages) { - /* That page does not exist. */ - ems->enabled = 0; - } + uint32_t page = ems->phys_base / EMS_PGSIZE; - /* Pre-calculate the page address in EMS RAM. */ - ems->addr = ram + ems->start + (ems->page * EMS_PGSIZE); + if ((dev->regs[REG_RB7] & RB7_EMSEN) && ems->enabled && + (page >= 0x40) && (page < (0x40 + dev->ems_pages))) { + neat_log("ems_recalc(): %08X-%08X -> %08X-%08X\n", + ems->virt_base, ems->virt_base + EMS_PGSIZE - 1, + ems->phys_base, ems->phys_base + EMS_PGSIZE - 1); + mem_mapping_set_addr(&ems->mapping, ems->virt_base, EMS_PGSIZE); - if (ems->enabled) { /* Update the EMS RAM address for this page. */ - mem_mapping_set_exec(&ems->mapping, ems->addr); + mem_mapping_set_exec(&ems->mapping, ram + ems->phys_base); - /* Enable this page. */ - mem_mapping_enable(&ems->mapping); + if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000)) + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, RAM_FLAG_EMS, RAM_FMASK_EMS); #if NEAT_DEBUG > 1 neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n", @@ -315,15 +401,18 @@ ems_recalc(neat_t *dev, emspage_t *ems) } else { /* Disable this page. */ mem_mapping_disable(&ems->mapping); + + if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000)) + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS); } } static void ems_write(uint16_t port, uint8_t val, void *priv) { - neat_t *dev = (neat_t *) priv; - emspage_t *ems; - int vpage; + neat_t *dev = (neat_t *) priv; + ram_page_t *ems; + int vpage; #if NEAT_DEBUG > 1 neat_log("NEAT: ems_write(%04x, %02x)\n", port, val); @@ -337,8 +426,7 @@ ems_write(uint16_t port, uint8_t val, void *priv) case 0x0008: case 0x0009: ems->enabled = !!(val & 0x80); - ems->page &= 0x0180; /* clear lower bits */ - ems->page |= (val & 0x7f); /* add new bits */ + ems->phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE); ems_recalc(dev, ems); break; default: @@ -358,7 +446,7 @@ ems_read(uint16_t port, void *priv) switch (port & 0x000f) { case 0x0008: /* page number register */ - ret = dev->ems[vpage].page & 0x7f; + ret = (dev->ems[vpage].phys_base / EMS_PGSIZE) & 0x7f; if (dev->ems[vpage].enabled) ret |= 0x80; break; @@ -373,68 +461,21 @@ ems_read(uint16_t port, void *priv) return ret; } -/* Initialize the EMS module. */ static void -ems_init(neat_t *dev, int en) +ems_update(neat_t *dev, int en) { - uint8_t j; - - /* Remove if needed. */ - if (!en) { - if (dev->ems_base > 0) - for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { - /* Disable for now. */ - mem_mapping_disable(&dev->ems[i].mapping); - - /* Remove I/O handler. */ - io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2, - ems_read, NULL, NULL, ems_write, NULL, NULL, dev); - } - -#ifdef ENABLE_NEAT_LOG - neat_log("NEAT: EMS disabled\n"); -#endif - - return; - } - - /* Get configured I/O address. */ - j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; - dev->ems_base = 0x0208 + (0x10 * j); - - /* Get configured frame address. */ - j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; - dev->ems_frame = 0xC0000 + (EMS_PGSIZE * j); - - /* - * For each supported page (we can have a maximum of 4), - * create, initialize and disable the mappings, and set - * up the I/O control handler. - */ for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { - /* Create and initialize a page mapping. */ - mem_mapping_add(&dev->ems[i].mapping, - dev->ems_frame + (EMS_PGSIZE * i), EMS_PGSIZE, - ems_readb, ems_readw, NULL, - ems_writeb, ems_writew, NULL, - ram, MEM_MAPPING_EXTERNAL, - dev); - - /* Disable for now. */ - mem_mapping_disable(&dev->ems[i].mapping); - /* Set up an I/O port handler. */ - io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2, - ems_read, NULL, NULL, ems_write, NULL, NULL, dev); + io_handler(en, dev->ems_base + (i * EMS_PGSIZE), 2, + ems_read, NULL, NULL, ems_write, NULL, NULL, dev); - /* - * TODO: update the 'high_mem' mapping to reflect that we now - * have NN MB less extended memory available.. - */ + if (en) + dev->ems[i].virt_base = dev->ems_frame + (i * EMS_PGSIZE); + + ems_recalc(dev, &(dev->ems[i])); } - neat_log("NEAT: EMS enabled, I/O=%04xH, Frame=%05XH\n", - dev->ems_base, dev->ems_frame); + flushmmucache_nopc(); } static void @@ -442,6 +483,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) { neat_t *dev = (neat_t *) priv; uint8_t xval; + uint8_t j; uint8_t *reg; int i; @@ -493,6 +535,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB1: val &= RB1_MASK; *reg = (*reg & ~RB1_MASK) | val; + shadow_recalc(dev); #if NEAT_DEBUG > 1 neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg); #endif @@ -501,6 +544,10 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB2: val &= RB2_MASK; *reg = (*reg & ~RB2_MASK) | val; + if (val & RB2_TOP128) + neat_mem_update_state(dev, 0x00080000, 0x00020000, RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE, RAM_FMASK_SHADOW); + else + neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, RAM_FMASK_SHADOW); #if NEAT_DEBUG > 1 neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); #endif @@ -509,6 +556,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB3: val &= RB3_MASK; *reg = (*reg & ~RB3_MASK) | val; + shadow_recalc(dev); #if NEAT_DEBUG > 1 neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg); #endif @@ -517,6 +565,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB4: val &= RB4_MASK; *reg = (*reg & ~RB4_MASK) | val; + shadow_recalc(dev); #if NEAT_DEBUG > 1 neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg); #endif @@ -525,6 +574,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB5: val &= RB5_MASK; *reg = (*reg & ~RB5_MASK) | val; + shadow_recalc(dev); #if NEAT_DEBUG > 1 neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg); #endif @@ -544,10 +594,9 @@ neat_write(uint16_t port, uint8_t val, void *priv) #if NEAT_DEBUG > 1 neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg); #endif - if (val & RB7_EMSEN) - ems_init(dev, 1); - else if (xval & RB7_EMSEN) - ems_init(dev, 0); + + if (xval & RB7_EMSEN) + ems_update(dev, !!(val & RB7_EMSEN)); if (xval & RB7_UMAREL) { if (val & RB7_UMAREL) @@ -571,10 +620,19 @@ neat_write(uint16_t port, uint8_t val, void *priv) #if NEAT_DEBUG > 1 neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); #endif - if (dev->regs[REG_RB7] & RB7_EMSEN) { - ems_init(dev, 0); - ems_init(dev, 1); - } + + ems_update(dev, 0); + + /* Get configured I/O address. */ + j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; + dev->ems_base = 0x0208 + (0x10 * j); + + /* Get configured frame address. */ + j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; + dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j); + + if (dev->regs[REG_RB7] & RB7_EMSEN) + ems_update(dev, 1); break; case REG_RB10: @@ -584,23 +642,29 @@ neat_write(uint16_t port, uint8_t val, void *priv) neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); #endif - dev->ems[3].start = ((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21; - dev->ems[2].start = ((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21; - dev->ems[1].start = ((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21; - dev->ems[0].start = ((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21; - for (i = 0; i < EMS_MAXPAGE; i++) - ems_recalc(dev, &dev->ems[i]); + dev->ems[3].phys_base = (dev->ems[3].phys_base & 0x001fffff) | + (((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21); + dev->ems[2].phys_base = (dev->ems[2].phys_base & 0x001fffff) | + (((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21); + dev->ems[1].phys_base = (dev->ems[1].phys_base & 0x001fffff) | + (((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21); + dev->ems[0].phys_base = (dev->ems[0].phys_base & 0x001fffff) | + (((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21); + + if (dev->regs[REG_RB7] & RB7_EMSEN) + for (i = 0; i < EMS_MAXPAGE; i++) + ems_recalc(dev, &dev->ems[i]); break; - case REG_RB11: - val &= RB11_MASK; - *reg = (*reg & ~RB11_MASK) | val; + case REG_RB12: + val &= RB12_MASK; + *reg = (*reg & ~RB12_MASK) | val; #if NEAT_DEBUG > 1 - neat_log("NEAT: RB11=%02x(%02x)\n", val, *reg); + neat_log("NEAT: RB12=%02x(%02x)\n", val, *reg); #endif - i = (val & RB11_EMSLEN) >> RB11_EMSLEN_SH; + i = (val & RB12_EMSLEN) >> RB12_EMSLEN_SH; switch (i) { - case 0: /* "less than 2MB" */ + case 0: /* "less than 1MB" */ dev->ems_size = 512; break; @@ -617,10 +681,18 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; } dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE; + + if (dev->regs[REG_RB7] & RB7_EMSEN) + for (i = 0; i < EMS_MAXPAGE; i++) + ems_recalc(dev, &dev->ems[i]); + if (dev->regs[REG_RB7] & RB7_EMSEN) { neat_log("NEAT: EMS %iKB (%i pages)\n", dev->ems_size, dev->ems_pages); } + + mem_a20_key = val & RB12_GA20; + mem_a20_recalc(); break; default: @@ -629,6 +701,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; } break; + default: break; } @@ -646,8 +719,10 @@ neat_read(uint16_t port, void *priv) break; case 0x23: - if ((dev->indx >= 0x60) && (dev->indx <= 0x6f)) + if ((dev->indx >= 0x60) && (dev->indx <= 0x6e)) ret = dev->regs[dev->indx]; + else if (dev->indx == 0x6f) + ret = (dev->regs[dev->indx] & 0xfd) | (mem_a20_key & 2); break; default: @@ -674,16 +749,50 @@ neat_init(UNUSED(const device_t *info)) { neat_t *dev; uint8_t dram_mode = 0; - uint8_t i; + uint8_t j; /* Create an instance. */ dev = (neat_t *) malloc(sizeof(neat_t)); memset(dev, 0x00, sizeof(neat_t)); + /* Get configured I/O address. */ + j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; + dev->ems_base = 0x0208 + (0x10 * j); + + /* Get configured frame address. */ + j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; + dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j); + + mem_mapping_disable(&ram_mid_mapping); + + /* + * For each supported page (we can have a maximum of 4), + * create, initialize and disable the mappings, and set + * up the I/O control handler. + */ + for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { + /* Create and initialize a page mapping. */ + mem_mapping_add(&dev->ems[i].mapping, + dev->ems_frame + (EMS_PGSIZE * i), EMS_PGSIZE, + ems_readb, ems_readw, NULL, + ems_writeb, ems_writew, NULL, + ram, MEM_MAPPING_INTERNAL, + &(dev->ems[i])); + + /* Disable for now. */ + mem_mapping_disable(&dev->ems[i].mapping); + } + + for (uint8_t i = 0; i < 32; i++) { + dev->shadow[i].virt_base = dev->shadow[i].phys_base = + (i * EMS_PGSIZE) + 0x00080000; + dev->shadow[i].enabled = 1; + } + /* Initialize some of the registers to specific defaults. */ - for (i = REG_RA0; i <= REG_RB11; i++) { + for (uint8_t i = REG_RA0; i <= REG_RB12; i++) { dev->indx = i; - neat_write(0x0023, 0x00, dev); + neat_write(0x0023, defaults[i & REG_MASK], dev); } /* From b36d2c5abad252cb073cf382120762c22d7daccf Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:59:53 +0100 Subject: [PATCH 0087/1190] Few corrections to Quantum Fireball series --- src/disk/hdd.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 5243f016b..035bc83c6 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -448,13 +448,6 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1080AT", .internal_name = "TM10A462", .model = "QUANTUM FIREBALL TM1.0A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1.2AT", .internal_name = "TM12A012", .model = "QUANTUM FIREBALL TM1.2A", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-2] Samsung PLS-31274A", .internal_name = "PLS31274A", .model = "SAMSUNG PLS-31274A", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 45, .track_seek_ms = 4.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, { .name = "[ATA-2] Samsung Winner-1", .internal_name = "WNR31601A", .model = "SAMSUNG WNR-31601A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Seagate Medalist (ST3780A)", .internal_name = "ST3780A", .model = "ST3780A", .zones = 8, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, @@ -501,6 +494,9 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92049U6)", .internal_name = "92049U6", .model = "Maxtor 92049U6", .zones = 16, .avg_spt = 90, .heads = 6, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 90, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 115, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, @@ -513,9 +509,15 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200-00LA", .zones = 16, .avg_spt = 110, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 92, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 92, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 92, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM + { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 92, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-5] Maxtor DiamondMax VL 20", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 110, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 89, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, From 46426d5e929bb9d2d24f2e85118c412ce4d2aa3f Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:16:04 +0100 Subject: [PATCH 0088/1190] Update cdrom.h for TEAC CD-532E/NEC CDR-1900A --- src/include/86box/cdrom.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index efb45ecfb..7272f5e8c 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -95,6 +95,7 @@ enum CDROM_TYPE_NEC_77_106, CDROM_TYPE_NEC_211_100, CDROM_TYPE_NEC_464_105, + CDROM_TYPE_NEC_CDR_1900A_100, CDROM_TYPE_ShinaKen_DM3x1S_104, CDROM_TYPE_SONY_CDU541_10i, CDROM_TYPE_SONY_CDU561_18k, @@ -102,6 +103,7 @@ enum CDROM_TYPE_PHILIPS_CDD2600_107, CDROM_TYPE_PIONEER_DRM604X_2403, CDROM_TYPE_PLEXTOR_PX32TS_103, + CDROM_TYPE_TEAC_CD532E_20A, CDROM_TYPE_TEAC_CD50_100, CDROM_TYPE_TEAC_R55S_10R, CDROM_TYPE_TEXEL_DM3024_100, @@ -145,9 +147,11 @@ static const struct { "NEC", "CD-ROM DRIVE:273", "4.20", "NEC CD-ROM DRIVE:273 4.20", "NEC_CD-ROM_DRIVE273_4.20", BUS_TYPE_IDE }, { "NEC", "CD-ROM DRIVE:280", "1.05", "NEC CD-ROM DRIVE:280 1.05", "NEC_CD-ROM_DRIVE280_1.05", BUS_TYPE_IDE }, { "NEC", "CD-ROM DRIVE:280", "3.08", "NEC CD-ROM DRIVE:280 3.08", "NEC_CD-ROM_DRIVE280_3.08", BUS_TYPE_IDE }, + { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, + { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, From 68a8392baf2cbd5d94554ac43099c4f59949bd9a Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:31:21 +0100 Subject: [PATCH 0089/1190] Add TEAC CD-532E (32X)/NEC CDR-1900A (32X) --- src/scsi/scsi_cdrom.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index ad7f0d1c0..ddbb65849 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -4097,6 +4097,10 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "3.08 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:280 ", 40); /* Model */ break; + case CDROM_TYPE_NEC_CDR_1900A_100: + ide_padstr((char *) (ide->buffer + 23), "1.00 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CDR-1900A ", 40); /* Model */ + break; case CDROM_TYPE_PHILIPS_PCA403CD_U31P: ide_padstr((char *) (ide->buffer + 23), "U31P ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "PHILIPS CD-ROM PCA403CD ", 40); /* Model */ @@ -4109,6 +4113,10 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "3.0h ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU311 ", 40); /* Model */ break; + case CDROM_TYPE_TEAC_CD_532E_20A: + ide_padstr((char *) (ide->buffer + 23), "2.0A ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TEAC CD-532E ", 40); /* Model */ + break; case CDROM_TYPE_TOSHIBA_5302TA_0305: ide_padstr((char *) (ide->buffer + 23), "0305 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5302TA ", 40); /* Model */ From 514abd4abde47b7e968d9f93194e3756964ba634 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:42:49 +0100 Subject: [PATCH 0090/1190] Update scsi_cdrom.c --- src/scsi/scsi_cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index ddbb65849..cdf653626 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -4113,7 +4113,7 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "3.0h ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU311 ", 40); /* Model */ break; - case CDROM_TYPE_TEAC_CD_532E_20A: + case CDROM_TYPE_TEAC_CD532E_20A: ide_padstr((char *) (ide->buffer + 23), "2.0A ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TEAC CD-532E ", 40); /* Model */ break; From 1aee794ae1cae4f684fed8251bd4ccef0bc09d27 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:58:29 +0100 Subject: [PATCH 0091/1190] Update cdrom.h From 9bb96bd836eae91c53725ae162f5d0c8fdd46e41 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 18:47:54 +0100 Subject: [PATCH 0092/1190] Fireball EX/CR now complete --- src/disk/hdd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 035bc83c6..e79f0f6c0 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -495,6 +495,7 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 90, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE4.3A", .internal_name = "SE43A011", .model = "QUANTUM FIREBALL SE4.3A", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 115, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, @@ -517,7 +518,10 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 89, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, From 70891ffdb5b944c907b85f094a747c1ccdc3a303 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 18:59:31 +0100 Subject: [PATCH 0093/1190] Updated INQUIRY --- src/include/86box/cdrom.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7272f5e8c..07ca72d36 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -80,9 +80,11 @@ enum CDROM_TYPE_NEC_273_420, CDROM_TYPE_NEC_280_105, CDROM_TYPE_NEC_280_308, + CDROM_TYPE_NEC_CDR_1900A_100 CDROM_TYPE_PHILIPS_PCA403CD_U31P, CDROM_TYPE_SONY_CDU76_10i, CDROM_TYPE_SONY_CDU311_30h, + CDROM_TYPE_TEAC_CD532E_20A, CDROM_TYPE_TOSHIBA_5302TA_0305, CDROM_TYPE_TOSHIBA_5702B_TA70, CDROM_TYPE_CHINON_CDS431_H42, From 1d6a49d7494c4a5cb3251161e286d3004bf5b9a8 Mon Sep 17 00:00:00 2001 From: unreal9010 <84349460+unreal9010@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:11:56 +0100 Subject: [PATCH 0094/1190] Update cdrom.h --- src/include/86box/cdrom.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 07ca72d36..5d90d84a4 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -80,7 +80,7 @@ enum CDROM_TYPE_NEC_273_420, CDROM_TYPE_NEC_280_105, CDROM_TYPE_NEC_280_308, - CDROM_TYPE_NEC_CDR_1900A_100 + CDROM_TYPE_NEC_CDR_1900A_100, CDROM_TYPE_PHILIPS_PCA403CD_U31P, CDROM_TYPE_SONY_CDU76_10i, CDROM_TYPE_SONY_CDU311_30h, @@ -97,7 +97,6 @@ enum CDROM_TYPE_NEC_77_106, CDROM_TYPE_NEC_211_100, CDROM_TYPE_NEC_464_105, - CDROM_TYPE_NEC_CDR_1900A_100, CDROM_TYPE_ShinaKen_DM3x1S_104, CDROM_TYPE_SONY_CDU541_10i, CDROM_TYPE_SONY_CDU561_18k, @@ -105,7 +104,6 @@ enum CDROM_TYPE_PHILIPS_CDD2600_107, CDROM_TYPE_PIONEER_DRM604X_2403, CDROM_TYPE_PLEXTOR_PX32TS_103, - CDROM_TYPE_TEAC_CD532E_20A, CDROM_TYPE_TEAC_CD50_100, CDROM_TYPE_TEAC_R55S_10R, CDROM_TYPE_TEXEL_DM3024_100, From bf3be9c0c7837e730b93cc2d5837c87c2602d3c9 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 14 Jan 2025 16:27:54 -0500 Subject: [PATCH 0095/1190] Correct EV-165A's name --- src/device/isamem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index a3baf466d..94f554473 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -1622,7 +1622,7 @@ static const device_config_t ev165a_config[] = { }; static const device_t ev165a_device = { - .name = "Everex Magi Magic EV-165A", + .name = "Everex Maxi Magic EV-165A", .internal_name = "ev165a", .flags = DEVICE_ISA, .local = ISAMEM_EV165A_CARD, From 7eef0665b5db8eba65e08f9dbbf76e427f038f3e Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 14 Jan 2025 16:45:07 -0500 Subject: [PATCH 0096/1190] Fix EV-165A config --- src/device/isamem.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index 94f554473..83e938abd 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -1547,12 +1547,12 @@ static const device_config_t ev165a_config[] = { .description = "Memory size", .type = CONFIG_SPINNER, .default_string = "", - .default_int = 512, + .default_int = 256, .file_filter = "", .spinner = { .min = 0, .max = 2048, - .step = 512 + .step = 256 }, .selection = { { 0 } } }, @@ -1561,12 +1561,12 @@ static const device_config_t ev165a_config[] = { .description = "Start Address", .type = CONFIG_SPINNER, .default_string = "", - .default_int = 0, + .default_int = 64, .file_filter = "", .spinner = { - .min = 0, - .max = 896, - .step = 128 + .min = 64, + .max = 640, + .step = 64 }, .selection = { { 0 } } }, @@ -1579,8 +1579,8 @@ static const device_config_t ev165a_config[] = { .file_filter = "", .spinner = { .min = 0, - .max = 16384, - .step = 128 + .max = 2048, + .step = 256 }, .selection = { { 0 } } }, From 4e8802c23ee9e7d771328398aa91863edf98f282 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 15 Jan 2025 00:37:02 +0100 Subject: [PATCH 0097/1190] Fix maximum amount of RAM on a few NEAT machine where it was set unrealistically high. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 330b7d52a..47a33fa8c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3597,7 +3597,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE | MACHINE_VIDEO, .ram = { .min = 512, - .max = 16384, + .max = 5120, .step = 128 }, .nvrmask = 127, @@ -3637,7 +3637,7 @@ const machine_t machines[] = { .flags = MACHINE_FLAGS_NONE, .ram = { .min = 512, - .max = 16384, + .max = 8192, .step = 128 }, .nvrmask = 127, From 7bc89f6feb0bf631294382c4c1945555696b0c12 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 07:13:21 +0700 Subject: [PATCH 0098/1190] Added a plenty of IDE CD-ROM models -Added other four ATA-3 models -Corrections to Western Digital pre-ATA-4 HDD models --- src/disk/hdd.c | 30 ++++++++++++++------------ src/include/86box/cdrom.h | 22 ++++++++++++++++++++ src/scsi/scsi_cdrom.c | 44 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index e79f0f6c0..328d8dcb0 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -431,10 +431,10 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-1] Quantum ProDrive LPS 105", .internal_name = "LPS105AT", .model = "QUANTUM PRODRIVE 105", .zones = 1, .avg_spt = 170, .heads = 2, .rpm = 3662, .full_stroke_ms = 45, .track_seek_ms = 5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, { .name = "[ATA-1] Quantum ProDrive LPS 120AT", .internal_name = "GM12A012", .model = "QUANTUM PRODRIVE 120AT", .zones = 1, .avg_spt = 150, .heads = 2, .rpm = 3605, .full_stroke_ms = 45, .track_seek_ms = 4, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, { .name = "[ATA-1] Seagate ST3243A", .internal_name = "ST3243A", .model = "ST3243A", .zones = 1, .avg_spt = 140, .heads = 4, .rpm = 3811, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "WDAC140", .model = "WDC WDAC140-50", .zones = 4, .avg_spt = 170, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "WDAC280", .model = "WDC WDAC280-00", .zones = 4, .avg_spt = 170, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "WDAC1210", .model = "WDC WDAC1210-21F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "WDAC2120", .model = "WDC WDAC2120-00M", .zones = 4, .avg_spt = 140, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "AC140", .model = "WDC AC140", .zones = 4, .avg_spt = 170, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "AC280", .model = "WDC AC280", .zones = 4, .avg_spt = 170, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "AC1210", .model = "WDC AC1210F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "AC2120", .model = "WDC AC2120M", .zones = 4, .avg_spt = 140, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, { .name = "[ATA-2] IBM DBOA-2720", .internal_name = "DBOA2720", .model = "IBM-DBOA-2720", .zones = 2, .avg_spt = 135, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, { .name = "[ATA-2] IBM DeskStar 4 (DCAA-32880)", .internal_name = "DCAA32880", .model = "IBM-DCAA-32880", .zones = 8, .avg_spt = 85, .heads = 2, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, { .name = "[ATA-2] IBM DeskStar 4 (DCAA-33610)", .internal_name = "DCAA33610", .model = "IBM-DCAA-33610", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, @@ -460,14 +460,15 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Seagate Medalist 1270SL", .internal_name = "ST51270A", .model = "ST51270A", .zones = 8, .avg_spt = 105, .heads = 3, .rpm = 5736, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Seagate Medalist 3240", .internal_name = "ST33240A", .model = "ST33240A", .zones = 16, .avg_spt = 125, .heads = 8, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Toshiba MK2101MAN (HDD2616)", .internal_name = "HDD2616", .model = "TOSHIBA MK2101MAN", .zones = 8, .avg_spt = 130, .heads = 10, .rpm = 4200, .full_stroke_ms = 36, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "WDAC2540", .model = "WDC WDAC2540-00H", .zones = 4, .avg_spt = 250, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "WDAC2850", .model = "WDC WDAC2850-00F", .zones = 4, .avg_spt = 230, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 11000", .internal_name = "WDAC11000", .model = "WDC WDAC11000-00H", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 21200", .internal_name = "WDAC21200", .model = "WDC WDAC21200-00H", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 5200, .full_stroke_ms = 39, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 21600", .internal_name = "WDAC21600", .model = "WDC WDAC21600-00H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000-32LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "WDAC22100", .model = "WDC WDAC22100-18H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "WDAC31200", .model = "WDC WDAC31200-00F", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "AC2540", .model = "WDC AC2540H", .zones = 4, .avg_spt = 250, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "AC2850", .model = "WDC AC2850F", .zones = 4, .avg_spt = 230, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 11000", .internal_name = "AC11000", .model = "WDC AC11000H", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 21200", .internal_name = "AC21200", .model = "WDC AC21200H", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 5200, .full_stroke_ms = 39, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 21600", .internal_name = "AC21600", .model = "WDC AC21600H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-3] Connor CFS1275A", .internal_name = "CFS1275A", .model = "Connor Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, @@ -475,9 +476,12 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-3] Fujitsu MPA3052AT", .internal_name = "MPA3052AT", .model = "FUJITSU MPA3052AT", .zones = 16, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Samsung Voyager 6", .internal_name = "SV0844A", .model = "SAMSUNG SV0844A", .zones = 8, .avg_spt = 105, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-3] Samsung Winner 5X", .internal_name = "WU33205A", .model = "SAMSUNG WU33205A", .zones = 16, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Seagate Medalist 636", .internal_name = "ST3636A", .model = "Seagate Technology 636MB - ST3636A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-3] Seagate Medalist 1082", .internal_name = "ST31082A", .model = "Seagate Technology 1082MB - ST31082A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-3] Seagate Medalist 1276", .internal_name = "ST31276A", .model = "Seagate Technology 1275MB - ST31276A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, { .name = "[ATA-3] Seagate Medalist 1720", .internal_name = "ST31720A", .model = "ST31720A", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Seagate Medalist 2132", .internal_name = "ST32132A", .model = "ST32132A", .zones = 8, .avg_spt = 125, .heads = 6, .rpm = 4500, .full_stroke_ms = 30, .track_seek_ms = 2.3, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 16 }, - { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "WDAC21700", .model = "WDC WDAC21700-40H", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version + { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "AC21700", .model = "WDC AC21700H", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version { .name = "[ATA-4] Fujitsu MPB3021AT", .internal_name = "MPB3021AT", .model = "FUJITSU MPB3021AT", .zones = 7, .avg_spt = 100, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 16 }, { .name = "[ATA-4] Fujitsu MPD3043AT", .internal_name = "MPD3043AT", .model = "FUJITSU MPD3043AT", .zones = 5, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 29, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-4] Fujitsu MPD3064AT", .internal_name = "MPD3064AT", .model = "FUJITSU MPD3064AT", .zones = 7, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 5d90d84a4..d7868951e 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -65,11 +65,17 @@ enum { enum { CDROM_TYPE_86BOX_100, + CDROM_TYPE_ASUS_CDS500_141, + CDROM_TYPE_ASUS_CDS520_132, CDROM_TYPE_AZT_CDA46802I_115, CDROM_TYPE_BTC_BCD36XH_U10, CDROM_TYPE_GOLDSTAR_CRD_8160B_314, CDROM_TYPE_HITACHI_CDR_8130_0020, + CDROM_TYPE_HLDTST_GCE8525B_101, CDROM_TYPE_KENWOOD_UCR_421_208E, + CDROM_TYPE_LG_CRN8245B_120, + CDROM_TYPE_LTN48125S_1S07, + CDROM_TYPE_MATSHITA_585_Z18P, CDROM_TYPE_MATSHITA_587_7S13, CDROM_TYPE_MATSHITA_588_LS15, CDROM_TYPE_MATSHITA_571_10e, @@ -84,9 +90,14 @@ enum CDROM_TYPE_PHILIPS_PCA403CD_U31P, CDROM_TYPE_SONY_CDU76_10i, CDROM_TYPE_SONY_CDU311_30h, + CDROM_TYPE_SONY_CDU5225_NYS4, + CDROM_TYPE_TEAC_CD516E_10G, + CDROM_TYPE_TEAC_CD524EA_30D, CDROM_TYPE_TEAC_CD532E_20A, CDROM_TYPE_TOSHIBA_5302TA_0305, CDROM_TYPE_TOSHIBA_5702B_TA70, + CDROM_TYPE_TOSHIBA_6702B_1007, + CDROM_TYPE_TOSHIBA_M1802_1051, CDROM_TYPE_CHINON_CDS431_H42, CDROM_TYPE_CHINON_CDX435_M62, CDROM_TYPE_DEC_RRD45_0436, @@ -132,11 +143,17 @@ static const struct const int bus_type; } cdrom_drive_types[] = { { "86BOX", "CD-ROM", "1.00", "86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_BOTH }, + { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.15", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, + { "ASUS", "CD-S520/A4", "1.32", "ASUS CD-S520/A4 1.32", "ASUS_CD-S520A4_1.32", BUS_TYPE_IDE }, { "AZT", "CDA46802I", "1.15", "AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE }, { "BTC", "CD-ROM BCD36XH", "U1.0", "BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE }, { "GOLDSTAR", "CRD-8160B", "3.14", "GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE }, { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, + { "HL-DT-ST", "GCE-8525B", "1.01", "HL-DT-ST GCE-8525B 1.01", "HL-DT-ST_GCE-8525B_1.01", BUS_TYPE_IDE }, { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, + { "LG", "CRN-8245B", "1.20", "LG CRN-8245B 1.20", "LG_CRN-8245B_1.20", BUS_TYPE_IDE }, + { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, + { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-588", "LS15", "MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE }, { "MATSHITA", "CR-571", "1.0e", "MATSHITA CR-571 1.0e", "MATSHITA_CR-571_1.0e", BUS_TYPE_IDE }, @@ -151,9 +168,14 @@ static const struct { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, + { "SONY", "CD-ROM CDU5225", "NYS4", "SONY CD-ROM CDU5225 NYS4", "SONY_CD-ROM_CDU5225_NYS4", BUS_TYPE_IDE }, + { "TEAC", "CD-516E", "1.0G", "TEAC CD-516E 1.0G", "TEAC_CD-516E_1.0G", BUS_TYPE_IDE }, + { "TEAC", "CD-524EA", "3.0D", "TEAC CD-524EA 3.0D", "TEAC_CD-524EA_3.0D", BUS_TYPE_IDE }, { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, + { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1.15", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index cdf653626..9f8a86fc9 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -4037,6 +4037,14 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ } else { switch (dev->drv->type) { + case CDROM_TYPE_ASUS_CDS500_141: + ide_padstr((char *) (ide->buffer + 23), "1.41 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "ASUS CD-S500/A ", 40); /* Model */ + break; + case CDROM_TYPE_ASUS_CDS520_132: + ide_padstr((char *) (ide->buffer + 23), "1.32 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "ASUS CD-S520/A4 ", 40); /* Model */ + break; case CDROM_TYPE_AZT_CDA46802I_115: ide_padstr((char *) (ide->buffer + 23), "1.15 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "AZT CDA46802I ", 40); /* Model */ @@ -4053,10 +4061,26 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ break; + case CDROM_TYPE_HLDTST_GCE8525B_101: + ide_padstr((char *) (ide->buffer + 23), "1.01 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST GCE-8525B ", 40); /* Model */ + break; case CDROM_TYPE_KENWOOD_UCR_421_208E: ide_padstr((char *) (ide->buffer + 23), "208E ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "KENWOOD CD-ROM UCR-421 ", 40); /* Model */ break; + case CDROM_TYPE_LG_CRN8245B_120: + ide_padstr((char *) (ide->buffer + 23), "1.20 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRN-8245B ", 40); /* Model */ + break; + case CDROM_TYPE_LTN48125S_1S07: + ide_padstr((char *) (ide->buffer + 23), "1S07 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "LTN48125S ", 40); /* Model */ + break; + case CDROM_TYPE_MATSHITA_585_Z18P: + ide_padstr((char *) (ide->buffer + 23), "Z18P ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-585 ", 40); /* Model */ + break; case CDROM_TYPE_MATSHITA_587_7S13: ide_padstr((char *) (ide->buffer + 23), "7S13 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-587 ", 40); /* Model */ @@ -4113,6 +4137,18 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "3.0h ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU311 ", 40); /* Model */ break; + case CDROM_TYPE_SONY_CDU5225_NYS4: + ide_padstr((char *) (ide->buffer + 23), "NYS4 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU5225 ", 40); /* Model */ + break; + case CDROM_TYPE_TEAC_CD516E_10G: + ide_padstr((char *) (ide->buffer + 23), "1.0G ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TEAC CD-516E ", 40); /* Model */ + break; + case CDROM_TYPE_TEAC_CD524EA_30D: + ide_padstr((char *) (ide->buffer + 23), "3.0D ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TEAC CD-524EA ", 40); /* Model */ + break; case CDROM_TYPE_TEAC_CD532E_20A: ide_padstr((char *) (ide->buffer + 23), "2.0A ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TEAC CD-532E ", 40); /* Model */ @@ -4125,6 +4161,14 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "TA70 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5702B ", 40); /* Model */ break; + case CDROM_TYPE_TOSHIBA_6702B_1007: + ide_padstr((char *) (ide->buffer + 23), "1007 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6702B ", 40); /* Model */ + break; + case CDROM_TYPE_TOSHIBA_M1802_1051: + ide_padstr((char *) (ide->buffer + 23), "1051 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TOSHIBA DVD-ROM SD-M1802 ", 40); /* Model */ + break; } } From 6b89a2e74d39373474cfb0b2148aa74006c90f64 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 07:30:48 +0700 Subject: [PATCH 0099/1190] Small name fixes to CDR-1900A --- src/include/86box/cdrom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index d7868951e..f579c8dc0 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -164,7 +164,7 @@ static const struct { "NEC", "CD-ROM DRIVE:273", "4.20", "NEC CD-ROM DRIVE:273 4.20", "NEC_CD-ROM_DRIVE273_4.20", BUS_TYPE_IDE }, { "NEC", "CD-ROM DRIVE:280", "1.05", "NEC CD-ROM DRIVE:280 1.05", "NEC_CD-ROM_DRIVE280_1.05", BUS_TYPE_IDE }, { "NEC", "CD-ROM DRIVE:280", "3.08", "NEC CD-ROM DRIVE:280 3.08", "NEC_CD-ROM_DRIVE280_3.08", BUS_TYPE_IDE }, - { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, + { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, From 75b99232839aec74dee4a6e13db5ee3a1bba2b08 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 07:45:13 +0700 Subject: [PATCH 0100/1190] Correct the revision names --- src/include/86box/cdrom.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index f579c8dc0..3895833a6 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -143,7 +143,7 @@ static const struct const int bus_type; } cdrom_drive_types[] = { { "86BOX", "CD-ROM", "1.00", "86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_BOTH }, - { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.15", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, + { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.41", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, { "ASUS", "CD-S520/A4", "1.32", "ASUS CD-S520/A4 1.32", "ASUS_CD-S520A4_1.32", BUS_TYPE_IDE }, { "AZT", "CDA46802I", "1.15", "AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE }, { "BTC", "CD-ROM BCD36XH", "U1.0", "BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE }, @@ -175,7 +175,7 @@ static const struct { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, - { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1.15", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, + { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, From 6d1d6d8830e1bc9caf11c9e1f6475edd5c1bb0eb Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 15 Jan 2025 04:30:59 +0100 Subject: [PATCH 0101/1190] NEAT: More fixes, closes #5145. --- src/chipset/neat.c | 252 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 193 insertions(+), 59 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 94f0d66e1..3b223bed4 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -231,6 +231,8 @@ typedef struct neat_t { uint16_t ems_size; /* EMS size in KB */ uint16_t ems_pages; /* EMS size in pages */ + uint32_t remap_base; + ram_page_t ems[EMS_MAXPAGE]; /* EMS page registers */ ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; @@ -238,6 +240,9 @@ typedef struct neat_t { static uint8_t defaults[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; +static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT }; +static uint8_t shifts[4] = { RB10_P0EXT_SH, RB10_P1EXT_SH, RB10_P2EXT_SH, RB10_P3EXT_SH }; + #ifdef ENABLE_NEAT_LOG int neat_do_log = ENABLE_NEAT_LOG; @@ -262,10 +267,17 @@ ems_readb(uint32_t addr, void *priv) { ram_page_t *dev = (ram_page_t *) priv; uint8_t ret = 0xff; +#ifdef ENABLE_NEAT_LOG + uint32_t old = addr; +#endif /* Grab the data. */ - ret = *(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]); + addr = addr - dev->virt_base + dev->phys_base; + if (addr < (mem_size << 10)) + ret = *(uint8_t *) &(ram[addr]); + + neat_log("[R08] %08X -> %08X (%08X): ret = %02X\n", old, addr, (mem_size << 10), ret); return ret; } @@ -275,10 +287,17 @@ ems_readw(uint32_t addr, void *priv) { ram_page_t *dev = (ram_page_t *) priv; uint16_t ret = 0xffff; +#ifdef ENABLE_NEAT_LOG + uint32_t old = addr; +#endif /* Grab the data. */ - ret = *(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]); + addr = addr - dev->virt_base + dev->phys_base; + if (addr < (mem_size << 10)) + ret = *(uint16_t *) &(ram[addr]); + + neat_log("[R16] %08X -> %08X (%08X): ret = %04X\n", old, addr, (mem_size << 10), ret); return ret; } @@ -287,9 +306,16 @@ static void ems_writeb(uint32_t addr, uint8_t val, void *priv) { ram_page_t *dev = (ram_page_t *) priv; +#ifdef ENABLE_NEAT_LOG + uint32_t old = addr; +#endif /* Write the data. */ - *(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val; + addr = addr - dev->virt_base + dev->phys_base; + neat_log("[W08] %08X -> %08X (%08X): val = %02X\n", old, addr, (mem_size << 10), val); + + if (addr < (mem_size << 10)) + *(uint8_t *) &(ram[addr]) = val; } /* Write one word to paged RAM. */ @@ -297,9 +323,16 @@ static void ems_writew(uint32_t addr, uint16_t val, void *priv) { ram_page_t *dev = (ram_page_t *) priv; +#ifdef ENABLE_NEAT_LOG + uint32_t old = addr; +#endif /* Write the data. */ - *(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val; + addr = addr - dev->virt_base + dev->phys_base; + neat_log("[W16] %08X -> %08X (%08X): val = %04X\n", old, addr, (mem_size << 10), val); + + if (addr < (mem_size << 10)) + *(uint16_t *) &(ram[addr]) = val; } static void @@ -379,10 +412,11 @@ shadow_recalc(neat_t *dev) static void ems_recalc(neat_t *dev, ram_page_t *ems) { - uint32_t page = ems->phys_base / EMS_PGSIZE; + uint32_t page = ems->phys_base / EMS_PGSIZE; - if ((dev->regs[REG_RB7] & RB7_EMSEN) && ems->enabled && - (page >= 0x40) && (page < (0x40 + dev->ems_pages))) { + neat_log("ems_recalc(): %08X, %04X, %04X\n", ems->virt_base, page, dev->ems_pages); + + if ((dev->regs[REG_RB7] & RB7_EMSEN) && ems->enabled && (page < dev->ems_pages)) { neat_log("ems_recalc(): %08X-%08X -> %08X-%08X\n", ems->virt_base, ems->virt_base + EMS_PGSIZE - 1, ems->phys_base, ems->phys_base + EMS_PGSIZE - 1); @@ -405,14 +439,20 @@ ems_recalc(neat_t *dev, ram_page_t *ems) if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000)) neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS); } + + flushmmucache_nopc(); } static void ems_write(uint16_t port, uint8_t val, void *priv) { - neat_t *dev = (neat_t *) priv; + neat_t *dev = (neat_t *) priv; ram_page_t *ems; int vpage; + int8_t old_enabled; + uint32_t old_phys_base; + int8_t new_enabled; + uint32_t new_phys_base; #if NEAT_DEBUG > 1 neat_log("NEAT: ems_write(%04x, %02x)\n", port, val); @@ -422,12 +462,29 @@ ems_write(uint16_t port, uint8_t val, void *priv) vpage = (port / EMS_PGSIZE); ems = &dev->ems[vpage]; + neat_log("Port: %04X, val: %02X\n", port, val); + switch (port & 0x000f) { case 0x0008: case 0x0009: - ems->enabled = !!(val & 0x80); - ems->phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE); - ems_recalc(dev, ems); + old_enabled = ems->enabled; + old_phys_base = ems->phys_base; + new_enabled = !!(val & 0x80); + new_phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE); + + if ((old_enabled != new_enabled) || (old_phys_base != new_phys_base)) { + if (old_enabled && (old_enabled == new_enabled)) { + ems->enabled = 0; + ems_recalc(dev, ems); + } + + ems->enabled = !!(val & 0x80); + + if (old_phys_base != new_phys_base) + ems->phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE); + + ems_recalc(dev, ems); + } break; default: break; @@ -454,6 +511,8 @@ ems_read(uint16_t port, void *priv) break; } + neat_log("Port: %04X, ret: %02X\n", port, ret); + #if NEAT_DEBUG > 1 neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret); #endif @@ -462,20 +521,76 @@ ems_read(uint16_t port, void *priv) } static void -ems_update(neat_t *dev, int en) +ems_recalc_all(neat_t *dev) +{ + for (uint8_t i = 0; i < EMS_MAXPAGE; i++) + ems_recalc(dev, &(dev->ems[i])); +} + +static void +ems_update_virt_base(neat_t *dev) +{ + for (uint8_t i = 0; i < EMS_MAXPAGE; i++) + dev->ems[i].virt_base = dev->ems_frame + (i * EMS_PGSIZE); +} + +static void +ems_remove_handlers(neat_t *dev) { for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { + neat_log("Removing I/O handler at %04X-%04X\n", + dev->ems_base + (i * EMS_PGSIZE), dev->ems_base + (i * EMS_PGSIZE) + 1); + /* Clean up any previous I/O port handler. */ + io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2, + ems_read, NULL, NULL, ems_write, NULL, NULL, dev); + } +} + +static void +ems_set_handlers(neat_t *dev) +{ + for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { + neat_log("Setting up I/O handler at %04X-%04X\n", + dev->ems_base + (i * EMS_PGSIZE), dev->ems_base + (i * EMS_PGSIZE) + 1); /* Set up an I/O port handler. */ - io_handler(en, dev->ems_base + (i * EMS_PGSIZE), 2, - ems_read, NULL, NULL, ems_write, NULL, NULL, dev); - - if (en) - dev->ems[i].virt_base = dev->ems_frame + (i * EMS_PGSIZE); - - ems_recalc(dev, &(dev->ems[i])); + io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2, + ems_read, NULL, NULL, ems_write, NULL, NULL, dev); } - flushmmucache_nopc(); + ems_recalc_all(dev); +} + +static void +remap_update(neat_t *dev, uint8_t val) +{ + if (dev->regs[REG_RB7] & RB7_UMAREL) { + mem_remap_top_ex(0, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + neat_log("0 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10); + } + + if (val & RB7_EMSEN) + dev->remap_base = mem_size - dev->ems_size; + else + dev->remap_base = mem_size; + neat_log("Total contiguous memory now: %i kB\n", dev->remap_base); + + if (dev->remap_base >= 640) + mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000); + else + mem_mapping_set_addr(&ram_low_mapping, 0x00000000, dev->remap_base << 10); + + if (dev->remap_base > 1024) + mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); + else + mem_mapping_disable(&ram_high_mapping); + + if (val & RB7_UMAREL) { + mem_remap_top_ex(384, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + neat_log("384 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10); + } + + /* Yes, this has to be done on every step because mem_remap_top_ex() reenables it. */ + mem_mapping_disable(&ram_mid_mapping); } static void @@ -590,20 +705,21 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB7: val &= RB7_MASK; - *reg = val; + + if (xval & (RB7_EMSEN | RB7_UMAREL)) + remap_update(dev, val); + + dev->regs[REG_RB7] = val; + + if (xval & RB7_EMSEN) + ems_remove_handlers(dev); + + if ((xval & RB7_EMSEN) && (val & RB7_EMSEN)) + ems_set_handlers(dev); + #if NEAT_DEBUG > 1 neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg); #endif - - if (xval & RB7_EMSEN) - ems_update(dev, !!(val & RB7_EMSEN)); - - if (xval & RB7_UMAREL) { - if (val & RB7_UMAREL) - mem_remap_top(384); - else - mem_remap_top(0); - } break; case REG_RB8: @@ -621,18 +737,20 @@ neat_write(uint16_t port, uint8_t val, void *priv) neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); #endif - ems_update(dev, 0); + ems_remove_handlers(dev); /* Get configured I/O address. */ - j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; - dev->ems_base = 0x0208 + (0x10 * j); + j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; + dev->ems_base = 0x0208 + (0x10 * j); /* Get configured frame address. */ j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j); + ems_update_virt_base(dev); + if (dev->regs[REG_RB7] & RB7_EMSEN) - ems_update(dev, 1); + ems_set_handlers(dev); break; case REG_RB10: @@ -642,18 +760,32 @@ neat_write(uint16_t port, uint8_t val, void *priv) neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); #endif - dev->ems[3].phys_base = (dev->ems[3].phys_base & 0x001fffff) | - (((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21); - dev->ems[2].phys_base = (dev->ems[2].phys_base & 0x001fffff) | - (((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21); - dev->ems[1].phys_base = (dev->ems[1].phys_base & 0x001fffff) | - (((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21); - dev->ems[0].phys_base = (dev->ems[0].phys_base & 0x001fffff) | - (((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21); + for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { + ram_page_t *ems = &(dev->ems[i]); + + uint32_t old_phys_base = ems->phys_base & 0xffe00000; + uint32_t new_phys_base = (((val & masks[i]) >> shifts[i]) << 21); - if (dev->regs[REG_RB7] & RB7_EMSEN) - for (i = 0; i < EMS_MAXPAGE; i++) - ems_recalc(dev, &dev->ems[i]); + if (new_phys_base != old_phys_base) { + int8_t old_enabled = ems->enabled; + + if ((dev->regs[REG_RB7] & RB7_EMSEN) && old_enabled) { + ems->enabled = 0; + ems_recalc(dev, &(dev->ems[i])); + } + + ems->phys_base = ems->phys_base - old_phys_base + new_phys_base; + + if ((dev->regs[REG_RB7] & RB7_EMSEN) && old_enabled) { + ems->enabled = old_enabled; + ems_recalc(dev, &(dev->ems[i])); + } + } + } + + neat_log("%08X, %08X, %08X, %08X\n", + dev->ems[0].phys_base, dev->ems[1].phys_base, + dev->ems[2].phys_base, dev->ems[3].phys_base); break; case REG_RB12: @@ -680,15 +812,12 @@ neat_write(uint16_t port, uint8_t val, void *priv) default: break; } - dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE; - - if (dev->regs[REG_RB7] & RB7_EMSEN) - for (i = 0; i < EMS_MAXPAGE; i++) - ems_recalc(dev, &dev->ems[i]); if (dev->regs[REG_RB7] & RB7_EMSEN) { - neat_log("NEAT: EMS %iKB (%i pages)\n", - dev->ems_size, dev->ems_pages); + remap_update(dev, dev->regs[REG_RB7]); + + neat_log("NEAT: EMS %iKB\n", + dev->ems_size); } mem_a20_key = val & RB12_GA20; @@ -756,12 +885,17 @@ neat_init(UNUSED(const device_t *info)) memset(dev, 0x00, sizeof(neat_t)); /* Get configured I/O address. */ - j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; - dev->ems_base = 0x0208 + (0x10 * j); + j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; + dev->ems_base = 0x0208 + (0x10 * j); /* Get configured frame address. */ - j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; - dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j); + j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH; + dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j); + + ems_update_virt_base(dev); + + dev->ems_pages = (mem_size << 10) / EMS_PGSIZE; + dev->remap_base = mem_size; mem_mapping_disable(&ram_mid_mapping); @@ -773,10 +907,10 @@ neat_init(UNUSED(const device_t *info)) for (uint8_t i = 0; i < EMS_MAXPAGE; i++) { /* Create and initialize a page mapping. */ mem_mapping_add(&dev->ems[i].mapping, - dev->ems_frame + (EMS_PGSIZE * i), EMS_PGSIZE, + 0x00000000, 0x00000000, ems_readb, ems_readw, NULL, ems_writeb, ems_writew, NULL, - ram, MEM_MAPPING_INTERNAL, + ram + dev->ems[i].virt_base, MEM_MAPPING_INTERNAL, &(dev->ems[i])); /* Disable for now. */ From 0063a9f4039fac7dd8ee35820ed9228788c3f0b5 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 12:33:26 +0700 Subject: [PATCH 0102/1190] Name corrections to LG CRN-8245B --- src/include/86box/cdrom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 3895833a6..008f0ddc4 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -151,7 +151,7 @@ static const struct { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, { "HL-DT-ST", "GCE-8525B", "1.01", "HL-DT-ST GCE-8525B 1.01", "HL-DT-ST_GCE-8525B_1.01", BUS_TYPE_IDE }, { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, - { "LG", "CRN-8245B", "1.20", "LG CRN-8245B 1.20", "LG_CRN-8245B_1.20", BUS_TYPE_IDE }, + { "LG", "CD-ROM CRN-8245B", "1.20", "LG CD-ROM CRN-8245B 1.20", "LG_CD-ROM_CRN-8245B_1.20", BUS_TYPE_IDE }, { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, From 72571d6211877d5b5934f74d0ca540b757f2d852 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 14:26:31 +0700 Subject: [PATCH 0103/1190] Added other two models (1x DVD/1x CD) Also updated the revision on CRN-8245B --- src/include/86box/cdrom.h | 8 ++++++-- src/scsi/scsi_cdrom.c | 12 ++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 008f0ddc4..7acfa2cc3 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -72,9 +72,11 @@ enum CDROM_TYPE_GOLDSTAR_CRD_8160B_314, CDROM_TYPE_HITACHI_CDR_8130_0020, CDROM_TYPE_HLDTST_GCE8525B_101, + CDROM_TYPE_HLDTST_GSA4160_A302, CDROM_TYPE_KENWOOD_UCR_421_208E, - CDROM_TYPE_LG_CRN8245B_120, + CDROM_TYPE_LG_CRN8245B_130, CDROM_TYPE_LTN48125S_1S07, + CDROM_TYPE_LTN526D_YSR5, CDROM_TYPE_MATSHITA_585_Z18P, CDROM_TYPE_MATSHITA_587_7S13, CDROM_TYPE_MATSHITA_588_LS15, @@ -150,9 +152,11 @@ static const struct { "GOLDSTAR", "CRD-8160B", "3.14", "GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE }, { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, { "HL-DT-ST", "GCE-8525B", "1.01", "HL-DT-ST GCE-8525B 1.01", "HL-DT-ST_GCE-8525B_1.01", BUS_TYPE_IDE }, + { "HL-DT-ST", "DVDRAM GSA-4160", "A302", "HL-DT-ST DVDRAM GSA-4160 A302", "HL-DT-ST_DVDRAM_GSA-4160_A302", BUS_TYPE_IDE }, { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, - { "LG", "CD-ROM CRN-8245B", "1.20", "LG CD-ROM CRN-8245B 1.20", "LG_CD-ROM_CRN-8245B_1.20", BUS_TYPE_IDE }, + { "LG", "CD-ROM CRN-8245B", "1.30", "LG CD-ROM CRN-8245B 1.30", "LG_CD-ROM_CRN-8245B_1.30", BUS_TYPE_IDE }, { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, + { "LITE-ON", "LTN526D", "YSR5", "LITE-ON LTN526D YSR5", "LITE-ON_LTN526D_YSR5", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, { "MATSHITA", "CD-ROM CR-588", "LS15", "MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE }, diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 9f8a86fc9..1eabc59f6 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -4065,18 +4065,26 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "1.01 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST GCE-8525B ", 40); /* Model */ break; + case CDROM_TYPE_HLDTST_GSA4160_A302: + ide_padstr((char *) (ide->buffer + 23), "A302 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST DVDRAM GSA-4160 ", 40); /* Model */ + break; case CDROM_TYPE_KENWOOD_UCR_421_208E: ide_padstr((char *) (ide->buffer + 23), "208E ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "KENWOOD CD-ROM UCR-421 ", 40); /* Model */ break; - case CDROM_TYPE_LG_CRN8245B_120: - ide_padstr((char *) (ide->buffer + 23), "1.20 ", 8); /* Firmware */ + case CDROM_TYPE_LG_CRN8245B_130: + ide_padstr((char *) (ide->buffer + 23), "1.30 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRN-8245B ", 40); /* Model */ break; case CDROM_TYPE_LTN48125S_1S07: ide_padstr((char *) (ide->buffer + 23), "1S07 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "LTN48125S ", 40); /* Model */ break; + case CDROM_TYPE_LTN526D_YSR5: + ide_padstr((char *) (ide->buffer + 23), "YSR5 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "LTN526D ", 40); /* Model */ + break; case CDROM_TYPE_MATSHITA_585_Z18P: ide_padstr((char *) (ide->buffer + 23), "Z18P ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-585 ", 40); /* Model */ From 2a16c3cea657753ce1bc1d0ba0e6a2c0204adee4 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 16:42:13 +0700 Subject: [PATCH 0104/1190] Added other five models I have forgotten Also changed the HL-DT-ST CD-ROM to reflect the model revision. --- src/include/86box/cdrom.h | 84 ++++++++++++++++++++++----------------- src/scsi/scsi_cdrom.c | 24 ++++++++++- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7acfa2cc3..bd50604bb 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -71,12 +71,15 @@ enum CDROM_TYPE_BTC_BCD36XH_U10, CDROM_TYPE_GOLDSTAR_CRD_8160B_314, CDROM_TYPE_HITACHI_CDR_8130_0020, - CDROM_TYPE_HLDTST_GCE8525B_101, + CDROM_TYPE_HITACHI_GD7500_A1, + CDROM_TYPE_HLDTST_GCR8526B_101, CDROM_TYPE_HLDTST_GSA4160_A302, CDROM_TYPE_KENWOOD_UCR_421_208E, CDROM_TYPE_LG_CRN8245B_130, + CDROM_TYPE_LG_CRD8322B_106, CDROM_TYPE_LTN48125S_1S07, CDROM_TYPE_LTN526D_YSR5, + CDROM_TYPE_MATSHITA_583_107, CDROM_TYPE_MATSHITA_585_Z18P, CDROM_TYPE_MATSHITA_587_7S13, CDROM_TYPE_MATSHITA_588_LS15, @@ -98,6 +101,8 @@ enum CDROM_TYPE_TEAC_CD532E_20A, CDROM_TYPE_TOSHIBA_5302TA_0305, CDROM_TYPE_TOSHIBA_5702B_TA70, + CDROM_TYPE_TOSHIBA_6202B_1512, + CDROM_TYPE_TOSHIBA_6402B_1008, CDROM_TYPE_TOSHIBA_6702B_1007, CDROM_TYPE_TOSHIBA_M1802_1051, CDROM_TYPE_CHINON_CDS431_H42, @@ -144,42 +149,47 @@ static const struct const char *internal_name; const int bus_type; } cdrom_drive_types[] = { - { "86BOX", "CD-ROM", "1.00", "86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_BOTH }, - { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.41", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, - { "ASUS", "CD-S520/A4", "1.32", "ASUS CD-S520/A4 1.32", "ASUS_CD-S520A4_1.32", BUS_TYPE_IDE }, - { "AZT", "CDA46802I", "1.15", "AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE }, - { "BTC", "CD-ROM BCD36XH", "U1.0", "BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE }, - { "GOLDSTAR", "CRD-8160B", "3.14", "GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE }, - { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, - { "HL-DT-ST", "GCE-8525B", "1.01", "HL-DT-ST GCE-8525B 1.01", "HL-DT-ST_GCE-8525B_1.01", BUS_TYPE_IDE }, - { "HL-DT-ST", "DVDRAM GSA-4160", "A302", "HL-DT-ST DVDRAM GSA-4160 A302", "HL-DT-ST_DVDRAM_GSA-4160_A302", BUS_TYPE_IDE }, - { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, - { "LG", "CD-ROM CRN-8245B", "1.30", "LG CD-ROM CRN-8245B 1.30", "LG_CD-ROM_CRN-8245B_1.30", BUS_TYPE_IDE }, - { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, - { "LITE-ON", "LTN526D", "YSR5", "LITE-ON LTN526D YSR5", "LITE-ON_LTN526D_YSR5", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-588", "LS15", "MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE }, - { "MATSHITA", "CR-571", "1.0e", "MATSHITA CR-571 1.0e", "MATSHITA_CR-571_1.0e", BUS_TYPE_IDE }, - { "MATSHITA", "CR-572", "1.0j", "MATSHITA CR-572 1.0j", "MATSHITA_CR-572_1.0j", BUS_TYPE_IDE }, - { "MITSUMI", "CRMC-FX4820T", "D02A", "MITSUMI CRMC-FX4820T D02A", "MITSUMI_CRMC-FX4820T_D02A", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:260", "1.00", "NEC CD-ROM DRIVE:260 1.00", "NEC_CD-ROM_DRIVE260_1.00", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:260", "1.01", "NEC CD-ROM DRIVE:260 1.01", "NEC_CD-ROM_DRIVE260_1.01", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:273", "4.20", "NEC CD-ROM DRIVE:273 4.20", "NEC_CD-ROM_DRIVE273_4.20", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:280", "1.05", "NEC CD-ROM DRIVE:280 1.05", "NEC_CD-ROM_DRIVE280_1.05", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:280", "3.08", "NEC CD-ROM DRIVE:280 3.08", "NEC_CD-ROM_DRIVE280_3.08", BUS_TYPE_IDE }, - { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, - { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU5225", "NYS4", "SONY CD-ROM CDU5225 NYS4", "SONY_CD-ROM_CDU5225_NYS4", BUS_TYPE_IDE }, - { "TEAC", "CD-516E", "1.0G", "TEAC CD-516E 1.0G", "TEAC_CD-516E_1.0G", BUS_TYPE_IDE }, - { "TEAC", "CD-524EA", "3.0D", "TEAC CD-524EA 3.0D", "TEAC_CD-524EA_3.0D", BUS_TYPE_IDE }, - { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, - { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, + { "86BOX", "CD-ROM", "1.00", "86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_BOTH }, + { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.41", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, + { "ASUS", "CD-S520/A4", "1.32", "ASUS CD-S520/A4 1.32", "ASUS_CD-S520A4_1.32", BUS_TYPE_IDE }, + { "AZT", "CDA46802I", "1.15", "AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE }, + { "BTC", "CD-ROM BCD36XH", "U1.0", "BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE }, + { "GOLDSTAR", "CRD-8160B", "3.14", "GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE }, + { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, + { "HITACHI", "GD-7500", "A1 ", "HITACHI GD-7500 A1", "HITACHI_GD-7500_A1", BUS_TYPE_IDE }, + { "HL-DT-ST", "CD-ROM GCR-8526B", "1.01", "HL-DT-ST CD-ROM GCR-8526B 1.01", "HL-DT-ST_CD-ROM_GCR-8526B_1.01", BUS_TYPE_IDE }, + { "HL-DT-ST", "DVDRAM GSA-4160", "A302", "HL-DT-ST DVDRAM GSA-4160 A302", "HL-DT-ST_DVDRAM_GSA-4160_A302", BUS_TYPE_IDE }, + { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, + { "LG", "CD-ROM CRN-8245B", "1.30", "LG CD-ROM CRN-8245B 1.30", "LG_CD-ROM_CRN-8245B_1.30", BUS_TYPE_IDE }, + { "LG", "CD-ROM CRD-8322B", "1.06", "LG CD-ROM CRD-8322B 1.06", "LG_CD-ROM_CRD-8322B_1.06", BUS_TYPE_IDE }, + { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, + { "LITE-ON", "LTN526D", "YSR5", "LITE-ON LTN526D YSR5", "LITE-ON_LTN526D_YSR5", BUS_TYPE_IDE }, + { "MATSHITA", "CD-ROM CR-583", "1.07", "MATSHITA CD-ROM CR-583 1.07", "MATSHITA_CD-ROM_CR-583_1.07", BUS_TYPE_IDE }, + { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, + { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, + { "MATSHITA", "CD-ROM CR-588", "LS15", "MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE }, + { "MATSHITA", "CR-571", "1.0e", "MATSHITA CR-571 1.0e", "MATSHITA_CR-571_1.0e", BUS_TYPE_IDE }, + { "MATSHITA", "CR-572", "1.0j", "MATSHITA CR-572 1.0j", "MATSHITA_CR-572_1.0j", BUS_TYPE_IDE }, + { "MITSUMI", "CRMC-FX4820T", "D02A", "MITSUMI CRMC-FX4820T D02A", "MITSUMI_CRMC-FX4820T_D02A", BUS_TYPE_IDE }, + { "NEC", "CD-ROM DRIVE:260", "1.00", "NEC CD-ROM DRIVE:260 1.00", "NEC_CD-ROM_DRIVE260_1.00", BUS_TYPE_IDE }, + { "NEC", "CD-ROM DRIVE:260", "1.01", "NEC CD-ROM DRIVE:260 1.01", "NEC_CD-ROM_DRIVE260_1.01", BUS_TYPE_IDE }, + { "NEC", "CD-ROM DRIVE:273", "4.20", "NEC CD-ROM DRIVE:273 4.20", "NEC_CD-ROM_DRIVE273_4.20", BUS_TYPE_IDE }, + { "NEC", "CD-ROM DRIVE:280", "1.05", "NEC CD-ROM DRIVE:280 1.05", "NEC_CD-ROM_DRIVE280_1.05", BUS_TYPE_IDE }, + { "NEC", "CD-ROM DRIVE:280", "3.08", "NEC CD-ROM DRIVE:280 3.08", "NEC_CD-ROM_DRIVE280_3.08", BUS_TYPE_IDE }, + { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, + { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, + { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, + { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, + { "SONY", "CD-ROM CDU5225", "NYS4", "SONY CD-ROM CDU5225 NYS4", "SONY_CD-ROM_CDU5225_NYS4", BUS_TYPE_IDE }, + { "TEAC", "CD-516E", "1.0G", "TEAC CD-516E 1.0G", "TEAC_CD-516E_1.0G", BUS_TYPE_IDE }, + { "TEAC", "CD-524EA", "3.0D", "TEAC CD-524EA 3.0D", "TEAC_CD-524EA_3.0D", BUS_TYPE_IDE }, + { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6202B", "1512", "TOSHIBA CD-ROM XM-6202B 1512", "TOSHIBA_CD-ROM_XM-6202B_1512", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6402B", "1008", "TOSHIBA CD-ROM XM-6402B 1008", "TOSHIBA_CD-ROM_XM-6402B_1008", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, + { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 1eabc59f6..91773c62c 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -4061,9 +4061,13 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ break; - case CDROM_TYPE_HLDTST_GCE8525B_101: + case CDROM_TYPE_HITACHI_GD7500_A1: + ide_padstr((char *) (ide->buffer + 23), "A1 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "HITACHI GD-7500 ", 40); /* Model */ + break; + case CDROM_TYPE_HLDTST_GCR8526B_101: ide_padstr((char *) (ide->buffer + 23), "1.01 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST GCE-8525B ", 40); /* Model */ + ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST CD-ROM GCR-8526B ", 40); /* Model */ break; case CDROM_TYPE_HLDTST_GSA4160_A302: ide_padstr((char *) (ide->buffer + 23), "A302 ", 8); /* Firmware */ @@ -4077,6 +4081,10 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "1.30 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRN-8245B ", 40); /* Model */ break; + case CDROM_TYPE_LG_CRD8322B_106: + ide_padstr((char *) (ide->buffer + 23), "1.06 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRD-8322B ", 40); /* Model */ + break; case CDROM_TYPE_LTN48125S_1S07: ide_padstr((char *) (ide->buffer + 23), "1S07 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "LTN48125S ", 40); /* Model */ @@ -4085,6 +4093,10 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "YSR5 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "LTN526D ", 40); /* Model */ break; + case CDROM_TYPE_MATSHITA_583_107: + ide_padstr((char *) (ide->buffer + 23), "1.07 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-583 ", 40); /* Model */ + break; case CDROM_TYPE_MATSHITA_585_Z18P: ide_padstr((char *) (ide->buffer + 23), "Z18P ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-585 ", 40); /* Model */ @@ -4169,6 +4181,14 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide_padstr((char *) (ide->buffer + 23), "TA70 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5702B ", 40); /* Model */ break; + case CDROM_TYPE_TOSHIBA_6202B_1512: + ide_padstr((char *) (ide->buffer + 23), "1512 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6202B ", 40); /* Model */ + break; + case CDROM_TYPE_TOSHIBA_6402B_1008: + ide_padstr((char *) (ide->buffer + 23), "1008 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6402B ", 40); /* Model */ + break; case CDROM_TYPE_TOSHIBA_6702B_1007: ide_padstr((char *) (ide->buffer + 23), "1007 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6702B ", 40); /* Model */ From cd5ad1f6c145386d0f0a902307123d52da4752d7 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 15 Jan 2025 20:12:29 +0700 Subject: [PATCH 0105/1190] Added one recently-added ATA-1 HDD model --- src/disk/hdd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 328d8dcb0..90d01bf9c 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -419,6 +419,7 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-1] Conner CP3024", .internal_name = "CP3024", .model = "Conner Peripherals 20MB - CP3024", .zones = 1, .avg_spt = 33, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work { .name = "[ATA-1] Conner CP3044", .internal_name = "CP3044", .model = "Conner Peripherals 40MB - CP3044", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work { .name = "[ATA-1] Conner CP3104", .internal_name = "CP3104", .model = "Conner Peripherals 104MB - CP3104", .zones = 1, .avg_spt = 33, .heads = 8, .rpm = 3500, .full_stroke_ms = 45, .track_seek_ms = 8, .rcache_num_seg = 4, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work + { .name = "[ATA-1] Conner CFS420A", .internal_name = "CFS420A", .model = "Conner Peripherals 420MB - CFS420A", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, { .name = "[ATA-1] HP Kittyhawk", .internal_name = "C3014A", .model = "HP C3014A", .zones = 6, .avg_spt = 180, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, { .name = "[ATA-1] IBM H3256-A3", .internal_name = "H3256A3", .model = "IBM-H3256-A3", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, { .name = "[ATA-1] IBM H3342-A4", .internal_name = "H3342A4", .model = "IBM-H3342-A4", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, From 2f5940fee34ca0f77b390cb718d6669f1b7c0c32 Mon Sep 17 00:00:00 2001 From: greblosdier <51314920+greblosdier@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:57:51 -0800 Subject: [PATCH 0106/1190] Update 386_dynarec.c Changed exec386_dynarec_dyn from inline to noinline to resolve NEW_DYNAREC build issue on Linux x86_64. --- src/cpu/386_dynarec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 590d6f5c7..d86412103 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -386,7 +386,7 @@ block_ended: cpu_end_block_after_ins = 0; } -static __inline void +static void __attribute__((noinline)) exec386_dynarec_dyn(void) { uint32_t start_pc = 0; From a582223e41c68b7d3dc79e317e4ea528e8a35c44 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 00:58:53 +0100 Subject: [PATCH 0107/1190] NEAT: Actually properly initialize the shadow RAM mappings, fixes #5148. --- src/chipset/neat.c | 47 +++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 3b223bed4..057a9a246 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -345,23 +345,27 @@ neat_mem_update_state(neat_t *dev, uint32_t addr, uint32_t size, uint8_t new_fla new_flags = dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE]; - neat_log("neat_mem_update_state(): %08X-%08X: %02X\n", addr, addr + size - 1, new_flags); - - if (new_flags & RAM_FLAG_EMS) + if (new_flags & RAM_FLAG_EMS) { + neat_log("neat_mem_update_state(): %08X-%08X: %02X (EMS)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else if (new_flags & RAM_FLAG_ROMCS) + } else if (new_flags & RAM_FLAG_ROMCS) { + neat_log("neat_mem_update_state(): %08X-%08X: %02X (ROMCS)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_ROMCS | MEM_WRITE_ROMCS); - else switch (new_flags & (RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE)) { + } else switch (new_flags & (RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE)) { case 0: + neat_log("neat_mem_update_state(): %08X-%08X: %02X (RE | WE)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); break; case 1: + neat_log("neat_mem_update_state(): %08X-%08X: %02X (RE | WI)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); break; case 2: + neat_log("neat_mem_update_state(): %08X-%08X: %02X (RI | WE)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); break; case 3: + neat_log("neat_mem_update_state(): %08X-%08X: %02X (RI | WI)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); break; default: @@ -383,14 +387,24 @@ shadow_recalc(neat_t *dev) int ram_flags; int read; - if (i > 16) { + if (i >= 16) { int rb1_romcs_bit = 7 - (i >> 2); int rb1_write_bit = rb1_romcs_bit + 4; romcs = !(dev->regs[REG_RB1] & (1 << rb1_romcs_bit)); write = !(dev->regs[REG_RB1] & (1 << rb1_write_bit)); - } else if (i <= 8) + neat_log("Shadow %08X-%08X: [%02X, %02X] %02X:%02X, %02X, %02X\n", + dev->shadow[i].virt_base, dev->shadow[i].virt_base + EMS_PGSIZE - 1, + dev->regs[REG_RB1], dev->regs[shadow_reg], + shadow_reg, shadow_bit, + rb1_romcs_bit, rb1_write_bit); + } else { shadow_bit ^= 4; + neat_log("Shadow %08X-%08X: [--, %02X] %02X:%02X, shadow bit ^= 4\n", + dev->shadow[i].virt_base, dev->shadow[i].virt_base + EMS_PGSIZE - 1, + dev->regs[shadow_reg], + shadow_reg, shadow_bit); + } read = dev->regs[shadow_reg] & (1 << shadow_bit); write = write && read; @@ -425,8 +439,7 @@ ems_recalc(neat_t *dev, ram_page_t *ems) /* Update the EMS RAM address for this page. */ mem_mapping_set_exec(&ems->mapping, ram + ems->phys_base); - if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000)) - neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, RAM_FLAG_EMS, RAM_FMASK_EMS); + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, RAM_FLAG_EMS, RAM_FMASK_EMS); #if NEAT_DEBUG > 1 neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n", @@ -436,11 +449,8 @@ ems_recalc(neat_t *dev, ram_page_t *ems) /* Disable this page. */ mem_mapping_disable(&ems->mapping); - if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000)) - neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS); + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS); } - - flushmmucache_nopc(); } static void @@ -921,6 +931,17 @@ neat_init(UNUSED(const device_t *info)) dev->shadow[i].virt_base = dev->shadow[i].phys_base = (i * EMS_PGSIZE) + 0x00080000; dev->shadow[i].enabled = 1; + + /* Create and initialize a page mapping. */ + mem_mapping_add(&dev->shadow[i].mapping, + dev->shadow[i].virt_base, EMS_PGSIZE, + ems_readb, ems_readw, NULL, + ems_writeb, ems_writew, NULL, + ram + dev->shadow[i].virt_base, MEM_MAPPING_INTERNAL, + &(dev->shadow[i])); + + /* Disable for now. */ + mem_mapping_disable(&dev->shadow[i].mapping); } /* Initialize some of the registers to specific defaults. */ From fbafb7507b22d0c5b265b29de37f7025ed74ec82 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 01:14:23 +0100 Subject: [PATCH 0108/1190] Dynamic recompiler: Only disable inline if not on Windows or MacOS. --- src/cpu/386_dynarec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index d86412103..7ad4f30c5 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -386,7 +386,11 @@ block_ended: cpu_end_block_after_ins = 0; } +#if defined(_WIN32) || defined(__APPLE__) +static __inline void +#else static void __attribute__((noinline)) +#endif exec386_dynarec_dyn(void) { uint32_t start_pc = 0; From 48b3bbb7971827d7481b7a2c77f9ca6763f10cb9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 03:34:38 +0100 Subject: [PATCH 0109/1190] NEAT: RA0-RA2 defaults and RA0 alt. reset. --- src/chipset/neat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 057a9a246..3c9838e06 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -237,7 +237,7 @@ typedef struct neat_t { ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; -static uint8_t defaults[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, +static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT }; @@ -628,6 +628,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RA0: val &= RA0_MASK; *reg = (*reg & ~RA0_MASK) | val | (RA0_REV_ID << RA0_REV_SH); + if ((xval & 0x20) && (val & 0x20)) + outb(0x64, 0xfe); #if NEAT_DEBUG > 1 neat_log("NEAT: RA0=%02x(%02x)\n", val, *reg); #endif From a94a5bb0b54e20294fbaaec6b667843dc30ecb6e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 05:48:37 +0100 Subject: [PATCH 0110/1190] Improved the Linux new dynamic recompiler freeze workaround per patch by Dax. --- src/cpu/386_dynarec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 7ad4f30c5..5991cf100 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -386,10 +386,10 @@ block_ended: cpu_end_block_after_ins = 0; } -#if defined(_WIN32) || defined(__APPLE__) -static __inline void +#if defined(__linux__) && !defined(__clang__) && defined(USE_NEW_DYNAREC) +static inline void __attribute__((optimize("O2"))) #else -static void __attribute__((noinline)) +static __inline void #endif exec386_dynarec_dyn(void) { From d8eb77849ca146965e05da889855b02ed6f523bd Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 5 May 2024 23:27:31 -0400 Subject: [PATCH 0111/1190] Corrections to the SixPakPlus --- src/device/isamem.c | 2 +- src/device/isartc.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index 83e938abd..f63a5a5a1 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -1310,7 +1310,7 @@ static const device_config_t a6pak_config[] = { .file_filter = "", .spinner = { .min = 0, - .max = 576, + .max = 384, .step = 64 }, .selection = { { 0 } } diff --git a/src/device/isartc.c b/src/device/isartc.c index 7721d9885..b56718400 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -714,8 +714,9 @@ static const device_config_t a6pak_config[] = { { { "Disabled", -1 }, { "IRQ2", 2 }, - { "IRQ3", 3 }, + { "IRQ4", 4 }, { "IRQ5", 5 }, + { "IRQ7", 7 }, { "" } }, }, From 3f3b921831cf689b532f93d7ef51b5e32f37ec2f Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 May 2024 06:40:57 -0400 Subject: [PATCH 0112/1190] Add Generic MM58167 RTC --- src/device/isartc.c | 122 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 11 deletions(-) diff --git a/src/device/isartc.c b/src/device/isartc.c index b56718400..61b07dc1a 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -76,17 +76,23 @@ #include <86box/machine.h> #include <86box/io.h> #include <86box/device.h> +#include <86box/mem.h> #include <86box/nvr.h> +#include <86box/rom.h> #include <86box/ui.h> #include <86box/plat.h> #include <86box/pic.h> #include <86box/isartc.h> -#define ISARTC_EV170 0 -#define ISARTC_DTK 1 -#define ISARTC_P5PAK 2 -#define ISARTC_A6PAK 3 -#define ISARTC_VENDEX 4 +#define ISARTC_EV170 0 +#define ISARTC_DTK 1 +#define ISARTC_P5PAK 2 +#define ISARTC_A6PAK 3 +#define ISARTC_VENDEX 4 +#define ISARTC_MM58167 10 + +#define ISARTC_ROM_MM58167_1 "roms/rtc/glatick/GLaTICK_0.8.5_NS_RP.ROM" +#define ISARTC_ROM_MM58167_2 "roms/rtc/glatick/GLaTICK_0.8.5_86B.ROM" #define ISARTC_DEBUG 0 @@ -101,6 +107,7 @@ typedef struct rtcdev_t { int8_t irq; /* configured IRQ channel */ int8_t base_addrsz; uint32_t base_addr; /* configured I/O address */ + rom_t rom; /* BIOS ROM, If configured */ /* Fields for the specific driver. */ void (*f_wr)(uint16_t, uint8_t, void *); @@ -524,6 +531,14 @@ isartc_init(const device_t *info) /* Do per-board initialization. */ switch (dev->board) { + case ISARTC_MM58167: /* Generic MM58167 RTC */ + { + int rom_addr = device_get_config_hex20("bios_addr"); + if (rom_addr != -1) + rom_init(&dev->rom, ISARTC_ROM_MM58167_1, + rom_addr, 0x0800, 0x7ff, 0, MEM_MAPPING_EXTERNAL); + + } case ISARTC_EV170: /* Everex EV-170 Magic I/O */ dev->flags |= FLAG_YEAR80; dev->base_addr = device_get_config_hex16("base"); @@ -738,6 +753,90 @@ static const device_t a6pak_device = { .config = a6pak_config }; +static const device_config_t mm58167_config[] = { + // clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x02C0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { "240H", 0x0240 }, + { "2C0H", 0x02c0 }, + { "340H", 0x0340 }, + { "" } + }, + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = -1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { "Disabled", -1 }, + { "IRQ2", 2 }, + { "IRQ5", 5 }, + { "IRQ7", 7 }, + { "" } + }, + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = "", + .default_int = 0xcc000, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = -1 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D200H", .value = 0xd2000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D600H", .value = 0xd6000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DA00H", .value = 0xda000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "DE00H", .value = 0xde000 }, + { .description = "E000H", .value = 0xe0000 }, + { .description = "E200H", .value = 0xe2000 }, + { .description = "E400H", .value = 0xe4000 }, + { .description = "E600H", .value = 0xe6000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EA00H", .value = 0xea000 }, + { .description = "EC00H", .value = 0xec000 }, + { .description = "EE00H", .value = 0xee000 }, + { .description = "" } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +static const device_t mm58167_device = { + .name = "Generic MM58167 RTC", + .internal_name = "rtc_mm58167", + .flags = DEVICE_ISA, + .local = ISARTC_MM58167, + .init = isartc_init, + .close = isartc_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = mm58167_config +}; + /* Onboard RTC devices */ const device_t vendex_xt_rtc_onboard_device = { .name = "National Semiconductor MM58167 (Vendex)", @@ -757,12 +856,13 @@ static const struct { const device_t *dev; } boards[] = { // clang-format off - { &device_none }, - { &ev170_device }, - { &pii147_device }, - { &p5pak_device }, - { &a6pak_device }, - { NULL }, + { &device_none }, + { &ev170_device }, + { &pii147_device }, + { &p5pak_device }, + { &a6pak_device }, + { &mm58167_device }, + { NULL } // clang-format on }; From 3189bf7fb8eea58c3654b8875d3378e5e1ae8169 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 13 Jan 2025 22:06:59 -0500 Subject: [PATCH 0113/1190] Cleanups in isartc --- src/device/isartc.c | 111 ++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/src/device/isartc.c b/src/device/isartc.c index 61b07dc1a..77f35ffc7 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -629,24 +629,36 @@ isartc_close(void *priv) static const device_config_t ev170_config[] = { // clang-format off { - "base", "Address", CONFIG_HEX16, "", 0x02C0, "", { 0 }, - { - { "240H", 0x0240 }, - { "2C0H", 0x02c0 }, - { "" } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x02C0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "240H", .value = 0x0240 }, + { .description = "2C0H", .value = 0x02c0 }, + { .description = "" } }, }, { - "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, - { - { "Disabled", -1 }, - { "IRQ2", 2 }, - { "IRQ5", 5 }, - { "IRQ7", 7 }, - { "" } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = -1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = -1 }, + { .description = "IRQ2", .value = 2 }, + { .description = "IRQ5", .value = 5 }, + { .description = "IRQ7", .value = 7 }, + { .description = "" } }, }, - { "", "", -1 } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -658,7 +670,7 @@ static const device_t ev170_device = { .init = isartc_init, .close = isartc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ev170_config @@ -667,14 +679,20 @@ static const device_t ev170_device = { static const device_config_t pii147_config[] = { // clang-format off { - "base", "Address", CONFIG_HEX16, "", 0x0240, "", { 0 }, - { - { "Clock 1", 0x0240 }, - { "Clock 2", 0x0340 }, - { "" } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = "", + .default_int = 0x0240, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Clock 1", .value = 0x0240 }, + { .description = "Clock 2", .value = 0x0340 }, + { .description = "" } }, }, - { "", "", -1 } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -686,7 +704,7 @@ static const device_t pii147_device = { .init = isartc_init, .close = isartc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pii147_config @@ -695,16 +713,22 @@ static const device_t pii147_device = { static const device_config_t p5pak_config[] = { // clang-format off { - "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, - { - { "Disabled", -1 }, - { "IRQ2", 2 }, - { "IRQ3", 3 }, - { "IRQ5", 5 }, - { "" } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = -1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", -1 }, + { .description = "IRQ2", 2 }, + { .description = "IRQ3", 3 }, + { .description = "IRQ5", 5 }, + { .description = "" } }, }, - { "", "", -1 } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -716,7 +740,7 @@ static const device_t p5pak_device = { .init = isartc_init, .close = isartc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = p5pak_config @@ -725,17 +749,22 @@ static const device_t p5pak_device = { static const device_config_t a6pak_config[] = { // clang-format off { - "irq", "IRQ", CONFIG_SELECTION, "", -1, "", { 0 }, - { - { "Disabled", -1 }, - { "IRQ2", 2 }, - { "IRQ4", 4 }, - { "IRQ5", 5 }, - { "IRQ7", 7 }, - { "" } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = -1, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = -1 }, + { .description = "IRQ2", .value = 2 }, + { .description = "IRQ3", .value = 3 }, + { .description = "IRQ5", .value = 5 }, + { .description = "" } }, }, - { "", "", -1 } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -747,7 +776,7 @@ static const device_t a6pak_device = { .init = isartc_init, .close = isartc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = a6pak_config @@ -846,7 +875,7 @@ const device_t vendex_xt_rtc_onboard_device = { .init = isartc_init, .close = isartc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL From b61751a6d0944482dfe2526a2538d0d40f6416ff Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 15 Jan 2025 23:45:00 -0500 Subject: [PATCH 0114/1190] CONFIG_BIOS for ibmat (5170) --- src/machine/m_at.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index fea87c8f6..93d111510 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -153,6 +153,29 @@ machine_at_ps2_ide_init(const machine_t *model) static const device_config_t ibmat_config[] = { // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ibm5170_111585", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "62X082x (11/15/85)", .internal_name = "ibm5170_111585", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmat/BIOS_5170_15NOV85_U27.BIN", "roms/machines/ibmat/BIOS_5170_15NOV85_U47.BIN", "" } }, + + { .name = "61X9266 (11/15/85) (Alt)", .internal_name = "ibm5170_111585_alt", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmat/BIOS_5170_15NOV85_U27_61X9266.BIN", "roms/machines/ibmat/BIOS_5170_15NOV85_U47_61X9265.BIN", "" } }, + + { .name = "648009x (06/10/85)", .internal_name = "ibm5170_061085", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmat/BIOS_5170_10JUN85_U27.BIN", "roms/machines/ibmat/BIOS_5170_10JUN85_U47.BIN", "" } }, + + { .name = "618102x (01/10/84)", .internal_name = "ibm5170_011084", .bios_type = BIOS_NORMAL, + .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmat/BIOS_5170_10JAN84_U27.BIN", "roms/machines/ibmat/BIOS_5170_10JAN84_U47.BIN", "" } }, + { .files_no = 0 } + }, + }, { .name = "enable_5161", .description = "IBM 5161 Expansion Unit", @@ -180,17 +203,21 @@ const device_t ibmat_device = { int machine_at_ibm_init(const machine_t *model) { - int ret; - uint8_t enable_5161; + int ret; + uint8_t enable_5161; + const char *fn[2]; + + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; device_context(model->device); enable_5161 = machine_get_config_int("enable_5161"); + fn[0] = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + fn[1] = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); + ret = bios_load_interleaved(fn[0], fn[1], 0x000f0000, 65536, 0); device_context_restore(); - ret = bios_load_interleaved("roms/machines/ibmat/62x0820.u27", - "roms/machines/ibmat/62x0821.u47", - 0x000f0000, 65536, 0); - if (bios_only || !ret) return ret; From 2eb65625f93338ce3da36cc2b90f6d80c54013c8 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Thu, 16 Jan 2025 00:36:23 -0500 Subject: [PATCH 0115/1190] GlaBIOS for 5150/5160 --- src/machine/m_xt.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 7b59686d6..2988ec201 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -74,6 +74,13 @@ static const device_config_t ibmpc_config[] = { .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc/BIOS_IBM5150_19OCT81_5700671_U33.BIN", "" } }, { .name = "5700051 (04/24/81)", .internal_name = "ibm5150_5700051", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc/BIOS_IBM5150_24APR81_5700051_U33.BIN", "" } }, + + // GlaBIOS for IBM PC + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8P.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VP.ROM", "" } }, + // The following are Diagnostic ROMs. { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, @@ -177,6 +184,13 @@ static const device_config_t ibmpc82_config[] = { .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc82/BIOS_5150_27OCT82_1501476_U33.BIN", "" } }, { .name = "5000024 (08/16/82)", .internal_name = "ibm5150_5000024", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/ibmpc82/BIOS_5150_16AUG82_5000024_U33.BIN", "" } }, + + // GlaBIOS for IBM PC + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8P.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VP.ROM", "" } }, + // The following are Diagnostic ROMs. { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, @@ -283,6 +297,12 @@ static const device_config_t ibmxt_config[] = { { .name = "5000026 (08/16/82)", .internal_name = "ibm5160_5000026_5000027", .bios_type = BIOS_NORMAL, .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt/BIOS_5160_16AUG82_U18_5000026.BIN", "roms/machines/ibmxt/BIOS_5160_16AUG82_U19_5000027.BIN", "" } }, #if 0 + // GlaBIOS for IBM XT + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8X.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VX.ROM", "" } }, + // The following are Diagnostic ROMs. { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, @@ -399,6 +419,12 @@ static const device_config_t ibmxt86_config[] = { { .name = "1501512 (01/10/86) (Alt)", .internal_name = "ibm5160_011086_alt", .bios_type = BIOS_NORMAL, .files_no = 2, .local = 0, .size = 65536, .files = { "roms/machines/ibmxt86/BIOS_5160_10JAN86_U18_62X0852_27256_F800.BIN", "roms/machines/ibmxt86/BIOS_5160_10JAN86_U19_62X0853_27256_F000.BIN", "" } }, #if 0 + // GlaBIOS for IBM XT + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8X.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 40960, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VX.ROM", "" } }, + // The following are Diagnostic ROMs. { .name = "Supersoft Diagnostics", .internal_name = "diag_supersoft", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 65536, .files = { "roms/machines/diagnostic/Supersoft_PCXT_8KB.bin", "" } }, From 43cf6e0b51b537ef708f531edb2b2de340f7154f Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Thu, 16 Jan 2025 13:07:23 +0700 Subject: [PATCH 0116/1190] Added 9 more ATA-4/ATA-5 HDD models -Small corrections to ATA-4 Western Digital HDD models -Line fixes to cdrom.h --- src/disk/hdd.c | 27 ++++++++++++++++++--------- src/include/86box/cdrom.h | 12 ++++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 90d01bf9c..6872c7ae1 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -507,30 +507,39 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-4] Seagate Medalist 6531", .internal_name = "ST36531A", .model = "ST36531A", .zones = 16, .avg_spt = 115, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 90, .heads = 2, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 90, .heads = 4, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 13030", .internal_name = "ST313030A", .model = "ST313030A", .zones = 16, .avg_spt = 90, .heads = 6, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 17240", .internal_name = "ST317240A", .model = "ST317240A", .zones = 16, .avg_spt = 90, .heads = 8, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-4] Toshiba MK4006MAV", .internal_name = "MK4006MAV", .model = "TOSHIBA MK4006MAV", .zones = 8, .avg_spt = 130, .heads = 6, .rpm = 4200, .full_stroke_ms = 25, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300-00RT", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200-00LB", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400-00RN", .zones = 16, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200-00LA", .zones = 16, .avg_spt = 110, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300RT", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200LB", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400RN", .zones = 16, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200LA", .zones = 16, .avg_spt = 110, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 92, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 92, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 92, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91021U2)", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91531U3)", .internal_name = "91531U3", .model = "Maxtor 91531U3", .zones = 16, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (92041U4)", .internal_name = "92041U4", .model = "Maxtor 92041U4", .zones = 16, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 110, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 89, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 89, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 89, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 17.2gb", .internal_name = "ST317221A", .model = "ST317221A", .zones = 16, .avg_spt = 89, .heads = 3, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Western Digital Caviar 102AA", .internal_name = "WD102AA", .model = "WDC WD102AA-00ANA0", .zones = 16, .avg_spt = 95, .heads = 8, .rpm = 5400, .full_stroke_ms = 12, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Western Digital Expert", .internal_name = "WD135BA", .model = "WDC WD135BA-60AK", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 1920, .max_multiple = 32 }, // clang-format on diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index bd50604bb..f28bba517 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -184,12 +184,12 @@ static const struct { "TEAC", "CD-516E", "1.0G", "TEAC CD-516E 1.0G", "TEAC_CD-516E_1.0G", BUS_TYPE_IDE }, { "TEAC", "CD-524EA", "3.0D", "TEAC CD-524EA 3.0D", "TEAC_CD-524EA_3.0D", BUS_TYPE_IDE }, { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6202B", "1512", "TOSHIBA CD-ROM XM-6202B 1512", "TOSHIBA_CD-ROM_XM-6202B_1512", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6402B", "1008", "TOSHIBA CD-ROM XM-6402B 1008", "TOSHIBA_CD-ROM_XM-6402B_1008", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, - { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6202B", "1512", "TOSHIBA CD-ROM XM-6202B 1512", "TOSHIBA_CD-ROM_XM-6202B_1512", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6402B", "1008", "TOSHIBA CD-ROM XM-6402B 1008", "TOSHIBA_CD-ROM_XM-6402B_1008", BUS_TYPE_IDE }, + { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, + { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, From 15684d6665d671ab59d163d2d4d3d9ab80341b09 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Thu, 16 Jan 2025 01:18:00 -0500 Subject: [PATCH 0117/1190] Initialized ret to 0 --- src/machine/m_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 93d111510..3f5e88011 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -203,7 +203,7 @@ const device_t ibmat_device = { int machine_at_ibm_init(const machine_t *model) { - int ret; + int ret = 0; uint8_t enable_5161; const char *fn[2]; From fceca8d1db0829939b637e6b6b810a378c641f85 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Thu, 16 Jan 2025 20:51:32 +0700 Subject: [PATCH 0118/1190] Added note on CFS1275A --- src/disk/hdd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 6872c7ae1..f10d1f3bf 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -469,7 +469,7 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[ATA-3] Connor CFS1275A", .internal_name = "CFS1275A", .model = "Connor Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-3] Connor CFS1275A", .internal_name = "CFS1275A", .model = "Connor Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, From 7696b1c13126c70ccc4de8a8c39748488667c72b Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Fri, 17 Jan 2025 03:02:19 +0700 Subject: [PATCH 0119/1190] A small fix to SV2046D --- src/disk/hdd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index f10d1f3bf..c17f64863 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -535,7 +535,7 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV2046D", .zones = 8, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 89, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 89, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 89, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, From ba86e5116f67dba7756f6451bfa59e4b3b67bc53 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Thu, 16 Jan 2025 22:28:34 +0200 Subject: [PATCH 0120/1190] GlaBIOS for Juko ST --- src/machine/m_xt.c | 52 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 2988ec201..ef3a84e24 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -594,13 +594,59 @@ machine_xt_dtk_init(const machine_t *model) return ret; } +static const device_config_t jukopc_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "jukost", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "Bios 2.30", .internal_name = "jukost", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 8192, .files = { "roms/machines/jukopc/000o001.bin", "" } }, + // GlaBIOS for Juko ST + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 8192, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8S_2.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 8192, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VS_2.ROM", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t jukopc_device = { + .name = "Juko ST Devices", + .internal_name = "jukopc_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = jukopc_config +}; + int machine_xt_jukopc_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/jukopc/000o001.bin", - 0x000fe000, 8192, 0); + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fe000, 8192, 0); + device_context_restore(); if (bios_only || !ret) return ret; From b293aa518c03e91f0a926695ab1edadb966e8cc2 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Thu, 16 Jan 2025 22:31:45 +0200 Subject: [PATCH 0121/1190] GlaBIOS for Juko ST --- src/machine/machine_table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 47a33fa8c..14ad58f95 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -64,6 +64,7 @@ extern const device_t ibmxt86_device; extern const device_t ibmat_device; extern const device_t ibmxt286_device; extern const device_t pb450_device; +extern const device_t jukopc_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -954,7 +955,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &jukopc_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, From 54a0bb8522dbf2a061f762b43f6846e1dae1d160 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 16 Jan 2025 22:37:52 +0100 Subject: [PATCH 0122/1190] 1st set of changes (video-related) of the day (January 16th, 2025) ATI Mach8-based (add-on only): Do not override the clone VGA banked mapping with the standard VGA when needed. Fixes issues with banked mapping with ATI 8514/A enabled on cards with clone mappings such as Cirrus, Video7, Paradise/WD, etc. --- src/video/vid_ati_mach8.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 558f37f5b..d294f61e9 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -3493,14 +3493,17 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 dev->vendor_mode = 1; } svga_recalctimings(svga); - mach32_updatemapping(mach, svga); + if ((dev->local & 0xff) >= 0x01) + mach32_updatemapping(mach, svga); + mach_log("ATI 8514/A: (0x%04x) val=0x%02x, extended 8514/A mode=%02x.\n", port, val, mach->regs[0xb0] & 0x20); break; case 0x32ee: case 0x32ef: WRITE8(port, mach->local_cntl, val); - mach32_updatemapping(mach, svga); + if ((dev->local & 0xff) >= 0x01) + mach32_updatemapping(mach, svga); break; case 0x36ee: @@ -3546,7 +3549,8 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d.\n", port, mach->accel.clock_sel & 0x01, val, dev->hdisp, dev->vdisp); mach_log("Vendor ATI mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); svga_recalctimings(svga); - mach32_updatemapping(mach, svga); + if ((dev->local & 0xff) >= 0x01) + mach32_updatemapping(mach, svga); break; case 0x52ee: @@ -3580,7 +3584,8 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 if (!mach->pci_bus) mach->linear_base = (mach->memory_aperture & 0xff00) << 12; - mach32_updatemapping(mach, svga); + if ((dev->local & 0xff) >= 0x01) + mach32_updatemapping(mach, svga); break; case 0x62ee: From 9a13eb7413bbe655a5ffd4de8481cc2e2cc7ad74 Mon Sep 17 00:00:00 2001 From: greblosdier <51314920+greblosdier@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:46:01 -0800 Subject: [PATCH 0123/1190] Fix incorrect chipset for MVI486 Changes the chipset of the Mylex MVI486 from Opti 82C895 to 82C495 --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 47a33fa8c..58ad404f4 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5962,10 +5962,10 @@ const machine_t machines[] = { /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix copyright. */ { - .name = "[OPTi 895] Mylex MVI486", + .name = "[OPTi 495] Mylex MVI486", .internal_name = "mvi486", .type = MACHINE_TYPE_486, - .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .chipset = MACHINE_CHIPSET_OPTI_495, .init = machine_at_mvi486_init, .p1_handler = NULL, .gpio_handler = NULL, From 5d25309027fac853bb8a2d890fe889c4c8f6e561 Mon Sep 17 00:00:00 2001 From: greblosdier <51314920+greblosdier@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:49:43 -0800 Subject: [PATCH 0124/1190] Fixes incorrect chipset model for MVI486 Fixes MVI486 to use Opti 495 chipset --- src/machine/m_at_386dx_486.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index d3c7a21d2..656db503b 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -834,7 +834,7 @@ machine_at_mvi486_init(const machine_t *model) machine_at_common_init(model); - device_add(&opti895_device); + device_add(&opti495_device); device_add(&keyboard_at_device); device_add(&pc87311_ide_device); From ef8a3d8d427bfbc327331fc9d4f72c39f9dce6c8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 23:18:41 +0100 Subject: [PATCH 0125/1190] SCAMP: Reworked a lot of stuff, backfill EMS should now also work. --- src/chipset/scamp.c | 848 +++++++++++++++++++++++++++----------------- 1 file changed, 520 insertions(+), 328 deletions(-) diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 00f9798cb..31e24eeba 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -47,13 +47,35 @@ #define ID_VL82C311 0xd6 -#define RAMMAP_REMP386 (1 << 4) +#define RAMMAP_ROMMOV 0x60 +#define RAMMAP_ROMMOV1 (1 << 6) +#define RAMMAP_ROMMOV0 (1 << 5) +#define RAMMAP_REMP384 (1 << 4) #define EMSEN1_EMSMAP (1 << 4) +#define EMSEN1_BFENAB (1 << 6) #define EMSEN1_EMSENAB (1 << 7) #define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) +#define EMS_MAXPAGE 4 +#define EMS_PGSIZE 16384 +#define EMS_PGMASK 16383 + +#define MEM_FLAG_SLOTBUS 0x40 +#define MEM_FLAG_REMAP 0x20 +#define MEM_FLAG_MEMCARD 0x10 +#define MEM_FLAG_EMS 0x08 +#define MEM_FLAG_ROMCS 0x04 +#define MEM_FLAG_READ 0x02 +#define MEM_FLAG_WRITE 0x01 +#define MEM_FMASK_SLOTBUS 0x40 +#define MEM_FMASK_REMAP 0x20 +#define MEM_FMASK_MEMCARD 0x10 +#define MEM_FMASK_EMS 0x08 +#define MEM_FMASK_ROMCS 0x04 +#define MEM_FMASK_RW 0x03 + /*Commodore SL386SX requires proper memory slot decoding to detect memory size. Therefore we emulate the SCAMP memory address decoding, and therefore are limited to the DRAM combinations supported by the actual chip*/ @@ -72,38 +94,43 @@ typedef struct ram_struct_t { int bank; } ram_struct_t; -typedef struct ems_struct_t { - void *parent; - int segment; -} ems_struct_t; +typedef struct card_mem_t { + int in_ram; + uint32_t virt_addr; + uint32_t phys_addr; + uint8_t *mem; +} mem_page_t; typedef struct scamp_t { - int cfg_index; - uint8_t cfg_regs[256]; - int cfg_enable; - int ram_config; + int cfg_index; + uint8_t cfg_regs[256]; + int cfg_enable; + int ram_config; int ems_index; int ems_autoinc; - uint16_t ems[0x24]; - mem_mapping_t ems_mappings[20]; /*a0000-effff*/ - uint32_t mappings[20]; + uint16_t ems[64]; mem_mapping_t ram_mapping[2]; ram_struct_t ram_struct[2]; - ems_struct_t ems_struct[20]; - uint32_t ram_virt_base[2]; - uint32_t ram_phys_base[2]; - uint32_t ram_mask[2]; - int row_virt_shift[2]; - int row_phys_shift[2]; - int ram_interleaved[2]; - int ibank_shift[2]; + uint32_t ram_virt_base[2]; + uint32_t ram_phys_base[2]; + uint32_t ram_mask[2]; + int row_virt_shift[2]; + int row_phys_shift[2]; + int ram_interleaved[2]; + int ibank_shift[2]; - int ram_flags[24]; + int mem_flags[64]; + mem_mapping_t mem_mappings[64]; /* The entire first 1 MB of memory space. */ + mem_page_t mem_pages[64]; - port_92_t *port_92; + uint32_t card_mem_size; + uint8_t *card_mem; + mem_page_t card_pages[4]; + + port_92_t *port_92; } scamp_t; static const struct { @@ -149,6 +176,70 @@ static const struct { { { BANK_1M_INTERLEAVED, BANK_4M_INTERLEAVED }, 0}, /*Undocumented - probably wrong!*/ }; +#ifdef ENABLE_SCAMP_LOG +int scamp_do_log = ENABLE_SCAMP_LOG; + +static void +scamp_log(const char *fmt, ...) +{ + va_list ap; + + if (scamp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define scamp_log(fmt, ...) +#endif + +/* Read one byte from paged RAM. */ +static uint8_t +scamp_mem_readb(uint32_t addr, void *priv) +{ + mem_page_t *dev = (mem_page_t *) priv; + uint8_t ret = 0xff; + + if (dev->mem != NULL) + ret = *(uint8_t *) &(dev->mem[addr & EMS_PGMASK]); + + return ret; +} + +/* Read one word from paged RAM. */ +static uint16_t +scamp_mem_readw(uint32_t addr, void *priv) +{ + mem_page_t *dev = (mem_page_t *) priv; + uint16_t ret = 0xffff; + + if (dev->mem != NULL) + ret = *(uint16_t *) &(dev->mem[addr & EMS_PGMASK]); + + return ret; +} + +/* Write one byte to paged RAM. */ +static void +scamp_mem_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_page_t *dev = (mem_page_t *) priv; + + if (dev->mem != NULL) + *(uint8_t *) &(dev->mem[addr & EMS_PGMASK]) = val; +} + +/* Write one word to paged RAM. */ +static void +scamp_mem_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_page_t *dev = (mem_page_t *) priv; + + if (dev->mem != NULL) + *(uint16_t *) &(dev->mem[addr & EMS_PGMASK]) = val; +} + /* The column bits masked when using 256kbit DRAMs in 4Mbit mode aren't contiguous, so we use separate routines for that special case */ static uint8_t @@ -334,208 +425,193 @@ recalc_mappings(void *priv) /* Once the BIOS programs the correct DRAM configuration, switch to regular linear memory mapping */ if (cur_rammap == ram_configs[dev->ram_config].rammap) { - mem_mapping_set_handler(&ram_low_mapping, - mem_read_ram, mem_read_ramw, mem_read_raml, - mem_write_ram, mem_write_ramw, mem_write_raml); - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_disable(&ram_low_mapping); + + for (uint8_t i = 0; i < 40; i++) + mem_mapping_enable(&(dev->mem_mappings[i])); + if (mem_size > 1024) mem_set_mem_state_both((1 << 20), (mem_size - 1024) << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_enable(&ram_high_mapping); - return; } else { mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_read, NULL, NULL, ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_low_mapping); - } - if (rammap[cur_rammap].bank[0] == BANK_NONE) - bank_nr = 1; + for (uint8_t i = 0; i < 40; i++) + mem_mapping_disable(&(dev->mem_mappings[i])); - for (; bank_nr < 2; bank_nr++) { - old_virt_base = virt_base; - phys_bank = ram_configs[dev->ram_config].bank[bank_nr]; + if (rammap[cur_rammap].bank[0] == BANK_NONE) + bank_nr = 1; - dev->ram_virt_base[bank_nr] = virt_base; + for (; bank_nr < 2; bank_nr++) { + old_virt_base = virt_base; + phys_bank = ram_configs[dev->ram_config].bank[bank_nr]; - if (virt_base == 0) { - switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_NONE: - fatal(" Bank %i is empty!\n }\n}\n", bank_nr); - break; + dev->ram_virt_base[bank_nr] = virt_base; - case BANK_256K: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - } - virt_base += (1 << 19); - dev->row_virt_shift[bank_nr] = 10; - break; + if (virt_base == 0) { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + fatal(" Bank %i is empty!\n }\n}\n", bank_nr); + break; - case BANK_256K_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - } - virt_base += (1 << 20); - dev->row_virt_shift[bank_nr] = 10; - break; + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + } + virt_base += (1 << 19); + dev->row_virt_shift[bank_nr] = 10; + break; - case BANK_1M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x100000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - mem_set_mem_state_both((1 << 20), (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 21); - dev->row_virt_shift[bank_nr] = 11; - break; + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + } + virt_base += (1 << 20); + dev->row_virt_shift[bank_nr] = 10; + break; - case BANK_1M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x300000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - mem_set_mem_state_both((1 << 20), (3 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 22); - dev->row_virt_shift[bank_nr] = 11; - break; + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 21); + dev->row_virt_shift[bank_nr] = 11; + break; - case BANK_4M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x700000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - mem_set_mem_state_both((1 << 20), (7 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 23); - dev->row_virt_shift[bank_nr] = 12; - break; + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x300000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (3 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 22); + dev->row_virt_shift[bank_nr] = 11; + break; - case BANK_4M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); - mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0xf00000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); - mem_set_mem_state_both((1 << 20), (15 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 24); - dev->row_virt_shift[bank_nr] = 12; - break; + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x700000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (7 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 23); + dev->row_virt_shift[bank_nr] = 12; + break; - default: - break; + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *) &dev->ram_struct[bank_nr]); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0xf00000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + mem_set_mem_state_both((1 << 20), (15 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 24); + dev->row_virt_shift[bank_nr] = 12; + break; + + default: + break; + } + } else { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + break; + + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x80000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 19), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 19); + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 20); + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x200000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 21), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 21); + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x400000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 22), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 22); + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x800000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 23), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 23); + dev->row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x1000000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + mem_set_mem_state_both(virt_base, (1 << 24), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + virt_base += (1 << 24); + dev->row_virt_shift[bank_nr] = 12; + break; + + default: + break; + } } - } else { + switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_NONE: - break; - case BANK_256K: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x80000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 19), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 19); - dev->row_virt_shift[bank_nr] = 10; - break; - - case BANK_256K_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x100000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 20), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 20); - dev->row_virt_shift[bank_nr] = 10; - break; - case BANK_1M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x200000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 21), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 21); - dev->row_virt_shift[bank_nr] = 11; - break; - - case BANK_1M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x400000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 22), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 22); - dev->row_virt_shift[bank_nr] = 11; - break; - case BANK_4M: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x800000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 23), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 23); - dev->row_virt_shift[bank_nr] = 12; - break; - - case BANK_4M_INTERLEAVED: - if (phys_bank != BANK_NONE) { - mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x1000000); - mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); - mem_set_mem_state_both(virt_base, (1 << 24), MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } - virt_base += (1 << 24); - dev->row_virt_shift[bank_nr] = 12; - break; - - default: - break; - } - } - switch (rammap[cur_rammap].bank[bank_nr]) { - case BANK_256K: - case BANK_1M: - case BANK_4M: - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], - ram_mirrored_read, NULL, NULL, - ram_mirrored_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_read, NULL, NULL, ram_mirrored_write, NULL, NULL); - break; - - case BANK_256K_INTERLEAVED: - case BANK_1M_INTERLEAVED: - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], - ram_mirrored_interleaved_read, NULL, NULL, - ram_mirrored_interleaved_write, NULL, NULL); - if (!old_virt_base) - mem_mapping_set_handler(&ram_low_mapping, - ram_mirrored_interleaved_read, NULL, NULL, - ram_mirrored_interleaved_write, NULL, NULL); - break; - - case BANK_4M_INTERLEAVED: - if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) { - mem_mapping_set_handler(&dev->ram_mapping[bank_nr], - ram_mirrored_256k_in_4mi_read, NULL, NULL, - ram_mirrored_256k_in_4mi_write, NULL, NULL); if (!old_virt_base) mem_mapping_set_handler(&ram_low_mapping, - ram_mirrored_256k_in_4mi_read, NULL, NULL, - ram_mirrored_256k_in_4mi_write, NULL, NULL); - } else { + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + break; + + case BANK_256K_INTERLEAVED: + case BANK_1M_INTERLEAVED: mem_mapping_set_handler(&dev->ram_mapping[bank_nr], ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); @@ -543,131 +619,137 @@ recalc_mappings(void *priv) mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_interleaved_read, NULL, NULL, ram_mirrored_interleaved_write, NULL, NULL); - } - break; + break; - default: - break; + case BANK_4M_INTERLEAVED: + if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + } else { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + } + break; + + default: + break; + } } } } static void -recalc_sltptr(scamp_t *dev) +scamp_mem_update_state(scamp_t *dev, uint32_t addr, uint32_t size, uint8_t new_flags, uint8_t mask) { - uint32_t sltptr = dev->cfg_regs[CFG_SLTPTR] << 16; + int read_ext = MEM_READ_EXTERNAL; + int write_ext = MEM_WRITE_EXTERNAL; - if (sltptr >= 0xa0000 && sltptr < 0x100000) - sltptr = 0x100000; - if (sltptr > 0xfe0000) - sltptr = 0xfe0000; + if ((addr < 0x00100000) && ((new_flags ^ dev->mem_flags[addr / EMS_PGSIZE]) & mask)) { + dev->mem_flags[addr / EMS_PGSIZE] &= ~mask; + dev->mem_flags[addr / EMS_PGSIZE] |= new_flags; - if (sltptr >= 0xa0000) { - mem_set_mem_state(0, 0xa0000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state(0x100000, sltptr - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state(sltptr, 0x1000000 - sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - } else { - mem_set_mem_state(0, sltptr, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state(sltptr, 0xa0000 - sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - mem_set_mem_state(0x100000, 0xf00000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - } -} + new_flags = dev->mem_flags[addr / EMS_PGSIZE]; -static uint8_t -scamp_ems_read(uint32_t addr, void *priv) -{ - const ems_struct_t *ems = (ems_struct_t *) priv; - const scamp_t *dev = ems->parent; - int segment = ems->segment; + if (new_flags & MEM_FLAG_ROMCS) { + read_ext = MEM_READ_ROMCS; + write_ext = MEM_WRITE_ROMCS; + } - addr = (addr & 0x3fff) | dev->mappings[segment]; - return ram[addr]; -} - -static void -scamp_ems_write(uint32_t addr, uint8_t val, void *priv) -{ - const ems_struct_t *ems = (ems_struct_t *) priv; - const scamp_t *dev = ems->parent; - int segment = ems->segment; - - addr = (addr & 0x3fff) | dev->mappings[segment]; - ram[addr] = val; -} - -static void -scamp_mem_update_state(scamp_t *dev, uint32_t addr, uint32_t size) -{ - uint8_t flags; - - if ((addr >= 0x000a0000) && (addr < 0x00100000)) { - flags = dev->ram_flags[(addr - 0x000a0000) >> 14]; - - if (flags & 4) + if (new_flags & (MEM_FLAG_REMAP | MEM_FLAG_SLOTBUS)) { + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (REMAP)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, read_ext | write_ext); + } else if (new_flags & (MEM_FLAG_EMS | MEM_FLAG_MEMCARD)) { + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (EMS)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - else switch (flags & 3) { + } else switch (new_flags & (MEM_FLAG_READ | MEM_FLAG_WRITE)) { case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (RE | WE)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, read_ext | write_ext); break; case 1: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (RE | WI)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, read_ext | MEM_WRITE_INTERNAL); break; case 2: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (RI | WE)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | write_ext); break; case 3: + scamp_log("scamp_mem_update_state(): %08X-%08X: %02X (RI | WI)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); break; default: break; } } + + flushmmucache_nopc(); +} + +static int +is_seg_in_ram(scamp_t *dev, uint8_t s) +{ + mem_page_t *mp = (mem_page_t *) dev->mem_mappings[s].priv; + const int ret = mp->in_ram; + + return ret; } static void recalc_ems(scamp_t *dev) { - const uint32_t ems_base[12] = { - 0xc0000, 0xc4000, 0xc8000, 0xcc000, - 0xd0000, 0xd4000, 0xd8000, 0xdc000, - 0xe0000, 0xe4000, 0xe8000, 0xec000 - }; - uint32_t new_mappings[20]; - uint16_t ems_enable; + const uint8_t seg_xlat[12] = { 40, 41, 42, 43, 52, 53, 54, 55, 44, 45, 46, 47 }; + const uint16_t seg_enable = dev->cfg_regs[CFG_EMSEN2] | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 8); - for (int segment = 0; segment < 20; segment++) - new_mappings[segment] = 0xa0000 + segment * 0x4000; + for (uint8_t s = 40; s < 60; s++) { + dev->mem_pages[s].phys_addr = dev->mem_pages[s].virt_addr; + dev->mem_pages[s].mem = ram + dev->mem_pages[s].phys_addr; - if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSENAB) - ems_enable = dev->cfg_regs[CFG_EMSEN2] | ((dev->cfg_regs[CFG_EMSEN1] & 0xf) << 8); - else - ems_enable = 0; + if (is_seg_in_ram(dev, s)) + mem_mapping_set_exec(&(dev->mem_mappings[s]), dev->mem_pages[s].mem); - for (int segment = 0; segment < 12; segment++) { - if (ems_enable & (1 << segment)) { - uint32_t phys_addr = dev->ems[segment] << 14; - - /*If physical address is in remapped memory then adjust down to a0000-fffff range*/ - if ((dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) && phys_addr >= (mem_size * 1024) - && phys_addr < ((mem_size + 384) * 1024)) - phys_addr = (phys_addr - mem_size * 1024) + 0xa0000; - new_mappings[(ems_base[segment] - 0xa0000) >> 14] = phys_addr; - } + scamp_mem_update_state(dev, s * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_EMS); } - for (int segment = 0; segment < 20; segment++) { - if (new_mappings[segment] != dev->mappings[segment]) { - dev->mappings[segment] = new_mappings[segment]; - if (new_mappings[segment] < (mem_size * 1024)) { - mem_mapping_set_exec(&dev->ems_mappings[segment], ram + dev->mappings[segment]); - mem_mapping_enable(&dev->ems_mappings[segment]); - dev->ram_flags[segment] |= 0x04; - } else { - mem_mapping_disable(&dev->ems_mappings[segment]); - dev->ram_flags[segment] &= 0xfb; - } + for (uint8_t i = 0; i < 36; i++) { + uint8_t s = (i < 12) ? (i + 48) : (i + 4); + uint8_t on = (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSENAB); + uint32_t phys_addr = dev->ems[i] << 14; - scamp_mem_update_state(dev, 0xa0000 + segment * 0x4000, 0x4000); + if (i < 12) { + if (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_EMSMAP) + s = seg_xlat[i]; + + on = on && (seg_enable & (1 << i)); + } else + on = on && (dev->cfg_regs[CFG_EMSEN1] & EMSEN1_BFENAB); + + if (on) { + dev->mem_pages[s].phys_addr = phys_addr; + dev->mem_pages[s].mem = ram + dev->mem_pages[s].phys_addr; + + if (is_seg_in_ram(dev, s)) + mem_mapping_set_exec(&(dev->mem_mappings[s]), dev->mem_pages[s].mem); + + scamp_mem_update_state(dev, s * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_EMS, MEM_FMASK_EMS); + } else if (i >= 12) { + dev->mem_pages[s].phys_addr = dev->mem_pages[s].virt_addr; + dev->mem_pages[s].mem = ram + dev->mem_pages[s].phys_addr; + + if (is_seg_in_ram(dev, s)) + mem_mapping_set_exec(&(dev->mem_mappings[s]), dev->mem_pages[s].mem); + + scamp_mem_update_state(dev, s * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_EMS); } } @@ -677,32 +759,11 @@ recalc_ems(scamp_t *dev) static void shadow_control(scamp_t *dev, uint32_t addr, uint32_t size, int state) { - dev->ram_flags[(addr - 0x000a0000) >> 14] &= 0xfc; - dev->ram_flags[(addr - 0x000a0000) >> 14] |= state; - if (size == 0x8000) { - dev->ram_flags[((addr - 0x000a0000) >> 14) + 1] &= 0xfc; - dev->ram_flags[((addr - 0x000a0000) >> 14) + 1] |= state; - } - - switch (state) { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - default: - break; - } - - scamp_mem_update_state(dev, addr, size); + scamp_mem_update_state(dev, addr, EMS_PGSIZE, state, MEM_FMASK_RW); + scamp_mem_update_state(dev, addr + EMS_PGSIZE, EMS_PGSIZE, state, MEM_FMASK_RW); + } else + scamp_mem_update_state(dev, addr, size, state, MEM_FMASK_RW); flushmmucache_nopc(); } @@ -710,14 +771,23 @@ shadow_control(scamp_t *dev, uint32_t addr, uint32_t size, int state) static void shadow_recalc(scamp_t *dev) { - uint8_t abaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_ABAXS]; - uint8_t caxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_CAXS]; - uint8_t daxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_DAXS]; - uint8_t feaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) ? 0 : dev->cfg_regs[CFG_FEAXS]; + uint8_t abaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) ? 0 : dev->cfg_regs[CFG_ABAXS]; + uint8_t caxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) ? 0 : dev->cfg_regs[CFG_CAXS]; + uint8_t daxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) ? 0 : dev->cfg_regs[CFG_DAXS]; + uint8_t feaxs = (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) ? 0 : dev->cfg_regs[CFG_FEAXS]; /*Enabling remapping will disable all shadowing*/ - if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) - mem_remap_top(384); + if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) + mem_remap_top_nomid(384); + else + mem_remap_top_nomid(0); + + for (uint8_t i = 40; i < 64; i++) { + if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP384) + scamp_mem_update_state(dev, (i * EMS_PGSIZE), EMS_PGSIZE, MEM_FLAG_REMAP, MEM_FMASK_REMAP); + else + scamp_mem_update_state(dev, (i * EMS_PGSIZE), EMS_PGSIZE, 0x00, MEM_FMASK_REMAP); + } shadow_control(dev, 0xa0000, 0x4000, abaxs & 3); shadow_control(dev, 0xa0000, 0x4000, abaxs & 3); @@ -748,6 +818,97 @@ shadow_recalc(scamp_t *dev) shadow_control(dev, 0xf8000, 0x8000, (feaxs >> 6) & 3); } +static void +recalc_sltptr(scamp_t *dev) +{ + uint32_t sltptr = dev->cfg_regs[CFG_SLTPTR] << 16; + + if (sltptr >= 0xa0000 && sltptr < 0x100000) + sltptr = 0x100000; + if (sltptr > 0xfe0000) + sltptr = 0xfe0000; + + if (sltptr >= 0xa0000) { + for (uint8_t i = 0; i < 40; i++) + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_SLOTBUS); + + mem_set_mem_state(0x100000, sltptr - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(sltptr, 0x1000000 - sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + if ((sltptr >= 0x40000) && (sltptr <= 0x90000)) { + dev->cfg_regs[CFG_EMSEN1] &= ~EMSEN1_BFENAB; + recalc_ems(dev); + } + } else { + for (uint8_t i = 0; i < (sltptr / EMS_PGSIZE); i++) + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_SLOTBUS); + + for (uint8_t i = (sltptr / EMS_PGSIZE); i < 40; i++) + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_SLOTBUS, MEM_FMASK_SLOTBUS); + + mem_set_mem_state(sltptr, 0xa0000 - sltptr, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state(0x100000, 0xf00000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + } + + flushmmucache_nopc(); +} + +static void +recalc_rommov(scamp_t *dev) +{ + switch ((dev->cfg_regs[CFG_RAMMAP] & RAMMAP_ROMMOV) >> 5) { + case 0x00: + scamp_mem_update_state(dev, 0x000c0000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c4000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c8000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000cc000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + + scamp_mem_update_state(dev, 0x000e0000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e4000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e8000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000ec000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + break; + + case 0x01: + scamp_mem_update_state(dev, 0x000c0000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c4000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c8000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000cc000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + + scamp_mem_update_state(dev, 0x000e0000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e4000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e8000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000ec000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + break; + + case 0x02: + scamp_mem_update_state(dev, 0x000c0000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c4000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c8000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000cc000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + + scamp_mem_update_state(dev, 0x000e0000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e4000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e8000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000ec000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + break; + + case 0x03: + scamp_mem_update_state(dev, 0x000c0000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c4000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000c8000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000cc000, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + + scamp_mem_update_state(dev, 0x000e0000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e4000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000e8000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + scamp_mem_update_state(dev, 0x000ec000, EMS_PGSIZE, 0x00, MEM_FMASK_ROMCS); + break; + } + + flushmmucache_nopc(); +} + static void scamp_write(uint16_t addr, uint8_t val, void *priv) { @@ -755,7 +916,7 @@ scamp_write(uint16_t addr, uint8_t val, void *priv) switch (addr) { case 0xe8: - dev->ems_index = val & 0x1f; + dev->ems_index = val & 0x3f; dev->ems_autoinc = val & 0x40; break; @@ -785,12 +946,14 @@ scamp_write(uint16_t addr, uint8_t val, void *priv) switch (dev->cfg_index) { case CFG_SLTPTR: recalc_sltptr(dev); + recalc_ems(dev); break; case CFG_RAMMAP: recalc_mappings(dev); mem_mapping_disable(&ram_remapped_mapping); shadow_recalc(dev); + recalc_rommov(dev); break; case CFG_EMSEN1: @@ -914,9 +1077,8 @@ scamp_init(UNUSED(const device_t *info)) mem_mapping_set_handler(&ram_low_mapping, ram_mirrored_read, NULL, NULL, ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_mid_mapping); mem_mapping_disable(&ram_high_mapping); - mem_mapping_set_addr(&ram_mid_mapping, 0xf0000, 0x10000); - mem_mapping_set_exec(&ram_mid_mapping, ram + 0xf0000); addr = 0; for (uint8_t c = 0; c < 2; c++) { @@ -988,15 +1150,45 @@ scamp_init(UNUSED(const device_t *info)) mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - for (uint8_t c = 0; c < 20; c++) { - dev->ems_struct[c].parent = dev; - dev->ems_struct[c].segment = c; - mem_mapping_add(&dev->ems_mappings[c], - 0xa0000 + c * 0x4000, 0x4000, - scamp_ems_read, NULL, NULL, - scamp_ems_write, NULL, NULL, - ram + 0xa0000 + c * 0x4000, MEM_MAPPING_INTERNAL, (void *) &dev->ems_struct[c]); - dev->mappings[c] = 0xa0000 + c * 0x4000; + for (uint8_t i = 0; i < 12; i++) + dev->ems[i] = (0x000c0000 + (i * EMS_PGSIZE)) >> 14; + + for (uint8_t i = 0; i < 24; i++) + dev->ems[i + 12] = (0x00040000 + (i * EMS_PGSIZE)) >> 14; + + for (uint8_t i = 0; i < 64; i++) { + dev->mem_pages[i].in_ram = 1; + dev->mem_pages[i].virt_addr = i * EMS_PGSIZE; + dev->mem_pages[i].phys_addr = dev->mem_pages[i].virt_addr; + dev->mem_pages[i].mem = ram + dev->mem_pages[i].phys_addr; + + mem_mapping_add(&(dev->mem_mappings[i]), + i * EMS_PGSIZE, EMS_PGSIZE, + scamp_mem_readb, scamp_mem_readw, NULL, + scamp_mem_writeb, scamp_mem_writew, NULL, + dev->mem_pages[i].mem, MEM_MAPPING_INTERNAL, + &(dev->mem_pages[i])); + + if (i < 40) { + mem_mapping_disable(&(dev->mem_mappings[i])); + + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_RW); + } else { + /* This is needed to the state update actually occurs. */ + dev->mem_flags[i] = MEM_FLAG_READ | MEM_FLAG_WRITE; + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_RW); + + if (i >= 60) + scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); + } + } + + dev->card_mem = NULL; + + for (uint8_t i = 0; i < 4; i++) { + dev->card_pages[i].virt_addr = i * EMS_PGSIZE; + dev->card_pages[i].phys_addr = dev->card_pages[i].virt_addr; + dev->card_pages[i].mem = dev->card_mem + dev->card_pages[i].phys_addr; } dev->port_92 = device_add(&port_92_device); From 458f7218979790471df07408ec47f0e703eaa3b6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 23:27:44 +0100 Subject: [PATCH 0126/1190] The forgotten mem.c/h changes. --- src/include/86box/mem.h | 2 ++ src/mem/mem.c | 48 ++++++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 87be14d5b..19a331925 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -460,7 +460,9 @@ extern void mem_init(void); extern void mem_close(void); extern void mem_reset(void); extern void mem_remap_top_ex(int kb, uint32_t start); +extern void mem_remap_top_ex_nomid(int kb, uint32_t start); extern void mem_remap_top(int kb); +extern void mem_remap_top_nomid(int kb); extern void umc_smram_recalc(uint32_t start, int set); diff --git a/src/mem/mem.c b/src/mem/mem.c index aafd6223c..d1c6de49d 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -3019,8 +3019,8 @@ umc_smram_recalc(uint32_t start, int set) umc_page_recalc(c, set); } -void -mem_remap_top_ex(int kb, uint32_t start) +static void +mem_remap_top_ex_common(int kb, uint32_t start, int mid) { uint32_t c; int offset; @@ -3123,37 +3123,61 @@ mem_remap_top_ex(int kb, uint32_t start) mem_mapping_set_addr(&ram_remapped_mapping2, (start * 1024) + 0x00020000, 0x00020000); mem_mapping_set_exec(&ram_remapped_mapping2, ram + 0x000d0000); - mem_mapping_set_addr(&ram_mid_mapping, 0x000c0000, 0x00010000); - mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000c0000); - mem_mapping_set_addr(&ram_mid_mapping2, 0x000f0000, 0x00010000); - mem_mapping_set_exec(&ram_mid_mapping2, ram + 0x000f0000); + if (mid) { + mem_mapping_set_addr(&ram_mid_mapping, 0x000c0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000c0000); + mem_mapping_set_addr(&ram_mid_mapping2, 0x000f0000, 0x00010000); + mem_mapping_set_exec(&ram_mid_mapping2, ram + 0x000f0000); + } } else { mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); mem_mapping_set_exec(&ram_remapped_mapping, ram + start_addr); mem_mapping_disable(&ram_remapped_mapping2); - mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); - mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); - mem_mapping_disable(&ram_mid_mapping2); + if (mid) { + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } } } else { mem_mapping_disable(&ram_remapped_mapping); mem_mapping_disable(&ram_remapped_mapping2); - mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); - mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); - mem_mapping_disable(&ram_mid_mapping2); + if (mid) { + mem_mapping_set_addr(&ram_mid_mapping, 0x000a0000, 0x00060000); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0x000a0000); + mem_mapping_disable(&ram_mid_mapping2); + } } flushmmucache(); } +void +mem_remap_top_ex(int kb, uint32_t start) +{ + mem_remap_top_ex_common(kb, start, 1); +} + +void +mem_remap_top_ex_nomid(int kb, uint32_t start) +{ + mem_remap_top_ex_common(kb, start, 0); +} + void mem_remap_top(int kb) { mem_remap_top_ex(kb, (mem_size >= 1024) ? mem_size : 1024); } +void +mem_remap_top_nomid(int kb) +{ + mem_remap_top_ex_nomid(kb, (mem_size >= 1024) ? mem_size : 1024); +} + void mem_reset_page_blocks(void) { From 1561b43fa9981945e4e638c9a811744608cdc8b2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 16 Jan 2025 23:28:19 +0100 Subject: [PATCH 0127/1190] NEAT: A few clean-ups. --- src/chipset/neat.c | 75 +++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 3c9838e06..73bd1b4c2 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -204,12 +204,14 @@ #define RB12_EMSLEN 0xe0 /* EMS memory chunk size */ #define RB12_EMSLEN_SH 5 -#define RAM_FLAG_EMS 0x08 -#define RAM_FLAG_ROMCS 0x04 -#define RAM_FLAG_SHREAD 0x02 -#define RAM_FLAG_SHWRITE 0x01 -#define RAM_FMASK_EMS 0x08 -#define RAM_FMASK_SHADOW 0x07 +#define MEM_FLAG_REMAP 0x10 +#define MEM_FLAG_EMS 0x08 +#define MEM_FLAG_ROMCS 0x04 +#define MEM_FLAG_READ 0x02 +#define MEM_FLAG_WRITE 0x01 +#define MEM_FMASK_REMAP 0x10 +#define MEM_FMASK_EMS 0x08 +#define MEM_FMASK_SHADOW 0x07 typedef struct ram_page_t { int8_t enabled; /* 1=ENABLED */ @@ -220,7 +222,7 @@ typedef struct ram_page_t { } ram_page_t; typedef struct neat_t { - uint8_t ram_flags[32]; + uint8_t mem_flags[32]; uint8_t regs[128]; /* all the CS8221 registers */ uint8_t indx; /* programmed index into registers */ @@ -339,19 +341,22 @@ static void neat_mem_update_state(neat_t *dev, uint32_t addr, uint32_t size, uint8_t new_flags, uint8_t mask) { if ((addr >= 0x00080000) && (addr < 0x00100000) && - ((new_flags ^ dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE]) & mask)) { - dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE] &= ~mask; - dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE] |= new_flags; + ((new_flags ^ dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]) & mask)) { + dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] &= ~mask; + dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] |= new_flags; - new_flags = dev->ram_flags[(addr - 0x00080000) / EMS_PGSIZE]; + new_flags = dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]; - if (new_flags & RAM_FLAG_EMS) { - neat_log("neat_mem_update_state(): %08X-%08X: %02X (EMS)\n", addr, addr + size - 1, new_flags); - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } else if (new_flags & RAM_FLAG_ROMCS) { + if (new_flags & MEM_FLAG_ROMCS) { neat_log("neat_mem_update_state(): %08X-%08X: %02X (ROMCS)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_ROMCS | MEM_WRITE_ROMCS); - } else switch (new_flags & (RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE)) { + } else if (new_flags & MEM_FLAG_REMAP) { + neat_log("neat_mem_update_state(): %08X-%08X: %02X (REMAP)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else if (new_flags & MEM_FLAG_EMS) { + neat_log("neat_mem_update_state(): %08X-%08X: %02X (EMS)\n", addr, addr + size - 1, new_flags); + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else switch (new_flags & (MEM_FLAG_READ | MEM_FLAG_WRITE)) { case 0: neat_log("neat_mem_update_state(): %08X-%08X: %02X (RE | WE)\n", addr, addr + size - 1, new_flags); mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); @@ -384,7 +389,7 @@ shadow_recalc(neat_t *dev) int write = 1; int shadow_reg = REG_RB3 + ((i - 8) >> 3); int shadow_bit = i & 7; - int ram_flags; + int mem_flags; int read; if (i >= 16) { @@ -409,16 +414,16 @@ shadow_recalc(neat_t *dev) read = dev->regs[shadow_reg] & (1 << shadow_bit); write = write && read; - ram_flags = romcs ? RAM_FLAG_ROMCS : 0x00; - ram_flags |= read ? RAM_FLAG_SHREAD : 0x00; - ram_flags |= write ? RAM_FLAG_SHWRITE : 0x00; + mem_flags = romcs ? MEM_FLAG_ROMCS : 0x00; + mem_flags |= read ? MEM_FLAG_READ : 0x00; + mem_flags |= write ? MEM_FLAG_WRITE : 0x00; - if ((ram_flags > 0x00) && !(ram_flags & RAM_FLAG_ROMCS)) + if ((mem_flags > 0x00) && !(mem_flags & MEM_FLAG_ROMCS)) mem_mapping_set_addr(&(dev->shadow[i].mapping), dev->shadow[i].virt_base, EMS_PGSIZE); else mem_mapping_disable(&(dev->shadow[i].mapping)); - neat_mem_update_state(dev, dev->shadow[i].virt_base, EMS_PGSIZE, ram_flags, RAM_FMASK_SHADOW); + neat_mem_update_state(dev, dev->shadow[i].virt_base, EMS_PGSIZE, mem_flags, MEM_FMASK_SHADOW); } } @@ -439,7 +444,7 @@ ems_recalc(neat_t *dev, ram_page_t *ems) /* Update the EMS RAM address for this page. */ mem_mapping_set_exec(&ems->mapping, ram + ems->phys_base); - neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, RAM_FLAG_EMS, RAM_FMASK_EMS); + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, MEM_FLAG_EMS, MEM_FMASK_EMS); #if NEAT_DEBUG > 1 neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n", @@ -449,7 +454,7 @@ ems_recalc(neat_t *dev, ram_page_t *ems) /* Disable this page. */ mem_mapping_disable(&ems->mapping); - neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS); + neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, MEM_FMASK_EMS); } } @@ -570,11 +575,20 @@ ems_set_handlers(neat_t *dev) ems_recalc_all(dev); } +static void +remap_update_states(neat_t *dev, uint8_t flag) +{ + for (uint8_t i = 0; i < 24; i++) + neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, flag, MEM_FMASK_REMAP); +} + static void remap_update(neat_t *dev, uint8_t val) { if (dev->regs[REG_RB7] & RB7_UMAREL) { - mem_remap_top_ex(0, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + mem_remap_top_ex_nomid(0, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + + remap_update_states(dev, 0x00); neat_log("0 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10); } @@ -595,12 +609,11 @@ remap_update(neat_t *dev, uint8_t val) mem_mapping_disable(&ram_high_mapping); if (val & RB7_UMAREL) { - mem_remap_top_ex(384, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + mem_remap_top_ex_nomid(384, (dev->remap_base >= 1024) ? dev->remap_base : 1024); + + remap_update_states(dev, MEM_FLAG_REMAP); neat_log("384 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10); } - - /* Yes, this has to be done on every step because mem_remap_top_ex() reenables it. */ - mem_mapping_disable(&ram_mid_mapping); } static void @@ -672,9 +685,9 @@ neat_write(uint16_t port, uint8_t val, void *priv) val &= RB2_MASK; *reg = (*reg & ~RB2_MASK) | val; if (val & RB2_TOP128) - neat_mem_update_state(dev, 0x00080000, 0x00020000, RAM_FLAG_SHREAD | RAM_FLAG_SHWRITE, RAM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); else - neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, RAM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, MEM_FMASK_SHADOW); #if NEAT_DEBUG > 1 neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); #endif From 9b7d5198d7f80e955756522079b642a8137c4aa1 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 18 Jan 2025 04:14:23 +0700 Subject: [PATCH 0128/1190] Removed onboard sound from three machines Per richardg867 --- src/machine/m_at_socket7_3v.c | 3 --- src/machine/m_at_socket8.c | 6 ------ src/machine/machine_table.c | 12 ++++++------ 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 4b980f2b0..262169010 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -695,9 +695,6 @@ machine_at_gw2kma_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); - if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available()) - machine_snd = device_add(machine_get_snd_device(machine)); - device_add(&i430vx_device); device_add(&piix3_device); device_add(&fdc37c932fr_device); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 59c412447..6d4776637 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -250,9 +250,6 @@ machine_at_vs440fx_init(const machine_t *model) pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - if (sound_card_current[0] == SOUND_INTERNAL) - device_add(machine_get_snd_device(machine)); - device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); @@ -288,9 +285,6 @@ machine_at_gw2kvenus_init(const machine_t *model) pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - if (sound_card_current[0] == SOUND_INTERNAL) - device_add(machine_get_snd_device(machine)); - device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index baba2723c..bd31a58b1 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11200,7 +11200,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 131072, @@ -11215,7 +11215,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = &sb_vibra16c_onboard_device, + .snd_device = NULL, .net_device = NULL }, @@ -13989,7 +13989,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14004,7 +14004,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = &cs4236b_device, + .snd_device = NULL, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ @@ -14113,7 +14113,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14128,7 +14128,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = &cs4236b_device, + .snd_device = NULL, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ From c20c211e29c1150bb88076221b72075be7509af2 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 18 Jan 2025 04:17:27 +0700 Subject: [PATCH 0129/1190] Line fixes --- src/machine/m_at_socket7_3v.c | 1 - src/machine/m_at_socket8.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 262169010..40ae221a0 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -694,7 +694,6 @@ machine_at_gw2kma_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); - device_add(&i430vx_device); device_add(&piix3_device); device_add(&fdc37c932fr_device); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 6d4776637..e6f78f6a2 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -249,7 +249,6 @@ machine_at_vs440fx_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); @@ -284,7 +283,6 @@ machine_at_gw2kvenus_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i440fx_device); device_add(&piix3_device); device_add(&keyboard_ps2_intel_ami_pci_device); From f89d960b7e499d1544b9301e30e7dec222e58ff4 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 18 Jan 2025 04:29:05 +0700 Subject: [PATCH 0130/1190] Added back onboard sound to Mailman Per richardg867 --- src/machine/m_at_socket7_3v.c | 4 ++++ src/machine/machine_table.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 40ae221a0..4b980f2b0 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -694,6 +694,10 @@ machine_at_gw2kma_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + + if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available()) + machine_snd = device_add(machine_get_snd_device(machine)); + device_add(&i430vx_device); device_add(&piix3_device); device_add(&fdc37c932fr_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bd31a58b1..7b0de9805 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11200,7 +11200,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 131072, @@ -11215,7 +11215,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &sb_vibra16c_onboard_device, .net_device = NULL }, From 5e12d46f3285dbe2494aba30e178220c0889ad6b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 18 Jan 2025 00:45:55 +0100 Subject: [PATCH 0131/1190] NEAT: More fixes, NEAT machines now POST again. --- src/chipset/neat.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 73bd1b4c2..000492d14 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -239,7 +239,7 @@ typedef struct neat_t { ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; -static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x00, +static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT }; @@ -924,6 +924,16 @@ neat_init(UNUSED(const device_t *info)) mem_mapping_disable(&ram_mid_mapping); + for (int i = 0; i < 24; i++) { + if (i >= 20) + neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_SHADOW); + else { + /* This is needed to actually trigger an update. */ + dev->mem_flags[i + 8] = MEM_FLAG_ROMCS; + neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, 0x00, MEM_FMASK_SHADOW); + } + } + /* * For each supported page (we can have a maximum of 4), * create, initialize and disable the mappings, and set @@ -1096,7 +1106,7 @@ neat_init(UNUSED(const device_t *info)) neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size); } if (dram_mode > 0) { - neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size); + neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", dram_mode, mem_size); } /* Set up an I/O handler for the chipset. */ From 351390b579a6d61b879f6a1a5a77ec1ed180b6d8 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 18 Jan 2025 10:59:35 -0300 Subject: [PATCH 0132/1190] CS423x: Change Control Indirect Address reserved bit readout for VS440FX BIOS --- src/sound/snd_cs423x.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index f28be9778..a75f695d9 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -147,12 +147,19 @@ cs423x_read(uint16_t addr, void *priv) ret |= 0x04; break; + case 3: /* Control Indirect Access Register */ + /* Intel VS440FX BIOS tells CS4236 from CS4232 through the upper bits. Setting them is enough. */ + ret |= 0xf0; + break; + case 4: /* Control Indirect Data Register */ ret = dev->indirect_regs[dev->regs[3]]; break; case 5: /* Control/RAM Access */ - /* Reading RAM is undocumented; the Windows drivers do so. */ + /* Reading RAM is undocumented, but performed by: + - Windows drivers (unknown purpose) + - Intel VS440FX BIOS (PnP ROM checksum recalculation) */ if (dev->ram_dl == 3) ret = dev->ram_data[dev->ram_addr++]; break; From fb3469c74e7e3660ddb98fcbead59ce1df375a87 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 18 Jan 2025 11:06:18 -0300 Subject: [PATCH 0133/1190] CS423x: Clean up RAM download state machine --- src/sound/snd_cs423x.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index a75f695d9..07f691f30 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -51,6 +51,12 @@ enum { CRYSTAL_CS4237B = 0xc8, CRYSTAL_CS4238B = 0xc9 }; +enum { + CRYSTAL_RAM_CMD = 0, + CRYSTAL_RAM_ADDR_LO = 1, + CRYSTAL_RAM_ADDR_HI = 2, + CRYSTAL_RAM_DATA = 3 +}; enum { CRYSTAL_SLAM_NONE = 0, CRYSTAL_SLAM_INDEX = 1, @@ -160,7 +166,7 @@ cs423x_read(uint16_t addr, void *priv) /* Reading RAM is undocumented, but performed by: - Windows drivers (unknown purpose) - Intel VS440FX BIOS (PnP ROM checksum recalculation) */ - if (dev->ram_dl == 3) + if (dev->ram_dl == CRYSTAL_RAM_DATA) ret = dev->ram_data[dev->ram_addr++]; break; @@ -255,7 +261,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 5: /* Control/RAM Access */ switch (dev->ram_dl) { - case 0: /* commands */ + case CRYSTAL_RAM_CMD: /* commands */ switch (val) { case 0x55: /* Disable PnP Key */ dev->pnp_enable = 0; @@ -273,7 +279,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) break; case 0xaa: /* Download RAM */ - dev->ram_dl = 1; + dev->ram_dl = CRYSTAL_RAM_ADDR_LO; break; default: @@ -281,17 +287,17 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) } break; - case 1: /* low address byte */ + case CRYSTAL_RAM_ADDR_LO: /* low address byte */ dev->ram_addr = val; - dev->ram_dl++; + dev->ram_dl = CRYSTAL_RAM_ADDR_HI; break; - case 2: /* high address byte */ - dev->ram_addr |= (val << 8); - dev->ram_dl++; + case CRYSTAL_RAM_ADDR_HI: /* high address byte */ + dev->ram_addr |= val << 8; + dev->ram_dl = CRYSTAL_RAM_DATA; break; - case 3: /* data */ + case CRYSTAL_RAM_DATA: /* data */ dev->ram_data[dev->ram_addr++] = val; break; @@ -303,7 +309,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 6: /* RAM Access End */ /* TriGem Delhi-III BIOS writes undocumented value 0x40 instead of 0x00. */ if ((val == 0x00) || (val == 0x40)) { - dev->ram_dl = 0; + dev->ram_dl = CRYSTAL_RAM_CMD; /* Update PnP state and resource data. */ cs423x_pnp_enable(dev, 1, 0); From 9dd6a1b29f764e063d953f0dda1343e64dec698a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 18 Jan 2025 11:48:14 -0300 Subject: [PATCH 0134/1190] CS423x: Add logging, which somehow never existed --- src/sound/snd_cs423x.c | 56 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 07f691f30..95a00cb56 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -15,12 +15,13 @@ * Copyright 2021-2022 RichardG. */ #include +#include #include #include #include #include #include - +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/dma.h> @@ -64,6 +65,24 @@ enum { CRYSTAL_SLAM_BYTE2 = 3 }; +#ifdef ENABLE_CS423X_LOG +int cs423x_do_log = ENABLE_CS423X_LOG; + +static void +cs423x_log(const char *fmt, ...) +{ + va_list ap; + + if (cs423x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define cs423x_log(fmt, ...) +#endif + static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC, 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, @@ -136,6 +155,8 @@ cs423x_nvram(cs423x_t *dev, uint8_t save) else (void) !fread(dev->eeprom_data, sizeof(dev->eeprom_data), 1, fp); fclose(fp); + } else { + cs423x_log("CS423x: EEPROM data %s failed\n", save ? "save" : "load"); } } @@ -166,8 +187,11 @@ cs423x_read(uint16_t addr, void *priv) /* Reading RAM is undocumented, but performed by: - Windows drivers (unknown purpose) - Intel VS440FX BIOS (PnP ROM checksum recalculation) */ - if (dev->ram_dl == CRYSTAL_RAM_DATA) - ret = dev->ram_data[dev->ram_addr++]; + if (dev->ram_dl == CRYSTAL_RAM_DATA) { + ret = dev->ram_data[dev->ram_addr]; + cs423x_log("CS423x: RAM read(%04X) = %02X\n", dev->ram_addr, ret); + dev->ram_addr++; + } break; case 7: /* Global Status */ @@ -188,6 +212,8 @@ cs423x_read(uint16_t addr, void *priv) break; } + cs423x_log("CS423x: read(%X) = %02X\n", reg, ret); + return ret; } @@ -195,7 +221,9 @@ static void cs423x_write(uint16_t addr, uint8_t val, void *priv) { cs423x_t *dev = (cs423x_t *) priv; - uint8_t reg = addr & 0x07; + uint8_t reg = addr & 7; + + cs423x_log("CS423x: write(%X, %02X)\n", reg, val); switch (reg) { case 1: /* EEPROM Interface */ @@ -295,9 +323,11 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case CRYSTAL_RAM_ADDR_HI: /* high address byte */ dev->ram_addr |= val << 8; dev->ram_dl = CRYSTAL_RAM_DATA; + cs423x_log("CS423x: RAM start(%04X)\n", dev->ram_addr); break; case CRYSTAL_RAM_DATA: /* data */ + cs423x_log("CS423x: RAM write(%04X, %02X)\n", dev->ram_addr, val); dev->ram_data[dev->ram_addr++] = val; break; @@ -309,6 +339,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 6: /* RAM Access End */ /* TriGem Delhi-III BIOS writes undocumented value 0x40 instead of 0x00. */ if ((val == 0x00) || (val == 0x40)) { + cs423x_log("CS423x: RAM end\n"); dev->ram_dl = CRYSTAL_RAM_CMD; /* Update PnP state and resource data. */ @@ -332,6 +363,8 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) cs423x_t *dev = (cs423x_t *) priv; uint8_t idx; + cs423x_log("CS423x: slam_write(%02X)\n", val); + switch (dev->slam_state) { case CRYSTAL_SLAM_NONE: /* Not in SLAM: read and compare Crystal key. */ @@ -346,6 +379,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) } /* Enter SLAM. */ + cs423x_log("CS423x: SLAM unlocked\n"); dev->slam_state = CRYSTAL_SLAM_INDEX; } } else { @@ -356,6 +390,8 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) case CRYSTAL_SLAM_INDEX: /* Intercept the Activate Audio Device command. */ if (val == 0x79) { + cs423x_log("CS423x: Exiting SLAM\n"); + /* Apply the last logical device's configuration. */ if (dev->slam_config) { cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); @@ -376,6 +412,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) case CRYSTAL_SLAM_BYTE1: case CRYSTAL_SLAM_BYTE2: /* Write register value: two bytes for I/O ports, single byte otherwise. */ + cs423x_log("CS423x: SLAM write(%02X, %02X)\n", dev->slam_reg, val); switch (dev->slam_reg) { case 0x06: /* Card Select Number */ isapnp_set_csn(dev->pnp_card, val); @@ -446,7 +483,7 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) break; } - /* Prepare for the next register, unless a two-byte read returns above. */ + /* Prepare for the next register, unless a two-byte write returns above. */ dev->slam_state = CRYSTAL_SLAM_INDEX; break; @@ -467,8 +504,11 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable) /* Enable SLAM if the CKD bit is not set. */ if (enable && !(dev->ram_data[0x4002] & 0x10)) { + cs423x_log("CS423x: Enabling SLAM\n"); dev->slam_enable = 1; io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev); + } else { + cs423x_log("CS423x: Disabling SLAM\n"); } } @@ -484,6 +524,7 @@ cs423x_ctxswitch_write(uint16_t addr, UNUSED(uint8_t val), void *priv) /* Flip context bit. */ dev->regs[7] ^= 0x80; ctx ^= 0x80; + cs423x_log("CS423x: Context switch to %s\n", ctx ? "WSS" : "SBPro"); /* Update CD audio filter. FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */ @@ -553,6 +594,8 @@ cs423x_get_music_buffer(int32_t *buffer, int len, void *priv) static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) { + cs423x_log("CS423x: Updating PnP ROM=%d hwconfig=%d\n", update_rom, update_hwconfig); + if (dev->pnp_card) { /* Update PnP resource data if requested. */ if (update_rom) @@ -747,6 +790,7 @@ cs423x_init(const device_t *info) /* Initialize model-specific data. */ dev->type = info->local & 0xff; + cs423x_log("CS423x: init(%02X)\n", dev->type); switch (dev->type) { case CRYSTAL_CS4235: case CRYSTAL_CS4236B: @@ -849,6 +893,8 @@ cs423x_close(void *priv) { cs423x_t *dev = (cs423x_t *) priv; + cs423x_log("CS423x: close()\n"); + /* Save EEPROM contents to file. */ if (dev->eeprom) { cs423x_nvram(dev, 1); From f6175add8ffdbd63a61ce31be203bcf14b7be272 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 18 Jan 2025 14:57:05 -0300 Subject: [PATCH 0135/1190] CS423x: Refactor EEPROM-less mode --- src/sound/snd_cs423x.c | 82 ++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 95a00cb56..d7d99b7b3 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -87,11 +87,9 @@ static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; -static const uint8_t cs4236b_eeprom[8224] = { +static const uint8_t cs4236b_default[] = { // clang-format off /* Chip configuration */ - 0x55, 0xbb, /* magic */ - 0x00, 0x00, /* length */ 0x00, 0x03, /* CD-ROM and modem decode */ 0x80, /* misc. config */ 0x80, /* global config */ @@ -102,8 +100,9 @@ static const uint8_t cs4236b_eeprom[8224] = { 0x75, 0xb9, 0xfc, /* IRQ routing */ 0x10, 0x03, /* DMA routing */ - /* PnP resources */ - 0x00 + /* Default PnP resources */ + /* TODO: broken, not picked up by VS440FX BIOS, pending hardware research of the actual defaults */ + 0x0e, 0x63, 0x42, 0x36, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x10, 0x00, 0x14, 0x41, 0xd0, 0xff, 0xff, 0x79, 0x00 // clang-format on }; @@ -122,6 +121,7 @@ typedef struct cs423x_t { uint16_t ram_addr; uint16_t eeprom_size : 11; uint16_t pnp_offset; + uint16_t pnp_size; uint8_t type; uint8_t ad1848_type; uint8_t regs[8]; @@ -363,7 +363,8 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) cs423x_t *dev = (cs423x_t *) priv; uint8_t idx; - cs423x_log("CS423x: slam_write(%02X)\n", val); + if ((dev->slam_state != CRYSTAL_SLAM_NONE) || (val == slam_init_key[dev->key_pos])) /* cut down on ISAPnP-related noise */ + cs423x_log("CS423x: slam_write(%02X)\n", val); switch (dev->slam_state) { case CRYSTAL_SLAM_NONE: @@ -599,7 +600,7 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) if (dev->pnp_card) { /* Update PnP resource data if requested. */ if (update_rom) - isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], 384); + isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], dev->pnp_size); /* Disable PnP key if the PKD bit is set, or if it was disabled by command 0x55. */ /* But wait! The TriGem Delhi-III BIOS sends command 0x55, and its behavior doesn't @@ -753,9 +754,21 @@ cs423x_reset(void *priv) /* Clear RAM. */ memset(dev->ram_data, 0, sizeof(dev->ram_data)); + /* Load default configuration data to RAM. */ + memcpy(&dev->ram_data[0x4000], cs4236b_default, sizeof(cs4236b_default)); + dev->pnp_size = 19; + if (dev->eeprom) { - /* Load EEPROM data to RAM. */ - memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], MIN(384, ((dev->eeprom_data[2] << 8) | dev->eeprom_data[3]) - 4)); + /* Load EEPROM data to RAM if the magic bytes are present. */ + if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) { + cs423x_log("CS423x: EEPROM data valid, loading to RAM\n"); + dev->pnp_size = (dev->eeprom_data[2] << 8) | dev->eeprom_data[3]; + if (dev->pnp_size > 384) + dev->pnp_size = 384; + memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], sizeof(dev->eeprom_data) - 4); + } else { + cs423x_log("CS423x: EEPROM data invalid, ignoring\n"); + } /* Save EEPROM contents to file. */ cs423x_nvram(dev, 1); @@ -800,30 +813,41 @@ cs423x_init(const device_t *info) dev->ad1848_type = (dev->type == CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236; dev->pnp_offset = 0x4013; - /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */ + /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init. */ dev->ad1848.xregs[25] = dev->type; if (!(info->local & CRYSTAL_NOEEPROM)) { - /* Load EEPROM contents from template. */ - memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom)); + /* Copy default configuration data. */ + memcpy(&dev->eeprom_data[4], cs4236b_default, sizeof(cs4236b_default)); + /* Load PnP resource data ROM. */ FILE *fp = rom_fopen(PNP_ROM_CS4236B, "rb"); if (fp) { - (void) !fread(&(dev->eeprom_data[23]), 1, 8201, fp); + uint16_t eeprom_pnp_offset = (dev->pnp_offset & 0x1ff) + 4; + /* This is wrong. The header field only indicates PnP resource data length, and real chips use + it to locate the firmware patch area, but we don't need any of that, so we can get away + with pretending the whole ROM is PnP data, at least until we can get full EEPROM dumps. */ + dev->pnp_size = fread(&dev->eeprom_data[eeprom_pnp_offset], 1, sizeof(dev->eeprom_data) - eeprom_pnp_offset, fp); fclose(fp); } - /* Set content size. */ - dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8; - dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff; + /* Populate EEPROM header if the PnP ROM was loaded. */ + if (dev->pnp_size) { + dev->eeprom_data[0] = 0x55; + dev->eeprom_data[1] = 0xbb; + dev->eeprom_data[2] = dev->pnp_size >> 8; + dev->eeprom_data[3] = dev->pnp_size; + } - /* Set PnP card ID and EEPROM file name. */ + /* Patch PnP ROM and set EEPROM file name. */ switch (dev->type) { case CRYSTAL_CS4235: - dev->eeprom_data[8] = 0x05; - dev->eeprom_data[16] = 0x08; - dev->eeprom_data[26] = 0x25; - dev->eeprom_data[44] = '5'; + if (dev->pnp_size) { + dev->eeprom_data[8] = 0x05; + dev->eeprom_data[16] = 0x08; + dev->eeprom_data[26] = 0x25; + dev->eeprom_data[44] = '5'; + } dev->nvr_path = "cs4235.nvr"; break; @@ -832,14 +856,18 @@ cs423x_init(const device_t *info) break; case CRYSTAL_CS4237B: - dev->eeprom_data[26] = 0x37; - dev->eeprom_data[44] = '7'; + if (dev->pnp_size) { + dev->eeprom_data[26] = 0x37; + dev->eeprom_data[44] = '7'; + } dev->nvr_path = "cs4237b.nvr"; break; case CRYSTAL_CS4238B: - dev->eeprom_data[26] = 0x38; - dev->eeprom_data[44] = '8'; + if (dev->pnp_size) { + dev->eeprom_data[26] = 0x38; + dev->eeprom_data[44] = '8'; + } dev->nvr_path = "cs4238b.nvr"; break; @@ -864,8 +892,8 @@ cs423x_init(const device_t *info) /* Initialize I2C bus for the EEPROM. */ dev->i2c = i2c_gpio_init("nvr_cs423x"); - /* Initialize I2C EEPROM if the contents are valid. */ - if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb)) + /* Initialize I2C EEPROM if enabled. */ + if (!(info->local & CRYSTAL_NOEEPROM)) dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1); /* Initialize ISAPnP. */ From 40fd79aeb9bfcf4a3fc597506995d9a250b59669 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 19 Jan 2025 09:06:39 +0100 Subject: [PATCH 0136/1190] FPU: Properly implement INT 10h FPU exception, fixes #5162. --- src/cpu/386.c | 11 ++++++++++- src/cpu/386_common.c | 1 + src/cpu/386_dynarec.c | 30 +++++++++++++++++++++++++++--- src/cpu/cpu.h | 2 ++ src/cpu/x86.c | 1 + src/cpu/x86_ops_fpu.h | 4 ++-- src/cpu/x86_ops_fpu_2386.h | 5 ++++- src/cpu/x87.c | 8 ++++---- src/cpu/x87.h | 4 ++-- src/cpu/x87_ops.h | 4 ++-- 10 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index 8b612604d..21db155e9 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -268,7 +268,8 @@ exec386_2386(int32_t cycs) } else { CHECK_READ_CS(MIN(ol, 4)); } - ins_fetch_fault = cpu_386_check_instruction_fault(); + if (is386) + ins_fetch_fault = cpu_386_check_instruction_fault(); /* Breakpoint fault has priority over other faults. */ if (ins_fetch_fault) { @@ -336,6 +337,14 @@ exec386_2386(int32_t cycs) #endif } } + } else if (new_ne) { + flags_rebuild(); + new_ne = 0; +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + cpu_state.oldpc = cpu_state.pc; + x86_int(16); } else if (trap) { flags_rebuild(); if (trap & 2) dr[6] |= 0x8000; diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index dcbe3608c..a68d866bf 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -72,6 +72,7 @@ extern uint8_t *pccache2; extern int optype; extern uint32_t pccache; +int new_ne = 0; int in_sys = 0; int unmask_a20_in_smm = 0; uint32_t old_rammask = 0xffffffff; diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5991cf100..c4c095735 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -357,6 +357,8 @@ exec386_dynarec_int(void) CPU_BLOCK_END(); if (smi_line) CPU_BLOCK_END(); + else if (new_ne) + CPU_BLOCK_END(); else if (trap) CPU_BLOCK_END(); else if (nmi && nmi_enable && nmi_mask) @@ -366,7 +368,7 @@ exec386_dynarec_int(void) } block_ended: - if (!cpu_state.abrt && trap) { + if (!cpu_state.abrt && !new_ne && trap) { # ifdef USE_DEBUG_REGS_486 //pclog("Debug trap 0x%X\n", trap); if (trap & 2) dr[6] |= 0x8000; @@ -602,6 +604,8 @@ exec386_dynarec_dyn(void) if (cpu_init) CPU_BLOCK_END(); + if (new_ne) + CPU_BLOCK_END(); if ((cpu_state.flags & T_FLAG) || (trap == 2)) CPU_BLOCK_END(); if (smi_line) @@ -626,7 +630,7 @@ exec386_dynarec_dyn(void) cpu_end_block_after_ins = 0; - if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !new_ne && !x86_was_reset) codegen_block_end_recompile(block); if (x86_was_reset) @@ -702,6 +706,8 @@ exec386_dynarec_dyn(void) if (cpu_init) CPU_BLOCK_END(); + if (new_ne) + CPU_BLOCK_END(); if (cpu_state.flags & T_FLAG) CPU_BLOCK_END(); if (smi_line) @@ -726,7 +732,7 @@ exec386_dynarec_dyn(void) cpu_end_block_after_ins = 0; - if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !new_ne && !x86_was_reset) codegen_block_end(); if (x86_was_reset) @@ -809,6 +815,15 @@ exec386_dynarec(int32_t cycs) } } + if (new_ne) { +# ifndef USE_NEW_DYNAREC + oldcs = CS; +# endif + cpu_state.oldpc = cpu_state.pc; + new_ne = 0; + x86_int(16); + } + if (smi_line) enter_smm_check(0); else if (nmi && nmi_enable && nmi_mask) { @@ -977,6 +992,15 @@ block_ended: #endif } } + } else if (new_ne) { + flags_rebuild(); + + new_ne = 0; +#ifndef USE_NEW_DYNAREC + oldcs = CS; +#endif + cpu_state.oldpc = cpu_state.pc; + x86_int(16); } else if (trap) { flags_rebuild(); #ifdef USE_DEBUG_REGS_486 diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f969390d2..bd841ccc6 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -814,6 +814,8 @@ extern int lock_legal_80[8]; extern int lock_legal_f6[8]; extern int lock_legal_fe[8]; +extern int new_ne; + extern int in_lock; extern int cpu_override_interpreter; diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 8a0bd830f..6f15560f3 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -271,6 +271,7 @@ reset_common(int hard) stack32 = 0; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); msw = 0; + new_ne = 0; if (hascache) cr0 = 1 << 30; else diff --git a/src/cpu/x86_ops_fpu.h b/src/cpu/x86_ops_fpu.h index 11f603c19..74c67c2ee 100644 --- a/src/cpu/x86_ops_fpu.h +++ b/src/cpu/x86_ops_fpu.h @@ -99,8 +99,8 @@ opWAIT(uint32_t fetchdat) if (fpu_softfloat) { if (fpu_state.swd & FPU_SW_Summary) { - if (is486 && (cr0 & 0x20)) - x86_int(16); + if (cr0 & 0x20) + new_ne = 1; else picint(1 << 13); return 1; diff --git a/src/cpu/x86_ops_fpu_2386.h b/src/cpu/x86_ops_fpu_2386.h index d8996d2e1..cc9c6dcc2 100644 --- a/src/cpu/x86_ops_fpu_2386.h +++ b/src/cpu/x86_ops_fpu_2386.h @@ -99,7 +99,10 @@ opWAIT(uint32_t fetchdat) if (fpu_softfloat) { if (fpu_state.swd & FPU_SW_Summary) { - picint(1 << 13); + if (cr0 & 0x20) + new_ne = 1; + else + picint(1 << 13); return 1; } } diff --git a/src/cpu/x87.c b/src/cpu/x87.c index 577fa1a40..3b06cab3c 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -355,10 +355,10 @@ FPU_exception(uint32_t fetchdat, uint16_t exceptions, int store) nmi = 1; } #else - if (is486 && (cr0 & 0x20)) - x86_int(16); - else - picint(1 << 13); + if (cr0 & 0x20) + new_ne = 1; + else + picint(1 << 13); #endif // FPU_8087 } return unmasked; diff --git a/src/cpu/x87.h b/src/cpu/x87.h index 2ad0c7b10..4d53725c9 100644 --- a/src/cpu/x87.h +++ b/src/cpu/x87.h @@ -228,8 +228,8 @@ FPU_save_regi_tag(extFloat80_t reg, int tag, int stnr) #define FPU_check_pending_exceptions() \ do { \ if (fpu_state.swd & FPU_SW_Summary) { \ - if (is486 && (cr0 & 0x20)) \ - x86_int(16); \ + if (cr0 & 0x20) \ + new_ne = 1; \ else \ picint(1 << 13); \ return 1; \ diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index e1bc5858a..d33122b5c 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -99,8 +99,8 @@ typedef union { dst = src1 / (double) src2; \ else { \ fpu_log("FPU : divide by zero\n"); \ - if (is486 && (cr0 & 0x20)) \ - x86_int(16); \ + if (cr0 & 0x20) \ + new_ne = 1; \ else \ picint(1 << 13); \ return 1; \ From 59e96d2aa01c6bc0a846108858ecc3ba93a99549 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 19 Jan 2025 17:35:38 -0300 Subject: [PATCH 0137/1190] ISAPnP: Create logical devices that don't exist instead of erroring out --- src/device/isapnp.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 470147953..f69c69612 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -121,6 +121,25 @@ typedef struct { isapnp_device_t *current_ld; } isapnp_t; +static isapnp_device_t * +isapnp_create_ld(isapnp_card_t *card) +{ + /* Allocate logical device. */ + isapnp_device_t *ld = calloc(1, sizeof(isapnp_device_t)); + + /* Add to the end of the card's logical device list. */ + isapnp_device_t *prev_ld = card->first_ld; + if (prev_ld) { + while (prev_ld->next) + prev_ld = prev_ld->next; + prev_ld->next = ld; + } else { + card->first_ld = ld; + } + + return ld; +} + static void isapnp_device_config_changed(isapnp_card_t *card, isapnp_device_t *ld) { @@ -532,8 +551,12 @@ isapnp_write_common(isapnp_t *dev, isapnp_card_t *card, isapnp_device_t *ld, uin ld = ld->next; } - if (!ld) - isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val); + if (!ld) { + isapnp_log("ISAPnP: CSN %02X has no device %02X, creating one\n", card->csn, val); + dev->current_ld_card = card; + dev->current_ld = isapnp_create_ld(card); + dev->current_ld->number = val; + } break; @@ -763,8 +786,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) uint8_t mem_range_df = 0; uint8_t mem_range_32_df = 0; uint32_t len; - isapnp_device_t *ld = NULL; - isapnp_device_t *prev_ld = NULL; + isapnp_device_t *ld = NULL; /* Check if this is an existing card which already has logical devices. Any new logical devices will be added to the list after existing ones. @@ -912,18 +934,7 @@ isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size) memset(ld->io_len, 0, sizeof(ld->io_len)); } else { /* Create logical device. */ - ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t)); - memset(ld, 0, sizeof(isapnp_device_t)); - - /* Add to end of list. */ - prev_ld = card->first_ld; - if (prev_ld) { - while (prev_ld->next) - prev_ld = prev_ld->next; - prev_ld->next = ld; - } else { - card->first_ld = ld; - } + ld = isapnp_create_ld(card); } /* Set and increment logical device number. */ From 8395f5078fc9effa42407e7b604c80049fa52d19 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 19 Jan 2025 17:45:35 -0300 Subject: [PATCH 0138/1190] CS423x: Fixes to PnP in EEPROM-less mode --- src/sound/snd_cs423x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index d7d99b7b3..b8d54ca3f 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -100,9 +100,8 @@ static const uint8_t cs4236b_default[] = { 0x75, 0xb9, 0xfc, /* IRQ routing */ 0x10, 0x03, /* DMA routing */ - /* Default PnP resources */ - /* TODO: broken, not picked up by VS440FX BIOS, pending hardware research of the actual defaults */ - 0x0e, 0x63, 0x42, 0x36, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x10, 0x00, 0x14, 0x41, 0xd0, 0xff, 0xff, 0x79, 0x00 + /* Default PnP data */ + 0x0e, 0x63, 0x42, 0x35, 0xff, 0xff, 0xff, 0xff, 0x00 /* hinted by documentation to be just the header */ // clang-format on }; @@ -343,6 +342,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) dev->ram_dl = CRYSTAL_RAM_CMD; /* Update PnP state and resource data. */ + dev->pnp_size = 384; /* we don't know the length */ cs423x_pnp_enable(dev, 1, 0); } break; @@ -756,7 +756,7 @@ cs423x_reset(void *priv) /* Load default configuration data to RAM. */ memcpy(&dev->ram_data[0x4000], cs4236b_default, sizeof(cs4236b_default)); - dev->pnp_size = 19; + dev->pnp_size = 9; if (dev->eeprom) { /* Load EEPROM data to RAM if the magic bytes are present. */ From ea28c723f1ccb093572264b312b02f528d405be3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 19 Jan 2025 17:49:32 -0300 Subject: [PATCH 0139/1190] CS423x: Fix CS4236B game port I/O inaccuracy --- src/sound/snd_cs423x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b8d54ca3f..2736acd82 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -879,9 +879,9 @@ cs423x_init(const device_t *info) cs423x_nvram(dev, 0); } - /* Initialize game port. The '7B and '8B game port only responds to 6 I/O ports; the remaining - 2 ports are reserved on those chips, and probably connected to the Digital Assist feature. */ - dev->gameport = gameport_add(((dev->type == CRYSTAL_CS4235) || (dev->type == CRYSTAL_CS4236B)) ? &gameport_pnp_device : &gameport_pnp_6io_device); + /* Initialize game port. The game port on all B chips only + responds to 6 I/O ports; the remaining 2 are reserved. */ + dev->gameport = gameport_add((dev->type == CRYSTAL_CS4235) ? &gameport_pnp_device : &gameport_pnp_6io_device); break; From 865297420569bfc6d5bf73aac8f8a10b879cc68b Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 19 Jan 2025 19:28:25 -0300 Subject: [PATCH 0140/1190] CS423x: Plumbing for more chips and clean-ups --- src/sound/snd_cs423x.c | 116 +++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 2736acd82..0d9af74f2 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -47,10 +47,13 @@ #define CRYSTAL_NOEEPROM 0x100 enum { - CRYSTAL_CS4235 = 0xdd, - CRYSTAL_CS4236B = 0xcb, + CRYSTAL_CS4232 = 0x32, /* no chip ID; dummy value */ + CRYSTAL_CS4236 = 0x36, /* no chip ID; dummy value */ + CRYSTAL_CS4236B = 0xab, /* report an older revision ID to make the values nice and incremental */ CRYSTAL_CS4237B = 0xc8, - CRYSTAL_CS4238B = 0xc9 + CRYSTAL_CS4238B = 0xc9, + CRYSTAL_CS4235 = 0xdd, + CRYSTAL_CS4239 = 0xde }; enum { CRYSTAL_RAM_CMD = 0, @@ -143,6 +146,7 @@ typedef struct cs423x_t { static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); +static void cs423x_reset(void *priv); static void cs423x_nvram(cs423x_t *dev, uint8_t save) @@ -173,13 +177,15 @@ cs423x_read(uint16_t addr, void *priv) ret |= 0x04; break; - case 3: /* Control Indirect Access Register */ + case 3: /* Control Indirect Access Register (CS4236B+) */ /* Intel VS440FX BIOS tells CS4236 from CS4232 through the upper bits. Setting them is enough. */ - ret |= 0xf0; + if (dev->type >= CRYSTAL_CS4236) + ret |= 0xf0; break; - case 4: /* Control Indirect Data Register */ - ret = dev->indirect_regs[dev->regs[3]]; + case 4: /* Control Indirect Data Register (CS4236B+) / Control Data Register (CS4236) */ + if (dev->type >= CRYSTAL_CS4236B) + ret = dev->indirect_regs[dev->regs[3]]; break; case 5: /* Control/RAM Access */ @@ -193,7 +199,10 @@ cs423x_read(uint16_t addr, void *priv) } break; - case 7: /* Global Status */ + case 7: /* Global Status (CS4236+) */ + if (dev->type < CRYSTAL_CS4236) + break; + /* Context switching: take active context and interrupt flag, then clear interrupt flag. */ ret &= 0xc0; dev->regs[7] &= 0x80; @@ -225,50 +234,75 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) cs423x_log("CS423x: write(%X, %02X)\n", reg, val); switch (reg) { + case 0: /* Joystick and Power Control */ + if (dev->type <= CRYSTAL_CS4232) + val &= 0xeb; + break; + case 1: /* EEPROM Interface */ + if (dev->type <= CRYSTAL_CS4232) + val &= 0x37; if (val & 0x04) i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02); break; - case 3: /* Control Indirect Access Register */ + case 2: /* Block Power Down (CS4236+) */ + if (dev->type < CRYSTAL_CS4236) + return; + break; + + case 3: /* Control Indirect Access Register (CS4236B+) */ + if (dev->type < CRYSTAL_CS4236B) + return; val &= 0x0f; break; - case 4: /* Control Indirect Data Register */ + case 4: /* Control Indirect Data Register (CS4236B+) / Control Data Register (CS4236) */ + if (dev->type < CRYSTAL_CS4236) { + return; + } else if (dev->type == CRYSTAL_CS4236) { + val &= 0x40; + break; + } switch (dev->regs[3] & 0x0f) { case 0: /* WSS Master Control */ - if (val & 0x80) + if ((dev->type < CRYSTAL_CS4235) && (val & 0x80)) ad1848_init(&dev->ad1848, dev->ad1848_type); val = 0x00; break; - case 1: /* Version / Chip ID */ - case 7: /* Reserved */ - case 9 ... 15: /* unspecified */ + case 1: /* Version / Chip ID */ + case 7: /* Reserved */ + case 10 ... 15: /* unspecified */ return; - case 2: /* 3D Space and {Center|Volume} */ - case 6: /* Upper Channel Status */ + case 2: /* 3D Space and {Center|Volume} (CS4237B+) */ if (dev->type < CRYSTAL_CS4237B) return; break; - case 3: /* 3D Enable */ + case 3: /* 3D Enable (CS4237B+) */ if (dev->type < CRYSTAL_CS4237B) return; val &= 0xe0; break; - case 4: /* Consumer Serial Port Enable */ + case 4: /* Consumer Serial Port Enable (CS423[78]B, unused on CS4235+) */ if (dev->type < CRYSTAL_CS4237B) return; val &= 0xf0; break; - case 5: /* Lower Channel Status */ + case 5: /* Lower Channel Status (CS423[78]B, unused on CS4235+) */ + if (dev->type < CRYSTAL_CS4237B) + return; + if (dev->type < CRYSTAL_CS4235) /* bit 0 changed from reserved to unused on CS4235 */ + val &= 0xfe; + break; + + case 6: /* Upper Channel Status (CS423[78]B, unused on CS4235+) */ if (dev->type < CRYSTAL_CS4237B) return; - val &= 0xfe; break; case 8: /* CS9236 Wavetable Control */ @@ -280,6 +314,16 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) ad1848_updatevolmask(&dev->ad1848); break; + case 9: /* Power Management (CS4235+) */ + if (dev->type < CRYSTAL_CS4235) + return; + if ((dev->indirect_regs[dev->regs[3]] & 0x80) && !(val & 0x80)) { + cs423x_reset(dev); + return; + } + val &= 0x83; + break; + default: break; } @@ -347,7 +391,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) } break; - case 7: /* Global Status */ + case 7: /* Global Status (CS4236+) */ return; default: @@ -557,7 +601,7 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) ad1848_update(&dev->ad1848); /* Don't output anything if the analog section is powered down. */ - if (!(dev->indirect_regs[2] & 0xa4)) { + if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x04)) { for (int c = 0; c < len * 2; c += 2) { buffer[c] += dev->ad1848.buffer[c] / 2; buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; @@ -570,26 +614,22 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) static void cs423x_get_music_buffer(int32_t *buffer, int len, void *priv) { - cs423x_t *dev = (cs423x_t *) priv; - int opl_wss = dev->opl_wss; - const int32_t *opl_buf = NULL; + cs423x_t *dev = (cs423x_t *) priv; /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ - if (opl_wss) - opl_buf = dev->sb->opl.update(dev->sb->opl.priv); + if (dev->opl_wss) { + const int32_t *opl_buf = dev->sb->opl.update(dev->sb->opl.priv); - /* Don't output anything if the analog section is powered down. */ - if (!(dev->indirect_regs[2] & 0xa4)) { - for (int c = 0; c < len * 2; c += 2) { - if (opl_wss) { + /* Don't output anything if the analog section or DAC2 (CS4235+) is powered down. */ + if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x06)) { + for (int c = 0; c < len * 2; c += 2) { buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16; buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16; } } - } - if (opl_wss) dev->sb->opl.reset_buffer(dev->sb->opl.priv); + } } static void @@ -625,7 +665,7 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) } /* Update SPS. */ - if (dev->type != CRYSTAL_CS4235) { + if ((dev->type >= CRYSTAL_CS4236B) && (dev->type <= CRYSTAL_CS4238B)) { if (dev->ram_data[0x4003] & 0x04) dev->indirect_regs[8] |= 0x04; else @@ -638,6 +678,14 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) else dev->ad1848.xregs[4] &= ~0x10; + /* Update VCEN. */ + if (dev->type == CRYSTAL_CS4236) { + if (dev->ram_data[0x4002] & 0x04) + dev->regs[4] |= 0x40; + else + dev->regs[4] &= ~0x40; + } + /* Inform WSS codec of the changes. */ ad1848_updatevolmask(&dev->ad1848); } From 84853cb21fbc0b1c5448ec34f2a58c04107ab57b Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 19 Jan 2025 20:23:11 -0300 Subject: [PATCH 0141/1190] AD1848: Plumbing for more CS423x chips --- src/include/86box/snd_ad1848.h | 8 ++-- src/sound/snd_ad1848.c | 87 +++++++++++++++++----------------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 319f9bf24..a7e38a6f8 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -16,7 +16,7 @@ * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. - * Copyright 2021 RichardG. + * Copyright 2021-2025 RichardG. */ #ifndef SOUND_AD1848_H @@ -26,8 +26,10 @@ enum { AD1848_TYPE_DEFAULT = 0, AD1848_TYPE_CS4248 = 1, AD1848_TYPE_CS4231 = 2, - AD1848_TYPE_CS4235 = 3, - AD1848_TYPE_CS4236 = 4 + AD1848_TYPE_CS4232 = 3, + AD1848_TYPE_CS4236 = 4, + AD1848_TYPE_CS4236B = 5, + AD1848_TYPE_CS4235 = 6 }; typedef struct ad1848_t { diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 4b7941959..a0166c4e5 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -16,7 +16,7 @@ * * Copyright 2008-2020 Sarah Walker. * Copyright 2018-2020 TheCollector1995. - * Copyright 2021-2022 RichardG. + * Copyright 2021-2025 RichardG. */ #include #include @@ -33,6 +33,7 @@ #include <86box/plat_fallthrough.h> #define CS4231 0x80 +#define CS4232 0x02 #define CS4236 0x03 static int ad1848_vols_7bits[128]; @@ -57,10 +58,10 @@ ad1848_setdma(ad1848_t *ad1848, int newdma) void ad1848_updatevolmask(ad1848_t *ad1848) { - if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->xregs[4] & 0x10) || ad1848->wten)) - ad1848->wave_vol_mask = 0x3f; - else + if ((ad1848->type == AD1848_TYPE_CS4236B) && !(ad1848->xregs[4] & 0x10) && !ad1848->wten) ad1848->wave_vol_mask = 0x7f; + else + ad1848->wave_vol_mask = 0x3f; } static double @@ -106,8 +107,8 @@ ad1848_updatefreq(ad1848_t *ad1848) { double freq; - if (ad1848->type >= AD1848_TYPE_CS4235) { - if (ad1848->xregs[11] & 0x20) { + if (ad1848->type >= AD1848_TYPE_CS4232) { + if (ad1848->xregs[11] & 0x20) { /* CS4236B+ only */ freq = 16934400.0; switch (ad1848->xregs[13]) { default: @@ -182,7 +183,7 @@ ad1848_read(uint16_t addr, void *priv) case 18: case 19: - if (ad1848->type >= AD1848_TYPE_CS4235) { + if (ad1848->type >= AD1848_TYPE_CS4236B) { if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */ ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */ @@ -192,13 +193,13 @@ ad1848_read(uint16_t addr, void *priv) case 20: case 21: - /* Backdoor to the Control/RAM registers on CS4235. */ - if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) + /* Backdoor to the Control/RAM registers on CS4235+. */ + if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) ret = ad1848->cram_read(ad1848->index - 15, ad1848->cram_priv); break; case 23: - if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->regs[23] & 0x08)) { + if ((ad1848->type >= AD1848_TYPE_CS4236B) && (ad1848->regs[23] & 0x08)) { if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */ ret = ad1848->regs[18 + ad1848->xindex]; else @@ -235,7 +236,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */ else ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */ - if (ad1848->type >= AD1848_TYPE_CS4235) + if (ad1848->type >= AD1848_TYPE_CS4236B) ad1848->regs[23] &= ~0x08; /* clear XRAE */ ad1848->trd = val & 0x20; ad1848->mce = val & 0x40; @@ -244,7 +245,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 1: switch (ad1848->index) { case 10: - if (ad1848->type < AD1848_TYPE_CS4235) + if (ad1848->type < AD1848_TYPE_CS4232) break; fallthrough; @@ -282,13 +283,13 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 17: /* Enable additional data formats on modes 2 and 3 where supported. */ - if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236)) + if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236B)) ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; break; case 18: case 19: - if (ad1848->type >= AD1848_TYPE_CS4235) { + if (ad1848->type >= AD1848_TYPE_CS4236B) { if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */ temp = 1; @@ -332,8 +333,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 20: case 21: - /* Backdoor to the Control/RAM registers on CS4235. */ - if ((ad1848->type == AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) { + /* Backdoor to the Control/RAM registers on CS4235+. */ + if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) { ad1848->cram_write(ad1848->index - 15, val, ad1848->cram_priv); val = ad1848->regs[ad1848->index]; } @@ -344,7 +345,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 23: - if ((ad1848->type >= AD1848_TYPE_CS4235) && ((ad1848->regs[12] & 0x60) == 0x60)) { + if ((ad1848->type >= AD1848_TYPE_CS4236B) && ((ad1848->regs[12] & 0x60) == 0x60)) { if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */ ad1848->xindex = ((val & 0x04) << 2) | (val >> 4); break; @@ -401,7 +402,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 25: return; case 27: - if (ad1848->type != AD1848_TYPE_DEFAULT) + if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236)) + return; + break; + case 29: + if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236)) return; break; @@ -456,17 +461,13 @@ ad1848_process_mulaw(uint8_t byte) { byte = ~byte; int temp = (((byte & 0x0f) << 3) + 0x84); - int16_t dec; temp <<= ((byte & 0x70) >> 4); temp = (byte & 0x80) ? (0x84 - temp) : (temp - 0x84); if (temp > 32767) - dec = 32767; + return 32767; else if (temp < -32768) - dec = -32768; - else - dec = (int16_t) temp; - - return dec; + return -32768; + return (int16_t) temp; } static int16_t @@ -489,8 +490,7 @@ ad1848_process_alaw(uint8_t byte) dec |= 0x108; break; } - dec = (byte & 0x80) ? dec : -dec; - return (int16_t) dec; + return (int16_t) ((byte & 0x80) ? dec : -dec); } static uint32_t @@ -704,10 +704,7 @@ ad1848_init(ad1848_t *ad1848, uint8_t type) ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type >= AD1848_TYPE_CS4235)) - ad1848->regs[12] = 0x8a; - else - ad1848->regs[12] = 0xa; + ad1848->regs[12] = (type >= AD1848_TYPE_CS4248) ? 0x8a : 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; @@ -719,27 +716,29 @@ ad1848_init(ad1848_t *ad1848, uint8_t type) ad1848->regs[25] = CS4231; ad1848->regs[26] = 0x80; ad1848->regs[29] = 0x80; - } else if (type >= AD1848_TYPE_CS4235) { + } else if (type >= AD1848_TYPE_CS4232) { ad1848->regs[16] = ad1848->regs[17] = 0; ad1848->regs[18] = ad1848->regs[19] = 0; ad1848->regs[20] = ad1848->regs[21] = 0; ad1848->regs[22] = ad1848->regs[23] = 0; ad1848->regs[24] = 0; - ad1848->regs[25] = CS4236; + ad1848->regs[25] = (type == AD1848_TYPE_CS4232) ? CS4232 : CS4236; ad1848->regs[26] = 0xa0; ad1848->regs[27] = ad1848->regs[29] = 0; ad1848->regs[30] = ad1848->regs[31] = 0; - ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; - ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; - ad1848->xregs[4] = 0x84; - ad1848->xregs[5] = 0; - ad1848->xregs[6] = ad1848->xregs[7] = 0x80; - ad1848->xregs[8] = ad1848->xregs[9] = 0; - ad1848->xregs[10] = 0x3f; - ad1848->xregs[11] = 0xc0; - ad1848->xregs[14] = ad1848->xregs[15] = 0; - ad1848->xregs[16] = ad1848->xregs[17] = 0; + if (type >= AD1848_TYPE_CS4236B) { + ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; + ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; + ad1848->xregs[4] = 0x84; + ad1848->xregs[5] = 0; + ad1848->xregs[6] = ad1848->xregs[7] = 0x80; + ad1848->xregs[8] = ad1848->xregs[9] = 0; + ad1848->xregs[10] = 0x3f; + ad1848->xregs[11] = 0xc0; + ad1848->xregs[14] = ad1848->xregs[15] = 0; + ad1848->xregs[16] = ad1848->xregs[17] = 0; + } } ad1848_updatefreq(ad1848); @@ -747,7 +746,7 @@ ad1848_init(ad1848_t *ad1848, uint8_t type) ad1848->out_l = ad1848->out_r = 0; ad1848->fm_vol_l = ad1848->fm_vol_r = 65536; ad1848_updatevolmask(ad1848); - if (type == AD1848_TYPE_CS4235) + if (type >= AD1848_TYPE_CS4235) ad1848->fmt_mask = 0x50; else ad1848->fmt_mask = 0x70; From f48c50f4ba7ac469fa79ed6119ac19f7376b79fd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 20 Jan 2025 03:26:49 +0100 Subject: [PATCH 0142/1190] The delayed video changes of the night (January 20th, 2025) Generic SVGA layer: Added function pointers of the banked mapping for use with add-on cards with their own mapping when the VGA card banked mapping is not active or viceversa (e.g.: XGA). XGA-1/2: 1. Reimplemented Area Fill and Boundary Mode as best as possible. 2. Fixed conflicts with banked mapping with VGA clones. 3. Fixed inverted colors (again) on accelerated 16bpp mode under OS/2. Video7 with ATI 8514/A add-on. Added a workaround (BIOS issue? I don't know) that disables 8514/A mode and reenables VGA mode when needed. Fixes screen freezes and polling issues with various drivers for Windows and others. --- src/include/86box/vid_svga.h | 8 + src/video/vid_cl54xx.c | 8 + src/video/vid_ht216.c | 27 +++- src/video/vid_paradise.c | 22 +-- src/video/vid_svga.c | 21 ++- src/video/vid_xga.c | 276 ++++++++++++++++++++--------------- 6 files changed, 219 insertions(+), 143 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index d38b7614b..2b26df2f3 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -202,6 +202,14 @@ typedef struct svga_t { void (*vblank_start)(struct svga_t *svga); + void (*write)(uint32_t addr, uint8_t val, void *priv); + void (*writew)(uint32_t addr, uint16_t val, void *priv); + void (*writel)(uint32_t addr, uint32_t val, void *priv); + + uint8_t (*read)(uint32_t addr, void *priv); + uint16_t (*readw)(uint32_t addr, void *priv); + uint32_t (*readl)(uint32_t addr, void *priv); + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); float (*getclock)(int clock, void *priv); float (*getclock8514)(int clock, void *priv); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index bc54d0d7c..08a8c7677 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4403,7 +4403,13 @@ gd54xx_init(const device_t *info) if ((vram == 1) || (vram >= 256 && vram <= 1024)) svga->decode_mask = gd54xx->vram_mask; + svga->read = gd54xx_read; + svga->readw = gd54xx_readw; + svga->write = gd54xx_write; + svga->writew = gd54xx_writew; if (gd54xx->bit32) { + svga->readl = gd54xx_readl; + svga->writel = gd54xx_writel; mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, @@ -4423,6 +4429,8 @@ gd54xx_init(const device_t *info) gd5480_vgablt_write, gd5480_vgablt_writew, gd5480_vgablt_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); } else { + svga->readl = NULL; + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, NULL, gd54xx_write, gd54xx_writew, NULL); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index a249631ee..f349864df 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -33,9 +33,12 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/video.h> +#include <86box/vid_8514a.h> #include <86box/vid_xga.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> +#include <86box/vid_ati_eeprom.h> +#include <86box/vid_ati_mach8.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> @@ -425,9 +428,8 @@ ht216_out(uint16_t addr, uint8_t val, void *priv) svga->banked_mask = 0xffff; } - if (svga->gdcaddr <= 8) { + if (svga->gdcaddr <= 8) svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4 && svga->packed_chain4; - } break; case 0x3D4: @@ -625,7 +627,9 @@ ht216_remap(ht216_t *ht216) void ht216_recalctimings(svga_t *svga) { - ht216_t *ht216 = (ht216_t *) svga->priv; + ht216_t *ht216 = (ht216_t *) svga->priv; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + mach_t *mach = (mach_t *) svga->ext8514; int high_res_256 = 0; @@ -672,10 +676,16 @@ ht216_recalctimings(svga_t *svga) if (!svga->scrblank && svga->attr_palette_enable) { if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ { + if (svga->seqregs[1] & 8) /*40 column*/ svga->render = svga_render_text_40; - } else { + else svga->render = svga_render_text_80; + + if (ibm8514_active && (svga->dev8514 != NULL)) { + if (svga->ext8514 != NULL) { + if (!(dev->accel.advfunc_cntl & 0x01) && !(mach->accel.clock_sel & 0x01)) /*FIXME: Possibly a BIOS bug within the V7 chips when it's used with a 8514/A card?*/ + dev->on &= ~0x01; + } } } else { if (svga->crtc[0x17] == 0xeb) { @@ -1576,10 +1586,17 @@ ht216_init(const device_t *info, uint32_t mem_size, int has_rom) if (has_rom == 4) svga->ramdac = device_add(&sc11484_nors2_ramdac_device); + svga->read = ht216_read; + svga->readw = NULL; + svga->readl = NULL; + svga->write = ht216_write; + svga->writew = ht216_writew; if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + svga->writel = ht216_writel; mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, ht216_writel); mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); } else { + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, NULL); mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, NULL, NULL, MEM_MAPPING_EXTERNAL, svga); } diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index bf038eb32..27e98d32d 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -362,11 +362,6 @@ paradise_write(uint32_t addr, uint8_t val, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) { - svga_write(addr, val, svga); - return; - } - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -400,11 +395,6 @@ paradise_writew(uint32_t addr, uint16_t val, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) { - svga_writew(addr, val, svga); - return; - } - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -438,9 +428,6 @@ paradise_read(uint32_t addr, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) - return svga_read(addr, svga); - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -474,9 +461,6 @@ paradise_readw(uint32_t addr, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) - return svga_readw(addr, svga); - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -550,6 +534,12 @@ paradise_init(const device_t *info, uint32_t memory) break; } + svga->read = paradise_read; + svga->readw = paradise_readw; + svga->readl = NULL; + svga->write = paradise_write; + svga->writew = paradise_writew; + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); mem_mapping_set_p(&svga->mapping, paradise); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 6a91713fb..e6201e4bf 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -984,7 +984,7 @@ svga_recalctimings(svga_t *svga) svga_log("IBM 8514/A poll.\n"); timer_set_callback(&svga->timer, ibm8514_poll); } else { - svga_log("SVGA Poll.\n"); + svga_log("SVGA poll enabled.\n"); timer_set_callback(&svga->timer, svga_poll); } } @@ -1081,6 +1081,7 @@ svga_poll(void *priv) } } + svga_log("SVGA Poll.\n"); if (!svga->linepos) { if (svga->displine == ((svga->hwcursor_latch.y < 0) ? 0 : svga->hwcursor_latch.y) && svga->hwcursor_latch.ena) { svga->hwcursor_on = svga->hwcursor_latch.cur_ysize - svga->hwcursor_latch.yoff; @@ -1406,16 +1407,34 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->ksc5601_english_font_type = 0; if ((info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + svga->read = svga_read; + svga->readw = svga_readw; + svga->readl = svga_readl; + svga->write = svga_write; + svga->writew = svga_writew; + svga->writel = svga_writel; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_AT)) { + svga->read = svga_read; + svga->readw = svga_readw; + svga->readl = NULL; + svga->write = svga_write; + svga->writew = svga_writew; + svga->writel = NULL; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, NULL, svga_write, svga_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, svga); } else { + svga->read = svga_read; + svga->readw = NULL; + svga->readl = NULL; + svga->write = svga_write; + svga->writew = NULL; + svga->writel = NULL; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, NULL, NULL, svga_write, NULL, NULL, diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 3df43a29c..852ff6273 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -188,7 +188,7 @@ xga_updatemapping(svga_t *svga) mem_mapping_disable(&xga->linear_mapping); break; default: - xga_log("XGA: Extended Graphics mode.\n"); + xga_log("XGA: Extended Graphics mode, ap=%d.\n", xga->aperture_cntl); switch (xga->aperture_cntl) { case 0: xga_log("XGA: No 64KB aperture: 1MB=%x, 4MB=%x, SVGA Mapping Base=%x.\n", xga->base_addr_1mb, xga->linear_base, svga->mapping.base); @@ -201,7 +201,7 @@ xga_updatemapping(svga_t *svga) } else mem_mapping_disable(&xga->linear_mapping); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); switch (svga->gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -439,9 +439,9 @@ xga_ext_out_reg(xga_t *xga, svga_t *svga, uint8_t idx, uint8_t val) break; case 0x51: - xga_log("Reg51 write = %02x.\n", val); + xga_log("Reg51 write=%02x.\n", val & 0x07); xga->disp_cntl_2 = val; - xga->on = ((val & 7) >= 2); + xga->on = ((val & 0x07) >= 0x02); svga_recalctimings(svga); break; @@ -535,9 +535,11 @@ xga_ext_outb(uint16_t addr, uint8_t val, void *priv) xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); switch (addr & 0x0f) { case 0: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); xga->op_mode = val; break; case 1: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); xga->aperture_cntl = val & 3; xga_updatemapping(svga); break; @@ -579,6 +581,7 @@ xga_ext_outb(uint16_t addr, uint8_t val, void *priv) break; default: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); break; } } @@ -807,6 +810,7 @@ xga_ext_inb(uint16_t addr, void *priv) break; default: + xga_log("[%04X:%08X]: EXT INB = %02x, ret = %02x.\n\n", CS, cpu_state.pc, addr, ret); break; } @@ -933,6 +937,32 @@ xga_accel_read_pattern_map_pixel(svga_t *svga, int x, int y, uint32_t base, int return px; } +static uint32_t +xga_accel_read_area_map_pixel(svga_t *svga, int x, int y, uint32_t base, int width) +{ + const xga_t *xga = (xga_t *) svga->xga; + uint32_t addr = base; + int bits; + uint8_t byte; + uint8_t px; + int skip = 0; + + if ((addr < xga->linear_base) || (addr > (xga->linear_base + 0xfffff))) + skip = 1; + + addr += (y * (width >> 3)); + addr += (x >> 3); + if (!skip) { + READ(addr, byte); + } else + byte = mem_readb_phys(addr); + + bits = 7 - (x & 7); + + px = (byte >> bits) & 1; + return px; +} + static uint32_t xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int width) { @@ -971,6 +1001,7 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int } else byte = mem_readb_phys(addr); + xga_log("4bpp read: OPMODEBIG=%02x, SRC Map=%02x, DST Map=%02x, AccessMode=%02x, SRCPIX=%02x, DSTPIX=%02x, wordpix=%04x, x=%d, y=%d, skip=%d.\n", xga->op_mode & 0x08, (xga->accel.px_map_format[xga->accel.src_map] & 0x0f), (xga->accel.px_map_format[xga->accel.dst_map] & 0x0f), xga->access_mode & 0x0f, xga->accel.src_map, xga->accel.dst_map, byte, x, y, skip); return byte; case 3: /*8-bit*/ addr += (y * width); @@ -984,19 +1015,15 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int case 4: /*16-bit*/ addr += (y * (width << 1)); addr += (x << 1); - if (xga->access_mode & 0x08) { - if (!skip) { - READW(addr, byte); - } else - byte = mem_readw_phys(addr); - } else { - if (!skip) { - READW(addr, byte); - } else { - byte = mem_readw_phys(addr); - if ((xga->access_mode & 0x07) == 0x04) - byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); - } + + if (!skip) { + READW(addr, byte); + } else { + byte = mem_readw_phys(addr); + if ((xga->access_mode & 0x07) == 0x04) + byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); + else if (xga->access_mode & 0x08) + byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); } return byte; @@ -1081,17 +1108,14 @@ xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, ui case 4: /*16-bit*/ addr += (y * width << 1); addr += (x << 1); - if (xga->access_mode & 0x08) { - if (!skip) { - WRITEW(addr, pixel); - } + + if (!skip) { + WRITEW(addr, pixel); } else { - if (!skip) { - WRITEW(addr, pixel); - } else { - if ((xga->access_mode & 0x07) == 0x04) - pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); - } + if ((xga->access_mode & 0x07) == 0x04) + pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); + else if (xga->access_mode & 0x08) + pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); } mem_writew_phys(addr, pixel); break; @@ -1237,12 +1261,11 @@ xga_line_draw_write(svga_t *svga) uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; int y = xga->accel.blt_width; int x = 0; + int draw_pixel = 0; int16_t dx; int16_t dy; int16_t cx; int16_t cy; - int err = xga->accel.bres_err_term; - int draw_pixel = 0; cx = xga->accel.src_map_x & 0xfff; cy = xga->accel.src_map_y & 0xfff; @@ -1256,38 +1279,57 @@ xga_line_draw_write(svga_t *svga) dy |= ~0x17ff; if ((xga->accel.command & 0x30) == 0x30) - xga_log("Line Draw Write: BLTWIDTH=%d, BLTHEIGHT=%d, FRGDCOLOR=%04x, XDIR=%i, YDIR=%i, steep=%s, ERR=%04x.\n", xga->accel.blt_width, xga->accel.blt_height, xga->accel.frgd_color & 0xffff, xdir, ydir, (xga->accel.octant & 0x01) ? "0" : "1", err); - + xga_log("Line Draw Write Fill: DX=%d, DY=%d, BLTWIDTH=%d, BLTHEIGHT=%d, FRGDCOLOR=%04x, negative XDIR=%i, negative YDIR=%i, YMAJOR=%d, ERR=%d, BRESK2=%d, BRESK1=%d, mask=%02x.\n", dx, dy, xga->accel.blt_width, xga->accel.blt_height, xga->accel.frgd_color & 0xffff, (xga->accel.octant & 0x04), (xga->accel.octant & 0x02), (xga->accel.octant & 0x01), xga->accel.bres_err_term, xga->accel.bres_k2, xga->accel.bres_k1, xga->accel.command & 0xc0); if (xga->accel.pat_src == 8) { if ((xga->accel.command & 0x30) == 0x30) { while (y >= 0) { draw_pixel = 0; - if (xga->accel.octant & 0x01) { - if (xga->accel.octant & 0x02) { /*Bottom-to-Top*/ + if (xga->accel.octant & 0x01) { /*Y Major*/ + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ if (x) draw_pixel = 1; - } else { /*Top-to-Bottom*/ + } else { /*Top to Bottom*/ if (y) draw_pixel = 1; } - } else if (!(xga->accel.octant & 0x04) && (err < (xga->accel.bres_k2 + xga->accel.bres_k1))) /*X+*/ - draw_pixel = 1; - else if ((xga->accel.octant & 0x04) && (err >= 0)) /*X-*/ - draw_pixel = 1; - - if (xga->accel.command & 0xc0) { - if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { - if (draw_pixel) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, cx, cy, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1) : xga->accel.frgd_color; - dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); - - if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { - ROP(1, dest_dat, src_dat); - xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); + } else { /*X Major*/ + if (xga->accel.octant & 0x04) { /*Right to Left*/ + if (xga->accel.bres_err_term >= 0) { + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ + if (x) + draw_pixel = 1; + } else { /*Top to Bottom*/ + if (y) + draw_pixel = 1; } } + } else { /*Left to Right*/ + if (xga->accel.bres_err_term < (xga->accel.bres_k1 + xga->accel.bres_k2)) { + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ + if (x) + draw_pixel = 1; + } else { /*Top to Bottom*/ + if (y) + draw_pixel = 1; + } + } + } + } + + xga_log("Draw Boundary: DX=%d, DY=%d, wrt_pix=%d, ymajor=%d, bottomtotop=%x, len=%d, err=%d, frgdmix=%02x.\n", dx, dy, draw_pixel, xga->accel.octant & 0x01, xga->accel.octant & 0x02, y, xga->accel.bres_err_term, xga->accel.frgd_mix & 0x1f); + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off)) && draw_pixel) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, cx, cy, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); + } } } else { if (draw_pixel) { @@ -1295,7 +1337,9 @@ xga_line_draw_write(svga_t *svga) dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); } } @@ -1310,28 +1354,28 @@ xga_line_draw_write(svga_t *svga) else dy++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x04) dx--; else dx++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } else { if (xga->accel.octant & 0x04) dx--; else dx++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x02) dy--; else dy++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } x++; y--; @@ -1384,28 +1428,28 @@ xga_line_draw_write(svga_t *svga) else dy++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x04) dx--; else dx++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } else { if (xga->accel.octant & 0x04) dx--; else dx++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x02) dy--; else dy++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } y--; x++; @@ -1454,20 +1498,21 @@ xga_bitblt(svga_t *svga) if (xga->accel.dst_map_y >= 0x1800) dy |= ~0x17ff; - xga_log("D(%d,%d), SWH(%d,%d), BLT(%d,%d), dstwidth=%d.\n", dx, dy, xga->accel.x, xga->accel.y, srcwidth, srcheight, dstwidth); + xga_log("D(%d,%d), SWH(%d,%d), BLT(%d,%d), dstwidth=%d, frgdcol=%04x, bkgdcol=%04x.\n", dx, dy, xga->accel.x, xga->accel.y, srcwidth, srcheight, dstwidth, frgdcol, bkgdcol); xga->accel.pattern = 0; xga->accel.filling = 0; - xga_log("XGA bitblt linear endian reverse=%d, access_mode=%x, octanty=%d, src command = %08x, " + xga_log("XGA bitblt access_mode=%x, octanty=%d, src command=%08x, " "pxsrcmap=%x, pxpatmap=%x, pxdstmap=%x, srcmap=%d, patmap=%d, dstmap=%d, " - "usesrcvramfr=%d, usevrambk=%d.\n", - xga->linear_endian_reverse, xga->access_mode & 0x0f, ydir, xga->accel.command, + "usesrcvramfr=%d, usevrambk=%d, frgdcol=%04x, bkgdcol=%04x, bgmix=%02x, fgmix=%02x.\n", + xga->access_mode & 0x0f, ydir, xga->accel.command, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.px_map_format[xga->accel.pat_src] & 0x0f, xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.src_map, xga->accel.pat_src, - xga->accel.dst_map, ((xga->accel.command >> 28) & 3), ((xga->accel.command >> 30) & 3)); + xga->accel.dst_map, ((xga->accel.command >> 28) & 3), ((xga->accel.command >> 30) & 3), + frgdcol, bkgdcol, xga->accel.bkgd_mix & 0x1f, xga->accel.frgd_mix & 0x1f); if (xga->accel.pat_src == 8) { if (srcheight == 7) @@ -1593,17 +1638,19 @@ xga_bitblt(svga_t *svga) xga->accel.px_map_width[2], xga->accel.px_map_width[3], bkgdcol); xga_log("Pattern Enabled?=%d, patwidth=%d, patheight=%d, P(%d,%d).\n", xga->accel.pattern, patwidth, patheight, xga->accel.px, xga->accel.py); - if ((((xga->accel.command >> 24) & 0x0f) == 0x0a) && ((xga->accel.bkgd_mix & 0x1f) == 5)) { - while (xga->accel.y >= 0) { - mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, patbase, patwidth + 1); - if (mix) - xga->accel.filling = !xga->accel.filling; + if (((xga->accel.command >> 24) & 0x0f) == 0x0a) { + if ((xga->accel.bkgd_mix & 0x1f) == 0x05) { + while (xga->accel.y >= 0) { + mix = xga_accel_read_area_map_pixel(svga, xga->accel.px, xga->accel.py, patbase, patwidth + 1); + if (mix) + xga->accel.filling ^= 1; - if (xga->accel.command & 0xc0) { - if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; - if (xga->accel.filling) { - dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, 1024); + xga_log("Area Fill Command: dx=%d, dy=%d, mix=%x, filling=%x.\n", dx, dy, mix, xga->accel.filling); + + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off)) && xga->accel.filling) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; ROP(1, dest_dat, src_dat); @@ -1612,11 +1659,9 @@ xga_bitblt(svga_t *svga) xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); } } - } - } else { - if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight)) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; - if (xga->accel.filling) { + } else { + if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight) && xga->accel.filling) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; @@ -1627,32 +1672,35 @@ xga_bitblt(svga_t *svga) } } } - } - xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); - xga->accel.px++; + xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); + xga->accel.px++; - dx++; - xga->accel.x--; - if (xga->accel.x < 0) { - xga->accel.y--; - xga->accel.x = xga->accel.blt_width & 0xfff; + dx++; + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.y--; + xga->accel.x = xga->accel.blt_width & 0xfff; - dx = xga->accel.dst_map_x; - if (xga->accel.dst_map_x >= 0x1800) - dx |= ~0x17ff; + dx = xga->accel.dst_map_x; + if (xga->accel.dst_map_x >= 0x1800) + dx |= ~0x17ff; - xga->accel.sx = xga->accel.src_map_x & 0xfff; - xga->accel.px = xga->accel.pat_map_x & 0xfff; + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; - xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); - xga->accel.py++; + xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); + xga->accel.py++; - dy++; - xga->accel.filling = 0; + dy++; + xga->accel.filling = 0; - if (xga->accel.y < 0) - return; + if (xga->accel.y < 0) { + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; + return; + } + } } } } else { @@ -2171,7 +2219,6 @@ exec_command: xga->accel.src_map = ((xga->accel.command >> 20) & 0x0f); xga_log("PATMAP=%x, DSTMAP=%x, SRCMAP=%x.\n", xga->accel.px_map_format[xga->accel.pat_src], xga->accel.px_map_format[xga->accel.dst_map], xga->accel.px_map_format[xga->accel.src_map]); -#ifdef ENABLE_XGA_LOG if (xga->accel.pat_src) xga_log("[%04X:%08X]: Accel Command = %02x, full = %08x, patwidth = %d, " "dstwidth = %d, srcwidth = %d, patheight = %d, dstheight = %d, " @@ -2196,7 +2243,7 @@ exec_command: xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.plane_mask); -#endif + switch ((xga->accel.command >> 24) & 0x0f) { case 2: /*Short Stroke Vectors Read */ xga_log("Short Stroke Vectors Read.\n"); @@ -2670,7 +2717,7 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga->vram[addr & xga->vram_mask] = val; xga_log("XGA Linear endian reverse write, val = %02x, addr = %05x, banked mask = %04x, a5test=%d.\n", val, addr, svga->banked_mask, xga->a5_test); } - } else if (xga->aperture_cntl) + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) xga->on = 0; } } @@ -2777,9 +2824,8 @@ xga_read_test(uint32_t addr, void *priv) addr += xga->read_bank; return xga->vram[addr & xga->vram_mask]; } - } else if (xga->aperture_cntl) { + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) xga->on = 0; - } } return ret; } @@ -2874,7 +2920,7 @@ xga_write_linear(uint32_t addr, uint8_t val, void *priv) svga_t *svga = (svga_t *) priv; xga_t *xga = (xga_t *) svga->xga; - xga_log("WrtieLL XGA=%d.\n", xga->on); + xga_log("WriteLL XGA=%d.\n", xga->on); if (!xga->on) { svga_write_linear(addr, val, svga); return; @@ -2889,13 +2935,6 @@ xga_write_linear(uint32_t addr, uint8_t val, void *priv) cycles -= svga->monitor->mon_video_timing_write_b; - if (!(xga->access_mode & 0x08)) { - if ((xga->access_mode & 0x07) == 0x04) { - if ((xga->accel.px_map_format[xga->accel.dst_map] & 0x07) == 0x04) - addr ^= 1; - } - } - xga->changedvram[(addr & xga->vram_mask) >> 12] = svga->monitor->mon_changeframecount; xga->vram[addr & xga->vram_mask] = val; } @@ -2951,14 +2990,9 @@ xga_read_linear(uint32_t addr, void *priv) cycles -= svga->monitor->mon_video_timing_read_b; - if (!(xga->access_mode & 0x08)) { - if ((xga->access_mode & 0x07) == 0x04) { - if ((xga->accel.px_map_format[xga->accel.dst_map] & 0x07) == 0x04) - addr ^= 1; - } - } + ret = xga->vram[addr & xga->vram_mask]; - return xga->vram[addr & xga->vram_mask]; + return ret; } static uint16_t @@ -3234,7 +3268,7 @@ xga_mca_reset(void *priv) svga_t *svga = (svga_t *) priv; xga_log("MCA Reset.\n"); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); xga_mca_write(0x102, 0, svga); } @@ -3250,7 +3284,7 @@ xga_reset(void *priv) xga->on = 0; xga->a5_test = 0; - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); } static uint8_t From f1a856c8863ea06db030605bc0342f340cbe02f7 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Mon, 20 Jan 2025 05:53:40 +0200 Subject: [PATCH 0143/1190] GlaBIOS for Vendex HeadStart Turbo 888-XT --- src/machine/m_xt.c | 53 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index ef3a84e24..9f232ac95 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -919,18 +919,63 @@ machine_xt_pc500_init(const machine_t *model) return ret; } +static const device_config_t vendex_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "vendex", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "Bios 2.03C", .internal_name = "vendex", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/vendex/Vendex Turbo 888 XT - ROM BIOS - VER 2.03C.bin", "" } }, + // GlaBIOS for Juko ST + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8TV.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VTV.ROM", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t vendex_device = { + .name = "Vendex 888T Devices", + .internal_name = "vendex_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = vendex_config +}; + int machine_xt_vendex_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/vendex/Vendex Turbo 888 XT - ROM BIOS - VER 2.03C.bin", - 0x000fc000, 16384, 0); + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fc000, 16384, 0); + device_context_restore(); if (bios_only || !ret) return ret; - /* On-board FDC cannot be disabled */ machine_xt_clone_init(model, 1); device_add(&vendex_xt_rtc_onboard_device); From ce390fb9cde6b5f3fadec433fad176d2c0b39368 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Mon, 20 Jan 2025 05:55:03 +0200 Subject: [PATCH 0144/1190] GlaBIOS for Vendex HeadStart Turbo 888-XT --- src/machine/machine_table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index cafbe514d..f2fb53a6f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -65,6 +65,7 @@ extern const device_t ibmat_device; extern const device_t ibmxt286_device; extern const device_t pb450_device; extern const device_t jukopc_device; +extern const device_t vendex_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -1696,7 +1697,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &vendex_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, From 23ba9889d26c62270bf254e8d75e97eb445ea3ac Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:16:36 +0900 Subject: [PATCH 0145/1190] Fixed an illegal memory access error Fixed an illegal memory access error when reading font ROM data beyond 1 MB border --- src/video/vid_ps55da2.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 6a90a3dc3..d75d0aa03 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -42,6 +42,7 @@ #define DA2_FONTROM_BASESBCS 0x98000 #define DA2_GAIJIRAM_SBCS 0x34000 #define DA2_GAIJIRAM_SBEX 0x3c000 +#define DA2_INVALIDACCESS8 0xff #define DA2_MASK_MMIO 0x1ffff #define DA2_MASK_GRAM 0x1ffff #define DA2_MASK_CRAM 0xfff @@ -1244,7 +1245,7 @@ uint16_t da2_in(uint16_t addr, void *p) break; case LS_DATA: //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) - if (da2->ioctladdr > 0xf) return 0xff; + if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrc[LV_COMPATIBILITY] & 0x08) @@ -1275,14 +1276,14 @@ uint16_t da2_in(uint16_t addr, void *p) temp = da2->fctladdr; break; case LF_DATA: - if (da2->fctladdr > 0x1f) return 0xff; + if (da2->fctladdr > 0x1f) return DA2_INVALIDACCESS8; temp = da2->fctl[da2->fctladdr]; break; case LC_INDEX: temp = da2->crtcaddr; break; case LC_DATA: - if (da2->crtcaddr > 0x1f) return 0xff; + if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; temp = da2->crtc[da2->crtcaddr]; break; case LV_PORT: @@ -2270,12 +2271,12 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.ram[addr]; break; case 0x10://Font ROM + if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); - if (addr > DA2_FONTROM_SIZE) return 0xff; return da2->mmio.font[addr]; break; default: - return 0xff;//invalid memory access + return DA2_INVALIDACCESS8;//invalid memory access break; } } @@ -2677,7 +2678,7 @@ static void da2_code_writew(uint32_t addr, uint16_t val, void* p) static uint8_t da2_code_read(uint32_t addr, void* p) { da2_t* da2 = (da2_t*)p; - if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return 0xff; + if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return DA2_INVALIDACCESS8; addr &= DA2_MASK_CRAM; return da2->cram[addr]; } From 0be045b3cff89cd27b019700b782a1ad77643ccd Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 20 Jan 2025 12:51:27 -0300 Subject: [PATCH 0146/1190] AD1848: Fix additional data format unlocking which has been wrong this whole time --- src/sound/snd_ad1848.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index a0166c4e5..ddf8e61ec 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -273,20 +273,21 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) return; case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + if (ad1848->type >= AD1848_TYPE_CS4248) { + ad1848->regs[12] = 0x80 | (val & 0x70) | (ad1848->regs[12] & 0x0f); + if ((ad1848->type >= AD1848_TYPE_CS4231) && (ad1848->type < AD1848_TYPE_CS4235)) { + if (val & 0x40) + ad1848->fmt_mask |= 0x80; + else + ad1848->fmt_mask &= ~0x80; + } + } return; case 14: ad1848->count = ad1848->regs[15] | (val << 8); break; - case 17: - /* Enable additional data formats on modes 2 and 3 where supported. */ - if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236B)) - ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; - break; - case 18: case 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { From 3dea388ae4bf7cb8792f9bd6b2f690ebc446de33 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 20 Jan 2025 13:37:55 -0300 Subject: [PATCH 0147/1190] CS423x: Fix broken codec on CS4236B --- src/sound/snd_cs423x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 0d9af74f2..0a383e13f 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -12,7 +12,7 @@ * * Authors: RichardG, * - * Copyright 2021-2022 RichardG. + * Copyright 2021-2025 RichardG. */ #include #include @@ -386,7 +386,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) dev->ram_dl = CRYSTAL_RAM_CMD; /* Update PnP state and resource data. */ - dev->pnp_size = 384; /* we don't know the length */ + dev->pnp_size = (dev->type >= CRYSTAL_CS4236) ? 384 : 256; /* we don't know the length */ cs423x_pnp_enable(dev, 1, 0); } break; @@ -853,12 +853,13 @@ cs423x_init(const device_t *info) dev->type = info->local & 0xff; cs423x_log("CS423x: init(%02X)\n", dev->type); switch (dev->type) { - case CRYSTAL_CS4235: case CRYSTAL_CS4236B: case CRYSTAL_CS4237B: case CRYSTAL_CS4238B: + case CRYSTAL_CS4235: + case CRYSTAL_CS4239: /* Same WSS codec and EEPROM structure. */ - dev->ad1848_type = (dev->type == CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236; + dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236B; dev->pnp_offset = 0x4013; /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init. */ From b48594a4cc10e4a96d4444d9010025b0230bcd7d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 20 Jan 2025 14:20:14 -0300 Subject: [PATCH 0148/1190] AD1848: Add one more CS4235 register access backdoor --- src/sound/snd_ad1848.c | 30 ++++++++++++++++++++++++------ src/sound/snd_cs423x.c | 7 +++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index ddf8e61ec..d870b4588 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -200,10 +200,22 @@ ad1848_read(uint16_t addr, void *priv) case 23: if ((ad1848->type >= AD1848_TYPE_CS4236B) && (ad1848->regs[23] & 0x08)) { - if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */ - ret = ad1848->regs[18 + ad1848->xindex]; - else - ret = ad1848->xregs[ad1848->xindex]; + ret = ad1848->xregs[ad1848->xindex]; + switch (ad1848->xindex) { + case 0 ... 1: + /* Remapped line volume. */ + ret = ad1848->regs[18 + ad1848->xindex]; + break; + + case 26: + /* Backdoor to the Joystick Control register on CS4235+. */ + if (ad1848->type >= AD1848_TYPE_CS4235) + ret = ad1848->cram_read(0, ad1848->cram_priv); + break; + + default: + break; + } } break; @@ -353,8 +365,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) } switch (ad1848->xindex) { - case 0: - case 1: /* remapped line volume */ + case 0 ... 1: + /* Remapped line volume. */ ad1848->regs[18 + ad1848->xindex] = val; return; @@ -380,6 +392,12 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 25: return; + case 26: + /* Backdoor to the Joystick Control register on CS4235+. */ + if (ad1848->type >= AD1848_TYPE_CS4235) + ad1848->cram_write(0, val, ad1848->cram_priv); + break; + default: break; } diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 0a383e13f..288314a13 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -144,6 +144,7 @@ typedef struct cs423x_t { } cs423x_t; static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable); +static void cs423x_ctxswitch_write(uint16_t addr, UNUSED(uint8_t val), void *priv); static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig); static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); static void cs423x_reset(void *priv); @@ -237,6 +238,12 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) case 0: /* Joystick and Power Control */ if (dev->type <= CRYSTAL_CS4232) val &= 0xeb; + if ((dev->type >= CRYSTAL_CS4235) && (addr == 0) && (val & 0x08)) { + /* CS4235+ through X26 backdoor only (hence the addr check): WSS off (one-way trip?) */ + io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848); + io_removehandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev); + dev->wss_base = 0; + } break; case 1: /* EEPROM Interface */ From 40080101313bf30a235610792ac522761b3a94fd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 20 Jan 2025 19:55:18 +0100 Subject: [PATCH 0149/1190] Big SCSI bus update of the day, NCR 5380 too (January 20th, 2025) 1. Separate the SCSI bus functions from NCR 5380 into true general purpose SCSI bus functions, allowing use of future legacy scsi controllers. 2. Corrected NCR 5380 chip period for the SCSI controllers based on that chip so that CD-ROM speed is correct enough per speed tests and no more breakage (I hope, report if they are still there, please!) on desyncs. 3. A NCR 5380 software reset involves asserting an IRQ. --- src/include/86box/scsi_device.h | 46 ++++ src/include/86box/scsi_ncr5380.h | 48 +--- src/scsi/scsi_device.c | 334 +++++++++++++++++++++++++++- src/scsi/scsi_ncr5380.c | 371 ++++--------------------------- src/scsi/scsi_ncr53c400.c | 128 +++++------ src/scsi/scsi_t128.c | 89 +++++--- src/sound/snd_pas16.c | 12 +- 7 files changed, 546 insertions(+), 482 deletions(-) diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 6fdac5ebd..538a96fac 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -333,6 +333,20 @@ #define BUS_IDLE (1 << 31) +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_DATAIN 2 +#define STATE_DATAOUT 3 +#define STATE_STATUS 4 +#define STATE_MESSAGEIN 5 +#define STATE_SELECT 6 +#define STATE_MESSAGEOUT 7 +#define STATE_MESSAGE_ID 8 + +#define PIO_TX_BUS 0 +#define DMA_IN_TX_BUS 1 +#define DMA_OUT_TX_BUS 2 + #define PHASE_IDLE 0x00 #define PHASE_COMMAND 0x01 #define PHASE_DATA_IN 0x02 @@ -420,6 +434,36 @@ typedef struct scsi_device_t { void (*command_stop)(scsi_common_t *sc); } scsi_device_t; +typedef struct scsi_bus_t { + int tx_mode; + int clear_req; + int wait_data; + int wait_complete; + int bus_out; + int bus_in; + int command_pos; + int command_issued; + int data_pos; + int msgout_pos; + int is_msgout; + int state; + int dma_on_pio_enabled; + uint8_t data; + uint8_t msglun; + uint8_t data_wait; + uint8_t command[16]; + uint8_t msgout[4]; + uint8_t target_id; + uint8_t bus_device; + uint32_t bus_phase; + double period; + double speed; + double divider; + double multi; + void *priv; + void (*timer)(void *priv, double period); +} scsi_bus_t; + /* These are based on the INQUIRY values. */ #define SCSI_NONE 0x0060 #define SCSI_FIXED_DISK 0x0000 @@ -454,6 +498,8 @@ extern void scsi_device_init(void); extern void scsi_reset(void); extern uint8_t scsi_get_bus(void); +extern int scsi_bus_read(scsi_bus_t *scsi_bus); +extern void scsi_bus_update(scsi_bus_t *scsi_bus, int bus); extern void scsi_bus_set_speed(uint8_t bus, double speed); extern double scsi_bus_get_speed(uint8_t bus); diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index 09307fed6..0b8a4efd8 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -44,6 +44,9 @@ #define ICR_ACK 0x10 #define ICR_ARB_LOST 0x20 #define ICR_ARB_IN_PROGRESS 0x40 +#define ICR_RST 0x80 +#define ICR_PHASE 0x9e +#define ICR_WRITE 0x9f #define MODE_ARBITRATE 0x01 #define MODE_DMA 0x02 @@ -63,70 +66,33 @@ #define TCR_REQ 0x08 #define TCR_LAST_BYTE_SENT 0x80 - -#define STATE_IDLE 0 -#define STATE_COMMAND 1 -#define STATE_DATAIN 2 -#define STATE_DATAOUT 3 -#define STATE_STATUS 4 -#define STATE_MESSAGEIN 5 -#define STATE_SELECT 6 -#define STATE_MESSAGEOUT 7 -#define STATE_MESSAGE_ID 8 - -#define DMA_IDLE 0 -#define DMA_SEND 1 -#define DMA_INITIATOR_RECEIVE 2 - typedef struct ncr_t { uint8_t icr; uint8_t mode; uint8_t tcr; - uint8_t data_wait; uint8_t isr; uint8_t output_data; - uint8_t target_id; uint8_t tx_data; - uint8_t msglun; uint8_t irq_state; - uint8_t command[20]; - uint8_t msgout[4]; uint8_t bus; - int msgout_pos; - int is_msgout; - - int dma_mode; - int cur_bus; - int bus_in; - int new_phase; - int state; - int clear_req; - int wait_data; - int wait_data_back; - int wait_complete; - int command_pos; - int data_pos; - int irq; double period; void *priv; - void (*dma_mode_ext)(void *priv, void *ext_priv); + void (*dma_mode_ext)(void *priv, void *ext_priv, uint8_t val); int (*dma_send_ext)(void *priv, void *ext_priv); int (*dma_initiator_receive_ext)(void *priv, void *ext_priv); void (*timer)(void *ext_priv, double period); + + scsi_bus_t scsibus; } ncr_t; -extern int ncr5380_cmd_len[8]; - extern void ncr5380_irq(ncr_t *ncr, int set_irq); -extern void ncr5380_set_irq(ncr_t *ncr, int irq); +extern void ncr5380_set_irq(ncr_t *ncr, int irq); extern uint32_t ncr5380_get_bus_host(ncr_t *ncr); -extern void ncr5380_bus_read(ncr_t *ncr); -extern void ncr5380_bus_update(ncr_t *ncr, int bus); extern void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr); extern uint8_t ncr5380_read(uint16_t port, ncr_t *ncr); diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 4442b2680..33d3fa89a 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -16,10 +16,14 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2017-2018 Fred N. van Kempen. */ +#include #include #include #include +#include +#include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/hdd.h> @@ -29,9 +33,29 @@ #include <86box/plat_unused.h> scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; - +int scsi_command_length[8] = { 6, 10, 10, 6, 16, 12, 10, 6 }; uint8_t scsi_null_device_sense[18] = { 0x70, 0, SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 0, 0, 0, 0, 0, ASC_INV_LUN, 0, 0, 0, 0, 0 }; +#define SET_BUS_STATE(scsi_bus, state) scsi_bus->bus_out = (scsi_bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) + +#ifdef ENABLE_SCSI_DEVICE_LOG +int scsi_device_do_log = ENABLE_SCSI_DEVICE_LOG; + +static void +scsi_device_log(const char *fmt, ...) +{ + va_list ap; + + if (scsi_device_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define scsi_device_log(fmt, ...) +#endif + static uint8_t scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) { @@ -189,3 +213,311 @@ scsi_device_init(void) } } } + +int +scsi_device_get_id(uint8_t data) +{ + for (uint8_t c = 0; c < SCSI_ID_MAX; c++) { + if (data & (1 << c)) + return c; + } + + return -1; +} + + +static int +scsi_device_get_msg(uint8_t *msgp, int len) +{ + uint8_t msg = msgp[0]; + if ((msg == 0) || ((msg >= 0x02) && (msg <= 0x1f)) || (msg >= 0x80)) + return 1; + + if ((msg >= 0x20) && (msg <= 0x2f)) + return 2; + + if (len < 2) + return 3; + + return msgp[1]; +} + +int +scsi_bus_read(scsi_bus_t *scsi_bus) +{ + scsi_device_t *dev; + int phase; + + /*Wait processes to handle bus requests*/ + if (scsi_bus->clear_req) { + scsi_bus->clear_req--; + if (!scsi_bus->clear_req) { + scsi_device_log("Prelude to command data\n"); + SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase); + scsi_bus->bus_out |= BUS_REQ; + } + } + + if (scsi_bus->wait_data) { + scsi_bus->wait_data--; + if (!scsi_bus->wait_data) { + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase); + phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN; + + switch (phase) { + case SCSI_PHASE_DATA_IN: + scsi_device_log("DataIn.\n"); + scsi_bus->state = STATE_DATAIN; + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++]; + + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP; + break; + case SCSI_PHASE_DATA_OUT: + if (scsi_bus->bus_phase & BUS_IDLE) { + scsi_device_log("Bus Idle.\n"); + scsi_bus->state = STATE_IDLE; + scsi_bus->bus_out &= ~BUS_BSY; + scsi_bus->timer(scsi_bus->priv, 0.0); + } else { + scsi_device_log("DataOut.\n"); + scsi_bus->state = STATE_DATAOUT; + } + break; + case SCSI_PHASE_STATUS: + scsi_device_log("Status.\n"); + scsi_bus->bus_out |= BUS_REQ; + scsi_bus->state = STATE_STATUS; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; + break; + case SCSI_PHASE_MESSAGE_IN: + scsi_device_log("Message In.\n"); + scsi_bus->state = STATE_MESSAGEIN; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + case SCSI_PHASE_MESSAGE_OUT: + scsi_device_log("Message Out.\n"); + scsi_bus->bus_out |= BUS_REQ; + scsi_bus->state = STATE_MESSAGEOUT; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->target_id >> 5) | BUS_DBP; + break; + default: + break; + } + } + } + + if (scsi_bus->wait_complete) { + scsi_bus->wait_complete--; + if (!scsi_bus->wait_complete) + scsi_bus->bus_out |= BUS_REQ; + } + + return scsi_bus->bus_out; +} + +void +scsi_bus_update(scsi_bus_t *scsi_bus, int bus) +{ + scsi_device_t *dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + double p; + uint8_t sel_data; + int msglen; + + /*Start the SCSI command layer, which will also make the timings*/ + if (bus & BUS_ARB) + scsi_bus->state = STATE_IDLE; + + scsi_device_log("State = %i\n", scsi_bus->state); + + switch (scsi_bus->state) { + case STATE_IDLE: + scsi_bus->clear_req = scsi_bus->wait_data = scsi_bus->wait_complete = 0; + if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { + sel_data = BUS_GETDATA(bus); + + scsi_bus->target_id = scsi_device_get_id(sel_data); + + /*Once the device has been found and selected, mark it as busy*/ + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_bus->bus_out |= BUS_BSY; + scsi_bus->state = STATE_SELECT; + scsi_device_log("Select - target ID = %i, moving to state = %d.\n", scsi_bus->target_id, scsi_bus->state); + } else { + scsi_device_log("Device not found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_bus->bus_out = 0; + } + } + break; + case STATE_SELECT: + if (!(bus & BUS_SEL)) { + if (!(bus & BUS_ATN)) { + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_device_log("Device found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_bus->state = STATE_COMMAND; + scsi_bus->bus_out = BUS_BSY | BUS_REQ; + scsi_bus->command_pos = 0; + SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND); + } else { + scsi_device_log("Device not found at ID %i again.\n", scsi_bus->target_id); + scsi_bus->state = STATE_IDLE; + scsi_bus->bus_out = 0; + } + } else { + scsi_device_log("Set to SCSI Message Out\n"); + scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_OUT; + scsi_bus->wait_data = 4; + scsi_bus->msgout_pos = 0; + scsi_bus->is_msgout = 1; + } + } + break; + case STATE_COMMAND: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + /*Write command byte to the output data register*/ + scsi_bus->command[scsi_bus->command_pos++] = BUS_GETDATA(bus); + scsi_bus->clear_req = 3; + scsi_bus->bus_phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN; + scsi_bus->bus_out &= ~BUS_REQ; + + scsi_device_log("Command pos=%i, output data=%02x\n", scsi_bus->command_pos, BUS_GETDATA(bus)); + + if (scsi_bus->command_pos == scsi_command_length[(scsi_bus->command[0] >> 5) & 7]) { + if (scsi_bus->is_msgout) { + scsi_bus->is_msgout = 0; +#if 0 + scsi_bus->command[1] = (scsi_bus->command[1] & 0x1f) | (scsi_bus->msglun << 5); +#endif + } + + /*Reset data position to default*/ + scsi_bus->data_pos = 0; + + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + + scsi_device_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", scsi_bus->command[0], scsi_bus->target_id, dev->status); + dev->buffer_length = -1; + scsi_device_command_phase0(dev, scsi_bus->command); + scsi_device_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", scsi_bus->target_id, scsi_bus->command[0], dev->buffer_length, dev->phase); + + scsi_bus->period = 1.0; + scsi_bus->wait_data = 4; + scsi_bus->data_wait = 0; + scsi_bus->command_issued = 1; + + if (dev->status == SCSI_STATUS_OK) { + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) { + p = scsi_device_get_callback(dev); + scsi_bus->period = (p > 0.0) ? ((p / scsi_bus->divider) * scsi_bus->multi) : (((double) dev->buffer_length) * scsi_bus->speed); + scsi_device_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", scsi_bus->target_id, scsi_bus->command[0], scsi_device_get_callback(dev), scsi_bus->period, dev->buffer_length, scsi_bus->tx_mode); + } + } + scsi_bus->bus_phase = dev->phase; + } + } + break; + case STATE_DATAIN: + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + if (scsi_bus->data_pos >= dev->buffer_length) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_device_command_phase1(dev); + scsi_bus->bus_phase = SCSI_PHASE_STATUS; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + } else { + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++]; + + scsi_device_log("TXMode DataIn=%x, cmd=%02x.\n", scsi_bus->tx_mode, scsi_bus->command[0]); + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP | BUS_REQ; + if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not read 6/10 has been issued*/ + scsi_device_log("DMA mode idle IN=%d.\n", scsi_bus->data_pos); + scsi_bus->data_wait |= 1; + scsi_bus->timer(scsi_bus->priv, scsi_bus->period); + } else { + scsi_device_log("DMA mode IN=%d.\n", scsi_bus->data_pos); + scsi_bus->clear_req = 3; + } + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = SCSI_PHASE_DATA_IN; + } + } + break; + case STATE_DATAOUT: + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + dev->sc->temp_buffer[scsi_bus->data_pos++] = BUS_GETDATA(bus); + + if (scsi_bus->data_pos >= dev->buffer_length) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_device_command_phase1(dev); + scsi_bus->bus_phase = SCSI_PHASE_STATUS; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + } else { + /*More data is to be transferred, place a request*/ + if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not write 6/10 has been issued*/ + scsi_device_log("DMA mode idle OUT=%d.\n", scsi_bus->data_pos); + scsi_bus->data_wait |= 1; + scsi_bus->timer(scsi_bus->priv, scsi_bus->period); + scsi_bus->bus_out &= ~BUS_REQ; + } else { + scsi_device_log("DMA mode OUT=%d.\n", scsi_bus->data_pos); + scsi_bus->bus_out |= BUS_REQ; + } + } + } + break; + case STATE_STATUS: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + /*All transfers done, wait until next transfer*/ + scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], SCSI_LUN_USE_CDB); + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_IN; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + scsi_bus->command_issued = 0; + } + break; + case STATE_MESSAGEIN: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = BUS_IDLE; + scsi_bus->wait_data = 4; + } + break; + case STATE_MESSAGEOUT: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + scsi_bus->msgout[scsi_bus->msgout_pos++] = BUS_GETDATA(bus); + msglen = scsi_device_get_msg(scsi_bus->msgout, scsi_bus->msgout_pos); + if (scsi_bus->msgout_pos >= msglen) { + if ((scsi_bus->msgout[0] & (0x80 | 0x20)) == 0x80) + scsi_bus->msglun = scsi_bus->msgout[0] & 7; + + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->state = STATE_MESSAGE_ID; + } + } + break; + case STATE_MESSAGE_ID: + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_device_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], scsi_bus->msglun); + scsi_bus->state = STATE_COMMAND; + scsi_bus->bus_out = BUS_BSY | BUS_REQ; + scsi_bus->command_pos = 0; + SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND); + } + break; + + default: + break; + } + + scsi_bus->bus_in = bus; +} + diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index e5dff88f8..60f60473e 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -42,8 +42,6 @@ #include <86box/scsi_device.h> #include <86box/scsi_ncr5380.h> -int ncr5380_cmd_len[8] = { 6, 10, 10, 6, 16, 12, 10, 6 }; - #ifdef ENABLE_NCR5380_LOG int ncr5380_do_log = ENABLE_NCR5380_LOG; @@ -62,8 +60,6 @@ ncr5380_log(const char *fmt, ...) # define ncr5380_log(fmt, ...) #endif -#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) - void ncr5380_irq(ncr_t *ncr, int set_irq) { @@ -86,45 +82,15 @@ ncr5380_set_irq(ncr_t *ncr, int irq) ncr->irq = irq; } -static int -ncr5380_get_dev_id(uint8_t data) -{ - for (uint8_t c = 0; c < SCSI_ID_MAX; c++) { - if (data & (1 << c)) - return c; - } - - return -1; -} - -static int -ncr5380_getmsglen(uint8_t *msgp, int len) -{ - uint8_t msg = msgp[0]; - if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) || msg >= 0x80) - return 1; - if (msg >= 0x20 && msg <= 0x2f) - return 2; - if (len < 2) - return 3; - return msgp[1]; -} - static void ncr5380_reset(ncr_t *ncr) { - ncr->command_pos = 0; - ncr->data_pos = 0; - ncr->state = STATE_IDLE; - ncr->clear_req = 0; - ncr->cur_bus = 0; - ncr->tx_data = 0; + scsi_bus_t *scsi_bus = &ncr->scsibus; + ncr->output_data = 0; - ncr->data_wait = 0; ncr->mode = 0; ncr->tcr = 0; ncr->icr = 0; - ncr->dma_mode = DMA_IDLE; ncr5380_log("NCR Reset\n"); ncr->timer(ncr->priv, 0.0); @@ -132,6 +98,17 @@ ncr5380_reset(ncr_t *ncr) for (int i = 0; i < 8; i++) scsi_device_reset(&scsi_devices[ncr->bus][i]); + scsi_bus->state = STATE_IDLE; + scsi_bus->clear_req = 0; + scsi_bus->wait_complete = 0; + scsi_bus->wait_data = 0; + scsi_bus->bus_in = 0; + scsi_bus->bus_out = 0; + scsi_bus->command_pos = 0; + scsi_bus->data_wait = 0; + scsi_bus->data = 0; + scsi_bus->command_issued = 0; + ncr5380_irq(ncr, 0); } @@ -173,280 +150,10 @@ ncr5380_get_bus_host(ncr_t *ncr) return (bus_host | BUS_SETDATA(ncr->output_data)); } -void -ncr5380_bus_read(ncr_t *ncr) -{ - const scsi_device_t *dev; - int phase; - - /*Wait processes to handle bus requests*/ - if (ncr->clear_req) { - ncr->clear_req--; - if (!ncr->clear_req) { - ncr5380_log("Prelude to command data\n"); - SET_BUS_STATE(ncr, ncr->new_phase); - ncr->cur_bus |= BUS_REQ; - } - } - - if (ncr->wait_data) { - ncr->wait_data--; - if (!ncr->wait_data) { - dev = &scsi_devices[ncr->bus][ncr->target_id]; - SET_BUS_STATE(ncr, ncr->new_phase); - phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); - - if (phase == SCSI_PHASE_DATA_IN) { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext || (ncr->wait_data_back == 1)) { - ncr5380_log("Phase Data In.\n"); - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - - ncr->state = STATE_DATAIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; - } - } else if (phase == SCSI_PHASE_DATA_OUT) { - if (ncr->new_phase & BUS_IDLE) { - ncr->state = STATE_IDLE; - ncr->cur_bus &= ~BUS_BSY; - } else { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext || (ncr->wait_data_back == 1)) - ncr->state = STATE_DATAOUT; - } - } else if (phase == SCSI_PHASE_STATUS) { - ncr5380_log("Phase Status.\n"); - ncr->wait_data_back = 0; - ncr->cur_bus |= BUS_REQ; - ncr->state = STATE_STATUS; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; - } else if (phase == SCSI_PHASE_MESSAGE_IN) { - ncr5380_log("Phase Message In.\n"); - ncr->state = STATE_MESSAGEIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; - } else if (phase == SCSI_PHASE_MESSAGE_OUT) { - ncr->cur_bus |= BUS_REQ; - ncr->state = STATE_MESSAGEOUT; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->target_id >> 5) | BUS_DBP; - } - } - } - - if (ncr->wait_complete) { - ncr->wait_complete--; - if (!ncr->wait_complete) - ncr->cur_bus |= BUS_REQ; - } -} - -void -ncr5380_bus_update(ncr_t *ncr, int bus) -{ - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; - double p; - uint8_t sel_data; - int msglen; - - /*Start the SCSI command layer, which will also make the timings*/ - if (bus & BUS_ARB) - ncr->state = STATE_IDLE; - - ncr5380_log("State = %i\n", ncr->state); - - switch (ncr->state) { - case STATE_IDLE: - ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; - if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { - ncr5380_log("Selection phase\n"); - sel_data = BUS_GETDATA(bus); - - ncr->target_id = ncr5380_get_dev_id(sel_data); - - ncr5380_log("Select - target ID = %i\n", ncr->target_id); - - /*Once the device has been found and selected, mark it as busy*/ - if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr->cur_bus |= BUS_BSY; - ncr->state = STATE_SELECT; - } else { - ncr5380_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->cur_bus = 0; - } - } - break; - case STATE_SELECT: - if (!(bus & BUS_SEL)) { - if (!(bus & BUS_ATN)) { - if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr5380_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - } else { - ncr->state = STATE_IDLE; - ncr->cur_bus = 0; - } - } else { - ncr5380_log("Set to SCSI Message Out\n"); - ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; - ncr->wait_data = 4; - ncr->msgout_pos = 0; - ncr->is_msgout = 1; - } - } - break; - case STATE_COMMAND: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*Write command byte to the output data register*/ - ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); - ncr->clear_req = 3; - ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; - ncr->cur_bus &= ~BUS_REQ; - - ncr5380_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); - - if (ncr->command_pos == ncr5380_cmd_len[(ncr->command[0] >> 5) & 7]) { - if (ncr->is_msgout) { - ncr->is_msgout = 0; -#if 0 - ncr->command[1] = (ncr->command[1] & 0x1f) | (ncr->msglun << 5); -#endif - } - - /*Reset data position to default*/ - ncr->data_pos = 0; - - dev = &scsi_devices[ncr->bus][ncr->target_id]; - - ncr5380_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); - dev->buffer_length = -1; - scsi_device_command_phase0(dev, ncr->command); - ncr5380_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); - - ncr->period = 1.0; - ncr->wait_data = 4; - ncr->data_wait = 0; - - if (dev->status == SCSI_STATUS_OK) { - /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) { - p = scsi_device_get_callback(dev); - ncr->period = (p > 0.0) ? p : (((double) dev->buffer_length) * 0.2); - ncr5380_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", ncr->target_id, ncr->command[0], scsi_device_get_callback(dev), ncr->period, dev->buffer_length, ncr->dma_mode); - } - } - ncr->new_phase = dev->phase; - } - } - break; - case STATE_DATAIN: - dev = &scsi_devices[ncr->bus][ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if (ncr->data_pos >= dev->buffer_length) { - ncr->cur_bus &= ~BUS_REQ; - ncr5380_log("CMD Phase1 DataIn.\n"); - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/ - ncr->data_wait |= 1; - ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); - ncr->timer(ncr->priv, ncr->period); - } else { - ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); - ncr->clear_req = 3; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; - } - } - break; - case STATE_DATAOUT: - dev = &scsi_devices[ncr->bus][ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); - - if (ncr->data_pos >= dev->buffer_length) { - ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - /*More data is to be transferred, place a request*/ - if (ncr->dma_mode == DMA_IDLE) { /*If a data out command that is not write 6/10 has been issued*/ - ncr->data_wait |= 1; - ncr5380_log("DMA mode idle out\n"); - ncr->timer(ncr->priv, ncr->period); - } else - ncr->clear_req = 3; - - ncr->cur_bus &= ~BUS_REQ; - ncr5380_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); - } - } - break; - case STATE_STATUS: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*All transfers done, wait until next transfer*/ - scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], SCSI_LUN_USE_CDB); - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_MESSAGE_IN; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - break; - case STATE_MESSAGEIN: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = BUS_IDLE; - ncr->wait_data = 4; - } - break; - case STATE_MESSAGEOUT: - ncr5380_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); - msglen = ncr5380_getmsglen(ncr->msgout, ncr->msgout_pos); - if (ncr->msgout_pos >= msglen) { - if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) - ncr->msglun = ncr->msgout[0] & 7; - ncr->cur_bus &= ~BUS_REQ; - ncr->state = STATE_MESSAGE_ID; - } - } - break; - case STATE_MESSAGE_ID: - if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr5380_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], ncr->msglun); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - } - break; - - default: - break; - } - - ncr->bus_in = bus; -} - void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) { + scsi_bus_t *scsi_bus = &ncr->scsibus; int bus_host = 0; ncr5380_log("NCR5380 write(%04x,%02x)\n", port & 7, val); @@ -462,8 +169,10 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) if ((val & 0x80) && !(ncr->icr & 0x80)) { ncr5380_log("Resetting the 5380\n"); ncr5380_reset(ncr); + ncr5380_irq(ncr, 1); } ncr->icr = val; + ncr5380_log("ICR WaitData=%d, ClearReq=%d.\n", scsi_bus->wait_data, scsi_bus->clear_req); break; case 2: /* Mode register */ @@ -472,10 +181,8 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) ncr->icr &= ~ICR_ARB_LOST; ncr->icr |= ICR_ARB_IN_PROGRESS; } - ncr->mode = val; - - ncr->dma_mode_ext(ncr, ncr->priv); + ncr->dma_mode_ext(ncr, ncr->priv, val); break; case 3: /* Target Command Register */ @@ -488,17 +195,17 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 5: /* start DMA Send */ - ncr5380_log("Write: start DMA send register\n"); + pclog("Write: start DMA send register\n"); /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ - ncr->dma_mode = DMA_SEND; + scsi_bus->tx_mode = DMA_OUT_TX_BUS; if (ncr->dma_send_ext) ncr->dma_send_ext(ncr, ncr->priv); break; case 7: /* start DMA Initiator Receive */ - ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); + ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, waitdata=%d, clearreq=%d.\n", CS, cpu_state.pc, scsi_bus->wait_data, scsi_bus->clear_req); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ - ncr->dma_mode = DMA_INITIATOR_RECEIVE; + scsi_bus->tx_mode = DMA_IN_TX_BUS; if (ncr->dma_initiator_receive_ext) ncr->dma_initiator_receive_ext(ncr, ncr->priv); break; @@ -509,12 +216,13 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) } bus_host = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus_host); + scsi_bus_update(scsi_bus, bus_host); } uint8_t ncr5380_read(uint16_t port, ncr_t *ncr) { + scsi_bus_t *scsi_bus = &ncr->scsibus; uint8_t ret = 0xff; int bus; int bus_state; @@ -524,12 +232,17 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_log("Read: Current SCSI data register\n"); if (ncr->icr & ICR_DBP) { /*Return the data from the output register if on data bus phase from ICR*/ - ret = ncr->output_data; - ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data); + if (scsi_bus->command_issued) { + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); + } else + ret = ncr->output_data; + + ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x, txmode=%x.\n", CS, cpu_state.pc, ret, scsi_bus->clear_req, scsi_bus->wait_data, scsi_bus->tx_mode); } else { /*Return the data from the SCSI bus*/ - ncr5380_bus_read(ncr); - ret = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret); } break; @@ -552,15 +265,16 @@ ncr5380_read(uint16_t port, ncr_t *ncr) case 4: /* Current SCSI Bus status */ ncr5380_log("Read: SCSI bus status register\n"); ret = 0; - ncr5380_bus_read(ncr); - ncr5380_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); - ret |= (ncr->cur_bus & 0xff); + bus = scsi_bus_read(scsi_bus); + ret |= (bus & 0xff); if (ncr->icr & ICR_SEL) ret |= BUS_SEL; if (ncr->icr & ICR_BSY) ret |= BUS_BSY; - // if ((ret & SCSI_PHASE_MESSAGE_IN) == SCSI_PHASE_MESSAGE_IN) - // ret &= ~BUS_REQ; + + /*Note by TC1995: Horrible hack, I know.*/ + (void) scsi_bus_read(scsi_bus); + (void) scsi_bus_read(scsi_bus); break; case 5: /* Bus and Status register */ @@ -571,13 +285,12 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_log("Get host from Interrupt\n"); /*Check if the phase in process matches with TCR's*/ - if ((bus & SCSI_PHASE_MESSAGE_IN) == (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) { + if ((bus & SCSI_PHASE_MESSAGE_IN) == (scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN)) { ncr5380_log("Phase match\n"); ret |= STATUS_PHASE_MATCH; } - ncr5380_bus_read(ncr); - bus = ncr->cur_bus; + bus = scsi_bus_read(scsi_bus); if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK)) ret |= STATUS_ACK; @@ -610,8 +323,8 @@ ncr5380_read(uint16_t port, ncr_t *ncr) case 6: ncr5380_log("Read: Input Data.\n"); - ncr5380_bus_read(ncr); - ret = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); break; case 7: /* reset Parity/Interrupt */ diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index e028c7b42..a9d07af95 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -121,7 +121,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) { ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; addr &= 0x3fff; @@ -146,16 +147,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->busy = 1; - if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0))) - timer_on_auto(&ncr400->timer, ncr->period / 250.0); - else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { - if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 100.0); - else - timer_on_auto(&ncr400->timer, 40.0); - } } - } + } else + ncr53c400_log("No Write.\n"); break; case 0x3980: @@ -173,7 +167,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) break; case 0x3981: /* block counter register */ - ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, ncr->dma_mode, ncr->period); + ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, scsi_bus->tx_mode, scsi_bus->period); ncr400->block_count = val; ncr400->block_count_loaded = 1; @@ -186,17 +180,11 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) } if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); - if (ncr->mode & MODE_MONITOR_BUSY) - timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0); - else if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 40.0); - else - timer_on_auto(&ncr400->timer, ncr->period); - - ncr->wait_data_back = ncr->wait_data; - ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", - ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); - } + timer_on_auto(&ncr400->timer, scsi_bus->period); + ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n", + ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer)); + } else + ncr53c400_log("No Timer.\n"); break; default: @@ -216,7 +204,8 @@ ncr53c400_read(uint32_t addr, void *priv) { ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; uint8_t ret = 0xff; addr &= 0x3fff; @@ -240,7 +229,7 @@ ncr53c400_read(uint32_t addr, void *priv) break; case 0x3900: - if (ncr400->buffer_host_pos >= MIN(128, dev->buffer_length) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) { + if ((ncr400->buffer_host_pos >= MIN(128, dev->buffer_length)) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) { ret = 0xff; ncr53c400_log("No Read.\n"); } else { @@ -249,15 +238,6 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; - ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl); - if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0)) - timer_on_auto(&ncr400->timer, ncr->period / 250.0); - else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { - if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 100.0); - else - timer_on_auto(&ncr400->timer, 40.0); - } } } break; @@ -272,7 +252,7 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr->mode & 0x30) { /*Parity bits*/ if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ - ncr->mode = 0; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ + ncr->mode = 0x00; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ } } ncr53c400_log("NCR 53c400 status=%02x.\n", ret); @@ -411,46 +391,47 @@ t130b_in(uint16_t port, void *priv) } static void -ncr53c400_dma_mode_ext(void *priv, void *ext_priv) +ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv), uint8_t val) { - ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; + scsi_bus_t *scsi_bus = &ncr->scsibus; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded); - if (!ncr400->block_count_loaded) { - if (!(ncr->mode & MODE_DMA)) { - ncr53c400_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; - } + ncr53c400_log("NCR 53c400: BlockCountLoaded=%d, DMA mode enabled=%02x, valDMA=%02x.\n", ncr400->block_count_loaded, ncr->mode & MODE_DMA, val & MODE_DMA); + if (!(val & MODE_DMA) && (ncr->mode & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + scsi_bus->tx_mode = PIO_TX_BUS; } } static void ncr53c400_callback(void *priv) { - ncr53c400_t *ncr400 = (void *) priv; + ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; int bus; uint8_t c; uint8_t temp; + uint8_t status; - if (ncr->dma_mode != DMA_IDLE) + if (scsi_bus->tx_mode != PIO_TX_BUS) timer_on_auto(&ncr400->timer, 1.0); - if (ncr->data_wait & 1) { - ncr->clear_req = 3; - ncr->data_wait &= ~1; + if (scsi_bus->data_wait & 1) { + scsi_bus->clear_req = 3; + scsi_bus->data_wait &= ~1; } - if (ncr->dma_mode == DMA_IDLE) + if (scsi_bus->tx_mode == PIO_TX_BUS) { + ncr53c400_log("Timer CMD=%02x.\n", scsi_bus->command[0]); return; + } - switch (ncr->dma_mode) { - case DMA_SEND: + switch (scsi_bus->tx_mode) { + case DMA_OUT_TX_BUS: if (ncr400->status_ctrl & CTRL_DATA_DIR) { ncr53c400_log("DMA_SEND with DMA direction set wrong\n"); break; @@ -468,8 +449,8 @@ ncr53c400_callback(void *priv) while (1) { for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ @@ -478,8 +459,8 @@ ncr53c400_callback(void *priv) bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus |= BUS_SETDATA(temp); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); ncr400->buffer_pos++; ncr53c400_log("NCR 53c400 Buffer pos for writing = %d\n", ncr400->buffer_pos); @@ -492,7 +473,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count); if (!ncr400->block_count) { - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -507,7 +488,7 @@ ncr53c400_callback(void *priv) } break; - case DMA_INITIATOR_RECEIVE: + case DMA_IN_TX_BUS: if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) { ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); break; @@ -523,18 +504,18 @@ ncr53c400_callback(void *priv) while (1) { for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ - ncr5380_bus_read(ncr); - temp = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); bus = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); ncr400->buffer[ncr400->buffer_pos++] = temp; ncr53c400_log("NCR 53c400 Buffer pos for reading = %d\n", ncr400->buffer_pos); @@ -546,7 +527,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); if (!ncr400->block_count) { - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; @@ -564,13 +545,12 @@ ncr53c400_callback(void *priv) break; } - ncr53c400_log("Bus Read.\n"); - ncr5380_bus_read(ncr); + status = scsi_bus_read(scsi_bus); - if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { ncr53c400_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; } } @@ -643,6 +623,7 @@ ncr53c400_init(const device_t *info) const char *fn; ncr53c400_t *ncr400; ncr_t *ncr; + scsi_bus_t *scsi_bus; ncr400 = malloc(sizeof(ncr53c400_t)); memset(ncr400, 0x00, sizeof(ncr53c400_t)); @@ -651,6 +632,7 @@ ncr53c400_init(const device_t *info) ncr400->type = info->local; ncr->bus = scsi_get_bus(); + scsi_bus = &ncr->scsibus; switch (ncr400->type) { case ROM_LCS6821N: /* Longshine LCS6821N */ @@ -734,11 +716,17 @@ ncr53c400_init(const device_t *info) ncr->dma_send_ext = NULL; ncr->dma_initiator_receive_ext = NULL; ncr->timer = ncr53c400_timer_on_auto; + scsi_bus->bus_device = ncr->bus; + scsi_bus->timer = ncr->timer; + scsi_bus->priv = ncr->priv; ncr400->status_ctrl = STATUS_BUFFER_NOT_READY; ncr400->buffer_host_pos = 128; timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 0); scsi_bus_set_speed(ncr->bus, 5000000.0); + scsi_bus->speed = 0.2; + scsi_bus->divider = 2.0; + scsi_bus->multi = 1.750; return ncr400; } diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index c878bbb91..0d653469a 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -69,7 +69,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv) { t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; - const scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + const scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; addr &= 0x3fff; if ((addr >= 0x1800) && (addr < 0x1880)) @@ -84,7 +85,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv) ncr5380_write((addr - 0x1d00) >> 5, val, ncr); else if ((addr >= 0x1e00) && (addr < 0x2000)) { if ((t128->host_pos < MIN(512, dev->buffer_length)) && - (ncr->dma_mode == DMA_SEND)) { + (scsi_bus->tx_mode == DMA_OUT_TX_BUS)) { t128->buffer[t128->host_pos] = val; t128->host_pos++; @@ -106,7 +107,8 @@ t128_read(uint32_t addr, void *priv) { t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; uint8_t ret = 0xff; addr &= 0x3fff; @@ -124,7 +126,7 @@ t128_read(uint32_t addr, void *priv) ret = ncr5380_read((addr - 0x1d00) >> 5, ncr); else if (addr >= 0x1e00 && addr < 0x2000) { if ((t128->host_pos >= MIN(512, dev->buffer_length)) || - (ncr->dma_mode != DMA_INITIATOR_RECEIVE)) + (scsi_bus->tx_mode != DMA_IN_TX_BUS)) ret = 0xff; else { ret = t128->buffer[t128->host_pos++]; @@ -135,8 +137,8 @@ t128_read(uint32_t addr, void *priv) if (t128->host_pos == MIN(512, dev->buffer_length)) { t128->status &= ~0x04; t128_log("T128 Transfer busy read, status = %02x, period = %lf\n", - t128->status, ncr->period); - if ((ncr->period == 0.2) || (ncr->period == 0.02)) + t128->status, scsi_bus->period); + if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02)) timer_on_auto(&t128->timer, 40.2); } else if ((t128->host_pos < MIN(512, dev->buffer_length)) && (scsi_device_get_callback(dev) > 100.0)) @@ -148,15 +150,16 @@ t128_read(uint32_t addr, void *priv) } static void -t128_dma_mode_ext(void *priv, void *ext_priv) +t128_dma_mode_ext(void *priv, void *ext_priv, UNUSED(uint8_t val)) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; + scsi_bus_t *scsi_bus = &ncr->scsibus; /*Don't stop the timer until it finishes the transfer*/ if (t128->block_loaded && (ncr->mode & MODE_DMA)) { t128_log("Continuing DMA mode\n"); - timer_on_auto(&t128->timer, ncr->period + 1.0); + timer_on_auto(&t128->timer, scsi_bus->period + 1.0); } /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ @@ -164,7 +167,7 @@ t128_dma_mode_ext(void *priv, void *ext_priv) t128_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; } } @@ -173,7 +176,8 @@ t128_dma_send_ext(void *priv, void *ext_priv) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { memset(t128->buffer, 0, MIN(512, dev->buffer_length)); @@ -194,7 +198,8 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { memset(t128->buffer, 0, MIN(512, dev->buffer_length)); @@ -227,27 +232,29 @@ t128_callback(void *priv) { t128_t *t128 = (void *) priv; ncr_t *ncr = &t128->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; - int bus; - uint8_t c; - uint8_t temp; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; + int bus; + uint8_t c; + uint8_t temp; + uint8_t status; - if ((ncr->dma_mode != DMA_IDLE) && (ncr->mode & MODE_DMA) && t128->block_loaded) { + if ((scsi_bus->tx_mode != PIO_TX_BUS) && (ncr->mode & MODE_DMA) && t128->block_loaded) { if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count) t128->status |= 0x04; - timer_on_auto(&t128->timer, ncr->period / 55.0); + timer_on_auto(&t128->timer, scsi_bus->period / 55.0); } - if (ncr->data_wait & 1) { - ncr->clear_req = 3; - ncr->data_wait &= ~1; - if (ncr->dma_mode == DMA_IDLE) + if (scsi_bus->data_wait & 1) { + scsi_bus->clear_req = 3; + scsi_bus->data_wait &= ~1; + if (scsi_bus->tx_mode == PIO_TX_BUS) return; } - switch (ncr->dma_mode) { - case DMA_SEND: + switch (scsi_bus->tx_mode) { + case DMA_OUT_TX_BUS: if (!(t128->status & 0x04)) { t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); break; @@ -263,8 +270,8 @@ t128_callback(void *priv) write_again: for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } @@ -274,8 +281,8 @@ write_again: bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus |= BUS_SETDATA(temp); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); t128->pos++; t128_log("T128 Buffer pos for writing = %d\n", t128->pos); @@ -302,7 +309,7 @@ write_again: goto write_again; break; - case DMA_INITIATOR_RECEIVE: + case DMA_IN_TX_BUS: if (!(t128->status & 0x04)) { t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); break; @@ -318,19 +325,19 @@ write_again: read_again: for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ - ncr5380_bus_read(ncr); - temp = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); bus = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); t128->buffer[t128->pos++] = temp; t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length); @@ -360,12 +367,12 @@ read_again: break; } - ncr5380_bus_read(ncr); + status = scsi_bus_read(scsi_bus); - if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { t128_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; timer_on_auto(&t128->timer, 10.0); } } @@ -467,12 +474,14 @@ t128_init(const device_t *info) { t128_t *t128; ncr_t *ncr; + scsi_bus_t *scsi_bus; t128 = malloc(sizeof(t128_t)); memset(t128, 0x00, sizeof(t128_t)); ncr = &t128->ncr; ncr->bus = scsi_get_bus(); + scsi_bus = &ncr->scsibus; if (info->flags & DEVICE_MCA) { rom_init(&t128->bios_rom, T128_ROM, @@ -504,6 +513,9 @@ t128_init(const device_t *info) ncr->dma_send_ext = t128_dma_send_ext; ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext; ncr->timer = t128_timer_on_auto; + scsi_bus->bus_device = ncr->bus; + scsi_bus->timer = ncr->timer; + scsi_bus->priv = ncr->priv; t128->status = 0x00 /*0x04*/; t128->host_pos = 512; if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) @@ -516,6 +528,9 @@ t128_init(const device_t *info) timer_add(&t128->timer, t128_callback, t128, 0); scsi_bus_set_speed(ncr->bus, 5000000.0); + scsi_bus->speed = 0.2; + scsi_bus->divider = 1.0; + scsi_bus->multi = 1.0; return t128; } diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index ed82afebf..110ee95c9 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -86,7 +86,7 @@ * Copyright 2008-2024 Sarah Walker. * Copyright 2024 Miran Grca. */ -#define _USE_MATH_DEFINES +#define _USE_MATH_DEFINES #include #include #include @@ -706,6 +706,7 @@ static uint8_t pas16_in(uint16_t port, void *priv) { pas16_t *pas16 = (pas16_t *) priv; + scsi_bus_t *scsi_bus = NULL; uint8_t ret = 0xff; port -= pas16->base; @@ -784,9 +785,11 @@ pas16_in(uint16_t port, void *priv) ret = t128_read(0x1e00, pas16->scsi); break; case 0x5c01: - if (pas16->has_scsi) + if (pas16->has_scsi) { + scsi_bus = &pas16->scsi->ncr.scsibus; /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ - ret = (((pas16->scsi->ncr.dma_mode != DMA_IDLE) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + } break; case 0x5c03: if (pas16->has_scsi) @@ -1183,10 +1186,11 @@ pas16_scsi_callback(void *priv) { pas16_t * pas16 = (pas16_t *) priv; t128_t * dev = pas16->scsi; + scsi_bus_t * scsi_bus = &dev->ncr.scsibus; t128_callback(pas16->scsi); - if ((dev->ncr.dma_mode != DMA_IDLE) && (dev->status & 0x04)) { + if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) { timer_stop(&pas16->scsi_timer); pas16->timeout_status &= 0x7f; } From 714eadfc3a0b3325060cef21f14faa9b90929ec4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 23 Jan 2025 10:31:31 +0100 Subject: [PATCH 0150/1190] NVR: Get/set time functions now take a void pointer, so nvr.h can be included without requiring time.h. --- src/include/86box/nvr.h | 4 ++-- src/nvr.c | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 85e0954f0..c6dc08a12 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -114,8 +114,8 @@ extern int nvr_save(void); extern int nvr_is_leap(int year); extern int nvr_get_days(int month, int year); extern void nvr_time_sync(void); -extern void nvr_time_get(struct tm *); -extern void nvr_time_set(struct tm *); +extern void nvr_time_get(void *priv); +extern void nvr_time_set(void *priv); extern void nvr_reg_write(uint16_t reg, uint8_t val, void *priv); extern void nvr_at_handler(int set, uint16_t base, nvr_t *nvr); diff --git a/src/nvr.c b/src/nvr.c index d833618d0..d0b05b93a 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -326,14 +326,15 @@ nvr_time_sync(void) /* Get current time from internal clock. */ void -nvr_time_get(struct tm *tm) +nvr_time_get(void *priv) { - uint8_t dom; - uint8_t mon; - uint8_t sum; - uint8_t wd; - uint16_t cent; - uint16_t yr; + struct tm *tm = (struct tm *) priv; + uint8_t dom; + uint8_t mon; + uint8_t sum; + uint8_t wd; + uint16_t cent; + uint16_t yr; tm->tm_sec = intclk.tm_sec; tm->tm_min = intclk.tm_min; @@ -352,8 +353,10 @@ nvr_time_get(struct tm *tm) /* Set internal clock time. */ void -nvr_time_set(struct tm *tm) +nvr_time_set(void *priv) { + struct tm *tm = (struct tm *) priv; + intclk.tm_sec = tm->tm_sec; intclk.tm_min = tm->tm_min; intclk.tm_hour = tm->tm_hour; From fbd1a16eeb39e5f0385322b8c66aedfc19069d2d Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Sat, 25 Jan 2025 00:22:59 +0300 Subject: [PATCH 0151/1190] Add the AT&T Globalyst 330 (Pentium/Socket 4) --- src/include/86box/machine.h | 1 + src/machine/m_at_socket4.c | 31 ++++++++++++++++++++++++++++ src/machine/machine_table.c | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 0cd3564ee..b0365314e 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -637,6 +637,7 @@ extern int machine_at_m5pi_init(const machine_t *); extern int machine_at_excalibur_init(const machine_t *); +extern int machine_at_globalyst330_p5_init(const machine_t *); extern int machine_at_p5vl_init(const machine_t *); extern int machine_at_excaliburpci2_init(const machine_t *); diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index c3213f1ac..78df5b0cb 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -384,6 +384,37 @@ machine_at_m5pi_init(const machine_t *model) return ret; } +int +machine_at_globalyst330_p5_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/globalyst330_p5/MiTAC_PB5500C_v1.02_120794_ATT.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x10, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 5, 6, 7, 8); + pci_register_slot(0x13, PCI_CARD_NORMAL, 9, 10, 11, 12); + pci_register_slot(0x14, PCI_CARD_NORMAL, 13, 14, 15, 16); + + device_add(&opti5x7_pci_device); + device_add(&opti822_device); + device_add(&sst_flash_29ee010_device); + device_add(&keyboard_at_ami_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + int machine_at_excalibur_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f2fb53a6f..2a50159e9 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -9582,6 +9582,46 @@ const machine_t machines[] = { }, /* OPTi 596/597/822 */ + /* Has a VIA VT82C42N KBC with AMI 'F' firmware */ + { + .name = "[OPTi 597] AT&T Globalyst 330 (Pentium)", + .internal_name = "globalyst330_p5", + .type = MACHINE_TYPE_SOCKET4, + .chipset = MACHINE_CHIPSET_OPTI_547_597, + .init = machine_at_globalyst330_p5_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET4, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 5000, + .max_voltage = 5000, + .min_multi = MACHINE_MULTIPLIER_FIXED, + .max_multi = MACHINE_MULTIPLIER_FIXED + }, + .bus_flags = MACHINE_PCIV, + .flags = MACHINE_APM, + .ram = { + .min = 8192, + .max = 65536, + .step = 8192 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* This has AMIKey 'F' KBC firmware. */ { .name = "[OPTi 597] Supermicro P5VL-PCI", From e61f3c8a5d4b3b70de7c1f684f871d39e3fb1513 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 26 Jan 2025 14:25:35 +0100 Subject: [PATCH 0152/1190] Video changes of the day (January 26th, 2025) XGA: 1. Added a proper poll so to have its timings independent of the SVGA core and changes its renderer accordingly, mainly a blank render one. 2. Workaround the Ctrl-Alt-Del reset of Windows 2.x so that it switches back to VGA text mode correctly when using the 0xA000 64K aperture (in vid_svga.c). SVGA core: Re-organized the way the different timers are organized so that the XGA and 8514/A pollers can coexist with the SVGA timer without conflicts. ATI Mach32: Reworked the true color renderer and made it a Mach32 exclusive due to its differences from the standard one. Fixes wrong rendered colors in NT using the 32bpp renderer in RGB mode. --- src/include/86box/vid_svga.h | 12 +- src/include/86box/vid_xga.h | 2 - src/video/vid_8514a.c | 12 +- src/video/vid_ati_mach8.c | 102 ++++++++++- src/video/vid_svga.c | 204 +++++++++++++++++---- src/video/vid_xga.c | 340 +++++++++++++++++++---------------- 6 files changed, 466 insertions(+), 206 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 2b26df2f3..3be4ee9e5 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -189,6 +189,7 @@ typedef struct svga_t { void (*render)(struct svga_t *svga); void (*render8514)(struct svga_t *svga); + void (*render_xga)(struct svga_t *svga); void (*recalctimings_ex)(struct svga_t *svga); void (*video_out)(uint16_t addr, uint8_t val, void *priv); @@ -306,6 +307,7 @@ typedef struct svga_t { void * xga; } svga_t; +extern void ibm8514_set_poll(svga_t *svga); extern void ibm8514_poll(void *priv); extern void ibm8514_recalctimings(svga_t *svga); extern uint8_t ibm8514_ramdac_in(uint16_t port, void *priv); @@ -328,10 +330,11 @@ extern void ati8514_mca_write(int port, uint8_t val, void *priv); extern void ati8514_pos_write(uint16_t port, uint8_t val, void *priv); extern void ati8514_init(svga_t *svga, void *ext8514, void *dev8514); -extern void xga_write_test(uint32_t addr, uint8_t val, void *priv); -extern uint8_t xga_read_test(uint32_t addr, void *priv); -extern void xga_poll(void *priv); -extern void xga_recalctimings(svga_t *svga); +extern void xga_write_test(uint32_t addr, uint8_t val, void *priv); +extern uint8_t xga_read_test(uint32_t addr, void *priv); +extern void xga_set_poll(svga_t *svga); +extern void xga_poll(void *priv); +extern void xga_recalctimings(svga_t *svga); extern uint32_t svga_decode_addr(svga_t *svga, uint32_t addr, int write); @@ -376,6 +379,7 @@ uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); void svga_doblit(int wx, int wy, svga_t *svga); +void svga_set_poll(svga_t *svga); void svga_poll(void *priv); enum { diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h index b90b53978..b2001dba9 100644 --- a/src/include/86box/vid_xga.h +++ b/src/include/86box/vid_xga.h @@ -240,8 +240,6 @@ typedef struct xga_t { uint16_t px_map_height[4]; uint32_t px_map_base[4]; } accel; - - int big_endian_linear; } xga_t; #endif /*VIDEO_XGA_H*/ diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 0e51feae4..d2e7efd8b 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -301,7 +301,7 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in if ((cmd >= 2) && (dev->accel.cmd & 0x1000)) val = (val >> 8) | (val << 8); } - if ((cmd <= 2) || (cmd == 4) || ((cmd == 6))) { + if ((cmd <= 2) || (cmd == 4) || (cmd == 6)) { if ((dev->accel.cmd & 0x08) && (cmd >= 2)) monoxfer = val; else { @@ -3605,6 +3605,12 @@ ibm8514_render_overscan_right(ibm8514_t *dev, svga_t *svga) buffer32->line[dev->displine + svga->y_add][svga->x_add + dev->h_disp + i] = svga->overscan_color; } +void +ibm8514_set_poll(svga_t *svga) +{ + timer_set_callback(&svga->timer, ibm8514_poll); +} + void ibm8514_poll(void *priv) { @@ -3614,7 +3620,7 @@ ibm8514_poll(void *priv) int wx; int wy; - ibm8514_log("IBM 8514/A poll.\n"); + ibm8514_log("IBM 8514/A poll=%x.\n", dev->on); if (dev->on) { ibm8514_log("ON!\n"); if (!dev->linepos) { @@ -3857,7 +3863,7 @@ ibm8514_mca_reset(void *priv) else ibm8514_mca_write(0x102, 0, svga); - timer_set_callback(&svga->timer, svga_poll); + svga_set_poll(svga); } static void * diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index d294f61e9..812885559 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2503,6 +2503,96 @@ ati8514_in(uint16_t addr, void *priv) return temp; } +static void +ati_render_24bpp(svga_t *svga) +{ + mach_t *mach = (mach_t *) svga->priv; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + uint32_t *p; + uint32_t dat; + + if ((dev->displine + svga->y_add) < 0) + return; + + if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; + + if (dev->firstline_draw == 2000) + dev->firstline_draw = dev->displine; + dev->lastline_draw = dev->displine; + + if (mach->accel.ext_ge_config & 0x400) { /*BGR, Blue-(23:16), Green-(15:8), Red-(7:0)*/ + for (int x = 0; x <= dev->h_disp; x += 4) { + dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + p[x + 1] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + p[x + 2] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + p[x + 3] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + + dev->ma += 12; + } + } else { /*RGB, Red-(23:16), Green-(15:8), Blue-(7:0)*/ + for (int x = 0; x <= dev->h_disp; x += 4) { + dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + p[x] = dat & 0xffffff; + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + p[x + 1] = dat & 0xffffff; + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + p[x + 2] = dat & 0xffffff; + + dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + p[x + 3] = dat & 0xffffff; + + dev->ma += 12; + } + } + dev->ma &= dev->vram_mask; + } +} + +static void +ati_render_32bpp(svga_t *svga) +{ + mach_t *mach = (mach_t *) svga->priv; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + int x; + uint32_t *p; + uint32_t dat; + + if ((dev->displine + svga->y_add) < 0) + return; + + if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || dev->changedvram[(dev->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; + + if (dev->firstline_draw == 2000) + dev->firstline_draw = dev->displine; + dev->lastline_draw = dev->displine; + + if (mach->accel.ext_ge_config & 0x400) { /*BGR, Blue-(23:16), Green-(15:8), Red-(7:0)*/ + for (x = 0; x <= dev->h_disp; x++) { + dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + *p++ = ((dat & 0x00ff0000) >> 16) | (dat & 0x0000ff00) | ((dat & 0x000000ff) << 16); + } + } else { /*RGB, Red-(31:24), Green-(23:16), Blue-(15:8)*/ + for (x = 0; x <= dev->h_disp; x++) { + dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + *p++ = ((dat & 0xffffff00) >> 8); + } + } + dev->ma += (x * 4); + dev->ma &= dev->vram_mask; + } +} + void ati8514_recalctimings(svga_t *svga) { @@ -2711,17 +2801,11 @@ mach_recalctimings(svga_t *svga) break; case 24: mach_log("GEConfig24bpp: %03x.\n", mach->accel.ext_ge_config & 0x600); - if (mach->accel.ext_ge_config & 0x400) - svga->render8514 = ibm8514_render_BGR; - else - svga->render8514 = ibm8514_render_24bpp; + svga->render8514 = ati_render_24bpp; break; case 32: mach_log("GEConfig32bpp: %03x.\n", mach->accel.ext_ge_config & 0x600); - if (mach->accel.ext_ge_config & 0x400) - svga->render8514 = ibm8514_render_ABGR8888; - else - svga->render8514 = ibm8514_render_32bpp; + svga->render8514 = ati_render_32bpp; break; default: @@ -5776,7 +5860,7 @@ mach_mca_reset(void *priv) mach_log("MCA reset.\n"); dev->on = 0; mach_mca_write(0x102, 0, mach); - timer_set_callback(&svga->timer, svga_poll); + svga_set_poll(svga); } uint8_t diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index e6201e4bf..4db2737ca 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -83,26 +83,76 @@ svga_get_pri(void) return svga_pri; } +void +svga_set_poll(svga_t *svga) +{ + svga_log("SVGA Timer activated, enabled?=%x.\n", timer_is_enabled(&svga->timer)); + timer_set_callback(&svga->timer, svga_poll); + if (!timer_is_enabled(&svga->timer)) + timer_enable(&svga->timer); +} + void svga_set_override(svga_t *svga, int val) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + xga_t *xga = (xga_t *) svga->xga; + uint8_t ret_poll = 0; if (svga->override && !val) svga->fullchange = svga->monitor->mon_changeframecount; + svga->override = val; svga_log("Override=%x.\n", val); - if (ibm8514_active && (svga->dev8514 != NULL)) { - if (dev->on) { - if (svga->override) - timer_set_callback(&svga->timer, svga_poll); - else - timer_set_callback(&svga->timer, ibm8514_poll); - } else - timer_set_callback(&svga->timer, svga_poll); - } else - timer_set_callback(&svga->timer, svga_poll); + if (ibm8514_active && (svga->dev8514 != NULL)) + ret_poll |= 1; + + if (xga_active && (svga->xga != NULL)) + ret_poll |= 2; + + if (svga->override) + svga_set_poll(svga); + else { + switch (ret_poll) { + case 0: + default: + svga_set_poll(svga); + break; + + case 1: + if (ibm8514_active && (svga->dev8514 != NULL)) { + if (dev->on) + ibm8514_set_poll(svga); + else + svga_set_poll(svga); + } else + svga_set_poll(svga); + break; + + case 2: + if (xga_active && (svga->xga != NULL)) { + if (xga->on) + xga_set_poll(svga); + else + svga_set_poll(svga); + } else + svga_set_poll(svga); + break; + + case 3: + if (ibm8514_active && (svga->dev8514 != NULL) && xga_active && (svga->xga != NULL)) { + if (dev->on) + ibm8514_set_poll(svga); + else if (xga->on) + xga_set_poll(svga); + else + svga_set_poll(svga); + } else + svga_set_poll(svga); + break; + } + } #ifdef OVERRIDE_OVERSCAN if (!val) { @@ -241,7 +291,7 @@ svga_out(uint16_t addr, uint8_t val, void *priv) if (ibm8514_active && dev) dev->on = (val & 0x01) ? 0 : 1; - svga_log("Write Port 3C3.\n"); + svga_log("Write Port 3C3=%x.\n", val & 0x01); svga_recalctimings(svga); break; case 0x3c4: @@ -612,6 +662,8 @@ void svga_recalctimings(svga_t *svga) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + xga_t *xga = (xga_t *) svga->xga; + uint8_t set_timer = 0; double crtcconst; double _dispontime; double _dispofftime; @@ -620,6 +672,10 @@ svga_recalctimings(svga_t *svga) double _dispontime8514 = 0.0; double _dispofftime8514 = 0.0; double disptime8514 = 0.0; + double crtcconst_xga = 0.0; + double _dispontime_xga = 0.0; + double _dispofftime_xga = 0.0; + double disptime_xga = 0.0; #ifdef ENABLE_SVGA_LOG int vsyncend; int vblankend; @@ -709,6 +765,12 @@ svga_recalctimings(svga_t *svga) } else svga->render = svga_render_text_80; + if (xga_active && (svga->xga != NULL)) { + if (xga->on) { + if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl == 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ + xga->on = 0; + } + } svga->hdisp_old = svga->hdisp; } else { svga->hdisp_old = svga->hdisp; @@ -904,6 +966,10 @@ svga_recalctimings(svga_t *svga) if (dev->on) crtcconst8514 = svga->clock8514; } + if (xga_active && (svga->xga != NULL)) { + if (xga->on) + crtcconst_xga = svga->clock_xga; + } #ifdef ENABLE_SVGA_LOG vsyncend = (svga->vsyncstart & 0xfffffff0) | (svga->crtc[0x11] & 0x0f); @@ -952,6 +1018,13 @@ svga_recalctimings(svga_t *svga) } } + if (xga_active && (svga->xga != NULL)) { + if (xga->on) { + disptime_xga = xga->h_total ? xga->h_total : TIMER_USEC; + _dispontime_xga = xga->h_disp; + } + } + if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; @@ -968,25 +1041,84 @@ svga_recalctimings(svga_t *svga) if (svga->dispofftime < TIMER_USEC) svga->dispofftime = TIMER_USEC; - if (ibm8514_active && (svga->dev8514 != NULL)) { - if (dev->on) { - _dispofftime8514 = disptime8514 - _dispontime8514; - _dispontime8514 *= crtcconst8514; - _dispofftime8514 *= crtcconst8514; + if (ibm8514_active && (svga->dev8514 != NULL)) + set_timer |= 1; - dev->dispontime = (uint64_t) (_dispontime8514); - dev->dispofftime = (uint64_t) (_dispofftime8514); - if (dev->dispontime < TIMER_USEC) - dev->dispontime = TIMER_USEC; - if (dev->dispofftime < TIMER_USEC) - dev->dispofftime = TIMER_USEC; + if (xga_active && (svga->xga != NULL)) + set_timer |= 2; - svga_log("IBM 8514/A poll.\n"); - timer_set_callback(&svga->timer, ibm8514_poll); - } else { - svga_log("SVGA poll enabled.\n"); - timer_set_callback(&svga->timer, svga_poll); - } + switch (set_timer) { + default: + case 0: /*VGA only*/ + svga_set_poll(svga); + break; + + case 1: /*Plus 8514/A*/ + if (dev->on) { + _dispofftime8514 = disptime8514 - _dispontime8514; + _dispontime8514 *= crtcconst8514; + _dispofftime8514 *= crtcconst8514; + + dev->dispontime = (uint64_t) (_dispontime8514); + dev->dispofftime = (uint64_t) (_dispofftime8514); + if (dev->dispontime < TIMER_USEC) + dev->dispontime = TIMER_USEC; + if (dev->dispofftime < TIMER_USEC) + dev->dispofftime = TIMER_USEC; + + ibm8514_set_poll(svga); + } else + svga_set_poll(svga); + break; + + case 2: /*Plus XGA*/ + if (xga->on) { + _dispofftime_xga = disptime_xga - _dispontime_xga; + _dispontime_xga *= crtcconst_xga; + _dispofftime_xga *= crtcconst_xga; + + xga->dispontime = (uint64_t) (_dispontime_xga); + xga->dispofftime = (uint64_t) (_dispofftime_xga); + if (xga->dispontime < TIMER_USEC) + xga->dispontime = TIMER_USEC; + if (xga->dispofftime < TIMER_USEC) + xga->dispofftime = TIMER_USEC; + + xga_set_poll(svga); + } else + svga_set_poll(svga); + break; + + case 3: /*Plus 8514/A and XGA*/ + if (dev->on) { + _dispofftime8514 = disptime8514 - _dispontime8514; + _dispontime8514 *= crtcconst8514; + _dispofftime8514 *= crtcconst8514; + + dev->dispontime = (uint64_t) (_dispontime8514); + dev->dispofftime = (uint64_t) (_dispofftime8514); + if (dev->dispontime < TIMER_USEC) + dev->dispontime = TIMER_USEC; + if (dev->dispofftime < TIMER_USEC) + dev->dispofftime = TIMER_USEC; + + ibm8514_set_poll(svga); + } else if (xga->on) { + _dispofftime_xga = disptime_xga - _dispontime_xga; + _dispontime_xga *= crtcconst_xga; + _dispofftime_xga *= crtcconst_xga; + + xga->dispontime = (uint64_t) (_dispontime_xga); + xga->dispofftime = (uint64_t) (_dispofftime_xga); + if (xga->dispontime < TIMER_USEC) + xga->dispontime = TIMER_USEC; + if (xga->dispofftime < TIMER_USEC) + xga->dispofftime = TIMER_USEC; + + xga_set_poll(svga); + } else + svga_set_poll(svga); + break; } if (!svga->force_old_addr) @@ -1064,7 +1196,6 @@ void svga_poll(void *priv) { svga_t *svga = (svga_t *) priv; - xga_t *xga = (xga_t *) svga->xga; uint32_t x; uint32_t blink_delay; int wx; @@ -1072,15 +1203,6 @@ svga_poll(void *priv) int ret; int old_ma; - if (!svga->override) { - if (xga_active && xga && xga->on) { - if ((xga->disp_cntl_2 & 7) >= 2) { - xga_poll(svga); - return; - } - } - } - svga_log("SVGA Poll.\n"); if (!svga->linepos) { if (svga->displine == ((svga->hwcursor_latch.y < 0) ? 0 : svga->hwcursor_latch.y) && svga->hwcursor_latch.ena) { @@ -2070,6 +2192,8 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *priv) cycles -= svga->monitor->mon_video_timing_read_w; if (!linear) { + (void) xga_read_test(addr, svga); + (void) xga_read_test(addr + 1, svga); addr = svga_decode_addr(svga, addr, 0); if (addr == 0xffffffff) return 0xffff; @@ -2116,6 +2240,10 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *priv) cycles -= svga->monitor->mon_video_timing_read_l; if (!linear) { + (void) xga_read_test(addr, svga); + (void) xga_read_test(addr + 1, svga); + (void) xga_read_test(addr + 2, svga); + (void) xga_read_test(addr + 3, svga); addr = svga_decode_addr(svga, addr, 0); if (addr == 0xffffffff) return 0xffffffff; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 852ff6273..8bdc72fc6 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -243,6 +243,26 @@ xga_updatemapping(svga_t *svga) } } +static void +xga_render_blank(svga_t *svga) +{ + xga_t *xga = (xga_t *) svga->xga; + + if ((xga->displine + svga->y_add) < 0) + return; + + if (xga->firstline_draw == 2000) + xga->firstline_draw = xga->displine; + + xga->lastline_draw = xga->displine; + + uint32_t *line_ptr = &svga->monitor->target_buffer->line[xga->displine + svga->y_add][svga->x_add]; + uint32_t line_width = (uint32_t)(xga->h_disp) * sizeof(uint32_t); + + if (xga->h_disp > 0) + memset(line_ptr, 0, line_width); +} + void xga_recalctimings(svga_t *svga) { @@ -272,26 +292,43 @@ xga_recalctimings(svga_t *svga) xga->ma_latch = xga->disp_start_addr; + xga_log("XGA ClkSel1 = %d, ClkSel2 = %02x, dispcntl2=%02x.\n", (xga->clk_sel_1 >> 2) & 3, xga->clk_sel_2 & 0x80, xga->disp_cntl_2 & 0xc0); switch ((xga->clk_sel_1 >> 2) & 3) { case 0: xga_log("HDISP VGA0 = %d, XGA = %d.\n", svga->hdisp, xga->h_disp); if (xga->clk_sel_2 & 0x80) - svga->clock = (cpuclock * (double) (1ULL << 32)) / 41539000.0; + svga->clock_xga = (cpuclock * (double) (1ULL << 32)) / 41539000.0; else - svga->clock = (cpuclock * (double) (1ULL << 32)) / 25175000.0; + svga->clock_xga = (cpuclock * (double) (1ULL << 32)) / 25175000.0; break; case 1: xga_log("HDISP VGA1 = %d, XGA = %d.\n", svga->hdisp, xga->h_disp); - svga->clock = (cpuclock * (double) (1ULL << 32)) / 28322000.0; + svga->clock_xga = (cpuclock * (double) (1ULL << 32)) / 28322000.0; break; case 3: - svga->clock = (cpuclock * (double) (1ULL << 32)) / 44900000.0; + svga->clock_xga = (cpuclock * (double) (1ULL << 32)) / 44900000.0; break; default: break; } + + switch (xga->disp_cntl_2 & 7) { + case 2: + svga->render_xga = xga_render_4bpp; + break; + case 3: + svga->render_xga = xga_render_8bpp; + break; + case 4: + svga->render_xga = xga_render_16bpp; + break; + + default: + svga->render_xga = xga_render_blank; + break; + } } } @@ -2717,8 +2754,10 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga->vram[addr & xga->vram_mask] = val; xga_log("XGA Linear endian reverse write, val = %02x, addr = %05x, banked mask = %04x, a5test=%d.\n", val, addr, svga->banked_mask, xga->a5_test); } - } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) { xga->on = 0; + xga_log("OFF XGA write.\n"); + } } } @@ -2824,8 +2863,10 @@ xga_read_test(uint32_t addr, void *priv) addr += xga->read_bank; return xga->vram[addr & xga->vram_mask]; } - } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) { xga->on = 0; + xga_log("OFF XGA read.\n"); + } } return ret; } @@ -3029,6 +3070,12 @@ xga_readl_linear(uint32_t addr, void *priv) return ret; } +void +xga_set_poll(svga_t *svga) +{ + timer_set_callback(&svga->timer, xga_poll); +} + void xga_poll(void *priv) { @@ -3038,166 +3085,158 @@ xga_poll(void *priv) int wx; int wy; - if (!xga->linepos) { - if (xga->displine == xga->hwcursor_latch.y && xga->hwcursor_latch.ena) { - xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - ((xga->hwcursor_latch.yoff & 0x20) ? 32 : 0); - xga->hwcursor_oddeven = 0; - } - - if (xga->displine == (xga->hwcursor_latch.y + 1) && xga->hwcursor_latch.ena && xga->interlace) { - xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - ((xga->hwcursor_latch.yoff & 0x20) ? 33 : 1); - xga->hwcursor_oddeven = 1; - } - - timer_advance_u64(&svga->timer, svga->dispofftime); - svga->cgastat |= 1; - xga->linepos = 1; - - if (xga->dispon) { - xga->h_disp_on = 1; - - xga->ma &= xga->vram_mask; - - if (xga->firstline == 2000) { - xga->firstline = xga->displine; - video_wait_for_buffer_monitor(svga->monitor_index); + xga_log("XGA Poll=%d.\n", xga->on); + if (xga->on) { + if (!xga->linepos) { + if (xga->displine == xga->hwcursor_latch.y && xga->hwcursor_latch.ena) { + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - ((xga->hwcursor_latch.yoff & 0x20) ? 32 : 0); + xga->hwcursor_oddeven = 0; } - if (xga->hwcursor_on) - xga->changedvram[xga->ma >> 12] = xga->changedvram[(xga->ma >> 12) + 1] = xga->interlace ? 3 : 2; - - switch (xga->disp_cntl_2 & 7) { - case 2: - xga_render_4bpp(svga); - break; - case 3: - xga_render_8bpp(svga); - break; - case 4: - xga_render_16bpp(svga); - break; - default: - break; + if (xga->displine == (xga->hwcursor_latch.y + 1) && xga->hwcursor_latch.ena && xga->interlace) { + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - ((xga->hwcursor_latch.yoff & 0x20) ? 33 : 1); + xga->hwcursor_oddeven = 1; } - svga->x_add = (overscan_x >> 1); - xga_render_overscan_left(xga, svga); - xga_render_overscan_right(xga, svga); - svga->x_add = (overscan_x >> 1); + timer_advance_u64(&svga->timer, xga->dispofftime); + svga->cgastat |= 1; + xga->linepos = 1; - if (xga->hwcursor_on) { - xga_hwcursor_draw(svga, xga->displine + svga->y_add); - xga->hwcursor_on--; - if (xga->hwcursor_on && xga->interlace) + if (xga->dispon) { + xga->h_disp_on = 1; + + xga->ma &= xga->vram_mask; + + if (xga->firstline == 2000) { + xga->firstline = xga->displine; + video_wait_for_buffer_monitor(svga->monitor_index); + } + + if (xga->hwcursor_on) + xga->changedvram[xga->ma >> 12] = xga->changedvram[(xga->ma >> 12) + 1] = xga->interlace ? 3 : 2; + + svga->render_xga(svga); + + svga->x_add = (overscan_x >> 1); + xga_render_overscan_left(xga, svga); + xga_render_overscan_right(xga, svga); + svga->x_add = (overscan_x >> 1); + + if (xga->hwcursor_on) { + xga_hwcursor_draw(svga, xga->displine + svga->y_add); xga->hwcursor_on--; + if (xga->hwcursor_on && xga->interlace) + xga->hwcursor_on--; + } + + if (xga->lastline < xga->displine) + xga->lastline = xga->displine; } - if (xga->lastline < xga->displine) - xga->lastline = xga->displine; - } - - xga->displine++; - if (xga->interlace) xga->displine++; - if ((svga->cgastat & 8) && ((xga->displine & 0x0f) == (svga->crtc[0x11] & 0x0f)) && svga->vslines) - svga->cgastat &= ~8; - if (xga->displine > 1500) - xga->displine = 0; - } else { - timer_advance_u64(&svga->timer, svga->dispontime); - if (xga->dispon) - svga->cgastat &= ~1; + if (xga->interlace) + xga->displine++; + if ((svga->cgastat & 8) && ((xga->displine & 0x0f) == (svga->crtc[0x11] & 0x0f)) && svga->vslines) + svga->cgastat &= ~8; + if (xga->displine > 1500) + xga->displine = 0; + } else { + timer_advance_u64(&svga->timer, xga->dispontime); + if (xga->dispon) + svga->cgastat &= ~1; - xga->h_disp_on = 0; + xga->h_disp_on = 0; - xga->linepos = 0; - if (xga->dispon) { - if (xga->sc == xga->rowcount) { - xga->sc = 0; + xga->linepos = 0; + if (xga->dispon) { + if (xga->sc == xga->rowcount) { + xga->sc = 0; - xga_log("MA=%08x, MALATCH=%x.\n", xga->ma, xga->ma_latch); - xga->maback += (xga->rowoffset << 3); - if (xga->interlace) + xga_log("MA=%08x, MALATCH=%x.\n", xga->ma, xga->ma_latch); xga->maback += (xga->rowoffset << 3); + if (xga->interlace) + xga->maback += (xga->rowoffset << 3); - xga->maback &= xga->vram_mask; - xga->ma = xga->maback; - } else { - xga->sc++; - xga->sc &= 0x1f; - xga->ma = xga->maback; + xga->maback &= xga->vram_mask; + xga->ma = xga->maback; + } else { + xga->sc++; + xga->sc &= 0x1f; + xga->ma = xga->maback; + } + } + + xga->vc++; + xga->vc &= 0x7ff; + + if (xga->vc == xga->split) { + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = (xga->rowoffset << 1); + else + xga->ma = xga->maback = 0; + + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + + xga->sc = 0; + } + if (xga->vc == xga->dispend) { + xga->dispon = 0; + + for (x = 0; x < ((xga->vram_mask + 1) >> 12); x++) { + if (xga->changedvram[x]) + xga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (xga->vc == xga->v_syncstart) { + xga->dispon = 0; + svga->cgastat |= 8; + x = xga->h_disp; + + if (xga->interlace && !xga->oddeven) + xga->lastline++; + if (xga->interlace && xga->oddeven) + xga->firstline--; + + wx = x; + + wy = xga->lastline - xga->firstline; + svga_doblit(wx, wy, svga); + + xga->firstline = 2000; + xga->lastline = 0; + + xga->firstline_draw = 2000; + xga->lastline_draw = 0; + + xga->oddeven ^= 1; + + svga->monitor->mon_changeframecount = xga->interlace ? 3 : 2; + + if (xga->interlace && xga->oddeven) + xga->ma = xga->maback = xga->ma_latch + (xga->rowoffset << 1); + else + xga->ma = xga->maback = xga->ma_latch; + + xga->ma = (xga->ma << 2); + xga->maback = (xga->maback << 2); + } + if (xga->vc == xga->v_total) { + xga->vc = 0; + xga->sc = 0; + xga->dispon = 1; + xga->displine = (xga->interlace && xga->oddeven) ? 1 : 0; + + svga->x_add = (overscan_x >> 1); + + xga->hwcursor_on = 0; + xga->hwcursor_latch = xga->hwcursor; } } - - xga->vc++; - xga->vc &= 0x7ff; - - if (xga->vc == xga->split) { - if (xga->interlace && xga->oddeven) - xga->ma = xga->maback = (xga->rowoffset << 1); - else - xga->ma = xga->maback = 0; - - xga->ma = (xga->ma << 2); - xga->maback = (xga->maback << 2); - - xga->sc = 0; - } - if (xga->vc == xga->dispend) { - xga->dispon = 0; - - for (x = 0; x < ((xga->vram_mask + 1) >> 12); x++) { - if (xga->changedvram[x]) - xga->changedvram[x]--; - } - if (svga->fullchange) - svga->fullchange--; - } - if (xga->vc == xga->v_syncstart) { - xga->dispon = 0; - svga->cgastat |= 8; - x = xga->h_disp; - - if (xga->interlace && !xga->oddeven) - xga->lastline++; - if (xga->interlace && xga->oddeven) - xga->firstline--; - - wx = x; - - wy = xga->lastline - xga->firstline; - svga_doblit(wx, wy, svga); - - xga->firstline = 2000; - xga->lastline = 0; - - xga->firstline_draw = 2000; - xga->lastline_draw = 0; - - xga->oddeven ^= 1; - - svga->monitor->mon_changeframecount = xga->interlace ? 3 : 2; - - if (xga->interlace && xga->oddeven) - xga->ma = xga->maback = xga->ma_latch + (xga->rowoffset << 1); - else - xga->ma = xga->maback = xga->ma_latch; - - xga->ma = (xga->ma << 2); - xga->maback = (xga->maback << 2); - } - if (xga->vc == xga->v_total) { - xga->vc = 0; - xga->sc = 0; - xga->dispon = 1; - xga->displine = (xga->interlace && xga->oddeven) ? 1 : 0; - - svga->x_add = (overscan_x >> 1); - - xga->hwcursor_on = 0; - xga->hwcursor_latch = xga->hwcursor; - } - } + } else + svga_recalctimings(svga); } static uint8_t @@ -3285,6 +3324,7 @@ xga_reset(void *priv) xga->on = 0; xga->a5_test = 0; mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); + svga_set_poll(svga); } static uint8_t From 9af10bdac39b4c36bb619bb922da253d6ecbce0a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 26 Jan 2025 15:42:03 +0100 Subject: [PATCH 0153/1190] More changes to the 5380 chips (January 26th, 2025) Apparently the Trantor T130B SCSI controllers has a different way of calculating the timings and removed the scsi_bus_read() calls from the Current SCSI bus status port (Read Port+4). Fixes NT using said controller as well as CD swapping while maintaining the correct accurate CD speed. --- src/include/86box/scsi_ncr5380.h | 1 + src/scsi/scsi_ncr5380.c | 9 +++------ src/scsi/scsi_ncr53c400.c | 30 ++++++++++++++++++++---------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index 0b8a4efd8..5a43ba76a 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -74,6 +74,7 @@ typedef struct ncr_t { uint8_t output_data; uint8_t tx_data; uint8_t irq_state; + uint8_t isr_reg; uint8_t bus; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 60f60473e..048194a96 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -195,7 +195,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 5: /* start DMA Send */ - pclog("Write: start DMA send register\n"); + ncr5380_log("Write: start DMA send register\n"); /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ scsi_bus->tx_mode = DMA_OUT_TX_BUS; if (ncr->dma_send_ext) @@ -238,7 +238,7 @@ ncr5380_read(uint16_t port, ncr_t *ncr) } else ret = ncr->output_data; - ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x, txmode=%x.\n", CS, cpu_state.pc, ret, scsi_bus->clear_req, scsi_bus->wait_data, scsi_bus->tx_mode); + ncr5380_log("[%04X:%08X]: Data Bus Phase, CMDissued=%d, ret=%02x, clearreq=%d, waitdata=%x, txmode=%x.\n", CS, cpu_state.pc, scsi_bus->command_issued, ret, scsi_bus->clear_req, scsi_bus->wait_data, scsi_bus->tx_mode); } else { /*Return the data from the SCSI bus*/ bus = scsi_bus_read(scsi_bus); @@ -271,10 +271,6 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ret |= BUS_SEL; if (ncr->icr & ICR_BSY) ret |= BUS_BSY; - - /*Note by TC1995: Horrible hack, I know.*/ - (void) scsi_bus_read(scsi_bus); - (void) scsi_bus_read(scsi_bus); break; case 5: /* Bus and Status register */ @@ -319,6 +315,7 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ret |= STATUS_BUSY_ERROR; } ret |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + ncr->isr_reg = ret; break; case 6: diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index a9d07af95..fcfda69e4 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -180,7 +180,10 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) } if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); - timer_on_auto(&ncr400->timer, scsi_bus->period); + if (ncr400->type == ROM_T130B) + timer_on_auto(&ncr400->timer, 10.0); + else + timer_on_auto(&ncr400->timer, scsi_bus->period); ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer)); } else @@ -391,17 +394,20 @@ t130b_in(uint16_t port, void *priv) } static void -ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv), uint8_t val) +ncr53c400_dma_mode_ext(void *priv, void *ext_priv, uint8_t val) { + ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; scsi_bus_t *scsi_bus = &ncr->scsibus; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - ncr53c400_log("NCR 53c400: BlockCountLoaded=%d, DMA mode enabled=%02x, valDMA=%02x.\n", ncr400->block_count_loaded, ncr->mode & MODE_DMA, val & MODE_DMA); - if (!(val & MODE_DMA) && (ncr->mode & MODE_DMA)) { - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - scsi_bus->tx_mode = PIO_TX_BUS; + ncr53c400_log("NCR 53c400: Loaded?=%d, DMA mode enabled=%02x, valDMA=%02x.\n", ncr400->block_count_loaded, ncr->mode & MODE_DMA, val & MODE_DMA); + if (!ncr400->block_count_loaded) { + if (!(val & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + scsi_bus->tx_mode = PIO_TX_BUS; + } } } @@ -417,8 +423,13 @@ ncr53c400_callback(void *priv) uint8_t temp; uint8_t status; - if (scsi_bus->tx_mode != PIO_TX_BUS) - timer_on_auto(&ncr400->timer, 1.0); + if (scsi_bus->tx_mode != PIO_TX_BUS) { + if (ncr400->type == ROM_T130B) { + ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 200.0); + timer_on_auto(&ncr400->timer, scsi_bus->period / 200.0); + } else + timer_on_auto(&ncr400->timer, 1.0); + } if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; @@ -727,7 +738,6 @@ ncr53c400_init(const device_t *info) scsi_bus->speed = 0.2; scsi_bus->divider = 2.0; scsi_bus->multi = 1.750; - return ncr400; } From b141967a31fe929b60b3e92534fd7d27e05ffd19 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 26 Jan 2025 17:57:39 +0100 Subject: [PATCH 0154/1190] 8514/A and S3 minor change (January 26th, 2025) 1. Cosmetic changes. 2. Revert the position of the starting coordinates of the Short Stroke command, fixes some glitches in NT and elsewhere. --- src/video/vid_8514a.c | 18 +++++++++--------- src/video/vid_s3.c | 13 ++++++++----- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index d2e7efd8b..470642884 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -432,6 +432,14 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (len == 2) { dev->accel.short_stroke = val; + dev->accel.cx = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + dev->accel.cx |= ~0x5ff; + + dev->accel.cy = dev->accel.cur_y; + if (dev->accel.cur_y >= 0x600) + dev->accel.cy |= ~0x5ff; + if (dev->accel.cmd & 0x1000) { ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke & 0xff, len); ibm8514_short_stroke_start(-1, 0, -1, 0, svga, dev->accel.short_stroke >> 8, len); @@ -1139,16 +1147,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat the NOP command)*/ switch (cmd) { case 0: /*NOP (Short Stroke Vectors)*/ - if (dev->accel.ssv_state == 0) { - dev->accel.cx = dev->accel.cur_x; - if (dev->accel.cur_x >= 0x600) - dev->accel.cx |= ~0x5ff; - - dev->accel.cy = dev->accel.cur_y; - if (dev->accel.cur_y >= 0x600) - dev->accel.cy |= ~0x5ff; + if (dev->accel.ssv_state == 0) break; - } if (dev->accel.cmd & 0x08) { while (count-- && dev->accel.ssv_len >= 0) { diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index bb5c283ad..7839a602a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -923,6 +923,9 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); s3->accel.ssv_state = 1; + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cmd & 0x1000) { s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); @@ -1785,6 +1788,9 @@ s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) s3->accel.short_stroke = val; s3->accel.ssv_state = 1; + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cmd & 0x1000) { s3_short_stroke_start(s3, s3->accel.short_stroke & 0xff); s3_short_stroke_start(s3, s3->accel.short_stroke >> 8); @@ -7861,7 +7867,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi uint32_t srcbase; uint32_t dstbase; - if ((s3->chip >= S3_TRIO64 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) && (s3->accel.cmd & (1 << 11))) + if (((s3->chip >= S3_TRIO64) || (s3->chip == S3_VISION968) || (s3->chip == S3_VISION868)) && (s3->accel.cmd & (1 << 11))) cmd |= 0x08; // SRC-BASE/DST-BASE @@ -7970,11 +7976,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi switch (cmd) { case 0: /*NOP (Short Stroke Vectors)*/ - if (s3->accel.ssv_state == 0) { - s3->accel.cx = s3->accel.cur_x & 0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.ssv_state == 0) break; - } if (s3->accel.cmd & 0x08) { /*Radial*/ while (count-- && s3->accel.ssv_len >= 0) { From 8f5cf293bddd1fdba845806ff014780bdde3ef4b Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 27 Jan 2025 01:20:37 +0100 Subject: [PATCH 0155/1190] Assorted fixes, including warning message box for unavailable devices and translation fixes. --- src/device.c | 17 ++++++++++++++++- src/include/86box/nvr.h | 7 +++++-- src/include/86box/plat.h | 4 +--- src/include/86box/version.h.in | 4 ++++ src/qt/languages/86box.pot | 5 ++++- src/qt/languages/ca-ES.po | 15 ++++++++++++--- src/qt/languages/cs-CZ.po | 13 +++++++++++-- src/qt/languages/de-DE.po | 13 +++++++++++-- src/qt/languages/es-ES.po | 13 +++++++++++-- src/qt/languages/fi-FI.po | 17 +++++++++++++---- src/qt/languages/fr-FR.po | 13 +++++++++++-- src/qt/languages/hr-HR.po | 13 +++++++++++-- src/qt/languages/hu-HU.po | 13 +++++++++++-- src/qt/languages/it-IT.po | 12 ++++++++++++ src/qt/languages/ja-JP.po | 13 +++++++++++-- src/qt/languages/ko-KR.po | 13 +++++++++++-- src/qt/languages/nl-NL.po | 13 +++++-------- src/qt/languages/pl-PL.po | 25 +++++++++++++++++-------- src/qt/languages/pt-BR.po | 13 +++++-------- src/qt/languages/pt-PT.po | 13 +++++++++++-- src/qt/languages/ru-RU.po | 7 +++++-- src/qt/languages/sk-SK.po | 13 +++++++++++-- src/qt/languages/sl-SI.po | 15 ++++++++++++--- src/qt/languages/tr-TR.po | 13 +++++++++++-- src/qt/languages/uk-UA.po | 13 +++++++++++-- src/qt/languages/vi-VN.po | 13 +++++++++++-- src/qt/languages/zh-CN.po | 13 +++++++++++-- src/qt/languages/zh-TW.po | 13 +++++++++++-- src/qt/qt_platform.cpp | 3 ++- src/timer.c | 6 ++++-- 30 files changed, 282 insertions(+), 76 deletions(-) diff --git a/src/device.c b/src/device.c index 5b733df46..55552ead4 100644 --- a/src/device.c +++ b/src/device.c @@ -45,6 +45,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/ini.h> @@ -52,8 +53,10 @@ #include <86box/device.h> #include <86box/machine.h> #include <86box/mem.h> +#include <86box/plat.h> #include <86box/rom.h> #include <86box/sound.h> +#include <86box/ui.h> #define DEVICE_MAX 256 /* max # of devices */ @@ -155,6 +158,17 @@ device_add_common(const device_t *dev, void *p, void *params, int inst) void *priv = NULL; int16_t c; + if (!device_available(dev)) { + wchar_t temp[512] = { 0 }; + swprintf(temp, sizeof_w(temp), + plat_get_string(STRING_HW_NOT_AVAILABLE_DEVICE), + dev->name); + ui_msgbox_header(MBX_INFO, + plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), + temp); + return ((void *) dev->name); + } + if (params != NULL) { init_dev = calloc(1, sizeof(device_t)); memcpy(init_dev, dev, sizeof(device_t)); @@ -171,7 +185,8 @@ device_add_common(const device_t *dev, void *p, void *params, int inst) break; } if (c >= DEVICE_MAX) { - fatal("DEVICE: too many devices\n"); + fatal("Attempting to initialize more than the maximum " + "limit of %i devices\n", DEVICE_MAX); return NULL; } diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index c6dc08a12..0f7d22172 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -60,6 +60,7 @@ #define TIME_SYNC_ENABLED 1 #define TIME_SYNC_UTC 2 +#ifdef _TIMER_H_ /* Define a generic RTC/NVRAM device. */ typedef struct _nvr_ { char *fn; /* pathname of image file */ @@ -104,8 +105,6 @@ extern const device_t elt_nvr_device; extern void rtc_tick(void); extern void nvr_init(nvr_t *); -extern char *nvr_path(char *str); -extern FILE *nvr_fopen(char *str, char *mode); extern int nvr_load(void); extern void nvr_close(void); extern void nvr_set_ven_save(void (*ven_save)(void)); @@ -132,5 +131,9 @@ extern void nvr_irq_set(int irq, nvr_t *nvr); extern void nvr_smi_enable(int enable, nvr_t *nvr); extern uint8_t nvr_smi_status(nvr_t *nvr); extern void nvr_smi_status_clear(nvr_t *nvr); +#endif + +extern char *nvr_path(char *str); +extern FILE *nvr_fopen(char *str, char *mode); #endif /*EMU_NVR_H*/ diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 225c45ae1..f39f6ba51 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -47,6 +47,7 @@ enum { STRING_HW_NOT_AVAILABLE_MACHINE, /* "Machine \"%hs\" is not available..." */ STRING_HW_NOT_AVAILABLE_VIDEO, /* "Video card \"%hs\" is not available..." */ STRING_HW_NOT_AVAILABLE_VIDEO2, /* "Video card #2 \"%hs\" is not available..." */ + STRING_HW_NOT_AVAILABLE_DEVICE, /* "Device \"%hs\" is not available..." */ STRING_MONITOR_SLEEP, /* "Monitor in sleep mode" */ STRING_GHOSTPCL_ERROR_TITLE, /* "Unable to initialize GhostPCL" */ STRING_GHOSTPCL_ERROR_DESC /* "gpcl6dll32.dll/gpcl6dll64.dll/libgpcl6 is required..." */ @@ -187,9 +188,6 @@ extern void zip_reload(uint8_t id); extern void mo_eject(uint8_t id); extern void mo_mount(uint8_t id, char *fn, uint8_t wp); extern void mo_reload(uint8_t id); -extern int ioctl_open(uint8_t id, char d); -extern void ioctl_reset(uint8_t id); -extern void ioctl_close(uint8_t id); /* Other stuff. */ extern void startblit(void); diff --git a/src/include/86box/version.h.in b/src/include/86box/version.h.in index 5ebf7dba9..17c5b3068 100644 --- a/src/include/86box/version.h.in +++ b/src/include/86box/version.h.in @@ -14,6 +14,8 @@ * * Copyright 2020 Miran Grca. */ +#ifndef EMU_VERSION_H +#define EMU_VERSION_H #define _LSTR(s) L ## s #define LSTR(s) _LSTR(s) @@ -58,3 +60,5 @@ # define EMU_DOCS_URL "https://86box.readthedocs.io" #endif #define EMU_DOCS_URL_W LSTR(EMU_DOCS_URL) + +#endif /*EMU_VERSION_H*/ diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index c427d1300..ac2db7d07 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -687,7 +687,10 @@ msgstr "" msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "" -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "" + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." msgstr "" msgid "Machine" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index cf0556c36..e49ab3223 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -376,7 +376,7 @@ msgid "Time synchronization" msgstr "Sincronització horària" msgid "Disabled" -msgstr "Desactuvat" +msgstr "Deshabilitat" msgid "Enabled (local time)" msgstr "Activat (hora local)" @@ -687,8 +687,11 @@ msgstr "La màquina \"%hs\" no està disponible perquè falten ROM al directori msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "La targeta de vídeo \"%hs\" no està disponible perquè falten ROM al directori roms/video. Canvi a una targeta de vídeo disponible." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "La targeta de vídeo 2 \"%hs\" no està disponible perquè falten ROM al directori roms/video. Canvi a una targeta de vídeo disponible." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "La targeta de vídeo 2 \"%hs\" no està disponible perquè falten ROM al directori roms/video. Deshabilitant la segona targeta de vídeo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "El dispositiu \"%hs\" no està disponible perquè falten ROM. Ignorant el dispositiu." msgid "Machine" msgstr "Màquina" @@ -2120,3 +2123,9 @@ msgstr "Clon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Frabricant" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Expansió de memòria genèrica PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Expansió de memòria genèrica PC/AT" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 070c8a0df..cafadd63b 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -687,8 +687,11 @@ msgstr "Počítač \"%hs\" není dostupný, jelikož chybí obraz jeho paměti R msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Video adaptér \"%hs\" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce \"roms/video\". Konfigurace se přepne na jiný dostupný adaptér." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Video adaptér 2 \"%hs\" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce \"roms/video\". Konfigurace se přepne na jiný dostupný adaptér." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Video adaptér 2 \"%hs\" není dostupný, jelikož chybí obraz jeho paměti ROM ve složce \"roms/video\". Druhá grafická karta se zakáže." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Zařízení \"%hs\" není dostupné, jelikož chybí obraz jeho paměti ROM. Zařízení je ignorováno." msgid "Machine" msgstr "Počítač" @@ -2120,3 +2123,9 @@ msgstr "Klon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Výrobce" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Obecné rozšíření paměti PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Obecné rozšíření paměti PC/AT" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index e94b8ebf4..aa666cc48 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -687,8 +687,11 @@ msgstr "Das System \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/m msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Die Videokarte \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." msgid "Machine" msgstr "System" @@ -2123,3 +2126,9 @@ msgstr "IBM 8514/A-Klon (ISA)" msgid "Vendor" msgstr "Hersteller" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Generische PC/XT-Speichererweiterung" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Generische PC/AT-Speichererweiterung" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 7a457b225..5cac8968f 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -687,8 +687,11 @@ msgstr "La máquina \"%hs\" no está disponible debido a ROMs faltantes en el di msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "La tarjeta de vídeo \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una tarjeta de vídeo disponible." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "La tarjeta de vídeo 2 \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una tarjeta de vídeo disponible." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "La tarjeta de vídeo 2 \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Deshabilitanto la segunda tarjeta de vídeo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "El dispositivo \"%hs\" no está disponible debido a ROMs faltantes. Ignorando el dispositivo." msgid "Machine" msgstr "Máquina" @@ -2119,3 +2122,9 @@ msgstr "Clon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricante" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Expansión de Memoria Generica PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Expansión de Memoria Generica PC/AT" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 6aa71a867..21dcfd1bc 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -682,13 +682,16 @@ msgid "Surface images" msgstr "Pintalevykuvat" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -msgstr "Konetta \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen koneeseen." +msgstr "Konetta \"%hs\" ei voi käyttää, koska roms/machines-hakemistosta puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen koneeseen." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Näytönohjainta \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen näytönohjaimeen." +msgstr "Näytönohjainta \"%hs\" ei voi käyttää, koska roms/machines-hakemistosta puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen näytönohjaimeen." -msgid "Video card 2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Näytönohjainta 2 \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Vaihdetaan käyttökelpoiseen näytönohjaimeen." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Näytönohjainta 2 \"%hs\" ei voi käyttää, koska roms/machines-hakemistosta puuttuvien ROM-tiedostojen vuoksi. Toisen näytönohjaimen poistaminen käytöstä." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Laite \"%hs\" ei voi käyttää puuttuvien ROM-tiedostojen vuoksi. Laitteen huomiotta jättäminen." msgid "Machine" msgstr "Tietokone" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A-klooni (ISA)" msgid "Vendor" msgstr "Valmistaja" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Yleinen PC/XT-muistilaajennus" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Yleinen PC/AT-muistilaajennus" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index c8e4aa6cd..ff8a5168f 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -687,8 +687,11 @@ msgstr "La machine \"%hs\" n'est pas disponible en raison de l'absence de ROMs d msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "La carte vidéo \"%hs\" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/video. Basculer vers une carte vidéo disponible." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "La carte vidéo 2 \"%hs\" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/video. Basculer vers une carte vidéo disponible." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "La carte vidéo 2 \"%hs\" n'est pas disponible en raison de l'absence de ROMs dans le répertoire roms/video. Désactiver la deuxième carte vidéo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Le dispositif \"%hs\" n'est pas disponible en raison de l'absence de ROMs. Ignorer le dispositif." msgid "Machine" msgstr "Machine" @@ -2120,3 +2123,9 @@ msgstr "Clon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricant" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Expansion de la mémoire générique PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Expansion de la mémoire générique PC/AT" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index c1c76f468..9d242f8e0 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -687,8 +687,11 @@ msgstr "Sistem \"%hs\" nije dostupan jer ne postoje potrebni ROM-ovi u mapu roms msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Video kartica \"%hs\" nije dostupna jer ne postoje potrebni ROM-ovi u mapu roms/video. Prebacivanje na dostupnu video karticu." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Video kartica 2 \"%hs\" nije dostupna jer ne postoje potrebni ROM-ovi u mapu roms/video. Prebacivanje na dostupnu video karticu." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Video kartica 2 \"%hs\" nije dostupna jer ne postoje potrebni ROM-ovi u mapu roms/video. Isključivanje druge video karice." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Uređaj \"%hs\" nije dostupan jer ne postoje potrebni ROM-ovi. Ignoriranje uređaja." msgid "Machine" msgstr "Sistem" @@ -2120,3 +2123,9 @@ msgstr "Klon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Proizvođać" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Generičko proširenje memorije PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Generičko proširenje memorije PC/AT" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 732a75df7..2b5adacf4 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -687,8 +687,11 @@ msgstr "A számítógép \"%hs\" nem elérhető a \"roms/machines\" mappából h msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "A videokártya \"%hs\" nem elérhető a \"roms/video\" mappából hiányzó ROM-képek miatt. Ehelyett egy másik kártya kerül futtatásra." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "A videokártya 2 \"%hs\" nem elérhető a \"roms/video\" mappából hiányzó ROM-képek miatt. Ehelyett egy másik kártya kerül futtatásra." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "A videokártya 2 \"%hs\" nem elérhető a \"roms/video\" mappából hiányzó ROM-képek miatt. A második videokártya kerül letiltásra." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Az eszköz \"%hs\" nem elérhető a hiányzó ROM-képek miatt. Az eszköz figyelmen kívül marad." msgid "Machine" msgstr "Számítógép" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A klón (ISA)" msgid "Vendor" msgstr "Gyártó" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Általános PC/XT memóriabővítők" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Általános PC/AT memóriabővítők" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 088b625af..c9af80127 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -687,6 +687,12 @@ msgstr "La macchina \"%hs\" non è disponibile a causa di immagini ROM mancanti msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "La scheda video \"%hs\" non è disponibile a causa di immagini ROM mancanti nella directory roms/video. Cambiando ad una scheda video disponibile." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "La scheda video 2 \"%hs\" non è disponibile a causa di immagini ROM mancanti nella directory roms/video. Disabilitando la seconda scheda video." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Il dispositivo \"%hs\" non è disponibile a causa di immagini ROM mancanti. Ignorando il dispositivo." + msgid "Machine" msgstr "Piastra madre" @@ -2117,3 +2123,9 @@ msgstr "Clone IBM 8514/A(ISA)" msgid "Vendor" msgstr "Fabricante" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Espansione di memoria generica PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Espansione di memoria generica PC/AT" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 8ad510745..9a3289b51 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -687,8 +687,11 @@ msgstr "roms/machines ディレクトリにROMがないため、マシン「%hs msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "roms/video ディレクトリにROMがないため、ビデオ カード「%hs」は使用できません。使用可能なビデオカードに切り替えます。" -msgid "Video card 2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "roms/video ディレクトリにROMがないため、ビデオ カード2「%hs」は使用できません。使用可能なビデオカードに切り替えます。" +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "roms/video ディレクトリにROMがないため、ビデオ カード2「%hs」は使用できません。2枚目のビデオカードを無効にします。" + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "ROMがないため、デバイス「%hs」は使用できません。装置を無視する。" msgid "Machine" msgstr "マシン" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A クローン(ISA)" msgid "Vendor" msgstr "業者" + +msgid "Generic PC/XT Memory Expansion" +msgstr "汎用PC/XTメモリ拡張カード" + +msgid "Generic PC/AT Memory Expansion" +msgstr "汎用PC/ATメモリ拡張カード" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 485789f56..c6928ad43 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -687,8 +687,11 @@ msgstr "roms/machines 디렉토리에 필요한 롬파일이 없어 기종 \"%hs msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "roms/video 디렉토리에 필요한 롬파일이 없어 비디오 카드 \"%hs\"을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." -msgid "Video card 2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "roms/video 디렉토리에 필요한 롬파일이 없어 비디오 카드 2 \"%hs\"을(를) 사용할 수 없습니다. 사용 가능한 기종으로 변경합니다." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "roms/video 디렉토리에 필요한 롬파일이 없어 비디오 카드 2 \"%hs\"을(를) 사용할 수 없습니다. 두 번째 비디오 카드를 비활성화합니다." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "필요한 롬파일이 없어 장치 \"%hs\"을(를) 사용할 수 없습니다. 장치를 무시합니다." msgid "Machine" msgstr "기종" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A 클론(ISA)" msgid "Vendor" msgstr "제조사" + +msgid "Generic PC/XT Memory Expansion" +msgstr "일반 PC/XT 메모리 확장 카드" + +msgid "Generic PC/AT Memory Expansion" +msgstr "일반 PC/AT 메모리 확장 카드" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index b54bc1cb0..27870db90 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -687,8 +687,11 @@ msgstr "Machine \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Videokaart \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Overschakel over naar een beschikbare videokaart." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Videokaart #2 \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Overschakel over naar een beschikbare videokaart." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Videokaart #2 \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Uitschakel de tweede videokaart." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Het apparaat \"%hs\" is niet beschikbaar door ontbrekende ROMs. Negeer het apparaat." msgid "Machine" msgstr "Machine" @@ -2121,12 +2124,6 @@ msgstr "IBM 8514/A-kloon (ISA)" msgid "Vendor" msgstr "Verkoper" -msgid "30 Hz (JMP2 = 1)" -msgstr "30 Hz (JMP2 = 1)" - -msgid "60 Hz (JMP2 = 2)" -msgstr "60 Hz (JMP2 = 2)" - msgid "Generic PC/XT Memory Expansion" msgstr "Generieke PC/XT geheugenuitbreiding" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 9fa67bf9e..e42904458 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -687,8 +687,11 @@ msgstr "Maszyna \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w kat msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Karta wideo \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/video. Przełączanie na dostępną kartę wideo." -msgid "Video card 2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Karta wideo 2 \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/video. Przełączanie na dostępną kartę wideo." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Karta wideo 2 \"%hs\" nie jest dostępna, ponieważ brakuje obrazów ROM w katalogu roms/video. Wyłączenie drugiej karty graficznej." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Urządzenie \"%hs\" nie jest dostępne, ponieważ brakuje obrazów ROM. Ignorowanie urządzenia." msgid "Machine" msgstr "Maszyna" @@ -871,10 +874,10 @@ msgid "Invalid configuration" msgstr "Nieprawidłowa konfiguracja" msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." -msgstr "%1 jest wymagany do automatycznej konwersji plików PostScript do PDF.\n\nDokumenty wysłane do ogólnej drukarki PostScript zostaną zapisane jako pliki PostScript (.ps)." +msgstr "%1 jest wymagany do automatycznej konwersji plików PostScript do PDF.\n\nDokumenty wysłane do generycznej drukarki PostScript zostaną zapisane jako pliki PostScript (.ps)." msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." -msgstr "%1 jest wymagany do automatycznej konwersji plików PCL do PDF.\n\nDokumenty wysłane do ogólnej drukarki PCL zostaną zapisane jako pliki Printer Command Language (.pcl)." +msgstr "%1 jest wymagany do automatycznej konwersji plików PCL do PDF.\n\nDokumenty wysłane do generycznej drukarki PCL zostaną zapisane jako pliki Printer Command Language (.pcl)." msgid "Entering fullscreen mode" msgstr "Przechodzenie do trybu pełnoekranowego" @@ -1942,7 +1945,7 @@ msgid "New" msgstr "Nowość" msgid "Color (generic)" -msgstr "Kolor (ogólny)" +msgstr "Kolor (generyczny)" msgid "Green Monochrome" msgstr "Zielony monochromatyczny" @@ -2056,16 +2059,16 @@ msgid "Stereo LPT DAC" msgstr "Stereofoniczny przetwornik cyfrowo-analogowy LPT" msgid "Generic Text Printer" -msgstr "Ogólna drukarka tekstowa" +msgstr "Generyczna drukarka tekstowa" msgid "Generic ESC/P Dot-Matrix Printer" msgstr "Generyczna drukarka igłowa ESC/P" msgid "Generic PostScript Printer" -msgstr "Ogólna drukarka PostScript" +msgstr "Generyczna drukarka PostScript" msgid "Generic PCL5e Printer" -msgstr "Drukarka PCL5e" +msgstr "Generyczna drukarka PCL5e" msgid "Parallel Line Internet Protocol" msgstr "Protokół internetowy linii równoległej" @@ -2120,3 +2123,9 @@ msgstr "Klon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Producent" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Generyczne rozszerzenie pamięci PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Generyczne rozszerzenie pamięci PC/AT" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index c9ff9615b..de1bcd544 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -687,8 +687,11 @@ msgstr "A máquina \"%hs\" não está disponível devido à falta de ROMs no dir msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "A placa de vídeo \"%hs\" não está disponível devido à falta de ROMs no diretório roms/video. Mudando para uma placa de vídeo disponível." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "A placa de vídeo 2 \"%hs\" não está disponível devido à falta de ROMs no diretório roms/video. Mudando para uma placa de vídeo disponível." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "A placa de vídeo 2 \"%hs\" não está disponível devido à falta de ROMs no diretório roms/video. Desativando a segunda placa vídeo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "O dispositivo \"%hs\" não está disponível devido à falta de ROMs. Ignorando o dispositivo." msgid "Machine" msgstr "Máquina" @@ -2121,12 +2124,6 @@ msgstr "Clone IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricante" -msgid "30 Hz (JMP2 = 1)" -msgstr "30 Hz (JMP2 = 1)" - -msgid "60 Hz (JMP2 = 2)" -msgstr "60 Hz (JMP2 = 2)" - msgid "Generic PC/XT Memory Expansion" msgstr "Expansão de memória genérica PC/XT" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 1494ce1dc..d4c8bf170 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -687,8 +687,11 @@ msgstr "A máquina \"%hs\" não está disponível devido à falta de ROMs na pas msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "A placa vídeo \"%hs\" não está disponível devido à falta de ROMs na pasta roms/video. A mudar para uma placa vídeo disponível." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "A placa vídeo 2 \"%hs\" não está disponível devido à falta de ROMs na pasta roms/video. A mudar para uma placa vídeo disponível." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "A placa vídeo 2 \"%hs\" não está disponível devido à falta de ROMs na pasta roms/video. A desativar a segunda placa vídeo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "O dispositivo \"%hs\" não está disponível devido à falta de ROMs A ignorar o dispositivo." msgid "Machine" msgstr "Máquina" @@ -2120,3 +2123,9 @@ msgstr "Clone IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricante" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Expansão de memória genérica PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Expansão de memória genérica PC/AT" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 8476090d1..e6405ab79 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -687,8 +687,11 @@ msgstr "Системная плата \"%hs\" недоступна из-за о msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Видеокарта \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Переключение на доступную видеокарту." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Видеокарта 2 \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Переключение на доступную видеокарту." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Видеокарта 2 \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Отключение второй видеокарты." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Устройство \"%hs\" недоступно из-за отсутствия файла его ПЗУ. Игнорирование устройства." msgid "Machine" msgstr "Компьютер" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 708c24dd8..6b2074d47 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -687,8 +687,11 @@ msgstr "Počítač \"%hs\" ie je dostupný, pretože chýba obraz jeho pamäte R msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Video adaptér \"%hs\" nie je dostupný, pretože chýba obraz jeho pamäte ROM v zložke \"roms/video\". Konfigurácia sa prepne na iný dostupný adaptér." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Video adaptér 2 \"%hs\" nie je dostupný, pretože chýba obraz jeho pamäte ROM v zložke \"roms/video\". Konfigurácia sa prepne na iný dostupný adaptér." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Video adaptér 2 \"%hs\" nie je dostupný, pretože chýba obraz jeho pamäte ROM v zložke \"roms/video\". Druhá grafická karta sa zakáže." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Zariadenie \"%hs\" nie je dostupné, pretože chýba obraz jeho pamäte ROM. Zariadenie sa ignoruje." msgid "Machine" msgstr "Počítač" @@ -2120,3 +2123,9 @@ msgstr "Klon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Výrobca" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Všeobecné rozšírenie pamäte PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Všeobecné rozšírenie pamäte PC/AT" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index c9c99d6b2..9d8ccaaf9 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -685,10 +685,13 @@ msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines msgstr "Sistem \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/machines. Preklapljam na drug sistem, ki je na voljo." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Grafična kartica \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Preklapljam na drugo grafično kartico, ki je na voljo.." +msgstr "Grafična kartica \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Preklapljam na drugo grafično kartico, ki je na voljo." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Grafična kartica 2 \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Preklapljam na drugo grafično kartico, ki je na voljo.." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Grafična kartica 2 \"%hs\" ni na voljo zaradi manjkajočih ROM-ov v mapi roms/video. Onemogočam drugo grafično kartico." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Naprava \"%hs\" ni na voljo zaradi manjkajočih ROM-ov. Preziram napravo." msgid "Machine" msgstr "Sistem" @@ -2120,3 +2123,9 @@ msgstr "Klon IBM 8514/A (ISA)" msgid "Vendor" msgstr "Proizvajalec" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Generična razširitev pomnilnika PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Generična razširitev pomnilnika PC/AT" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 3a0cc2b96..288412154 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -687,8 +687,11 @@ msgstr "\"%hs\" makinesi roms/machines klasöründe gerekli ROM imajlarının me msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "\"%hs\" ekran kartı roms/video klasöründe gerekli ROM imajlarının mevcut olmaması nedeniyle kullanılamıyor. Bundan dolayı kullanılabilen bir ekran kartına geçiş yapılacaktır." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "\"%hs\" ikinci ekran kartı roms/video klasöründe gerekli ROM imajlarının mevcut olmaması nedeniyle kullanılamıyor. Bundan dolayı kullanılabilen bir ekran kartına geçiş yapılacaktır." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "\"%hs\" ikinci ekran kartı roms/video klasöründe gerekli ROM imajlarının mevcut olmaması nedeniyle kullanılamıyor. İkinci ekran kartı devre dışı bırakılır." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "\"%hs\" cihazı gerekli ROM imajlarının mevcut olmaması nedeniyle kullanılamıyor. Cihaz yok sayılıyor." msgid "Machine" msgstr "Makine" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A klonu (ISA)" msgid "Vendor" msgstr "Üretici" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Sıradan PC/XT bellek artırma" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Sıradan PC/AT bellek artırma" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 6cef7c294..5ce59be01 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -687,8 +687,11 @@ msgstr "Системна плата \"%hs\" недоступна через ві msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Відеокарта \"%hs\" недоступна через відсутність файлу її ПЗУ в каталозі roms/video. Переключення на доступну відеокарту." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Відеокарта 2 \"%hs\" недоступна через відсутність файлу її ПЗУ в каталозі roms/video. Переключення на доступну відеокарту." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Відеокарта 2 \"%hs\" недоступна через відсутність файлу її ПЗУ в каталозі roms/video. Відключення другої відеокарти." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Пристрій \"%hs\" недоступний через відсутність файлу його ПЗУ. Ігнорування пристрою." msgid "Machine" msgstr "Комп'ютер" @@ -2126,3 +2129,9 @@ msgstr "30 Гц (JMP2 = 1)" msgid "60 Hz (JMP2 = 2)" msgstr "60 Гц (JMP2 = 2)" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Загальне розширення пам'яті PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Загальне розширення пам'яті PC/AT" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 15802fc2d..707c7ae7f 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -687,8 +687,11 @@ msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tươ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Vô hiệu hóa card đồ họa thứ hai." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Bỏ qua thiết bị." msgid "Machine" msgstr "Mẫu máy" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A dòng vô tính (ISA)" msgid "Vendor" msgstr "Nhà sản xuất" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Chung mở rộng bộ nhớ qua PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Chung mở rộng bộ nhớ qua PC/AT" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 6b659b504..81451b2b3 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -687,8 +687,11 @@ msgstr "由于 roms/machines 文件夹中缺少合适的 ROM,机型 \"%hs\" msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "由于 roms/video 文件夹中缺少合适的 ROM,显卡 \"%hs\" 不可用。将切换到其他可用显卡。" -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "由于 roms/video 文件夹中缺少合适的 ROM,显卡 2 \"%hs\" 不可用。将切换到其他可用显卡。" +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "由于 roms/video 文件夹中缺少合适的 ROM,显卡 2 \"%hs\" 不可用。禁用第二块显卡。" + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "由于缺少合适的 ROM,设备 \"%hs\" 不可用。忽略设备。" msgid "Machine" msgstr "机型" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A 克隆 (ISA)" msgid "Vendor" msgstr "制造商" + +msgid "Generic PC/XT Memory Expansion" +msgstr "通用 PC/XT 内存扩展" + +msgid "Generic PC/AT Memory Expansion" +msgstr "通用 PC/AT 内存扩展" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index f9e917d98..9bf8edfc6 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -687,8 +687,11 @@ msgstr "由於 roms/machines 資料夾中缺少合適的 ROM,機型 \"%hs\" msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "由於 roms/video 資料夾中缺少合適的 ROM,顯示卡 \"%hs\" 不可用。將切換到其他可用顯示卡。" -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "由於 roms/video 資料夾中缺少合適的 ROM,顯示卡 2 \"%hs\" 不可用。將切換到其他可用顯示卡。" +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "由於 roms/video 資料夾中缺少合適的 ROM,顯示卡 2 \"%hs\" 不可用。禁用第二块显卡。" + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "由於缺少合適的 ROM,裝置 \"%hs\" 不可用。忽略设备。" msgid "Machine" msgstr "機型" @@ -2120,3 +2123,9 @@ msgstr "IBM 8514/A 克隆 (ISA)" msgid "Vendor" msgstr "製造商" + +msgid "Generic PC/XT Memory Expansion" +msgstr "通用 PC/XT 記憶體擴充" + +msgid "Generic PC/AT Memory Expansion" +msgstr "通用 PC/AT 記憶體擴充" diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 6b8b44405..a0ef86533 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -632,7 +632,8 @@ ProgSettings::reloadStrings() translatedstrings[STRING_GHOSTPCL_ERROR_DESC] = QCoreApplication::translate("", "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files.").arg(LIB_NAME_GPCL).toStdWString(); translatedstrings[STRING_HW_NOT_AVAILABLE_MACHINE] = QCoreApplication::translate("", "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine.").toStdWString(); translatedstrings[STRING_HW_NOT_AVAILABLE_VIDEO] = QCoreApplication::translate("", "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card.").toStdWString(); - translatedstrings[STRING_HW_NOT_AVAILABLE_VIDEO2] = QCoreApplication::translate("", "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card.").toStdWString(); + translatedstrings[STRING_HW_NOT_AVAILABLE_VIDEO2] = QCoreApplication::translate("", "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card.").toStdWString(); + translatedstrings[STRING_HW_NOT_AVAILABLE_DEVICE] = QCoreApplication::translate("", "Device \"%hs\" is not available due to missing ROMs. Ignoring the device.").toStdWString(); translatedstrings[STRING_HW_NOT_AVAILABLE_TITLE] = QCoreApplication::translate("", "Hardware not available").toStdWString(); translatedstrings[STRING_MONITOR_SLEEP] = QCoreApplication::translate("", "Monitor in sleep mode").toStdWString(); translatedstrings[STRING_NET_ERROR] = QCoreApplication::translate("", "Failed to initialize network driver").toStdWString(); diff --git a/src/timer.c b/src/timer.c index a3a7c9efb..9fed37511 100644 --- a/src/timer.c +++ b/src/timer.c @@ -31,7 +31,8 @@ timer_enable(pc_timer_t *timer) timer_disable(timer); if (timer->next || timer->prev) - fatal("timer_enable - timer->next\n"); + fatal("timer_disable(): Attempting to enable a non-isolated " + "timer incorrectly marked as disabled\n"); /*List currently empty - add to head*/ if (!timer_head) { @@ -92,7 +93,8 @@ timer_disable(pc_timer_t *timer) return; if (!timer->next && !timer->prev && timer != timer_head) - fatal("timer_disable - !timer->next\n"); + fatal("timer_disable(): Attempting to disable an isolated " + "non-head timer incorrectly marked as enabled\n"); timer->flags &= ~TIMER_ENABLED; timer->in_callback = 0; From f85e7debde395043d3e8389f71d5a1218c50a8fb Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 27 Jan 2025 01:48:14 +0100 Subject: [PATCH 0156/1190] Russian translation fixes by lemondrops. --- src/qt/languages/ru-RU.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index e6405ab79..a2e352faa 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -688,10 +688,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Видеокарта \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Переключение на доступную видеокарту." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Видеокарта 2 \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Отключение второй видеокарты." +msgstr "Видеокарта 2 \"%hs\" недоступна из-за отсутствия файла её ПЗУ в каталоге roms/video. Вторая видеокарта отключена." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Устройство \"%hs\" недоступно из-за отсутствия файла его ПЗУ. Игнорирование устройства." +msgstr "Устройство \"%hs\" недоступно из-за отсутствия файла его ПЗУ. Устройство проигнорировано." msgid "Machine" msgstr "Компьютер" From 2753a8e4bfc20ff9adb2c4924c8b5eb2236fcef4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 27 Jan 2025 09:54:39 +0100 Subject: [PATCH 0157/1190] Radisys EPC-2102: Move it to among the 430HX machines, where it should be. --- src/machine/machine_table.c | 80 ++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 2a50159e9..8ea850610 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11791,6 +11791,46 @@ const machine_t machines[] = { .snd_device = &sb_vibra16c_onboard_device, .net_device = NULL }, + /* Unknown PS/2 KBC. */ + { + .name = "[i430HX] Radisys EPC-2102", + .internal_name = "epc2102", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_epc2102_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 83333333, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . @@ -12448,46 +12488,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Unknown PS/2 KBC. */ - { - .name = "[i430HX] Radisys EPC-2102", - .internal_name = "epc2102", - .type = MACHINE_TYPE_SOCKET7, - .chipset = MACHINE_CHIPSET_INTEL_430HX, - .init = machine_at_epc2102_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, - .min_bus = 50000000, - .max_bus = 83333333, - .min_voltage = 2500, - .max_voltage = 3520, - .min_multi = 1.5, - .max_multi = 3.0 - }, - .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, - .ram = { - .min = 8192, - .max = 262144, - .step = 8192 - }, - .nvrmask = 127, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* This has a Holtek KBC and the BIOS does not send a single non-standard KBC command, so it must be an ASIC that clones the standard IBM PS/2 KBC. */ { From f78403ffe537d02b2a4a79d29d1edc1fe0ed5a56 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 27 Jan 2025 12:01:23 +0300 Subject: [PATCH 0158/1190] Add the PC Partner VIA809DS (Socket 7 D.V./VIA VP3) --- src/include/86box/machine.h | 1 + src/machine/m_at_socket7.c | 32 +++++++++++++++++++++++++++ src/machine/machine_table.c | 43 ++++++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b0365314e..f4f3f8834 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -746,6 +746,7 @@ extern int machine_at_tomahawk_init(const machine_t *); extern int machine_at_ficva502_init(const machine_t *); extern int machine_at_ficpa2012_init(const machine_t *); +extern int machine_at_via809ds_init(const machine_t *); extern int machine_at_r534f_init(const machine_t *); extern int machine_at_ms5146_init(const machine_t *); diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 2dbb83684..14b641540 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -1271,6 +1271,38 @@ machine_at_ficpa2012_init(const machine_t *model) return ret; } +int +machine_at_via809ds_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/via809ds/v30422sg.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); /* assumed */ + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&via_vp3_device); + device_add(&via_vt82c586b_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 512); + + return ret; +} + int machine_at_r534f_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8ea850610..bad86a786 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13063,7 +13063,48 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - + /* Has the VIA VT82C586B southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA VP3] PC Partner VIA809DS", + .internal_name = "via809ds", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_VP3, + .init = machine_at_via809ds_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 75000000, + .min_voltage = 2100, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 1048576, + .step = 8192 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + /* SiS 5571 */ /* Has the SiS 5571 chipset with on-chip KBC. */ { From 90e1190c9262bef735ee0dbfb3827242dab4ad53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 16:26:28 +0100 Subject: [PATCH 0159/1190] The great CD-ROM clean-up and rewrite, fixes #5134. --- src/cdrom/CMakeLists.txt | 4 +- src/cdrom/cdrom.c | 3556 +++++++++++++---------- src/cdrom/cdrom_image.c | 2176 ++++++++++++-- src/cdrom/cdrom_image_backend.c | 1499 ---------- src/cdrom/cdrom_image_viso.c | 138 +- src/cdrom/cdrom_ioctl.c | 267 -- src/cdrom/cdrom_mitsumi.c | 8 - src/config.c | 128 +- src/disk/hdc_esdi_at.c | 2 +- src/disk/hdc_esdi_mca.c | 2 +- src/disk/hdc_ide.c | 32 +- src/disk/hdc_ide_sff8038i.c | 11 +- src/disk/hdc_st506_at.c | 2 +- src/disk/hdc_st506_xt.c | 2 +- src/disk/hdc_xta.c | 2 +- src/disk/hdd.c | 2 +- src/disk/mo.c | 1551 +++++----- src/disk/zip.c | 1758 +++++------ src/include/86box/cdrom.h | 554 ++-- src/include/86box/cdrom_image.h | 40 +- src/include/86box/cdrom_image_backend.h | 119 - src/include/86box/cdrom_image_viso.h | 26 + src/include/86box/cdrom_interface.h | 14 +- src/include/86box/cdrom_ioctl.h | 32 - src/include/86box/hdc.h | 5 - src/include/86box/hdc_ide.h | 15 +- src/include/86box/hdd.h | 2 +- src/include/86box/log.h | 23 +- src/include/86box/mo.h | 122 +- src/include/86box/plat_cdrom.h | 73 - src/include/86box/plat_cdrom_ioctl.h | 34 + src/include/86box/scsi.h | 18 +- src/include/86box/scsi_cdrom.h | 67 +- src/include/86box/scsi_device.h | 183 +- src/include/86box/scsi_disk.h | 54 +- src/include/86box/zip.h | 107 +- src/log.c | 353 ++- src/machine/m_ps1_hdc.c | 2 +- src/qt/dummy_cdrom_ioctl.c | 292 +- src/qt/qt_machinestatus.cpp | 4 +- src/qt/qt_mediamenu.cpp | 27 +- src/qt/qt_settingsfloppycdrom.cpp | 43 +- src/qt/qt_settingsharddisks.cpp | 24 +- src/qt/win_cdrom_ioctl.c | 952 +++--- src/scsi/scsi_cdrom.c | 3214 +++++++++----------- src/scsi/scsi_disk.c | 1040 +++---- src/sound/snd_sb.c | 4 +- src/unix/dummy_cdrom_ioctl.c | 292 +- 48 files changed, 9486 insertions(+), 9389 deletions(-) delete mode 100644 src/cdrom/cdrom_image_backend.c delete mode 100644 src/cdrom/cdrom_ioctl.c delete mode 100644 src/include/86box/cdrom_image_backend.h create mode 100644 src/include/86box/cdrom_image_viso.h delete mode 100644 src/include/86box/cdrom_ioctl.h delete mode 100644 src/include/86box/plat_cdrom.h create mode 100644 src/include/86box/plat_cdrom_ioctl.h diff --git a/src/cdrom/CMakeLists.txt b/src/cdrom/CMakeLists.txt index 2f0f1cd23..621b069b0 100644 --- a/src/cdrom/CMakeLists.txt +++ b/src/cdrom/CMakeLists.txt @@ -21,10 +21,8 @@ pkg_check_modules(SNDFILE REQUIRED IMPORTED_TARGET sndfile) add_library(cdrom OBJECT cdrom.c - cdrom_image_backend.c - cdrom_image_viso.c cdrom_image.c - cdrom_ioctl.c + cdrom_image_viso.c ) target_link_libraries(86Box PkgConfig::SNDFILE) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 6d993f24a..5ddd788cb 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -15,105 +15,90 @@ * Copyright 2018-2021 Miran Grca. */ #include +#ifdef ENABLE_CDROM_LOG #include +#endif #include #include #include #include -#include -#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/config.h> #include <86box/cdrom.h> #include <86box/cdrom_image.h> #include <86box/cdrom_interface.h> -#include <86box/cdrom_mitsumi.h> +#include <86box/log.h> #include <86box/plat.h> +#include <86box/plat_cdrom_ioctl.h> #include <86box/scsi.h> #include <86box/scsi_device.h> +#include <86box/scsi_cdrom.h> #include <86box/sound.h> - -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#undef MSFtoLBA -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) +#include <86box/ui.h> #define RAW_SECTOR_SIZE 2352 -#define COOKED_SECTOR_SIZE 2048 #define MIN_SEEK 2000 #define MAX_SEEK 333333 -#pragma pack(push, 1) -typedef struct { - uint8_t user_data[2048], - ecc[288]; -} m1_data_t; - -typedef struct { - uint8_t sub_header[8], - user_data[2328]; -} m2_data_t; - -typedef union { - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2336]; -} sector_data_t; - -typedef struct { - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; -} sector_raw_data_t; - -typedef union { - sector_raw_data_t sector_data; - uint8_t raw_data[2352]; -} sector_t; - -typedef struct { - sector_t sector; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; -} cdrom_sector_t; - -typedef union { - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; -} sector_buffer_t; -#pragma pack(pop) - static int cdrom_sector_size; -static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */ +/* Needs some extra breathing space in case of overflows. */ +static uint8_t raw_buffer[4096]; static uint8_t extra_buffer[296]; -cdrom_t cdrom[CDROM_NUM]; +cdrom_t cdrom[CDROM_NUM] = { 0 }; int cdrom_interface_current; #ifdef ENABLE_CDROM_LOG int cdrom_do_log = ENABLE_CDROM_LOG; -void -cdrom_log(const char *fmt, ...) +static void +cdrom_log(void *priv, const char *fmt, ...) { - va_list ap; - if (cdrom_do_log) { + va_list ap; va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define cdrom_log(fmt, ...) +# define cdrom_log(priv, fmt, ...) #endif +static void process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b); +static void process_mode2_non_xa(const cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b); +static void process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b); +static void process_mode2_xa_form2(const cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b); + +typedef void (*cdrom_process_data_t)(const cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b); + +static cdrom_process_data_t cdrom_process_data[4] = { process_mode1, process_mode2_non_xa, + process_mode2_xa_form1, process_mode2_xa_form2 }; +#ifdef ENABLE_CDROM_LOG +static char * cdrom_req_modes[14] = { "Any", "Audio", "Mode 1", "Mode 2", + "CD-I/XA Mode 2 Form 1", "CD-I/XA Mode 2 Form 2", "Unk", "Unk", + "Any Data", "Any Data - 4", + "CD-I/XA Mode 2 Form 1", "CD-I/XA Mode 2 Form 1 - 4", + "Any CD-I/XA Data", "Any CD-I/XA Data - 4" }; +static char * cdrom_modes[4] = { "Mode 1", "Mode 2", "CD-I/XA Mode 2 Form 1", "CD-I/XA Mode 2 Form 2" }; +#endif +static uint8_t cdrom_mode_masks[14] = { 0x0f, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, + 0x05, 0x05, 0x04, 0x04, 0x0c, 0x0c }; + +static uint8_t status_codes[2][8] = { { 0x13, 0x15, 0x15, 0x15, 0x12, 0x11, 0x13, 0x13 }, + { 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00 } }; +static int mult = 1; +static int part = 0; +static int ecc_diff = 288; + static const device_t cdrom_interface_none_device = { .name = "None", .internal_name = "none", @@ -137,146 +122,57 @@ static const struct { // clang-format on }; -/* Reset the CD-ROM Interface, whichever one that is. */ -void -cdrom_interface_reset(void) +/* Private functions. */ +static void +cdrom_generate_name(const int type, char *name, const int internal) { - cdrom_log("CD-ROM Interface: reset(current=%d)\n", - cdrom_interface_current); + char elements[3][2048] = { 0 }; - /* If we have a valid controller, add its device. */ - if ((cdrom_interface_current > 0) && controllers[cdrom_interface_current].device) - device_add(controllers[cdrom_interface_current].device); -} + memcpy(elements[0], cdrom_drive_types[type].vendor, + strlen(cdrom_drive_types[type].vendor) + 1); + if (internal) for (int i = 0; i < strlen(elements[0]); i++) + if (elements[0][i] == ' ') + elements[0][i] = '_'; -const char * -cdrom_interface_get_internal_name(int cdinterface) -{ - return device_get_internal_name(controllers[cdinterface].device); -} + if (internal) { + int j = 0; + for (int i = 0; i <= strlen(cdrom_drive_types[type].model); i++) + if (cdrom_drive_types[type].model[i] != ':') + elements[1][j++] = cdrom_drive_types[type].model[i]; + } else + memcpy(elements[1], cdrom_drive_types[type].model, + strlen(cdrom_drive_types[type].model) + 1); + char *s = strstr(elements[1], " "); + if (s != NULL) + s[0] = 0x00; + if (internal) for (int i = 0; i < strlen(elements[1]); i++) + if (elements[1][i] == ' ') + elements[1][i] = '_'; -int -cdrom_interface_get_from_internal_name(char *s) -{ - int c = 0; + memcpy(elements[2], cdrom_drive_types[type].revision, + strlen(cdrom_drive_types[type].revision) + 1); + s = strstr(elements[2], " "); + if (s != NULL) + s[0] = 0x00; + if (internal) for (int i = 0; i < strlen(elements[2]); i++) + if (elements[2][i] == ' ') + elements[2][i] = '_'; - while (controllers[c].device != NULL) { - if (!strcmp(controllers[c].device->internal_name, s)) - return c; - c++; - } - - return 0; -} - -const device_t * -cdrom_interface_get_device(int cdinterface) -{ - return (controllers[cdinterface].device); -} - -int -cdrom_interface_has_config(int cdinterface) -{ - const device_t *dev = cdrom_interface_get_device(cdinterface); - - if (dev == NULL) - return 0; - - if (!device_has_config(dev)) - return 0; - - return 1; -} - -int -cdrom_interface_get_flags(int cdinterface) -{ - return (controllers[cdinterface].device->flags); -} - -int -cdrom_interface_available(int cdinterface) -{ - return (device_available(controllers[cdinterface].device)); -} - -char * -cdrom_getname(int type) -{ - return (char *) cdrom_drive_types[type].name; -} - -char * -cdrom_get_internal_name(int type) -{ - return (char *) cdrom_drive_types[type].internal_name; -} - -int -cdrom_get_from_internal_name(char *s) -{ - int c = 0; - - while (strlen(cdrom_drive_types[c].internal_name)) { - if (!strcmp((char *) cdrom_drive_types[c].internal_name, s)) - return c; - c++; - } - - return 0; -} - -void -cdrom_set_type(int model, int type) -{ - cdrom[model].type = type; -} - -int -cdrom_get_type(int model) -{ - return cdrom[model].type; -} - -static __inline int -bin2bcd(int x) -{ - return (x % 10) | ((x / 10) << 4); -} - -static __inline int -bcd2bin(int x) -{ - return (x >> 4) * 10 + (x & 0x0f); -} - -int -cdrom_lba_to_msf_accurate(int lba) -{ - int pos; - int m; - int s; - int f; - - pos = lba + 150; - f = pos % 75; - pos -= f; - pos /= 75; - s = pos % 60; - pos -= s; - pos /= 60; - m = pos; - - return ((m << 16) | (s << 8) | f); + if (internal) + sprintf(name, "%s_%s_%s", elements[0], elements[1], elements[2]); + else if (cdrom_drive_types[type].speed == -1) + sprintf(name, "%s %s %s", elements[0], elements[1], elements[2]); + else + sprintf(name, "%s %s %s (%ix)", elements[0], elements[1], + elements[2], cdrom_drive_types[type].speed); } static double -cdrom_get_short_seek(cdrom_t *dev) +cdrom_get_short_seek(const cdrom_t *dev) { switch (dev->cur_speed) { case 0: - fatal("CD-ROM %i: 0x speed\n", dev->id); + log_fatal(dev->log, "0x speed\n"); return 0.0; case 1: return 240.0; @@ -324,11 +220,11 @@ cdrom_get_short_seek(cdrom_t *dev) } static double -cdrom_get_long_seek(cdrom_t *dev) +cdrom_get_long_seek(const cdrom_t *dev) { switch (dev->cur_speed) { case 0: - fatal("CD-ROM %i: 0x speed\n", dev->id); + log_fatal(dev->log, "0x speed\n"); return 0.0; case 1: return 1446.0; @@ -375,113 +271,6 @@ cdrom_get_long_seek(cdrom_t *dev) } } -double -cdrom_seek_time(cdrom_t *dev) -{ - uint32_t diff = dev->seek_diff; - double sd = (double) (MAX_SEEK - MIN_SEEK); - - if (diff < MIN_SEEK) - return 0.0; - if (diff > MAX_SEEK) - diff = MAX_SEEK; - - diff -= MIN_SEEK; - - return cdrom_get_short_seek(dev) + ((cdrom_get_long_seek(dev) * ((double) diff)) / sd); -} - -void -cdrom_stop(cdrom_t *dev) -{ - if (dev->cd_status > CD_STATUS_DATA_ONLY) - dev->cd_status = CD_STATUS_STOPPED; -} - -void -cdrom_seek(cdrom_t *dev, uint32_t pos, uint8_t vendor_type) -{ - int m; - int s; - int f; - - if (!dev) - return; - - cdrom_log("CD-ROM %i: Seek to LBA %08X, vendor type = %02x.\n", dev->id, pos, vendor_type); - - switch (vendor_type) { - case 0x40: - m = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - f = bcd2bin((pos >> 8) & 0xff); - pos = MSFtoLBA(m, s, f) - 150; - break; - case 0x80: - pos = bcd2bin((pos >> 24) & 0xff); - break; - default: - break; - } - - dev->seek_pos = pos; - cdrom_stop(dev); -} - -int -cdrom_is_pre(cdrom_t *dev, uint32_t lba) -{ - if (dev->ops && dev->ops->is_track_pre) - return dev->ops->is_track_pre(dev, lba); - - return 0; -} - -int -cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) -{ - int ret = 1; - - if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING) || dev->audio_muted_soft) { - // cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); - if (dev->cd_status == CD_STATUS_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; - } - - while (dev->cd_buflen < len) { - if (dev->seek_pos < dev->cd_end) { - if (dev->ops->read_sector(dev, (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), dev->seek_pos)) { - cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos); - memcpy(dev->subch_buffer, ((uint8_t *) &(dev->cd_buffer[dev->cd_buflen])) + 2352, 96); - dev->seek_pos++; - dev->cd_buflen += (RAW_SECTOR_SIZE / 2); - ret = 1; - } else { - cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos); - memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_STOPPED; - dev->cd_buflen = len; - ret = 0; - } - } else { - cdrom_log("CD-ROM %i: Playing completed\n", dev->id); - memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_PLAYING_COMPLETED; - dev->cd_buflen = len; - ret = 0; - } - } - - memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); - dev->cd_buflen -= len; - - cdrom_log("CD-ROM %i: Audio callback returning %i\n", dev->id, ret); - return ret; -} - static void msf_from_bcd(int *m, int *s, int *f) { @@ -498,386 +287,1359 @@ msf_to_bcd(int *m, int *s, int *f) *f = bin2bcd(*f); } -uint8_t -cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) +static int +read_data(const cdrom_t *dev, const uint32_t lba) { - track_info_t ti; - int m = 0; - int s = 0; - int f = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - cdrom_log("CD-ROM %i: Play audio - %08X %08X %i\n", dev->id, pos, len, ismsf); - if (ismsf & 0x100) { - /* Track-relative audio play. */ - dev->ops->get_track_info(dev, ismsf & 0xff, 0, &ti); - pos += MSFtoLBA(ti.m, ti.s, ti.f) - 150; - } else if ((ismsf == 2) || (ismsf == 3)) { - dev->ops->get_track_info(dev, pos, 0, &ti); - pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - if (ismsf == 2) { - /* We have to end at the *end* of the specified track, - not at the beginning. */ - dev->ops->get_track_info(dev, len, 1, &ti); - len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - } - } else if (ismsf == 1) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) /*NEC*/ - msf_from_bcd(&m, &s, &f); - - if (pos == 0xffffff) { - cdrom_log("CD-ROM %i: Playing from current position (MSF)\n", dev->id); - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; - - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) /*NEC*/ - msf_from_bcd(&m, &s, &f); - - len = MSFtoLBA(m, s, f) - 150; - - cdrom_log("CD-ROM %i: MSF - pos = %08X len = %08X\n", dev->id, pos, len); - } else if (ismsf == 0) { - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); - pos = dev->seek_pos; - } - len += pos; - } - - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. */ - if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; - } - - dev->seek_pos = pos; - dev->cd_end = len; - dev->cd_status = CD_STATUS_PLAYING; - dev->cd_buflen = 0; - return 1; -} - -uint8_t -cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit) -{ - int m = 0; - int s = 0; - int f = 0; - uint32_t pos2 = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - cdrom_log("Audio Track Search: MSF = %06x, type = %02x, playbit = %02x\n", pos, type, playbit); - switch (type) { - case 0x00: - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: (type 0) Search from current position\n", dev->id); - pos = dev->seek_pos; - } - dev->seek_pos = pos; - break; - case 0x40: - m = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - f = bcd2bin((pos >> 8) & 0xff); - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: (type 1) Search from current position\n", dev->id); - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; - - dev->seek_pos = pos; - break; - case 0x80: - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: (type 2) Search from current position\n", dev->id); - pos = dev->seek_pos; - } - dev->seek_pos = (pos >> 24) & 0xff; - break; - default: - break; - } - - pos2 = pos - 1; - if (pos2 == 0xffffffff) - pos2 = pos + 1; - - /* Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. */ - if (!(dev->ops->track_type(dev, pos2) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: Track Search: LBA %08X not on an audio track\n", dev->id, pos); - dev->audio_muted_soft = 1; - if (dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; - } else - dev->audio_muted_soft = 0; - - cdrom_log("Track Search Toshiba: Muted?=%d, LBA=%08X.\n", dev->audio_muted_soft, pos); - dev->cd_buflen = 0; - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; - return 1; -} - -uint8_t -cdrom_audio_track_search_pioneer(cdrom_t *dev, uint32_t pos, uint8_t playbit) -{ - int m = 0; - int s = 0; - int f = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - f = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - m = bcd2bin((pos >> 8) & 0xff); - if (pos == 0xffffffff) { - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; - - dev->seek_pos = pos; - - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. */ - if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; - } - - dev->cd_buflen = 0; - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; - return 1; -} - -uint8_t -cdrom_audio_play_pioneer(cdrom_t *dev, uint32_t pos) -{ - int m = 0; - int s = 0; - int f = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - f = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - m = bcd2bin((pos >> 8) & 0xff); - pos = MSFtoLBA(m, s, f) - 150; - dev->cd_end = pos; - - dev->audio_muted_soft = 0; - dev->cd_buflen = 0; - dev->cd_status = CD_STATUS_PLAYING; - return 1; -} - -uint8_t -cdrom_audio_play_toshiba(cdrom_t *dev, uint32_t pos, int type) -{ - int m = 0; - int s = 0; - int f = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - /*Preliminary support, revert if too incomplete*/ - switch (type) { - case 0x00: - dev->cd_end = pos; - break; - case 0x40: - m = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - f = bcd2bin((pos >> 8) & 0xff); - pos = MSFtoLBA(m, s, f) - 150; - dev->cd_end = pos; - break; - case 0x80: - dev->cd_end = (pos >> 24) & 0xff; - break; - case 0xc0: - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); - pos = dev->cd_end; - } - dev->cd_end = pos; - break; - default: - break; - } - - cdrom_log("Toshiba Play Audio: Muted?=%d, LBA=%08X.\n", dev->audio_muted_soft, pos); - dev->cd_buflen = 0; - dev->cd_status = CD_STATUS_PLAYING; - return 1; -} - -uint8_t -cdrom_audio_scan(cdrom_t *dev, uint32_t pos, int type) -{ - int m = 0; - int s = 0; - int f = 0; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - cdrom_log("Audio Scan: MSF = %06x, type = %02x\n", pos, type); - switch (type) { - case 0x00: - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: (type 0) Search from current position\n", dev->id); - pos = dev->seek_pos; - } - dev->seek_pos = pos; - break; - case 0x40: - m = bcd2bin((pos >> 24) & 0xff); - s = bcd2bin((pos >> 16) & 0xff); - f = bcd2bin((pos >> 8) & 0xff); - if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: (type 1) Search from current position\n", dev->id); - pos = dev->seek_pos; - } else - pos = MSFtoLBA(m, s, f) - 150; - - dev->seek_pos = pos; - break; - case 0x80: - dev->seek_pos = (pos >> 24) & 0xff; - break; - default: - break; - } - - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. */ - if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; - } - - dev->cd_buflen = 0; - return 1; -} - -void -cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume) -{ - if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) - dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); + return dev->ops->read_sector(dev->local, raw_buffer, lba); } static void -cdrom_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc, int cooked) +cdrom_get_subchannel(const cdrom_t *dev, const uint32_t lba, + subchannel_t *subc, const int cooked) { - uint8_t *scb = dev->subch_buffer; - uint8_t q[16] = { 0 }; + const uint8_t *scb; + uint32_t scb_offs = 0; + uint8_t q[16] = { 0 }; - if ((lba == dev->seek_pos) && (dev->cd_status == CD_STATUS_PLAYING)) { - for (int i = 0; i < 12; i++) - for (int j = 0; j < 8; j++) - q[i] |= ((scb[(i << 3) + j] >> 6) & 0x01) << (7 - j); + if ((lba == dev->seek_pos) && + ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))) + scb = dev->subch_buffer; + else { + scb = (const uint8_t *) raw_buffer; + scb_offs = 2352; - if (cooked) { - uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); - q[0] = temp; + memset(raw_buffer, 0, 2448); - for (int i = 1; i < 10; i++) { - temp = bcd2bin(q[i]); - q[i] = temp; - } + (void) read_data(dev, lba); + } + + for (int i = 0; i < 12; i++) + for (int j = 0; j < 8; j++) + q[i] |= ((scb[scb_offs + (i << 3) + j] >> 6) & 0x01) << (7 - j); + + if (cooked) { + uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); + q[0] = temp; + + for (int i = 1; i < 10; i++) { + temp = bcd2bin(q[i]); + q[i] = temp; } + } - subc->attr = q[0]; - subc->track = q[1]; - subc->index = q[2]; - subc->rel_m = q[3]; - subc->rel_s = q[4]; - subc->rel_f = q[5]; - subc->abs_m = q[7]; - subc->abs_s = q[8]; - subc->abs_f = q[9]; - } else if ((dev->ops != NULL) && (dev->ops->get_subchannel != NULL)) { - dev->ops->get_subchannel(dev, lba, subc); + subc->attr = q[0]; + subc->track = q[1]; + subc->index = q[2]; + subc->rel_m = q[3]; + subc->rel_s = q[4]; + subc->rel_f = q[5]; + subc->abs_m = q[7]; + subc->abs_s = q[8]; + subc->abs_f = q[9]; +} - if (!cooked) { - uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); - q[0] = temp; +static void +read_toc_identify_sessions(const raw_track_info_t *rti, const int num, unsigned char *b) +{ + /* Bytes 2 and 3 = Number of first and last sessions */ + b[2] = 0xff; + b[3] = 0x00; - subc->attr = (subc->attr >> 4) | ((subc->attr & 0xf) << 4); - subc->track = bin2bcd(subc->track); - subc->index = bin2bcd(subc->index); - subc->rel_m = bin2bcd(subc->rel_m); - subc->rel_s = bin2bcd(subc->rel_s); - subc->rel_f = bin2bcd(subc->rel_f); - subc->abs_m = bin2bcd(subc->abs_m); - subc->abs_s = bin2bcd(subc->abs_s); - subc->abs_f = bin2bcd(subc->abs_f); - } + for (int i = (num - 1); i >= 0; i--) { + if (rti[i].session < b[2]) + b[2] = rti[i].session; + } + + for (int i = 0; i < num; i++) { + if (rti[i].session > b[3]) + b[3] = rti[i].session; } } -uint8_t -cdrom_get_current_status(cdrom_t *dev) +static int +find_track(const raw_track_info_t *trti, const int num, const int first) { - uint8_t ret; + int ret = -1; - if (dev->cd_status == CD_STATUS_DATA_ONLY) - ret = 0x15; - else { - if (dev->cd_status == CD_STATUS_PLAYING) - ret = 0x11; - else if (dev->cd_status == CD_STATUS_PAUSED) - ret = 0x12; + if (first) { + for (int i = 0; i < num; i++) + if ((trti[i].point >= 1) && (trti[i].point <= 99)) { + ret = i; + break; + } + } else { + for (int i = (num - 1); i >= 0; i--) + if ((trti[i].point >= 1) && (trti[i].point <= 99)) { + ret = i; + break; + } + } + + return ret; +} + +static int +find_last_lead_out(const raw_track_info_t *trti, const int num) +{ + int ret = -1; + + for (int i = (num - 1); i >= 0; i--) + if (trti[i].point == 0xa2) { + ret = i; + break; + } + + return ret; +} + +static int +find_specific_track(const raw_track_info_t *trti, const int num, const int track) +{ + int ret = -1; + + if ((track >= 1) && (track <= 99)) { + for (int i = (num - 1); i >= 0; i--) + if (trti[i].point == track) { + ret = i; + break; + } + } + + return ret; +} + +static int +read_toc_normal(const cdrom_t *dev, unsigned char *b, + const unsigned char start_track, const int msf, + const int sony) +{ + uint8_t rti[65536] = { 0 }; + uint8_t prti[65536] = { 0 }; + const raw_track_info_t *trti = (raw_track_info_t *) rti; + raw_track_info_t * tprti = (raw_track_info_t *) prti; + int num = 0; + int len = 4; + int t = -1; + + cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i)\n", + (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); + + dev->ops->get_raw_track_info(dev->local, &num, rti); + + if (num > 0) { + int j = 0; + for (int i = 0; i < num; i++) { + if ((trti[i].point >= 0x01) && (trti[i].point <= 0x63)) { + tprti[j] = trti[i]; + if ((t == -1) && (tprti[j].point >= start_track)) + t = j; + cdrom_log(dev->log, "Sorted %03i = Unsorted %03i\n", j, i); + j++; + } + } + + /* Bytes 2 and 3 = Number of first and last tracks found before lead out */ + b[2] = tprti[0].point; + b[3] = tprti[j - 1].point; + + for (int i = (num - 1); i >= 0; i--) { + if (trti[i].point == 0xa2) { + tprti[j] = trti[i]; + tprti[j].point = 0xaa; + if ((t == -1) && (tprti[j].point >= start_track)) + t = j; + cdrom_log(dev->log, "Sorted %03i = Unsorted %03i\n", j, i); + j++; + break; + } + } + + if (t != -1) for (int i = t; i < j; i++) { +#ifdef ENABLE_CDROM_LOG + uint8_t *c = &(b[len]); +#endif + + if (!sony) + b[len++] = 0; /* Reserved */ + b[len++] = tprti[i].adr_ctl; /* ADR/CTL */ + b[len++] = tprti[i].point; /* Track number */ + if (!sony) + b[len++] = 0; /* Reserved */ + + if (msf) { + b[len++] = 0; + + /* NEC CDR-260 speaks BCD. */ + if (dev->is_early) { + int m = tprti[i].pm; + int s = tprti[i].ps; + int f = tprti[i].pf; + msf_to_bcd(&m, &s, &f); + b[len++] = m; + b[len++] = s; + b[len++] = f; + } else { + b[len++] = tprti[i].pm; + b[len++] = tprti[i].ps; + b[len++] = tprti[i].pf; + } + } else { + const uint32_t temp = MSFtoLBA(tprti[i].pm, tprti[i].ps, + tprti[i].pf) - 150; + + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + +#ifdef ENABLE_CDROM_LOG + cdrom_log(dev->log, "Track %02X: %02X %02X %02X %02X %02X %02X %02X %02X\n", + i, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); +#endif + } + } else + b[2] = b[3] = 0; + + return len; +} + +static int +read_toc_session(const cdrom_t *dev, unsigned char *b, const int msf) +{ + uint8_t rti[65536] = { 0 }; + const raw_track_info_t *t = (raw_track_info_t *) rti; + const raw_track_info_t *first = NULL; + int num = 0; + int len = 4; + + dev->ops->get_raw_track_info(dev->local, &num, rti); + + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + + cdrom_log(dev->log, "read_toc_session(%016" PRIXPTR ", %016" PRIXPTR ", %i)\n", + (uintptr_t) dev, (uintptr_t) b, msf); + + if (num != 0) { + for (int i = 0; i < num; i++) { + if ((t[i].session == b[3]) && (t[i].point >= 0x01) && (t[i].point <= 0x63)) { + first = &(t[i]); + break; + } + } + if (first != NULL) { + b[len++] = 0x00; + b[len++] = first->adr_ctl; + b[len++] = first->point; + b[len++] = 0x00; + + if (msf) { + b[len++] = 0x00; + + /* NEC CDR-260 speaks BCD. */ + if (dev->is_early) { + int m = first->pm; + int s = first->ps; + int f = first->pf; + + msf_to_bcd(&m, &s, &f); + + b[len++] = m; + b[len++] = s; + b[len++] = f; + } else { + b[len++] = first->pm; + b[len++] = first->ps; + b[len++] = first->pf; + } + } else { + const uint32_t temp = MSFtoLBA(first->pm, first->ps, + first->pf) - 150; + + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + } + } + + if (len == 4) + memset(&(b[len += 8]), 0x00, 8); + + return len; +} + +static int +read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_track) +{ + uint8_t rti[65536] = { 0 }; + const raw_track_info_t *t = (raw_track_info_t *) rti; + int num = 0; + int len = 4; + + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + + cdrom_log(dev->log, "read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", + (uintptr_t) dev, (uintptr_t) b, start_track); + + dev->ops->get_raw_track_info(dev->local, &num, rti); + + if (num != 0) for (int i = 0; i < num; i++) + if (t[i].session >= start_track) { + memcpy(&(b[len]), &(t[i]), 11); + len += 11; + } + + return len; +} + +static int +track_type_is_valid(const cdrom_t *dev, const int type, const int flags, const int audio, + const int mode2) +{ + if (!(flags & 0x70) && (flags & 0xf8)) { /* 0x08/0x80/0x88 are illegal modes */ + cdrom_log(dev->log, "[Any Mode] 0x08/0x80/0x88 are illegal modes\n"); + return 0; + } + + if ((type != 1) && !audio) { + if ((flags & 0x06) == 0x06) { + cdrom_log(dev->log, "[Any Data Mode] Invalid error flags\n"); + return 0; + } + + if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { + cdrom_log(dev->log, "[Any Data Mode] Invalid subchannel data flags (%02X)\n", + flags & 0x700); + return 0; + } + + if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ + cdrom_log(dev->log, "[Any Data Mode] EDC/ECC without user data is an " + "illegal mode\n"); + return 0; + } + + if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ + cdrom_log(dev->log, "[Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n"); + return 0; + } + + if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) { + if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ + cdrom_log(dev->log, "[Any XA Mode 2] 0x30/0x38 are illegal modes\n"); + return 0; + } + if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ + cdrom_log(dev->log, "[Any XA Mode 2] 0xBx and 0xDx are illegal modes\n"); + return 0; + } + } + } + + return 1; +} + +static int +read_audio(const cdrom_t *dev, const uint32_t lba, uint8_t *b) +{ + const int ret = dev->ops->read_sector(dev->local, raw_buffer, lba); + + memcpy(b, raw_buffer, 2352); + + cdrom_sector_size = 2352; + + return ret; +} + + +static void +process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +{ + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log(dev->log, "[Mode 1] Sync\n"); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log(dev->log, "[Mode 1] Header\n"); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) { + /* No user data */ + cdrom_log(dev->log, "[Mode 1] Sub-header\n"); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + } + + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log(dev->log, "[Mode 1] User data\n"); + if (mult > 1) { + memcpy(b, raw_buffer + 16 + (part * dev->sector_size), dev->sector_size); + cdrom_sector_size += dev->sector_size; + b += dev->sector_size; + } else { + memcpy(b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + } + + if (cdrom_sector_flags & 0x08) { + /* EDC/ECC */ + cdrom_log(dev->log, "[Mode 1] EDC/ECC\n"); + memcpy(b, raw_buffer + 2064, (288 - ecc_diff)); + cdrom_sector_size += (288 - ecc_diff); + } +} + +static void +process_mode2_non_xa(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +{ + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log(dev->log, "[Mode 2 Formless] Sync\n"); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log(dev->log, "[Mode 2 Formless] Header\n"); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log(dev->log, "[Mode 2 Formless] Sub-header\n"); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log(dev->log, "[Mode 2 Formless] User data\n"); + memcpy(b, raw_buffer + 24, (2336 - ecc_diff)); + cdrom_sector_size += (2336 - ecc_diff); + } +} + +static void +process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +{ + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log(dev->log, "[XA Mode 2 Form 1] Sync\n"); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log(dev->log, "[XA Mode 2 Form 1] Header\n"); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log(dev->log, "[XA Mode 2 Form 1] Sub-header\n"); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log(dev->log, "[XA Mode 2 Form 1] User data\n"); + if (mult > 1) { + memcpy(b, raw_buffer + 24 + (part * dev->sector_size), dev->sector_size); + cdrom_sector_size += dev->sector_size; + b += dev->sector_size; + } else { + memcpy(b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + } + + if (cdrom_sector_flags & 0x08) { + /* EDC/ECC */ + cdrom_log(dev->log, "[XA Mode 2 Form 1] EDC/ECC\n"); + memcpy(b, raw_buffer + 2072, (280 - ecc_diff)); + cdrom_sector_size += (280 - ecc_diff); + } +} + +static void +process_mode2_xa_form2(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +{ + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { + /* Sync */ + cdrom_log(dev->log, "[XA Mode 2 Form 2] Sync\n"); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { + /* Header */ + cdrom_log(dev->log, "[XA Mode 2 Form 2] Header\n"); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { + /* Sub-header */ + cdrom_log(dev->log, "[XA Mode 2 Form 2] Sub-header\n"); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { + /* User data */ + cdrom_log(dev->log, "[XA Mode 2 Form 2] User data\n"); + memcpy(b, raw_buffer + 24, (2328 - ecc_diff)); + cdrom_sector_size += (2328 - ecc_diff); + } +} + +static void +cdrom_drive_reset(cdrom_t *dev) +{ + dev->priv = NULL; + dev->insert = NULL; + dev->close = NULL; + dev->get_volume = NULL; + dev->get_channel = NULL; + + if (cdrom_drive_types[dev->type].speed == -1) + dev->real_speed = dev->speed; + else + dev->real_speed = cdrom_drive_types[dev->type].speed; +} + +static void +cdrom_unload(cdrom_t *dev) +{ + cdrom_log(dev->log, "CDROM: cdrom_unload(%s)\n", dev->image_path); + + dev->cd_status = CD_STATUS_EMPTY; + + if (dev->local != NULL) { + dev->ops->close(dev->local); + dev->local = NULL; + } + + dev->ops = NULL; +} + +/* Reset the CD-ROM Interface, whichever one that is. */ +void +cdrom_interface_reset(void) +{ + /* If we have a valid controller, add its device. */ + if ((cdrom_interface_current > 0) && + controllers[cdrom_interface_current].device) + device_add(controllers[cdrom_interface_current].device); +} + +const char * +cdrom_interface_get_internal_name(const int cdinterface) +{ + return device_get_internal_name(controllers[cdinterface].device); +} + +int +cdrom_interface_get_from_internal_name(const char *s) +{ + int c = 0; + + while (controllers[c].device != NULL) { + if (!strcmp(controllers[c].device->internal_name, s)) + return c; + c++; + } + + return 0; +} + +const device_t * +cdrom_interface_get_device(const int cdinterface) +{ + return (controllers[cdinterface].device); +} + +int +cdrom_interface_has_config(const int cdinterface) +{ + const device_t *dev = cdrom_interface_get_device(cdinterface); + + if (dev == NULL) + return 0; + + if (!device_has_config(dev)) + return 0; + + return 1; +} + +int +cdrom_interface_get_flags(const int cdinterface) +{ + return (controllers[cdinterface].device->flags); +} + +int +cdrom_interface_available(const int cdinterface) +{ + return (device_available(controllers[cdinterface].device)); +} + +char * +cdrom_get_vendor(const int type) +{ + return (char *) cdrom_drive_types[type].vendor; +} + +void +cdrom_get_model(const int type, char *name, const int id) +{ + if (!strcmp(cdrom_drive_types[type].vendor, EMU_NAME)) + sprintf(name, "%s%02i", cdrom_drive_types[type].model, id); + else + sprintf(name, "%s", cdrom_drive_types[type].model); +} + +char * +cdrom_get_revision(const int type) +{ + return (char *) cdrom_drive_types[type].revision; +} + +int +cdrom_get_scsi_std(const int type) +{ + return cdrom_drive_types[type].scsi_std; +} + +int +cdrom_is_early(const int type) +{ + return (cdrom_drive_types[type].scsi_std == 1); +} + +int +cdrom_is_generic(const int type) +{ + return (cdrom_drive_types[type].speed == -1); +} + +int +cdrom_has_date(const int type) +{ + /* This will do for now. */ + return !strcmp(cdrom_drive_types[type].vendor, "PIONEER"); +} + +int +cdrom_is_sony(const int type) +{ + /* This will do for now. */ + return (cdrom_drive_types[type].bus_type == BUS_TYPE_SCSI) && + (!strcmp(cdrom_drive_types[type].vendor, "DEC") || + !strcmp(cdrom_drive_types[type].vendor, "ShinaKen") || + !strcmp(cdrom_drive_types[type].vendor, "SONY") || + !strcmp(cdrom_drive_types[type].vendor, "TEXEL")); +} + +int +cdrom_is_caddy(const int type) +{ + return cdrom_drive_types[type].caddy; +} + +int +cdrom_get_speed(const int type) +{ + return cdrom_drive_types[type].speed; +} + +int +cdrom_get_inquiry_len(const int type) +{ + return cdrom_drive_types[type].inquiry_len; +} + +int +cdrom_get_transfer_max(const int type, const int mode) +{ + return cdrom_drive_types[type].transfer_max[mode]; +} + +int +cdrom_has_dma(const int type) +{ + return (cdrom_drive_types[type].transfer_max[2] != -1); +} + +int +cdrom_get_type_count(void) +{ + int count = 0; + + while (1) { + if (strlen(cdrom_drive_types[count].vendor) == 0) + break; else - ret = 0x13; + count++; + } + + return count; +} + +void +cdrom_get_identify_model(const int type, char *name, const int id) +{ + char elements[2][2048] = { 0 }; + + memcpy(elements[0], cdrom_drive_types[type].vendor, + strlen(cdrom_drive_types[type].vendor) + 1); + + memcpy(elements[1], cdrom_drive_types[type].model, + strlen(cdrom_drive_types[type].model) + 1); + + char *s = strstr(elements[1], " "); + + if (s != NULL) + s[0] = 0x00; + + if (!strcmp(cdrom_drive_types[type].vendor, EMU_NAME)) + sprintf(name, "%s%02i", elements[1], id); + else if (!strcmp(cdrom_drive_types[type].vendor, "ASUS")) + sprintf(name, "%s %s", elements[0], elements[1]); + else if (!strcmp(cdrom_drive_types[type].vendor, "NEC")) + sprintf(name, "%s %s", elements[0], elements[1]); + else if (!strcmp(cdrom_drive_types[type].vendor, "LITE-ON")) + sprintf(name, "%s", elements[1]); + else + sprintf(name, "%s %s", elements[0], elements[1]); +} + +void +cdrom_get_name(const int type, char *name) +{ + char n[2048] = { 0 }; + + cdrom_generate_name(type, n, 0); + + if (cdrom_drive_types[type].bus_type == BUS_TYPE_SCSI) + sprintf(name, "[SCSI-%i] %s", cdrom_drive_types[type].scsi_std, n); + else + sprintf(name, "%s", n); +} + +char * +cdrom_get_internal_name(const int type) +{ + return (char *) cdrom_drive_types[type].internal_name; +} + +int +cdrom_get_from_internal_name(const char *s) +{ + int c = 0; + int found = 0; + + while (strlen(cdrom_drive_types[c].internal_name) > 0) { + if (!strcmp((char *) cdrom_drive_types[c].internal_name, s)) { + found = 1; + break; + } + c++; + } + + if (!found) + c = -1; + + return c; +} + +/* TODO: Configuration migration, remove when no longer needed. */ +int +cdrom_get_from_name(const char *s) +{ + int c = 0; + int found = 0; + char n[2048] = { 0 }; + + if (strcmp(s, "none")) { + while (strlen(cdrom_drive_types[c].internal_name) > 0) { + memset(n, 0x00, 2048); + cdrom_generate_name(c, n, 1); + /* Special case some names. */ + if ((!strcmp(s, "86BOX_CD-ROM_1.00") && !strcmp(n, "86Box_86B_CD_3.50")) || + (!strcmp(s, "TEAC_CD_532E_2.0A") && !strcmp(n, "TEAC_CD-532E_2.0A")) || + !strcmp(n, s)) { + found = 1; + break; + } + c++; + } + } + + if (!found) { + if (strcmp(s, "none")) { + wchar_t tempmsg[2048]; + sprintf(n, "WARNING: CD-ROM \"%s\" not found - contact 86Box support\n", s); + swprintf(tempmsg, sizeof_w(tempmsg), L"%hs", n); + pclog(n); + ui_msgbox_header(MBX_INFO, + plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), + tempmsg); + } + c = -1; + } + + return c; +} + +void +cdrom_set_type(const int model, const int type) +{ + cdrom[model].type = type; +} + +int +cdrom_get_type(const int model) +{ + return cdrom[model].type; +} + +int +cdrom_lba_to_msf_accurate(const int lba) +{ + int pos = lba + 150; + const int f = pos % 75; + pos -= f; + pos /= 75; + const int s = pos % 60; + pos -= s; + pos /= 60; + const int m = pos; + + return ((m << 16) | (s << 8) | f); +} + +double +cdrom_seek_time(const cdrom_t *dev) +{ + uint32_t diff = dev->seek_diff; + const double sd = (double) (MAX_SEEK - MIN_SEEK); + + if (diff < MIN_SEEK) + return 0.0; + if (diff > MAX_SEEK) + diff = MAX_SEEK; + + diff -= MIN_SEEK; + + return cdrom_get_short_seek(dev) + + ((cdrom_get_long_seek(dev) * ((double) diff)) / sd); +} + +void +cdrom_stop(cdrom_t *dev) +{ + if (dev->cd_status > CD_STATUS_DVD) + dev->cd_status = CD_STATUS_STOPPED; +} + +void +cdrom_seek(cdrom_t *dev, const uint32_t pos, const uint8_t vendor_type) +{ + int m; + int s; + int f; + uint32_t real_pos = pos; + + if (dev == NULL) + return; + + cdrom_log(dev->log, "Seek to LBA %08X, vendor type = %02x.\n", pos, vendor_type); + + switch (vendor_type) { + case 0x40: + m = bcd2bin((pos >> 24) & 0xff); + s = bcd2bin((pos >> 16) & 0xff); + f = bcd2bin((pos >> 8) & 0xff); + real_pos = MSFtoLBA(m, s, f) - 150; + break; + case 0x80: + real_pos = bcd2bin((pos >> 24) & 0xff); + break; + default: + break; + } + + dev->seek_pos = real_pos; + cdrom_stop(dev); +} + +int +cdrom_is_pre(const cdrom_t *dev, const uint32_t lba) +{ + if (dev->ops && dev->ops->is_track_pre) + return dev->ops->is_track_pre(dev->local, lba); + + return 0; +} + +int +cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len) +{ + int ret = 1; + + if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING) || dev->audio_muted_soft) { + // cdrom_log(dev->log, "Audio callback while not playing\n"); + if (dev->cd_status == CD_STATUS_PLAYING) + dev->seek_pos += (len >> 11); + memset(output, 0, len * 2); + return 0; + } + + while (dev->cd_buflen < len) { + if (dev->seek_pos < dev->cd_end) { + if (dev->ops->read_sector(dev->local, + (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), dev->seek_pos)) { + cdrom_log(dev->log, "Read LBA %08X successful\n", dev->seek_pos); + memcpy(dev->subch_buffer, + ((uint8_t *) &(dev->cd_buffer[dev->cd_buflen])) + 2352, 96); + dev->seek_pos++; + dev->cd_buflen += (RAW_SECTOR_SIZE / 2); + ret = 1; + } else { + cdrom_log(dev->log, "Read LBA %08X failed\n", dev->seek_pos); + memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, + (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_STOPPED; + dev->cd_buflen = len; + ret = 0; + } + } else { + cdrom_log(dev->log, "Playing completed\n"); + memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_status = CD_STATUS_PLAYING_COMPLETED; + dev->cd_buflen = len; + ret = 0; + } + } + + memcpy(output, dev->cd_buffer, len * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + dev->cd_buflen -= len; + + cdrom_log(dev->log, "Audio callback returning %i\n", ret); + return ret; +} + +uint8_t +cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ismsf) +{ + track_info_t ti; + uint32_t pos2 = pos; + uint32_t len2 = len; + int ret = 0; + + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + cdrom_log(dev->log, "Play audio - %08X %08X %i\n", pos2, len, ismsf); + + if (ismsf & 0x100) { + /* Track-relative audio play. */ + ret = dev->ops->get_track_info(dev->local, ismsf & 0xff, 0, &ti); + if (ret) + pos2 += MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", ismsf & 0xff); + cdrom_stop(dev); + } + } else if ((ismsf == 2) || (ismsf == 3)) { + ret = dev->ops->get_track_info(dev->local, pos2, 0, &ti); + if (ret) { + pos2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + if (ismsf == 2) { + /* We have to end at the *end* of the specified track, + not at the beginning. */ + ret = dev->ops->get_track_info(dev->local, len, 1, &ti); + if (ret) + len2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the ending position for " + "track %08X\n", pos2); + cdrom_stop(dev); + } + } + } else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", pos2); + cdrom_stop(dev); + } + } else if (ismsf == 1) { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + + /* NEC CDR-260 speaks BCD. */ + if (dev->is_early) + msf_from_bcd(&m, &s, &f); + + if (pos == 0xffffff) { + cdrom_log(dev->log, "Playing from current position (MSF)\n"); + pos2 = dev->seek_pos; + } else + pos2 = MSFtoLBA(m, s, f) - 150; + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + + /* NEC CDR-260 speaks BCD. */ + if (dev->is_early) + msf_from_bcd(&m, &s, &f); + + len2 = MSFtoLBA(m, s, f) - 150; + + ret = 1; + + cdrom_log(dev->log, "MSF - pos = %08X len = %08X\n", pos2, len); + } else if (ismsf == 0) { + if (pos == 0xffffffff) { + cdrom_log(dev->log, "Playing from current position\n"); + pos2 = dev->seek_pos; + } + len2 += pos2; + + ret = 1; + } + } + + if (ret) { + dev->audio_muted_soft = 0; + + /* + Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. + */ + ret = (dev->ops->get_track_type(dev->local, pos2) == CD_TRACK_AUDIO); + + if (ret) { + dev->seek_pos = pos2; + dev->cd_end = len2; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; + } else { + cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); + cdrom_stop(dev); + } + } + + return ret; +} + +uint8_t +cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, + const int type, const uint8_t playbit) +{ + uint32_t pos2 = pos; + uint8_t ret = 0; + + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + cdrom_log(dev->log, "Audio Track Search: MSF = %06x, type = %02x, " + "playbit = %02x\n", pos, type, playbit); + + switch (type) { + case 0x00: + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 0) Search from current position\n"); + pos2 = dev->seek_pos; + } + dev->seek_pos = pos2; + break; + case 0x40: { + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 1) Search from current position\n"); + pos2 = dev->seek_pos; + } else + pos2 = MSFtoLBA(m, s, f) - 150; + + dev->seek_pos = pos2; + break; + } case 0x80: + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 2) Search from current position\n"); + pos2 = dev->seek_pos; + } + dev->seek_pos = (pos2 >> 24) & 0xff; + break; + default: + break; + } + + if (pos2 != 0x00000000) + pos2--; + + /* + Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. + */ + if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) + dev->audio_muted_soft = 0; + else { + cdrom_log(dev->log, "Track Search: LBA %08X not on an audio track\n", pos); + dev->audio_muted_soft = 1; + if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) + dev->audio_muted_soft = 0; + } + + cdrom_log(dev->log, "Track Search Toshiba: Muted?=%d, LBA=%08X.\n", + dev->audio_muted_soft, pos); + dev->cd_buflen = 0; + + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; + + ret = 1; + } + + return ret; +} + +uint8_t +cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t playbit) +{ + uint8_t ret = 0; + + if (dev->cd_status &= CD_STATUS_HAS_AUDIO) { + const int f = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int m = bcd2bin((pos >> 8) & 0xff); + uint32_t pos2; + + if (pos == 0xffffffff) + pos2 = dev->seek_pos; + else + pos2 = MSFtoLBA(m, s, f) - 150; + + dev->seek_pos = pos2; + + dev->audio_muted_soft = 0; + + /* + Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. + */ + if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) { + dev->cd_buflen = 0; + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; + + ret = 1; + } else { + cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); + cdrom_stop(dev); + } + } + + return ret; +} + +uint8_t +cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos) +{ + uint8_t ret = 0; + + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + const int f = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int m = bcd2bin((pos >> 8) & 0xff); + uint32_t pos2 = MSFtoLBA(m, s, f) - 150; + dev->cd_end = pos2; + + dev->audio_muted_soft = 0; + dev->cd_buflen = 0; + + dev->cd_status = CD_STATUS_PLAYING; + + ret = 1; + } + + return ret; +} + +uint8_t +cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) +{ + uint32_t pos2 = pos; + uint8_t ret = 0; + + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + /* Preliminary support, revert if too incomplete. */ + switch (type) { + case 0x00: + dev->cd_end = pos2; + break; + case 0x40: + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); + pos2 = MSFtoLBA(m, s, f) - 150; + dev->cd_end = pos2; + break; + case 0x80: + dev->cd_end = (pos2 >> 24) & 0xff; + break; + case 0xc0: + if (pos == 0xffffffff) { + cdrom_log(dev->log, "Playing from current position\n"); + pos2 = dev->cd_end; + } + dev->cd_end = pos2; + break; + default: + break; + } + + cdrom_log(dev->log, "Toshiba Play Audio: Muted?=%d, LBA=%08X.\n", + dev->audio_muted_soft, pos2); + dev->cd_buflen = 0; + + dev->cd_status = CD_STATUS_PLAYING; + + ret = 1; + } + + return ret; +} + +uint8_t +cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type) +{ + uint32_t pos2 = pos; + uint8_t ret = 0; + + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + cdrom_log(dev->log, "Audio Scan: MSF = %06x, type = %02x\n", pos, type); + + switch (type) { + case 0x00: + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 0) Search from current position\n"); + pos2 = dev->seek_pos; + } + dev->seek_pos = pos2; + break; + case 0x40: + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 1) Search from current position\n"); + pos2 = dev->seek_pos; + } else + pos2 = MSFtoLBA(m, s, f) - 150; + + dev->seek_pos = pos2; + break; + case 0x80: + dev->seek_pos = (pos >> 24) & 0xff; + break; + default: + break; + } + + dev->audio_muted_soft = 0; + /* Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. */ + if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) { + dev->cd_buflen = 0; + ret = 1; + } else { + cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); + cdrom_stop(dev); + } } return ret; } void -cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) +cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume) +{ + if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) + dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); +} + +uint8_t +cdrom_get_current_status(const cdrom_t *dev) +{ + const uint8_t is_chinon = !strcmp(cdrom_drive_types[dev->type].vendor, "CHINON"); + const uint8_t ret = status_codes[is_chinon][dev->cd_status & CD_STATUS_MASK]; + + return ret; +} + +void +cdrom_get_current_subchannel(const cdrom_t *dev, uint8_t *b, const int msf) { subchannel_t subc; - uint32_t dat; cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); - cdrom_log("CD-ROM %i: Returned subchannel absolute at %02i:%02i.%02i, " + cdrom_log(dev->log, "Returned subchannel absolute at %02i:%02i.%02i, " "relative at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x.\n", - dev->id, subc.abs_m, subc.abs_s, subc.abs_f, subc.rel_m, subc.rel_s, subc.rel_f, + subc.abs_m, subc.abs_s, subc.abs_f, subc.rel_m, subc.rel_s, subc.rel_f, dev->seek_pos, dev->cd_end); /* Format code. */ switch (b[0]) { - /* Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), - the rest are stuff like ISRC etc., which can be all zeroes. */ + /* + Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current + position), the rest are stuff like ISRC etc., which can be all zeroes. + */ case 0x01: /* Current position. */ b[1] = subc.attr; @@ -888,8 +1650,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) b[4] = b[8] = 0x00; /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { - /* NEC */ + if (dev->is_early) { b[5] = bin2bcd(subc.abs_m); b[6] = bin2bcd(subc.abs_s); b[7] = bin2bcd(subc.abs_f); @@ -907,7 +1668,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) b[11] = subc.rel_f; } } else { - dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + uint32_t dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; b[4] = (dat >> 24) & 0xff; b[5] = (dat >> 16) & 0xff; b[6] = (dat >> 8) & 0xff; @@ -925,8 +1686,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) memset(&(b[1]), 0x00, 19); memset(&(b[5]), 0x30, 13); /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) - /* NEC */ + if (dev->is_early) b[19] = bin2bcd(subc.abs_f); else b[19] = subc.abs_f; @@ -936,27 +1696,27 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) memset(&(b[1]), 0x00, 19); memset(&(b[5]), 0x30, 12); /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) - /* NEC */ + if (dev->is_early) b[18] = bin2bcd(subc.abs_f); else b[18] = subc.abs_f; break; default: - cdrom_log("b[0] = %02X\n", b[0]); + cdrom_log(dev->log, "b[0] = %02X\n", b[0]); break; } } void -cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf) +cdrom_get_current_subchannel_sony(const cdrom_t *dev, uint8_t *b, const int msf) { subchannel_t subc; - uint32_t dat; cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); - cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x, msf = %x.\n", dev->id, subc.abs_m, subc.abs_s, subc.abs_f, dev->seek_pos, dev->cd_end, msf); + cdrom_log(dev->log, "Returned subchannel at %02i:%02i.%02i, seek pos = %08x, " + "cd_end = %08x, msf = %x.\n", + subc.abs_m, subc.abs_s, subc.abs_f, dev->seek_pos, dev->cd_end, msf); b[0] = subc.attr; b[1] = subc.track; @@ -970,7 +1730,7 @@ cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf) b[7] = subc.abs_s; b[8] = subc.abs_f; } else { - dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); + uint32_t dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); b[3] = (dat >> 16) & 0xff; b[4] = (dat >> 8) & 0xff; b[5] = dat & 0xff; @@ -982,23 +1742,22 @@ cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf) } uint8_t -cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b) +cdrom_get_audio_status_pioneer(const cdrom_t *dev, uint8_t *b) { uint8_t ret; subchannel_t subc; cdrom_get_subchannel(dev, dev->seek_pos, &subc, 0); - if (dev->cd_status == CD_STATUS_DATA_ONLY) - ret = 0x05; - else { + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { if (dev->cd_status == CD_STATUS_PLAYING) ret = dev->sound_on ? 0x00 : 0x02; else if (dev->cd_status == CD_STATUS_PAUSED) ret = 0x01; else ret = 0x03; - } + } else + ret = 0x05; b[0] = 0; b[1] = subc.abs_m; @@ -1009,24 +1768,22 @@ cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b) } uint8_t -cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf) +cdrom_get_audio_status_sony(const cdrom_t *dev, uint8_t *b, const int msf) { uint8_t ret; subchannel_t subc; - uint32_t dat; cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); - if (dev->cd_status == CD_STATUS_DATA_ONLY) - ret = 0x05; - else { + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { if (dev->cd_status == CD_STATUS_PLAYING) ret = dev->sound_on ? 0x00 : 0x02; else if (dev->cd_status == CD_STATUS_PAUSED) ret = 0x01; else ret = 0x03; - } + } else + ret = 0x05; if (msf) { b[0] = 0; @@ -1034,7 +1791,7 @@ cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf) b[2] = subc.abs_s; b[3] = subc.abs_f; } else { - dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + const uint32_t dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; b[0] = (dat >> 24) & 0xff; b[1] = (dat >> 16) & 0xff; b[2] = (dat >> 8) & 0xff; @@ -1045,7 +1802,7 @@ cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf) } void -cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) +cdrom_get_current_subcodeq(const cdrom_t *dev, uint8_t *b) { subchannel_t subc; @@ -1070,6 +1827,7 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) cdrom_get_current_subcodeq(dev, b); if ((dev->cd_status == CD_STATUS_DATA_ONLY) || + (dev->cd_status == CD_STATUS_DVD) || (dev->cd_status == CD_STATUS_PLAYING_COMPLETED) || (dev->cd_status == CD_STATUS_STOPPED)) ret = 0x03; @@ -1077,268 +1835,17 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) ret = (dev->cd_status == CD_STATUS_PLAYING) ? 0x00 : dev->audio_op; /*If a valid audio track is detected with audio on, unmute it.*/ - if (dev->ops->track_type(dev, dev->seek_pos) & CD_TRACK_AUDIO) + if (dev->ops->get_track_type(dev->local, dev->seek_pos) & CD_TRACK_AUDIO) dev->audio_muted_soft = 0; - cdrom_log("SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", + cdrom_log(dev->log, "SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", dev->seek_pos, dev->cd_end, dev->audio_muted_soft); return ret; } -static void -read_toc_identify_sessions(raw_track_info_t *rti, int num, unsigned char *b) -{ - /* Bytes 2 and 3 = Number of first and last sessions */ - b[2] = 0xff; - b[3] = 0x00; - - for (int i = (num - 1); i >= 0; i--) { - if (rti[i].session < b[2]) - b[2] = rti[i].session; - } - - for (int i = 0; i < num; i++) { - if (rti[i].session > b[3]) - b[3] = rti[i].session; - } -} - -static int -find_track(raw_track_info_t *trti, int num, int first) -{ - int ret = -1; - - if (first) { - for (int i = 0; i < num; i++) - if ((trti[i].point >= 1) && (trti[i].point <= 99)) { - ret = i; - break; - } - } else { - for (int i = (num - 1); i >= 0; i--) - if ((trti[i].point >= 1) && (trti[i].point <= 99)) { - ret = i; - break; - } - } - - return ret; -} - -static int -find_last_lead_out(raw_track_info_t *trti, int num) -{ - int ret = -1; - - for (int i = (num - 1); i >= 0; i--) - if (trti[i].point == 0xa2) { - ret = i; - break; - } - - return ret; -} - -static int -find_specific_track(raw_track_info_t *trti, int num, int track) -{ - int ret = -1; - - if ((track >= 1) && (track <= 99)) { - for (int i = (num - 1); i >= 0; i--) - if (trti[i].point == track) { - ret = i; - break; - } - } - - return ret; -} - -static int -read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int sony) -{ - uint8_t rti[65536] = { 0 }; - uint8_t prti[65536] = { 0 }; - raw_track_info_t *trti = (raw_track_info_t *) rti; - raw_track_info_t *tprti = (raw_track_info_t *) prti; - int num = 0; - int len = 4; - int s = -1; - - cdrom_log("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i)\n", - (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); - - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); - - if (num > 0) { - int j = 0; - for (int i = 0; i < num; i++) { - if ((trti[i].point >= 0x01) && (trti[i].point <= 0x63)) { - tprti[j] = trti[i]; - if ((s == -1) && (tprti[j].point >= start_track)) - s = j; - cdrom_log("Sorted %03i = Unsorted %03i (s = %03i)\n", j, i, s); - j++; - } - } - - /* Bytes 2 and 3 = Number of first and last tracks found before lead out */ - b[2] = tprti[0].point; - b[3] = tprti[j - 1].point; - - for (int i = (num - 1); i >= 0; i--) { - if (trti[i].point == 0xa2) { - tprti[j] = trti[i]; - tprti[j].point = 0xaa; - if ((s == -1) && (tprti[j].point >= start_track)) - s = j; - cdrom_log("Sorted %03i = Unsorted %03i (s = %03i)\n", j, i, s); - j++; - break; - } - } - - if (s != -1) for (int i = s; i < j; i++) { -#ifdef ENABLE_CDROM_LOG - uint8_t *c = &(b[len]); -#endif - - if (!sony) - b[len++] = 0; /* Reserved */ - b[len++] = tprti[i].adr_ctl; /* ADR/CTL */ - b[len++] = tprti[i].point; /* Track number */ - if (!sony) - b[len++] = 0; /* Reserved */ - - if (msf) { - b[len++] = 0; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { - int m = tprti[i].pm; - int s = tprti[i].ps; - int f = tprti[i].pf; - msf_to_bcd(&m, &s, &f); - b[len++] = m; - b[len++] = s; - b[len++] = f; - } else { - b[len++] = tprti[i].pm; - b[len++] = tprti[i].ps; - b[len++] = tprti[i].pf; - } - } else { - uint32_t temp = MSFtoLBA(tprti[i].pm, tprti[i].ps, tprti[i].pf) - 150; - - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - -#ifdef ENABLE_CDROM_LOG - cdrom_log("Track %02X: %02X %02X %02X %02X %02X %02X %02X %02X\n", - i, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); -#endif - } - } else - b[2] = b[3] = 0; - - return len; -} - -static int -read_toc_session(cdrom_t *dev, unsigned char *b, int msf) -{ - uint8_t rti[65536] = { 0 }; - raw_track_info_t *t = (raw_track_info_t *) rti; - raw_track_info_t *first = NULL; - int num = 0; - int len = 4; - - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); - - /* Bytes 2 and 3 = Number of first and last sessions */ - read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - - cdrom_log("read_toc_session(%016" PRIXPTR ", %016" PRIXPTR ", %i)\n", - (uintptr_t) dev, (uintptr_t) b, msf); - - if (num != 0) { - for (int i = 0; i < num; i++) if ((t[i].session == b[3]) && (t[i].point >= 0x01) && (t[i].point <= 0x63)) { - first = &(t[i]); - break; - } - if (first != NULL) { - b[len++] = 0x00; - b[len++] = first->adr_ctl; - b[len++] = first->point; - b[len++] = 0x00; - - if (msf) { - b[len++] = 0x00; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ - int m = first->pm; - int s = first->ps; - int f = first->pf; - - msf_to_bcd(&m, &s, &f); - - b[len++] = m; - b[len++] = s; - b[len++] = f; - } else { - b[len++] = first->pm; - b[len++] = first->ps; - b[len++] = first->pf; - } - } else { - uint32_t temp = MSFtoLBA(first->pm, first->ps, first->pf) - 150; - - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - } - } - - if (len == 4) - memset(&(b[len += 8]), 0x00, 8); - - return len; -} - -static int -read_toc_raw(cdrom_t *dev, unsigned char *b, unsigned char start_track) -{ - uint8_t rti[65536] = { 0 }; - raw_track_info_t *t = (raw_track_info_t *) rti; - int num = 0; - int len = 4; - - /* Bytes 2 and 3 = Number of first and last sessions */ - read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - - cdrom_log("read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", - (uintptr_t) dev, (uintptr_t) b, start_track); - - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); - - if (num != 0) for (int i = 0; i < num; i++) - if (t[i].session >= start_track) { - memcpy(&(b[len]), &(t[i]), 11); - len += 11; - } - - return len; -} - int -cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len) +cdrom_read_toc(const cdrom_t *dev, uint8_t *b, const int type, + const uint8_t start_track, const int msf, const int max_len) { int len; @@ -1353,7 +1860,7 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra len = read_toc_raw(dev, b, start_track); break; default: - cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type); + cdrom_log(dev->log, "Unknown TOC read type: %i\n", type); return 0; } @@ -1366,11 +1873,10 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra } int -cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int max_len) +cdrom_read_toc_sony(const cdrom_t *dev, uint8_t *b, const uint8_t start_track, + const int msf, const int max_len) { - int len; - - len = read_toc_normal(dev, b, start_track, msf, 1); + int len = read_toc_normal(dev, b, start_track, msf, 1); len = MIN(len, max_len); @@ -1392,7 +1898,7 @@ cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) int last = -1; if (dev != NULL) - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + dev->ops->get_raw_track_info(dev->local, &num, rti); if (num > 0) { first = find_track(trti, num, 1); @@ -1437,68 +1943,86 @@ uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len) { track_info_t ti; + int ret = 0; - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; + if (dev->cd_status & CD_STATUS_HAS_AUDIO) { + cdrom_log(dev->log, "Play Mitsumi audio - %08X %08X\n", pos, len); - cdrom_log("CD-ROM 0: Play Mitsumi audio - %08X %08X\n", pos, len); - dev->ops->get_track_info(dev, pos, 0, &ti); - pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - dev->ops->get_track_info(dev, len, 1, &ti); - len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + ret = dev->ops->get_track_info(dev->local, pos, 0, &ti); - /* Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. */ - if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { - cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); - cdrom_stop(dev); - return 0; + if (ret) { + pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + ret = dev->ops->get_track_info(dev->local, len, 1, &ti); + + if (ret) { + len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + + /* + Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. + */ + ret = (dev->ops->get_track_type(dev->local, pos) == CD_TRACK_AUDIO); + + if (ret) { + dev->seek_pos = pos; + dev->cd_end = len; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; + } else { + cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); + cdrom_stop(dev); + } + } else { + cdrom_log(dev->log, "Unable to get the ending position for track %08X\n", + len); + cdrom_stop(dev); + } + } else { + cdrom_log(dev->log, "Unable to get the starting position for track %08X\n", pos); + cdrom_stop(dev); + } } - dev->seek_pos = pos; - dev->cd_end = len; - dev->cd_status = CD_STATUS_PLAYING; - dev->cd_buflen = 0; - - return 1; + return ret; } #endif uint8_t -cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type) +cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, + const uint8_t track, const int type) { - uint8_t rti[65536] = { 0 }; - raw_track_info_t *trti = (raw_track_info_t *) rti; - int num = 0; - int first = -1; - int last = -1; - int t = -1; - uint32_t temp; - uint8_t ret = 1; + uint8_t rti[65536] = { 0 }; + const raw_track_info_t *trti = (raw_track_info_t *) rti; + int num = 0; + int first = -1; + int t = -1; + uint8_t ret = 1; + uint32_t temp; - if (dev != NULL) - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + cdrom_log(dev->log, "Read DISC Info TOC Type = %d, track = %d\n", type, track); - cdrom_log("Read DISC Info TOC Type = %d, track = %d\n", type, track); + dev->inv_field = track; + dev->ops->get_raw_track_info(dev->local, &num, rti); switch (type) { case 0: if (num > 0) { first = find_track(trti, num, 1); - last = find_track(trti, num, 0); - } + const int last = find_track(trti, num, 0); - if ((first == -1) || (last == -1)) + if ((first == -1) || (last == -1)) + ret = 0; + else { + b[0] = bin2bcd(first); + b[1] = bin2bcd(last); + b[2] = 0x00; + b[3] = 0x00; + + cdrom_log(dev->log, "Returned Toshiba/NEC disc information (type 0) " + "at %02i:%02i\n", b[0], b[1]); + } + } else ret = 0; - else { - b[0] = bin2bcd(first); - b[1] = bin2bcd(last); - b[2] = 0x00; - b[3] = 0x00; - - cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 0) at %02i:%02i\n", - dev->id, b[0], b[1]); - } break; case 1: if (num > 0) @@ -1512,8 +2036,8 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in b[2] = bin2bcd(trti[t].pf); b[3] = 0x00; - cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 1) at %02i:%02i.%02i\n", - dev->id, b[0], b[1], b[2]); + cdrom_log(dev->log, "Returned Toshiba/NEC disc information (type 1) at " + "%02i:%02i.%02i\n", b[0], b[1], b[2]); } break; case 2: @@ -1528,49 +2052,41 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in b[2] = bin2bcd(trti[t].pf); b[3] = trti[t].adr_ctl; - cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 2) at " - "%02i:%02i.%02i, track=%d, attr=%02x.\n", dev->id, b[0], b[1], b[2], bcd2bin(track), b[3]); + cdrom_log(dev->log, "Returned Toshiba/NEC disc information (type 2) at " + "%02i:%02i.%02i, track=%d, attr=%02x.\n", b[0], b[1], + b[2], bcd2bin(track), b[3]); } break; case 3: /* Undocumented on NEC CD-ROM's, from information based on sr_vendor.c from the Linux kernel */ - switch (dev->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: - b[0x0e] = 0x00; + if (dev->is_nec) { + b[0x0e] = 0x00; - if (num > 0) - first = find_track(trti, num, 1); + if (num > 0) + first = find_track(trti, num, 1); - if (first == -1) - ret = 0; - else { - temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; - b[0x0f] = temp >> 24; - b[0x10] = temp >> 16; - b[0x11] = temp >> 8; - b[0x12] = temp; - } - break; + if (first == -1) + ret = 0; + else { + temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; + b[0x0f] = temp >> 24; + b[0x10] = temp >> 16; + b[0x11] = temp >> 8; + b[0x12] = temp; + } + } else { + b[0] = 0x00; /* Audio or CDROM disc. */ - default: - b[0] = 0x00; /* Audio or CDROM disc. */ + if (num > 0) + first = find_track(trti, num, 1); - if (num > 0) - first = find_track(trti, num, 1); - - if (first == -1) - ret = 0; - else { - temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; - b[0x1] = temp >> 24; - b[0x2] = temp >> 16; - b[0x3] = temp >> 8; - } - break; + if (first == -1) + ret = 0; + else { + temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; + b[0x1] = temp >> 24; + b[0x2] = temp >> 16; + b[0x3] = temp >> 8; + } } break; default: @@ -1580,307 +2096,57 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in return ret; } -static int -track_type_is_valid(UNUSED(uint8_t id), int type, int flags, int audio, int mode2) -{ - if (!(flags & 0x70) && (flags & 0xf8)) { /* 0x08/0x80/0x88 are illegal modes */ - cdrom_log("CD-ROM %i: [Any Mode] 0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } - - if ((type != 1) && !audio) { - if ((flags & 0x06) == 0x06) { - cdrom_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); - return 0; - } - - if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { - cdrom_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, flags & 0x700); - return 0; - } - - if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ - cdrom_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); - return 0; - } - - if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ - cdrom_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); - return 0; - } - - if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) { - if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ - cdrom_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); - return 0; - } - if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ - cdrom_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); - return 0; - } - } - } - - return 1; -} - -static int -read_audio(cdrom_t *dev, uint32_t lba, uint8_t *b) -{ - int ret = dev->ops->read_sector(dev, raw_buffer, lba); - - memcpy(b, raw_buffer, 2352); - - cdrom_sector_size = 2352; - - return ret; -} - -static void -process_mode1(cdrom_t *dev, int cdrom_sector_flags, uint8_t *b) -{ - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { - /* Sync */ - cdrom_log("CD-ROM %i: [Mode 1] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { - /* Header */ - cdrom_log("CD-ROM %i: [Mode 1] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { - /* Sub-header */ - if (!(cdrom_sector_flags & 0x10)) { - /* No user data */ - cdrom_log("CD-ROM %i: [Mode 1] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - } - - if (cdrom_sector_flags & 0x10) { - /* User data */ - cdrom_log("CD-ROM %i: [Mode 1] User data\n", dev->id); - memcpy(b, raw_buffer + 16, 2048); - cdrom_sector_size += 2048; - b += 2048; - } - - if (cdrom_sector_flags & 0x08) { - /* EDC/ECC */ - cdrom_log("CD-ROM %i: [Mode 1] EDC/ECC\n", dev->id); - memcpy(b, raw_buffer + 2064, 288); - cdrom_sector_size += 288; - b += 288; - } -} - -static int -read_data(cdrom_t *dev, uint32_t lba) -{ - return dev->ops->read_sector(dev, raw_buffer, lba); -} - -static int -read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) -{ - int ret = read_data(dev, lba); - - process_mode1(dev, cdrom_sector_flags, b); - - return ret; -} - -static int -read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) -{ - int ret = dev->ops->read_sector(dev, raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { - /* Sync */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { - /* Header */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) { - /* Sub-header */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { - /* User data */ - cdrom_log("CD-ROM %i: [Mode 2 Formless] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2336); - cdrom_sector_size += 2336; - b += 2336; - } - - return ret; -} - -static void -process_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint8_t *b) -{ - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { - /* Sync */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { - /* Header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { - /* Sub-header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { - /* User data */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2048); - cdrom_sector_size += 2048; - b += 2048; - } - - if (cdrom_sector_flags & 0x08) { - /* EDC/ECC */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", dev->id); - memcpy(b, raw_buffer + 2072, 280); - cdrom_sector_size += 280; - b += 280; - } -} - -static int -read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) -{ - int ret = read_data(dev, lba); - - process_mode2_xa_form1(dev, cdrom_sector_flags, b); - - return ret; -} - -static int -read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) -{ - int ret = dev->ops->read_sector(dev, raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { - /* Sync */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", dev->id); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; - b += 12; - } - - if (cdrom_sector_flags & 0x20) { - /* Header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", dev->id); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - b += 4; - } - - if (cdrom_sector_flags & 0x40) { - /* Sub-header */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", dev->id); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - b += 8; - } - - if (cdrom_sector_flags & 0x10) { - /* User data */ - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", dev->id); - memcpy(b, raw_buffer + 24, 2328); - cdrom_sector_size += 2328; - b += 2328; - } - - return ret; -} - int -cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, - int cdrom_sector_flags, int *len, uint8_t vendor_type) +cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, + int cdrom_sector_type, const int cdrom_sector_flags, + int *len, const uint8_t vendor_type) { - uint8_t *b; uint8_t *temp_b; uint32_t lba; int audio = 0; int mode2 = 0; - int unk = 0; - int ret = 0; + int pos = sector; + int ret; + + if ((cdrom_sector_type & 0x0f) >= 0x08) { + mult = cdrom_sector_type >> 4; + cdrom_sector_type &= 0x0f; + part = pos % mult; + pos /= mult; + ecc_diff = (cdrom_sector_type & 0x01) ? 4 : 0; + } else { + mult = 1; + part = 0; + ecc_diff = 0; + } if (dev->cd_status == CD_STATUS_EMPTY) return 0; - b = temp_b = buffer; + uint8_t *b = temp_b = buffer; *len = 0; if (ismsf) { - int m = (sector >> 16) & 0xff; - int s = (sector >> 8) & 0xff; - int f = sector & 0xff; + const int m = (pos >> 16) & 0xff; + const int s = (pos >> 8) & 0xff; + const int f = pos & 0xff; lba = MSFtoLBA(m, s, f) - 150; } else { switch (vendor_type) { case 0x00: - lba = sector; + lba = pos; break; case 0x40: { - int m = bcd2bin((sector >> 24) & 0xff); - int s = bcd2bin((sector >> 16) & 0xff); - int f = bcd2bin((sector >> 8) & 0xff); + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); lba = MSFtoLBA(m, s, f) - 150; break; } case 0x80: - lba = bcd2bin((sector >> 24) & 0xff); + lba = bcd2bin((pos >> 24) & 0xff); break; /* Never used values but the compiler complains. */ default: @@ -1888,127 +2154,111 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c } } - if (dev->ops->track_type) - audio = dev->ops->track_type(dev, lba); + if (dev->ops->get_track_type) + audio = dev->ops->get_track_type(dev->local, lba); - mode2 = audio & CD_TRACK_MODE2; - unk = audio & CD_TRACK_UNK_DATA; - audio &= CD_TRACK_AUDIO; + int dm = audio & CD_TRACK_MODE_MASK; + audio &= CD_TRACK_AUDIO; + + if (dm != CD_TRACK_NORMAL) + mode2 = 1; memset(raw_buffer, 0, 2448); memset(extra_buffer, 0, 296); if ((cdrom_sector_flags & 0xf8) == 0x08) { /* 0x08 is an illegal mode */ - cdrom_log("CD-ROM %i: [Mode 1] 0x08 is an illegal mode\n", dev->id); + cdrom_log(dev->log, "[Mode 1] 0x08 is an illegal mode\n"); return 0; } - if (!track_type_is_valid(dev->id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) + if ((cdrom_sector_type > 5) && (cdrom_sector_type < 8)) { + cdrom_log(dev->log, "Attempting to read an unrecognized sector " + "type from an image\n"); return 0; - - if ((cdrom_sector_type > 5) && (cdrom_sector_type != 8)) { - cdrom_log("CD-ROM %i: Attempting to read an unrecognized sector type from an image\n", dev->id); - return 0; - } else if (cdrom_sector_type == 1) { - if (!audio || (dev->cd_status == CD_STATUS_DATA_ONLY)) { - cdrom_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", dev->id); + } else { + if ((cdrom_sector_type > 1) && audio && (dev->cd_status & CD_STATUS_HAS_AUDIO)) { + cdrom_log(dev->log, "[%s] Attempting to read a data sector " + "from an audio track\n", cdrom_req_modes[cdrom_sector_type]); + return 0; + } else if ((cdrom_sector_type == 1) && + (!audio || !(dev->cd_status & CD_STATUS_HAS_AUDIO))) { + cdrom_log(dev->log, "[Audio] Attempting to read an audio sector " + "from a data track\n"); return 0; } - ret = read_audio(dev, lba, temp_b); - } else if (cdrom_sector_type == 2) { - if (audio || mode2) { - cdrom_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", dev->id); - return 0; - } - - ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); - } else if (cdrom_sector_type == 3) { - if (audio || !mode2 || (mode2 & 0x03)) { - cdrom_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", dev->id); - return 0; - } - - ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, temp_b); - } else if (cdrom_sector_type == 4) { - if (audio || !mode2 || ((mode2 & 0x03) != 1)) { - cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", dev->id); - return 0; - } - - read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); - } else if (cdrom_sector_type == 5) { - if (audio || !mode2 || ((mode2 & 0x03) != 2)) { - cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", dev->id); - return 0; - } - - ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, temp_b); - } else if (cdrom_sector_type == 8) { if (audio) { - cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", dev->id); - return 0; - } + if (!track_type_is_valid(dev, cdrom_sector_type, cdrom_sector_flags, 1, 0x00)) + ret = 0; + else + ret = read_audio(dev, lba, temp_b); + } else { + int form = 0; - if (unk) { - /* This is needed to correctly read Mode 2 XA Form 1 sectors over IOCTL. */ ret = read_data(dev, lba); - if (raw_buffer[0x000f] == 0x02) { - cdrom_log("CD-ROM %i: [Any Data] Unknown data type determined to be XA Mode 2 Form 1\n", dev->id); - process_mode2_xa_form1(dev, cdrom_sector_flags, temp_b); - } else { - cdrom_log("CD-ROM %i: [Any Data] Unknown data type determined to be Mode 1\n", dev->id); - process_mode1(dev, cdrom_sector_flags, temp_b); + if ((raw_buffer[0x000f] == 0x00) || (raw_buffer[0x000f] > 0x02)) { + cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", + cdrom_req_modes[cdrom_sector_type], raw_buffer[0x000f]); + return 0; + } + + if (mode2) { + if (raw_buffer[0x000f] == 0x01) + log_fatal(dev->log, "Mode 1 sector on CD-I/XA disc\n"); + else if (raw_buffer[0x0012] != raw_buffer[0x0016]) { + cdrom_log(dev->log, "[%s] XA Mode 2 sector with malformed " + "sub-header\n", cdrom_req_modes[cdrom_sector_type], + raw_buffer[0x000f]); + return 0; + } else + form = ((raw_buffer[0x0012] & 0x20) >> 5) + 1; + } else if (raw_buffer[0x000f] == 0x02) + mode2 = 1; + + const int mode_id = mode2 + form; + + cdrom_log(dev->log, "[%s] %s detected\n", cdrom_req_modes[cdrom_sector_type], + cdrom_modes[mode_id]); + + if (!track_type_is_valid(dev, cdrom_sector_type, cdrom_sector_flags, 0, + (mode2 << 2) + form)) + return 0; + + /* It just so happens that only modes with even ID's have a sector user data size of 2048. */ + if (cdrom_mode_masks[cdrom_sector_type] & (1 << mode_id)) + cdrom_process_data[mode_id](dev, cdrom_sector_flags, temp_b); + else { + cdrom_log(dev->log, "[%s] Attempting to read a %s sector\n", + cdrom_req_modes[cdrom_sector_type], cdrom_modes[mode_id]); + return 0; } - } else if (mode2 && ((mode2 & 0x03) == 1)) - ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); - else if (!mode2) - ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); - else { - cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size " - "is not 2048 bytes\n", dev->id); - return 0; - } - } else { - if (mode2) { - if ((mode2 & 0x03) == 0x01) - ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); - else if ((mode2 & 0x03) == 0x02) - ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, temp_b); - else - ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, temp_b); - } else { - if (audio) - ret = read_audio(dev, lba, temp_b); - else - ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); } } if ((cdrom_sector_flags & 0x06) == 0x02) { /* Add error flags. */ - cdrom_log("CD-ROM %i: Error flags\n", dev->id); + cdrom_log(dev->log, "Error flags\n"); memcpy(b + cdrom_sector_size, extra_buffer, 294); cdrom_sector_size += 294; } else if ((cdrom_sector_flags & 0x06) == 0x04) { /* Add error flags. */ - cdrom_log("CD-ROM %i: Full error flags\n", dev->id); + cdrom_log(dev->log, "Full error flags\n"); memcpy(b + cdrom_sector_size, extra_buffer, 296); cdrom_sector_size += 296; } if ((cdrom_sector_flags & 0x700) == 0x100) { - cdrom_log("CD-ROM %i: Raw subchannel data\n", dev->id); + cdrom_log(dev->log, "Raw subchannel data\n"); memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); cdrom_sector_size += 96; } else if ((cdrom_sector_flags & 0x700) == 0x200) { - cdrom_log("CD-ROM %i: Q subchannel data\n", dev->id); + cdrom_log(dev->log, "Q subchannel data\n"); memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); cdrom_sector_size += 16; } else if ((cdrom_sector_flags & 0x700) == 0x400) { - cdrom_log("CD-ROM %i: R/W subchannel data\n", dev->id); + cdrom_log(dev->log, "R/W subchannel data\n"); memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); cdrom_sector_size += 96; } @@ -2018,22 +2268,381 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c return ret; } -/* Peform a master init on the entire module. */ -void -cdrom_global_init(void) +/* + Read DVD Structure + + Yes, +2 instead of +4 is correct, I have verified this via Windows IOCTL, and it also matches + the MMC specification. + */ +int +cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_t layer, const uint8_t format, + uint8_t *buffer, uint32_t *info) { - /* Clear the global data. */ - memset(cdrom, 0x00, sizeof(cdrom)); + int max_layer = 0; + int ret = 0; + uint64_t total_sectors; + + if (format < 0xc0) { + if (dev->cd_status != CD_STATUS_DVD) { + *info = format; + ret = -(SENSE_ILLEGAL_REQUEST << 16) | (ASC_INCOMPATIBLE_FORMAT << 8); + } else if ((dev->ops != NULL) && (dev->ops->read_dvd_structure != NULL)) + ret = dev->ops->read_dvd_structure(dev->local, layer, format, buffer, info); + } + + if (ret == 0) switch (format) { + case 0x00: /* Physical format information */ + total_sectors = (uint64_t) dev->cdrom_capacity; + + if (total_sectors > DVD_LAYER_0_SECTORS) + max_layer++; + + if (layer > max_layer) { + *info = layer; + ret = -(SENSE_ILLEGAL_REQUEST << 16) | (ASC_INV_FIELD_IN_CMD_PACKET << 8); + } else { + if (total_sectors == 0) { + *info = 0x00000000; + ret = -(SENSE_NOT_READY << 16) | (ASC_MEDIUM_NOT_PRESENT << 8); + } else { + buffer[4] = 0x01; /* DVD-ROM, part version 1. */ + buffer[5] = 0x0f; /* 120mm disc, minimum rate unspecified .*/ + if (max_layer == 1) + /* Two layers, OTP track path, read-only (per MMC-2 spec). */ + buffer[6] = 0x31; + else + /* One layer, read-only (per MMC-2 spec). */ + buffer[6] = 0x01; + buffer[7] = 0x10; /* Default densities. */ + + /* Start sector. */ + buffer[8] = 0x00; + buffer[9] = (0x030000 >> 16) & 0xff; + buffer[10] = (0x030000 >> 8) & 0xff; + buffer[11] = 0x030000 & 0xff; + + /* End sector. */ + buffer[12] = 0x00; + if (layer == 1) { + buffer[13] = ((total_sectors - DVD_LAYER_0_SECTORS) >> 16) & 0xff; + buffer[14] = ((total_sectors - DVD_LAYER_0_SECTORS) >> 8) & 0xff; + buffer[15] = (total_sectors - DVD_LAYER_0_SECTORS) & 0xff; + } else if (max_layer == 1) { + buffer[13] = (DVD_LAYER_0_SECTORS >> 16) & 0xff; + buffer[14] = (DVD_LAYER_0_SECTORS >> 8) & 0xff; + buffer[15] = DVD_LAYER_0_SECTORS & 0xff; + } else { + buffer[13] = (total_sectors >> 16) & 0xff; + buffer[14] = (total_sectors >> 8) & 0xff; + buffer[15] = total_sectors & 0xff; + } + + /* Layer 0 end sector. */ + buffer[16] = 0x00; + buffer[17] = (total_sectors >> 16) & 0xff; + buffer[18] = (total_sectors >> 8) & 0xff; + buffer[19] = total_sectors & 0xff; + + buffer[20] = 0x00; /* No BCA */ + + /* 2048 bytes of data + 2 byte header */ + ret = (2048 + 2); + } + } + break; + + case 0x01: /* DVD copyright information */ + buffer[4] = 0; /* No copyright data. */ + buffer[5] = 0; /* No region restrictions. */ + + /* 4 bytes of data + 2 byte header. */ + ret = (4 + 2); + break; + + case 0x04: /* DVD disc manufacturing information. */ + /* 2048 bytes of data + 2 byte header */ + ret = (2048 + 2); + break; + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buffer[4] = 0x00; /* Physical format */ + buffer[5] = 0x40; /* Not writable, is readable */ + buffer[6] = ((2048 + 4) >> 8) & 0xff; + buffer[7] = (2048 + 4) & 0xff; + + buffer[8] = 0x01; /* Copyright info */ + buffer[9] = 0x40; /* Not writable, is readable */ + buffer[10] = ((4 + 2) >> 8) & 0xff; + buffer[11] = (4 + 2) & 0xff; + + buffer[12] = 0x03; /* BCA info */ + buffer[13] = 0x40; /* Not writable, is readable */ + buffer[14] = ((188 + 2) >> 8) & 0xff; + buffer[15] = (188 + 2) & 0xff; + + buffer[16] = 0x04; /* Manufacturing info */ + buffer[17] = 0x40; /* Not writable, is readable */ + buffer[18] = ((2048 + 2) >> 8) & 0xff; + buffer[19] = (2048 + 2) & 0xff; + + /* data written + 4 byte header */ + ret = (16 + 2); + break; + + default: + *info = format; + ret = -(SENSE_ILLEGAL_REQUEST << 16) | (ASC_INV_FIELD_IN_CMD_PACKET << 8); + break; + } + + return ret; } -static void -cdrom_drive_reset(cdrom_t *dev) +void +cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer) { - dev->priv = NULL; - dev->insert = NULL; - dev->close = NULL; - dev->get_volume = NULL; - dev->get_channel = NULL; + uint8_t rti[65536] = { 0 }; + raw_track_info_t *t = (raw_track_info_t *) rti; + int num = 0; + int first = 0; + int sessions = 0; + int ls_first = 0; + int ls_last = 0; + int t_b0 = -1; + + dev->ops->get_raw_track_info(dev->local, &num, rti); + + for (int i = 0; i < num; i++) + if (t[i].session > sessions) + sessions = t[i].session; + else if ((first == 0) && (t[i].point >= 1) && (t[i].point <= 99)) + first = t[i].point; + + for (int i = 0; i < num; i++) + if ((t[i].session == sessions) && (t[i].point >= 1) && (t[i].point <= 99)) { + ls_first = t[i].point; + break; + } + + for (int i = (num - 1); i >= 0; i--) + if ((t[i].session == sessions) && (t[i].point >= 1) && (t[i].point <= 99)) { + ls_last = t[i].point; + break; + } + + for (int i = (num - 1); i >= 0; i--) + if (t[i].point == 0xb0) { + t_b0 = i; + break; + } + + memset(buffer, 0x00, 34); + + buffer[ 0] = 0x00; /* Disc Information Length (MSB) */ + buffer[ 1] = 0x20; /* Disc Information Lenght (LSB) */ + buffer[ 2] = 0x0e; /* Last session complete, disc finalized */ + buffer[ 3] = first; /* Number of First Track on Disc */ + buffer[ 4] = sessions; /* Number of Sessions (LSB) */ + buffer[ 5] = ls_first; /* First Track Number in Last Session (LSB) */ + buffer[ 5] = ls_last; /* Last Track Number in Last Session (LSB) */ + buffer[ 7] = 0x20; /* Unrestricted use */ + buffer[ 8] = t[0].ps; /* Disc Type */ + buffer[ 9] = 0x00; /* Number Of Sessions (MSB) */ + buffer[10] = 0x00; /* First Track Number in Last Session (MSB) */ + buffer[11] = 0x00; /* Last Track Number in Last Session (MSB) */ + + if (t_b0 == -1) { + /* Single-session disc. */ + + /* Last Session Lead-in Start Time MSF is 00:00:00 */ + + /* Last Possible Start Time for Start of Lead-out */ + buffer[20] = t[2].pm; + buffer[21] = t[2].ps; + buffer[22] = t[2].pf; + } else { + /* Multi-session disc. */ + + /* Last Session Lead-in Start Time MSF */ + buffer[17] = t[t_b0].m; + buffer[18] = t[t_b0].s; + buffer[19] = t[t_b0].f; + + /* Last Possible Start Time for Start of Lead-out */ + buffer[20] = t[t_b0].pm; + buffer[21] = t[t_b0].ps; + buffer[22] = t[t_b0].pf; + } +} + +int +cdrom_read_track_information(const cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) +{ + uint8_t rti[65536] = { 0 }; + const raw_track_info_t *t = (raw_track_info_t *) rti; + const raw_track_info_t *track = NULL; + const raw_track_info_t lead_in = { 0 }; + const uint32_t pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + uint32_t real_pos = pos; + int num = 0; + int ret; + + dev->ops->get_raw_track_info(dev->local, &num, rti); + + switch (cdb[1] & 0x03) { + default: + ret = -cdb[1]; + break; + case 0x00: + if (num < 4) + ret = -pos; + else { + for (int i = 0; i < num; i++) { + const raw_track_info_t *ct = &(t[i]); + const uint32_t start = ((ct->pm * 60 * 75) + (ct->ps * 75) + + ct->pf) - 150; + if (pos > start) { + track = ct; + break; + } + } + + if (track == NULL) + ret = -cdb[1]; + else + ret = 36; + } + break; + case 0x01: + switch (pos) { + default: + /* + TODO: Does READ TRACK INFORMATION use track AAh + or the raw A0h, A1h, and A2h? + */ + if (pos == 0xaa) + real_pos = 0xa2; + + for (int i = 0; i < num; i++) { + const raw_track_info_t *ct = &(t[i]); + if (ct->point == real_pos) { + track = ct; + break; + } + } + + if (track == NULL) + ret = -pos; + else + ret = 36; + break; + case 0x00: + track = &lead_in; + ret = 36; + break; + case 0xff: + ret = -pos; + break; + } + break; + case 0x02: + for (int i = 0; i < num; i++) { + const raw_track_info_t *ct = &(t[i]); + if ((ct->session == pos) && (ct->point >= 1) && (ct->point <= 99)) { + track = ct; + break; + } + } + + if (track == NULL) + ret = -pos; + else + ret = 36; + break; + } + + if (ret == 36) { + uint32_t start = ((track->pm * 60 * 75) + (track->ps * 75) + + track->pf) - 150; + uint32_t len = 0x00000000; + uint8_t mode = 0xf; + + memset(buffer, 0, 36); + buffer[0] = 0x00; + buffer[1] = 0x22; + buffer[2] = track->point; /* Track number (LSB). */ + buffer[3] = track->session; /* Session number (LSB). */ + /* Not damaged, primary copy. */ + buffer[5] = track->adr_ctl & 0x04; + + if ((track->point >= 1) && (track->point >= 99)) { + for (int i = 0; i < num; i++) { + const raw_track_info_t *ct = &(t[i]); + const uint32_t ts = ((ct->pm * 60 * 75) + (ct->ps * 75) + + ct->pf) - 150; + if ((ts > start) && ((ct->point == 0xa2) || ((ct->point >= 1) && + (ct->point <= 99)))) { + len = ts - start; + break; + } + } + + if (track->adr_ctl & 0x04) { + ret = read_data(dev, start); + mode = raw_buffer[3]; + } + } else if (track->point != 0xa2) + start = 0x00000000; + + /* Not reserved track, not blank, not packet writing, not fixed packet. */ + buffer[ 6] = mode << 0; + /* Last recorded address not valid, next recordable address not valid. */ + buffer[ 7] = 0x00; + + buffer[ 8] = (start >> 24) & 0xff; + buffer[ 9] = (start >> 16) & 0xff; + buffer[10] = (start >> 8) & 0xff; + buffer[11] = start & 0xff; + + buffer[24] = (len >> 24) & 0xff; + buffer[25] = (len >> 16) & 0xff; + buffer[26] = (len >> 8) & 0xff; + buffer[27] = len & 0xff; + } + + return ret; +} + +int +cdrom_ext_medium_changed(const cdrom_t *dev) +{ + int ret = 0; + + if (dev && dev->ops && dev->ops->ext_medium_changed && + (dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED)) + ret = dev->ops->ext_medium_changed(dev->local); + + return ret; +} + +int +cdrom_is_empty(const uint8_t id) +{ + const cdrom_t *dev = &cdrom[id]; + int ret = 0; + + /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ + if (strlen(dev->image_path) == 0) + /* Switch from empty to empty. Do nothing. */ + ret = 1; + + return ret; } #ifdef ENABLE_CDROM_LOG @@ -2047,7 +2656,7 @@ cdrom_toc_dump(cdrom_t *dev) fwrite(b, 1, len, f); fflush(f); fclose(f); - pclog("Written TOC of %i bytes to %s\n", len, fn2); + cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2); memset(b, 0x00, 65536); len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); @@ -2056,7 +2665,7 @@ cdrom_toc_dump(cdrom_t *dev) fwrite(b, 1, len, f); fflush(f); fclose(f); - pclog("Written cooked TOC of %i bytes to %s\n", len, fn2); + cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2); memset(b, 0x00, 65536); len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); @@ -2065,24 +2674,96 @@ cdrom_toc_dump(cdrom_t *dev) fwrite(b, 1, len, f); fflush(f); fclose(f); - pclog("Written session TOC of %i bytes to %s\n", len, fn2); + cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2); } #endif +int +cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) +{ + const int was_empty = cdrom_is_empty(dev->id); + int ret = 0; + + /* Make sure to not STRCPY if the two are pointing + at the same place. */ + if (fn != dev->image_path) + strcpy(dev->image_path, fn); + + /* Open the target. */ + if ((strlen(dev->image_path) != 0) && + (strstr(dev->image_path, "ioctl://") == dev->image_path)) + dev->local = ioctl_open(dev, dev->image_path); + else + dev->local = image_open(dev, dev->image_path); + + if (dev->local == NULL) { + dev->ops = NULL; + dev->image_path[0] = 0; + + ret = 1; + } else { + /* All good, reset state. */ + dev->seek_pos = 0; + dev->cd_buflen = 0; + + if (dev->ops->is_dvd(dev->local)) + dev->cd_status = CD_STATUS_DVD; + else + dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : + CD_STATUS_DATA_ONLY; + + dev->cdrom_capacity = dev->ops->get_last_block(dev->local); + + cdrom_log(dev->log, "CD-ROM capacity: %i sectors (%" PRIi64 " bytes)\n", + dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity) << 11ULL); + } + +#ifdef ENABLE_CDROM_LOG + cdrom_toc_dump(dev); +#endif + + if (!skip_insert) { + /* Signal media change to the emulated machine. */ + cdrom_insert(dev->id); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + cdrom_insert(dev->id); + } + + return ret; +} + +/* Peform a master init on the entire module. */ +void +cdrom_global_init(void) +{ + /* Clear the global data. */ + memset(cdrom, 0x00, sizeof(cdrom)); +} + void cdrom_hard_reset(void) { - cdrom_t *dev; - for (uint8_t i = 0; i < CDROM_NUM; i++) { - dev = &cdrom[i]; - if (dev->bus_type) { - cdrom_log("CD-ROM %i: Hard reset\n", i); + cdrom_t *dev = &cdrom[i]; - dev->id = i; + if (dev->bus_type) { + cdrom_log(dev->log, "Hard reset\n"); + + dev->id = i; + + dev->is_early = cdrom_is_early(dev->type); + dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && + !strcmp(cdrom_drive_types[dev->type].vendor, "NEC"); cdrom_drive_reset(dev); + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i ", i + 1); + dev->log = log_open(n); + switch (dev->bus_type) { case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: @@ -2105,18 +2786,7 @@ cdrom_hard_reset(void) dev->image_path[strlen(dev->image_path) - 1] = '/'; #endif - if ((strlen(dev->image_path) != 0) && (strstr(dev->image_path, "ioctl://") == dev->image_path)) - cdrom_ioctl_open(dev, dev->image_path); - else - cdrom_image_open(dev, dev->image_path); - - cdrom_insert(i); - cdrom_insert(i); - -#ifdef ENABLE_CDROM_LOG - if (i == 0) - cdrom_toc_dump(dev); -#endif + cdrom_load(dev, dev->image_path, 0); } } } @@ -2127,10 +2797,8 @@ cdrom_hard_reset(void) void cdrom_close(void) { - cdrom_t *dev; - for (uint8_t i = 0; i < CDROM_NUM; i++) { - dev = &cdrom[i]; + cdrom_t *dev = &cdrom[i]; if (dev->bus_type == CDROM_BUS_SCSI) memset(&scsi_devices[dev->scsi_device_id], 0x00, sizeof(scsi_device_t)); @@ -2138,92 +2806,79 @@ cdrom_close(void) if (dev->close) dev->close(dev->priv); - if (dev->ops && dev->ops->exit) - dev->ops->exit(dev); + cdrom_unload(dev); dev->ops = NULL; dev->priv = NULL; cdrom_drive_reset(dev); + + if (dev->log != NULL) { + cdrom_log(dev->log, "Log closed\n"); + + log_close(dev->log); + dev->log = NULL; + } } } /* Signal disc change to the emulated machine. */ void -cdrom_insert(uint8_t id) +cdrom_insert(const uint8_t id) { - cdrom_t *dev = &cdrom[id]; + const cdrom_t *dev = &cdrom[id]; if (dev->bus_type && dev->insert) dev->insert(dev->priv); } void -cdrom_exit(uint8_t id) +cdrom_exit(const uint8_t id) { cdrom_t *dev = &cdrom[id]; strcpy(dev->prev_image_path, dev->image_path); if (dev->ops) { - if (dev->ops->exit) - dev->ops->exit(dev); + cdrom_unload(dev); dev->ops = NULL; } memset(dev->image_path, 0, sizeof(dev->image_path)); - cdrom_log("cdrom_exit(%i): cdrom_insert(%i)\n", id, id); + cdrom_log(dev->log, "cdrom_exit(): cdrom_insert()\n"); cdrom_insert(id); } -int -cdrom_is_empty(uint8_t id) -{ - cdrom_t *dev = &cdrom[id]; - int ret = 0; - - /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) - /* Switch from empty to empty. Do nothing. */ - ret = 1; - - return ret; -} - /* The mechanics of ejecting a CD-ROM from a drive. */ void -cdrom_eject(uint8_t id) +cdrom_eject(const uint8_t id) { - cdrom_t *dev = &cdrom[id]; + const cdrom_t *dev = &cdrom[id]; - /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) - /* Switch from empty to empty. Do nothing. */ - return; + if (strlen(dev->image_path) != 0) { + cdrom_exit(id); - cdrom_exit(id); + plat_cdrom_ui_update(id, 0); - plat_cdrom_ui_update(id, 0); - - config_save(); + config_save(); + } } /* The mechanics of re-loading a CD-ROM drive. */ void -cdrom_reload(uint8_t id) +cdrom_reload(const uint8_t id) { - cdrom_t *dev = &cdrom[id]; - int was_empty = cdrom_is_empty(id); + cdrom_t *dev = &cdrom[id]; if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || (strlen(dev->prev_image_path) == 0) || (strlen(dev->image_path) > 0)) { /* Switch from empty to empty. Do nothing. */ return; } - if (dev->ops && dev->ops->exit) - dev->ops->exit(dev); + cdrom_unload(dev); + dev->ops = NULL; memset(dev->image_path, 0, sizeof(dev->image_path)); @@ -2242,22 +2897,7 @@ cdrom_reload(uint8_t id) dev->image_path[strlen(dev->image_path) - 1] = '/'; #endif - if ((strlen(dev->image_path) != 0) && (strstr(dev->image_path, "ioctl://") == dev->image_path)) - cdrom_ioctl_open(dev, dev->image_path); - else - cdrom_image_open(dev, dev->image_path); - -#ifdef ENABLE_CDROM_LOG - cdrom_toc_dump(dev); -#endif - - /* Signal media change to the emulated machine. */ - cdrom_log("cdrom_reload(%i): cdrom_insert(%i)\n", id, id); - cdrom_insert(id); - - /* The drive was previously empty, transition directly to UNIT ATTENTION. */ - if (was_empty) - cdrom_insert(id); + cdrom_load(dev, dev->image_path, 0); } plat_cdrom_ui_update(id, 1); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 0c7870902..e4a425c78 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -6,63 +6,1705 @@ * * This file is part of the 86Box distribution. * - * CD-ROM image support. + * CD-ROM image file handling module. * + * Authors: Miran Grca, + * RichardG, + * Cacodemon345 * - * - * Authors: RichardG867, - * Miran Grca, - * bit, - * - * Copyright 2015-2019 Richardg867. - * Copyright 2015-2019 Miran Grca. - * Copyright 2017-2019 bit. + * Copyright 2016-2025 Miran Grca. + * Copyright 2016-2025 RichardG. + * Copyright 2024-2025 Cacodemon345. */ +#define __STDC_FORMAT_MACROS +#include #include +#ifdef ENABLE_IMAGE_LOG #include -#include +#endif #include -#include +#include #include -#include -#define HAVE_STDARG_H +#include +#include +#ifndef _WIN32 +# include +#endif #include <86box/86box.h> -#include <86box/config.h> +#include <86box/log.h> #include <86box/path.h> #include <86box/plat.h> -#include <86box/scsi_device.h> -#include <86box/cdrom_image_backend.h> #include <86box/cdrom.h> #include <86box/cdrom_image.h> +#include <86box/cdrom_image_viso.h> -#ifdef ENABLE_CDROM_IMAGE_LOG -int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; +#include + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +static char temp_keyword[1024]; + +#define INDEX_SPECIAL -2 /* Track A0h onwards. */ +#define INDEX_NONE -1 /* Empty block. */ +#define INDEX_ZERO 0 /* Block not in the file, return all 0x00's. */ +#define INDEX_NORMAL 1 /* Block in the file. */ + +typedef struct track_index_t { + /* + Is the current block in the file? If not, return all 0x00's. -1 means not + yet loaded. + */ + int32_t type; + /* The amount of bytes to skip at the beginning of each sector. */ + int32_t skip; + /* + Starting and ending sector LBA - negative in order to accomodate LBA -150 to -1 + to read the pregap of track 1. + */ + uint64_t start; + uint64_t length; + uint64_t file_start; + uint64_t file_length; + track_file_t *file; +} track_index_t; + +typedef struct track_t { + uint8_t session; + uint8_t attr; + uint8_t tno; + uint8_t point; + uint8_t extra[4]; + uint8_t mode; + uint8_t form; + uint8_t subch_type; + uint8_t skip; + uint32_t sector_size; + track_index_t idx[3]; +} track_t; + +typedef struct cd_image_t { + cdrom_t *dev; + void *log; + int is_dvd; + int has_audio; + int32_t tracks_num; + uint32_t bad_sectors_num; + track_t *tracks; + uint32_t *bad_sectors; +} cd_image_t; + +#ifdef ENABLE_IMAGE_LOG +int image_do_log = ENABLE_IMAGE_LOG; void -cdrom_image_log(const char *fmt, ...) +image_log(void *priv, const char *fmt, ...) { va_list ap; - if (cdrom_image_do_log) { + if (image_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } + +static char *cit[4] = { "SPECIAL", "NONE", "ZERO", "NORMAL" }; #else -# define cdrom_image_log(fmt, ...) +# define image_log(priv, fmt, ...) #endif -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) +typedef struct audio_file_t { + SNDFILE *file; + SF_INFO info; +} audio_file_t; + +/* Audio file functions */ +static int +audio_read(void *priv, uint8_t *buffer, const uint64_t seek, const size_t count) +{ + const track_file_t *tf = (track_file_t *) priv; + const audio_file_t *audio = (audio_file_t *) tf->priv; + const uint64_t samples_seek = seek / 4; + const uint64_t samples_count = count / 4; + + if ((seek & 3) || (count & 3)) { + image_log(tf->log, "CD Audio file: Reading on non-4-aligned boundaries.\n"); + } + + const sf_count_t res = sf_seek(audio->file, samples_seek, SEEK_SET); + + if (res == -1) + return 0; + + return !!sf_readf_short(audio->file, (short *) buffer, samples_count); +} + +static uint64_t +audio_get_length(void *priv) +{ + const track_file_t *tf = (track_file_t *) priv; + const audio_file_t *audio = (audio_file_t *) tf->priv; + + /* Assume 16-bit audio, 2 channel. */ + return audio->info.frames * 4ull; +} static void -image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) +audio_close(void *priv) { - cd_img_t *img = (cd_img_t *) dev->local; - track_t *ct = NULL; + track_file_t *tf = (track_file_t *) priv; + audio_file_t *audio = (audio_file_t *) tf->priv; + + memset(tf->fn, 0x00, sizeof(tf->fn)); + if (audio && audio->file) + sf_close(audio->file); + free(audio); + free(tf); +} + +static track_file_t * +audio_init(const uint8_t id, const char *filename, int *error) +{ + track_file_t *tf = (track_file_t *) calloc(sizeof(track_file_t), 1); + audio_file_t *audio = (audio_file_t *) calloc(sizeof(audio_file_t), 1); +#ifdef _WIN32 + wchar_t filename_w[4096]; +#endif + + if (tf == NULL || audio == NULL) { + goto cleanup_error; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + strncpy(tf->fn, filename, sizeof(tf->fn) - 1); +#ifdef _WIN32 + mbstowcs(filename_w, filename, 4096); + audio->file = sf_wchar_open(filename_w, SFM_READ, &audio->info); +#else + audio->file = sf_open(filename, SFM_READ, &audio->info); +#endif + + if (audio->file == NULL) { + image_log(tf->log, "Audio file open error!"); + goto cleanup_error; + } + + if (audio->info.channels != 2 || audio->info.samplerate != 44100 || !audio->info.seekable) { + image_log(tf->log, "Audio file not seekable or in non-CD format!"); + sf_close(audio->file); + goto cleanup_error; + } + + *error = 0; + + tf->priv = audio; + tf->fp = NULL; + tf->close = audio_close; + tf->get_length = audio_get_length; + tf->read = audio_read; + + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i Audio", id + 1); + tf->log = log_open(n); + + return tf; +cleanup_error: + free(tf); + free(audio); + *error = 1; + return NULL; +} + +/* Binary file functions. */ +static int +bin_read(void *priv, uint8_t *buffer, const uint64_t seek, const size_t count) +{ + const track_file_t *tf = (track_file_t *) priv; + + if (tf->fp == NULL) + return 0; + + image_log(tf->log, "binary_read(%08lx, pos=%" PRIu64 " count=%lu)\n", + tf->fp, seek, count); + + if (fseeko64(tf->fp, seek, SEEK_SET) == -1) { + image_log(tf->log, "binary_read failed during seek!\n"); + + return -1; + } + + if (fread(buffer, count, 1, tf->fp) != 1) { + image_log(tf->log, "binary_read failed during read!\n"); + + return -1; + } + + if (UNLIKELY(tf->motorola)) { + for (uint64_t i = 0; i < count; i += 2) { + const uint8_t buffer0 = buffer[i]; + const uint8_t buffer1 = buffer[i + 1]; + buffer[i] = buffer1; + buffer[i + 1] = buffer0; + } + } + + return 1; +} + +static uint64_t +bin_get_length(void *priv) +{ + const track_file_t *tf = (track_file_t *) priv; + + if (tf->fp == NULL) + return 0; + + fseeko64(tf->fp, 0, SEEK_END); + const off64_t len = ftello64(tf->fp); + image_log(tf->log, "binary_length(%08lx) = %" PRIu64 "\n", tf->fp, len); + + return len; +} + +static void +bin_close(void *priv) +{ + track_file_t *tf = (track_file_t *) priv; + + if (tf == NULL) + return; + + if (tf->fp != NULL) { + fclose(tf->fp); + tf->fp = NULL; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + + free(priv); +} + +static track_file_t * +bin_init(const uint8_t id, const char *filename, int *error) +{ + track_file_t *tf = (track_file_t *) calloc(1, sizeof(track_file_t)); + struct stat stats; + + if (tf == NULL) { + *error = 1; + return NULL; + } + + memset(tf->fn, 0x00, sizeof(tf->fn)); + strncpy(tf->fn, filename, sizeof(tf->fn) - 1); + tf->fp = plat_fopen64(tf->fn, "rb"); + image_log(tf->log, "binary_open(%s) = %08lx\n", tf->fn, tf->fp); + + if (stat(tf->fn, &stats) != 0) { + /* Use a blank structure if stat failed. */ + memset(&stats, 0, sizeof(struct stat)); + } + *error = ((tf->fp == NULL) || ((stats.st_mode & S_IFMT) == S_IFDIR)); + + /* Set the function pointers. */ + if (!*error) { + tf->read = bin_read; + tf->get_length = bin_get_length; + tf->close = bin_close; + + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i Bin ", id + 1); + tf->log = log_open(n); + } else { + /* From the check above, error may still be non-zero if opening a directory. + * The error is set for viso to try and open the directory following this function. + * However, we need to make sure the descriptor is closed. */ + if ((tf->fp != NULL) && ((stats.st_mode & S_IFMT) == S_IFDIR)) { + /* tf is freed by bin_close */ + bin_close(tf); + } else + free(tf); + tf = NULL; + } + + return tf; +} + +static track_file_t * +index_file_init(const uint8_t id, const char *filename, int *error, int *is_viso) +{ + track_file_t *tf = NULL; + + *is_viso = 0; + + /* Current we only support .BIN files, either combined or one per + track. In the future, more is planned. */ + tf = bin_init(id, filename, error); + + if (*error) { + if ((tf != NULL) && (tf->close != NULL)) { + tf->close(tf); + tf = NULL; + } + + tf = viso_init(id, filename, error); + + if (!*error) + *is_viso = 1; + } + + return tf; +} + +static void +index_file_close(track_index_t *idx) +{ + if ((idx == NULL) || (idx->file == NULL) || + (idx->file->close == NULL)) + return; + + idx->file->close(idx->file); + + image_log(idx->file->log, "Log closed\n"); + + if (idx->file->log != NULL) { + log_close(idx->file->log); + idx->file->log = NULL; + } + + idx->file = NULL; +} + +/* Internal functions. */ +static int +image_get_track(const cd_image_t *img, const uint32_t sector) +{ + int ret = -1; + + for (int i = 0; i < img->tracks_num; i++) { + track_t *ct = &(img->tracks[i]); + for (int j = 0; j < 3; j++) { + const track_index_t *ci = &(ct->idx[j]); + if ((ci->type >= INDEX_ZERO) && (ci->length != 0ULL) && + ((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { + ret = i; + break; + } + } + } + + return ret; +} + +static void +image_get_track_and_index(const cd_image_t *img, const uint32_t sector, + int *track, int *index) +{ + *track = -1; + *index = -1; + + for (int i = 0; i < img->tracks_num; i++) { + track_t *ct = &(img->tracks[i]); + for (int j = 0; j < 3; j++) { + track_index_t *ci = &(ct->idx[j]); + if ((ci->type >= INDEX_ZERO) && (ci->length != 0ULL) && + ((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { + *track = i; + *index = j; + break; + } + } + } +} + +static int +image_is_sector_bad(const cd_image_t *img, const uint32_t sector) +{ + int ret = 0; + + if (img->bad_sectors_num > 0) for (int i = 0; i < img->bad_sectors_num; i++) + if (img->bad_sectors[i] == sector) { + ret = 1; + break; + } + + return ret; +} + +static int +image_is_track_audio(const cd_image_t *img, const uint32_t pos) +{ + int ret = 0; + + if (img->has_audio) { + const int track = image_get_track(img, pos); + + if (track >= 0) { + const track_t *trk = &(img->tracks[track]); + + ret = (trk->mode == 0); + } + } + + return ret; +} + +static int +image_can_read_pvd(track_file_t *file, const uint64_t start, + const uint64_t sector_size, const int xa) +{ + uint8_t buf[2448] = { 0 }; + /* First VD is located at sector 16. */ + uint64_t seek = start + (16ULL * sector_size); + uint8_t *pvd = (uint8_t *) buf; + + if (sector_size >= RAW_SECTOR_SIZE) { + if (xa) + pvd = &(buf[24]); + else + pvd = &(buf[16]); + } else if (sector_size >= 2332) { + if (xa) + pvd = &(buf[8]); + } + + file->read(file, buf, seek, sector_size); + + int ret = (((pvd[0] == 1) && + !strncmp((char *) &(pvd[1]), "CD001", 5) && + (pvd[6] == 1)) || + ((pvd[8] == 1) && + !strncmp((char *) &(pvd[9]), "CDROM", 5) && + (pvd[14] == 1))); + + if (ret) { + if (sector_size >= RAW_SECTOR_SIZE) { + if (xa) + /* Mode 2 XA, Form from the sub-header. */ + ret = 0x20 | (((buf[18] & 0x20) >> 5) + 1); + else + /* Mode from header. */ + ret = buf[15] << 4; + } else if (sector_size >= 2332) { + if (xa) + /* Mode 2 XA, Form from the sub-header. */ + ret = 0x20 | (((buf[2] & 0x20) >> 5) + 1); + else + /* Mode 2 non-XA. */ + ret = 0x20; + } else if (sector_size >= 2324) + /* Mode 2 XA Form 2. */ + ret = 0x22; + else if (!strncmp((char *) &(pvd[0x400]), "CD-XA001", 8)) + /* Mode 2 XA Form 1. */ + ret = 0x21; + else + /* Mode 1. */ + ret = 0x10; + } + + return ret; +} + +static int +image_cue_get_buffer(char *str, char **line, const int up) +{ + char *s = *line; + char *p = str; + int quote = 0; + int done = 0; + int space = 1; + + /* Copy to local buffer until we have end of string or whitespace. */ + while (!done) { + switch (*s) { + case '\0': + if (quote) { + /* Ouch, unterminated string.. */ + return 0; + } + done = 1; + break; + + case '\"': + quote ^= 1; + break; + + case ' ': + case '\t': + if (space) + break; + + if (!quote) { + done = 1; + break; + } + fallthrough; + + default: + if (up && islower((int) *s)) + *p++ = toupper((int) *s); + else + *p++ = *s; + space = 0; + break; + } + + if (!done) + s++; + } + *p = '\0'; + + *line = s; + + return 1; +} + +static int +image_cue_get_keyword(char **dest, char **line) +{ + int success = image_cue_get_buffer(temp_keyword, line, 1); + + if (success) + *dest = temp_keyword; + + return success; +} + +/* Get a string from the input line, handling quotes properly. */ +static uint64_t +image_cue_get_number(char **line) +{ + char temp[128]; + uint64_t num; + + if (!image_cue_get_buffer(temp, line, 0)) + return 0; + + if (sscanf(temp, "%" PRIu64, &num) != 1) + return 0; + + return num; +} + +static int +image_cue_get_frame(uint64_t *frames, char **line) +{ + char temp[128]; + int min = 0; + int sec = 0; + int fr = 0; + + int success = image_cue_get_buffer(temp, line, 0); + if (!success) + return 0; + + success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; + if (!success) + return 0; + + *frames = MSF_TO_FRAMES(min, sec, fr); + + return 1; +} + +static int +image_cue_get_flags(track_t *cur, char **line) +{ + char temp[128]; + char temp2[128]; + + int success = image_cue_get_buffer(temp, line, 0); + if (!success) + return 0; + + memset(temp2, 0x00, sizeof(temp2)); + success = sscanf(temp, "%s", temp2) == 1; + if (!success) + return 0; + + if (strstr(temp2, "PRE") != NULL) + cur->attr |= 0x01; + if (strstr(temp2, "DCP") != NULL) + cur->attr |= 0x02; + if (strstr(temp2, "4CH") != NULL) + cur->attr |= 0x08; + + return 1; +} + +static track_t * +image_insert_track(cd_image_t *img, const uint8_t session, const uint8_t point) +{ + track_t *ct = NULL; + + img->tracks_num++; + if (img->tracks == NULL) { + img->tracks = calloc(1, sizeof(track_t)); + ct = &(img->tracks[0]); + } else { + img->tracks = realloc(img->tracks, img->tracks_num * sizeof(track_t)); + ct = &(img->tracks[img->tracks_num - 1]); + } + + image_log(img->log, " [TRACK ] Insert %02X: img->tracks[%2i]\n", + point, img->tracks_num - 1); + + memset(ct, 0x00, sizeof(track_t)); + + ct->session = session; + ct->point = point; + + for (int i = 0; i < 3; i++) + ct->idx[i].type = (point > 99) ? INDEX_SPECIAL : INDEX_NONE; + + if (point >= 0xb0) + ct->attr = 0x50; + + return ct; +} + +static void +image_process(cd_image_t *img) +{ + track_t *ct = NULL; + track_t *lt = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + uint64_t tf_len = 0ULL; + uint64_t cur_pos = 0ULL; + int pos = 0; + int ls = 0; + int map[256] = { 0 }; + int lead[3] = { 0 }; + uint64_t spg[256] = { 0ULL }; + track_t *lo[256] = { 0 }; + + /* + Pass 2 - adjusting pre-gaps of the first track of every session and creating the + map so we can map from <01-99> to <01-99> + so that their times and length can be adjusted correctly in the third and fourth + passes - especially important for multi-session Cue files. + + We have to do that because Cue sheets do not explicitly indicate those pre-gaps + but they are required so we have the correct frames - the first track of each + session always has a pre-gap of at least 0:02:00. We do not adjust it if it is + already present. + */ + image_log(img->log, "Pass 2 (adjusting pre-gaps and preparing map)...\n"); + + /* Pre-gap of the first track of the first session. */ + ct = &(img->tracks[3]); + ci = &(ct->idx[0]); + + if (ci->type == INDEX_NONE) { + ci->type = INDEX_ZERO; + ci->start = 0ULL; + ci->length = 150ULL; + } + + image_log(img->log, " [PREGAP ] Adjusted pre-gap of track %02X (first in " + "session %i)\n", ct->point, ct->session); + + /* The other pre-gaps and the preparation of the map. */ + for (int i = 0; i < img->tracks_num; i++) { + ct = &(img->tracks[i]); + if (((ct->point >= 1) && (ct->point <= 99)) || (ct->point >= 0xb0)) { + if (ct->point == 0xb0) { + /* The first track of a session always has a pre-gap of at least 0:02:00. */ + track_t *ft = &(img->tracks[i + (ct->session == 1) + 4]); + ci = &(ft->idx[0]); + + if (ci->type == INDEX_NONE) { + if (ft->idx[1].type == INDEX_NORMAL) { + ci->type = INDEX_NORMAL; + ci->file_start = ft->idx[1].file_start - 150ULL; + } else { + ci->type = INDEX_ZERO; + ci->start = 0ULL; + ci->length = 150ULL; + } + } + + image_log(img->log, " [PREGAP ] Adjusted pre-gap of track %02X " + "(first in session %i)\n", ft->point, ct->session); + + /* Point B0h found, add the previous three lead tracks. */ + for (int j = 0; j < 3; j++) { + map[pos] = lead[j]; + image_log(img->log, " [REMAP ] Remap %3i to %3i (%02X)\n", pos, + map[pos], 0xa0 + j); + pos++; + } + } + + /* Add the current track. */ + map[pos] = i; + image_log(img->log, " [NORMAL ] Remap %3i to %3i\n", pos, map[pos]); + pos++; + } else if ((ct->point >= 0xa0) && (ct->point <= 0xa2)) { + /* + Collect lead track (A0 = first track in session, A1 = last track in session, + A2 = lead out). + */ + lead[ct->point & 0x03] = i; + + image_log(img->log, " [LEAD ] Lead %i = %3i (%02X)\n", ct->point & 0x03, i, + ct->point); + } + } + + /* Add the last three lead tracks. */ + for (int i = 0; i < 3; i++) { + map[pos] = lead[i]; + image_log(img->log, " [REMAP ] Remap %3i to %3i (%02X)\n", pos, map[pos], + 0xa0 + i); + pos++; + } + + /* + If these two mismatch, it is a fatal condition since it means something + has gone wrong enough that the Cue sheet processing has been messed up. + */ + if (pos != img->tracks_num) + log_fatal(img->log, "Something has gone wrong and we have remappped %3i tracks " + "instead of the expected %3i\n", pos, img->tracks_num); + + /* + Pass 3 - adjusting the time lengths of each index of track according to the + files. + + We have to do that because Cue sheets do not explicitly indicate the lengths + of track, so we have to deduce them from what the combination of the Cue sheet + and the various files give us. + */ + image_log(img->log, "Pass 3 (adjusting track file lengths according to the files)...\n"); + for (int i = (img->tracks_num - 1); i >= 0; i--) { + ct = &(img->tracks[map[i]]); + if (ct->idx[1].type != INDEX_SPECIAL) { + for (int j = 2; j >= 0; j--) { + ci = &(ct->idx[j]); + + /* + If the file is not NULL and is different from the previous file, + open it and read its length. + */ + if ((ci->file != NULL) && (ci->file != tf)) { + tf = ci->file; + if (tf != NULL) { + tf_len = tf->get_length(tf) / ct->sector_size; + image_log(img->log, " [FILE ] File length: %016" + PRIX64 " sectors\n", tf_len); + } + } + + if ((ci->type < INDEX_SPECIAL) || (ci->type > INDEX_NORMAL)) { + image_log(img->log, " [TRACK ] %02X, INDEX %02X, ATTR %02X,\n", + ci->type, j, + ct->attr); + log_fatal(img->log, " Unrecognized index type during " + "Pass 3: %2i\n", + ci->type); + } else if (ci->type == INDEX_NORMAL) { + /* Index was in the cue sheet and is present in the file. */ + ci->file_length = tf_len - ci->file_start; + tf_len -= ci->file_length; + } else { + /* Index was not in the cue sheet or is not present in the file, + keep its length at zero. */ + ci->file_start = tf_len; + } + + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, ATTR %02X, " + "MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + image_log(img->log, " file_start = %016" + PRIX64 " (%2i:%02i:%02i),\n", + ci->file_start, + (int) ((ci->file_start / 75) / 60), + (int) ((ci->file_start / 75) % 60), + (int) (ci->file_start % 75)); + image_log(img->log, " file_length = %016" + PRIX64 " (%2i:%02i:%02i),\n", + ci->file_length, + (int) ((ci->file_length / 75) / 60), + (int) ((ci->file_length / 75) % 60), + (int) (ci->file_length % 75)); + image_log(img->log, " remaining = %016" + PRIX64 " (%2i:%02i:%02i)\n", + tf_len, + (int) ((tf_len / 75) / 60), + (int) ((tf_len / 75) % 60), + (int) (tf_len % 75)); + } + } + } + + /* + Pass 4 - calculating the actual track starts and lengths for the TOC. + */ + image_log(img->log, "Pass 4 (calculating the actual track starts " + "and lengths for the TOC)...\n"); + for (int i = 0; i < img->tracks_num; i++) { + ct = &(img->tracks[map[i]]); + if (ct->idx[1].type != INDEX_SPECIAL) { + int session_changed = 0; + + /* + If the session has changed, store the last session + and mark that it has changed. + */ + if (ct->session != ls) { + ls = ct->session; + session_changed = 1; + } + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + + if ((ci->type < INDEX_SPECIAL) || (ci->type > INDEX_NORMAL)) { + image_log(img->log, " [TRACK ] %02X, INDEX %02X, ATTR %02X,\n", + ci->type, j, + ct->attr); + log_fatal(img->log, " Unrecognized index type during " + "Pass 4: %2i\n", + ci->type); + } else if (ci->type <= INDEX_NONE) + /* Index was not in the cue sheet, keep its length at zero. */ + ci->start = cur_pos; + else if (ci->type == INDEX_ZERO) { + /* Index was in the cue sheet and is not present in the file. */ + ci->start = cur_pos; + cur_pos += ci->length; + } else if (ci->type == INDEX_NORMAL) { + /* Index was in the cue sheet and is present in the file. */ + ci->start = cur_pos; + ci->length = ci->file_length; + cur_pos += ci->file_length; + } + + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, ATTR %02X, " + "MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + image_log(img->log, " start = %016" + PRIX64 " (%2i:%02i:%02i),\n", + ci->start, + (int) ((ci->start / 75) / 60), + (int) ((ci->start / 75) % 60), + (int) (ci->start % 75)); + image_log(img->log, " length = %016" + PRIX64 " (%2i:%02i:%02i),\n", + ci->length, + (int) ((ci->length / 75) / 60), + (int) ((ci->length / 75) % 60), + (int) (ci->length % 75)); + image_log(img->log, " cur_pos = %016" + PRIX64 " (%2i:%02i:%02i)\n", + cur_pos, + (int) ((cur_pos / 75) / 60), + (int) ((cur_pos / 75) % 60), + (int) (cur_pos % 75)); + + /* Set the pre-gap of the first track of this session. */ + if (session_changed) + spg[ct->session] = ct->idx[0].start; + } + } + } + + /* + Pass 5 - setting the lead out starts for all sessions. + */ + image_log(img->log, "Pass 5 (setting the lead out starts for all sessions)...\n"); + for (int i = 0; i <= ls; i++) { + lo[i] = NULL; + for (int j = (img->tracks_num - 1); j >= 0; j--) { + const track_t *jt = &(img->tracks[j]); + if ((jt->session == i) && (jt->point >= 1) && (jt->point <= 99)) { + lo[i] = &(img->tracks[j]); + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, ATTR %02X, " + "MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + image_log(img->log, " using to calculate the start of session " + "%02X lead out\n", + ct->session); + break; + } + } + } + + /* + Pass 6 - refinining modes and forms, and finalizing all the special tracks. + */ + image_log(img->log, "Pass 6 (refinining modes and forms, and finalizing " + "all the special tracks)...\n"); + for (int i = 0; i < img->tracks_num; i++) { + ct = &(img->tracks[i]); + lt = NULL; + switch (ct->point) { + default: + break; + case 1 ... 99: + ci = &(ct->idx[1]); + + if ((ci->type == INDEX_NORMAL) && (ct->mode >= 1)) { + image_log(img->log, " [TRACK ] %02X/01, INDEX %02X, ATTR %02X, " + "MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, + ct->attr, + ct->mode, ct->form, + cit[ct->idx[1].type + 2]); + + /* Override the loaded modes with that we determine here. */ + int can_read_pvd = image_can_read_pvd(ci->file, + ci->file_start * ct->sector_size, + ct->sector_size, 0); + ct->skip = 0; + if (can_read_pvd) { + ct->mode = can_read_pvd >> 4; + ct->form = can_read_pvd & 0xf; + if (((ct->sector_size == 2332) || (ct->sector_size == 2336)) && + (ct->form >= 1)) + ct->skip = 8; + } else if (ct->sector_size >= 2332) { + can_read_pvd = image_can_read_pvd(ci->file, + ci->file_start * ct->sector_size, + ct->sector_size, 1); + if (can_read_pvd) { + ct->mode = can_read_pvd >> 4; + ct->form = can_read_pvd & 0xf; + if (((ct->sector_size == 2332) || (ct->sector_size == 2336)) && + (ct->form >= 1)) + ct->skip = 8; + } + } + + image_log(img->log, " NEW MODE: %02X/%02X\n", + ct->mode, ct->form); + } + break; + case 0xa0: + for (int j = 0; j < img->tracks_num; j++) { + track_t *jt = &(img->tracks[j]); + if ((jt->session == ct->session) && + (jt->point >= 1) && (jt->point <= 99)) { + lt = jt; + break; + } + } + + if (lt != NULL) { + int disc_type = 0x00; + + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + if (lt->mode == 2) + disc_type = 0x20; + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = (lt->point * 60 * 75) + (disc_type * 75); + ci->length = 0; + + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, " + "ATTR %02X, MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + image_log(img->log, " first track = %02X, " + "disc type = %02X\n", + lt->point, disc_type); + } + } + break; + case 0xa1: + for (int j = (img->tracks_num - 1); j >= 0; j--) { + track_t *jt = &(img->tracks[j]); + if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { + lt = jt; + break; + } + } + + if (lt != NULL) { + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = (lt->point * 60 * 75); + ci->length = 0; + + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, " + "ATTR %02X, MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + image_log(img->log, " last track = %02X\n", + lt->point); + } + } + break; + case 0xa2: + if (lo[ct->session] != NULL) { + /* + We have a track to use for the calculation, first adjust the track's + attribute (ADR/Ctrl), mode, and form to match the last non-special track. + */ + lt = lo[ct->session]; + + ct->attr = lt->attr; + + ct->mode = lt->mode; + ct->form = lt->form; + + if (ct->idx[1].type != INDEX_NORMAL) { + /* + Index not normal, therefore, this is not a lead out track from a + second or afterwards session of a multi-session Cue sheet, calculate + the starting time and update all the indexes accordingly. + */ + const track_index_t *li = &(lt->idx[2]); + + for (int j = 0; j < 3; j++) { + image_log(img->log, " [TRACK ] %02X/%02X, INDEX %02X, " + "ATTR %02X, MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, j, + ct->attr, + ct->mode, ct->form, + cit[ci->type + 2]); + + ci = &(ct->idx[j]); + ci->type = INDEX_ZERO; + ci->start = li->start + li->length; + ci->length = 0; + + image_log(img->log, " start = %016" PRIX64 + " (%2i:%02i:%02i)\n", + ci->start, + (int) ((ci->start / 75) / 60), + (int) ((ci->start / 75) % 60), + (int) (ci->start % 75)); + } + } +#ifdef ENABLE_IMAGE_LOG + else + image_log(img->log, " no start calculation done, " + "already specified\n"); +#endif + } +#ifdef ENABLE_IMAGE_LOG + else + image_log(img->log, " nothing done, no suitable last track " + "found\n"); +#endif + break; + case 0xb0: + /* + B0: MSF points to the beginning of the pre-gap + of the following session's first track. + */ + ct->extra[0] = (spg[ct->session + 1] / 75) / 60; + ct->extra[1] = (spg[ct->session + 1] / 75) % 60; + ct->extra[2] = spg[ct->session + 1] % 75; + + image_log(img->log, " [TRACK ] %02X/%02X, INDEX 01, " + "ATTR %02X, MODE %02X/%02X, %8s,\n", + ct->session, + ct->point, + ct->attr, + ct->mode, ct->form, + cit[ct->idx[1].type + 2]); + image_log(img->log, " %02X:%02X:%02X, %02X,\n", + ct->extra[0], ct->extra[1], ct->extra[2], ct->extra[3]); + + /* + B0 PMSF points to the start of the lead out track + of the last session. + */ + if (lo[ls] != NULL) { + lt = lo[ls]; + const track_index_t *li = &(lt->idx[2]); + + ct->idx[1].start = li->start + li->length; + + image_log(img->log, " start = %016" PRIX64 + " (%2i:%02i:%02i)\n", + ct->idx[1].start, + (int) ((ct->idx[1].start / 75) / 60), + (int) ((ct->idx[1].start / 75) % 60), + (int) (ct->idx[1].start % 75)); + } +#ifdef ENABLE_IMAGE_LOG + else + image_log(img->log, " no start calculation done, " + "no suitable last track found\n"); +#endif + break; + } + } + +#ifdef ENABLE_IMAGE_LOG + image_log(img->log, "Final tracks list:\n"); + for (int i = 0; i < img->tracks_num; i++) { + ct = &(img->tracks[i]); + for (int j = 0; j < 3; j++) { + ci = &(ct->idx[j]); + image_log(img->log, " [TRACK ] %02X INDEX %02X: [%8s, %016" PRIX64 "]\n", + ct->point, j, + cit[ci->type + 2], ci->file_start * ct->sector_size); + image_log(img->log, " TOC data: %02X %02X %02X " + "%%02X %02X %02X %02X 02X %02X %02X %02X\n", + ct->session, ct->attr, ct->tno, ct->point, + ct->extra[0], ct->extra[1], ct->extra[2], ct->extra[3], + (uint32_t) ((ci->start / 75) / 60), + (uint32_t) ((ci->start / 75) % 60), + (uint32_t) (ci->start % 75)); + } + } +#endif +} + +static void +image_set_track_subch_type(track_t *ct) +{ + if (ct->sector_size == 2448) + ct->subch_type = 0x08; + else if (ct->sector_size == 2368) + ct->subch_type = 0x10; + else + ct->subch_type = 0x00; +} + +static int +image_load_iso(cd_image_t *img, const char *filename) +{ + track_t *ct = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + int success = 1; + int error = 1; + int is_viso = 0; + int sector_sizes[8] = { 2448, 2368, RAW_SECTOR_SIZE, 2336, + 2332, 2328, 2324, COOKED_SECTOR_SIZE }; + + img->tracks = NULL; + /* + Pass 1 - loading the ISO image. + */ + image_log(img->log, "Pass 1 (loading the ISO image)...\n"); + img->tracks_num = 0; + + image_insert_track(img, 1, 0xa0); + image_insert_track(img, 1, 0xa1); + image_insert_track(img, 1, 0xa2); + + /* Data track (shouldn't there be a lead in track?). */ + tf = index_file_init(img->dev->id, filename, &error, &is_viso); + + if (error) { + if (tf != NULL) { + tf->close(tf); + tf = NULL; + } + + success = 0; + } else if (is_viso) + success = 3; + + if (success) { + ct = image_insert_track(img, 1, 1); + ci = &(ct->idx[1]); + + ct->form = 0; + ct->mode = 0; + + for (int i = 0; i < 3; i++) + ct->idx[i].type = INDEX_NONE; + + ct->attr = DATA_TRACK; + + /* Try to detect ISO type. */ + ct->mode = 1; + ct->form = 0; + + ci->type = INDEX_NORMAL; + ci->file_start = 0ULL; + + ci->file = tf; + + for (int i = 0; i < 8; i++) { + ct->sector_size = sector_sizes[i]; + int can_read_pvd = image_can_read_pvd(ci->file, 0, ct->sector_size, 0); + if (can_read_pvd) { + ct->mode = can_read_pvd >> 4; + ct->form = can_read_pvd & 0xf; + if (((ct->sector_size == 2332) || (ct->sector_size == 2336)) && + (ct->form >= 1)) + ct->skip = 8; + break; + } else if (ct->sector_size >= 2332) { + can_read_pvd = image_can_read_pvd(ci->file, 0, ct->sector_size, 1); + if (can_read_pvd) { + ct->mode = can_read_pvd >> 4; + ct->form = can_read_pvd & 0xf; + if (((ct->sector_size == 2332) || (ct->sector_size == 2336)) && + (ct->form >= 1)) + ct->skip = 8; + break; + } + } + } + + image_set_track_subch_type(ct); + + image_log(img->log, " [TRACK ] %02X/%02X, ATTR %02X, MODE %02X/%02X,\n", + ct->session, + ct->point, + ct->attr, + ct->mode, ct->form); + image_log(img->log, " %02X:%02X:%02X, %02X, %i\n", + ct->sector_size); + } + + if (success) for (int i = 2; i >= 0; i--) { + if (ct->idx[i].file == NULL) + ct->idx[i].file = tf; + else + break; + } + + tf = NULL; + + if (success) + image_process(img); + else { + image_log(img->log, " [ISO ] Unable to open image or folder \"%s\"\n", + filename); + return 0; + } + + return success; +} + +static int +image_load_cue(cd_image_t *img, const char *cuefile) +{ + track_t *ct = NULL; + track_index_t *ci = NULL; + track_file_t *tf = NULL; + uint64_t frame = 0ULL; + uint64_t last = 0ULL; + uint8_t session = 1; + int last_t = -1; + int is_viso = 0; + int lead[3] = { 0 }; + int error; + char pathname[MAX_FILENAME_LENGTH]; + char buf[MAX_LINE_LENGTH]; + char *line; + char *command; + char *type; + char temp; + + img->tracks = NULL; + img->tracks_num = 0; + + /* Get a copy of the filename into pathname, we need it later. */ + memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(char)); + path_get_dirname(pathname, cuefile); + + /* Open the file. */ + FILE *fp = plat_fopen(cuefile, "r"); + if (fp == NULL) + return 0; + + int success = 0; + + /* + Pass 1 - loading the Cue sheet. + */ + image_log(img->log, "Pass 1 (loading the Cue sheet)...\n"); + img->tracks_num = 0; + + for (int i = 0; i < 3; i++) { + lead[i] = img->tracks_num; + (void) image_insert_track(img, session, 0xa0 + i); + } + + while (1) { + line = buf; + + /* Read a line from the cuesheet file. */ + if (feof(fp) || (fgets(buf, sizeof(buf), fp) == NULL) || ferror(fp)) + break; + + /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, + but do checks to make sure we're not nuking other bytes. */ + for (uint8_t i = 0; i < 2; i++) { + if (strlen(buf) > 0) { + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + /* nuke trailing newline */ + else if (buf[strlen(buf) - 1] == '\r') + buf[strlen(buf) - 1] = '\0'; + /* nuke trailing newline */ + } + } + image_log(img->log, " [LINE ] \"%s\"\n", line); + + (void) image_cue_get_keyword(&command, &line); + + if (!strcmp(command, "FILE")) { + /* The file for the track. */ + char filename[MAX_FILENAME_LENGTH]; + char ansi[MAX_FILENAME_LENGTH]; + + tf = NULL; + + memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); + memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(char)); + + success = image_cue_get_buffer(ansi, &line, 0); + if (!success) + break; + success = image_cue_get_keyword(&type, &line); + if (!success) + break; + + error = 1; + is_viso = 0; + + if (!strcmp(type, "BINARY") || !strcmp(type, "MOTOROLA")) { + if (!path_abs(ansi)) + path_append_filename(filename, pathname, ansi); + else + strcpy(filename, ansi); + + tf = index_file_init(img->dev->id, filename, &error, &is_viso); + + if (tf) + tf->motorola = !strcmp(type, "MOTOROLA"); + } else if (!strcmp(type, "WAVE") || !strcmp(type, "AIFF") || + !strcmp(type, "MP3")) { + if (!path_abs(ansi)) + path_append_filename(filename, pathname, ansi); + else + strcpy(filename, ansi); + tf = audio_init(img->dev->id, filename, &error); + } + if (error) { + if (tf != NULL) { + tf->close(tf); + tf = NULL; + } + success = 0; + } else if (is_viso) + success = 3; + +#ifdef ENABLE_IMAGE_LOG + if (!success) + image_log(img->log, " [FILE ] Unable to open file \"%s\" " + "specified in cue sheet\n", filename); +#endif + } else if (!strcmp(command, "TRACK")) { + int t = image_cue_get_number(&line); + success = image_cue_get_keyword(&type, &line); + + if (!success) + break; + + if (last_t != -1) { + /* + Important: This has to be done like this because pointers + change due to realloc. + */ + ct = &(img->tracks[t]); + + for (int i = 2; i >= 0; i--) { + if (ct->idx[i].file == NULL) + ct->idx[i].file = tf; + else + break; + } + } + + last_t = t; + ct = image_insert_track(img, session, t); + + ct->form = 0; + ct->mode = 0; + + if (!strcmp(type, "AUDIO")) { + ct->sector_size = RAW_SECTOR_SIZE; + ct->attr = AUDIO_TRACK; + } else if (!memcmp(type, "MODE", 4)) { + uint32_t mode; + ct->attr = DATA_TRACK; + sscanf(type, "MODE%" PRIu32 "/%" PRIu32, + &mode, &(ct->sector_size)); + ct->mode = mode; + if (ct->mode == 2) switch(ct->sector_size) { + default: + break; + case 2324: case 2328: + ct->form = 2; + break; + case 2048: case 2332: case 2336: case 2352: case 2368: case 2448: + ct->form = 1; + break; + } + if (((ct->sector_size == 2336) || (ct->sector_size == 2332)) && (ct->mode == 2) && (ct->form == 1)) + ct->skip = 8; + } else if (!memcmp(type, "CD", 2)) { + ct->attr = DATA_TRACK; + ct->mode = 2; + sscanf(type, "CD%c/%i", &temp, &(ct->sector_size)); + } else + success = 0; + + if (success) { + image_set_track_subch_type(ct); + + last = ct->sector_size; + + image_log(img->log, " [TRACK ] %02X/%02X, ATTR %02X, MODE %02X/%02X,\n", + ct->session, + ct->point, + ct->attr, + ct->mode, ct->form); + image_log(img->log, " %i\n", + ct->sector_size); + } +#ifdef ENABLE_IMAGE_LOG + else + image_log(img->log, " [TRACK ] Unable to initialize track %02X " + "specified in Cue sheet\n", t); +#endif + } else if (!strcmp(command, "INDEX")) { + int t = image_cue_get_number(&line); + ci = &(ct->idx[t]); + + ci->type = INDEX_NORMAL; + ci->file = tf; + success = image_cue_get_frame(&frame, &line); + ci->file_start = frame; + + image_log(img->log, " [INDEX ] %02X (%8s): Initialization %s\n", + t, cit[ci->type + 2], success ? "successful" : "failed"); + } else if (!strcmp(command, "PREGAP")) { + ci = &(ct->idx[0]); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = image_cue_get_frame(&frame, &line); + ci->length = frame; + + image_log(img->log, " [INDEX ] 00 (%8s): Initialization %s\n", + cit[ci->type + 2], success ? "successful" : "failed"); + } else if (!strcmp(command, "PAUSE") || !strcmp(command, "ZERO")) { + ci = &(ct->idx[1]); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = image_cue_get_frame(&frame, &line); + ci->length = frame; + + image_log(img->log, " [INDEX ] 01 (%8s): Initialization %s\n", + cit[ci->type + 2], success ? "successful" : "failed"); + } else if (!strcmp(command, "POSTGAP")) { + ci = &(ct->idx[2]); + + ci->type = INDEX_ZERO; + ci->file = tf; + success = image_cue_get_frame(&frame, &line); + ci->length = frame; + + image_log(img->log, " [INDEX ] 02 (%8s): Initialization %s\n", + cit[ci->type + 2], success ? "successful" : "failed"); + } else if (!strcmp(command, "FLAGS")) { + success = image_cue_get_flags(ct, &line); + + image_log(img->log, " [FLAGS ] Initialization %s\n", + success ? "successful" : "failed"); + } else if (!strcmp(command, "REM")) { + success = 1; + char *space = strstr(line, " "); + if (space != NULL) { + space++; + if (space < (line + strlen(line))) { + (void) image_cue_get_keyword(&command, &space); + if (!strcmp(command, "LEAD-OUT")) { + ct = &(img->tracks[lead[2]]); + /* + Mark it this way so file pointers on it are not + going to be adjusted. + */ + last_t = -1; + ct->sector_size = last; + ci = &(ct->idx[1]); + ci->type = INDEX_NORMAL; + ci->file = tf; + success = image_cue_get_frame(&frame, &space); + ci->file_start = frame; + + image_log(img->log, " [LEAD-OUT] Initialization %s\n", + success ? "successful" : "failed"); + } else if (!strcmp(command, "SESSION")) { + session = image_cue_get_number(&space); + + if (session > 1) { + ct = image_insert_track(img, session - 1, 0xb0); + /* + Mark it this way so file pointers on it are not + going to be adjusted. + */ + last_t = -1; + ci = &(ct->idx[1]); + ci->start = (0x40 * 60 * 75) + (0x02 * 75); + + if (session == 2) { + ct->extra[3] = 0x02; + + /* + 00:00:00 on Wembley, C0:00:00 in the spec. + And what's in PMSF? + */ + ct = image_insert_track(img, session - 1, 0xc0); + /* + Mark it this way so file pointers on it are not + going to be adjusted. + */ + last_t = -1; + ci = &(ct->idx[1]); + /* Queen - Live at Wembley '86 CD 1. */ + ci->start = (0x5f * 75 * 60); + /* Optimum recording power. */ + ct->extra[0] = 0x00; + } else + ct->extra[3] = 0x01; + + for (int i = 0; i < 3; i++) { + lead[i] = img->tracks_num; + (void) image_insert_track(img, session, 0xa0 + i); + } + } + + image_log(img->log, " [SESSION ] Initialization successful\n"); + } + } + } + } else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || + !strcmp(command, "ISRC") || !strcmp(command, "PERFORMER") || + !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || + !strcmp(command, "")) { + /* Ignored commands. */ + image_log(img->log, " [CUE ] Ignored command \"%s\" in Cue sheet\n", + command); + success = 1; + } else { + image_log(img->log, " [CUE ] Unsupported command \"%s\" in Cue sheet\n", + command); + success = 0; + } + + if (!success) + break; + } + + if (success && (ct != NULL)) for (int i = 2; i >= 0; i--) { + if (ct->idx[i].file == NULL) + ct->idx[i].file = tf; + else + break; + } + + tf = NULL; + + fclose(fp); + + if (success) + image_process(img); + else { + image_log(img->log, " [CUE ] Unable to open Cue sheet \"%s\"\n", cuefile); + return 0; + } + + return success; +} + +/* Root functions. */ +static void +image_clear_tracks(cd_image_t *img) +{ + const track_file_t *last = NULL; + track_t *cur = NULL; + track_index_t *idx = NULL; + + if ((img->tracks != NULL) && (img->tracks_num > 0)) { + for (int i = 0; i < img->tracks_num; i++) { + cur = &img->tracks[i]; + + if (((cur->point >= 1) && (cur->point <= 99)) || + (cur->point == 0xa2)) for (int j = 0; j < 3; j++) { + idx = &(cur->idx[j]); + /* Make sure we do not attempt to close a NULL file. */ + if ((idx->file != NULL) && (idx->type == INDEX_NORMAL)) { + if (idx->file != last) { + last = idx->file; + index_file_close(idx); + } else + idx->file = NULL; + } + } + } + + /* Now free the array. */ + free(img->tracks); + img->tracks = NULL; + + /* Mark that there's no tracks. */ + img->tracks_num = 0; + } +} + +/* Shared functions. */ +static int +image_get_track_info(const void *local, const uint32_t track, + const int end, track_info_t *ti) +{ + const cd_image_t *img = (const cd_image_t *) local; + const track_t *ct = NULL; + int ret = 0; for (int i = 0; i < img->tracks_num; i++) { ct = &(img->tracks[i]); @@ -70,238 +1712,328 @@ image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) break; } - ti->number = ct->point; + if (ct != NULL) { + const uint32_t pos = end ? ct->idx[1].start : + (ct->idx[1].start + ct->idx[1].length); - if (ct == NULL) { - ti->attr = 0x14; - ti->m = 0; - ti->s = 2; - ti->f = 0; - } else { - uint32_t pos = end ? ct->idx[1].start : (ct->idx[1].start + ct->idx[1].length); - ti->attr = ct->attr; - ti->m = (pos / 75) / 60; - ti->s = (pos / 75) % 60; - ti->f = pos % 75; + ti->number = ct->point; + ti->attr = ct->attr; + ti->m = (pos / 75) / 60; + ti->s = (pos / 75) % 60; + ti->f = pos % 75; + + ret = 1; } + + return ret; } static void -image_get_raw_track_info(cdrom_t *dev, int *num, raw_track_info_t *rti) +image_get_raw_track_info(const void *local, int *num, uint8_t *buffer) { - cdi_get_raw_track_info((cd_img_t *) dev->local, num, (uint8_t *) rti); -} + const cd_image_t *img = (const cd_image_t *) local; + int len = 0; -static void -image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) -{ - cd_img_t *img = (cd_img_t *) dev->local; - TMSF rel_pos; - TMSF abs_pos; + image_log(img->log, "img->tracks_num = %i\n", img->tracks_num); - cdi_get_audio_sub(img, lba, &subc->attr, &subc->track, &subc->index, - &rel_pos, &abs_pos); + for (int i = 0; i < img->tracks_num; i++) { + const track_t *ct = &(img->tracks[i]); +#ifdef ENABLE_IMAGE_LOG + int old_len = len; +#endif + buffer[len++] = ct->session; /* Session number. */ + buffer[len++] = ct->attr; /* Track ADR and Control. */ + buffer[len++] = ct->tno; /* TNO (always 0). */ + buffer[len++] = ct->point; /* Point (track number). */ + for (int j = 0; j < 4; j++) + buffer[len++] = ct->extra[j]; + buffer[len++] = (ct->idx[1].start / 75) / 60; + buffer[len++] = (ct->idx[1].start / 75) % 60; + buffer[len++] = ct->idx[1].start % 75; + image_log(img->log, "%i: %02X %02X %02X %02X %02X %02X %02X\n", i, + buffer[old_len], buffer[old_len + 1], + buffer[old_len + 2], buffer[old_len + 3], + buffer[old_len + 8], buffer[old_len + 9], + buffer[old_len + 10]); + } - subc->abs_m = abs_pos.min; - subc->abs_s = abs_pos.sec; - subc->abs_f = abs_pos.fr; - - subc->rel_m = rel_pos.min; - subc->rel_s = rel_pos.sec; - subc->rel_f = rel_pos.fr; - - cdrom_image_log("image_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, - subc->rel_m, subc->rel_s, subc->rel_f); + *num = img->tracks_num; } static int -image_get_capacity(cdrom_t *dev) +image_is_track_pre(const void *local, const uint32_t sector) { - cd_img_t *img = (cd_img_t *) dev->local; - uint32_t lb = 0; - track_t *lo = NULL; + const cd_image_t *img = (const cd_image_t *) local; + int ret = 0; - if (!img) - return 0; + if (img->has_audio) { + const int track = image_get_track(img, sector); - for (int i = (img->tracks_num - 1); i >= 0; i--) { - if (img->tracks[i].point == 0xa2) { - lo = &(img->tracks[i]); - break; + if (track >= 0) { + const track_t *trk = &(img->tracks[track]); + + ret = !!(trk->attr & 0x01); } } - if (lo != NULL) - lb = lo->idx[1].start - 1; + return ret; +} + +static int +image_read_sector(const void *local, uint8_t *buffer, + const uint32_t sector) +{ + const cd_image_t *img = (const cd_image_t *) local; + int m = 0; + int s = 0; + int f = 0; + int ret = 0; + uint32_t lba = sector; + int track; + int index; + uint8_t q[16] = { 0x00 }; + + if (sector == 0xffffffff) + lba = img->dev->seek_pos; + + const uint64_t sect = (uint64_t) lba; + + image_get_track_and_index(img, lba, &track, &index); + + const track_t *trk = &(img->tracks[track]); + const track_index_t *idx = &(trk->idx[index]); + const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || + (trk->sector_size == 2448)); + const uint64_t seek = ((sect + 150 - idx->start + idx->file_start) * + trk->sector_size) + trk->skip; + + if (track >= 0) { + /* Signal CIRC error to the guest if sector is bad. */ + ret = image_is_sector_bad(img, lba) ? -1 : 1; + + if (ret > 0) { + uint64_t offset = 0ULL; + + image_log(img->log, "cdrom_read_sector(%08X): track %02X, index %02X, %016" + PRIX64 ", %i, %i, %i, %i\n", + lba, track, index, idx->start, trk->sector_size, track_is_raw, + trk->mode, trk->form); + + memset(buffer, 0x00, 2448); + + if ((trk->attr & 0x04) && ((idx->type < INDEX_NORMAL) || !track_is_raw)) { + offset += 16ULL; + + /* Construct the header. */ + memset(buffer + 1, 0xff, 10); + buffer += 12; + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + /* These have to be BCD. */ + buffer[0] = bin2bcd(m & 0xff); + buffer[1] = bin2bcd(s & 0xff); + buffer[2] = bin2bcd(f & 0xff); + /* Data, should reflect the actual sector type. */ + buffer[3] = trk->mode; + buffer += 4; + if (trk->form >= 1) { + offset += 8ULL; + + /* Construct the CD-I/XA sub-header. */ + buffer[2] = buffer[6] = (trk->form - 1) << 5; + buffer += 8; + } + } + + if (idx->type >= INDEX_NORMAL) { + /* Read the data from the file. */ + ret = idx->file->read(idx->file, buffer, seek, trk->sector_size); + } else + /* Index is not in the file, no read to fail here. */ + ret = 1; + + if ((ret > 0) && ((idx->type < INDEX_NORMAL) || (trk->subch_type != 0x08))) { + buffer -= offset; + + if (trk->subch_type == 0x10) + memcpy(q, &(buffer[2352]), 12); + else { + /* Construct Q. */ + q[0] = (trk->attr >> 4) | ((trk->attr & 0xf) << 4); + q[1] = bin2bcd(trk->point); + q[2] = index; + if (index == 0) { + /* + Pre-gap sector relative frame addresses count from + 00:01:74 downwards. + */ + FRAMES_TO_MSF((int32_t) (149 - (lba + 150 - idx->start)), &m, &s, &f); + } else { + FRAMES_TO_MSF((int32_t) (lba + 150 - idx->start), &m, &s, &f); + } + q[3] = bin2bcd(m & 0xff); + q[4] = bin2bcd(s & 0xff); + q[5] = bin2bcd(f & 0xff); + FRAMES_TO_MSF(lba + 150, &m, &s, &f); + q[7] = bin2bcd(m & 0xff); + q[8] = bin2bcd(s & 0xff); + q[9] = bin2bcd(f & 0xff); + } + + /* Construct raw subchannel data from Q only. */ + for (int i = 0; i < 12; i++) + for (int j = 0; j < 8; j++) + buffer[2352 + (i << 3) + j] = ((q[i] >> (7 - j)) & 0x01) << 6; + } + } + } + + return ret; +} + +static uint8_t +image_get_track_type(const void *local, const uint32_t sector) +{ + const cd_image_t *img = (cd_image_t *) local; + const int track = image_get_track(img, sector); + const track_t * trk = &(img->tracks[track]); + int ret = 0x00; + + if (image_is_track_audio(img, sector)) + ret = CD_TRACK_AUDIO; + else if (track >= 0) for (int i = 0; i < img->tracks_num; i++) { + const track_t *ct = &(img->tracks[i]); + const track_t *nt = &(img->tracks[i + 1]); + + if (ct->point == 0xa0) { + uint8_t first = (ct->idx[1].start / 75 / 60); + uint8_t last = (nt->idx[1].start / 75 / 60); + + if ((trk->point >= first) && (trk->point <= last)) { + ret = (ct->idx[1].start / 75) % 60; + break; + } + } + } + + return ret; +} + +static uint32_t +image_get_last_block(const void *local) +{ + const cd_image_t *img = (const cd_image_t *) local; + uint32_t lb = 0x00000000; + + if (img != NULL) { + const track_t *lo = NULL; + + for (int i = (img->tracks_num - 1); i >= 0; i--) { + if (img->tracks[i].point == 0xa2) { + lo = &(img->tracks[i]); + break; + } + } + + if (lo != NULL) + lb = lo->idx[1].start - 1; + } return lb; } static int -image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) -{ - cd_img_t *img = (cd_img_t *) dev->local; - int m; - int s; - int f; - - if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) - return 0; - - if (ismsf) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - pos = MSFtoLBA(m, s, f) - 150; - } - - return cdi_is_audio(img, pos); -} - -static int -image_is_track_pre(cdrom_t *dev, uint32_t lba) -{ - cd_img_t *img = (cd_img_t *) dev->local; - - if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) - return 0; - - return cdi_is_pre(img, lba); -} - -static int -image_sector_size(struct cdrom *dev, uint32_t lba) -{ - cd_img_t *img = (cd_img_t *) dev->local; - - return cdi_get_sector_size(img, lba); -} - -static int -image_read_sector(struct cdrom *dev, uint8_t *b, uint32_t lba) -{ - cd_img_t *img = (cd_img_t *) dev->local; - - if (cdi_get_sector_size(img, lba) <= 2352) - return cdi_read_sector(img, b, 1, lba); - else - return cdi_read_sector_sub(img, b, lba); -} - -static int -image_track_type(cdrom_t *dev, uint32_t lba) -{ - cd_img_t *img = (cd_img_t *) dev->local; - - if (img) { - if (image_is_track_audio(dev, lba, 0)) - return CD_TRACK_AUDIO; - else if (cdi_is_mode2(img, lba)) - return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); - } - - return 0; -} - -static int -image_ext_medium_changed(cdrom_t *dev) +image_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t format, + uint8_t *buffer, uint32_t *info) { return 0; } +static int +image_is_dvd(const void *local) +{ + const cd_image_t *img = (const cd_image_t *) local; + + return img->is_dvd; +} + +static int +image_has_audio(const void *local) +{ + const cd_image_t *img = (const cd_image_t *) local; + + return img->has_audio; +} + static void -image_exit(cdrom_t *dev) +image_close(void *local) { - cd_img_t *img = (cd_img_t *) dev->local; + cd_image_t *img = (cd_image_t *) local; - cdrom_image_log("CDROM: image_exit(%s)\n", dev->image_path); - dev->cd_status = CD_STATUS_EMPTY; + if (img != NULL) { + image_clear_tracks(img); - if (img) { - cdi_close(img); - dev->local = NULL; + image_log(img->log, "Log closed\n"); + + log_close(img->log); + img->log = NULL; + + free(img); } - - dev->ops = NULL; } -static const cdrom_ops_t cdrom_image_ops = { +static const cdrom_ops_t image_ops = { image_get_track_info, image_get_raw_track_info, - image_get_subchannel, image_is_track_pre, - image_sector_size, image_read_sector, - image_track_type, - image_ext_medium_changed, - image_exit + image_get_track_type, + image_get_last_block, + image_read_dvd_structure, + image_is_dvd, + image_has_audio, + NULL, + image_close }; -static int -image_open_abort(cdrom_t *dev) +/* Public functions. */ +void * +image_open(cdrom_t *dev, const char *path) { - cdrom_image_close(dev); - dev->ops = NULL; - dev->image_path[0] = 0; - return 1; -} - -int -cdrom_image_open(cdrom_t *dev, const char *fn) -{ - cd_img_t *img; - - /* Make sure to not STRCPY if the two are pointing - at the same place. */ - if (fn != dev->image_path) - strcpy(dev->image_path, fn); - - /* Create new instance of the CDROM_Image class. */ - img = (cd_img_t *) calloc(1, sizeof(cd_img_t)); - - /* This guarantees that if ops is not NULL, then - neither is the image pointer. */ - if (img == NULL) - return image_open_abort(dev); - - dev->local = img; - - /* Open the image. */ - int i = cdi_set_device(img, fn); - if (!i) - return image_open_abort(dev); - - /* All good, reset state. */ - if (i >= 2) - dev->cd_status = CD_STATUS_DATA_ONLY; - else - dev->cd_status = CD_STATUS_STOPPED; - dev->seek_pos = 0; - dev->cd_buflen = 0; - dev->cdrom_capacity = image_get_capacity(dev); - cdrom_image_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes)\n", dev->cdrom_capacity, - ((uint64_t) dev->cdrom_capacity) << 11ULL); -#ifdef ENABLE_CDROM_IMAGE_LOG - int cm, cs, cf; - cf = dev->cdrom_capacity % 75; - cs = (dev->cdrom_capacity / 75) % 60; - cm = (dev->cdrom_capacity / 75) / 60; - cdrom_image_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes) (time: %02i:%02i:%02i)\n", - dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity - 150ULL) * 2352ULL, cm, cs, cf); -#endif - - /* Attach this handler to the drive. */ - dev->ops = &cdrom_image_ops; - - return 0; -} - -void -cdrom_image_close(cdrom_t *dev) -{ - cdrom_image_log("CDROM: image_close(%s)\n", dev->image_path); - - if (dev && dev->ops && dev->ops->exit) - dev->ops->exit(dev); + const uintptr_t ext = path + strlen(path) - strrchr(path, '.'); + cd_image_t *img = (cd_image_t *) calloc(1, sizeof(cd_image_t)); + + if (img != NULL) { + int ret; + const int is_cue = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE")); + + if (is_cue) { + ret = image_load_cue(img, path); + + if (ret >= 2) + img->has_audio = 0; + else if (ret) + img->has_audio = 1; + } else { + ret = image_load_iso(img, path); + + if (!ret) { + image_close(img); + img = NULL; + } else + img->has_audio = 0; + } + + if (ret) { + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i Image", dev->id + 1); + img->log = log_open(n); + + img->dev = dev; + + dev->ops = &image_ops; + } + } + + return img; } diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c deleted file mode 100644 index 9d065a0cb..000000000 --- a/src/cdrom/cdrom_image_backend.c +++ /dev/null @@ -1,1499 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * CD-ROM image file handling module. - * - * Authors: Miran Grca, - * RichardG, - * Cacodemon345 - * - * Copyright 2016-2025 Miran Grca. - * Copyright 2016-2025 Miran Grca. - * Copyright 2024-2025 Cacodemon345. - */ -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -# include -# include -#else -# include -#endif -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/path.h> -#include <86box/plat.h> -#include <86box/cdrom_image_backend.h> - -#include - -#define CDROM_BCD(x) (((x) % 10) | (((x) / 10) << 4)) - -#define MAX_LINE_LENGTH 512 -#define MAX_FILENAME_LENGTH 256 -#define CROSS_LEN 512 - -static char temp_keyword[1024]; - -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG -int cdrom_image_backend_do_log = ENABLE_CDROM_IMAGE_BACKEND_LOG; - -void -cdrom_image_backend_log(const char *fmt, ...) -{ - va_list ap; - - if (cdrom_image_backend_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -# define cdrom_image_backend_log(fmt, ...) -#endif - -typedef struct audio_file_t { - SNDFILE *file; - SF_INFO info; -} audio_file_t; - -/* Audio file functions */ -static int -audio_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count) -{ - track_file_t *tf = (track_file_t *) priv; - audio_file_t *audio = (audio_file_t *) tf->priv; - uint64_t samples_seek = seek / 4; - uint64_t samples_count = count / 4; - - if ((seek & 3) || (count & 3)) { - cdrom_image_backend_log("CD Audio file: Reading on non-4-aligned boundaries.\n"); - } - - sf_count_t res = sf_seek(audio->file, samples_seek, SEEK_SET); - - if (res == -1) - return 0; - - return !!sf_readf_short(audio->file, (short *) buffer, samples_count); -} - -static uint64_t -audio_get_length(void *priv) -{ - track_file_t *tf = (track_file_t *) priv; - audio_file_t *audio = (audio_file_t *) tf->priv; - - /* Assume 16-bit audio, 2 channel. */ - return audio->info.frames * 4ull; -} - -static void -audio_close(void *priv) -{ - track_file_t *tf = (track_file_t *) priv; - audio_file_t *audio = (audio_file_t *) tf->priv; - - memset(tf->fn, 0x00, sizeof(tf->fn)); - if (audio && audio->file) - sf_close(audio->file); - free(audio); - free(tf); -} - -static track_file_t * -audio_init(const char *filename, int *error) -{ - track_file_t *tf = (track_file_t *) calloc(sizeof(track_file_t), 1); - audio_file_t *audio = (audio_file_t *) calloc(sizeof(audio_file_t), 1); -#ifdef _WIN32 - wchar_t filename_w[4096]; -#endif - - if (tf == NULL || audio == NULL) { - goto cleanup_error; - } - - memset(tf->fn, 0x00, sizeof(tf->fn)); - strncpy(tf->fn, filename, sizeof(tf->fn) - 1); -#ifdef _WIN32 - mbstowcs(filename_w, filename, 4096); - audio->file = sf_wchar_open(filename_w, SFM_READ, &audio->info); -#else - audio->file = sf_open(filename, SFM_READ, &audio->info); -#endif - - if (!audio->file) { - cdrom_image_backend_log("Audio file open error!"); - goto cleanup_error; - } - - if (audio->info.channels != 2 || audio->info.samplerate != 44100 || !audio->info.seekable) { - cdrom_image_backend_log("Audio file not seekable or in non-CD format!"); - sf_close(audio->file); - goto cleanup_error; - } - - *error = 0; - tf->priv = audio; - tf->fp = NULL; - tf->close = audio_close; - tf->get_length = audio_get_length; - tf->read = audio_read; - return tf; -cleanup_error: - free(tf); - free(audio); - *error = 1; - return NULL; -} - -/* Binary file functions. */ -static int -bin_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count) -{ - track_file_t *tf = NULL; - - if ((tf = (track_file_t *) priv)->fp == NULL) - return 0; - - cdrom_image_backend_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu)\n", - tf->fp, seek, count); - - if (fseeko64(tf->fp, seek, SEEK_SET) == -1) { - cdrom_image_backend_log("CDROM: binary_read failed during seek!\n"); - - return -1; - } - - if (fread(buffer, count, 1, tf->fp) != 1) { - cdrom_image_backend_log("CDROM: binary_read failed during read!\n"); - - return -1; - } - - if (UNLIKELY(tf->motorola)) { - for (uint64_t i = 0; i < count; i += 2) { - uint8_t buffer0 = buffer[i]; - uint8_t buffer1 = buffer[i + 1]; - buffer[i] = buffer1; - buffer[i + 1] = buffer0; - } - } - - return 1; -} - -static uint64_t -bin_get_length(void *priv) -{ - track_file_t *tf = NULL; - - if ((tf = (track_file_t *) priv)->fp == NULL) - return 0; - - fseeko64(tf->fp, 0, SEEK_END); - const off64_t len = ftello64(tf->fp); - cdrom_image_backend_log("CDROM: binary_length(%08lx) = %" PRIu64 "\n", tf->fp, len); - - return len; -} - -static void -bin_close(void *priv) -{ - track_file_t *tf = (track_file_t *) priv; - - if (tf == NULL) - return; - - if (tf->fp != NULL) { - fclose(tf->fp); - tf->fp = NULL; - } - - memset(tf->fn, 0x00, sizeof(tf->fn)); - - free(priv); -} - -static track_file_t * -bin_init(const char *filename, int *error) -{ - track_file_t *tf = (track_file_t *) calloc(1, sizeof(track_file_t)); - struct stat stats; - - if (tf == NULL) { - *error = 1; - return NULL; - } - - memset(tf->fn, 0x00, sizeof(tf->fn)); - strncpy(tf->fn, filename, sizeof(tf->fn) - 1); - tf->fp = plat_fopen64(tf->fn, "rb"); - cdrom_image_backend_log("CDROM: binary_open(%s) = %08lx\n", tf->fn, tf->fp); - - if (stat(tf->fn, &stats) != 0) { - /* Use a blank structure if stat failed. */ - memset(&stats, 0, sizeof(struct stat)); - } - *error = ((tf->fp == NULL) || ((stats.st_mode & S_IFMT) == S_IFDIR)); - - /* Set the function pointers. */ - if (!*error) { - tf->read = bin_read; - tf->get_length = bin_get_length; - tf->close = bin_close; - } else { - /* From the check above, error may still be non-zero if opening a directory. - * The error is set for viso to try and open the directory following this function. - * However, we need to make sure the descriptor is closed. */ - if ((tf->fp != NULL) && ((stats.st_mode & S_IFMT) == S_IFDIR)) { - /* tf is freed by bin_close */ - bin_close(tf); - } else - free(tf); - tf = NULL; - } - - return tf; -} - -static track_file_t * -track_file_init(const char *filename, int *error, int *is_viso) -{ - track_file_t *tf; - - *is_viso = 0; - - /* Current we only support .BIN files, either combined or one per - track. In the future, more is planned. */ - tf = bin_init(filename, error); - - if (*error) { - if ((tf != NULL) && (tf->close != NULL)) { - tf->close(tf); - tf = NULL; - } - - tf = viso_init(filename, error); - - if (!*error) - *is_viso = 1; - } - - return tf; -} - -static void -index_file_close(track_index_t *idx) -{ - if (idx == NULL) - return; - - if (idx->file == NULL) - return; - - if (idx->file->close == NULL) - return; - - idx->file->close(idx->file); - idx->file = NULL; -} - -void -cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer) -{ - int len = 0; - - cdrom_image_backend_log("cdi->tracks_num = %i\n", cdi->tracks_num); - - for (int i = 0; i < cdi->tracks_num; i++) { - track_t *ct = &(cdi->tracks[i]); -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - int old_len = len; -#endif - buffer[len++] = ct->session; /* Session number */ - buffer[len++] = ct->attr; /* Track ADR and Control */ - buffer[len++] = ct->tno; /* TNO (always 0) */ - buffer[len++] = ct->point; /* Point (for track points - track number) */ - for (int j = 0; j < 4; j++) - buffer[len++] = ct->extra[j]; - buffer[len++] = (ct->idx[1].start / 75) / 60; - buffer[len++] = (ct->idx[1].start / 75) % 60; - buffer[len++] = ct->idx[1].start % 75; - cdrom_image_backend_log("%i: %02X %02X %02X %02X %02X %02X %02X\n", i, - buffer[old_len], buffer[old_len + 1], buffer[old_len + 2], buffer[old_len + 3], - buffer[old_len + 8], buffer[old_len + 9], buffer[old_len + 10]); - } - - *num = cdi->tracks_num; -} - -static int -cdi_get_track(cd_img_t *cdi, uint32_t sector) -{ - int ret = -1; - - for (int i = 0; i < cdi->tracks_num; i++) { - track_t *ct = &(cdi->tracks[i]); - for (int j = 0; j < 3; j++) { - track_index_t *ci = &(ct->idx[j]); - if (((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { - ret = i; - break; - } - } - } - - return ret; -} - -static void -cdi_get_track_and_index(cd_img_t *cdi, uint32_t sector, int *track, int *index) -{ - *track = -1; - *index = -1; - - for (int i = 0; i < cdi->tracks_num; i++) { - track_t *ct = &(cdi->tracks[i]); - for (int j = 0; j < 3; j++) { - track_index_t *ci = &(ct->idx[j]); - if (((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { - *track = i; - *index = j; - break; - } - } - } -} - -/* TODO: See if track start is adjusted by 150 or not. */ -int -cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos) -{ - int cur_track = cdi_get_track(cdi, sector); - - if (cur_track < 1) - return 0; - - *track = (uint8_t) cur_track; - const track_t *trk = &cdi->tracks[*track]; - *attr = trk->attr; - *index = 1; - - /* Absolute position should be adjusted by 150, not the relative ones. */ - FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr); - - /* Relative position is relative Index 1 start - pre-gap values will be negative. */ - FRAMES_TO_MSF((int32_t) (sector + 150 - trk->idx[1].start), &rel_pos->min, &rel_pos->sec, &rel_pos->fr); - - return 1; -} - -static __inline int -bin2bcd(int x) -{ - return (x % 10) | ((x / 10) << 4); -} - -int -cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) -{ - const uint64_t sect = (uint64_t) sector; - int m = 0; - int s = 0; - int f = 0; - int ret = 0; - uint64_t offset = 0ULL; - int track; - int index; - int raw_size; - int cooked_size; - uint8_t q[16] = { 0x00 }; - - cdi_get_track_and_index(cdi, sector, &track, &index); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - const track_index_t *idx = &(trk->idx[index]); - const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); - const uint64_t seek = (sect + 150 - idx->start + idx->file_start) * trk->sector_size; - - cdrom_image_backend_log("cdrom_read_sector(%08X): track %02X, index %02X, %016" PRIX64 ", %016" PRIX64 ", %i\n", - sector, track, index, idx->start, trk->sector_size); - - if (track_is_raw) - raw_size = trk->sector_size; - else - raw_size = 2448; - - if ((trk->mode == 2) && (trk->form != 1)) { - if (trk->form == 2) - cooked_size = (track_is_raw ? 2328 : trk->sector_size); /* Both 2324 + ECC and 2328 variants are valid. */ - else - cooked_size = 2336; - } else - cooked_size = COOKED_SECTOR_SIZE; - - if ((trk->mode == 2) && (trk->form >= 1)) - offset = 24ULL; - else - offset = 16ULL; - - if (idx->type < INDEX_NORMAL) { - memset(buffer, 0x00, 2448); - if (trk->attr & 0x04) { - /* Construct the rest of the raw sector. */ - memset(buffer + 1, 0xff, 10); - buffer += 12; - FRAMES_TO_MSF(sector + 150, &m, &s, &f); - /* These have to be BCD. */ - buffer[0] = CDROM_BCD(m & 0xff); - buffer[1] = CDROM_BCD(s & 0xff); - buffer[2] = CDROM_BCD(f & 0xff); - /* Data, should reflect the actual sector type. */ - buffer[3] = trk->mode; - ret = 1; - } - } else if (raw && !track_is_raw) { - memset(buffer, 0x00, 2448); - /* We are doing a raw read but the track is cooked, length should be cooked size. */ - const int temp = idx->file->read(idx->file, buffer + offset, seek, cooked_size); - if (temp <= 0) - return temp; - if (trk->attr & 0x04) { - /* Construct the rest of the raw sector. */ - memset(buffer + 1, 0xff, 10); - buffer += 12; - FRAMES_TO_MSF(sector + 150, &m, &s, &f); - /* These have to be BCD. */ - buffer[0] = CDROM_BCD(m & 0xff); - buffer[1] = CDROM_BCD(s & 0xff); - buffer[2] = CDROM_BCD(f & 0xff); - /* Data, should reflect the actual sector type. */ - buffer[3] = trk->mode; - ret = 1; - } - } else if (!raw && track_is_raw) - /* The track is raw but we are doing a cooked read, length should be cooked size. */ - return idx->file->read(idx->file, buffer, seek + offset, cooked_size); - else { - /* The track is raw and we are doing a raw read, length should be raw size. */ - ret = idx->file->read(idx->file, buffer, seek, raw_size); - if (raw && (raw_size == 2448)) - return ret; - } - - /* Construct Q. */ - q[0] = (trk->attr >> 4) | ((trk->attr & 0xf) << 4); - q[1] = bin2bcd(trk->point); - q[2] = index; - if (index == 0) { - /* Pre-gap sector relative frame addresses count from 00:01:74 downwards. */ - FRAMES_TO_MSF((int32_t) (149 - (sector + 150 - idx->start)), &m, &s, &f); - } else { - FRAMES_TO_MSF((int32_t) (sector + 150 - idx->start), &m, &s, &f); - } - q[3] = bin2bcd(m); - q[4] = bin2bcd(s); - q[5] = bin2bcd(f); - FRAMES_TO_MSF(sector + 150, &m, &s, &f); - q[7] = bin2bcd(m); - q[8] = bin2bcd(s); - q[9] = bin2bcd(f); - - /* Construct raw subchannel data from Q only. */ - for (int i = 0; i < 12; i++) - for (int j = 0; j < 8; j++) - buffer[2352 + (i << 3) + j] = ((q[i] >> (7 - j)) & 0x01) << 6; - - return ret; -} - -/* TODO: Do CUE+BIN images with a sector size of 2448 even exist? */ -int -cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector) -{ - int track; - int index; - - cdi_get_track_and_index(cdi, sector, &track, &index); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - const track_index_t *idx = &(trk->idx[index]); - - const uint64_t seek = (((uint64_t) sector + 150 - idx->start + idx->file_start) * trk->sector_size); - - if ((idx->type < INDEX_NORMAL) && (trk->sector_size != 2448)) - return 0; - - return idx->file->read(idx->file, buffer, seek, 2448); -} - -int -cdi_get_sector_size(cd_img_t *cdi, uint32_t sector) -{ - int track = cdi_get_track(cdi, sector); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - - return trk->sector_size; -} - -int -cdi_is_audio(cd_img_t *cdi, uint32_t sector) -{ - int track = cdi_get_track(cdi, sector); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - - return !!(trk->mode == 0); -} - -int -cdi_is_pre(cd_img_t *cdi, uint32_t sector) -{ - int track = cdi_get_track(cdi, sector); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - - return !!(trk->attr & 0x01); -} - -int -cdi_is_mode2(cd_img_t *cdi, uint32_t sector) -{ - int track = cdi_get_track(cdi, sector); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - - return !!(trk->mode == 2); -} - -int -cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector) -{ - int track = cdi_get_track(cdi, sector); - - if (track < 0) - return 0; - - const track_t *trk = &(cdi->tracks[track]); - - return trk->form; -} - -static int -cdi_can_read_pvd(track_file_t *file, uint64_t sector_size, int mode2, int form) -{ - uint8_t pvd[COOKED_SECTOR_SIZE]; - uint64_t seek = 16ULL * sector_size; /* First VD is located at sector 16. */ - - if (sector_size == RAW_SECTOR_SIZE) { - if (mode2 && (form > 0)) - seek += 24; - else - seek += 16; - } else if (form > 0) - seek += 8; - - file->read(file, pvd, seek, COOKED_SECTOR_SIZE); - - return ((pvd[0] == 1 && !strncmp((char *) (&pvd[1]), "CD001", 5) && pvd[6] == 1) || (pvd[8] == 1 && !strncmp((char *) (&pvd[9]), "CDROM", 5) && pvd[14] == 1)); -} - -static int -cdi_cue_get_buffer(char *str, char **line, int up) -{ - char *s = *line; - char *p = str; - int quote = 0; - int done = 0; - int space = 1; - - /* Copy to local buffer until we have end of string or whitespace. */ - while (!done) { - switch (*s) { - case '\0': - if (quote) { - /* Ouch, unterminated string.. */ - return 0; - } - done = 1; - break; - - case '\"': - quote ^= 1; - break; - - case ' ': - case '\t': - if (space) - break; - - if (!quote) { - done = 1; - break; - } - fallthrough; - - default: - if (up && islower((int) *s)) - *p++ = toupper((int) *s); - else - *p++ = *s; - space = 0; - break; - } - - if (!done) - s++; - } - *p = '\0'; - - *line = s; - - return 1; -} - -static int -cdi_cue_get_keyword(char **dest, char **line) -{ - int success; - - success = cdi_cue_get_buffer(temp_keyword, line, 1); - if (success) - *dest = temp_keyword; - - return success; -} - -/* Get a string from the input line, handling quotes properly. */ -static uint64_t -cdi_cue_get_number(char **line) -{ - char temp[128]; - uint64_t num; - - if (!cdi_cue_get_buffer(temp, line, 0)) - return 0; - - if (sscanf(temp, "%" PRIu64, &num) != 1) - return 0; - - return num; -} - -static int -cdi_cue_get_frame(uint64_t *frames, char **line) -{ - char temp[128]; - int min = 0; - int sec = 0; - int fr = 0; - int success; - - success = cdi_cue_get_buffer(temp, line, 0); - if (!success) - return 0; - - success = sscanf(temp, "%d:%d:%d", &min, &sec, &fr) == 3; - if (!success) - return 0; - - *frames = MSF_TO_FRAMES(min, sec, fr); - - return 1; -} - -static int -cdi_cue_get_flags(track_t *cur, char **line) -{ - char temp[128]; - char temp2[128]; - int success; - - success = cdi_cue_get_buffer(temp, line, 0); - if (!success) - return 0; - - memset(temp2, 0x00, sizeof(temp2)); - success = sscanf(temp, "%s", temp2) == 1; - if (!success) - return 0; - - if (strstr(temp2, "PRE") != NULL) - cur->attr |= 0x01; - if (strstr(temp2, "DCP") != NULL) - cur->attr |= 0x02; - if (strstr(temp2, "4CH") != NULL) - cur->attr |= 0x08; - - return 1; -} - -static track_t * -cdi_insert_track(cd_img_t *cdi, uint8_t session, uint8_t point) -{ - track_t *ct = NULL; - - cdi->tracks_num++; - if (cdi->tracks == NULL) { - cdi->tracks = calloc(1, sizeof(track_t)); - ct = &(cdi->tracks[0]); - } else { - cdi->tracks = realloc(cdi->tracks, cdi->tracks_num * sizeof(track_t)); - ct = &(cdi->tracks[cdi->tracks_num - 1]); - } - cdrom_image_backend_log("%02X: cdi->tracks[%2i] = %016" PRIX64 "\n", point, cdi->tracks_num - 1, (uint64_t) ct); - - memset(ct, 0x00, sizeof(track_t)); - - ct->session = session; - ct->point = point; - - for (int i = 0; i < 3; i++) - ct->idx[i].type = (point > 99) ? INDEX_SPECIAL : INDEX_NONE; - - return ct; -} - -static void -cdi_last_3_passes(cd_img_t *cdi) -{ - track_t *ct = NULL; - track_t *lt = NULL; - track_index_t *ci = NULL; - track_file_t *tf = NULL; - uint64_t tf_len = 0ULL; - uint64_t cur_pos = 0ULL; - int map[256] = { 0 }; - int lead[3] = { 0 }; - int pos = 0; - int ls = 0; - uint64_t spg[256] = { 0ULL }; - track_t *lo[256] = { 0 }; - - cdrom_image_backend_log("A2 = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[2])); - - for (int i = 0; i < cdi->tracks_num; i++) { - ct = &(cdi->tracks[i]); - if (((ct->point >= 1) && (ct->point <= 99)) || (ct->point >= 0xb0)) { - if (ct->point == 0xb0) { - /* Point B0h found, add the previous three lead tracks. */ - for (int j = 0; j < 3; j++) { - map[pos] = lead[j]; - pos++; - } - } - - map[pos] = i; - pos++; - } else if ((ct->point >= 0xa0) && (ct->point <= 0xa2)) - lead[ct->point & 0x03] = i; - } - - /* The last lead tracks. */ - for (int i = 0; i < 3; i++) { - map[pos] = lead[i]; - pos++; - } -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - cdrom_image_backend_log("pos = %i, cdi->tracks_num = %i\n", pos, cdi->tracks_num); - for (int i = 0; i < pos; i++) - cdrom_image_backend_log("map[%02i] = %02X\n", i, map[i]); -#endif - - cdrom_image_backend_log("Second pass:\n"); - for (int i = (cdi->tracks_num - 1); i >= 0; i--) { - ct = &(cdi->tracks[map[i]]); - if (ct->idx[1].type != INDEX_SPECIAL) { - for (int j = 2; j >= 0; j--) { - ci = &(ct->idx[j]); - - if ((ci->type >= INDEX_ZERO) && (ci->file != tf)) { - tf = ci->file; - if (tf != NULL) { - tf_len = tf->get_length(tf) / ct->sector_size; - cdrom_image_backend_log(" File length: %016" PRIX64 " sectors\n", tf_len); - } - } - - if (ci->type == INDEX_NONE) { - /* Index was not in the cue sheet, keep its length at zero. */ - ci->file_start = tf_len; - } else if (ci->type == INDEX_NORMAL) { - /* Index was in the cue sheet and is present in the file. */ - ci->file_length = tf_len - ci->file_start; - tf_len -= ci->file_length; - } - - cdrom_image_backend_log(" TRACK %2i (%2i), ATTR %02X, INDEX %i: %2i, file_start = %016" - PRIX64 " (%2i:%02i:%02i), file_length = %016" PRIX64 " (%2i:%02i:%02i)\n", - i, map[i], - ct->attr, - j, ci->type, - ci->file_start, - (int) ((ci->file_start / 75) / 60), - (int) ((ci->file_start / 75) % 60), - (int) (ci->file_start % 75), - ci->file_length, - (int) ((ci->file_length / 75) / 60), - (int) ((ci->file_length / 75) % 60), - (int) (ci->file_length % 75)); - } - } - } - - cdrom_image_backend_log("Third pass:\n"); - for (int i = 0; i < cdi->tracks_num; i++) { - int session_changed = 0; - - ct = &(cdi->tracks[map[i]]); - if (ct->idx[1].type != INDEX_SPECIAL) { - if (ct->session != ls) { - /* The first track of a session always has a pre-gap of at least 0:02:00. */ - ci = &(ct->idx[0]); - if (ci->type == INDEX_NONE) { - ci->type = INDEX_ZERO; - ci->start = 0ULL; - ci->length = 150ULL; - } - - session_changed = 1; - ls = ct->session; - } - - for (int j = 0; j < 3; j++) { - ci = &(ct->idx[j]); - - if (ci->type == INDEX_NONE) - /* Index was not in the cue sheet, keep its length at zero. */ - ci->start = cur_pos; - else if (ci->type == INDEX_ZERO) { - /* Index was in the cue sheet and is not present in the file. */ - ci->start = cur_pos; - cur_pos += ci->length; - } else if (ci->type == INDEX_NORMAL) { - /* Index was in the cue sheet and is present in the file. */ - ci->start = cur_pos; - ci->length = ci->file_length; - cur_pos += ci->file_length; - } - - cdrom_image_backend_log(" TRACK %2i (%2i) (%2i), ATTR %02X, MODE %i, INDEX %i: %2i, " - "start = %016" PRIX64 " (%2i:%02i:%02i), length = %016" PRIX64 - " (%2i:%02i:%02i)\n", - i, map[i], - ct->point, ct->attr, - ct->mode, - j, ci->type, - ci->start, - (int) ((ci->start / 75) / 60), - (int) ((ci->start / 75) % 60), - (int) (ci->start % 75), - ci->length, - (int) ((ci->length / 75) / 60), - (int) ((ci->length / 75) % 60), - (int) (ci->length % 75)); - - /* Set the pre-gap of the first track of this session. */ - if (session_changed) - spg[ct->session] = ct->idx[0].start; - } - } - } - - /* Set the lead out starts for all sessions. */ - for (int i = 0; i <= ls; i++) { - lo[i] = NULL; - for (int j = (cdi->tracks_num - 1); j >= 0; j--) { - track_t *jt = &(cdi->tracks[j]); - if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { - lo[i] = &(cdi->tracks[j]); - break; - } - } - } - - cdrom_image_backend_log("Fourth pass:\n"); - for (int i = 0; i < cdi->tracks_num; i++) { - ct = &(cdi->tracks[i]); - lt = NULL; - switch (ct->point) { - case 0xa0: - for (int j = 0; j < cdi->tracks_num; j++) { - track_t *jt = &(cdi->tracks[j]); - if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { - lt = &(cdi->tracks[j]); - break; - } - } - if (lt != NULL) { - int disc_type = 0x00; - - ct->attr = lt->attr; - - ct->mode = lt->mode; - ct->form = lt->form; - - if (lt->mode == 2) - disc_type = (lt->form > 0) ? 0x20 : 0x10; - for (int j = 0; j < 3; j++) { - ci = &(ct->idx[j]); - ci->type = INDEX_ZERO; - ci->start = (lt->point * 60 * 75) + (disc_type * 75); - ci->length = 0; - } - } - break; - case 0xa1: - for (int j = (cdi->tracks_num - 1); j >= 0; j--) { - track_t *jt = &(cdi->tracks[j]); - if ((jt->session == ct->session) && (jt->point >= 1) && (jt->point <= 99)) { - lt = &(cdi->tracks[j]); - break; - } - } - if (lt != NULL) { - ct->attr = lt->attr; - - ct->mode = lt->mode; - ct->form = lt->form; - - for (int j = 0; j < 3; j++) { - ci = &(ct->idx[j]); - ci->type = INDEX_ZERO; - ci->start = (lt->point * 60 * 75); - ci->length = 0; - } - } - break; - case 0xa2: - if (lo[ct->session] != NULL) { - lt = lo[ct->session]; - - ct->attr = lt->attr; - - ct->mode = lt->mode; - ct->form = lt->form; - - if (ct->idx[1].type != INDEX_NORMAL) { - track_index_t *li = &(lt->idx[2]); - - for (int j = 0; j < 3; j++) { - ci = &(ct->idx[j]); - ci->type = INDEX_ZERO; - ci->start = li->start + li->length; - ci->length = 0; - } - } - } - break; - case 0xb0: - /* - B0 MSF (*NOT* PMSF) points to the beginning of the pre-gap - of the corresponding session's first track. - */ - ct->extra[0] = (spg[ct->session] / 75) / 60; - ct->extra[1] = (spg[ct->session] / 75) % 60; - ct->extra[2] = spg[ct->session] % 75; - - /* - B0 PMSF points to the start of the lead out track - of the last session. - */ - if (lo[ls] != NULL) { - lt = lo[ls]; - track_index_t *li = &(lt->idx[2]); - - ct->idx[1].start = li->start + li->length; - } - break; - } - -#ifdef ENABLE_CDROM_IMAGE_BACKEND_LOG - if ((ct->point >= 0xa0) && (ct->point <= 0xa2)) - cdrom_image_backend_log(" TRACK %02X, SESSION %i: start = %016" PRIX64 " (%2i:%02i:%02i)\n", - ct->point, ct->session, - ct->idx[1].start, - (int) ((ct->idx[1].start / 75) / 60), - (int) ((ct->idx[1].start / 75) % 60), - (int) (ct->idx[1].start % 75)); -#endif - } -} - -int -cdi_load_iso(cd_img_t *cdi, const char *filename) -{ - track_t *ct = NULL; - track_index_t *ci = NULL; - track_file_t *tf = NULL; - int success; - int error = 1; - int is_viso = 0; - - cdi->tracks = NULL; - success = 1; - - cdrom_image_backend_log("First pass:\n"); - cdi->tracks_num = 0; - - cdi_insert_track(cdi, 1, 0xa0); - cdi_insert_track(cdi, 1, 0xa1); - cdi_insert_track(cdi, 1, 0xa2); - - /* Data track (shouldn't there be a lead in track?). */ - tf = track_file_init(filename, &error, &is_viso); - - if (error) { - cdrom_image_backend_log("ISO: cannot open file '%s'!\n", filename); - - if (tf != NULL) { - tf->close(tf); - tf = NULL; - } - success = 0; - } else if (is_viso) - success = 3; - - if (success) { - ct = cdi_insert_track(cdi, 1, 1); - ci = &(ct->idx[1]); - - ct->form = 0; - ct->mode = 0; - - for (int i = 0; i < 3; i++) - ct->idx[i].type = INDEX_NONE; - - ct->attr = DATA_TRACK; - - /* Try to detect ISO type. */ - ct->mode = 1; - ct->form = 0; - - ci->type = INDEX_NORMAL; - ci->file_start = 0ULL; - - ci->file = tf; - - /* For Mode 2 XA, skip the first 8 bytes in every sector when sector size = 2336. */ - if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 0, 0)) - ct->sector_size = RAW_SECTOR_SIZE; - else if (cdi_can_read_pvd(ci->file, 2336, 1, 0)) { - ct->sector_size = 2336; - ct->mode = 2; - } else if (cdi_can_read_pvd(ci->file, 2324, 1, 2)) { - ct->sector_size = 2324; - ct->mode = 2; - ct->form = 2; - } else if (cdi_can_read_pvd(ci->file, 2328, 1, 2)) { - ct->sector_size = 2328; - ct->mode = 2; - ct->form = 2; - } else if (cdi_can_read_pvd(ci->file, 2336, 1, 1)) { - ct->sector_size = 2336; - ct->mode = 2; - ct->form = 1; - ct->skip = 8; - } else if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 1, 0)) { - ct->sector_size = RAW_SECTOR_SIZE; - ct->mode = 2; - } else if (cdi_can_read_pvd(ci->file, RAW_SECTOR_SIZE, 1, 1)) { - ct->sector_size = RAW_SECTOR_SIZE; - ct->mode = 2; - ct->form = 1; - } else { - /* We use 2048 mode 1 as the default. */ - ct->sector_size = COOKED_SECTOR_SIZE; - } - - cdrom_image_backend_log("TRACK 1: Mode = %i, Form = %i, Sector size = %08X\n", - ct->mode, ct->form, ct->sector_size); - } - - tf = NULL; - - if (!success) - return 0; - - cdi_last_3_passes(cdi); - - return success; -} - -int -cdi_load_cue(cd_img_t *cdi, const char *cuefile) -{ - track_t *ct = NULL; - track_index_t *ci = NULL; - track_file_t *tf = NULL; - uint64_t frame = 0ULL; - uint64_t last = 0ULL; - uint8_t session = 1; - int success; - int error; - int is_viso = 0; - int lead[3] = { 0 }; - char pathname[MAX_FILENAME_LENGTH]; - char buf[MAX_LINE_LENGTH]; - FILE *fp; - char *line; - char *command; - char *type; - char temp; - - cdi->tracks = NULL; - cdi->tracks_num = 0; - - /* Get a copy of the filename into pathname, we need it later. */ - memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(char)); - path_get_dirname(pathname, cuefile); - - /* Open the file. */ - fp = plat_fopen(cuefile, "r"); - if (fp == NULL) - return 0; - - success = 0; - - cdrom_image_backend_log("First pass:\n"); - cdi->tracks_num = 0; - - for (int i = 0; i < 3; i++) { - lead[i] = cdi->tracks_num; - (void *) cdi_insert_track(cdi, session, 0xa0 + i); - } - cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) &(cdi->tracks[lead[2]])); - - while (1) { - line = buf; - - /* Read a line from the cuesheet file. */ - if (feof(fp) || (fgets(buf, sizeof(buf), fp) == NULL) || ferror(fp)) - break; - - /* Do two iterations to make sure to nuke even if it's \r\n or \n\r, - but do checks to make sure we're not nuking other bytes. */ - for (uint8_t i = 0; i < 2; i++) { - if (strlen(buf) > 0) { - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; - /* nuke trailing newline */ - else if (buf[strlen(buf) - 1] == '\r') - buf[strlen(buf) - 1] = '\0'; - /* nuke trailing newline */ - } - } - cdrom_image_backend_log(" line = %s\n", line); - - (void) cdi_cue_get_keyword(&command, &line); - - if (!strcmp(command, "FILE")) { - /* The file for the track. */ - char filename[MAX_FILENAME_LENGTH]; - char ansi[MAX_FILENAME_LENGTH]; - - tf = NULL; - - memset(ansi, 0, MAX_FILENAME_LENGTH * sizeof(char)); - memset(filename, 0, MAX_FILENAME_LENGTH * sizeof(char)); - - success = cdi_cue_get_buffer(ansi, &line, 0); - if (!success) - break; - success = cdi_cue_get_keyword(&type, &line); - if (!success) - break; - - error = 1; - is_viso = 0; - - if (!strcmp(type, "BINARY") || !strcmp(type, "MOTOROLA")) { - if (!path_abs(ansi)) - path_append_filename(filename, pathname, ansi); - else - strcpy(filename, ansi); - - tf = track_file_init(filename, &error, &is_viso); - - if (tf) - tf->motorola = !strcmp(type, "MOTOROLA"); - } else if (!strcmp(type, "WAVE") || !strcmp(type, "AIFF") || !strcmp(type, "MP3")) { - if (!path_abs(ansi)) - path_append_filename(filename, pathname, ansi); - else - strcpy(filename, ansi); - tf = audio_init(filename, &error); - } - if (error) { - cdrom_image_backend_log("CUE: cannot open file '%s' in cue sheet!\n", - filename); - - if (tf != NULL) { - tf->close(tf); - tf = NULL; - } - success = 0; - } else if (is_viso) - success = 3; - } else if (!strcmp(command, "TRACK")) { - int t = cdi_cue_get_number(&line); - success = cdi_cue_get_keyword(&type, &line); - - if (!success) - break; - - ct = cdi_insert_track(cdi, session, t); - - cdrom_image_backend_log(" TRACK %i\n", t); - - ct->form = 0; - ct->mode = 0; - - if (!strcmp(type, "AUDIO")) { - ct->sector_size = RAW_SECTOR_SIZE; - ct->attr = AUDIO_TRACK; - } else if (!memcmp(type, "MODE", 4)) { - uint32_t mode; - ct->attr = DATA_TRACK; - sscanf(type, "MODE%" PRIu32 "/%" PRIu32, &mode, &(ct->sector_size)); - ct->mode = mode; - if (ct->mode == 2) switch(ct->sector_size) { - case 2324: case 2328: - ct->form = 2; - break; - case 2048: case 2336: case 2352: case 2448: - ct->form = 1; - break; - } - if ((ct->sector_size == 2336) && (ct->mode == 2) && (ct->form == 1)) - ct->skip = 8; - } else if (!memcmp(type, "CD", 2)) { - ct->attr = DATA_TRACK; - ct->mode = 2; - sscanf(type, "CD%c/%i", &temp, &(ct->sector_size)); - } else - success = 0; - - if (success) - last = ct->sector_size; - } else if (!strcmp(command, "INDEX")) { - int t = cdi_cue_get_number(&line); - ci = &(ct->idx[t]); - - cdrom_image_backend_log(" INDEX %i (1)\n", t); - - ci->type = INDEX_NORMAL; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &line); - ci->file_start = frame; - } else if (!strcmp(command, "PREGAP")) { - ci = &(ct->idx[0]); - cdrom_image_backend_log(" INDEX 0 (0)\n"); - - ci->type = INDEX_ZERO; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &line); - ci->length = frame; - } else if (!strcmp(command, "PAUSE")) { - ci = &(ct->idx[1]); - cdrom_image_backend_log(" INDEX 1 (0)\n"); - - ci->type = INDEX_ZERO; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &line); - ci->length = frame; - } else if (!strcmp(command, "POSTGAP")) { - ci = &(ct->idx[2]); - cdrom_image_backend_log(" INDEX 2 (0)\n"); - - ci->type = INDEX_ZERO; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &line); - ci->length = frame; - } else if (!strcmp(command, "ZERO")) { - ci = &(ct->idx[1]); - cdrom_image_backend_log(" INDEX 1 (0)\n"); - - ci->type = INDEX_ZERO; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &line); - ci->length = frame; - } else if (!strcmp(command, "FLAGS")) - success = cdi_cue_get_flags(ct, &line); - else if (!strcmp(command, "REM")) { - success = 1; - char *space = strstr(line, " "); - if (space != NULL) { - space++; - if (space < (line + strlen(line))) { - (void) cdi_cue_get_keyword(&command, &space); - if (!strcmp(command, "LEAD-OUT")) { - ct = &(cdi->tracks[lead[2]]); - cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", (uint64_t) ct); - ct->sector_size = last; - ci = &(ct->idx[1]); - ci->type = INDEX_NORMAL; - ci->file = tf; - success = cdi_cue_get_frame(&frame, &space); - ci->file_start = frame; - - cdrom_image_backend_log(" LEAD-OUT\n"); - } else if (!strcmp(command, "SESSION")) { - session = cdi_cue_get_number(&space); - - if (session > 1) { - ct = cdi_insert_track(cdi, session - 1, 0xb0); - ci = &(ct->idx[1]); - ci->start = (0x40 * 60 * 75) + (0x02 * 75); - - if (session == 2) { - ct->extra[3] = 0x02; - - /* 5F:00:00 on Wembley, C0:00:00 in the spec. And what's in PMSF? */ - ct = cdi_insert_track(cdi, session - 1, 0xc0); - ci = &(ct->idx[1]); - ct->extra[0] = 0x5f; /* Optimum recording power. */ - } else - ct->extra[3] = 0x01; - - for (int i = 0; i < 3; i++) { - lead[i] = cdi->tracks_num; - (void *) cdi_insert_track(cdi, session, 0xa0 + i); - } - cdrom_image_backend_log("lead[2] = %016" PRIX64 "\n", - (uint64_t) &(cdi->tracks[lead[2]])); - } - - cdrom_image_backend_log(" SESSION %i\n", session); - } - } - } - } else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || - !strcmp(command, "ISRC") || !strcmp(command, "PERFORMER") || - !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || - !strcmp(command, "")) - /* Ignored commands. */ - success = 1; - else { - cdrom_image_backend_log("CUE: unsupported command '%s' in cue sheet!\n", command); - - success = 0; - } - - if (!success) - break; - } - - tf = NULL; - - fclose(fp); - - if (!success) - return 0; - - cdi_last_3_passes(cdi); - - return success; -} - -/* Root functions. */ -static void -cdi_clear_tracks(cd_img_t *cdi) -{ - track_file_t *last = NULL; - track_t *cur = NULL; - track_index_t *idx = NULL; - - if ((cdi->tracks == NULL) || (cdi->tracks_num == 0)) - return; - - for (int i = 0; i < cdi->tracks_num; i++) { - cur = &cdi->tracks[i]; - - if ((cur->point >= 1) && (cur->point <= 99)) for (int j = 0; j < 3; j++) { - idx = &(cur->idx[j]); - - /* Make sure we do not attempt to close a NULL file. */ - if (idx->file != NULL) { - if (idx->file != last) { - last = idx->file; - index_file_close(idx); - } else - idx->file = NULL; - } - } - } - - /* Now free the array. */ - free(cdi->tracks); - cdi->tracks = NULL; - - /* Mark that there's no tracks. */ - cdi->tracks_num = 0; -} - -void -cdi_close(cd_img_t *cdi) -{ - cdi_clear_tracks(cdi); - free(cdi); -} - -int -cdi_set_device(cd_img_t *cdi, const char *path) -{ - uintptr_t ext = path + strlen(path) - strrchr(path, '.'); - int ret; - - cdrom_image_backend_log("cdi_set_device(): %" PRIu64 ", %lli, %s\n", - ext, strlen(path), path + strlen(path) - ext + 1); - - if ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE")) { - if ((ret = cdi_load_cue(cdi, path))) - return ret; - - cdi_clear_tracks(cdi); - } - - if ((ret = cdi_load_iso(cdi, path))) - return ret; - - cdi_close(cdi); - - return 0; -} diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index 24f60836d..52657e38d 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -21,7 +21,9 @@ #define __STDC_FORMAT_MACROS #include #include +#ifdef IMAGE_VISO_LOG #include +#endif #include #include #include @@ -29,15 +31,16 @@ #include #include #include -#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/bswap.h> -#include <86box/cdrom_image_backend.h> +#include <86box/cdrom.h> +#include <86box/cdrom_image.h> +#include <86box/cdrom_image_viso.h> +#include <86box/log.h> #include <86box/path.h> #include <86box/plat.h> #include <86box/plat_dir.h> #include <86box/version.h> -#include <86box/timer.h> #include <86box/nvr.h> #ifndef S_ISDIR @@ -136,29 +139,30 @@ static const char rr_eid[] = "RRIP_1991A"; /* identifiers used in ER field for static const char rr_edesc[] = "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."; static int8_t tz_offset = 0; -#ifdef ENABLE_CDROM_IMAGE_VISO_LOG -int cdrom_image_viso_do_log = ENABLE_CDROM_IMAGE_VISO_LOG; +#ifdef IMAGE_VISO_LOG +int image_viso_do_log = IMAGE_VISO_LOG; void -cdrom_image_viso_log(const char *fmt, ...) +image_viso_log(void *priv, const char *fmt, ...) { va_list ap; - if (cdrom_image_viso_do_log) { + if (image_viso_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define cdrom_image_viso_log(fmt, ...) +# define image_viso_log(priv, fmt, ...) #endif static size_t -viso_pread(void *ptr, uint64_t offset, size_t size, size_t count, FILE *fp) +viso_pread(void *ptr, const uint64_t offset, const size_t size, + const size_t count, FILE *fp) { - uint64_t cur_pos = ftello64(fp); - size_t ret = 0; + const uint64_t cur_pos = ftello64(fp); + size_t ret = 0; if (fseeko64(fp, offset, SEEK_SET) != -1) ret = fread(ptr, size, count, fp); fseeko64(fp, cur_pos, SEEK_SET); @@ -166,10 +170,11 @@ viso_pread(void *ptr, uint64_t offset, size_t size, size_t count, FILE *fp) } static size_t -viso_pwrite(const void *ptr, uint64_t offset, size_t size, size_t count, FILE *fp) +viso_pwrite(const void *ptr, const uint64_t offset, const size_t size, + const size_t count, FILE *fp) { - uint64_t cur_pos = ftello64(fp); - size_t ret = 0; + const uint64_t cur_pos = ftello64(fp); + size_t ret = 0; if (fseeko64(fp, offset, SEEK_SET) != -1) ret = fwrite(ptr, size, count, fp); fseeko64(fp, cur_pos, SEEK_SET); @@ -691,22 +696,22 @@ viso_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count) /* Close any existing FIFO entry's file. */ viso_entry_t *other_entry = viso->file_fifo[viso->file_fifo_pos]; if (other_entry && other_entry->file) { - cdrom_image_viso_log("VISO: Closing [%s]", other_entry->path); + image_viso_log(viso->tf.log, "Closing [%s]...\n", other_entry->path); fclose(other_entry->file); other_entry->file = NULL; - cdrom_image_viso_log("\n"); + image_viso_log(viso->tf.log, "Done\n"); } /* Open file. */ - cdrom_image_viso_log("VISO: Opening [%s]", entry->path); + image_viso_log(viso->tf.log, "Opening [%s]...\n", entry->path); if ((entry->file = fopen(entry->path, "rb"))) { - cdrom_image_viso_log("\n"); + image_viso_log(viso->tf.log, "Done\n"); /* Add this entry to the FIFO. */ viso->file_fifo[viso->file_fifo_pos++] = entry; viso->file_fifo_pos &= (sizeof(viso->file_fifo) / sizeof(viso->file_fifo[0])) - 1; } else { - cdrom_image_viso_log(" => failed\n"); + image_viso_log(viso->tf.log, "Failed\n"); /* Clear any existing FIFO entry. */ viso->file_fifo[viso->file_fifo_pos] = NULL; @@ -753,12 +758,12 @@ viso_close(void *priv) if (viso == NULL) return; - cdrom_image_viso_log("VISO: close()\n"); + image_viso_log(viso->tf.log, "close()\n"); /* De-allocate everything. */ if (tf->fp) fclose(tf->fp); -#ifndef ENABLE_CDROM_IMAGE_VISO_LOG +#ifndef ENABLE_IMAGE_VISO_LOG remove(nvr_path(viso->tf.fn)); #endif @@ -777,21 +782,32 @@ viso_close(void *priv) if (viso->entry_map) free(viso->entry_map); + if (tf->log != NULL) { + + } + free(viso); } track_file_t * -viso_init(const char *dirname, int *error) +viso_init(const uint8_t id, const char *dirname, int *error) { - cdrom_image_viso_log("VISO: init()\n"); - /* Initialize our data structure. */ viso_t *viso = (viso_t *) calloc(1, sizeof(viso_t)); uint8_t *data = NULL; uint8_t *p; *error = 1; + if (viso == NULL) goto end; + + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i VISO ", id + 1); + viso->tf.log = log_open(n); + + image_viso_log(viso->tf.log, "init()\n"); + viso->sector_size = VISO_SECTOR_SIZE; viso->format = VISO_FORMAT_ISO | VISO_FORMAT_JOLIET | VISO_FORMAT_RR; viso->use_version_suffix = (viso->format & VISO_FORMAT_ISO); /* cleared later if required */ @@ -802,7 +818,7 @@ viso_init(const char *dirname, int *error) goto end; /* Open temporary file. */ -#ifdef ENABLE_CDROM_IMAGE_VISO_LOG +#ifdef ENABLE_IMAGE_VISO_LOG strcpy(viso->tf.fn, "viso-debug.iso"); #else plat_tempfile(viso->tf.fn, "viso", ".tmp"); @@ -812,7 +828,7 @@ viso_init(const char *dirname, int *error) goto end; /* Set up directory traversal. */ - cdrom_image_viso_log("VISO: Traversing directories:\n"); + image_viso_log(viso->tf.log, "Traversing directories:\n"); viso_entry_t *entry; viso_entry_t *last_entry; viso_entry_t *dir; @@ -839,7 +855,7 @@ viso_init(const char *dirname, int *error) if (!S_ISDIR(dir->stats.st_mode)) /* root is not a directory */ goto end; dir->parent = dir; /* for the root's path table and .. entries */ - cdrom_image_viso_log("[%08X] %s => [root]\n", dir, dir->path); + image_viso_log(viso->tf.log, "[%08X] %s => [root]\n", dir, dir->path); /* Traverse directories, starting with the root. */ viso_entry_t **dir_entries = NULL; @@ -889,7 +905,8 @@ viso_init(const char *dirname, int *error) /* Set basename. */ strcpy(entry->name_short, children_count ? ".." : "."); - cdrom_image_viso_log("[%08X] %s => %s\n", entry, dir->path, entry->name_short); + image_viso_log(viso->tf.log, "[%08X] %s => %s\n", entry, + dir->path, entry->name_short); } /* Iterate through this directory's children again, making the entries. */ @@ -897,12 +914,16 @@ viso_init(const char *dirname, int *error) rewinddir(dirp); while ((readdir_entry = readdir(dirp))) { /* Ignore . and .. pseudo-directories. */ - if ((readdir_entry->d_name[0] == '.') && ((readdir_entry->d_name[1] == '\0') || (*((uint16_t *) &readdir_entry->d_name[1]) == '.'))) + if ((readdir_entry->d_name[0] == '.') && + ((readdir_entry->d_name[1] == '\0') || + (*((uint16_t *) &readdir_entry->d_name[1]) == '.'))) continue; /* Add and fill entry. */ - entry = dir_entries[children_count++] = (viso_entry_t *) calloc(1, sizeof(viso_entry_t) + dir_path_len + strlen(readdir_entry->d_name) + 2); - if (!entry) + entry = dir_entries[children_count++] = + (viso_entry_t *) calloc(1, sizeof(viso_entry_t) + + dir_path_len + strlen(readdir_entry->d_name) + 2); + if (entry == NULL) break; entry->parent = dir; strcpy(entry->path, dir->path); @@ -972,10 +993,12 @@ have_eltorito_entry: continue; } - cdrom_image_viso_log("[%08X] %s => [%-12s] %s\n", entry, dir->path, entry->name_short, entry->basename); + image_viso_log(viso->tf.log, "[%08X] %s => [%-12s] %s\n", entry, + dir->path, entry->name_short, entry->basename); } } else { - cdrom_image_viso_log("VISO: Failed to enumerate [%s], will be empty\n", dir->path); + image_viso_log(viso->tf.log, "Failed to enumerate [%s], will be empty\n", + dir->path); } /* Add terminator. */ @@ -1129,13 +1152,17 @@ next_dir: /* Write El Torito boot descriptor. This is an awkward spot for that, but the spec requires it to be the second descriptor. */ if (!i && eltorito_entry) { - cdrom_image_viso_log("VISO: Writing El Torito boot descriptor for entry [%08X]\n", eltorito_entry); + image_viso_log(viso->tf.log, "Writing El Torito boot descriptor for " + "entry [%08X]\n", eltorito_entry); p = data; if (!(viso->format & VISO_FORMAT_ISO)) - VISO_LBE_32(p, ftello64(viso->tf.fp) / viso->sector_size); /* sector offset (HSF only) */ - *p++ = 0; /* type */ - memcpy(p, (viso->format & VISO_FORMAT_ISO) ? "CD001" : "CDROM", 5); /* standard ID */ + /* Sector offset (HSF only). */ + VISO_LBE_32(p, ftello64(viso->tf.fp) / viso->sector_size); + /* Type. */ + *p++ = 0; + /* Standard ID. */ + memcpy(p, (viso->format & VISO_FORMAT_ISO) ? "CD001" : "CDROM", 5); p += 5; *p++ = 1; /* version */ @@ -1236,7 +1263,7 @@ next_dir: /* Write each path table. */ for (int i = 0; i <= ((max_vd << 1) | 1); i++) { - cdrom_image_viso_log("VISO: Generating path table #%d:\n", i); + image_viso_log(viso->tf.log, "Generating path table #%d:\n", i); /* Save this path table's start offset. */ uint64_t pt_start = ftello64(viso->tf.fp); @@ -1257,7 +1284,9 @@ next_dir: continue; } - cdrom_image_viso_log("[%08X] %s => %s\n", dir, dir->path, ((i & 2) || (dir == viso->root_dir)) ? dir->basename : dir->name_short); + image_viso_log(viso->tf.log, "[%08X] %s => %s\n", dir, + dir->path, ((i & 2) || (dir == viso->root_dir)) ? dir->basename : + dir->name_short); /* Save this directory's path table index and offset. */ dir->pt_idx = pt_idx; @@ -1325,7 +1354,7 @@ next_dir: /* Write directory records for each type. */ int dir_type = VISO_DIR_CURRENT_ROOT; for (int i = 0; i <= max_vd; i++) { - cdrom_image_viso_log("VISO: Generating directory record set #%d:\n", i); + image_viso_log(viso->tf.log, "Generating directory record set #%d:\n", i); /* Go through directories. */ dir = viso->root_dir; @@ -1368,8 +1397,10 @@ next_dir: if ((entry == eltorito_entry) || (entry == eltorito_dir)) goto next_entry; - cdrom_image_viso_log("[%08X] %s => %s\n", entry, dir->path, - ((dir_type == VISO_DIR_PARENT) ? ".." : ((dir_type < VISO_DIR_PARENT) ? "." : (i ? entry->basename : entry->name_short)))); + image_viso_log(viso->tf.log, "[%08X] %s => %s\n", entry, dir->path, + ((dir_type == VISO_DIR_PARENT) ? ".." : + ((dir_type < VISO_DIR_PARENT) ? "." : + (i ? entry->basename : entry->name_short)))); /* Fill directory record. */ viso_fill_dir_record(data, entry, viso, dir_type); @@ -1436,7 +1467,8 @@ next_entry: /* Allocate entry map for sector->file lookups. */ size_t orig_sector_size = viso->sector_size; while (1) { - cdrom_image_viso_log("VISO: Allocating entry map for %zu %zu-byte sectors\n", viso->entry_map_size, viso->sector_size); + image_viso_log(viso->tf.log, "Allocating entry map for %zu %zu-byte sectors\n", + viso->entry_map_size, viso->sector_size); viso->entry_map = (viso_entry_t **) calloc(viso->entry_map_size, sizeof(viso_entry_t *)); if (viso->entry_map) { /* Successfully allocated. */ @@ -1477,7 +1509,7 @@ next_entry: viso->all_sectors = viso->metadata_sectors; /* Go through files, assigning sectors to them. */ - cdrom_image_viso_log("VISO: Assigning sectors to files:\n"); + image_viso_log(viso->tf.log, "Assigning sectors to files:\n"); size_t base_factor = viso->sector_size / orig_sector_size; viso_entry_t *prev_entry = viso->root_dir; viso_entry_t **entry_map_p = viso->entry_map; @@ -1522,7 +1554,8 @@ next_entry: size_t size = entry->stats.st_size / viso->sector_size; if (entry->stats.st_size % viso->sector_size) size++; /* round up to the next sector */ - cdrom_image_viso_log("[%08X] %s => %zu + %zu sectors\n", entry, entry->path, viso->all_sectors, size); + image_viso_log(viso->tf.log, "[%08X] %s => %zu + %zu sectors\n", entry, + entry->path, viso->all_sectors, size); /* Allocate sectors to this file. */ viso->all_sectors += size; @@ -1541,9 +1574,10 @@ next_entry: viso_pwrite(data, viso->vol_size_offsets[i], 8, 1, viso->tf.fp); /* Metadata processing is finished, read it back to memory. */ - cdrom_image_viso_log("VISO: Reading back %zu %zu-byte sectors of metadata\n", viso->metadata_sectors, viso->sector_size); + image_viso_log(viso->tf.log, "Reading back %zu %zu-byte sectors of metadata\n", + viso->metadata_sectors, viso->sector_size); viso->metadata = (uint8_t *) calloc(viso->metadata_sectors, viso->sector_size); - if (!viso->metadata) + if (viso->metadata == NULL) goto end; fseeko64(viso->tf.fp, 0, SEEK_SET); size_t metadata_size = viso->metadata_sectors * viso->sector_size; @@ -1554,7 +1588,7 @@ next_entry: /* We no longer need the temporary file; close and delete it. */ fclose(viso->tf.fp); viso->tf.fp = NULL; -#ifndef ENABLE_CDROM_IMAGE_VISO_LOG +#ifndef ENABLE_IMAGE_VISO_LOG remove(nvr_path(viso->tf.fn)); #endif @@ -1565,13 +1599,15 @@ end: /* Set the function pointers. */ viso->tf.priv = viso; if (!*error) { - cdrom_image_viso_log("VISO: Initialized\n"); + image_viso_log(viso->tf.log, "Initialized\n"); + viso->tf.read = viso_read; viso->tf.get_length = viso_get_length; viso->tf.close = viso_close; + return &viso->tf; } else { - cdrom_image_viso_log("VISO: Initialization failed\n"); + image_viso_log(viso->tf.log, "Initialization failed\n"); if (data) free(data); viso_close(&viso->tf); diff --git a/src/cdrom/cdrom_ioctl.c b/src/cdrom/cdrom_ioctl.c deleted file mode 100644 index 2bb691f30..000000000 --- a/src/cdrom/cdrom_ioctl.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * CD-ROM passthrough support. - * - * - * - * Authors: TheCollector1995, , - * Miran Grca, - * - * Copyright 2023 TheCollector1995. - * Copyright 2023 Miran Grca. - */ -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/config.h> -#include <86box/path.h> -#include <86box/plat.h> -#include <86box/scsi_device.h> -#include <86box/cdrom.h> -#include <86box/plat_cdrom.h> - -#ifdef ENABLE_CDROM_IOCTL_LOG -int cdrom_ioctl_do_log = ENABLE_CDROM_IOCTL_LOG; - -void -cdrom_ioctl_log(const char *fmt, ...) -{ - va_list ap; - - if (cdrom_ioctl_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -# define cdrom_ioctl_log(fmt, ...) -#endif - -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) - -static void -ioctl_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) -{ - TMSF tmsf; - - plat_cdrom_get_audio_track_info(dev->local, end, track, &ti->number, &tmsf, &ti->attr); - - ti->m = tmsf.min; - ti->s = tmsf.sec; - ti->f = tmsf.fr; -} - -static void -ioctl_get_raw_track_info(cdrom_t *dev, int *num, raw_track_info_t *rti) -{ - plat_cdrom_get_raw_track_info(dev->local, num, rti); -} - -static void -ioctl_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) -{ - TMSF rel_pos; - TMSF abs_pos; - - if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) { - const uint32_t trk = plat_cdrom_get_track_start(dev->local, lba, &subc->attr, &subc->track); - - FRAMES_TO_MSF(lba + 150, &abs_pos.min, &abs_pos.sec, &abs_pos.fr); - - /* Absolute position should be adjusted by 150, not the relative ones. */ - FRAMES_TO_MSF(lba - trk, &rel_pos.min, &rel_pos.sec, &rel_pos.fr); - - subc->index = 1; - } else - plat_cdrom_get_audio_sub(dev->local, lba, &subc->attr, &subc->track, &subc->index, - &rel_pos, &abs_pos); - - subc->abs_m = abs_pos.min; - subc->abs_s = abs_pos.sec; - subc->abs_f = abs_pos.fr; - - subc->rel_m = rel_pos.min; - subc->rel_s = rel_pos.sec; - subc->rel_f = rel_pos.fr; - - cdrom_ioctl_log("ioctl_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, - subc->rel_m, subc->rel_s, subc->rel_f); -} - -static int -ioctl_get_capacity(cdrom_t *dev) -{ - int ret; - - ret = plat_cdrom_get_last_block(dev->local); - cdrom_ioctl_log("GetCapacity=%x.\n", ret); - return ret; -} - -static int -ioctl_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) -{ - int m; - int s; - int f; - - if (dev->cd_status == CD_STATUS_DATA_ONLY) - return 0; - - if (ismsf) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - pos = MSFtoLBA(m, s, f) - 150; - } - - /* GetTrack requires LBA. */ - return plat_cdrom_is_track_audio(dev->local, pos); -} - -static int -ioctl_is_track_pre(cdrom_t *dev, uint32_t lba) -{ - return plat_cdrom_is_track_pre(dev->local, lba); -} - -static int -ioctl_sector_size(cdrom_t *dev, uint32_t lba) -{ - cdrom_ioctl_log("LBA=%x.\n", lba); - return plat_cdrom_get_sector_size(dev->local, lba); -} - -static int -ioctl_read_sector(cdrom_t *dev, uint8_t *b, uint32_t lba) -{ - cdrom_ioctl_log("cdrom_ioctl_read_sector(): Raw.\n"); - return plat_cdrom_read_sector(dev->local, b, lba); -} - -static int -ioctl_track_type(cdrom_t *dev, uint32_t lba) -{ - int ret = CD_TRACK_UNK_DATA; - - if (ioctl_is_track_audio(dev, lba, 0)) - ret = CD_TRACK_AUDIO; - - cdrom_ioctl_log("cdrom_ioctl_track_type(): %i\n", ret); - - return ret; -} - -static int -ioctl_ext_medium_changed(cdrom_t *dev) -{ - int ret; - - if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED)) - ret = 0; - else - ret = plat_cdrom_ext_medium_changed(dev->local); - - if (ret == 1) { - dev->cd_status = CD_STATUS_STOPPED; - dev->cdrom_capacity = ioctl_get_capacity(dev); - } else if (ret == -1) - dev->cd_status = CD_STATUS_EMPTY; - - return ret; -} - -static void -ioctl_exit(cdrom_t *dev) -{ - cdrom_ioctl_log("CDROM: ioctl_exit(%s)\n", dev->image_path); - dev->cd_status = CD_STATUS_EMPTY; - - plat_cdrom_close(dev->local); - dev->local = NULL; - - dev->ops = NULL; -} - -static const cdrom_ops_t cdrom_ioctl_ops = { - ioctl_get_track_info, - ioctl_get_raw_track_info, - ioctl_get_subchannel, - ioctl_is_track_pre, - ioctl_sector_size, - ioctl_read_sector, - ioctl_track_type, - ioctl_ext_medium_changed, - ioctl_exit -}; - -static int -cdrom_ioctl_open_abort(cdrom_t *dev) -{ - cdrom_ioctl_close(dev); - dev->ops = NULL; - dev->image_path[0] = 0; - return 1; -} - -int -cdrom_ioctl_open(cdrom_t *dev, const char *drv) -{ - const char *actual_drv = &(drv[8]); - int local_size = plat_cdrom_get_local_size(); - - /* Make sure to not STRCPY if the two are pointing - at the same place. */ - if (drv != dev->image_path) - strcpy(dev->image_path, drv); - - /* Open the image. */ - if (strstr(drv, "ioctl://") != drv) - return cdrom_ioctl_open_abort(dev); - cdrom_ioctl_log("actual_drv = %s\n", actual_drv); - if (dev->local == NULL) - dev->local = calloc(1, local_size); - int i = plat_cdrom_set_drive(dev->local, actual_drv); - if (!i) - return cdrom_ioctl_open_abort(dev); - - /* All good, reset state. */ - dev->cd_status = CD_STATUS_STOPPED; - dev->seek_pos = 0; - dev->cd_buflen = 0; - dev->cdrom_capacity = ioctl_get_capacity(dev); - cdrom_ioctl_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes)\n", - dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity) << 11ULL); - - /* Attach this handler to the drive. */ - dev->ops = &cdrom_ioctl_ops; - - return 0; -} - -void -cdrom_ioctl_close(cdrom_t *dev) -{ - cdrom_ioctl_log("CDROM: ioctl_close(%s)\n", dev->image_path); - - if (dev && dev->ops && dev->ops->exit) - dev->ops->exit(dev); -} - diff --git a/src/cdrom/cdrom_mitsumi.c b/src/cdrom/cdrom_mitsumi.c index c3c362b1b..19fa06e23 100644 --- a/src/cdrom/cdrom_mitsumi.c +++ b/src/cdrom/cdrom_mitsumi.c @@ -118,14 +118,6 @@ typedef struct mcd_t { int newstat; } mcd_t; -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#ifdef MSFtoLBA -#undef MSFtoLBA -#endif -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) - #define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4)) #define CD_DCB(x) ((((x) &0xf0) >> 4) * 10 + ((x) &0x0f)) diff --git a/src/config.c b/src/config.c index 24efcf264..83b010eb2 100644 --- a/src/config.c +++ b/src/config.c @@ -29,12 +29,13 @@ */ #include +#ifdef ENABLE_CONFIG_LOG #include +#endif #include #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -53,10 +54,8 @@ #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/fdd.h> -#include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/gameport.h> -#include <86box/serial.h> #include <86box/serial_passthrough.h> #include <86box/machine.h> #include <86box/mouse.h> @@ -300,7 +299,7 @@ load_machine(void) /* Only copy if a file with the new name doesn't already exist. */ FILE *g = nvr_fopen(new_fn, "rb"); - if (!g) { + if (g == NULL) { FILE *f = nvr_fopen(entry->d_name, "rb"); g = nvr_fopen(new_fn, "wb"); @@ -361,7 +360,7 @@ load_machine(void) while (!cpu_family_is_eligible(&cpu_families[c], machine)) { if (cpu_families[c++].package == 0) { /* End of list. */ - fatal("No eligible CPU families for the selected machine\n"); + fatal("Configuration: No eligible CPU families for the selected machine\n"); return; } } @@ -441,7 +440,6 @@ load_video(void) if (free_p) { free(p); p = NULL; - free_p = 0; } } @@ -618,7 +616,7 @@ load_sound(void) memset(temp, '\0', sizeof(temp)); p = ini_section_get_string(cat, "sound_type", "float"); if (strlen(p) > 511) - fatal("load_sound(): strlen(p) > 511\n"); + fatal("Configuration: Length of sound_type is more than 511\n"); else strncpy(temp, p, 511); if (!strcmp(temp, "float") || !strcmp(temp, "1")) @@ -847,7 +845,6 @@ load_storage_controllers(void) if (free_p) { free(p); p = NULL; - free_p = 0; } ide_ter_enabled = !!ini_section_get_int(cat, "ide_ter", 0); @@ -866,7 +863,7 @@ load_storage_controllers(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_storage_controllers(): strlen(p) > 511 (cassette_fname)\n"); + fatal("Configuration: Length of cassette_file is more than 511\n"); else strncpy(cassette_fname, p, 511); } else @@ -876,7 +873,7 @@ load_storage_controllers(void) p = ini_section_get_string(cat, "cassette_mode", "load"); if (strlen(p) > 511) - fatal("load_storage_controllers(): strlen(p) > 511\n"); + fatal("Configuration: Length of cassette_mode is more than 511\n"); else strncpy(cassette_mode, p, 511); @@ -887,8 +884,8 @@ load_storage_controllers(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_storage_controllers(): strlen(p) > 2047 " - "(cassette_image_history[%i])\n", i); + fatal("Configuration: Length of cassette_image_history_%02i is more " + "than %i\n", i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(cassette_image_history[i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -937,7 +934,8 @@ load_storage_controllers(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_storage_controllers(): strlen(p) > 511 (cart_fns[%i])\n", c); + fatal("Configuration: Length of cartridge_%02i_fn is more than 511\n", + c + 1); else strncpy(cart_fns[c], p, 511); } else @@ -952,8 +950,8 @@ load_storage_controllers(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_storage_controllers(): strlen(p) > 2047 " - "(cart_image_history[%i][%i])\n", c, i); + fatal("Configuration: Length of cartridge_%02i_image_history_%02i " + "is more than %i\n", c + 1, i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(cart_image_history[c][i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -992,8 +990,8 @@ load_hard_disks(void) sscanf(p, "%u, %u, %u, %i, %s", &hdd[c].spt, &hdd[c].hpc, &hdd[c].tracks, (int *) &hdd[c].wp, s); - hdd[c].bus = hdd_string_to_bus(s, 0); - switch (hdd[c].bus) { + hdd[c].bus_type = hdd_string_to_bus(s, 0); + switch (hdd[c].bus_type) { default: case HDD_BUS_DISABLED: max_spt = max_hpc = max_tracks = 0; @@ -1039,7 +1037,7 @@ load_hard_disks(void) hdd[c].tracks = max_tracks; sprintf(temp, "hdd_%02i_speed", c + 1); - switch (hdd[c].bus) { + switch (hdd[c].bus_type) { case HDD_BUS_IDE: case HDD_BUS_ESDI: case HDD_BUS_ATAPI: @@ -1055,28 +1053,28 @@ load_hard_disks(void) /* MFM/RLL */ sprintf(temp, "hdd_%02i_mfm_channel", c + 1); - if (hdd[c].bus == HDD_BUS_MFM) + if (hdd[c].bus_type == HDD_BUS_MFM) hdd[c].mfm_channel = !!ini_section_get_int(cat, temp, c & 1); else ini_section_delete_var(cat, temp); /* XTA */ sprintf(temp, "hdd_%02i_xta_channel", c + 1); - if (hdd[c].bus == HDD_BUS_XTA) + if (hdd[c].bus_type == HDD_BUS_XTA) hdd[c].xta_channel = !!ini_section_get_int(cat, temp, c & 1); else ini_section_delete_var(cat, temp); /* ESDI */ sprintf(temp, "hdd_%02i_esdi_channel", c + 1); - if (hdd[c].bus == HDD_BUS_ESDI) + if (hdd[c].bus_type == HDD_BUS_ESDI) hdd[c].esdi_channel = !!ini_section_get_int(cat, temp, c & 1); else ini_section_delete_var(cat, temp); /* IDE */ sprintf(temp, "hdd_%02i_ide_channel", c + 1); - if ((hdd[c].bus == HDD_BUS_IDE) || (hdd[c].bus == HDD_BUS_ATAPI)) { + if ((hdd[c].bus_type == HDD_BUS_IDE) || (hdd[c].bus_type == HDD_BUS_ATAPI)) { sprintf(tmp2, "%01u:%01u", c >> 1, c & 1); p = ini_section_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); @@ -1090,7 +1088,7 @@ load_hard_disks(void) ini_section_delete_var(cat, temp); /* SCSI */ - if (hdd[c].bus == HDD_BUS_SCSI) { + if (hdd[c].bus_type == HDD_BUS_SCSI) { sprintf(temp, "hdd_%02i_scsi_location", c + 1); sprintf(tmp2, "%01u:%02u", SCSI_BUS_MAX, c + 2); p = ini_section_get_string(cat, temp, tmp2); @@ -1130,7 +1128,8 @@ load_hard_disks(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_hard_disks(): strlen(p) > 511 (hdd[%i].fn)\n", c); + fatal("Configuration: Length of hdd_%02i_fn is more " + "than 511\n", c + 1); else strncpy(hdd[c].fn, p, 511); } else @@ -1179,12 +1178,12 @@ load_floppy_and_cdrom_drives(void) char temp[512]; char tmp2[512]; char *p; - char *def_type; char s[512]; unsigned int board = 0; unsigned int dev = 0; int c; int d = 0; + int count = cdrom_get_type_count(); memset(temp, 0x00, sizeof(temp)); for (c = 0; c < FDD_NUM; c++) { @@ -1203,7 +1202,7 @@ load_floppy_and_cdrom_drives(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_floppy_and_cdrom_drives(): strlen(p) > 511 (floppyfns[%i])\n", c); + fatal("Configuration: Length of fdd_%02i_fn is more than 511\n", c + 1); else strncpy(floppyfns[c], p, 511); } else @@ -1251,8 +1250,8 @@ load_floppy_and_cdrom_drives(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_floppy_and_cdrom_drives(): strlen(p) > 2047 " - "(fdd_image_history[%i][%i])\n", c, i); + fatal("Configuration: Length of fdd_%02i_image_history_%02i is more " + "than %i\n", c + 1, i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(fdd_image_history[c][i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -1284,12 +1283,20 @@ load_floppy_and_cdrom_drives(void) cdrom[c].speed = ini_section_get_int(cat, temp, 8); sprintf(temp, "cdrom_%02i_type", c + 1); - def_type = (c == 1) ? "86BOX_CD-ROM_1.00" : "none"; - p = ini_section_get_string(cat, temp, def_type); - cdrom_set_type(c, cdrom_get_from_internal_name(p)); - if (cdrom_get_type(c) > KNOWN_CDROM_DRIVE_TYPES) - cdrom_set_type(c, KNOWN_CDROM_DRIVE_TYPES); - if (!strcmp(p, def_type)) + p = ini_section_get_string(cat, temp, "86cd"); + /* TODO: Configuration migration, remove when no longer needed. */ + int cdrom_type = cdrom_get_from_internal_name(p); + if (cdrom_type == -1) { + cdrom_type = cdrom_get_from_name(p); + if (cdrom_type == -1) + cdrom_set_type(c, cdrom_get_from_internal_name("86cd")); + else + cdrom_set_type(c, cdrom_type); + } else + cdrom_set_type(c, cdrom_type); + if (cdrom_get_type(c) >= count) + cdrom_set_type(c, count - 1); + if (!strcmp(p, "86cd")) ini_section_delete_var(cat, temp); /* Default values, needed for proper operation of the Settings dialog. */ @@ -1347,7 +1354,7 @@ load_floppy_and_cdrom_drives(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_floppy_and_cdrom_drives(): strlen(p) > 511 (cdrom[%i].image_path)\n", c); + fatal("Configuration: Length of cdrom_%02i_image_path is more than 511\n", c + 1); else strncpy(cdrom[c].image_path, p, 511); } else @@ -1362,8 +1369,8 @@ load_floppy_and_cdrom_drives(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_floppy_and_cdrom_drives(): strlen(p) > 2047 " - "(cdrom[%i].image_history[%i])\n", c, i); + fatal("Configuration: Length of cdrom_%02i_image_history_%02i is more " + "than %i\n", c + 1, i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(cdrom[c].image_history[i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -1378,6 +1385,12 @@ load_floppy_and_cdrom_drives(void) sprintf(temp, "cdrom_%02i_parameters", c + 1); ini_section_delete_var(cat, temp); + sprintf(temp, "cdrom_%02i_speed", c + 1); + ini_section_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_type", c + 1); + ini_section_delete_var(cat, temp); + sprintf(temp, "cdrom_%02i_ide_channel", c + 1); ini_section_delete_var(cat, temp); @@ -1476,8 +1489,7 @@ load_other_removable_devices(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_other_removable_devices(): strlen(p) > 511 (zip_drives[%i].image_path)\n", - c); + fatal("Configuration: Length of zip_%02i_image_path is more than 511\n", c + 1); else strncpy(zip_drives[c].image_path, p, 511); } else @@ -1492,8 +1504,8 @@ load_other_removable_devices(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_other_removable_devices(): strlen(p) > 2047 " - "(zip_drives[%i].image_history[%i])\n", c, i); + fatal("Configuration: Length of zip_%02i_image_history_%02i is more than %i\n", + c + 1, i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(zip_drives[c].image_history[i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -1589,8 +1601,7 @@ load_other_removable_devices(void) if (p[0] != 0x00) { if (path_abs(p)) { if (strlen(p) > 511) - fatal("load_other_removable_devices(): strlen(p) > 511 (mo_drives[%i].image_path)\n", - c); + fatal("Configuration: Length of mo_%02i_image_path is more than 511\n", c + 1); else strncpy(mo_drives[c].image_path, p, 511); } else @@ -1605,8 +1616,8 @@ load_other_removable_devices(void) if (p) { if (path_abs(p)) { if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) - fatal("load_other_removable_devices(): strlen(p) > 2047 " - "(mo_drives[%i].image_history[%i])\n", c, i); + fatal("Configuration: Length of mo_%02i_image_history_%02i is more than %i\n", + c + 1, i + 1, MAX_IMAGE_PATH_LEN - 1); else snprintf(mo_drives[c].image_history[i], MAX_IMAGE_PATH_LEN, "%s", p); } else @@ -1698,7 +1709,7 @@ config_load(void) config = ini_read(cfg_path); - if (!config) { + if (config == NULL) { config = ini_new(); config_changed = 1; @@ -2574,7 +2585,7 @@ save_hard_disks(void) for (uint8_t c = 0; c < HDD_NUM; c++) { sprintf(temp, "hdd_%02i_parameters", c + 1); if (hdd_is_valid(c)) { - p = hdd_bus_to_string(hdd[c].bus, 0); + p = hdd_bus_to_string(hdd[c].bus_type, 0); sprintf(tmp2, "%u, %u, %u, %i, %s", hdd[c].spt, hdd[c].hpc, hdd[c].tracks, hdd[c].wp, p); ini_section_set_string(cat, temp, tmp2); @@ -2582,25 +2593,26 @@ save_hard_disks(void) ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_mfm_channel", c + 1); - if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_MFM)) + if (hdd_is_valid(c) && (hdd[c].bus_type == HDD_BUS_MFM)) ini_section_set_int(cat, temp, hdd[c].mfm_channel); else ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_xta_channel", c + 1); - if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_XTA)) + if (hdd_is_valid(c) && (hdd[c].bus_type == HDD_BUS_XTA)) ini_section_set_int(cat, temp, hdd[c].xta_channel); else ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_esdi_channel", c + 1); - if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_ESDI)) + if (hdd_is_valid(c) && (hdd[c].bus_type == HDD_BUS_ESDI)) ini_section_set_int(cat, temp, hdd[c].esdi_channel); else ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_ide_channel", c + 1); - if (!hdd_is_valid(c) || ((hdd[c].bus != HDD_BUS_IDE) && (hdd[c].bus != HDD_BUS_ATAPI))) + if (!hdd_is_valid(c) || ((hdd[c].bus_type != HDD_BUS_IDE) && + (hdd[c].bus_type != HDD_BUS_ATAPI))) ini_section_delete_var(cat, temp); else { sprintf(tmp2, "%01u:%01u", hdd[c].ide_channel >> 1, hdd[c].ide_channel & 1); @@ -2611,7 +2623,7 @@ save_hard_disks(void) ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_scsi_location", c + 1); - if (hdd[c].bus != HDD_BUS_SCSI) + if (hdd[c].bus_type != HDD_BUS_SCSI) ini_section_delete_var(cat, temp); else { sprintf(tmp2, "%01u:%02u", hdd[c].scsi_id >> 4, @@ -2643,8 +2655,9 @@ save_hard_disks(void) ini_section_delete_var(cat, temp); sprintf(temp, "hdd_%02i_speed", c + 1); - if (!hdd_is_valid(c) || ((hdd[c].bus != HDD_BUS_ESDI) && (hdd[c].bus != HDD_BUS_IDE) && - (hdd[c].bus != HDD_BUS_SCSI) && (hdd[c].bus != HDD_BUS_ATAPI))) + if (!hdd_is_valid(c) || + ((hdd[c].bus_type != HDD_BUS_ESDI) && (hdd[c].bus_type != HDD_BUS_IDE) && + (hdd[c].bus_type != HDD_BUS_SCSI) && (hdd[c].bus_type != HDD_BUS_ATAPI))) ini_section_delete_var(cat, temp); else ini_section_set_string(cat, temp, hdd_preset_get_internal_name(hdd[c].speed_preset)); @@ -2729,11 +2742,12 @@ save_floppy_and_cdrom_drives(void) ini_section_set_int(cat, temp, cdrom[c].speed); sprintf(temp, "cdrom_%02i_type", c + 1); - if ((cdrom[c].bus_type == 0) || (cdrom[c].bus_type == CDROM_BUS_MITSUMI)) + char *tn = cdrom_get_internal_name(cdrom_get_type(c)); + if ((cdrom[c].bus_type == 0) || (cdrom[c].bus_type == CDROM_BUS_MITSUMI) || + !strcmp(tn, "86cd")) ini_section_delete_var(cat, temp); else - ini_section_set_string(cat, temp, - cdrom_get_internal_name(cdrom_get_type(c))); + ini_section_set_string(cat, temp, tn); sprintf(temp, "cdrom_%02i_parameters", c + 1); if (cdrom[c].bus_type == 0) diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 7228cba62..82314e6db 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -925,7 +925,7 @@ wd1007vse1_init(UNUSED(const device_t *info)) c = 0; for (uint8_t d = 0; d < HDD_NUM; d++) { - if ((hdd[d].bus == HDD_BUS_ESDI) && (hdd[d].esdi_channel < ESDI_NUM)) { + if ((hdd[d].bus_type == HDD_BUS_ESDI) && (hdd[d].esdi_channel < ESDI_NUM)) { loadhd(esdi, hdd[d].esdi_channel, d, hdd[d].fn); if (++c >= ESDI_NUM) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index c63c80721..539684b81 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1265,7 +1265,7 @@ esdi_init(UNUSED(const device_t *info)) dev->drives[0].present = dev->drives[1].present = 0; for (c = 0, i = 0; i < HDD_NUM; i++) { - if ((hdd[i].bus == HDD_BUS_ESDI) && (hdd[i].esdi_channel < ESDI_NUM)) { + if ((hdd[i].bus_type == HDD_BUS_ESDI) && (hdd[i].esdi_channel < ESDI_NUM)) { /* This is an ESDI drive. */ drive = &dev->drives[hdd[i].esdi_channel]; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index a212361dc..3af561989 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -486,7 +486,7 @@ ide_get_max(const ide_t *ide, const int type) int ret; if (ide->type == IDE_ATAPI) - ret = ide->get_max(!IDE_ATAPI_IS_EARLY && ata_4, type); + ret = ide->get_max(ide, !IDE_ATAPI_IS_EARLY && ata_4, type); else ret = max[ata_4][type]; @@ -501,7 +501,7 @@ ide_get_timings(const ide_t *ide, const int type) int ret; if (ide->type == IDE_ATAPI) - ret = ide->get_timings(!IDE_ATAPI_IS_EARLY && ata_4, type); + ret = ide->get_timings(ide, !IDE_ATAPI_IS_EARLY && ata_4, type); else ret = timings[ata_4][type]; @@ -643,7 +643,7 @@ ide_identify(ide_t *ide) memset(ide->buffer, 0, 512); if (ide->type == IDE_ATAPI) - ide->identify(ide, !IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL)); + ide->identify((const ide_t *) ide, !IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL)); else if (ide->type == IDE_HDD) ide_hd_identify(ide); else { @@ -973,7 +973,7 @@ ide_atapi_attach(ide_t *ide) ide->type = IDE_ATAPI; ide_allocate_buffer(ide); ide_set_signature(ide); - ide->mdma_mode = (1 << ide->get_max(!IDE_ATAPI_IS_EARLY && + ide->mdma_mode = (1 << ide->get_max((const ide_t *) ide, !IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL), TYPE_PIO)); ide->tf->error = 1; ide->cfg_spt = ide->cfg_hpc = 0; @@ -1655,7 +1655,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->sc->callback = 200.0 * IDE_TIME; if (ide->type == IDE_HDD) { - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); uint32_t sec_count; double wait_time; if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { @@ -1697,7 +1697,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on less times. */ - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); fallthrough; case WIN_WRITE: @@ -1885,7 +1885,7 @@ ide_read_data(ide_t *ide) ide_set_callback(ide, seek_us + xfer_us); } } else - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } } } @@ -2238,7 +2238,7 @@ ide_callback(void *priv) ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } break; @@ -2277,7 +2277,7 @@ ide_callback(void *priv) ide->tf->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } else { /* Bus master DMAS error, abort the command. */ ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); @@ -2346,10 +2346,10 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide->tf->pos = 0; ide_next_sector(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } else { ide->tf->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } if (ret < 0) err = UNC_ERR; @@ -2391,7 +2391,7 @@ ide_callback(void *priv) err = UNC_ERR; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } else { /* Bus master DMA error, abort the command. */ ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); @@ -2429,7 +2429,7 @@ ide_callback(void *priv) ide_next_sector(ide); } else { ide->tf->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } if (ret < 0) err = UNC_ERR; @@ -2446,7 +2446,7 @@ ide_callback(void *priv) ide->tf->pos = 0; ide->tf->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } break; @@ -2463,7 +2463,7 @@ ide_callback(void *priv) err = UNC_ERR; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } break; @@ -2759,7 +2759,7 @@ ide_board_setup(const int board) c = 0; for (d = 0; d < HDD_NUM; d++) { - const int is_ide = (hdd[d].bus == HDD_BUS_IDE); + const int is_ide = (hdd[d].bus_type == HDD_BUS_IDE); const int ch = hdd[d].ide_channel; const int valid_ch = ((ch >= min_ch) && (ch <= max_ch)); diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 631afa931..3b8da3f2e 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -475,19 +475,22 @@ sff_reset(void *priv) #endif for (uint8_t i = 0; i < HDD_NUM; i++) { - if ((hdd[i].bus == HDD_BUS_ATAPI) && (hdd[i].ide_channel < 4) && hdd[i].priv) + if ((hdd[i].bus_type == HDD_BUS_ATAPI) && (hdd[i].ide_channel < 4) && hdd[i].priv) scsi_disk_reset((scsi_common_t *) hdd[i].priv); } for (uint8_t i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && cdrom[i].priv) + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel < 4) && + cdrom[i].priv) scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); } for (uint8_t i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel < 4) && + zip_drives[i].priv) zip_reset((scsi_common_t *) zip_drives[i].priv); } for (uint8_t i = 0; i < MO_NUM; i++) { - if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel < 4) && mo_drives[i].priv) + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel < 4) && + mo_drives[i].priv) mo_reset((scsi_common_t *) mo_drives[i].priv); } diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index 9e5b82336..8cc5fe20a 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -749,7 +749,7 @@ mfm_init(UNUSED(const device_t *info)) c = 0; for (uint8_t d = 0; d < HDD_NUM; d++) { - if ((hdd[d].bus == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) { + if ((hdd[d].bus_type == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) { loadhd(mfm, hdd[d].mfm_channel, d, hdd[d].fn); st506_at_log("WD1003(%d): (%s) geometry %d/%d/%d\n", c, hdd[d].fn, diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index 766b28086..5d310e96b 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -1799,7 +1799,7 @@ st506_init(const device_t *info) st506_xt_log("ST506: looking for disks...\n"); #endif for (c = 0, i = 0; i < HDD_NUM; i++) { - if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) { + if ((hdd[i].bus_type == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) { st506_xt_log("ST506: disk '%s' on channel %i\n", hdd[i].fn, hdd[i].mfm_channel); loadhd(dev, hdd[i].mfm_channel, i, hdd[i].fn); diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index a65ab5c69..91bdd709d 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1038,7 +1038,7 @@ xta_init(const device_t *info) /* Load any disks for this device class. */ c = 0; for (uint8_t i = 0; i < HDD_NUM; i++) { - if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < max)) { + if ((hdd[i].bus_type == HDD_BUS_XTA) && (hdd[i].xta_channel < max)) { drive = &dev->drives[hdd[i].xta_channel]; if (!hdd_image_load(i)) { diff --git a/src/disk/hdd.c b/src/disk/hdd.c index c17f64863..25257e878 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -123,7 +123,7 @@ hdd_bus_to_string(int bus, UNUSED(int cdrom)) int hdd_is_valid(int c) { - if (hdd[c].bus == HDD_BUS_DISABLED) + if (hdd[c].bus_type == HDD_BUS_DISABLED) return 0; if (strlen(hdd[c].fn) == 0) diff --git a/src/disk/mo.c b/src/disk/mo.c index 5f757c8af..7528806c7 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -9,35 +9,31 @@ * Implementation of a generic Magneto-Optical Disk drive * commands, for both ATAPI and SCSI usage. * - * - * * Authors: Natalia Portillo * Miran Grca, * Fred N. van Kempen, * - * Copyright 2020-2021 Natalia Portillo. - * Copyright 2020-2021 Miran Grca. - * Copyright 2020-2021 Fred N. van Kempen + * Copyright 2020-2025 Natalia Portillo. + * Copyright 2020-2025 Miran Grca. + * Copyright 2020-2025 Fred N. van Kempen */ -#include -#include -#include -#include +#ifdef ENABLE_MO_LOG #include -#include -#define HAVE_STDARG_H +#endif +#include +#include +#include +#include #include <86box/86box.h> #include <86box/timer.h> -#include <86box/config.h> -#include <86box/timer.h> #include <86box/device.h> +#include <86box/log.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/nvr.h> #include <86box/path.h> #include <86box/plat.h> #include <86box/ui.h> -#include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/mo.h> #include <86box/version.h> @@ -53,235 +49,50 @@ mo_drive_t mo_drives[MO_NUM]; -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +// clang-format off +/* + Table of all SCSI commands and their flags, needed for the new disc change / + not ready handler. + */ const uint8_t mo_command_flags[0x100] = { - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, - IMPLEMENTED, /* 0x15 */ - IMPLEMENTED | SCSI_ONLY, /* 0x16 */ - IMPLEMENTED | SCSI_ONLY, /* 0x17 */ - 0, 0, - IMPLEMENTED, /* 0x1A */ - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, - IMPLEMENTED, /* 0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2C */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, - IMPLEMENTED | CHECK_READY | NONDATA, /* 0xAC */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + [0x00] = IMPLEMENTED | CHECK_READY, + [0x01] = IMPLEMENTED | ALLOW_UA | SCSI_ONLY, + [0x03] = IMPLEMENTED | ALLOW_UA, + [0x04] = IMPLEMENTED | CHECK_READY | ALLOW_UA | SCSI_ONLY, + [0x08] = IMPLEMENTED | CHECK_READY, + [0x0a] = IMPLEMENTED | CHECK_READY, + [0x0b] = IMPLEMENTED | CHECK_READY, + [0x12] = IMPLEMENTED | ALLOW_UA, + [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x15] = IMPLEMENTED, + [0x16] = IMPLEMENTED | SCSI_ONLY, + [0x17] = IMPLEMENTED | SCSI_ONLY, + [0x1a] = IMPLEMENTED, + [0x1b] = IMPLEMENTED | CHECK_READY, + [0x1d] = IMPLEMENTED, + [0x1e] = IMPLEMENTED | CHECK_READY, + [0x25] = IMPLEMENTED | CHECK_READY, + [0x28] = IMPLEMENTED | CHECK_READY, + [0x2a ... 0x2c] = IMPLEMENTED | CHECK_READY, + [0x2e] = IMPLEMENTED | CHECK_READY, + [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x41] = IMPLEMENTED | CHECK_READY, + [0x55] = IMPLEMENTED, + [0x5a] = IMPLEMENTED, + [0xa8] = IMPLEMENTED | CHECK_READY, + [0xaa] = IMPLEMENTED | CHECK_READY, + [0xac] = IMPLEMENTED | CHECK_READY, + [0xae] = IMPLEMENTED | CHECK_READY, + [0xaf] = IMPLEMENTED | CHECK_READY | SCSI_ONLY }; static uint64_t mo_mode_sense_page_flags = GPMODEP_ALL_PAGES; -static const mode_sense_pages_t mo_mode_sense_pages_default = - // clang-format off -{ { - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -} }; -// clang-format on +static const mode_sense_pages_t mo_mode_sense_pages_default = { 0 }; -static const mode_sense_pages_t mo_mode_sense_pages_default_scsi = - // clang-format off -{ { - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -} }; -// clang-format on +static const mode_sense_pages_t mo_mode_sense_pages_default_scsi = { 0 }; -static const mode_sense_pages_t mo_mode_sense_pages_changeable = - // clang-format off -{ { - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -} }; +static const mode_sense_pages_t mo_mode_sense_pages_changeable = { 0 }; // clang-format on static void mo_command_complete(mo_t *dev); @@ -291,32 +102,22 @@ static void mo_init(mo_t *dev); int mo_do_log = ENABLE_MO_LOG; static void -mo_log(const char *fmt, ...) +mo_log(void *priv, const char *fmt, ...) { va_list ap; if (mo_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define mo_log(fmt, ...) +# define mo_log(priv, fmt, ...) #endif -int -find_mo_for_channel(uint8_t channel) -{ - for (uint8_t i = 0; i < MO_NUM; i++) { - if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - static int -mo_load_abort(mo_t *dev) +mo_load_abort(const mo_t *dev) { if (dev->drv->fp) fclose(dev->drv->fp); @@ -330,105 +131,125 @@ mo_load_abort(mo_t *dev) int image_is_mdi(const char *s) { - if (!strcasecmp(path_get_extension((char *) s), "MDI")) - return 1; - else - return 0; + return !strcasecmp(path_get_extension((char *) s), "MDI"); } int -mo_load(mo_t *dev, char *fn) +mo_is_empty(const uint8_t id) { - int is_mdi; - uint32_t size = 0; - unsigned int found = 0; + const mo_t *dev = (const mo_t *) mo_drives[id].priv; + int ret = 0; - if (!dev->drv) { + if ((dev->drv == NULL) || (dev->drv->fp == NULL)) + ret = 1; + + return ret; +} + +void +mo_load(const mo_t *dev, const char *fn, const int skip_insert) +{ + const int was_empty = mo_is_empty(dev->id); + int ret = 0; + + if (dev->drv == NULL) mo_eject(dev->id); - return 0; - } + else { + const int is_mdi = image_is_mdi(fn); - is_mdi = image_is_mdi(fn); + dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); + ret = 1; - dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); - if (!dev->drv->fp) { - if (!dev->drv->read_only) { - dev->drv->fp = plat_fopen(fn, "rb"); - if (dev->drv->fp) - dev->drv->read_only = 1; - else - return mo_load_abort(dev); - } else - return mo_load_abort(dev); - } + if (dev->drv->fp == NULL) { + if (!dev->drv->read_only) { + dev->drv->fp = plat_fopen(fn, "rb"); + if (dev->drv->fp == NULL) + ret = mo_load_abort(dev); + else + dev->drv->read_only = 1; + } else + ret = mo_load_abort(dev); + } - fseek(dev->drv->fp, 0, SEEK_END); - size = (uint32_t) ftell(dev->drv->fp); + if (ret) { + fseek(dev->drv->fp, 0, SEEK_END); - if (is_mdi) { - /* This is a MDI image. */ - size -= 0x1000LL; - dev->drv->base = 0x1000; - } + uint32_t size = (uint32_t) ftell(dev->drv->fp); + unsigned int found = 0; - for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { - if (size == (mo_types[i].sectors * mo_types[i].bytes_per_sector)) { - found = 1; - dev->drv->medium_size = mo_types[i].sectors; - dev->drv->sector_size = mo_types[i].bytes_per_sector; - break; + if (is_mdi) { + /* This is a MDI image. */ + size -= 0x1000LL; + dev->drv->base = 0x1000; + } else + dev->drv->base = 0; + + for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { + if (size == (mo_types[i].sectors * mo_types[i].bytes_per_sector)) { + found = 1; + dev->drv->medium_size = mo_types[i].sectors; + dev->drv->sector_size = mo_types[i].bytes_per_sector; + break; + } + } + + if (found) { + if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) + log_fatal(dev->log, "mo_load(): Error seeking to the beginning of " + "the file\n"); + + strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); + + ret = 1; + } else + ret = mo_load_abort(dev); } } - if (!found) - return mo_load_abort(dev); + if (ret && !skip_insert) { + /* Signal media change to the emulated machine. */ + mo_insert((mo_t *) dev); - if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) - fatal("mo_load(): Error seeking to the beginning of the file\n"); - - strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); - - return 1; + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + mo_insert((mo_t *) dev); + } } void -mo_disk_reload(mo_t *dev) +mo_disk_reload(const mo_t *dev) { - int ret = 0; - - if (strlen(dev->drv->prev_image_path) == 0) - return; - else - ret = mo_load(dev, dev->drv->prev_image_path); - - if (ret) - dev->unit_attention = 1; + if (strlen(dev->drv->prev_image_path) != 0) + (void) mo_load(dev, dev->drv->prev_image_path, 0); } -void -mo_disk_unload(mo_t *dev) +static void +mo_disk_unload(const mo_t *dev) { - if (dev->drv && dev->drv->fp) { + if ((dev->drv != NULL) && (dev->drv->fp != NULL)) { fclose(dev->drv->fp); dev->drv->fp = NULL; } } void -mo_disk_close(mo_t *dev) +mo_disk_close(const mo_t *dev) { - if (dev->drv && dev->drv->fp) { + if ((dev->drv != NULL) && (dev->drv->fp != NULL)) { mo_disk_unload(dev); - memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); + memcpy(dev->drv->prev_image_path, dev->drv->image_path, + sizeof(dev->drv->prev_image_path)); memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); dev->drv->medium_size = 0; + + mo_insert((mo_t *) dev); } } static void -mo_set_callback(mo_t *dev) +mo_set_callback(const mo_t *dev) { if (dev->drv->bus_type != MO_BUS_SCSI) ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback); @@ -437,55 +258,55 @@ mo_set_callback(mo_t *dev) static void mo_init(mo_t *dev) { - if (dev->id >= MO_NUM) - return; - - dev->requested_blocks = 1; - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - dev->drv->bus_mode = 0; - if (dev->drv->bus_type >= MO_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus_type < MO_BUS_SCSI) - dev->drv->bus_mode |= 1; - mo_log("MO %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - if (dev->drv->bus_type < MO_BUS_SCSI) { - dev->tf->phase = 1; - dev->tf->request_length = 0xEB14; + if (dev->id < MO_NUM) { + dev->requested_blocks = 1; + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= MO_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < MO_BUS_SCSI) + dev->drv->bus_mode |= 1; + mo_log(dev->log, "Bus type %i, bus mode %i\n", dev->drv->bus_type, dev->drv->bus_mode); + if (dev->drv->bus_type < MO_BUS_SCSI) { + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; + } + dev->tf->status = READY_STAT | DSC_STAT; + dev->tf->pos = 0; + dev->packet_status = PHASE_NONE; + mo_sense_key = mo_asc = mo_ascq = dev->unit_attention = dev->transition = 0; + mo_info = 0x00000000; } - dev->tf->status = READY_STAT | DSC_STAT; - dev->tf->pos = 0; - dev->packet_status = PHASE_NONE; - mo_sense_key = mo_asc = mo_ascq = dev->unit_attention = 0; } static int -mo_supports_pio(mo_t *dev) +mo_supports_pio(const mo_t *dev) { return (dev->drv->bus_mode & 1); } static int -mo_supports_dma(mo_t *dev) +mo_supports_dma(const mo_t *dev) { return (dev->drv->bus_mode & 2); } /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ static int -mo_current_mode(mo_t *dev) +mo_current_mode(const mo_t *dev) { if (!mo_supports_pio(dev) && !mo_supports_dma(dev)) return 0; if (mo_supports_pio(dev) && !mo_supports_dma(dev)) { - mo_log("MO %i: Drive does not support DMA, setting to PIO\n", dev->id); + mo_log(dev->log, "Drive does not support DMA, setting to PIO\n"); return 1; } if (!mo_supports_pio(dev) && mo_supports_dma(dev)) return 2; if (mo_supports_pio(dev) && mo_supports_dma(dev)) { - mo_log("MO %i: Drive supports both, setting to %s\n", dev->id, - (dev->tf->features & 1) ? "DMA" : "PIO"); + mo_log(dev->log, "Drive supports both, setting to %s\n", (dev->tf->features & 1) ? + "DMA" : "PIO"); return (dev->tf->features & 1) ? 2 : 1; } @@ -495,21 +316,21 @@ mo_current_mode(mo_t *dev) static void mo_mode_sense_load(mo_t *dev) { - FILE *fp; - char fn[512]; + char fn[512] = { 0 }; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (mo_drives[dev->id].bus_type == MO_BUS_SCSI) - memcpy(&dev->ms_pages_saved, &mo_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &mo_mode_sense_pages_default_scsi, + sizeof(mode_sense_pages_t)); else - memcpy(&dev->ms_pages_saved, &mo_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &mo_mode_sense_pages_default, + sizeof(mode_sense_pages_t)); - memset(fn, 0, 512); if (dev->drv->bus_type == MO_BUS_SCSI) sprintf(fn, "scsi_mo_%02i_mode_sense_bin", dev->id); else sprintf(fn, "mo_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(fn), "rb"); + FILE *fp = plat_fopen(nvr_path(fn), "rb"); if (fp) { /* Nothing to read, not used by MO. */ fclose(fp); @@ -517,28 +338,27 @@ mo_mode_sense_load(mo_t *dev) } static void -mo_mode_sense_save(mo_t *dev) +mo_mode_sense_save(const mo_t *dev) { - FILE *fp; - char fn[512]; + char fn[512] = { 0 }; - memset(fn, 0, 512); if (dev->drv->bus_type == MO_BUS_SCSI) sprintf(fn, "scsi_mo_%02i_mode_sense_bin", dev->id); else sprintf(fn, "mo_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(fn), "wb"); + FILE *fp = plat_fopen(nvr_path(fn), "wb"); if (fp) { /* Nothing to write, not used by MO. */ fclose(fp); } } -/*SCSI Mode Sense 6/10*/ +/* SCSI Mode Sense 6/10. */ static uint8_t -mo_mode_sense_read(mo_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +mo_mode_sense_read(const mo_t *dev, const uint8_t pgctl, + const uint8_t page, const uint8_t pos) { - switch (page_control) { + switch (pgctl) { case 0: case 3: return dev->ms_pages_saved.pages[page][pos]; @@ -558,14 +378,11 @@ mo_mode_sense_read(mo_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) } static uint32_t -mo_mode_sense(mo_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +mo_mode_sense(const mo_t *dev, uint8_t *buf, uint32_t pos, + uint8_t page, const uint8_t block_descriptor_len) { - uint64_t pf; - uint8_t page_control = (page >> 6) & 3; - - pf = mo_mode_sense_page_flags; - - uint8_t msplen; + const uint64_t pf = mo_mode_sense_page_flags; + const uint8_t pgctl = (page >> 6) & 3; page &= 0x3f; @@ -583,12 +400,12 @@ mo_mode_sense(mo_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block for (uint8_t i = 0; i < 0x40; i++) { if ((page == GPMODE_ALL_PAGES) || (page == i)) { if (pf & (1LL << ((uint64_t) page))) { - buf[pos++] = mo_mode_sense_read(dev, page_control, i, 0); - msplen = mo_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - mo_log("MO %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + const uint8_t msplen = mo_mode_sense_read(dev, pgctl, i, 1); + buf[pos++] = mo_mode_sense_read(dev, pgctl, i, 0); + buf[pos++] = msplen; + mo_log(dev->log, "MODE SENSE: Page [%02X] length %i\n", i, msplen); for (uint8_t j = 0; j < msplen; j++) - buf[pos++] = mo_mode_sense_read(dev, page_control, i, 2 + j); + buf[pos++] = mo_mode_sense_read(dev, pgctl, i, 2 + j); } } } @@ -604,7 +421,10 @@ mo_update_request_length(mo_t *dev, int len, int block_len) dev->max_transfer_len = dev->tf->request_length; - /* For media access commands, make sure the requested DRQ length matches the block length. */ + /* + For media access commands, make sure the requested DRQ length + matches the block length. + */ switch (dev->current_cdb[0]) { case 0x08: case 0x0a: @@ -615,8 +435,10 @@ mo_update_request_length(mo_t *dev, int len, int block_len) /* Round it to the nearest 2048 bytes. */ dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9; - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ + /* + Make sure total length is not bigger than sum of the lengths of + all the requested blocks. + */ bt = (dev->requested_blocks * block_len); if (len > bt) len = bt; @@ -641,7 +463,10 @@ mo_update_request_length(mo_t *dev, int len, int block_len) /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + /* + If the DRQ length is smaller or equal in size to the total remaining length, + set it to that. + */ if (!dev->max_transfer_len) dev->max_transfer_len = 65534; @@ -649,8 +474,6 @@ mo_update_request_length(mo_t *dev, int len, int block_len) dev->tf->request_length = dev->max_transfer_len = len; else if (len > dev->max_transfer_len) dev->tf->request_length = dev->max_transfer_len; - - return; } static double @@ -676,23 +499,22 @@ mo_bus_speed(mo_t *dev) static void mo_command_common(mo_t *dev) { - double bytes_per_second; - double period; - dev->tf->status = BUSY_STAT; dev->tf->phase = 1; dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; else { + double bytes_per_second; + if (dev->drv->bus_type == MO_BUS_SCSI) { dev->callback = -1.0; /* Speed depends on SCSI controller */ return; } else bytes_per_second = mo_bus_speed(dev); - period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); + const double period = 1000000.0 / bytes_per_second; + dev->callback = period * (double) (dev->packet_len); } mo_set_callback(dev); @@ -733,16 +555,20 @@ mo_command_write_dma(mo_t *dev) mo_command_common(dev); } -/* id = Current MO device ID; +/* + dev = Pointer to current MO device; len = Total transfer length; block_len = Length of a single block (why does it matter?!); alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ + direction = Transfer direction (0 = read from host, 1 = write to host). + */ static void -mo_data_command_finish(mo_t *dev, int len, int block_len, int alloc_len, int direction) +mo_data_command_finish(mo_t *dev, int len, const int block_len, + const int alloc_len, const int direction) { - mo_log("MO %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); + mo_log(dev->log, "Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->current_cdb[0], len, block_len, alloc_len, + direction, dev->tf->request_length); dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) @@ -771,27 +597,26 @@ mo_data_command_finish(mo_t *dev, int len, int block_len, int alloc_len, int dir } } - mo_log("MO %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, - dev->tf->phase); + mo_log(dev->log, "Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->packet_status, dev->tf->request_length, dev->packet_len, + dev->tf->pos, dev->tf->phase); } static void mo_sense_clear(mo_t *dev, UNUSED(int command)) { mo_sense_key = mo_asc = mo_ascq = 0; + mo_info = 0x00000000; } static void -mo_set_phase(mo_t *dev, uint8_t phase) +mo_set_phase(const mo_t *dev, const uint8_t phase) { - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; - if (dev->drv->bus_type != MO_BUS_SCSI) - return; - - scsi_devices[scsi_bus][scsi_id].phase = phase; + if (dev->drv->bus_type == MO_BUS_SCSI) + scsi_devices[scsi_bus][scsi_id].phase = phase; } static void @@ -799,8 +624,6 @@ mo_cmd_error(mo_t *dev) { mo_set_phase(dev, SCSI_PHASE_STATUS); dev->tf->error = ((mo_sense_key & 0xf) << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->tf->error |= MCR_ERR; dev->tf->status = READY_STAT | ERR_STAT; dev->tf->phase = 3; dev->tf->pos = 0; @@ -808,31 +631,30 @@ mo_cmd_error(mo_t *dev) dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); - mo_log("MO %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], mo_sense_key, mo_asc, mo_ascq); + mo_log(dev->log, "[%02X] ERROR: %02X/%02X/%02X\n", dev->current_cdb[0], mo_sense_key, + mo_asc, mo_ascq); } static void mo_unit_attention(mo_t *dev) { mo_set_phase(dev, SCSI_PHASE_STATUS); - dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->tf->error |= MCR_ERR; - dev->tf->status = READY_STAT | ERR_STAT; - dev->tf->phase = 3; - dev->tf->pos = 0; - dev->packet_status = PHASE_ERROR; - dev->callback = 50.0 * MO_TIME; + dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); - mo_log("MO %i: UNIT ATTENTION\n", dev->id); + mo_log(dev->log, "UNIT ATTENTION\n"); } static void mo_buf_alloc(mo_t *dev, uint32_t len) { - mo_log("MO %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->buffer) + mo_log(dev->log, "Allocated buffer length: %i\n", len); + if (dev->buffer == NULL) dev->buffer = (uint8_t *) malloc(len); } @@ -840,7 +662,7 @@ static void mo_buf_free(mo_t *dev) { if (dev->buffer) { - mo_log("MO %i: Freeing buffer...\n", dev->id); + mo_log(dev->log, "Freeing buffer...\n"); free(dev->buffer); dev->buffer = NULL; } @@ -853,6 +675,10 @@ mo_bus_master_error(scsi_common_t *sc) mo_buf_free(dev); mo_sense_key = mo_asc = mo_ascq = 0; + mo_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); mo_cmd_error(dev); } @@ -862,6 +688,7 @@ mo_not_ready(mo_t *dev) mo_sense_key = SENSE_NOT_READY; mo_asc = ASC_MEDIUM_NOT_PRESENT; mo_ascq = 0; + mo_info = 0x00000000; mo_cmd_error(dev); } @@ -871,6 +698,10 @@ mo_write_protected(mo_t *dev) mo_sense_key = SENSE_UNIT_ATTENTION; mo_asc = ASC_WRITE_PROTECTED; mo_ascq = 0; + mo_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); mo_cmd_error(dev); } @@ -880,6 +711,10 @@ mo_write_error(mo_t *dev) mo_sense_key = SENSE_MEDIUM_ERROR; mo_asc = ASC_WRITE_ERROR; mo_ascq = 0; + mo_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); mo_cmd_error(dev); } @@ -889,24 +724,30 @@ mo_read_error(mo_t *dev) mo_sense_key = SENSE_MEDIUM_ERROR; mo_asc = ASC_UNRECOVERED_READ_ERROR; mo_ascq = 0; + mo_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); mo_cmd_error(dev); } static void -mo_invalid_lun(mo_t *dev) +mo_invalid_lun(mo_t *dev, const uint8_t lun) { mo_sense_key = SENSE_ILLEGAL_REQUEST; mo_asc = ASC_INV_LUN; mo_ascq = 0; + mo_info = lun << 24; mo_cmd_error(dev); } static void -mo_illegal_opcode(mo_t *dev) +mo_illegal_opcode(mo_t *dev, const uint8_t opcode) { mo_sense_key = SENSE_ILLEGAL_REQUEST; mo_asc = ASC_ILLEGAL_OPCODE; mo_ascq = 0; + mo_info = opcode << 24; mo_cmd_error(dev); } @@ -916,140 +757,171 @@ mo_lba_out_of_range(mo_t *dev) mo_sense_key = SENSE_ILLEGAL_REQUEST; mo_asc = ASC_LBA_OUT_OF_RANGE; mo_ascq = 0; + mo_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); mo_cmd_error(dev); } static void -mo_invalid_field(mo_t *dev) +mo_invalid_field(mo_t *dev, const uint32_t field) { mo_sense_key = SENSE_ILLEGAL_REQUEST; mo_asc = ASC_INV_FIELD_IN_CMD_PACKET; mo_ascq = 0; + mo_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); mo_cmd_error(dev); dev->tf->status = 0x53; } static void -mo_invalid_field_pl(mo_t *dev) +mo_invalid_field_pl(mo_t *dev, const uint32_t field) { mo_sense_key = SENSE_ILLEGAL_REQUEST; mo_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; mo_ascq = 0; + mo_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); mo_cmd_error(dev); dev->tf->status = 0x53; } static int -mo_blocks(mo_t *dev, int32_t *len, UNUSED(int first_batch), int out) +mo_blocks(mo_t *dev, int32_t *len, int out) { - *len = 0; + int ret = 0; - if (!dev->sector_len) { + *len = 0; + + if (!dev->sector_len) mo_command_complete(dev); - return 0; - } + else { + mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", + dev->requested_blocks, dev->sector_pos); - mo_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); - - if (dev->sector_pos >= dev->drv->medium_size) { - mo_log("MO %i: Trying to %s beyond the end of disk\n", dev->id, out ? "write" : "read"); - mo_lba_out_of_range(dev); - return 0; - } - - *len = dev->requested_blocks * dev->drv->sector_size; - - for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size) + (i * dev->drv->sector_size), SEEK_SET) == -1) { - if (out) - mo_write_error(dev); - else - mo_read_error(dev); - return -1; - } - - if (feof(dev->drv->fp)) - break; - - if (out) { - if (fwrite(dev->buffer + (i * dev->drv->sector_size), 1, dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { - mo_log("mo_blocks(): Error writing data\n"); - mo_write_error(dev); - return -1; - } - - fflush(dev->drv->fp); + if (dev->sector_pos >= dev->drv->medium_size) { + mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); + mo_lba_out_of_range(dev); } else { - if (fread(dev->buffer + (i * dev->drv->sector_size), 1, dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { - mo_log("mo_blocks(): Error reading data\n"); - mo_read_error(dev); - return -1; + *len = dev->requested_blocks * dev->drv->sector_size; + ret = 1; + + for (int i = 0; i < dev->requested_blocks; i++) { + if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size) + (i * dev->drv->sector_size), SEEK_SET) == -1) { + if (out) + mo_write_error(dev); + else + mo_read_error(dev); + + ret = -1; + } else { + if (!feof(dev->drv->fp)) + break; + + if (out) { + if (fwrite(dev->buffer + (i * dev->drv->sector_size), 1, + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + mo_log(dev->log, "mo_blocks(): Error writing data\n"); + mo_write_error(dev); + ret = -1; + } else + fflush(dev->drv->fp); + } else { + if (fread(dev->buffer + (i * dev->drv->sector_size), 1, + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + mo_log(dev->log, "mo_blocks(): Error reading data\n"); + mo_read_error(dev); + ret = -1; + } + } + } + + if (ret == -1) + break; + + dev->sector_pos++; + } + + if (ret == 1) { + mo_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + dev->sector_len -= dev->requested_blocks; } } } - mo_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - dev->sector_pos += dev->requested_blocks; - dev->sector_len -= dev->requested_blocks; - - return 1; + return ret; } void mo_insert(mo_t *dev) { - dev->unit_attention = 1; + if ((dev != NULL) && (dev->drv != NULL)) { + if (dev->drv->fp == NULL) { + dev->unit_attention = 0; + dev->transition = 0; + mo_log(dev->log, "Media removal\n"); + } else if (dev->transition) { + dev->unit_attention = 1; + /* Turn off the medium changed status. */ + dev->transition = 0; + mo_log(dev->log, "Media insert\n"); + } else { + dev->unit_attention = 0; + dev->transition = 1; + mo_log(dev->log, "Media transition\n"); + } + } } void mo_format(mo_t *dev) { - long size; int ret; int fd; - mo_log("MO %i: Formatting media...\n", dev->id); + mo_log(dev->log, "Formatting media...\n"); fseek(dev->drv->fp, 0, SEEK_END); - size = ftell(dev->drv->fp); + long size = ftell(dev->drv->fp); #ifdef _WIN32 - HANDLE fh; LARGE_INTEGER liSize; - fd = _fileno(dev->drv->fp); - fh = (HANDLE) _get_osfhandle(fd); + fd = _fileno(dev->drv->fp); + const HANDLE fh = (HANDLE) _get_osfhandle(fd); liSize.QuadPart = 0; ret = (int) SetFilePointerEx(fh, liSize, NULL, FILE_BEGIN); - if (!ret) { - mo_log("MO %i: Failed seek to start of image file\n", dev->id); - return; - } + if (ret) { + ret = (int) SetEndOfFile(fh); - ret = (int) SetEndOfFile(fh); + if (ret) { + liSize.QuadPart = size; + ret = (int) SetFilePointerEx(fh, liSize, NULL, FILE_BEGIN); - if (!ret) { - mo_log("MO %i: Failed to truncate image file to 0\n", dev->id); - return; - } + if (ret) { + ret = (int) SetEndOfFile(fh); - liSize.QuadPart = size; - ret = (int) SetFilePointerEx(fh, liSize, NULL, FILE_BEGIN); - - if (!ret) { - mo_log("MO %i: Failed seek to end of image file\n", dev->id); - return; - } - - ret = (int) SetEndOfFile(fh); - - if (!ret) { - mo_log("MO %i: Failed to truncate image file to %llu\n", dev->id, size); - return; + if (!ret) { + mo_log(dev->log, "Failed to truncate image file to %llu\n", size); + } + } else { + mo_log(dev->log, "Failed seek to end of image file\n"); + } + } else { + mo_log(dev->log, "Failed to truncate image file to 0\n"); + } + } else { + mo_log(dev->log, "Failed seek to start of image file\n"); } #else fd = fileno(dev->drv->fp); @@ -1057,15 +929,13 @@ mo_format(mo_t *dev) ret = ftruncate(fd, 0); if (ret) { - mo_log("MO %i: Failed to truncate image file to 0\n", dev->id); - return; - } + mo_log(dev->log, "Failed to truncate image file to 0\n"); + } else { + ret = ftruncate(fd, size); - ret = ftruncate(fd, size); - - if (ret) { - mo_log("MO %i: Failed to truncate image file to %llu", dev->id, size); - return; + if (ret) { + mo_log(dev->log, "Failed to truncate image file to %llu", size); + } } #endif } @@ -1080,10 +950,11 @@ mo_erase(mo_t *dev) return -1; } - mo_log("MO %i: Erasing %i blocks starting from %i...\n", dev->id, dev->sector_len, dev->sector_pos); + mo_log(dev->log, "Erasing %i blocks starting from %i...\n", + dev->sector_len, dev->sector_pos); if (dev->sector_pos >= dev->drv->medium_size) { - mo_log("MO %i: Trying to erase beyond the end of disk\n", dev->id); + mo_log(dev->log, "Trying to erase beyond the end of disk\n"); mo_lba_out_of_range(dev); return 0; } @@ -1091,7 +962,8 @@ mo_erase(mo_t *dev) mo_buf_alloc(dev, dev->drv->sector_size); memset(dev->buffer, 0, dev->drv->sector_size); - fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size), SEEK_SET); + fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size), + SEEK_SET); for (i = 0; i < dev->requested_blocks; i++) { if (feof(dev->drv->fp)) @@ -1102,7 +974,7 @@ mo_erase(mo_t *dev) fflush(dev->drv->fp); - mo_log("MO %i: Erased %i bytes of blocks...\n", dev->id, i * dev->drv->sector_size); + mo_log(dev->log, "Erased %i bytes of blocks...\n", i * dev->drv->sector_size); dev->sector_pos += i; dev->sector_len -= i; @@ -1110,96 +982,110 @@ mo_erase(mo_t *dev) return 1; } -/*SCSI Sense Initialization*/ -void -mo_sense_code_ok(mo_t *dev) -{ - mo_sense_key = SENSE_NONE; - mo_asc = 0; - mo_ascq = 0; -} - static int -mo_pre_execution_check(mo_t *dev, uint8_t *cdb) +mo_pre_execution_check(mo_t *dev, const uint8_t *cdb) { - int ready = 0; + int ready; - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - mo_log("MO %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && + (cdb[1] & 0xe0)) { + mo_log(dev->log, "Attempting to execute a unknown command targeted at SCSI LUN %i\n", ((dev->tf->request_length >> 5) & 7)); - mo_invalid_lun(dev); + mo_invalid_lun(dev, cdb[1] >> 5); return 0; } if (!(mo_command_flags[cdb[0]] & IMPLEMENTED)) { - mo_log("MO %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == MO_BUS_SCSI) ? "SCSI" : "ATAPI"); + mo_log(dev->log, "Attempting to execute unknown command %02X over %s\n", + cdb[0], (dev->drv->bus_type == MO_BUS_SCSI) ? + "SCSI" : "ATAPI"); - mo_illegal_opcode(dev); + mo_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type < MO_BUS_SCSI) && (mo_command_flags[cdb[0]] & SCSI_ONLY)) { - mo_log("MO %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - mo_illegal_opcode(dev); + if ((dev->drv->bus_type < MO_BUS_SCSI) && + (mo_command_flags[cdb[0]] & SCSI_ONLY)) { + mo_log(dev->log, "Attempting to execute SCSI-only command %02X " + "over ATAPI\n", cdb[0]); + mo_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type == MO_BUS_SCSI) && (mo_command_flags[cdb[0]] & ATAPI_ONLY)) { - mo_log("MO %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); - mo_illegal_opcode(dev); + if ((dev->drv->bus_type == MO_BUS_SCSI) && + (mo_command_flags[cdb[0]] & ATAPI_ONLY)) { + mo_log(dev->log, "Attempting to execute ATAPI-only command %02X " + "over SCSI\n", cdb[0]); + mo_illegal_opcode(dev, cdb[0]); return 0; } - ready = (dev->drv->fp != NULL); + if (dev->transition) { + if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) + ready = 0; + else { + if (!(mo_command_flags[cdb[0]] & ALLOW_UA)) { + mo_log(dev->log, "(ext_medium_changed != 0): mo_insert()\n"); + mo_insert((void *) dev); + } - /* If the drive is not ready, there is no reason to keep the + ready = (dev->drv->fp != NULL); + } + } else + ready = (dev->drv->fp != NULL); + + /* + If the drive is not ready, there is no reason to keep the UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && dev->unit_attention) + disc changes. + */ + if (!ready && (dev->unit_attention > 0)) dev->unit_attention = 0; - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ + /* + If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. + */ if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ + /* + Only increment the unit attention phase if the command can + not pass through it. + */ if (!(mo_command_flags[cdb[0]] & ALLOW_UA)) { - /* mo_log("MO %i: Unit attention now 2\n", dev->id); */ - dev->unit_attention = 2; - mo_log("MO %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", dev->id, cdb[0]); + mo_log(dev->log, "Unit attention now 2\n"); + dev->unit_attention++; + mo_log(dev->log, "UNIT ATTENTION: Command %02X not allowed to " + "pass through\n", cdb[0]); mo_unit_attention(dev); return 0; } } else if (dev->unit_attention == 2) { if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* mo_log("MO %i: Unit attention now 0\n", dev->id); */ + mo_log(dev->log, "MO %i: Unit attention now 0\n"); dev->unit_attention = 0; } } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ + /* + Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear + the UNIT ATTENTION condition if it's set. + */ if (cdb[0] != GPCMD_REQUEST_SENSE) mo_sense_clear(dev, cdb[0]); - /* Next it's time for NOT READY. */ - if ((mo_command_flags[cdb[0]] & CHECK_READY) && !ready) { - mo_log("MO %i: Not ready (%02X)\n", dev->id, cdb[0]); + if (!ready && (mo_command_flags[cdb[0]] & CHECK_READY)) { + mo_log(dev->log, "Not ready (%02X)\n", cdb[0]); mo_not_ready(dev); return 0; } - mo_log("MO %i: Continuing with command %02X\n", dev->id, cdb[0]); - + mo_log(dev->log, "Continuing with command %02X\n", cdb[0]); return 1; } static void mo_seek(mo_t *dev, uint32_t pos) { -#if 0 - mo_log("MO %i: Seek %08X\n", dev->id, pos); -#endif dev->sector_pos = pos; } @@ -1220,28 +1106,30 @@ mo_reset(scsi_common_t *sc) dev->callback = 0.0; mo_set_callback(dev); dev->tf->phase = 1; - dev->tf->request_length = 0xEB14; + dev->tf->request_length = 0xeb14; dev->packet_status = PHASE_NONE; - dev->unit_attention = 0; dev->cur_lun = SCSI_LUN_USE_CDB; + mo_sense_key = mo_asc = mo_ascq = dev->unit_attention = dev->transition = 0; + mo_info = 0x00000000; } static void -mo_request_sense(mo_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +mo_request_sense(mo_t *dev, uint8_t *buffer, const uint8_t alloc_length, const int desc) { - /*Will return 18 bytes of 0*/ + /* Will return 18 bytes of 0. */ if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, dev->sense, alloc_length); - else { + memset(buffer, 0x00, alloc_length); + if (desc) { buffer[1] = mo_sense_key; buffer[2] = mo_asc; buffer[3] = mo_ascq; - } + } else + memcpy(buffer, dev->sense, alloc_length); } - buffer[0] = desc ? 0x72 : 0x70; + buffer[0] = desc ? 0x72 : 0xf0; + if (!desc) + buffer[7] = 10; if (dev->unit_attention && (mo_sense_key == 0)) { buffer[desc ? 1 : 2] = SENSE_UNIT_ATTENTION; @@ -1249,25 +1137,27 @@ mo_request_sense(mo_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) buffer[desc ? 3 : 13] = 0; } - mo_log("MO %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + mo_log(dev->log, "Reporting sense: %02X %02X %02X\n", buffer[2], buffer[12], buffer[13]); if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ + /* If the last remaining sense is unit attention, clear that condition. */ dev->unit_attention = 0; } /* Clear the sense stuff as per the spec. */ mo_sense_clear(dev, GPCMD_REQUEST_SENSE); + + if (dev->transition) { + mo_log(dev->log, "MO_TRANSITION: mo_insert()\n"); + mo_insert((void *) dev); + } } static void mo_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { - mo_t *dev = (mo_t *) sc; - int ready = 0; - - ready = (dev->drv->fp != NULL); + mo_t *dev = (mo_t *) sc; + const int ready = (dev->drv->fp != NULL); if (!ready && dev->unit_attention) { /* If the drive is not ready, there is no reason to keep the @@ -1277,12 +1167,11 @@ mo_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_leng } /* Do *NOT* advance the unit attention phase. */ - mo_request_sense(dev, buffer, alloc_length, 0); } static void -mo_set_buf_len(mo_t *dev, int32_t *BufLen, int32_t *src_len) +mo_set_buf_len(const mo_t *dev, int32_t *BufLen, int32_t *src_len) { if (dev->drv->bus_type == MO_BUS_SCSI) { if (*BufLen == -1) @@ -1291,29 +1180,28 @@ mo_set_buf_len(mo_t *dev, int32_t *BufLen, int32_t *src_len) *BufLen = MIN(*src_len, *BufLen); *src_len = *BufLen; } - mo_log("MO %i: Actual transfer length: %i\n", dev->id, *BufLen); + mo_log(dev->log, "Actual transfer length: %i\n", *BufLen); } } static void -mo_command(scsi_common_t *sc, uint8_t *cdb) +mo_command(scsi_common_t *sc, const uint8_t *cdb) { - mo_t *dev = (mo_t *) sc; - int pos = 0; - int block_desc = 0; - int ret; - int32_t len; - int32_t max_len; - int32_t alloc_length; - int size_idx; - int idx = 0; - unsigned preamble_len; - char device_identify[9] = { '8', '6', 'B', '_', 'M', 'O', '0', '0', 0 }; - int32_t blen = 0; - int32_t *BufLen; - uint32_t previous_pos = 0; - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + mo_t * dev = (mo_t *) sc; + char device_identify[9] = { '8', '6', 'B', '_', 'M', 'O', '0', '0', 0 }; + uint32_t previous_pos = 0; + int32_t blen = 0; + const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + int pos = 0; + int idx = 0; + int32_t len; + int32_t max_len; + int32_t alloc_length; + unsigned preamble_len; + int block_desc; + int size_idx; + int32_t * BufLen; if (dev->drv->bus_type == MO_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; @@ -1331,11 +1219,13 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { - mo_log("MO %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], mo_sense_key, mo_asc, mo_ascq, dev->unit_attention); - mo_log("MO %i: Request length: %04X\n", dev->id, dev->tf->request_length); + mo_log(dev->log, "Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, " + "Unit attention: %i\n", + cdb[0], mo_sense_key, mo_asc, mo_ascq, dev->unit_attention); + mo_log(dev->log, "Request length: %04X\n", dev->tf->request_length); - mo_log("MO %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + mo_log(dev->log, "CDB: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); } @@ -1344,14 +1234,17 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) mo_set_phase(dev, SCSI_PHASE_STATUS); - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + /* + This handles the Not Ready/Unit Attention check if it has to be + handled at this point. + */ if (mo_pre_execution_check(dev, cdb) == 0) return; switch (cdb[0]) { case GPCMD_SEND_DIAGNOSTIC: if (!(cdb[1] & (1 << 2))) { - mo_invalid_field(dev); + mo_invalid_field(dev, cdb[1]); return; } fallthrough; @@ -1380,8 +1273,6 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ mo_set_phase(dev, SCSI_PHASE_DATA_IN); max_len = cdb[4]; @@ -1422,158 +1313,187 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) switch (cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); if (dev->sector_len == 0) dev->sector_len = 256; - mo_log("MO %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + mo_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - mo_log("MO %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + mo_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - mo_log("MO %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + mo_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; default: break; } - if (!dev->sector_len) { + if (dev->sector_len) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + dev->packet_len = max_len * alloc_length; + mo_buf_alloc(dev, dev->packet_len); + + const int ret = mo_blocks(dev, &alloc_length, 0); + + if (ret > 0) { + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + mo_data_command_finish(dev, alloc_length, dev->drv->sector_size, alloc_length, 0); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_MO | dev->id, 1); + else + ui_sb_update_icon(SB_MO | dev->id, 0); + } else { + mo_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * MO_TIME; + mo_set_callback(dev); + mo_buf_free(dev); + } + } else { mo_set_phase(dev, SCSI_PHASE_STATUS); - /* mo_log("MO %i: All done - callback set\n", dev->id); */ + /* mo_log(dev->log, "All done - callback set\n"); */ dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * MO_TIME; mo_set_callback(dev); - break; } - - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - dev->packet_len = max_len * alloc_length; - mo_buf_alloc(dev, dev->packet_len); - - ret = mo_blocks(dev, &alloc_length, 1, 0); - if (ret <= 0) { - mo_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; - dev->callback = 20.0 * MO_TIME; - mo_set_callback(dev); - mo_buf_free(dev); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - mo_data_command_finish(dev, alloc_length, dev->drv->sector_size, alloc_length, 0); - - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_MO | dev->id, 1); - else - ui_sb_update_icon(SB_MO | dev->id, 0); - return; + break; case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: case GPCMD_VERIFY_12: - /* Data and blank verification cannot be set at the same time */ - if ((cdb[1] & 2) && (cdb[1] & 4)) { - mo_invalid_field(dev); - return; - } - if (!(cdb[1] & 2) || (cdb[1] & 4)) { + if (!(cdb[1] & 2)) { mo_set_phase(dev, SCSI_PHASE_STATUS); mo_command_complete(dev); break; } - /*TODO: Implement*/ - mo_invalid_field(dev); - return; - + fallthrough; case GPCMD_WRITE_6: case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - alloc_length = dev->drv->sector_size; - - if (dev->drv->read_only) { - mo_write_protected(dev); - return; - } + alloc_length = 512; switch (cdb[0]) { case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + /* + For READ (6) and WRITE (6), a length of 0 indicates a + transfer of 256 sectors. + */ if (dev->sector_len == 0) - dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + mo_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_10: case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - mo_log("MO %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + mo_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_12: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: break; } - if ((dev->sector_pos >= dev->drv->medium_size) /* || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/ - ) { + if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) mo_lba_out_of_range(dev); - return; + else { + if (dev->sector_len) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + dev->packet_len = max_len * alloc_length; + mo_buf_alloc(dev, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + mo_data_command_finish(dev, dev->packet_len, 512, + dev->packet_len, 1); + + ui_sb_update_icon(SB_MO | dev->id, + dev->packet_status != PHASE_COMPLETE); + } else { + mo_set_phase(dev, SCSI_PHASE_STATUS); + mo_log(dev->log, "All done - callback set\n"); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + mo_set_callback(dev); + } } + break; - if (!dev->sector_len) { - mo_set_phase(dev, SCSI_PHASE_STATUS); - /* mo_log("MO %i: All done - callback set\n", dev->id); */ - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * MO_TIME; - mo_set_callback(dev); - break; + case GPCMD_WRITE_SAME_10: + alloc_length = 512; + + if ((cdb[1] & 6) == 6) + mo_invalid_field(dev, cdb[1]); + else { + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) + mo_lba_out_of_range(dev); + else if (dev->sector_len) { + mo_buf_alloc(dev, alloc_length); + mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + dev->requested_blocks = 1; + dev->packet_len = alloc_length; + + mo_set_phase(dev, SCSI_PHASE_DATA_OUT); + + mo_data_command_finish(dev, 512, 512, + alloc_length, 1); + + ui_sb_update_icon(SB_MO | dev->id, + dev->packet_status != PHASE_COMPLETE); + } else { + mo_set_phase(dev, SCSI_PHASE_STATUS); + mo_log(dev->log, "All done - callback set\n"); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + mo_set_callback(dev); + } } - - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - dev->packet_len = max_len * alloc_length; - mo_buf_alloc(dev, dev->packet_len); - - dev->requested_blocks = max_len; - dev->packet_len = max_len << 9; - - mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - mo_data_command_finish(dev, dev->packet_len, dev->drv->sector_size, dev->packet_len, 1); - - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_MO | dev->id, 1); - else - ui_sb_update_icon(SB_MO | dev->id, 0); - return; + break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: @@ -1593,7 +1513,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) } if (!(mo_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { - mo_invalid_field(dev); + mo_invalid_field(dev, cdb[2]); mo_buf_free(dev); return; } @@ -1602,14 +1522,16 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) alloc_length = len; if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = mo_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); + len = mo_mode_sense(dev, dev->buffer, 4, + cdb[2], block_desc); len = MIN(len, alloc_length); dev->buffer[0] = len - 1; dev->buffer[1] = 0; if (block_desc) dev->buffer[3] = 8; } else { - len = mo_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); + len = mo_mode_sense(dev, dev->buffer, 8, + cdb[2], block_desc); len = MIN(len, alloc_length); dev->buffer[0] = (len - 2) >> 8; dev->buffer[1] = (len - 2) & 255; @@ -1622,7 +1544,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) mo_set_buf_len(dev, BufLen, &len); - mo_log("MO %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + mo_log(dev->log, "Reading mode page: %02X...\n", cdb[2]); mo_data_command_finish(dev, len, len, alloc_length, 0); return; @@ -1682,7 +1604,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) preamble_len = 4; size_idx = 3; - dev->buffer[idx++] = 7; /*Optical disk*/ + dev->buffer[idx++] = 7; /* Optical disk */ dev->buffer[idx++] = cdb[2]; dev->buffer[idx++] = 0; @@ -1693,14 +1615,15 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[idx++] = 0x00; dev->buffer[idx++] = 0x80; break; - case 0x80: /*Unit serial number page*/ + case 0x80: /*Unit serial number page*/ dev->buffer[idx++] = strlen("VCM!10") + 1; - ide_padstr8(dev->buffer + idx, 20, "VCM!10"); /* Serial */ + /* Serial */ + ide_padstr8(dev->buffer + idx, 20, "VCM!10"); idx += strlen("VCM!10"); break; default: - mo_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - mo_invalid_field(dev); + mo_log(dev->log, "INQUIRY: Invalid page: %02X\n", cdb[2]); + mo_invalid_field(dev, cdb[2]); mo_buf_free(dev); return; } @@ -1710,30 +1633,34 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->buffer, 0, 8); if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) - dev->buffer[0] = 0x7f; /*No physical device on this LUN*/ + dev->buffer[0] = 0x7f; /* No physical device on this LUN */ else - dev->buffer[0] = 0x07; /*Optical disk*/ - dev->buffer[1] = 0x80; /*Removable*/ - dev->buffer[2] = (dev->drv->bus_type == MO_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + dev->buffer[0] = 0x07; /* Optical disk */ + dev->buffer[1] = 0x80; /* Removable */ + /* SCSI-2 compliant */ + dev->buffer[2] = (dev->drv->bus_type == MO_BUS_SCSI) ? 0x02 : 0x00; dev->buffer[3] = (dev->drv->bus_type == MO_BUS_SCSI) ? 0x02 : 0x21; -#if 0 - dev->buffer[4] = 31; -#endif dev->buffer[4] = 0; if (dev->drv->bus_type == MO_BUS_SCSI) { - dev->buffer[6] = 1; /* 16-bit transfers supported */ - dev->buffer[7] = 0x20; /* Wide bus supported */ + dev->buffer[6] = 1; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ } dev->buffer[7] |= 0x02; if (dev->drv->type > 0) { - ide_padstr8(dev->buffer + 8, 8, mo_drive_types[dev->drv->type].vendor); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, mo_drive_types[dev->drv->type].model); /* Product */ - ide_padstr8(dev->buffer + 32, 4, mo_drive_types[dev->drv->type].revision); /* Revision */ + ide_padstr8(dev->buffer + 8, 8, + mo_drive_types[dev->drv->type].vendor); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, + mo_drive_types[dev->drv->type].model); /* Product */ + ide_padstr8(dev->buffer + 32, 4, + mo_drive_types[dev->drv->type].revision); /* Revision */ } else { - ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ + ide_padstr8(dev->buffer + 8, 8, + EMU_NAME); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, + device_identify); /* Product */ + ide_padstr8(dev->buffer + 32, 4, + EMU_VERSION_EX); /* Revision */ } idx = 36; @@ -1784,7 +1711,8 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) mo_buf_alloc(dev, 8); - max_len = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + /* IMPORTANT: What's returned is the last LBA block. */ + max_len = dev->drv->medium_size - 1; memset(dev->buffer, 0, 8); dev->buffer[0] = (max_len >> 24) & 0xff; dev->buffer[1] = (max_len >> 16) & 0xff; @@ -1801,7 +1729,7 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_ERASE_10: case GPCMD_ERASE_12: - /*Relative address*/ + /* Relative address. */ if (cdb[1] & 1) previous_pos = dev->sector_pos; @@ -1810,18 +1738,20 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; break; case GPCMD_ERASE_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); break; default: break; } - /*Erase all remaining sectors*/ + /* Erase all remaining sectors. */ if (cdb[1] & 4) { - /* Cannot have a sector number when erase all*/ + /* Cannot have a sector number when erase all. */ if (dev->sector_len) { - mo_invalid_field(dev); + mo_invalid_field(dev, dev->sector_len); return; } mo_format(dev); @@ -1832,10 +1762,13 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) switch (cdb[0]) { case GPCMD_ERASE_10: - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; break; case GPCMD_ERASE_12: - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; default: @@ -1849,7 +1782,10 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) mo_command_complete(dev); break; - /*Never seen media that supports generations but it's interesting to know if any implementation calls this commmand*/ + /* + Never seen media that supports generations but it's interesting to know if any + implementation calls this commmand. + */ case GPCMD_READ_GENERATION: mo_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -1866,12 +1802,13 @@ mo_command(scsi_common_t *sc, uint8_t *cdb) break; default: - mo_illegal_opcode(dev); + mo_illegal_opcode(dev, cdb[0]); break; } #if 0 - mo_log("MO %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, dev->tf->request_length); + mo_log(dev->log, "Phase: %02X, request length: %i\n", + dev->tf->phase, dev->tf->request_length); #endif if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) @@ -1891,22 +1828,16 @@ mo_command_stop(scsi_common_t *sc) static uint8_t mo_phase_data_out(scsi_common_t *sc) { - mo_t *dev = (mo_t *) sc; - - uint16_t block_desc_len; - uint16_t pos; - uint16_t param_list_len; - - uint8_t error = 0; - uint8_t page; - uint8_t page_len; - - uint8_t hdr_len; - uint8_t val; - uint8_t old_val; - uint8_t ch; - - int len = 0; + mo_t * dev = (mo_t *) sc; + const uint32_t last_sector = mo_types[dev->drv->type].sectors - 1; + int len = 0; + uint8_t error = 0; + uint32_t last_to_write; + uint16_t block_desc_len; + uint16_t pos; + uint16_t param_list_len; + uint8_t hdr_len; + uint8_t val; switch (dev->current_cdb[0]) { case GPCMD_VERIFY_6: @@ -1919,7 +1850,40 @@ mo_phase_data_out(scsi_common_t *sc) case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: if (dev->requested_blocks > 0) - mo_blocks(dev, &len, 1, 1); + mo_blocks(dev, &len, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = dev->sector_pos + dev->sector_len - 1; + + for (int i = dev->sector_pos; i <= (int) last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + dev->buffer[0] = (i >> 24) & 0xff; + dev->buffer[1] = (i >> 16) & 0xff; + dev->buffer[2] = (i >> 8) & 0xff; + dev->buffer[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + uint32_t s = (i % 63); + uint32_t h = ((i - s) / 63) % 16; + uint32_t c = ((i - s) / 63) / 16; + dev->buffer[0] = (c >> 16) & 0xff; + dev->buffer[1] = (c >> 8) & 0xff; + dev->buffer[2] = c & 0xff; + dev->buffer[3] = h & 0xff; + dev->buffer[4] = (s >> 24) & 0xff; + dev->buffer[5] = (s >> 16) & 0xff; + dev->buffer[6] = (s >> 8) & 0xff; + dev->buffer[7] = s & 0xff; + } + if (fseek(dev->drv->fp, (i * dev->drv->sector_size), SEEK_SET) == -1) + mo_write_error(dev); + if (feof(dev->drv->fp)) + break; + if (fwrite(dev->buffer, 1, dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) + mo_write_error(dev); + } break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: @@ -1950,27 +1914,27 @@ mo_phase_data_out(scsi_common_t *sc) while (1) { if (pos >= param_list_len) { - mo_log("MO %i: Buffer has only block descriptor\n", dev->id); + mo_log(dev->log, "Buffer has only block descriptor\n"); break; } - page = dev->buffer[pos] & 0x3F; - page_len = dev->buffer[pos + 1]; + const uint8_t page = dev->buffer[pos] & 0x3F; + const uint8_t page_len = dev->buffer[pos + 1]; pos += 2; if (!(mo_mode_sense_page_flags & (1LL << ((uint64_t) page)))) error |= 1; - else { - for (uint8_t i = 0; i < page_len; i++) { - ch = mo_mode_sense_pages_changeable.pages[page][i + 2]; - val = dev->buffer[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else - error |= 1; + else for (uint8_t i = 0; i < page_len; i++) { + const uint8_t ch = mo_mode_sense_pages_changeable.pages[page][i + 2]; + const uint8_t old_val = dev->ms_pages_saved.pages[page][i + 2]; + val = dev->buffer[pos + i]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + error |= 1; + mo_invalid_field_pl(dev, val); } } } @@ -1990,7 +1954,6 @@ mo_phase_data_out(scsi_common_t *sc) if (error) { mo_buf_free(dev); - mo_invalid_field_pl(dev); return 0; } break; @@ -2012,7 +1975,7 @@ mo_global_init(void) } static int -mo_get_max(int ide_has_dma, int type) +mo_get_max(const ide_t *ide, const int ide_has_dma, const int type) { int ret; @@ -2036,7 +1999,7 @@ mo_get_max(int ide_has_dma, int type) } static int -mo_get_timings(int ide_has_dma, int type) +mo_get_timings(const ide_t *ide, const int ide_has_dma, const int type) { int ret; @@ -2059,7 +2022,7 @@ mo_get_timings(int ide_has_dma, int type) } static void -mo_do_identify(ide_t *ide, int ide_has_dma) +mo_do_identify(const ide_t *ide, const int ide_has_dma) { char model[40]; @@ -2068,56 +2031,65 @@ mo_do_identify(ide_t *ide, int ide_has_dma) memset(model, 0, 40); if (mo_drives[mo->id].type > 0) { - snprintf(model, 40, "%s %s", mo_drive_types[mo_drives[mo->id].type].vendor, mo_drive_types[mo_drives[mo->id].type].model); - ide_padstr((char *) (ide->buffer + 23), mo_drive_types[mo_drives[mo->id].type].revision, 8); /* Firmware */ + snprintf(model, 40, "%s %s", mo_drive_types[mo_drives[mo->id].type].vendor, + mo_drive_types[mo_drives[mo->id].type].model); + /* Firmware */ + ide_padstr((char *) (ide->buffer + 23), + mo_drive_types[mo_drives[mo->id].type].revision, 8); ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ } else { snprintf(model, 40, "%s %s%02i", EMU_NAME, "86B_MO", mo->id); - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ } if (ide_has_dma) { - ide->buffer[80] = 0x70; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6*/ - ide->buffer[81] = 0x19; /*Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a*/ + /* Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6 */ + ide->buffer[80] = 0x70; + /* Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a */ + ide->buffer[81] = 0x19; } } static void -mo_identify(ide_t *ide, int ide_has_dma) +mo_identify(const ide_t *ide, const int ide_has_dma) { - ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5); + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + /* Interpret zero byte count limit as maximum length */ + ide->buffer[126] = 0xfffe; mo_do_identify(ide, ide_has_dma); } static void -mo_drive_reset(int c) +mo_drive_reset(const int c) { - mo_t *dev; - scsi_device_t *sd; - ide_t *id; - uint8_t scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = mo_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = mo_drives[c].scsi_device_id & 0x0f; - if (!mo_drives[c].priv) { - mo_drives[c].priv = (mo_t *) malloc(sizeof(mo_t)); - memset(mo_drives[c].priv, 0, sizeof(mo_t)); + if (mo_drives[c].priv == NULL) { + mo_drives[c].priv = (mo_t *) calloc(1, sizeof(mo_t)); + mo_t *dev = (mo_t *) mo_drives[c].priv; + + char n[1024] = { 0 }; + + sprintf(n, "MO %i", c + 1); + dev->log = log_open(n); } - dev = (mo_t *) mo_drives[c].priv; + mo_t *dev = (mo_t *) mo_drives[c].priv; dev->id = c; dev->cur_lun = SCSI_LUN_USE_CDB; if (mo_drives[c].bus_type == MO_BUS_SCSI) { - if (!dev->tf) + if (dev->tf == NULL) dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); /* SCSI MO, attach to the SCSI bus. */ - sd = &scsi_devices[scsi_bus][scsi_id]; + scsi_device_t *sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = mo_command; @@ -2128,7 +2100,7 @@ mo_drive_reset(int c) sd->type = SCSI_REMOVABLE_DISK; } else if (mo_drives[c].bus_type == MO_BUS_ATAPI) { /* ATAPI MO, attach to the IDE bus. */ - id = ide_get_drive(mo_drives[c].ide_channel); + ide_t *id = ide_get_drive(mo_drives[c].ide_channel); /* If the IDE channel is initialized, we attach to it, otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ @@ -2155,17 +2127,11 @@ mo_drive_reset(int c) void mo_hard_reset(void) { - mo_t *dev; - uint8_t scsi_id; - uint8_t scsi_bus; - for (uint8_t c = 0; c < MO_NUM; c++) { if ((mo_drives[c].bus_type == MO_BUS_ATAPI) || (mo_drives[c].bus_type == MO_BUS_SCSI)) { - mo_log("MO hard_reset drive=%d\n", c); - if (mo_drives[c].bus_type == MO_BUS_SCSI) { - scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; - scsi_id = mo_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = mo_drives[c].scsi_device_id & 0x0f; /* Make sure to ignore any SCSI MO drive that has an out of range SCSI Bus. */ if (scsi_bus >= SCSI_BUS_MAX) @@ -2182,7 +2148,9 @@ mo_hard_reset(void) mo_drive_reset(c); - dev = (mo_t *) mo_drives[c].priv; + mo_t *dev = (mo_t *) mo_drives[c].priv; + + mo_log(dev->log, "MO hard_reset drive=%d\n", c); if (dev->tf == NULL) continue; @@ -2193,14 +2161,16 @@ mo_hard_reset(void) mo_init(dev); if (strlen(mo_drives[c].image_path)) - mo_load(dev, mo_drives[c].image_path); + mo_load(dev, mo_drives[c].image_path, 0); mo_mode_sense_load(dev); if (mo_drives[c].bus_type == MO_BUS_SCSI) - mo_log("SCSI MO drive %i attached to SCSI ID %i\n", c, mo_drives[c].scsi_device_id); + mo_log(dev->log, "SCSI MO drive %i attached to SCSI ID %i\n", + c, mo_drives[c].scsi_device_id); else if (mo_drives[c].bus_type == MO_BUS_ATAPI) - mo_log("ATAPI MO drive %i attached to IDE channel %i\n", c, mo_drives[c].ide_channel); + mo_log(dev->log, "ATAPI MO drive %i attached to IDE channel %i\n", + c, mo_drives[c].ide_channel); } } } @@ -2208,19 +2178,15 @@ mo_hard_reset(void) void mo_close(void) { - mo_t *dev; - uint8_t scsi_id; - uint8_t scsi_bus; - for (uint8_t c = 0; c < MO_NUM; c++) { if (mo_drives[c].bus_type == MO_BUS_SCSI) { - scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; - scsi_id = mo_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (mo_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = mo_drives[c].scsi_device_id & 0x0f; memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); } - dev = (mo_t *) mo_drives[c].priv; + mo_t *dev = (mo_t *) mo_drives[c].priv; if (dev) { mo_disk_unload(dev); @@ -2228,6 +2194,13 @@ mo_close(void) if (dev->tf) free(dev->tf); + if (dev->log != NULL) { + mo_log(dev->log, "Log closed\n"); + + log_close(dev->log); + dev->log = NULL; + } + free(dev); mo_drives[c].priv = NULL; } diff --git a/src/disk/zip.c b/src/disk/zip.c index 4a5a9b968..fd261b4dd 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,30 +9,27 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * - * * Authors: Miran Grca, * - * Copyright 2018-2019 Miran Grca. + * Copyright 2018-2025 Miran Grca. */ -#include -#include -#include -#include +#ifdef ENABLE_ZIP_LOG #include -#include -#define HAVE_STDARG_H +#endif +#include +#include +#include +#include #include <86box/86box.h> #include <86box/timer.h> -#include <86box/config.h> -#include <86box/timer.h> #include <86box/device.h> +#include <86box/log.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/nvr.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/ui.h> -#include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/zip.h> @@ -40,402 +37,107 @@ zip_drive_t zip_drives[ZIP_NUM]; -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +// clang-format off +/* + Table of all SCSI commands and their flags, needed for the new disc change / + not ready handler. + */ const uint8_t zip_command_flags[0x100] = { - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ - 0, - IMPLEMENTED, /* 0x06 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - IMPLEMENTED, /* 0x0C */ - IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ - 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, - IMPLEMENTED, /* 0x15 */ - IMPLEMENTED | SCSI_ONLY, /* 0x16 */ - IMPLEMENTED | SCSI_ONLY, /* 0x17 */ - 0, 0, - IMPLEMENTED, /* 0x1A */ - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, - IMPLEMENTED, /* 0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, - IMPLEMENTED | ATAPI_ONLY, /* 0x23 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - IMPLEMENTED | CHECK_READY, /* 0x41 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0xBD */ - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + [0x00] = IMPLEMENTED | CHECK_READY, + [0x01] = IMPLEMENTED | ALLOW_UA | SCSI_ONLY, + [0x03] = IMPLEMENTED | ALLOW_UA, + [0x04] = IMPLEMENTED | CHECK_READY | ALLOW_UA | SCSI_ONLY, + [0x06] = IMPLEMENTED, + [0x08] = IMPLEMENTED | CHECK_READY, + [0x0a ... 0x0b] = IMPLEMENTED | CHECK_READY, + [0x0c] = IMPLEMENTED, + [0x0d] = IMPLEMENTED | ATAPI_ONLY, + [0x12] = IMPLEMENTED | ALLOW_UA, + [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x15] = IMPLEMENTED, + [0x16 ... 0x17] = IMPLEMENTED | SCSI_ONLY, + [0x1a] = IMPLEMENTED, + [0x1b] = IMPLEMENTED | CHECK_READY, + [0x1d] = IMPLEMENTED, + [0x1e] = IMPLEMENTED | CHECK_READY, + [0x23] = IMPLEMENTED | ATAPI_ONLY, + [0x25] = IMPLEMENTED | CHECK_READY, + [0x28] = IMPLEMENTED | CHECK_READY, + [0x2a ... 0x2b] = IMPLEMENTED | CHECK_READY, + [0x2e] = IMPLEMENTED | CHECK_READY, + [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x41] = IMPLEMENTED | CHECK_READY, + [0x55] = IMPLEMENTED, + [0x5a] = IMPLEMENTED, + [0xa8] = IMPLEMENTED | CHECK_READY, + [0xaa] = IMPLEMENTED | CHECK_READY, + [0xae] = IMPLEMENTED | CHECK_READY, + [0xaf] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xbd] = IMPLEMENTED }; -static uint64_t zip_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_IOMEGA_PAGE | GPMODEP_ALL_PAGES); -static uint64_t zip_250_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_FLEXIBLE_DISK_PAGE | GPMODEP_CACHING_PAGE | GPMODEP_IOMEGA_PAGE | GPMODEP_ALL_PAGES); +static uint64_t zip_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | + GPMODEP_IOMEGA_PAGE | GPMODEP_ALL_PAGES); +static uint64_t zip_250_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_FLEXIBLE_DISK_PAGE | + GPMODEP_CACHING_PAGE | GPMODEP_IOMEGA_PAGE | + GPMODEP_ALL_PAGES); -static const mode_sense_pages_t zip_mode_sense_pages_default = - // clang-format off -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; -// clang-format on +static const mode_sense_pages_t zip_mode_sense_pages_default = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0x00, 0x50, 0x20 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } } +}; -static const mode_sense_pages_t zip_250_mode_sense_pages_default = - // clang-format off -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; -// clang-format on +static const mode_sense_pages_t zip_250_mode_sense_pages_default = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00 }, + [0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0x00, 0x40, 0x20, 0x02, 0x00, + 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00 }, + [0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } } +}; -static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = - // clang-format off -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; -// clang-format on +static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0x00, 0x50, 0x20 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0xff, 0x0f } } +}; -static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = - // clang-format off -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; -// clang-format on +static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0x00, 0x00, 0x00, 0x00 }, + [0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0x80, 0x00, 0x40, 0x20, 0x02, 0x00, + 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x7d, 0x00, 0x00 }, + [0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } } +}; -static const mode_sense_pages_t zip_mode_sense_pages_changeable = - // clang-format off -{ { - { 0, 0 }, +static const mode_sense_pages_t zip_mode_sense_pages_changeable = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x5a, 0xff, 0xff, 0xff }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } } +}; - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } -} }; -// clang-format on - -static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = - // clang-format off -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xFF, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - {GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CACHING_PAGE, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } -} }; +static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x05] = { GPMODE_FLEXIBLE_DISK_PAGE, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }, + [0x08] = { GPMODE_CACHING_PAGE, 0x0a, 0x04, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff }, + [0x2f] = { GPMODE_IOMEGA_PAGE, 0x04, 0xff, 0xff, 0xff, 0xff } } +}; // clang-format on static void zip_command_complete(zip_t *dev); @@ -445,32 +147,22 @@ static void zip_init(zip_t *dev); int zip_do_log = ENABLE_ZIP_LOG; static void -zip_log(const char *fmt, ...) +zip_log(void *priv, const char *fmt, ...) { va_list ap; if (zip_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define zip_log(fmt, ...) +# define zip_log(priv, fmt, ...) #endif -int -find_zip_for_channel(uint8_t channel) -{ - for (uint8_t i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - static int -zip_load_abort(zip_t *dev) +zip_load_abort(const zip_t *dev) { if (dev->drv->fp) fclose(dev->drv->fp); @@ -481,104 +173,140 @@ zip_load_abort(zip_t *dev) } int -zip_load(zip_t *dev, char *fn) +image_is_zdi(const char *s) { - int size = 0; + return !strcasecmp(path_get_extension((char *) s), "ZDI"); +} - if (!dev->drv) { +int +zip_is_empty(const uint8_t id) +{ + const zip_t *dev = (const zip_t *) zip_drives[id].priv; + int ret = 0; + + if ((dev->drv == NULL) || (dev->drv->fp == NULL)) + ret = 1; + + return ret; +} + +void +zip_load(const zip_t *dev, const char *fn, const int skip_insert) +{ + const int was_empty = zip_is_empty(dev->id); + int ret = 0; + + if (dev->drv == NULL) zip_eject(dev->id); - return 0; - } + else { + const int is_zdi = image_is_zdi(fn); - dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); - if (!dev->drv->fp) { - if (!dev->drv->read_only) { - dev->drv->fp = plat_fopen(fn, "rb"); - if (dev->drv->fp) - dev->drv->read_only = 1; - else - return zip_load_abort(dev); - } else - return zip_load_abort(dev); - } + dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); + ret = 1; - fseek(dev->drv->fp, 0, SEEK_END); - size = ftell(dev->drv->fp); - - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - dev->drv->base = 0x1000; - } else - dev->drv->base = 0; - - if (dev->drv->is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", - ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - return zip_load_abort(dev); + if (dev->drv->fp == NULL) { + if (!dev->drv->read_only) { + dev->drv->fp = plat_fopen(fn, "rb"); + if (dev->drv->fp == NULL) + ret = zip_load_abort(dev); + else + dev->drv->read_only = 1; + } else + ret = zip_load_abort(dev); } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", - ZIP_SECTORS << 9); - return zip_load_abort(dev); + + if (ret) { + fseek(dev->drv->fp, 0, SEEK_END); + int size = ftell(dev->drv->fp); + + if (is_zdi) { + /* This is a ZDI image. */ + size -= 0x1000; + dev->drv->base = 0x1000; + } else + dev->drv->base = 0; + + if (dev->drv->is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log(dev->log, "File is incorrect size for a ZIP image\n"); + zip_log(dev->log, "Must be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + ret = zip_load_abort(dev); + } + } else if (size != (ZIP_SECTORS << 9)) { + zip_log(dev->log, "File is incorrect size for a ZIP image\n"); + zip_log(dev->log, "Must be exactly %i bytes\n", ZIP_SECTORS << 9); + ret = zip_load_abort(dev); + } + + if (ret) + dev->drv->medium_size = size >> 9; + } + + if (ret) { + if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) + log_fatal(dev->log, "zip_load(): Error seeking to the beginning of " + "the file\n"); + + strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); + /* + After using strncpy, dev->drv->image_path needs to be explicitly null + terminated to make gcc happy. + In the event strlen(dev->drv->image_path) == sizeof(dev->drv->image_path) + (no null terminator) it is placed at the very end. Otherwise, it is placed + right after the string. + */ + const size_t term = strlen(dev->drv->image_path) == + sizeof(dev->drv->image_path) ? sizeof(dev->drv->image_path) - 1 : + strlen(dev->drv->image_path); + dev->drv->image_path[term] = '\0'; } } - dev->drv->medium_size = size >> 9; + if (ret && !skip_insert) { + /* Signal media change to the emulated machine. */ + zip_insert((zip_t *) dev); - if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) - fatal("zip_load(): Error seeking to the beginning of the file\n"); - - strncpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path) - 1); - // After using strncpy, dev->drv->image_path needs to be explicitly null terminated to make gcc happy. - // In the event strlen(dev->drv->image_path) == sizeof(dev->drv->image_path) (no null terminator) - // it is placed at the very end. Otherwise, it is placed right after the string. - const size_t term = strlen(dev->drv->image_path) == sizeof(dev->drv->image_path) ? sizeof(dev->drv->image_path) - 1 : strlen(dev->drv->image_path); - dev->drv->image_path[term] = '\0'; - - return 1; + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + zip_insert((zip_t *) dev); + } } void -zip_disk_reload(zip_t *dev) +zip_disk_reload(const zip_t *dev) { - int ret = 0; - - if (strlen(dev->drv->prev_image_path) == 0) - return; - else - ret = zip_load(dev, dev->drv->prev_image_path); - - if (ret) - dev->unit_attention = 1; + if (strlen(dev->drv->prev_image_path) != 0) + (void) zip_load(dev, dev->drv->prev_image_path, 0); } -void -zip_disk_unload(zip_t *dev) +static void +zip_disk_unload(const zip_t *dev) { - if (dev->drv && dev->drv->fp) { + if ((dev->drv != NULL) && (dev->drv->fp != NULL)) { fclose(dev->drv->fp); dev->drv->fp = NULL; } } void -zip_disk_close(zip_t *dev) +zip_disk_close(const zip_t *dev) { - if (dev->drv && dev->drv->fp) { + if ((dev->drv != NULL) && (dev->drv->fp != NULL)) { zip_disk_unload(dev); - memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); + memcpy(dev->drv->prev_image_path, dev->drv->image_path, + sizeof(dev->drv->prev_image_path)); memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); dev->drv->medium_size = 0; + + zip_insert((zip_t *) dev); } } static void -zip_set_callback(zip_t *dev) +zip_set_callback(const zip_t *dev) { if (dev->drv->bus_type != ZIP_BUS_SCSI) ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback); @@ -587,54 +315,54 @@ zip_set_callback(zip_t *dev) static void zip_init(zip_t *dev) { - if (dev->id >= ZIP_NUM) - return; - - dev->requested_blocks = 1; - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - dev->drv->bus_mode = 0; - if (dev->drv->bus_type >= ZIP_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus_type < ZIP_BUS_SCSI) - dev->drv->bus_mode |= 1; - zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - if (dev->drv->bus_type < ZIP_BUS_SCSI) { - dev->tf->phase = 1; - dev->tf->request_length = 0xEB14; + if (dev->id < ZIP_NUM) { + dev->requested_blocks = 1; + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= ZIP_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < ZIP_BUS_SCSI) + dev->drv->bus_mode |= 1; + zip_log(dev->log, "Bus type %i, bus mode %i\n", dev->drv->bus_type, dev->drv->bus_mode); + if (dev->drv->bus_type < ZIP_BUS_SCSI) { + dev->tf->phase = 1; + dev->tf->request_length = 0xEB14; + } + dev->tf->status = READY_STAT | DSC_STAT; + dev->tf->pos = 0; + dev->packet_status = PHASE_NONE; + zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = dev->transition = 0; + zip_info = 0x00000000; } - dev->tf->status = READY_STAT | DSC_STAT; - dev->tf->pos = 0; - dev->packet_status = PHASE_NONE; - zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; } static int -zip_supports_pio(zip_t *dev) +zip_supports_pio(const zip_t *dev) { return (dev->drv->bus_mode & 1); } static int -zip_supports_dma(zip_t *dev) +zip_supports_dma(const zip_t *dev) { return (dev->drv->bus_mode & 2); } /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ static int -zip_current_mode(zip_t *dev) +zip_current_mode(const zip_t *dev) { if (!zip_supports_pio(dev) && !zip_supports_dma(dev)) return 0; if (zip_supports_pio(dev) && !zip_supports_dma(dev)) { - zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", dev->id); + zip_log(dev->log, "Drive does not support DMA, setting to PIO\n"); return 1; } if (!zip_supports_pio(dev) && zip_supports_dma(dev)) return 2; if (zip_supports_pio(dev) && zip_supports_dma(dev)) { - zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id, + zip_log(dev->log, "Drive supports both, setting to %s\n", (dev->tf->features & 1) ? "DMA" : "PIO"); return (dev->tf->features & 1) ? 2 : 1; } @@ -645,8 +373,7 @@ zip_current_mode(zip_t *dev) static void zip_mode_sense_load(zip_t *dev) { - FILE *fp; - char fn[512]; + char fn[512] = { 0 }; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); if (dev->drv->is_250) { @@ -661,12 +388,11 @@ zip_mode_sense_load(zip_t *dev) memcpy(&dev->ms_pages_saved, &zip_mode_sense_pages_default, sizeof(mode_sense_pages_t)); } - memset(fn, 0, 512); if (dev->drv->bus_type == ZIP_BUS_SCSI) sprintf(fn, "scsi_zip_%02i_mode_sense_bin", dev->id); else sprintf(fn, "zip_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(fn), "rb"); + FILE *fp = plat_fopen(nvr_path(fn), "rb"); if (fp) { /* Nothing to read, not used by ZIP. */ fclose(fp); @@ -674,31 +400,31 @@ zip_mode_sense_load(zip_t *dev) } static void -zip_mode_sense_save(zip_t *dev) +zip_mode_sense_save(const zip_t *dev) { - FILE *fp; - char fn[512]; + char fn[512] = { 0 }; - memset(fn, 0, 512); if (dev->drv->bus_type == ZIP_BUS_SCSI) sprintf(fn, "scsi_zip_%02i_mode_sense_bin", dev->id); else sprintf(fn, "zip_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(fn), "wb"); + FILE *fp = plat_fopen(nvr_path(fn), "wb"); if (fp) { /* Nothing to write, not used by ZIP. */ fclose(fp); } } -/*SCSI Mode Sense 6/10*/ +/* SCSI Mode Sense 6/10. */ static uint8_t -zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +zip_mode_sense_read(const zip_t *dev, const uint8_t pgctl, + const uint8_t page, const uint8_t pos) { - switch (page_control) { + switch (pgctl) { case 0: case 3: - if (dev->drv->is_250 && (page == 5) && (pos == 9) && (dev->drv->medium_size == ZIP_SECTORS)) + if (dev->drv->is_250 && (page == 5) && (pos == 9) && + (dev->drv->medium_size == ZIP_SECTORS)) return 0x60; return dev->ms_pages_saved.pages[page][pos]; case 1: @@ -729,18 +455,17 @@ zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) } static uint32_t -zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +zip_mode_sense(const zip_t *dev, uint8_t *buf, uint32_t pos, + uint8_t page, const uint8_t block_descriptor_len) { - uint64_t pf; - uint8_t page_control = (page >> 6) & 3; + uint64_t pf; + const uint8_t pgctl = (page >> 6) & 3; if (dev->drv->is_250) pf = zip_250_mode_sense_page_flags; else pf = zip_mode_sense_page_flags; - uint8_t msplen; - page &= 0x3f; if (block_descriptor_len) { @@ -757,12 +482,12 @@ zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t blo for (uint8_t i = 0; i < 0x40; i++) { if ((page == GPMODE_ALL_PAGES) || (page == i)) { if (pf & (1LL << ((uint64_t) page))) { - buf[pos++] = zip_mode_sense_read(dev, page_control, i, 0); - msplen = zip_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + const uint8_t msplen = zip_mode_sense_read(dev, pgctl, i, 1); + buf[pos++] = zip_mode_sense_read(dev, pgctl, i, 0); + buf[pos++] = msplen; + zip_log(dev->log, "MODE SENSE: Page [%02X] length %i\n", i, msplen); for (uint8_t j = 0; j < msplen; j++) - buf[pos++] = zip_mode_sense_read(dev, page_control, i, 2 + j); + buf[pos++] = zip_mode_sense_read(dev, pgctl, i, 2 + j); } } } @@ -778,7 +503,10 @@ zip_update_request_length(zip_t *dev, int len, int block_len) dev->max_transfer_len = dev->tf->request_length; - /* For media access commands, make sure the requested DRQ length matches the block length. */ + /* + For media access commands, make sure the requested DRQ length matches the + block length. + */ switch (dev->current_cdb[0]) { case 0x08: case 0x0a: @@ -789,8 +517,10 @@ zip_update_request_length(zip_t *dev, int len, int block_len) /* Round it to the nearest 2048 bytes. */ dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9; - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ + /* + Make sure total length is not bigger than sum of the lengths of + all the requested blocks. + */ bt = (dev->requested_blocks * block_len); if (len > bt) len = bt; @@ -812,10 +542,16 @@ zip_update_request_length(zip_t *dev, int len, int block_len) dev->packet_len = len; break; } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + /* + If the DRQ length is odd, and the total remaining length is bigger, + make sure it's even. + */ if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + /* + If the DRQ length is smaller or equal in size to the total remaining length, + set it to that. + */ if (!dev->max_transfer_len) dev->max_transfer_len = 65534; @@ -850,23 +586,22 @@ zip_bus_speed(zip_t *dev) static void zip_command_common(zip_t *dev) { - double bytes_per_second; - double period; - dev->tf->status = BUSY_STAT; dev->tf->phase = 1; dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; else { + double bytes_per_second; + if (dev->drv->bus_type == ZIP_BUS_SCSI) { dev->callback = -1.0; /* Speed depends on SCSI controller */ return; } else bytes_per_second = zip_bus_speed(dev); - period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); + double period = 1000000.0 / bytes_per_second; + dev->callback = period * (double) (dev->packet_len); } zip_set_callback(dev); @@ -907,16 +642,20 @@ zip_command_write_dma(zip_t *dev) zip_command_common(dev); } -/* id = Current ZIP device ID; +/* + dev = Pointer to current ZIP device; len = Total transfer length; block_len = Length of a single block (why does it matter?!); alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ + direction = Transfer direction (0 = read from host, 1 = write to host). + */ static void -zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int direction) +zip_data_command_finish(zip_t *dev, int len, const int block_len, + const int alloc_len, const int direction) { - zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); + zip_log(dev->log, "Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->current_cdb[0], len, block_len, alloc_len, + direction, dev->tf->request_length); dev->tf->pos = 0; if (alloc_len >= 0) { if (alloc_len < len) @@ -945,27 +684,26 @@ zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int d } } - zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, - dev->tf->phase); + zip_log(dev->log, "Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->packet_status, dev->tf->request_length, dev->packet_len, + dev->tf->pos, dev->tf->phase); } static void zip_sense_clear(zip_t *dev, UNUSED(int command)) { zip_sense_key = zip_asc = zip_ascq = 0; + zip_info = 0x00000000; } static void -zip_set_phase(zip_t *dev, uint8_t phase) +zip_set_phase(const zip_t *dev, const uint8_t phase) { - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; - if (dev->drv->bus_type != ZIP_BUS_SCSI) - return; - - scsi_devices[scsi_bus][scsi_id].phase = phase; + if (dev->drv->bus_type == ZIP_BUS_SCSI) + scsi_devices[scsi_bus][scsi_id].phase = phase; } static void @@ -973,8 +711,6 @@ zip_cmd_error(zip_t *dev) { zip_set_phase(dev, SCSI_PHASE_STATUS); dev->tf->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->tf->error |= MCR_ERR; dev->tf->status = READY_STAT | ERR_STAT; dev->tf->phase = 3; dev->tf->pos = 0; @@ -982,7 +718,8 @@ zip_cmd_error(zip_t *dev) dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); ui_sb_update_icon(SB_ZIP | dev->id, 0); - zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); + zip_log(dev->log, "[%02X] ERROR: %02X/%02X/%02X\n", dev->current_cdb[0], zip_sense_key, + zip_asc, zip_ascq); } static void @@ -990,8 +727,6 @@ zip_unit_attention(zip_t *dev) { zip_set_phase(dev, SCSI_PHASE_STATUS); dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->tf->error |= MCR_ERR; dev->tf->status = READY_STAT | ERR_STAT; dev->tf->phase = 3; dev->tf->pos = 0; @@ -999,22 +734,22 @@ zip_unit_attention(zip_t *dev) dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); ui_sb_update_icon(SB_ZIP | dev->id, 0); - zip_log("ZIP %i: UNIT ATTENTION\n", dev->id); + zip_log(dev->log, "UNIT ATTENTION\n", dev->id); } static void -zip_buf_alloc(zip_t *dev, uint32_t len) +zip_buf_alloc(zip_t *dev, const uint32_t len) { - zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->buffer) + zip_log(dev->log, "Allocated buffer length: %i\n", len); + if (dev->buffer == NULL) dev->buffer = (uint8_t *) malloc(len); } static void zip_buf_free(zip_t *dev) { - if (dev->buffer) { - zip_log("ZIP %i: Freeing buffer...\n", dev->id); + if (dev->buffer != NULL) { + zip_log(dev->log, "ZIP %i: Freeing buffer...\n"); free(dev->buffer); dev->buffer = NULL; } @@ -1027,6 +762,10 @@ zip_bus_master_error(scsi_common_t *sc) zip_buf_free(dev); zip_sense_key = zip_asc = zip_ascq = 0; + zip_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); zip_cmd_error(dev); } @@ -1036,6 +775,7 @@ zip_not_ready(zip_t *dev) zip_sense_key = SENSE_NOT_READY; zip_asc = ASC_MEDIUM_NOT_PRESENT; zip_ascq = 0; + zip_info = 0x00000000; zip_cmd_error(dev); } @@ -1045,6 +785,10 @@ zip_write_protected(zip_t *dev) zip_sense_key = SENSE_UNIT_ATTENTION; zip_asc = ASC_WRITE_PROTECTED; zip_ascq = 0; + zip_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); zip_cmd_error(dev); } @@ -1054,6 +798,10 @@ zip_write_error(zip_t *dev) zip_sense_key = SENSE_MEDIUM_ERROR; zip_asc = ASC_WRITE_ERROR; zip_ascq = 0; + zip_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); zip_cmd_error(dev); } @@ -1063,24 +811,30 @@ zip_read_error(zip_t *dev) zip_sense_key = SENSE_MEDIUM_ERROR; zip_asc = ASC_UNRECOVERED_READ_ERROR; zip_ascq = 0; + zip_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); zip_cmd_error(dev); } static void -zip_invalid_lun(zip_t *dev) +zip_invalid_lun(zip_t *dev, const uint8_t lun) { zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_INV_LUN; zip_ascq = 0; + zip_info = lun << 24; zip_cmd_error(dev); } static void -zip_illegal_opcode(zip_t *dev) +zip_illegal_opcode(zip_t *dev, const uint8_t opcode) { zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_ILLEGAL_OPCODE; zip_ascq = 0; + zip_info = opcode << 24; zip_cmd_error(dev); } @@ -1090,191 +844,244 @@ zip_lba_out_of_range(zip_t *dev) zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_LBA_OUT_OF_RANGE; zip_ascq = 0; + zip_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); zip_cmd_error(dev); } static void -zip_invalid_field(zip_t *dev) +zip_invalid_field(zip_t *dev, const uint32_t field) { zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; zip_ascq = 0; + zip_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); zip_cmd_error(dev); dev->tf->status = 0x53; } static void -zip_invalid_field_pl(zip_t *dev) +zip_invalid_field_pl(zip_t *dev, const uint32_t field) { zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; zip_ascq = 0; + zip_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); zip_cmd_error(dev); dev->tf->status = 0x53; } static void -zip_data_phase_error(zip_t *dev) +zip_data_phase_error(zip_t *dev, const uint32_t info) { zip_sense_key = SENSE_ILLEGAL_REQUEST; zip_asc = ASC_DATA_PHASE_ERROR; zip_ascq = 0; + zip_info = (info >> 24) | + ((info >> 16) << 8) | + ((info >> 8) << 16) | + ( info << 24); zip_cmd_error(dev); } static int -zip_blocks(zip_t *dev, int32_t *len, UNUSED(int first_batch), int out) +zip_blocks(zip_t *dev, int32_t *len, const int out) { - *len = 0; + int ret = 1; + *len = 0; - if (!dev->sector_len) { + if (!dev->sector_len) zip_command_complete(dev); - return 0; - } + else { + zip_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", + dev->requested_blocks, dev->sector_pos); - zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); - - if (dev->sector_pos >= dev->drv->medium_size) { - zip_log("ZIP %i: Trying to %s beyond the end of disk\n", dev->id, out ? "write" : "read"); - zip_lba_out_of_range(dev); - return 0; - } - - *len = dev->requested_blocks << 9; - - for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET) == -1) { - if (out) - zip_write_error(dev); - else - zip_read_error(dev); - return -1; - } - - if (feof(dev->drv->fp)) - break; - - if (out) { - if (fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->fp) != 512) { - zip_log("zip_blocks(): Error writing data\n"); - zip_write_error(dev); - return -1; - } - - fflush(dev->drv->fp); + if (dev->sector_pos >= dev->drv->medium_size) { + zip_log(dev->log, "Trying to %s beyond the end of disk\n", + out ? "write" : "read"); + zip_lba_out_of_range(dev); } else { - if (fread(dev->buffer + (i << 9), 1, 512, dev->drv->fp) != 512) { - zip_log("zip_blocks(): Error reading data\n"); - zip_read_error(dev); - return -1; + *len = dev->requested_blocks << 9; + + for (int i = 0; i < dev->requested_blocks; i++) { + if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9) + + (i << 9), SEEK_SET) == -1) { + if (out) + zip_write_error(dev); + else + zip_read_error(dev); + ret = -1; + } else { + if (feof(dev->drv->fp)) + break; + + if (out) { + if (fwrite(dev->buffer + (i << 9), 1, + 512, dev->drv->fp) != 512) { + zip_log(dev->log, "zip_blocks(): Error writing data\n"); + zip_write_error(dev); + ret = -1; + } else + fflush(dev->drv->fp); + } else if (fread(dev->buffer + (i << 9), 1, + 512, dev->drv->fp) != 512) { + zip_log(dev->log, "zip_blocks(): Error reading data\n"); + zip_read_error(dev); + ret = -1; + } + } + + if (ret == -1) + break; + + dev->sector_pos++; + } + + if (ret == 1) { + zip_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : + "Read", *len); + + dev->sector_len -= dev->requested_blocks; } } } - zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - dev->sector_pos += dev->requested_blocks; - dev->sector_len -= dev->requested_blocks; - - return 1; + return ret; } void zip_insert(zip_t *dev) { - dev->unit_attention = 1; -} - -/*SCSI Sense Initialization*/ -void -zip_sense_code_ok(zip_t *dev) -{ - zip_sense_key = SENSE_NONE; - zip_asc = 0; - zip_ascq = 0; + if ((dev != NULL) && (dev->drv != NULL)) { + if (dev->drv->fp == NULL) { + dev->unit_attention = 0; + dev->transition = 0; + zip_log(dev->log, "Media removal\n"); + } else if (dev->transition) { + dev->unit_attention = 1; + /* Turn off the medium changed status. */ + dev->transition = 0; + zip_log(dev->log, "Media insert\n"); + } else { + dev->unit_attention = 0; + dev->transition = 1; + zip_log(dev->log, "Media transition\n"); + } + } } static int -zip_pre_execution_check(zip_t *dev, uint8_t *cdb) +zip_pre_execution_check(zip_t *dev, const uint8_t *cdb) { - int ready = 0; + int ready; - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && + (cdb[1] & 0xe0)) { + zip_log(dev->log, "Attempting to execute a unknown command targeted at SCSI LUN %i\n", ((dev->tf->request_length >> 5) & 7)); - zip_invalid_lun(dev); + zip_invalid_lun(dev, cdb[1] >> 5); return 0; } if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { - zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == ZIP_BUS_SCSI) ? "SCSI" : "ATAPI"); + zip_log(dev->log, "Attempting to execute unknown command %02X over %s\n", + cdb[0], (dev->drv->bus_type == ZIP_BUS_SCSI) ? + "SCSI" : "ATAPI"); - zip_illegal_opcode(dev); + zip_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { - zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - zip_illegal_opcode(dev); + if ((dev->drv->bus_type < ZIP_BUS_SCSI) && + (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log(dev->log, "Attempting to execute SCSI-only command %02X " + "over ATAPI\n", cdb[0]); + zip_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { - zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); - zip_illegal_opcode(dev); + if ((dev->drv->bus_type == ZIP_BUS_SCSI) && + (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log(dev->log, "Attempting to execute ATAPI-only command %02X " + "over SCSI\n", cdb[0]); + zip_illegal_opcode(dev, cdb[0]); return 0; } - ready = (dev->drv->fp != NULL); + if (dev->transition) { + if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) + ready = 0; + else { + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + zip_log(dev->log, "(ext_medium_changed != 0): zip_insert()\n"); + zip_insert((void *) dev); + } - /* If the drive is not ready, there is no reason to keep the + ready = (dev->drv->fp != NULL); + } + } else + ready = (dev->drv->fp != NULL); + + /* + If the drive is not ready, there is no reason to keep the UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && dev->unit_attention) + disc changes. + */ + if (!ready && (dev->unit_attention > 0)) dev->unit_attention = 0; - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ + /* + If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. + */ if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ + /* + Only increment the unit attention phase if the command can + not pass through it. + */ if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { - /* zip_log("ZIP %i: Unit attention now 2\n", dev->id); */ - dev->unit_attention = 2; - zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", dev->id, cdb[0]); + zip_log(dev->log, "Unit attention now 2\n"); + dev->unit_attention++; + zip_log(dev->log, "UNIT ATTENTION: Command %02X not allowed to pass through\n", + cdb[0]); zip_unit_attention(dev); return 0; } } else if (dev->unit_attention == 2) { if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* zip_log("ZIP %i: Unit attention now 0\n", dev->id); */ + zip_log(dev->log, "Unit attention now 0\n"); dev->unit_attention = 0; } } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ + /* + Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear + the UNIT ATTENTION condition if it's set. + */ if (cdb[0] != GPCMD_REQUEST_SENSE) zip_sense_clear(dev, cdb[0]); - /* Next it's time for NOT READY. */ - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { - zip_log("ZIP %i: Not ready (%02X)\n", dev->id, cdb[0]); + if (!ready && (zip_command_flags[cdb[0]] & CHECK_READY)) { + zip_log(dev->log, "Not ready (%02X)\n", cdb[0]); zip_not_ready(dev); return 0; } - zip_log("ZIP %i: Continuing with command %02X\n", dev->id, cdb[0]); - + zip_log(dev->log, "Continuing with command %02X\n", cdb[0]); return 1; } static void -zip_seek(zip_t *dev, uint32_t pos) +zip_seek(zip_t *dev, const uint32_t pos) { -#if 0 - zip_log("ZIP %i: Seek %08X\n", dev->id, pos); -#endif dev->sector_pos = pos; } @@ -1299,10 +1106,12 @@ zip_reset(scsi_common_t *sc) dev->packet_status = PHASE_NONE; dev->unit_attention = 0; dev->cur_lun = SCSI_LUN_USE_CDB; + zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = dev->transition = 0; + zip_info = 0x00000000; } static void -zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +zip_request_sense(zip_t *dev, uint8_t *buffer, const uint8_t alloc_length, const int desc) { /*Will return 18 bytes of 0*/ if (alloc_length != 0) { @@ -1316,7 +1125,9 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) } } - buffer[0] = desc ? 0x72 : 0x70; + buffer[0] = desc ? 0x72 : 0xf0; + if (!desc) + buffer[7] = 10; if (dev->unit_attention && (zip_sense_key == 0)) { buffer[desc ? 1 : 2] = SENSE_UNIT_ATTENTION; @@ -1324,7 +1135,8 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) buffer[desc ? 3 : 13] = 0; } - zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + zip_log(dev->log, "Reporting sense: %02X %02X %02X\n", buffer[2], + buffer[12], buffer[13]); if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { /* If the last remaining sense is unit attention, clear @@ -1334,30 +1146,33 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) /* Clear the sense stuff as per the spec. */ zip_sense_clear(dev, GPCMD_REQUEST_SENSE); + + if (dev->transition) { + zip_log(dev->log, "ZIP_TRANSITION: zip_insert()\n"); + zip_insert((void *) dev); + } } static void -zip_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) +zip_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, const uint8_t alloc_length) { - zip_t *dev = (zip_t *) sc; - int ready = 0; - - ready = (dev->drv->fp != NULL); + zip_t *dev = (zip_t *) sc; + const int ready = (dev->drv->fp != NULL); if (!ready && dev->unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ + /* + If the drive is not ready, there is no reason to keep the UNIT ATTENTION + condition present, as we only use it to mark disc changes. + */ dev->unit_attention = 0; } /* Do *NOT* advance the unit attention phase. */ - zip_request_sense(dev, buffer, alloc_length, 0); } static void -zip_set_buf_len(zip_t *dev, int32_t *BufLen, int32_t *src_len) +zip_set_buf_len(const zip_t *dev, int32_t *BufLen, int32_t *src_len) { if (dev->drv->bus_type == ZIP_BUS_SCSI) { if (*BufLen == -1) @@ -1366,28 +1181,27 @@ zip_set_buf_len(zip_t *dev, int32_t *BufLen, int32_t *src_len) *BufLen = MIN(*src_len, *BufLen); *src_len = *BufLen; } - zip_log("ZIP %i: Actual transfer length: %i\n", dev->id, *BufLen); + zip_log(dev->log, "Actual transfer length: %i\n", *BufLen); } } static void -zip_command(scsi_common_t *sc, uint8_t *cdb) +zip_command(scsi_common_t *sc, const uint8_t *cdb) { - zip_t *dev = (zip_t *) sc; - int pos = 0; - int block_desc = 0; - int ret; - int32_t len; - int32_t max_len; - int32_t alloc_length; - uint32_t i = 0; - int size_idx; - int idx = 0; - unsigned preamble_len; - int32_t blen = 0; - int32_t *BufLen; - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + zip_t *dev = (zip_t *) sc; + const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + int pos = 0; + int idx = 0; + int32_t blen = 0; + uint32_t i; + unsigned preamble_len; + int32_t len; + int32_t max_len; + int32_t alloc_length; + int block_desc; + int size_idx; + int32_t * BufLen; if (dev->drv->bus_type == ZIP_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; @@ -1403,11 +1217,13 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { - zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); - zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->tf->request_length); + zip_log(dev->log, "Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, " + "Unit attention: %i\n", + cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); + zip_log(dev->log, "Request length: %04X\n", dev->tf->request_length); - zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + zip_log(dev->log, "CDB: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); } @@ -1416,14 +1232,17 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_set_phase(dev, SCSI_PHASE_STATUS); - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + /* + This handles the Not Ready/Unit Attention check if it has to be handled at + this point. + */ if (zip_pre_execution_check(dev, cdb) == 0) return; switch (cdb[0]) { case GPCMD_SEND_DIAGNOSTIC: if (!(cdb[1] & (1 << 2))) { - zip_invalid_field(dev); + zip_invalid_field(dev, cdb[1]); return; } fallthrough; @@ -1435,13 +1254,12 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_FORMAT_UNIT: - if (dev->drv->read_only) { + if (dev->drv->read_only) zip_write_protected(dev); - return; + else { + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_command_complete(dev); } - - zip_set_phase(dev, SCSI_PHASE_STATUS); - zip_command_complete(dev); break; case GPCMD_IOMEGA_SENSE: @@ -1451,8 +1269,10 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_set_buf_len(dev, BufLen, &max_len); memset(dev->buffer, 0, 256); if (cdb[2] == 1) { - /* This page is related to disk health status - setting - this page to 0 makes disk health read as "marginal". */ + /* + This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". + */ dev->buffer[0] = 0x58; dev->buffer[1] = 0x00; for (i = 0x00; i < 0x58; i++) @@ -1468,7 +1288,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) for (i = 0x00; i < 0x27; i++) dev->buffer[i + 0x16] = 0x00; } else { - zip_invalid_field(dev); + zip_invalid_field(dev, cdb[2]); zip_buf_free(dev); return; } @@ -1482,9 +1302,11 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not - ready, a standalone REQUEST SENSE should forget about the not - ready, and report unit attention straight away. */ + /* + If there's a unit attention condition and there's a buffered not ready, a + standalone REQUEST SENSE should forget about the not ready, and report unit + attention straight away. + */ zip_set_phase(dev, SCSI_PHASE_DATA_IN); max_len = cdb[4]; @@ -1533,17 +1355,20 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = 256; dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + zip_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + zip_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; @@ -1551,51 +1376,47 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; } - if (dev->sector_pos >= dev->drv->medium_size) { + if (dev->sector_pos >= dev->drv->medium_size) zip_lba_out_of_range(dev); - return; - } + else if (dev->sector_len) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; - if (!dev->sector_len) { + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(dev, dev->packet_len); + + int ret = 0; + + if (dev->sector_len > 0) + ret = zip_blocks(dev, &alloc_length, 0); + + if (ret > 0) { + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + zip_data_command_finish(dev, alloc_length, 512, + alloc_length, 0); + + ui_sb_update_icon(SB_ZIP | dev->id, + dev->packet_status != PHASE_COMPLETE); + } else { + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; + zip_set_callback(dev); + zip_buf_free(dev); + } + } else { zip_set_phase(dev, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ + /* zip_log(dev->log, "All done - callback set\n"); */ dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } - - max_len = dev->sector_len; - /* - If we're reading all blocks in one go for DMA, why not also for - PIO, it should NOT matter anyway, this step should be identical - and only the way the read dat is transferred to the host should - be different. - */ - dev->requested_blocks = max_len; - - dev->packet_len = max_len * alloc_length; - zip_buf_alloc(dev, dev->packet_len); - - ret = zip_blocks(dev, &alloc_length, 1, 0); - if (ret <= 0) { - zip_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; - dev->callback = 20.0 * ZIP_TIME; - zip_set_callback(dev); - zip_buf_free(dev); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0); - - ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: @@ -1616,7 +1437,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) if (dev->drv->read_only) { zip_write_protected(dev); - return; + break; } switch (cdb[0]) { @@ -1636,15 +1457,19 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + zip_log(dev->log, "Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_12: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; @@ -1652,86 +1477,75 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; } - if (dev->sector_pos >= dev->drv->medium_size) { + if (dev->sector_pos >= dev->drv->medium_size) zip_lba_out_of_range(dev); - return; - } + if (dev->sector_len) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; - if (!dev->sector_len) { + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(dev, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + zip_data_command_finish(dev, dev->packet_len, 512, + dev->packet_len, 1); + + ui_sb_update_icon(SB_ZIP | dev->id, + dev->packet_status != PHASE_COMPLETE); + } else { zip_set_phase(dev, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ + /* zip_log(dev->log, "All done - callback set\n"); */ dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); - break; } - - max_len = dev->sector_len; - /* - If we're writing all blocks in one go for DMA, why not also for - PIO, it should NOT matter anyway, this step should be identical - and only the way the read dat is transferred to the host should - be different. - */ - dev->requested_blocks = max_len; - - dev->packet_len = max_len * alloc_length; - zip_buf_alloc(dev, dev->packet_len); - - dev->requested_blocks = max_len; - dev->packet_len = max_len << 9; - - zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - - ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_WRITE_SAME_10: alloc_length = 512; - if ((cdb[1] & 6) == 6) { - zip_invalid_field(dev); - return; + if ((cdb[1] & 6) == 6) + zip_invalid_field(dev, cdb[1]); + else { + if (dev->drv->read_only) + zip_write_protected(dev); + else { + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + + if (dev->sector_pos >= dev->drv->medium_size) + zip_lba_out_of_range(dev); + else if (dev->sector_len) { + zip_buf_alloc(dev, alloc_length); + zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + max_len = 1; + dev->requested_blocks = 1; + + dev->packet_len = alloc_length; + + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); + + zip_data_command_finish(dev, 512, 512, + alloc_length, 1); + + ui_sb_update_icon(SB_ZIP | dev->id, + dev->packet_status != PHASE_COMPLETE); + } else { + zip_set_phase(dev, SCSI_PHASE_STATUS); + /* zip_log(dev->log, "All done - callback set\n"); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * ZIP_TIME; + zip_set_callback(dev); + } + } } - - if (dev->drv->read_only) { - zip_write_protected(dev); - return; - } - - dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - if (dev->sector_pos >= dev->drv->medium_size) { - zip_lba_out_of_range(dev); - return; - } - - if (!dev->sector_len) { - zip_set_phase(dev, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * ZIP_TIME; - zip_set_callback(dev); - break; - } - - zip_buf_alloc(dev, alloc_length); - zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - max_len = 1; - dev->requested_blocks = 1; - - dev->packet_len = alloc_length; - - zip_set_phase(dev, SCSI_PHASE_DATA_OUT); - - zip_data_command_finish(dev, 512, 512, alloc_length, 1); - - ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: @@ -1750,40 +1564,41 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_buf_alloc(dev, 65536); } - if (!(zip_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { - zip_invalid_field(dev); - zip_buf_free(dev); - return; - } + if (zip_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f))) { + memset(dev->buffer, 0, len); + alloc_length = len; - memset(dev->buffer, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = zip_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - dev->buffer[0] = len - 1; - dev->buffer[1] = 0; - if (block_desc) - dev->buffer[3] = 8; - } else { - len = zip_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - dev->buffer[0] = (len - 2) >> 8; - dev->buffer[1] = (len - 2) & 255; - dev->buffer[2] = 0; - if (block_desc) { - dev->buffer[6] = 0; - dev->buffer[7] = 8; + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(dev, dev->buffer, 4, cdb[2], + block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = len - 1; + dev->buffer[1] = 0; + if (block_desc) + dev->buffer[3] = 8; + } else { + len = zip_mode_sense(dev, dev->buffer, 8, cdb[2], + block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = (len - 2) >> 8; + dev->buffer[1] = (len - 2) & 255; + dev->buffer[2] = 0; + if (block_desc) { + dev->buffer[6] = 0; + dev->buffer[7] = 8; + } } + + zip_set_buf_len(dev, BufLen, &len); + + zip_log(dev->log, "Reading mode page: %02X...\n", cdb[2]); + + zip_data_command_finish(dev, len, len, alloc_length, 0); + } else { + zip_invalid_field(dev, cdb[2]); + zip_buf_free(dev); } - - zip_set_buf_len(dev, BufLen, &len); - - zip_log("ZIP %i: Reading mode page: %02X...\n", dev->id, cdb[2]); - - zip_data_command_finish(dev, len, len, alloc_length, 0); - return; + break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: @@ -1856,7 +1671,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; case 0x83: if (idx + 24 > max_len) { - zip_data_phase_error(dev); + zip_data_phase_error(dev, cdb[2]); zip_buf_free(dev); return; } @@ -1874,19 +1689,21 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[idx++] = 0x01; dev->buffer[idx++] = 0x00; dev->buffer[idx++] = 68; - ide_padstr8(dev->buffer + idx, 8, "IOMEGA "); /* Vendor */ + /* Vendor */ + ide_padstr8(dev->buffer + idx, 8, "IOMEGA "); idx += 8; + /* Product */ if (dev->drv->is_250) - ide_padstr8(dev->buffer + idx, 40, "ZIP 250 "); /* Product */ + ide_padstr8(dev->buffer + idx, 40, "ZIP 250 "); else - ide_padstr8(dev->buffer + idx, 40, "ZIP 100 "); /* Product */ + ide_padstr8(dev->buffer + idx, 40, "ZIP 100 "); idx += 40; - ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Product */ + ide_padstr8(dev->buffer + idx, 20, "53R141"); idx += 20; break; default: - zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - zip_invalid_field(dev); + zip_log(dev->log, "INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(dev, cdb[2]); zip_buf_free(dev); return; } @@ -1896,33 +1713,39 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->buffer, 0, 8); if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) - dev->buffer[0] = 0x7f; /*No physical device on this LUN*/ + dev->buffer[0] = 0x7f; /* No physical device on this LUN */ else - dev->buffer[0] = 0x00; /*Hard disk*/ - dev->buffer[1] = 0x80; /*Removable*/ - dev->buffer[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + dev->buffer[0] = 0x00; /* Hard disk */ + dev->buffer[1] = 0x80; /* Removable */ + /* SCSI-2 compliant */ + dev->buffer[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; dev->buffer[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; #if 0 dev->buffer[4] = 31; #endif dev->buffer[4] = 0; if (dev->drv->bus_type == ZIP_BUS_SCSI) { - dev->buffer[6] = 1; /* 16-bit transfers supported */ - dev->buffer[7] = 0x20; /* Wide bus supported */ + dev->buffer[6] = 1; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ } dev->buffer[7] |= 0x02; - ide_padstr8(dev->buffer + 8, 8, "IOMEGA "); /* Vendor */ + ide_padstr8(dev->buffer + 8, 8, "IOMEGA "); /* Vendor */ if (dev->drv->is_250) { - ide_padstr8(dev->buffer + 16, 16, "ZIP 250 "); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "42.S"); /* Revision */ + /* Product */ + ide_padstr8(dev->buffer + 16, 16, "ZIP 250 "); + /* Revision */ + ide_padstr8(dev->buffer + 32, 4, "42.S"); + /* Date? */ if (max_len >= 44) - ide_padstr8(dev->buffer + 36, 8, "08/08/01"); /* Date? */ + ide_padstr8(dev->buffer + 36, 8, "08/08/01"); if (max_len >= 122) ide_padstr8(dev->buffer + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ } else { - ide_padstr8(dev->buffer + 16, 16, "ZIP 100 "); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "E.08"); /* Revision */ + /* Product */ + ide_padstr8(dev->buffer + 16, 16, "ZIP 100 "); + /* Revision */ + ide_padstr8(dev->buffer + 32, 4, "E.08"); } idx = 36; @@ -1974,7 +1797,8 @@ atapi_out: zip_buf_alloc(dev, 8); - max_len = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + /* IMPORTANT: What's returned is the last LBA block. */ + max_len = dev->drv->medium_size - 1; memset(dev->buffer, 0, 8); dev->buffer[0] = (max_len >> 24) & 0xff; dev->buffer[1] = (max_len >> 16) & 0xff; @@ -2063,12 +1887,13 @@ atapi_out: break; default: - zip_illegal_opcode(dev); + zip_illegal_opcode(dev, cdb[0]); break; } #if 0 - zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, dev->tf->request_length); + zip_log(dev->log, "Phase: %02X, request length: %i\n", + dev->tf->phase, dev->tf->request_length); #endif if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) @@ -2088,29 +1913,16 @@ zip_command_stop(scsi_common_t *sc) static uint8_t zip_phase_data_out(scsi_common_t *sc) { - zip_t *dev = (zip_t *) sc; - + zip_t *dev = (zip_t *) sc; + int len = 0; + uint8_t error = 0; + uint32_t last_to_write; + uint32_t i; uint16_t block_desc_len; uint16_t pos; uint16_t param_list_len; - - uint8_t error = 0; - uint8_t page; - uint8_t page_len; - - uint32_t i = 0; - - uint8_t hdr_len; - uint8_t val; - uint8_t old_val; - uint8_t ch; - - uint32_t last_to_write = 0; - uint32_t c; - uint32_t h; - uint32_t s; - - int len = 0; + uint8_t hdr_len; + uint8_t val; switch (dev->current_cdb[0]) { case GPCMD_VERIFY_6: @@ -2123,7 +1935,7 @@ zip_phase_data_out(scsi_common_t *sc) case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: if (dev->requested_blocks > 0) - zip_blocks(dev, &len, 1, 1); + zip_blocks(dev, &len, 1); break; case GPCMD_WRITE_SAME_10: if (!dev->current_cdb[7] && !dev->current_cdb[8]) { @@ -2139,22 +1951,23 @@ zip_phase_data_out(scsi_common_t *sc) dev->buffer[3] = i & 0xff; } else if (dev->current_cdb[1] & 4) { /* CHS are 96, 1, 2048 (ZIP 100) and 239, 1, 2048 (ZIP 250) */ - s = (i % 2048); - h = ((i - s) / 2048) % 1; - c = ((i - s) / 2048) / 1; - dev->buffer[0] = (c >> 16) & 0xff; - dev->buffer[1] = (c >> 8) & 0xff; - dev->buffer[2] = c & 0xff; - dev->buffer[3] = h & 0xff; - dev->buffer[4] = (s >> 24) & 0xff; - dev->buffer[5] = (s >> 16) & 0xff; - dev->buffer[6] = (s >> 8) & 0xff; - dev->buffer[7] = s & 0xff; + const uint32_t s = (i % 2048); + const uint32_t h = ((i - s) / 2048) % 1; + const uint32_t c = ((i - s) / 2048) / 1; + dev->buffer[0] = (c >> 16) & 0xff; + dev->buffer[1] = (c >> 8) & 0xff; + dev->buffer[2] = c & 0xff; + dev->buffer[3] = h & 0xff; + dev->buffer[4] = (s >> 24) & 0xff; + dev->buffer[5] = (s >> 16) & 0xff; + dev->buffer[6] = (s >> 8) & 0xff; + dev->buffer[7] = s & 0xff; } - if (fseek(dev->drv->fp, dev->drv->base + (i << 9), SEEK_SET) == -1) - fatal("zip_phase_data_out(): Error seeking\n"); + if (fseek(dev->drv->fp, dev->drv->base + (i << 9), + SEEK_SET) == -1) + log_fatal(dev->log, "zip_phase_data_out(): Error seeking\n"); if (fwrite(dev->buffer, 1, 512, dev->drv->fp) != 512) - fatal("zip_phase_data_out(): Error writing data\n"); + log_fatal(dev->log, "zip_phase_data_out(): Error writing data\n"); } fflush(dev->drv->fp); @@ -2188,27 +2001,27 @@ zip_phase_data_out(scsi_common_t *sc) while (1) { if (pos >= param_list_len) { - zip_log("ZIP %i: Buffer has only block descriptor\n", dev->id); + zip_log(dev->log, "Buffer has only block descriptor\n"); break; } - page = dev->buffer[pos] & 0x3F; - page_len = dev->buffer[pos + 1]; + const uint8_t page = dev->buffer[pos] & 0x3f; + const uint8_t page_len = dev->buffer[pos + 1]; pos += 2; if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; - val = dev->buffer[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else - error |= 1; + else for (i = 0; i < page_len; i++) { + const uint8_t old_val = dev->ms_pages_saved.pages[page][i + 2]; + const uint8_t ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = dev->buffer[pos + i]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + error |= 1; + zip_invalid_field_pl(dev, val); } } } @@ -2228,7 +2041,6 @@ zip_phase_data_out(scsi_common_t *sc) if (error) { zip_buf_free(dev); - zip_invalid_field_pl(dev); return 0; } break; @@ -2250,7 +2062,7 @@ zip_global_init(void) } static int -zip_get_max(int ide_has_dma, int type) +zip_get_max(const ide_t *ide, const int ide_has_dma, const int type) { int ret; @@ -2274,7 +2086,7 @@ zip_get_max(int ide_has_dma, int type) } static int -zip_get_timings(int ide_has_dma, int type) +zip_get_timings(const ide_t *ide, const int ide_has_dma, const int type) { int ret; @@ -2297,39 +2109,43 @@ zip_get_timings(int ide_has_dma, int type) } static void -zip_100_identify(ide_t *ide) +zip_100_identify(const ide_t *ide) { ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ } static void -zip_250_identify(ide_t *ide, int ide_has_dma) +zip_250_identify(const ide_t *ide, const int ide_has_dma) { - ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + /* Firmware */ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); + /* Model */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); if (ide_has_dma) { - ide->buffer[80] = 0x70; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6*/ - ide->buffer[81] = 0x19; /*Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a*/ + ide->buffer[80] = 0x70; /* Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-6 */ + /* Maximum ATA revision supported : ATA/ATAPI-6 T13 1410D revision 3a */ + ide->buffer[81] = 0x19; } } static void -zip_identify(ide_t *ide, int ide_has_dma) +zip_identify(const ide_t *ide, const int ide_has_dma) { - const zip_t *zip; + const zip_t *zip = (zip_t *) ide->sc; - zip = (zip_t *) ide->sc; - - /* ATAPI device, direct-access device, removable media, interrupt DRQ: + /* + ATAPI device, direct-access device, removable media, interrupt DRQ: Using (2 << 5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive - as a LS-120. */ + as a LS-120. + */ ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5); - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + /* Interpret zero byte count limit as maximum length */ + ide->buffer[126] = 0xfffe; if (zip_drives[zip->id].is_250) zip_250_identify(ide, ide_has_dma); @@ -2338,30 +2154,32 @@ zip_identify(ide_t *ide, int ide_has_dma) } static void -zip_drive_reset(int c) +zip_drive_reset(const int c) { - zip_t *dev; - scsi_device_t *sd; - ide_t *id; - uint8_t scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = zip_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = zip_drives[c].scsi_device_id & 0x0f; - if (!zip_drives[c].priv) { - zip_drives[c].priv = (zip_t *) malloc(sizeof(zip_t)); - memset(zip_drives[c].priv, 0, sizeof(zip_t)); + if (zip_drives[c].priv == NULL) { + zip_drives[c].priv = (zip_t *) calloc(1, sizeof(zip_t)); + zip_t *dev = (zip_t *) zip_drives[c].priv; + + char n[1024] = { 0 }; + + sprintf(n, "ZIP %i", c + 1); + dev->log = log_open(n); } - dev = (zip_t *) zip_drives[c].priv; + zip_t *dev = (zip_t *) zip_drives[c].priv; dev->id = c; dev->cur_lun = SCSI_LUN_USE_CDB; if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { - if (!dev->tf) + if (dev->tf == NULL) dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); /* SCSI ZIP, attach to the SCSI bus. */ - sd = &scsi_devices[scsi_bus][scsi_id]; + scsi_device_t *sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = zip_command; @@ -2372,7 +2190,7 @@ zip_drive_reset(int c) sd->type = SCSI_REMOVABLE_DISK; } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { /* ATAPI CD-ROM, attach to the IDE bus. */ - id = ide_get_drive(zip_drives[c].ide_channel); + ide_t *id = ide_get_drive(zip_drives[c].ide_channel); /* If the IDE channel is initialized, we attach to it, otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ @@ -2399,17 +2217,12 @@ zip_drive_reset(int c) void zip_hard_reset(void) { - zip_t *dev; - uint8_t scsi_id; - uint8_t scsi_bus; - for (uint8_t c = 0; c < ZIP_NUM; c++) { if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI) || (zip_drives[c].bus_type == ZIP_BUS_SCSI)) { - zip_log("ZIP hard_reset drive=%d\n", c); if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { - scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; - scsi_id = zip_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = zip_drives[c].scsi_device_id & 0x0f; /* Make sure to ignore any SCSI ZIP drive that has an out of range SCSI bus. */ if (scsi_bus >= SCSI_BUS_MAX) @@ -2426,7 +2239,9 @@ zip_hard_reset(void) zip_drive_reset(c); - dev = (zip_t *) zip_drives[c].priv; + zip_t *dev = (zip_t *) zip_drives[c].priv; + + zip_log(dev->log, "ZIP hard_reset drive=%d\n", c); if (dev->tf == NULL) continue; @@ -2437,14 +2252,16 @@ zip_hard_reset(void) zip_init(dev); if (strlen(zip_drives[c].image_path)) - zip_load(dev, zip_drives[c].image_path); + zip_load(dev, zip_drives[c].image_path, 0); zip_mode_sense_load(dev); if (zip_drives[c].bus_type == ZIP_BUS_SCSI) - zip_log("SCSI ZIP drive %i attached to SCSI ID %i\n", c, zip_drives[c].scsi_device_id); + zip_log(dev->log, "SCSI ZIP drive %i attached to SCSI ID %i\n", + c, zip_drives[c].scsi_device_id); else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) - zip_log("ATAPI ZIP drive %i attached to IDE channel %i\n", c, zip_drives[c].ide_channel); + zip_log(dev->log, "ATAPI ZIP drive %i attached to IDE channel %i\n", + c, zip_drives[c].ide_channel); } } } @@ -2452,19 +2269,15 @@ zip_hard_reset(void) void zip_close(void) { - zip_t *dev; - uint8_t scsi_bus; - uint8_t scsi_id; - for (uint8_t c = 0; c < ZIP_NUM; c++) { if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { - scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; - scsi_id = zip_drives[c].scsi_device_id & 0x0f; + const uint8_t scsi_bus = (zip_drives[c].scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = zip_drives[c].scsi_device_id & 0x0f; memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); } - dev = (zip_t *) zip_drives[c].priv; + zip_t *dev = (zip_t *) zip_drives[c].priv; if (dev) { zip_disk_unload(dev); @@ -2472,6 +2285,13 @@ zip_close(void) if (dev->tf) free(dev->tf); + if (dev->log != NULL) { + zip_log(dev->log, "Log closed\n"); + + log_close(dev->log); + dev->log = NULL; + } + free(dev); zip_drives[c].priv = NULL; } diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index f28bba517..b9dbccb4b 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -15,26 +15,34 @@ #ifndef EMU_CDROM_H #define EMU_CDROM_H +#ifndef EMU_VERSION_H +#include <86box/version.h> +#endif + #define CDROM_NUM 8 #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PAUSED 2 -#define CD_STATUS_PLAYING 3 -#define CD_STATUS_STOPPED 4 -#define CD_STATUS_PLAYING_COMPLETED 5 +#define CD_STATUS_DVD 2 +#define CD_STATUS_PAUSED 4 +#define CD_STATUS_PLAYING 5 +#define CD_STATUS_STOPPED 6 +#define CD_STATUS_PLAYING_COMPLETED 7 +#define CD_STATUS_HAS_AUDIO 4 +#define CD_STATUS_MASK 7 /* Medium changed flag. */ #define CD_STATUS_TRANSITION 0x40 #define CD_STATUS_MEDIUM_CHANGED 0x80 -#define CD_TRACK_UNK_DATA 0x10 +#define CD_TRACK_UNK_DATA 0x04 +#define CD_TRACK_NORMAL 0x00 #define CD_TRACK_AUDIO 0x08 +#define CD_TRACK_CDI 0x10 +#define CD_TRACK_XA 0x20 +#define CD_TRACK_MODE_MASK 0x30 #define CD_TRACK_MODE2 0x04 - -#define CD_READ_DATA 0 -#define CD_READ_AUDIO 1 -#define CD_READ_RAW 2 +#define CD_TRACK_MODE2_MASK 0x07 #define CD_TOC_NORMAL 0 #define CD_TOC_SESSION 1 @@ -48,7 +56,34 @@ /* This is so that if/when this is changed to something else, changing this one define will be enough. */ -#define CDROM_EMPTY !dev->host_drive +#define CDROM_EMPTY !dev->host_drive + +#define DVD_LAYER_0_SECTORS 0x00210558ULL + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 + +#define FRAMES_TO_MSF(f, M, S, F) \ + { \ + uint64_t value = f; \ + *(F) = (value % CD_FPS) & 0xff; \ + value /= CD_FPS; \ + *(S) = (value % 60) & 0xff; \ + value /= 60; \ + *(M) = value & 0xff; \ + } +#define MSF_TO_FRAMES(M, S, F) ((M) *60 * CD_FPS + (S) *CD_FPS + (F)) + +typedef struct SMSF { + uint16_t min; + uint8_t sec; + uint8_t fr; +} TMSF; #ifdef __cplusplus extern "C" { @@ -62,161 +97,126 @@ enum { CDROM_BUS_USB = 8 }; -enum -{ - CDROM_TYPE_86BOX_100, - CDROM_TYPE_ASUS_CDS500_141, - CDROM_TYPE_ASUS_CDS520_132, - CDROM_TYPE_AZT_CDA46802I_115, - CDROM_TYPE_BTC_BCD36XH_U10, - CDROM_TYPE_GOLDSTAR_CRD_8160B_314, - CDROM_TYPE_HITACHI_CDR_8130_0020, - CDROM_TYPE_HITACHI_GD7500_A1, - CDROM_TYPE_HLDTST_GCR8526B_101, - CDROM_TYPE_HLDTST_GSA4160_A302, - CDROM_TYPE_KENWOOD_UCR_421_208E, - CDROM_TYPE_LG_CRN8245B_130, - CDROM_TYPE_LG_CRD8322B_106, - CDROM_TYPE_LTN48125S_1S07, - CDROM_TYPE_LTN526D_YSR5, - CDROM_TYPE_MATSHITA_583_107, - CDROM_TYPE_MATSHITA_585_Z18P, - CDROM_TYPE_MATSHITA_587_7S13, - CDROM_TYPE_MATSHITA_588_LS15, - CDROM_TYPE_MATSHITA_571_10e, - CDROM_TYPE_MATSHITA_572_10j, - CDROM_TYPE_MITSUMI_FX4820T_D02A, - CDROM_TYPE_NEC_260_100, - CDROM_TYPE_NEC_260_101, - CDROM_TYPE_NEC_273_420, - CDROM_TYPE_NEC_280_105, - CDROM_TYPE_NEC_280_308, - CDROM_TYPE_NEC_CDR_1900A_100, - CDROM_TYPE_PHILIPS_PCA403CD_U31P, - CDROM_TYPE_SONY_CDU76_10i, - CDROM_TYPE_SONY_CDU311_30h, - CDROM_TYPE_SONY_CDU5225_NYS4, - CDROM_TYPE_TEAC_CD516E_10G, - CDROM_TYPE_TEAC_CD524EA_30D, - CDROM_TYPE_TEAC_CD532E_20A, - CDROM_TYPE_TOSHIBA_5302TA_0305, - CDROM_TYPE_TOSHIBA_5702B_TA70, - CDROM_TYPE_TOSHIBA_6202B_1512, - CDROM_TYPE_TOSHIBA_6402B_1008, - CDROM_TYPE_TOSHIBA_6702B_1007, - CDROM_TYPE_TOSHIBA_M1802_1051, - CDROM_TYPE_CHINON_CDS431_H42, - CDROM_TYPE_CHINON_CDX435_M62, - CDROM_TYPE_DEC_RRD45_0436, - CDROM_TYPE_MATSHITA_501_10b, - CDROM_TYPE_NEC_25_10a, - CDROM_TYPE_NEC_38_103, - CDROM_TYPE_NEC_75_103, - CDROM_TYPE_NEC_77_106, - CDROM_TYPE_NEC_211_100, - CDROM_TYPE_NEC_464_105, - CDROM_TYPE_ShinaKen_DM3x1S_104, - CDROM_TYPE_SONY_CDU541_10i, - CDROM_TYPE_SONY_CDU561_18k, - CDROM_TYPE_SONY_CDU76S_100, - CDROM_TYPE_PHILIPS_CDD2600_107, - CDROM_TYPE_PIONEER_DRM604X_2403, - CDROM_TYPE_PLEXTOR_PX32TS_103, - CDROM_TYPE_TEAC_CD50_100, - CDROM_TYPE_TEAC_R55S_10R, - CDROM_TYPE_TEXEL_DM3024_100, - CDROM_TYPE_TEXEL_DM3028_106, - CDROM_TYPE_TOSHIBA_XM_3433, - CDROM_TYPE_TOSHIBA_XM3201B_3232, - CDROM_TYPE_TOSHIBA_XM3301TA_0272, - CDROM_TYPE_TOSHIBA_XM5701TA_3136, - CDROM_TYPE_TOSHIBA_SDM1401_1008, - CDROM_TYPES_NUM -}; - -#define KNOWN_CDROM_DRIVE_TYPES CDROM_TYPES_NUM #define BUS_TYPE_IDE CDROM_BUS_ATAPI #define BUS_TYPE_SCSI CDROM_BUS_SCSI #define BUS_TYPE_BOTH -2 #define BUS_TYPE_NONE -1 +#define CDV EMU_VERSION_EX + static const struct { - const char vendor[9]; - const char model[17]; - const char revision[5]; - const char *name; - const char *internal_name; - const int bus_type; + const char vendor[9]; + const char model[17]; + const char revision[5]; + const char * internal_name; + const int bus_type; + /* SCSI standard for SCSI (or both) devices, early for IDE. */ + const int scsi_std; + const int speed; + const int inquiry_len; + const int caddy; + const int transfer_max[4]; } cdrom_drive_types[] = { - { "86BOX", "CD-ROM", "1.00", "86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_BOTH }, - { "ASUS", "CD-S500/A", "1.41", "ASUS CD-S500/A 1.41", "ASUS_CD-S500A_1.41", BUS_TYPE_IDE }, - { "ASUS", "CD-S520/A4", "1.32", "ASUS CD-S520/A4 1.32", "ASUS_CD-S520A4_1.32", BUS_TYPE_IDE }, - { "AZT", "CDA46802I", "1.15", "AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE }, - { "BTC", "CD-ROM BCD36XH", "U1.0", "BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE }, - { "GOLDSTAR", "CRD-8160B", "3.14", "GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE }, - { "HITACHI", "CDR-8130", "0020", "HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE }, - { "HITACHI", "GD-7500", "A1 ", "HITACHI GD-7500 A1", "HITACHI_GD-7500_A1", BUS_TYPE_IDE }, - { "HL-DT-ST", "CD-ROM GCR-8526B", "1.01", "HL-DT-ST CD-ROM GCR-8526B 1.01", "HL-DT-ST_CD-ROM_GCR-8526B_1.01", BUS_TYPE_IDE }, - { "HL-DT-ST", "DVDRAM GSA-4160", "A302", "HL-DT-ST DVDRAM GSA-4160 A302", "HL-DT-ST_DVDRAM_GSA-4160_A302", BUS_TYPE_IDE }, - { "KENWOOD", "CD-ROM UCR-421", "208E", "KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE }, - { "LG", "CD-ROM CRN-8245B", "1.30", "LG CD-ROM CRN-8245B 1.30", "LG_CD-ROM_CRN-8245B_1.30", BUS_TYPE_IDE }, - { "LG", "CD-ROM CRD-8322B", "1.06", "LG CD-ROM CRD-8322B 1.06", "LG_CD-ROM_CRD-8322B_1.06", BUS_TYPE_IDE }, - { "LITE-ON", "LTN48125S", "1S07", "LITE-ON LTN48125S 1S07", "LITE-ON_LTN48125S_1S07", BUS_TYPE_IDE }, - { "LITE-ON", "LTN526D", "YSR5", "LITE-ON LTN526D YSR5", "LITE-ON_LTN526D_YSR5", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-583", "1.07", "MATSHITA CD-ROM CR-583 1.07", "MATSHITA_CD-ROM_CR-583_1.07", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-585", "Z18P", "MATSHITA CD-ROM CR-585 Z18P", "MATSHITA_CD-ROM_CR-585_Z18P", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-587", "7S13", "MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE }, - { "MATSHITA", "CD-ROM CR-588", "LS15", "MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE }, - { "MATSHITA", "CR-571", "1.0e", "MATSHITA CR-571 1.0e", "MATSHITA_CR-571_1.0e", BUS_TYPE_IDE }, - { "MATSHITA", "CR-572", "1.0j", "MATSHITA CR-572 1.0j", "MATSHITA_CR-572_1.0j", BUS_TYPE_IDE }, - { "MITSUMI", "CRMC-FX4820T", "D02A", "MITSUMI CRMC-FX4820T D02A", "MITSUMI_CRMC-FX4820T_D02A", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:260", "1.00", "NEC CD-ROM DRIVE:260 1.00", "NEC_CD-ROM_DRIVE260_1.00", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:260", "1.01", "NEC CD-ROM DRIVE:260 1.01", "NEC_CD-ROM_DRIVE260_1.01", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:273", "4.20", "NEC CD-ROM DRIVE:273 4.20", "NEC_CD-ROM_DRIVE273_4.20", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:280", "1.05", "NEC CD-ROM DRIVE:280 1.05", "NEC_CD-ROM_DRIVE280_1.05", BUS_TYPE_IDE }, - { "NEC", "CD-ROM DRIVE:280", "3.08", "NEC CD-ROM DRIVE:280 3.08", "NEC_CD-ROM_DRIVE280_3.08", BUS_TYPE_IDE }, - { "NEC", "CDR-1900A", "1.00", "NEC CDR-1900A 1.00", "NEC_CDR-1900A_1.00", BUS_TYPE_IDE }, - { "PHILIPS", "CD-ROM PCA403CD", "U31P", "PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU76", "1.0i", "SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, - { "SONY", "CD-ROM CDU5225", "NYS4", "SONY CD-ROM CDU5225 NYS4", "SONY_CD-ROM_CDU5225_NYS4", BUS_TYPE_IDE }, - { "TEAC", "CD-516E", "1.0G", "TEAC CD-516E 1.0G", "TEAC_CD-516E_1.0G", BUS_TYPE_IDE }, - { "TEAC", "CD-524EA", "3.0D", "TEAC CD-524EA 3.0D", "TEAC_CD-524EA_3.0D", BUS_TYPE_IDE }, - { "TEAC", "CD-532E", "2.0A", "TEAC CD-532E 2.0A", "TEAC_CD_532E_2.0A", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6202B", "1512", "TOSHIBA CD-ROM XM-6202B 1512", "TOSHIBA_CD-ROM_XM-6202B_1512", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6402B", "1008", "TOSHIBA CD-ROM XM-6402B 1008", "TOSHIBA_CD-ROM_XM-6402B_1008", BUS_TYPE_IDE }, - { "TOSHIBA", "CD-ROM XM-6702B", "1007", "TOSHIBA CD-ROM XM-6702B 1007", "TOSHIBA_CD-ROM_XM-6702B_1007", BUS_TYPE_IDE }, - { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "TOSHIBA DVD-ROM SD-M1802 1051", "TOSHIBA_DVD-ROM_SD-M1802_1051", BUS_TYPE_IDE }, - { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, - { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, - { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, - { "MATSHITA", "CD-ROM CR-501", "1.0b", "[SCSI-1] MATSHITA CD-ROM CR-501 1.0b", "MATSHITA_CD-ROM_CR-501_1.0b", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:25", "1.0a", "[SCSI-1] NEC CD-ROM DRIVE:25 1.0a", "NEC_CD-ROM_DRIVE25_1.0a", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:38", "1.00", "[SCSI-2] NEC CD-ROM DRIVE:38 1.00", "NEC_CD-ROM_DRIVE38_1.00", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:75", "1.03", "[SCSI-1] NEC CD-ROM DRIVE:75 1.03", "NEC_CD-ROM_DRIVE75_1.03", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:77", "1.06", "[SCSI-1] NEC CD-ROM DRIVE:77 1.06", "NEC_CD-ROM_DRIVE77_1.06", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:211", "1.00", "[SCSI-2] NEC CD-ROM DRIVE:211 1.00", "NEC_CD-ROM_DRIVE211_1.00", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:464", "1.05", "[SCSI-2] NEC CD-ROM DRIVE:464 1.05", "NEC_CD-ROM_DRIVE464_1.05", BUS_TYPE_SCSI }, - { "ShinaKen", "CD-ROM DM-3x1S", "1.04", "[SCSI-1] ShinaKen CD-ROM DM-3x1S 1.04", "ShinaKen_CD-ROM_DM-3x1S_1.04", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-541", "1.0i", "[SCSI-1] SONY CD-ROM CDU-541 1.0i", "SONY_CD-ROM_CDU-541_1.0i", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-561", "1.8k", "[SCSI-2] SONY CD-ROM CDU-561 1.8k", "SONY_CD-ROM_CDU-561_1.8k", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-76S", "1.00", "[SCSI-2] SONY CD-ROM CDU-76S 1.00", "SONY_CD-ROM_CDU-76S_1.00", BUS_TYPE_SCSI }, - { "PHILIPS", "CDD2600", "1.07", "[SCSI-2] PHILIPS CDD2600 1.07", "PHILIPS_CDD2600_1.07", BUS_TYPE_SCSI }, - { "PIONEER", "CD-ROM DRM-604X", "2403", "[SCSI-2] PIONEER CD-ROM DRM-604X 2403", "PIONEER_CD-ROM_DRM-604X_2403", BUS_TYPE_SCSI }, - { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "[SCSI-2] PLEXTOR CD-ROM PX-32TS 1.03", "PLEXTOR_CD-ROM_PX-32TS_1.03", BUS_TYPE_SCSI }, - { "TEAC", "CD 50", "1.00", "[SCSI-2] TEAC CD 50 1.00", "TEAC_CD_50_1.00", BUS_TYPE_SCSI }, - { "TEAC", "CD-ROM R55S", "1.0R", "[SCSI-2] TEAC CD-ROM R55S 1.0R", "TEAC_CD-ROM_R55S_1.0R", BUS_TYPE_SCSI }, - { "TEXEL", "CD-ROM DM-3024", "1.00", "[SCSI-1] TEXEL CD-ROM DM-3024 1.00", "TEXEL_CD-ROM_DM-3024_1.00", BUS_TYPE_SCSI }, - { "TEXEL", "CD-ROM DM-3028", "1.06", "[SCSI-2] TEXEL CD-ROM DM-3028 1.06", "TEXEL_CD-ROM_DM-3028_1.06", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "[SCSI-2] TOSHIBA CD-ROM DRIVE:XM 3433", "TOSHIBA_CD-ROM_DRIVEXM_3433", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-3201B", "3232", "[SCSI-1] TOSHIBA CD-ROM XM-3201B 3232", "TOSHIBA_CD-ROM_XM-3201B_3232", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "[SCSI-2] TOSHIBA CD-ROM XM-3301TA 0272", "TOSHIBA_CD-ROM_XM-3301TA_0272", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "[SCSI-2] TOSHIBA CD-ROM XM-5701TA 3136", "TOSHIBA_CD-ROM_XM-5701TA_3136", BUS_TYPE_SCSI }, - { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "[SCSI-2] TOSHIBA DVD-ROM SD-M1401 1008", "TOSHIBA_DVD-ROM_SD-M1401_1008", BUS_TYPE_SCSI }, - { "", "", "", "", "", BUS_TYPE_NONE }, + { EMU_NAME, "86B_CD", CDV, "86cd", BUS_TYPE_BOTH, 2, -1, 36, 0, { 4, 2, 2, 5 } }, + /* SCSI-1 / early ATAPI generic - second on purpose so the later variant is the default. */ + { EMU_NAME, "86B_CD", "1.00", "86cd100", BUS_TYPE_BOTH, 1, -1, 36, 1, { 0, -1, -1, -1 } }, + /* No difference from 86BOX CD-ROM, other than name - but enough people have requested such a name to warrant it. */ + { EMU_NAME, "86B_DVD", "4.30", "86dvd", BUS_TYPE_BOTH, 2, -1, 36, 0, { 4, 2, 2, 5 } }, + { "ASUS", "CD-S500/A", "1.41", "asus_500", BUS_TYPE_IDE, 0, 50, 36, 0, { 4, 2, 2, 2 } }, + { "ASUS", "CD-S520/A4", "1.32", "asus_520", BUS_TYPE_IDE, 0, 52, 36, 0, { 4, 2, 2, 2 } }, + { "AZT", "CDA46802I", "1.15", "azt_cda", BUS_TYPE_IDE, 0, 4, 36, 0, { 3, 0, 0, 0 } }, + { "BTC", "CD-ROM BCD36XH", "U1.0", "btc_36xh", BUS_TYPE_IDE, 0, 36, 36, 0, { 4, 2, 2, -1 } }, + { "GOLDSTAR", "CRD-8160B", "3.14", "goldstar", BUS_TYPE_IDE, 0, 16, 36, 0, { 4, 2, 2, -1 } }, + /* TODO: Find an IDENTIFY and/or INQUIRY dump. */ + { "GOLDSTAR", "GCD-R560B", "1.00", "goldstar", BUS_TYPE_IDE, 0, 6, 36, 0, { 4, 2, 2, -1 } }, + { "HITACHI", "CDR-8130", "0020", "hitachi_r8130", BUS_TYPE_IDE, 0, 16, 36, 0, { 4, 2, 2, -1 } }, + { "HITACHI", "GD-7500", "A1 ", "hitachi_7500", BUS_TYPE_IDE, 0, 40, 36, 0, { 4, 2, 2, 2 } }, /* DVD. */ + { "HL-DT-ST", "CD-ROM GCR-8526B", "1.01", "hldtst_8526b", BUS_TYPE_IDE, 0, 52, 36, 0, { 4, 2, 2, 2 } }, + { "HL-DT-ST", "DVDRAM GSA-4160", "A302", "hldtst_4160", BUS_TYPE_IDE, 0, 40, 36, 0, { 4, 2, 2, 2 } }, + { "KENWOOD", "CD-ROM UCR-421", "208E", "kenwood_421", BUS_TYPE_IDE, 0, 72, 36, 0, { 4, 2, 2, 4 } }, + /* + This is a laptop/notebook drive, as is also evident from the name: + CRN = Notebook, CRD = Desktop. + */ + { "LG", "CD-ROM CRN-8245B", "1.30", "lg_8245b", BUS_TYPE_IDE, 0, 24, 36, 0, { 4, 2, 2, -1 } }, + { "LG", "CD-ROM CRD-8322B", "1.06", "lg_8322b", BUS_TYPE_IDE, 0, 32, 36, 0, { 4, 2, 2, -1 } }, + /* Nothing on Google, deduced 48x from the name. */ + { "LITE-ON", "LTN48125S", "1S07", "liteon_48125s", BUS_TYPE_IDE, 0, 48, 36, 0, { 4, 2, 2, 2 } }, + /* Confirmed to be 52x, was the basis for deducing the other one's speed. */ + { "LITE-ON", "LTN526D", "YSR5", "liteon_526d", BUS_TYPE_IDE, 0, 52, 36, 0, { 4, 2, 2, 2 } }, + { "MATSHITA", "CD-ROM CR-583", "1.07", "matshita_583", BUS_TYPE_IDE, 0, 8, 36, 0, { 4, 2, 2, -1 } }, + { "MATSHITA", "CD-ROM CR-585", "Z18P", "matshita_585", BUS_TYPE_IDE, 0, 24, 36, 0, { 4, 2, 2, -1 } }, + { "MATSHITA", "CD-ROM CR-587", "7S13", "matshita_587", BUS_TYPE_IDE, 0, 24, 36, 0, { 4, 2, 2, -1 } }, + { "MATSHITA", "CD-ROM CR-588", "LS15", "matshita_588", BUS_TYPE_IDE, 0, 32, 36, 0, { 4, 2, 2, -1 } }, + { "MATSHITA", "CR-571", "1.0e", "matshita_571", BUS_TYPE_IDE, 0, 2, 36, 0, { 0, -1, -1, -1 } }, + { "MATSHITA", "CR-572", "1.0j", "matshita_572", BUS_TYPE_IDE, 0, 4, 36, 0, { 0, -1, -1, -1 } }, + { "MITSUMI", "CRMC-FX4820T", "D02A", "mitsumi_4820t", BUS_TYPE_IDE, 0, 48, 36, 0, { 4, 2, 2, 2 } }, + /* TODO: Find an IDENTIFY and/or INQUIRY dump. */ + { "MITSUMI", "CRMC-FX810T4", "????", "mitsumi_810t4", BUS_TYPE_IDE, 0, 8, 36, 0, { 4, 2, 2, -1 } }, + { "NEC", "CD-ROM DRIVE:260", "1.00", "nec_260_early", BUS_TYPE_IDE, 1, 2, 36, 1, { 0, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:260", "1.01", "nec_260", BUS_TYPE_IDE, 1, 4, 36, 1, { 0, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:273", "4.20", "nec_273", BUS_TYPE_IDE, 0, 4, 36, 0, { 0, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:280", "1.05", "nec_280_early", BUS_TYPE_IDE, 0, 6, 36, 1, { 4, 2, 2, -1 } }, + { "NEC", "CD-ROM DRIVE:280", "3.08", "nec_280", BUS_TYPE_IDE, 0, 8, 36, 1, { 4, 2, 2, -1 } }, + { "NEC", "CDR-1300A", "1.05", "nec_1300a", BUS_TYPE_IDE, 0, 6, 36, 0, { 4, 2, 2, -1 } }, + { "NEC", "CDR-1900A", "1.00", "nec_1900a", BUS_TYPE_IDE, 0, 32, 36, 0, { 4, 2, 2, -1 } }, + { "PHILIPS", "CD-ROM PCA403CD", "U31P", "philips_403", BUS_TYPE_IDE, 0, 40, 36, 0, { 4, 2, 2, -1 } }, + { "SONY", "CD-ROM CDU76", "1.0i", "sony_76", BUS_TYPE_IDE, 0, 4, 36, 0, { 2, -1, -1, -1 } }, + { "SONY", "CD-ROM CDU311", "3.0h", "sony_311", BUS_TYPE_IDE, 0, 8, 36, 0, { 3, 2, 1, -1 } }, + { "SONY", "CD-ROM CDU5225", "NYS4", "sony_5225", BUS_TYPE_IDE, 0, 52, 36, 0, { 4, 2, 2, 4 } }, + { "TEAC", "CD-516E", "1.0G", "teac_516e", BUS_TYPE_IDE, 0, 16, 36, 0, { 3, 2, 2, -1 } }, + { "TEAC", "CD-524EA", "3.0D", "teac_524ea", BUS_TYPE_IDE, 0, 24, 36, 0, { 3, 2, 2, -1 } }, + { "TEAC", "CD-532E", "2.0A", "teac_532e", BUS_TYPE_IDE, 0, 32, 36, 0, { 3, 2, 2, -1 } }, + { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "toshiba_5302ta", BUS_TYPE_IDE, 0, 4, 96, 0, { 0, -1, -1, -1 } }, + { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "toshiba_5702b", BUS_TYPE_IDE, 0, 12, 96, 0, { 3, 2, 1, -1 } }, + { "TOSHIBA", "CD-ROM XM-6202B", "1512", "toshiba_6202b", BUS_TYPE_IDE, 0, 32, 96, 0, { 4, 2, 2, -1 } }, + { "TOSHIBA", "CD-ROM XM-6402B", "1008", "toshiba_6402b", BUS_TYPE_IDE, 0, 32, 96, 0, { 4, 2, 2, 2 } }, + { "TOSHIBA", "CD-ROM XM-6702B", "1007", "toshiba_6720b", BUS_TYPE_IDE, 0, 48, 96, 0, { 4, 2, 2, 2 } }, + { "TOSHIBA", "DVD-ROM SD-M1802", "1051", "toshiba_m1802", BUS_TYPE_IDE, 0, 48, 96, 0, { 4, 2, 2, 2 } }, + { "CHINON", "CD-ROM CDS-431", "H42 ", "chinon_431", BUS_TYPE_SCSI, 1, 1, 36, 1, { -1, -1, -1, -1 } }, + { "CHINON", "CD-ROM CDX-435", "M62 ", "chinon_435", BUS_TYPE_SCSI, 1, 2, 36, 1, { -1, -1, -1, -1 } }, + { "DEC", "RRD45 (C) DEC", "0436", "dec_45", BUS_TYPE_SCSI, 1, 4, 36, 0, { -1, -1, -1, -1 } }, + { "MATSHITA", "CD-ROM CR-501", "1.0b", "matshita_501", BUS_TYPE_SCSI, 1, 1, 36, 1, { -1, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:25", "1.0a", "nec_25", BUS_TYPE_SCSI, 1, 2, 36, 0, { -1, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:38", "1.00", "nec_38", BUS_TYPE_SCSI, 2, 1, 36, 0, { -1, -1, -1, -1 } }, + /* The speed of the following two is guesswork based on the CDR-74. */ + { "NEC", "CD-ROM DRIVE:75", "1.03", "nec_75", BUS_TYPE_SCSI, 1, 1, 36, 1, { -1, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:77", "1.06", "nec_77", BUS_TYPE_SCSI, 1, 1, 36, 1, { -1, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:211", "1.00", "nec_211", BUS_TYPE_SCSI, 2, 3, 36, 0, { -1, -1, -1, -1 } }, + /* The speed of the following two is guesswork based on the CDR-400. */ + { "NEC", "CD-ROM DRIVE:464", "1.05", "nec_464", BUS_TYPE_SCSI, 2, 3, 36, 0, { -1, -1, -1, -1 } }, + /* The speed of the following two is guesswork based on the name. */ + { "ShinaKen", "CD-ROM DM-3x1S", "1.04", "shinaken_3x1s", BUS_TYPE_SCSI, 1, 3, 36, 0, { -1, -1, -1, -1 } }, + { "SONY", "CD-ROM CDU-541", "1.0i", "sony_541", BUS_TYPE_SCSI, 1, 1, 36, 1, { -1, -1, -1, -1 } }, + { "SONY", "CD-ROM CDU-561", "1.8k", "sony_561", BUS_TYPE_SCSI, 2, 2, 36, 1, { -1, -1, -1, -1 } }, + { "SONY", "CD-ROM CDU-76S", "1.00", "sony_76s", BUS_TYPE_SCSI, 2, 4, 36, 0, { -1, -1, -1, -1 } }, + { "PHILIPS", "CDD2600", "1.07", "philips_2600", BUS_TYPE_SCSI, 2, 6, 36, 0, { -1, -1, -1, -1 } }, + /* NOTE: The real thing is a CD changer drive! */ + { "PIONEER", "CD-ROM DRM-604X", "2403", "pioneer_604x", BUS_TYPE_SCSI, 2, 4, 47, 0, { -1, -1, -1, -1 } }, + { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "plextor_32ts", BUS_TYPE_SCSI, 2, 32, 36, 0, { -1, -1, -1, -1 } }, + /* The speed of the following two is guesswork based on the R55S. */ + { "TEAC", "CD 50", "1.00", "teac_50", BUS_TYPE_SCSI, 2, 4, 36, 1, { -1, -1, -1, -1 } }, + { "TEAC", "CD-ROM R55S", "1.0R", "teac_55s", BUS_TYPE_SCSI, 2, 4, 36, 0, { -1, -1, -1, -1 } }, + /* Texel is Plextor according to Plextor's own EU website. */ + { "TEXEL", "CD-ROM DM-3024", "1.00", "texel_3024", BUS_TYPE_SCSI, 2, 2, 36, 1, { -1, -1, -1, -1 } }, + /* + Unusual 2.23x according to Google, I'm rounding it upwards to 3x. + Assumed caddy based on the DM-3024. + */ + { "TEXEL", "CD-ROM DM-3028", "1.06", "texel_3028", BUS_TYPE_SCSI, 2, 3, 36, 1 }, /* Caddy. */ + /* + The characteristics are a complete guesswork because I can't find + this one on Google. + + Also, INQUIRY length is always 96 on these Toshiba drives. + */ + { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "toshiba_xm", BUS_TYPE_SCSI, 2, 2, 96, 0 }, /* Tray. */ + { "TOSHIBA", "CD-ROM XM-3201B", "3232", "toshiba_3201b", BUS_TYPE_SCSI, 1, 1, 96, 1 }, /* Caddy. */ + { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "toshiba_3301ta", BUS_TYPE_SCSI, 2, 2, 96, 0 }, /* Tray. */ + { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "toshiba_5701a", BUS_TYPE_SCSI, 2, 12, 96, 0 }, /* Tray. */ + { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "toshiba_m1401", BUS_TYPE_SCSI, 2, 40, 96, 0 }, /* Tray. */ + { "", "", "", "", BUS_TYPE_NONE, 0, -1, 0, 0 } }; /* To shut up the GCC compilers. */ @@ -258,133 +258,177 @@ typedef struct raw_track_info_t { /* Define the various CD-ROM drive operations (ops). */ typedef struct cdrom_ops_t { - void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); - void (*get_raw_track_info)(struct cdrom *dev, int *num, raw_track_info_t *rti); - void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); - int (*is_track_pre)(struct cdrom *dev, uint32_t lba); - int (*sector_size)(struct cdrom *dev, uint32_t lba); - int (*read_sector)(struct cdrom *dev, uint8_t *b, uint32_t lba); - int (*track_type)(struct cdrom *dev, uint32_t lba); - int (*ext_medium_changed)(struct cdrom *dev); - void (*exit)(struct cdrom *dev); + int (*get_track_info)(const void *local, const uint32_t track, + const int end, track_info_t *ti); + void (*get_raw_track_info)(const void *local, int *num, + uint8_t *rti); + int (*is_track_pre)(const void *local, const uint32_t sector); + int (*read_sector)(const void *local, uint8_t *buffer, + const uint32_t sector); + uint8_t (*get_track_type)(const void *local, const uint32_t sector); + uint32_t (*get_last_block)(const void *local); + int (*read_dvd_structure)(const void *local, const uint8_t layer, + const uint8_t format, uint8_t *buffer, + uint32_t *info); + int (*is_dvd)(const void *local); + int (*has_audio)(const void *local); + int (*ext_medium_changed)(void *local); + void (*close)(void *local); } cdrom_ops_t; typedef struct cdrom { - uint8_t id; + uint8_t id; union { - uint8_t res; - uint8_t res0; /* Reserved for other ID's. */ - uint8_t res1; - uint8_t ide_channel; - uint8_t scsi_device_id; + uint8_t res; + uint8_t res0; /* Reserved for other ID's. */ + uint8_t res1; + uint8_t ide_channel; + uint8_t scsi_device_id; }; - uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - uint8_t cd_status; /* Struct variable reserved for - media status. */ - uint8_t speed; - uint8_t cur_speed; + uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + uint8_t cd_status; /* Struct variable reserved for + media status. */ + uint8_t speed; + uint8_t cur_speed; - void *priv; + void * priv; - char image_path[1024]; - char prev_image_path[1024]; + char image_path[1024]; + char prev_image_path[1024]; - char *image_history[CD_IMAGE_HISTORY]; + char * image_history[CD_IMAGE_HISTORY]; - uint32_t sound_on; - uint32_t cdrom_capacity; - uint32_t seek_pos; - uint32_t seek_diff; - uint32_t cd_end; - uint32_t type; - uint32_t sector_size; + uint32_t sound_on; + uint32_t cdrom_capacity; + uint32_t seek_pos; + uint32_t seek_diff; + uint32_t cd_end; + uint32_t type; + uint32_t sector_size; - int cd_buflen; - int audio_op; - int audio_muted_soft; - int sony_msf; + int cd_buflen; + int audio_op; + int audio_muted_soft; + int sony_msf; + int real_speed; + int is_early; + int is_nec; + + uint32_t inv_field; const cdrom_ops_t *ops; - void *local; + void * local; + void * log; - void (*insert)(void *priv); - void (*close)(void *priv); - uint32_t (*get_volume)(void *p, int channel); - uint32_t (*get_channel)(void *p, int channel); + void (*insert)(void *priv); + void (*close)(void *priv); + uint32_t (*get_volume)(void *p, int channel); + uint32_t (*get_channel)(void *p, int channel); - int16_t cd_buffer[BUF_SIZE]; + int16_t cd_buffer[BUF_SIZE]; - uint8_t subch_buffer[96]; + uint8_t subch_buffer[96]; } cdrom_t; extern cdrom_t cdrom[CDROM_NUM]; -extern char *cdrom_getname(int type); +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) -extern char *cdrom_get_internal_name(int type); -extern int cdrom_get_from_internal_name(char *s); -extern void cdrom_set_type(int model, int type); -extern int cdrom_get_type(int model); +static __inline int +bin2bcd(int x) +{ + return (x % 10) | ((x / 10) << 4); +} -extern int cdrom_lba_to_msf_accurate(int lba); -extern double cdrom_seek_time(cdrom_t *dev); -extern void cdrom_stop(cdrom_t *dev); -extern int cdrom_is_pre(cdrom_t *dev, uint32_t lba); -extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len); -extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf); -extern uint8_t cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit); -extern uint8_t cdrom_audio_track_search_pioneer(cdrom_t *dev, uint32_t pos, uint8_t playbit); -extern uint8_t cdrom_audio_play_pioneer(cdrom_t *dev, uint32_t pos); -extern uint8_t cdrom_audio_play_toshiba(cdrom_t *dev, uint32_t pos, int type); -extern void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume); -extern uint8_t cdrom_audio_scan(cdrom_t *dev, uint32_t pos, int type); -extern uint8_t cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b); -extern uint8_t cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf); -extern uint8_t cdrom_get_current_status(cdrom_t *dev); -extern void cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf); -extern void cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf); -extern void cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b); -extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); -extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, - unsigned char start_track, int msf, int max_len); -extern int cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int max_len); -extern void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf); -extern void cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode); -extern uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len); -extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, - int cdrom_sector_type, int cdrom_sector_flags, int *len, uint8_t vendor_type); -extern uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type); +static __inline int +bcd2bin(int x) +{ + return (x >> 4) * 10 + (x & 0x0f); +} -extern void cdrom_seek(cdrom_t *dev, uint32_t pos, uint8_t vendor_type); +extern char *cdrom_get_vendor(const int type); +extern void cdrom_get_model(const int type, char *name, const int id); +extern char *cdrom_get_revision(const int type); +extern int cdrom_get_scsi_std(const int type); +extern int cdrom_is_early(const int type); +extern int cdrom_is_generic(const int type); +extern int cdrom_has_date(const int type); +extern int cdrom_is_sony(const int type); +extern int cdrom_is_caddy(const int type); +extern int cdrom_get_speed(const int type); +extern int cdrom_get_inquiry_len(const int type); +extern int cdrom_has_dma(const int type); +extern int cdrom_get_transfer_max(const int type, const int mode); +extern int cdrom_get_type_count(void); +extern void cdrom_get_identify_model(const int type, char *name, const int id); +extern void cdrom_get_name(const int type, char *name); +extern char *cdrom_get_internal_name(const int type); +extern int cdrom_get_from_internal_name(const char *s); +/* TODO: Configuration migration, remove when no longer needed. */ +extern int cdrom_get_from_name(const char *s); +extern void cdrom_set_type(const int model, const int type); +extern int cdrom_get_type(const int model); -extern void cdrom_close_handler(uint8_t id); -extern void cdrom_insert(uint8_t id); -extern void cdrom_exit(uint8_t id); -extern int cdrom_is_empty(uint8_t id); -extern void cdrom_eject(uint8_t id); -extern void cdrom_reload(uint8_t id); +extern int cdrom_lba_to_msf_accurate(const int lba); +extern double cdrom_seek_time(const cdrom_t *dev); +extern void cdrom_stop(cdrom_t *dev); +extern void cdrom_seek(cdrom_t *dev, const uint32_t pos, const uint8_t vendor_type); +extern int cdrom_is_pre(const cdrom_t *dev, const uint32_t lba); -extern int cdrom_image_open(cdrom_t *dev, const char *fn); -extern void cdrom_image_close(cdrom_t *dev); +extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len); +extern uint8_t cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ismsf); +extern uint8_t cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, + const int type, const uint8_t playbit); +extern uint8_t cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t playbit); +extern uint8_t cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos); +extern uint8_t cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type); +extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type); +extern void cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume); -extern int cdrom_ioctl_open(cdrom_t *dev, const char *drv); -extern void cdrom_ioctl_close(cdrom_t *dev); +extern uint8_t cdrom_get_current_status(const cdrom_t *dev); +extern void cdrom_get_current_subchannel(const cdrom_t *dev, uint8_t *b, const int msf); +extern void cdrom_get_current_subchannel_sony(const cdrom_t *dev, uint8_t *b, const int msf); +extern uint8_t cdrom_get_audio_status_pioneer(const cdrom_t *dev, uint8_t *b); +extern uint8_t cdrom_get_audio_status_sony(const cdrom_t *dev, uint8_t *b, const int msf); +extern void cdrom_get_current_subcodeq(const cdrom_t *dev, uint8_t *b); +extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); +extern int cdrom_read_toc(const cdrom_t *dev, uint8_t *b, const int type, + const uint8_t start_track, const int msf, const int max_len); +extern int cdrom_read_toc_sony(const cdrom_t *dev, uint8_t *b, const uint8_t start_track, + const int msf, const int max_len); +#ifdef USE_CDROM_MITSUMI +extern void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf); +extern void cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode); +extern uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len); +#endif +extern uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, + const uint8_t track, const int type); +extern int cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, + int cdrom_sector_type, const int cdrom_sector_flags, + int *len, const uint8_t vendor_type); +extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_t layer, const uint8_t format, + uint8_t *buffer, uint32_t *info); +extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); +extern int cdrom_read_track_information(const cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); +extern int cdrom_ext_medium_changed(const cdrom_t *dev); +extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); -extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, - int number_of_blocks); - -extern int find_cdrom_for_scsi_id(uint8_t scsi_id); - -extern void cdrom_close(void); -extern void cdrom_global_init(void); -extern void cdrom_global_reset(void); -extern void cdrom_hard_reset(void); -extern void scsi_cdrom_drive_reset(int c); +extern void cdrom_global_init(void); +extern void cdrom_hard_reset(void); +extern void cdrom_close(void); +extern void cdrom_insert(const uint8_t id); +extern void cdrom_exit(const uint8_t id); +extern int cdrom_is_empty(const uint8_t id); +extern void cdrom_eject(const uint8_t id); +extern void cdrom_reload(const uint8_t id); #ifdef __cplusplus } diff --git a/src/include/86box/cdrom_image.h b/src/include/86box/cdrom_image.h index c848af50d..84dd66f37 100644 --- a/src/include/86box/cdrom_image.h +++ b/src/include/86box/cdrom_image.h @@ -6,35 +6,33 @@ * * This file is part of the 86Box distribution. * - * CD-ROM image file handling module header, translated to C - * from cdrom_dosbox.h. + * CD-ROM image file handling module header. * - * Authors: RichardG, - * Miran Grca, + * Authors: Miran Grca, + * RichardG, + * Cacodemon345 * - * Copyright 2016-2022 RichardG. - * Copyright 2016-2022 Miran Grca. + * Copyright 2016-2025 Miran Grca. + * Copyright 2016-2025 RichardG. + * Copyright 2024-2025 Cacodemon345. */ #ifndef CDROM_IMAGE_H #define CDROM_IMAGE_H -/* this header file lists the functions provided by - various platform specific cdrom-ioctl files */ +/* Track file struct. */ +typedef struct track_file_t { + int (*read)(void *priv, uint8_t *buffer, uint64_t seek, size_t count); + uint64_t (*get_length)(void *priv); + void (*close)(void *priv); -#ifdef __cplusplus -extern "C" { -#endif + char fn[260]; + FILE *fp; + void *priv; + void *log; -extern int image_open(uint8_t id, wchar_t *fn); -extern void image_reset(uint8_t id); + int motorola; +} track_file_t; -extern void image_close(uint8_t id); - -void update_status_bar_icon_state(int tag, int state); -extern void cdrom_set_null_handler(uint8_t id); - -#ifdef __cplusplus -} -#endif +extern void * image_open(cdrom_t *dev, const char *path); #endif /*CDROM_IMAGE_H*/ diff --git a/src/include/86box/cdrom_image_backend.h b/src/include/86box/cdrom_image_backend.h deleted file mode 100644 index 64ce88d83..000000000 --- a/src/include/86box/cdrom_image_backend.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * CD-ROM image file handling module header. - * - * Authors: Miran Grca, - * RichardG, - * Cacodemon345 - * - * Copyright 2016-2025 Miran Grca. - * Copyright 2016-2025 Miran Grca. - * Copyright 2024-2025 Cacodemon345. - */ -#ifndef CDROM_IMAGE_BACKEND_H -#define CDROM_IMAGE_BACKEND_H - -#define RAW_SECTOR_SIZE 2352 -#define COOKED_SECTOR_SIZE 2048 - -#define DATA_TRACK 0x14 -#define AUDIO_TRACK 0x10 - -#define CD_FPS 75 -#define FRAMES_TO_MSF(f, M, S, F) \ - { \ - uint64_t value = f; \ - *(F) = (value % CD_FPS) & 0xff; \ - value /= CD_FPS; \ - *(S) = (value % 60) & 0xff; \ - value /= 60; \ - *(M) = value & 0xff; \ - } -#define MSF_TO_FRAMES(M, S, F) ((M) *60 * CD_FPS + (S) *CD_FPS + (F)) - -typedef struct SMSF { - uint16_t min; - uint8_t sec; - uint8_t fr; -} TMSF; - -/* Track file struct. */ -typedef struct track_file_t { - int (*read)(void *priv, uint8_t *buffer, uint64_t seek, size_t count); - uint64_t (*get_length)(void *priv); - void (*close)(void *priv); - - char fn[260]; - FILE *fp; - void *priv; - - int motorola; -} track_file_t; - -#define INDEX_SPECIAL -2 /* Track A0h onwards. */ -#define INDEX_NONE -1 /* Empty block. */ -#define INDEX_ZERO 0 /* Block not in the file, return all 0x00's. */ -#define INDEX_NORMAL 1 /* Block in the file. */ - -typedef struct track_index_t { - /* Is the current block in the file? If not, return all 0x00's. -1 means not yet loaded. */ - int32_t type; - /* The amount of bytes to skip at the beginning of each sector. */ - int32_t skip; - /* Starting and ending sector LBA - negative in order to accomodate LBA -150 to -1 - to read the pregap of track 1. */ - uint64_t start; - uint64_t length; - uint64_t file_start; - uint64_t file_length; - track_file_t *file; -} track_index_t; - -typedef struct track_t { - uint8_t session; - uint8_t attr; - uint8_t tno; - uint8_t point; - uint8_t extra[4]; - uint8_t mode; - uint8_t form; - uint8_t pad; - uint8_t skip; - uint32_t sector_size; - track_index_t idx[3]; -} track_t; - -typedef struct cd_img_t { - int32_t tracks_num; - track_t *tracks; -} cd_img_t; - -/* Binary file functions. */ -extern void cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer); -extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, - uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); -extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); -extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); -extern int cdi_get_sector_size(cd_img_t *cdi, uint32_t sector); -extern int cdi_is_audio(cd_img_t *cdi, uint32_t sector); -extern int cdi_is_pre(cd_img_t *cdi, uint32_t sector); -extern int cdi_is_mode2(cd_img_t *cdi, uint32_t sector); -extern int cdi_get_mode2_form(cd_img_t *cdi, uint32_t sector); -extern int cdi_load_iso(cd_img_t *cdi, const char *filename); -extern int cdi_load_cue(cd_img_t *cdi, const char *cuefile); -extern void cdi_close(cd_img_t *cdi); -extern int cdi_set_device(cd_img_t *cdi, const char *path); - -/* Virtual ISO functions. */ -extern int viso_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count); -extern uint64_t viso_get_length(void *priv); -extern void viso_close(void *priv); -extern track_file_t *viso_init(const char *dirname, int *error); - -#endif /*CDROM_IMAGE_BACKEND_H*/ diff --git a/src/include/86box/cdrom_image_viso.h b/src/include/86box/cdrom_image_viso.h new file mode 100644 index 000000000..19f0e1de0 --- /dev/null +++ b/src/include/86box/cdrom_image_viso.h @@ -0,0 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CD-ROM image file handling module header. + * + * Authors: RichardG, + * Miran Grca, + * + * Copyright 2016-2025 RichardG. + * Copyright 2016-2025 Miran Grca. + */ +#ifndef CDROM_IMAGE_VISO_H +#define CDROM_IMAGE_VISO_H + +/* Virtual ISO functions. */ +extern int viso_read(void *priv, uint8_t *buffer, uint64_t seek, size_t count); +extern uint64_t viso_get_length(void *priv); +extern void viso_close(void *priv); +extern track_file_t *viso_init(const uint8_t id, const char *dirname, int *error); + +#endif /*CDROM_IMAGE_VISO_H*/ diff --git a/src/include/86box/cdrom_interface.h b/src/include/86box/cdrom_interface.h index 081f758f6..ba4d0581b 100644 --- a/src/include/86box/cdrom_interface.h +++ b/src/include/86box/cdrom_interface.h @@ -21,11 +21,13 @@ extern int cdrom_interface_current; extern void cdrom_interface_reset(void); -extern const char *cdrom_interface_get_internal_name(int cdinterface); -extern int cdrom_interface_get_from_internal_name(char *s); -extern int cdrom_interface_has_config(int cdinterface); -extern const device_t *cdrom_interface_get_device(int cdinterface); -extern int cdrom_interface_get_flags(int cdinterface); -extern int cdrom_interface_available(int cdinterface); +const char *cdrom_interface_get_internal_name(const int cdinterface); +extern int cdrom_interface_get_from_internal_name(const char *s); +#ifdef EMU_DEVICE_H +extern const device_t *cdrom_interface_get_device(const int cdinterface); +#endif +extern int cdrom_interface_has_config(const int cdinterface); +extern int cdrom_interface_get_flags(const int cdinterface); +extern int cdrom_interface_available(const int cdinterface); #endif /*EMU_CDROM_INTERFACE_H*/ diff --git a/src/include/86box/cdrom_ioctl.h b/src/include/86box/cdrom_ioctl.h deleted file mode 100644 index 5fc157615..000000000 --- a/src/include/86box/cdrom_ioctl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * CD-ROM image file handling module header, translated to C - * from cdrom_dosbox.h. - * - * Authors: RichardG, - * Miran Grca, - * - * Copyright 2016-2022 RichardG. - * Copyright 2016-2022 Miran Grca. - */ -#ifndef CDROM_IOCTL_H -#define CDROM_IOCTL_H - -/* this header file lists the functions provided by - various platform specific cdrom-ioctl files */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif /*CDROM_IOCTL_H*/ diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index a3b667e2e..110804244 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -22,11 +22,6 @@ #define MFM_NUM 2 /* 2 drives per controller supported */ #define ESDI_NUM 2 /* 2 drives per controller supported */ #define XTA_NUM 2 /* 2 drives per controller supported */ -#define IDE_NUM 10 /* 8 drives per AT IDE + 2 for XT IDE */ -#define ATAPI_NUM 8 /* 8 drives per AT IDE */ -#define SCSI_NUM 16 /* theoretically the controller can have at \ - * least 7 devices, with each device being \ - * able to support 8 units, but hey... */ /* Controller types. */ #define HDC_NONE 0 diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 9094f7f00..0280cf301 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -19,6 +19,9 @@ #ifndef EMU_IDE_H #define EMU_IDE_H +#define IDE_NUM 10 /* 8 drives per AT IDE + 2 for XT IDE */ +#define ATAPI_NUM 10 /* 8 drives per AT IDE + 2 for XT IDE */ + #define IDE_BUS_MAX 4 #define IDE_CHAN_MAX 2 @@ -121,11 +124,11 @@ typedef struct ide_s { double pending_delay; #ifdef SCSI_DEVICE_H - int (*get_max)(int ide_has_dma, int type); - int (*get_timings)(int ide_has_dma, int type); - void (*identify)(struct ide_s *ide, int ide_has_dma); - void (*stop)(scsi_common_t *sc); - void (*packet_command)(scsi_common_t *sc, uint8_t *cdb); + int (*get_max)(const struct ide_s *ide, const int ide_has_dma, const int type); + int (*get_timings)(const struct ide_s *ide, const int ide_has_dma, const int type); + void (*identify)(const struct ide_s *ide, const int ide_has_dma); + void (*stop)(const scsi_common_t *sc); + void (*packet_command)(scsi_common_t *sc, const uint8_t *cdb); void (*device_reset)(scsi_common_t *sc); uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); @@ -142,10 +145,8 @@ typedef struct ide_s { #endif } ide_t; -#ifdef EMU_HDC_H extern ide_t *ide_drives[IDE_NUM]; #endif -#endif /* Type: 0 = PIO, diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index a4bded58f..b80c21c13 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -148,7 +148,7 @@ typedef struct hard_disk_t { uint8_t ide_channel; uint8_t scsi_id; }; - uint8_t bus; + uint8_t bus_type; uint8_t bus_mode; /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ uint8_t wp; /* Disk has been mounted READ-ONLY */ diff --git a/src/include/86box/log.h b/src/include/86box/log.h index 7f0b96d60..a37bdec4f 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -6,24 +6,20 @@ * * This file is part of the 86Box distribution. * - * Main include file for the application. - * - * + * New logging system handler header. * * Authors: Miran Grca, * Fred N. van Kempen, - * Connor Hyde + * Connor Hyde, * - * Copyright 2021 Miran Grca. - * Copyright 2021 Fred N. van Kempen. + * Copyright 2021-25 Miran Grca. + * Copyright 2021-25 Fred N. van Kempen. * Copyright 2025 Connor Hyde. */ #ifndef EMU_LOG_H #define EMU_LOG_H -#ifndef RELEASE_BUILD - # ifdef __cplusplus extern "C" { # endif @@ -35,20 +31,17 @@ extern "C" { /* Function prototypes. */ extern void log_set_suppr_seen(void *priv, int suppr_seen); extern void log_set_dev_name(void *priv, char *dev_name); -# ifdef HAVE_STDARG_H +#ifndef RELEASE_BUILD extern void log_out(void *priv, const char *fmt, va_list); extern void log_out_cyclic(void* priv, const char *fmt, va_list); +#endif /*RELEASE_BUILD*/ extern void log_fatal(void *priv, const char *fmt, ...); -# endif -extern void *log_open(char *dev_name); +extern void *log_open(const char *dev_name); +extern void *log_open_cyclic(const char *dev_name); extern void log_close(void *priv); # ifdef __cplusplus } # endif -#else -# define log_fatal(priv, fmt, ...) fatal(fmt, ...) -#endif /*RELEASE_BUILD*/ - #endif /*EMU_LOG_H*/ diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 4ab567aca..0b494952c 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -9,13 +9,13 @@ * Implementation of a generic Magneto-Optical Disk drive * commands, for both ATAPI and SCSI usage. * - * - * * Authors: Natalia Portillo - * Fred N. van Kempen, * Miran Grca, + * Fred N. van Kempen, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Natalia Portillo. + * Copyright 2020-2025 Miran Grca. + * Copyright 2020-2025 Fred N. van Kempen */ #ifndef EMU_MO_H @@ -91,88 +91,87 @@ enum { }; typedef struct mo_drive_t { - uint8_t id; + uint8_t id; union { - uint8_t res; - uint8_t res0; /* Reserved for other ID's. */ - uint8_t res1; - uint8_t ide_channel; - uint8_t scsi_device_id; + uint8_t res; + /* Reserved for other ID's. */ + uint8_t res0; + uint8_t res1; + uint8_t ide_channel; + uint8_t scsi_device_id; }; - uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - uint8_t read_only; /* Struct variable reserved for - media status. */ - uint8_t pad; - uint8_t pad0; + uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + uint8_t read_only; /* Struct variable reserved for + media status. */ + uint8_t pad; + uint8_t pad0; - FILE *fp; - void *priv; + FILE * fp; + void * priv; - char image_path[1024]; - char prev_image_path[1024]; + char image_path[1024]; + char prev_image_path[1024]; - char *image_history[MO_IMAGE_HISTORY]; + char * image_history[MO_IMAGE_HISTORY]; - uint32_t type; - uint32_t medium_size; - uint32_t base; - uint16_t sector_size; + uint32_t type; + uint32_t medium_size; + uint32_t base; + uint16_t sector_size; } mo_drive_t; typedef struct mo_t { mode_sense_pages_t ms_pages_saved; - mo_drive_t *drv; + mo_drive_t * drv; #ifdef EMU_IDE_H - ide_tf_t * tf; + ide_tf_t * tf; #else - void * tf; + void * tf; #endif - uint8_t *buffer; - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - uint8_t sense[256]; + void * log; - uint8_t id; - uint8_t cur_lun; - uint8_t pad0; - uint8_t pad1; + uint8_t * buffer; + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + uint8_t sense[256]; - uint16_t max_transfer_len; - uint16_t pad2; + uint8_t id; + uint8_t cur_lun; + uint8_t pad0; + uint8_t pad1; - int requested_blocks; - int packet_status; - int total_length; - int do_page_save; - int unit_attention; - int request_pos; - int old_len; - int pad3; + uint16_t max_transfer_len; + uint16_t pad2; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t packet_len; + int requested_blocks; + int packet_status; + int total_length; + int do_page_save; + int unit_attention; + int request_pos; + int old_len; + int transition; - double callback; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t packet_len; - uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } mo_t; -extern mo_t *mo[MO_NUM]; -extern mo_drive_t mo_drives[MO_NUM]; -#if 0 -extern uint8_t atapi_mo_drives[8]; -extern uint8_t scsi_mo_drives[16]; -#endif +extern mo_drive_t mo_drives[MO_NUM]; #define mo_sense_error dev->sense[0] #define mo_sense_key dev->sense[2] +#define mo_info *(uint32_t *) &(dev->sense[3]) #define mo_asc dev->sense[12] #define mo_ascq dev->sense[13] @@ -180,15 +179,16 @@ extern uint8_t scsi_mo_drives[16]; extern "C" { #endif -extern void mo_disk_close(mo_t *dev); -extern void mo_disk_reload(mo_t *dev); +extern void mo_disk_close(const mo_t *dev); +extern void mo_disk_reload(const mo_t *dev); extern void mo_insert(mo_t *dev); extern void mo_global_init(void); extern void mo_hard_reset(void); extern void mo_reset(scsi_common_t *sc); -extern int mo_load(mo_t *dev, char *fn); +extern int mo_is_empty(const uint8_t id); +extern void mo_load(const mo_t *dev, const char *fn, const int skip_insert); extern void mo_close(void); #ifdef __cplusplus diff --git a/src/include/86box/plat_cdrom.h b/src/include/86box/plat_cdrom.h deleted file mode 100644 index 643013a08..000000000 --- a/src/include/86box/plat_cdrom.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Definitions for platform specific serial to host passthrough. - * - * - * Authors: Andreas J. Reichel , - * Jasmine Iwanek - * - * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. - */ - -#ifndef PLAT_CDROM_H -#define PLAT_CDROM_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define RAW_SECTOR_SIZE 2352 -#define COOKED_SECTOR_SIZE 2048 - -#define DATA_TRACK 0x14 -#define AUDIO_TRACK 0x10 - -#define CD_FPS 75 -#define FRAMES_TO_MSF(f, M, S, F) \ - { \ - uint64_t value = f; \ - *(F) = (value % CD_FPS) & 0xff; \ - value /= CD_FPS; \ - *(S) = (value % 60) & 0xff; \ - value /= 60; \ - *(M) = value & 0xff; \ - } -#define MSF_TO_FRAMES(M, S, F) ((M) *60 * CD_FPS + (S) *CD_FPS + (F)) - -typedef struct SMSF { - uint16_t min; - uint8_t sec; - uint8_t fr; -} TMSF; - -extern void plat_cdrom_get_raw_track_info(void *local, int *num, raw_track_info_t *rti); -extern int plat_cdrom_is_track_audio(void *local, uint32_t sector); -extern int plat_cdrom_is_track_pre(void *local, uint32_t sector); -extern uint32_t plat_cdrom_get_last_block(void *local); -extern int plat_cdrom_get_audio_track_info(void *local, int end, int track, int *track_num, TMSF *start, - uint8_t *attr); -extern int plat_cdrom_get_audio_sub(void *local, uint32_t sector, uint8_t *attr, uint8_t *track, - uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); -extern int plat_cdrom_get_sector_size(void *local, uint32_t sector); -extern int plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector); -extern void plat_cdrom_eject(void *local); -extern void plat_cdrom_close(void *local); -extern int plat_cdrom_set_drive(void *local, const char *drv); -extern int plat_cdrom_ext_medium_changed(void *local); -extern uint32_t plat_cdrom_get_track_start(void *local, uint32_t sector, uint8_t *attr, uint8_t *track); -extern int plat_cdrom_get_local_size(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/include/86box/plat_cdrom_ioctl.h b/src/include/86box/plat_cdrom_ioctl.h new file mode 100644 index 000000000..471222134 --- /dev/null +++ b/src/include/86box/plat_cdrom_ioctl.h @@ -0,0 +1,34 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for platform specific serial to host passthrough. + * + * + * Authors: Andreas J. Reichel , + * Jasmine Iwanek + * + * Copyright 2021 Andreas J. Reichel. + * Copyright 2021-2022 Jasmine Iwanek. + */ + +#ifndef PLAT_CDROM_IOCTL_H +#define PLAT_CDROM_IOCTL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void * ioctl_open(cdrom_t *dev, const char *drv); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/include/86box/scsi.h b/src/include/86box/scsi.h index 32ad1f912..84a4a608e 100644 --- a/src/include/86box/scsi.h +++ b/src/include/86box/scsi.h @@ -29,15 +29,21 @@ #define SCSI_ID_MAX 16 /* 16 on wide buses */ #define SCSI_LUN_MAX 8 /* always 8 */ -extern int scsi_card_current[SCSI_CARD_MAX]; +extern int scsi_card_current[SCSI_CARD_MAX]; -extern int scsi_card_available(int card); +extern void scsi_reset(void); +extern uint8_t scsi_get_bus(void); + +extern int scsi_card_available(int card); #ifdef EMU_DEVICE_H extern const device_t *scsi_card_getdevice(int card); #endif -extern int scsi_card_has_config(int card); -extern const char *scsi_card_get_internal_name(int card); -extern int scsi_card_get_from_internal_name(char *s); -extern void scsi_card_init(void); +extern int scsi_card_has_config(int card); +extern const char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_card_init(void); + +extern void scsi_bus_set_speed(uint8_t bus, double speed); +extern double scsi_bus_get_speed(uint8_t bus); #endif /*EMU_SCSI_H*/ diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index 684a9d589..bc2d4c8bd 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -26,47 +26,56 @@ typedef struct scsi_cdrom_t { /* Common block. */ mode_sense_pages_t ms_pages_saved; - cdrom_t * drv; + cdrom_t * drv; #ifdef EMU_IDE_H - ide_tf_t *tf; + ide_tf_t * tf; #else - void * tf; + void * tf; #endif - uint8_t *buffer; - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - uint8_t sense[256]; + void * log; - uint8_t id; - uint8_t cur_lun; - uint8_t early; - uint8_t pad1; + uint8_t * buffer; + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + uint8_t sense[256]; - uint16_t max_transfer_len; - uint16_t pad2; + uint8_t id; + uint8_t cur_lun; + uint8_t early; + uint8_t sector_type; - int requested_blocks; - int packet_status; - int total_length; - int do_page_save; - int unit_attention; - int request_pos; - int old_len; - int media_status; + uint16_t max_transfer_len; + uint16_t sector_flags; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t packet_len; + int requested_blocks; + int packet_status; + int total_length; + int do_page_save; + int unit_attention; + int request_pos; + int old_len; + int media_status; - double callback; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t packet_len; - uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + double callback; - int sony_vendor; + int is_sony; + int use_cdb_9; + + uint8_t ven_cmd_is_data[256]; - mode_sense_pages_t ms_pages_saved_sony; mode_sense_pages_t ms_drive_status_pages_saved; + + uint64_t ms_page_flags; + + mode_sense_pages_t ms_pages_default; + mode_sense_pages_t ms_pages_changeable; + + uint8_t (*ven_cmd)(void *sc, const uint8_t *cdb, int32_t *BufLen); } scsi_cdrom_t; #endif @@ -74,10 +83,12 @@ extern scsi_cdrom_t *scsi_cdrom[CDROM_NUM]; #define scsi_cdrom_sense_error dev->sense[0] #define scsi_cdrom_sense_key dev->sense[2] +#define scsi_cdrom_info *(uint32_t *) &(dev->sense[3]) #define scsi_cdrom_asc dev->sense[12] #define scsi_cdrom_ascq dev->sense[13] #define scsi_cdrom_drive cdrom_drives[id].host_drive extern void scsi_cdrom_reset(scsi_common_t *sc); +extern void scsi_cdrom_drive_reset(const int c); #endif /*EMU_SCSI_CDROM_H*/ diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 538a96fac..84abee066 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -21,6 +21,7 @@ #define SCSI_DEVICE_H /* Configuration. */ +#define SCSI_NUM (SCSI_BUS_MAX * SCSI_ID_MAX) #define SCSI_LUN_USE_CDB 0xff @@ -53,8 +54,8 @@ #define GPCMD_SEEK_6 0x0b #define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c #define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ -#define GPCMD_NO_OPERATION_TOSHIBA 0x0d /* Toshiba Vendor Unique command */ -#define GPCMD_NO_OPERATION_NEC 0x0d /* NEC Vendor Unique command */ +#define GPCMD_NO_OPERATION_TOSHIBA 0x0d /* Toshiba Vendor Unique command. */ +#define GPCMD_NO_OPERATION_NEC 0x0d /* NEC Vendor Unique command. */ #define GPCMD_INQUIRY 0x12 #define GPCMD_VERIFY_6 0x13 #define GPCMD_MODE_SELECT_6 0x15 @@ -66,7 +67,7 @@ #define GPCMD_PREVENT_REMOVAL 0x1e #define GPCMD_READ_FORMAT_CAPACITIES 0x23 #define GPCMD_READ_CDROM_CAPACITY 0x25 -#define GPCMD_UNKNOWN_CHINON 0x26 /*Chinon Vendor Unique command*/ +#define GPCMD_UNKNOWN_CHINON 0x26 /* Chinon Vendor Unique command. */ #define GPCMD_READ_10 0x28 #define GPCMD_READ_GENERATION 0x29 #define GPCMD_WRITE_10 0x2a @@ -233,16 +234,12 @@ #define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 #define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 -/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). - Not that it means anything */ -#define CDROM_SPEED 706 /* 0x2C2 */ - -#define BUFFER_SIZE (256 * 1024) - -#define RW_DELAY (TIMER_USEC * 500) - /* Some generally useful CD-ROM information */ +#ifdef CONSERVATIVE_MAXIMUM #define CD_MINS 90 /* max. minutes per CD */ +#else +#define CD_MINS 100 /* max. minutes per CD - yes, 100-minute CD's in fact existed */ +#endif #define CD_SECS 60 /* seconds per minute */ #define CD_FRAMES 75 /* frames per second */ #define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ @@ -276,6 +273,10 @@ /* Profile list from MMC-6 revision 1 table 91 */ #define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_REMOVABLE_DISK 0x0002 +#define MMC_PROFILE_MO 0x0003 +#define MMC_PROFILE_MO_WORM 0x0004 +#define MMC_PROFILE_AS_MO 0x0005 #define MMC_PROFILE_CD_ROM 0x0008 #define MMC_PROFILE_CD_R 0x0009 #define MMC_PROFILE_CD_RW 0x000A @@ -304,7 +305,6 @@ #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF -#define EARLY_ONLY 64 #define SCSI_ONLY 32 #define ATAPI_ONLY 16 #define IMPLEMENTED 8 @@ -312,8 +312,6 @@ #define CHECK_READY 2 #define ALLOW_UA 1 -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) - #define MSG_COMMAND_COMPLETE 0x00 #define BUS_DBP 0x01 @@ -371,7 +369,7 @@ #define MODE_SELECT_PHASE_PAGE 4 typedef struct mode_sense_pages_t { - uint8_t pages[0x40][0x40]; + uint8_t pages[0x40][0x40]; } mode_sense_pages_t; /* This is so we can access the common elements to all SCSI device structs @@ -379,89 +377,105 @@ typedef struct mode_sense_pages_t { typedef struct scsi_common_s { mode_sense_pages_t ms_pages_saved; - void * priv; + void * priv; #ifdef EMU_IDE_H - ide_tf_t *tf; + ide_tf_t * tf; #else - void * tf; + void * tf; #endif - uint8_t *temp_buffer; - uint8_t atapi_cdb[16]; /* This is atapi_cdb in ATAPI-supporting devices, - and pad in SCSI-only devices. */ - uint8_t current_cdb[16]; - uint8_t sense[256]; + void * log; - uint8_t id; - uint8_t cur_lun; - uint8_t pad0; - uint8_t pad1; + uint8_t * temp_buffer; + /* + This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. + */ + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + uint8_t sense[256]; - uint16_t max_transfer_len; - uint16_t pad2; + uint8_t id; + uint8_t cur_lun; + uint8_t pad0; + uint8_t pad1; - int requested_blocks; - int packet_status; - int total_length; - int do_page_save; - int unit_attention; - int request_pos; - int old_len; - int media_status; + uint16_t max_transfer_len; + uint16_t pad2; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t packet_len; + int requested_blocks; + int packet_status; + int total_length; + int do_page_save; + int unit_attention; + int request_pos; + int old_len; + int media_status; - double callback; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t packet_len; - uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } scsi_common_t; typedef struct scsi_device_t { - int32_t buffer_length; + int32_t buffer_length; - uint8_t status; - uint8_t phase; - uint16_t type; + uint8_t status; + uint8_t phase; - scsi_common_t *sc; + uint16_t type; - void (*command)(scsi_common_t *sc, uint8_t *cdb); - void (*request_sense)(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length); - void (*reset)(scsi_common_t *sc); - uint8_t (*phase_data_out)(scsi_common_t *sc); - void (*command_stop)(scsi_common_t *sc); + scsi_common_t * sc; + + void (*command)(scsi_common_t *sc, const uint8_t *cdb); + void (*request_sense)(scsi_common_t *sc, uint8_t *buffer, + uint8_t alloc_length); + void (*reset)(scsi_common_t *sc); + uint8_t (*phase_data_out)(scsi_common_t *sc); + void (*command_stop)(scsi_common_t *sc); } scsi_device_t; typedef struct scsi_bus_t { - int tx_mode; - int clear_req; - int wait_data; - int wait_complete; - int bus_out; - int bus_in; - int command_pos; - int command_issued; - int data_pos; - int msgout_pos; - int is_msgout; - int state; - int dma_on_pio_enabled; - uint8_t data; - uint8_t msglun; - uint8_t data_wait; - uint8_t command[16]; - uint8_t msgout[4]; - uint8_t target_id; - uint8_t bus_device; - uint32_t bus_phase; - double period; - double speed; - double divider; - double multi; - void *priv; - void (*timer)(void *priv, double period); + uint8_t data; + uint8_t msglun; + uint8_t data_wait; + uint8_t target_id; + uint8_t bus_device; + uint8_t pad; + uint8_t pad0; + uint8_t pad1; + + uint8_t command[16]; + uint8_t msgout[4]; + uint8_t pad2[4]; + + int tx_mode; + int clear_req; + int wait_data; + int wait_complete; + int bus_out; + int bus_in; + int command_pos; + int command_issued; + int data_pos; + int msgout_pos; + int is_msgout; + int state; + int dma_on_pio_enabled; + + uint32_t bus_phase; + + double period; + double speed; + double divider; + double multi; + + void *priv; + void (*timer)(void *priv, double period); } scsi_bus_t; /* These are based on the INQUIRY values. */ @@ -474,15 +488,8 @@ typedef struct scsi_bus_t { extern scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; #endif /* EMU_SCSI_H */ -extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); -extern int cdrom_LBAtoMSF_accurate(void); - -extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); -extern int mode_select_terminate(int force); -extern int mode_select_write(uint8_t val); - -extern uint8_t *scsi_device_sense(scsi_device_t *dev); extern double scsi_device_get_callback(scsi_device_t *dev); +extern uint8_t *scsi_device_sense(scsi_device_t *dev); extern void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length); extern void scsi_device_reset(scsi_device_t *dev); @@ -490,8 +497,8 @@ extern int scsi_device_present(scsi_device_t *dev); extern int scsi_device_valid(scsi_device_t *dev); extern int scsi_device_cdb_length(scsi_device_t *dev); extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); -extern void scsi_device_command_phase1(scsi_device_t *dev); extern void scsi_device_command_stop(scsi_device_t *dev); +extern void scsi_device_command_phase1(scsi_device_t *dev); extern void scsi_device_identify(scsi_device_t *dev, uint8_t lun); extern void scsi_device_close_all(void); extern void scsi_device_init(void); diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index 8c7e045fb..7099b836a 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -19,42 +19,44 @@ typedef struct scsi_disk_t { mode_sense_pages_t ms_pages_saved; - hard_disk_t *drv; + hard_disk_t * drv; #ifdef EMU_IDE_H - ide_tf_t * tf; + ide_tf_t * tf; #else - void * tf; + void * tf; #endif - uint8_t *temp_buffer; - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - uint8_t sense[256]; + void * log; - uint8_t id; - uint8_t cur_lun; - uint8_t pad0; - uint8_t pad1; + uint8_t * temp_buffer; + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + uint8_t sense[256]; - uint16_t max_transfer_len; - uint16_t pad2; + uint8_t id; + uint8_t cur_lun; + uint8_t pad0; + uint8_t pad1; - int requested_blocks; - int packet_status; - int total_length; - int do_page_save; - int unit_attention; - int request_pos; - int pad6; - int pad7; + uint16_t max_transfer_len; + uint16_t pad2; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t packet_len; + int requested_blocks; + int packet_status; + int total_length; + int do_page_save; + int unit_attention; + int request_pos; + int pad6; + int pad7; - double callback; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t packet_len; - uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } scsi_disk_t; extern scsi_disk_t *scsi_disk[HDD_NUM]; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index 739ba388b..59b78b64e 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -13,7 +13,7 @@ * * Authors: Miran Grca, * - * Copyright 2018-2019 Miran Grca. + * Copyright 2018-2025 Miran Grca. */ #ifndef EMU_ZIP_H @@ -39,76 +39,79 @@ enum { }; typedef struct zip_drive_t { - uint8_t id; + uint8_t id; union { - uint8_t res; - uint8_t res0; /* Reserved for other ID's. */ - uint8_t res1; - uint8_t ide_channel; - uint8_t scsi_device_id; + uint8_t res; + /* Reserved for other ID's. */ + uint8_t res0; + uint8_t res1; + uint8_t ide_channel; + uint8_t scsi_device_id; }; - uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - uint8_t read_only; /* Struct variable reserved for - media status. */ - uint8_t pad; - uint8_t pad0; + uint8_t bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + uint8_t read_only; /* Struct variable reserved for + media status. */ + uint8_t pad; + uint8_t pad0; - FILE *fp; - void *priv; + FILE * fp; + void * priv; - char image_path[1024]; - char prev_image_path[1024]; + char image_path[1024]; + char prev_image_path[1024]; - char *image_history[ZIP_IMAGE_HISTORY]; + char * image_history[ZIP_IMAGE_HISTORY]; - uint32_t is_250; - uint32_t medium_size; - uint32_t base; + uint32_t is_250; + uint32_t medium_size; + uint32_t base; } zip_drive_t; typedef struct zip_t { mode_sense_pages_t ms_pages_saved; - zip_drive_t *drv; + zip_drive_t * drv; #ifdef EMU_IDE_H - ide_tf_t * tf; + ide_tf_t * tf; #else - void * tf; + void * tf; #endif - uint8_t *buffer; - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - uint8_t sense[256]; + void * log; - uint8_t id; - uint8_t cur_lun; - uint8_t pad0; - uint8_t pad1; + uint8_t * buffer; + uint8_t atapi_cdb[16]; + uint8_t current_cdb[16]; + uint8_t sense[256]; - uint16_t max_transfer_len; - uint16_t pad2; + uint8_t id; + uint8_t cur_lun; + uint8_t pad0; + uint8_t pad1; - int requested_blocks; - int packet_status; - int total_length; - int do_page_save; - int unit_attention; - int request_pos; - int old_len; - int pad3; + uint16_t max_transfer_len; + uint16_t pad2; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t packet_len; + int requested_blocks; + int packet_status; + int total_length; + int do_page_save; + int unit_attention; + int request_pos; + int old_len; + int transition; - double callback; + uint32_t sector_pos; + uint32_t sector_len; + uint32_t packet_len; - uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } zip_t; extern zip_t *zip[ZIP_NUM]; @@ -118,6 +121,7 @@ extern uint8_t scsi_zip_drives[16]; #define zip_sense_error dev->sense[0] #define zip_sense_key dev->sense[2] +#define zip_info *(uint32_t *) &(dev->sense[3]) #define zip_asc dev->sense[12] #define zip_ascq dev->sense[13] @@ -125,15 +129,16 @@ extern uint8_t scsi_zip_drives[16]; extern "C" { #endif -extern void zip_disk_close(zip_t *dev); -extern void zip_disk_reload(zip_t *dev); +extern void zip_disk_close(const zip_t *dev); +extern void zip_disk_reload(const zip_t *dev); extern void zip_insert(zip_t *dev); extern void zip_global_init(void); extern void zip_hard_reset(void); extern void zip_reset(scsi_common_t *sc); -extern int zip_load(zip_t *dev, char *fn); +extern int zip_is_empty(const uint8_t id); +extern void zip_load(const zip_t *dev, const char *fn, const int skip_insert); extern void zip_close(void); #ifdef __cplusplus diff --git a/src/log.c b/src/log.c index a4d84e616..c8dddf62e 100644 --- a/src/log.c +++ b/src/log.c @@ -6,16 +6,14 @@ * * This file is part of the 86Box distribution. * - * The handler of the new logging system. - * - * + * New logging system handler. * * Authors: Miran Grca, * Fred N. van Kempen, - * Connor Hyde + * Connor Hyde, * - * Copyright 2021 Miran Grca. - * Copyright 2021 Fred N. van Kempen. + * Copyright 2021-25 Miran Grca. + * Copyright 2021-25 Fred N. van Kempen. * Copyright 2025 Connor Hyde. */ #include @@ -37,21 +35,44 @@ #include <86box/version.h> #include <86box/log.h> -#ifndef RELEASE_BUILD typedef struct log_t { - char buff[1024]; - char *dev_name; - int seen; - int suppr_seen; - char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; // Cyclical log buffer. This is 32kb, might calloc? - int32_t cyclic_last_line; - int32_t log_cycles; + char buff[1024]; + char dev_name[1024]; + int seen; + int suppr_seen; + /* Cyclical log buffer. */ + char **cyclic_buff; + int32_t cyclic_last_line; + int32_t log_cycles; } log_t; -extern FILE *stdlog; /* file to log output to */ -// Functions only used in this translation unit +/* File to log output to. */ +extern FILE *stdlog; +/* Functions only used in this translation unit. */ void log_ensure_stdlog_open(void); +void +log_set_dev_name(void *priv, char *dev_name) +{ + log_t *log = (log_t *) priv; + + memcpy(log->dev_name, dev_name, strlen(dev_name) + 1); +} + +static void +log_copy(log_t *log, char *dest, const char *src, size_t dest_size) +{ + memset(dest, 0x00, dest_size * sizeof(char)); + + if ((log != NULL) && strcmp(log->dev_name, "")) { + strcat(dest, log->dev_name); + strcat(dest, ": "); + } + + strcat(dest, src); +} + +#ifndef RELEASE_BUILD void log_ensure_stdlog_open(void) { @@ -73,31 +94,12 @@ log_set_suppr_seen(void *priv, int suppr_seen) log->suppr_seen = suppr_seen; } -void -log_set_dev_name(void *priv, char *dev_name) -{ - log_t *log = (log_t *) priv; - - log->dev_name = dev_name; -} - -static void -log_copy(log_t *log, char *dest, const char *src, size_t dest_size) -{ - memset(dest, 0x00, dest_size * sizeof(char)); - if (log && log->dev_name && strcmp(log->dev_name, "")) { - strcat(dest, log->dev_name); - strcat(dest, ": "); - } - strcat(dest, src); -} - /* - * Log something to the logfile or stdout. - * - * To avoid excessively-large logfiles because some - * module repeatedly logs, we keep track of what is - * being logged, and catch repeating entries. + Log something to the logfile or stdout. + + To avoid excessively-large logfiles because some + module repeatedly logs, we keep track of what is + being logged, and catch repeating entries. */ void log_out(void *priv, const char *fmt, va_list ap) @@ -107,154 +109,164 @@ log_out(void *priv, const char *fmt, va_list ap) char fmt2[1024]; if (log == NULL) - return; + pclog("WARNING: Logging called with a NULL log pointer\n"); + else if (fmt == NULL) + pclog("WARNING: Logging called with a NULL format pointer\n"); + else if (fmt[0] != '\0') { + log_ensure_stdlog_open(); - if (strcmp(fmt, "") == 0) - return; - - log_ensure_stdlog_open(); - - vsprintf(temp, fmt, ap); - if (log->suppr_seen && !strcmp(log->buff, temp)) - log->seen++; - else { - if (log->suppr_seen && log->seen) { - log_copy(log, fmt2, "*** %d repeats ***\n", 1024); - fprintf(stdlog, fmt2, log->seen); + vsprintf(temp, fmt, ap); + if (log->suppr_seen && !strcmp(log->buff, temp)) + log->seen++; + else { + if (log->suppr_seen && log->seen) { + log_copy(log, fmt2, "*** %d repeats ***\n", 1024); + fprintf(stdlog, fmt2, log->seen); + } + log->seen = 0; + strcpy(log->buff, temp); + log_copy(log, fmt2, temp, 1024); + fprintf(stdlog, fmt2, ap); } - log->seen = 0; - strcpy(log->buff, temp); - log_copy(log, fmt2, temp, 1024); - fprintf(stdlog, fmt2, ap); - } - fflush(stdlog); + fflush(stdlog); + } } - /* -Starfrost, 7-8 January 2025: + Starfrost, 7-8 January 2025: -For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. + For RIVA 128 emulation I needed a way to suppress logging if a repeated + pattern of the same set of lines were found. -Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm + Implements a version of the Rabin-Karp algorithm: + https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm . */ void log_out_cyclic(void* priv, const char* fmt, va_list ap) { -#ifndef RELEASE_BUILD - // get our new logging system instance. - log_t* log = (log_t*)priv; + /* Get our new logging system instance. */ + log_t* log = (log_t*) priv; - // does the log actually exist? - if (!log) - return; + /* Does the log actually exist? */ + if (log == NULL) + pclog("WARNING: Cyclical logging called with a NULL log pointer\n"); + else if (log->cyclic_buff == NULL) + pclog("WARNING: Cyclical logging called with a non-cyclic log\n"); + else if (fmt == NULL) + pclog("WARNING: Cyclical logging called with a NULL format pointer\n"); + /* Is the string empty? */ + else if (fmt[0] != '\0') { + /* Ensure stdlog is open. */ + log_ensure_stdlog_open(); - // is the string empty? - if (fmt[0] == '\0') - return; - - // ensure stdlog is open - log_ensure_stdlog_open(); + char temp[LOG_SIZE_BUFFER] = {0}; - char temp[LOG_SIZE_BUFFER] = {0}; + log->cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; - log->cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; + vsprintf(temp, fmt, ap); - vsprintf(temp, fmt, ap); + log_copy(log, log->cyclic_buff[log->cyclic_last_line], temp, + LOG_SIZE_BUFFER); - log_copy(log, log->cyclic_buff[log->cyclic_last_line], temp, LOG_SIZE_BUFFER); + uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; - uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; + /* Random numbers. */ + uint32_t base = 257; + uint32_t mod = 1000000007; - // Random numbers - uint32_t base = 257; - uint32_t mod = 1000000007; + uint32_t repeat_order = 0; + bool is_cycle = false; - uint32_t repeat_order = 0; - bool is_cycle = false; + /* Compute the set of hashes for the current log buffer. */ + for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; + log_line++) { + if (log->cyclic_buff[log_line][0] == '\0') + continue; /* Skip. */ - // compute the set of hashes for the current log buffer - for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) - { - if (log->cyclic_buff[log_line][0] == '\0') - continue; // skip - - for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) - { - hashes[log_line] = hashes[log_line] * base + log->cyclic_buff[log_line][log_line_char] % mod; + for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; + log_line_char++) + hashes[log_line] = hashes[log_line] * base + + log->cyclic_buff[log_line][log_line_char] % mod; } - } - - // Now see if there are real cycles... - // We implement a minimum repeat size. - for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) - { - //TODO: Log what we need for cycle 1. - //TODO: Command line option that lets us turn off this behaviour. - for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) - { - if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) - { - repeat_order = check_size; - break; + /* + Now see if there are real cycles. + We implement a minimum repeat size. + */ + for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; + check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) { + /* + TODO: Log what we need for cycle 1. + TODO: Command line option that lets us turn off this behaviour. + */ + for (int32_t log_line_to_check = 0; log_line_to_check < check_size; + log_line_to_check++) { + if (hashes[log_line_to_check] == + hashes[(log_line_to_check + check_size) % + LOG_SIZE_BUFFER_CYCLIC_LINES]) { + repeat_order = check_size; + break; + } } + + is_cycle = (repeat_order != 0); + + /* If there still is a cycle, break. */ + if (is_cycle) + break; + } - is_cycle = (repeat_order != 0); + if (is_cycle) { + if (log->cyclic_last_line % repeat_order == 0) { + log->log_cycles++; - // if there still is a cycle.. - if (is_cycle) - break; - - } + if (log->log_cycles == 1) { + /* + 'Replay' the last few log entries so they actually + show up. - if (is_cycle) - { - if (log->cyclic_last_line % repeat_order == 0) - { - log->log_cycles++; + TODO: Is this right? + */ - if (log->log_cycles == 1) - { - // 'Replay' the last few log entries so they actually show up - // Todo: is this right? + for (uint32_t index = log->cyclic_last_line - 1; + index > (log->cyclic_last_line - repeat_order); + index--) { + /* *Very important* to prevent out of bounds index. */ + uint32_t real_index = index % + LOG_SIZE_BUFFER_CYCLIC_LINES; + log_copy(log, temp, log->cyclic_buff[real_index], + LOG_SIZE_BUFFER); - for (uint32_t index = log->cyclic_last_line - 1; index > (log->cyclic_last_line - repeat_order); index--) - { - // *very important* to prevent out of bounds index - uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; - log_copy(log, temp, log->cyclic_buff[real_index], LOG_SIZE_BUFFER); - - fprintf(stdlog, "%s", log->cyclic_buff[real_index]); + fprintf(stdlog, "%s", log->cyclic_buff[real_index]); + } + /* Restore the original line. */ + log_copy(log, temp, + log->cyclic_buff[log->cyclic_last_line], + LOG_SIZE_BUFFER); + + /* Allow normal logging. */ + fprintf(stdlog, "%s", temp); } - // restore the original line - log_copy(log, temp, log->cyclic_buff[log->cyclic_last_line], LOG_SIZE_BUFFER); - - fprintf(stdlog, "%s", temp); // allow normal logging + if (log->log_cycles > 1 && log->log_cycles < 100) + fprintf(stdlog, "***** Cyclical Log Repeat of Order %d " + "#%d *****\n", repeat_order, log->log_cycles); + else if (log->log_cycles == 100) + fprintf(stdlog, "Logged the same cycle 100 times... " + "Silence until something interesting happens\n"); } - - - if (log->log_cycles > 1 && log->log_cycles < 100) - fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log->log_cycles); - else if (log->log_cycles == 100) - fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); + } else { + log->log_cycles = 0; + fprintf(stdlog, "%s", temp); } - } - else - { - log->log_cycles = 0; - fprintf(stdlog, "%s", temp); - } - - log->cyclic_last_line++; - -#endif + log->cyclic_last_line++; + } } +#endif void log_fatal(void *priv, const char *fmt, ...) @@ -267,6 +279,13 @@ log_fatal(void *priv, const char *fmt, ...) if (log == NULL) return; + if (log->cyclic_buff != NULL) { + for (int i = 0; i < LOG_SIZE_BUFFER_CYCLIC_LINES; i++) + if (log->cyclic_buff[i] != NULL) + free(log->cyclic_buff[i]); + free(log->cyclic_buff); + } + va_start(ap, fmt); log_copy(log, fmt2, fmt, 1024); vsprintf(temp, fmt2, ap); @@ -275,21 +294,42 @@ log_fatal(void *priv, const char *fmt, ...) exit(-1); } -void * -log_open(char *dev_name) +static void * +log_open_common(const char *dev_name, const int cyclic) { - log_t *log = malloc(sizeof(log_t)); + log_t *log = calloc(1, sizeof(log_t)); - memset(log, 0, sizeof(log_t)); - - log->dev_name = dev_name; + memcpy(log->dev_name, dev_name, strlen(dev_name) + 1); log->suppr_seen = 1; log->cyclic_last_line = 0; log->log_cycles = 0; + if (cyclic) { + log->cyclic_buff = calloc(LOG_SIZE_BUFFER_CYCLIC_LINES, + sizeof(char *)); + for (int i = 0; i < LOG_SIZE_BUFFER_CYCLIC_LINES; i++) + log->cyclic_buff[i] = calloc(LOG_SIZE_BUFFER, sizeof(char)); + } + return (void *) log; } +void * +log_open(const char *dev_name) +{ + return log_open_common(dev_name, 0); +} + +/* + This is so that not all logs get the 32k cyclical buffer + they may not need. + */ +void * +log_open_cyclic(const char *dev_name) +{ + return log_open_common(dev_name, 1); +} + void log_close(void *priv) { @@ -297,4 +337,3 @@ log_close(void *priv) free(log); } -#endif diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index e1bacad6c..e3f6428a7 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -1311,7 +1311,7 @@ ps1_hdc_init(UNUSED(const device_t *info)) /* Load any disks for this device class. */ c = 0; for (uint8_t i = 0; i < HDD_NUM; i++) { - if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < 1)) { + if ((hdd[i].bus_type == HDD_BUS_XTA) && (hdd[i].xta_channel < 1)) { drive = &dev->drives[hdd[i].xta_channel]; if (!hdd_image_load(i)) { diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index fb0224bc6..c85628e01 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -17,16 +17,18 @@ * Copyright 2023 Miran Grca. */ #include +#ifdef ENABLE_IOCTL_LOG #include +#endif #include #include #include #include #include #define HAVE_STDARG_H -#include <86box/86box.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> +#include <86box/log.h> #include <86box/plat_unused.h> #include <86box/plat_cdrom.h> @@ -35,223 +37,203 @@ of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) -typedef struct dummy_cdrom_ioctl_t { +typedef struct ioctl_t { + cdrom_t *dev; + void *log; int toc_valid; -} dummy_cdrom_ioctl_t; +} ioctl_t; -#ifdef ENABLE_DUMMY_CDROM_IOCTL_LOG -int dummy_cdrom_ioctl_do_log = ENABLE_DUMMY_CDROM_IOCTL_LOG; +#ifdef ENABLE_IOCTL_LOG +int ioctl_do_log = ENABLE_IOCTL_LOG; void -dummy_cdrom_ioctl_log(const char *fmt, ...) +ioctl_log(void *priv, const char *fmt, ...) { - va_list ap; - - if (dummy_cdrom_ioctl_do_log) { + if (ioctl_do_log) { + va_list ap; va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define dummy_cdrom_ioctl_log(fmt, ...) +# define ioctl_log(priv, fmt, ...) #endif -static int -plat_cdrom_open(void *local) +/* Internal functions. */ +static void +ioctl_close_handle(UNUSED(const ioctl_t *ioctl)) { return 0; } static int -plat_cdrom_load(void *local) +ioctl_open_handle(UNUSED(ioctl_t *ioctl)) { return 0; } static void -plat_cdrom_read_toc(void *local) +ioctl_read_toc(ioctl_t *ioctl) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + if (!ioctl->toc_valid) { + ioctl->toc_valid = 1; + } +} + +/* Shared functions. */ +static int +ioctl_get_track_info(UNUSED(const void *local), UNUSED(const uint32_t track), + UNUSED(int end), UNUSED(track_info_t *ti)) +{ + return 0; +} + +static void +ioctl_get_raw_track_info(const void *local, UNUSED(int *num), UNUSED(uint8_t *rti)) +{ + ioctl_t *ioctl = (ioctl_t *) local; if (!ioctl->toc_valid) ioctl->toc_valid = 1; } -void -plat_cdrom_get_raw_track_info(UNUSED(void *local), int *num, raw_track_info_t *rti) +static void +ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) { *num = 1; memset(rti, 0x00, 11); } -int -plat_cdrom_is_track_audio(void *local, uint32_t sector) +static int +ioctl_is_track_pre(const void *local, const uint32_t sector) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - const int ret = 0; - - dummy_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); - - return ret; -} - -int -plat_cdrom_is_track_pre(void *local, uint32_t sector) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + ioctl_t *ioctl = (ioctl_t *) local; plat_cdrom_read_toc(ioctl); const int ret = 0; - dummy_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); + ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); return ret; } -uint32_t -plat_cdrom_get_track_start(void *local, uint32_t sector, uint8_t *attr, uint8_t *track) +static int +ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - return 0x00000000; -} - -uint32_t -plat_cdrom_get_last_block(void *local) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - return 0x00000000; -} - -int -plat_cdrom_ext_medium_changed(UNUSED(void *local)) -{ -#if 0 - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); -#endif - - int ret = 0; - - dummy_cdrom_ioctl_log("plat_cdrom_ext_medium_changed(): %i\n", ret); - - return ret; -} - -/* This replaces both Info and EndInfo, they are specified by a variable. */ -int -plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - if ((track < 1) || (track == 0xaa)) { - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i)\n", track); - return 0; - } - - start->min = 0; - start->sec = 0; - start->fr = 2; - - *track_num = 1; - *attr = 0x14; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", - track, start->min, start->sec, start->fr, *track_num, *attr); - - return 1; -} - -/* TODO: See if track start is adjusted by 150 or not. */ -int -plat_cdrom_get_audio_sub(UNUSED(void *local), UNUSED(uint32_t sector), uint8_t *attr, uint8_t *track, uint8_t *index, - TMSF *rel_pos, TMSF *abs_pos) -{ - *track = 1; - *attr = 0x14; - *index = 1; - - rel_pos->min = 0; - rel_pos->sec = 0; - rel_pos->fr = 0; - abs_pos->min = 0; - abs_pos->sec = 0; - abs_pos->fr = 2; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_sub(): %02i, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - *track, *attr, *index, rel_pos->min, rel_pos->sec, rel_pos->fr, abs_pos->min, abs_pos->sec, abs_pos->fr); - - return 1; -} - -int -plat_cdrom_get_sector_size(UNUSED(void *local), UNUSED(uint32_t sector)) -{ - dummy_cdrom_ioctl_log("BytesPerSector=2048\n"); - - return 2048; -} - -int -plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + ioctl_t *ioctl = (ioctl_t *) local; plat_cdrom_open(ioctl); /* Raw */ - dummy_cdrom_ioctl_log("Raw\n"); + ioctl_log("Raw\n"); plat_cdrom_close(ioctl); - dummy_cdrom_ioctl_log("ReadSector sector=%d.\n", sector); + ioctl_log("ReadSector sector=%d.\n", sector); return 0; } -void -plat_cdrom_eject(void *local) +static uint8_t +ioctl_get_track_type(UNUSED(const void *local), UNUSED(const uint32_t sector)) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_open(ioctl); - plat_cdrom_close(ioctl); + return 0x00; } -void -plat_cdrom_close(UNUSED(void *local)) +static uint32_t +ioctl_get_last_block(const void *local) { + ioctl_t *ioctl = (ioctl_t *) local; + + ioctl_read_toc(ioctl); + + return 0x00000000; } -int -plat_cdrom_set_drive(void *local, const char *drv) +static int +ioctl_read_dvd_structure(UNUSED(const void *local), UNUSED(const uint8_t layer), UNUSED(const uint8_t format), + UNUSED(uint8_t *buffer), UNUSED(uint32_t *info)) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_close(ioctl); - - ioctl->toc_valid = 0; - - plat_cdrom_load(ioctl); - - return 1; + return -0x00052100; } -int -plat_cdrom_get_local_size(void) +static int +ioctl_is_dvd(UNUSED(const void *local)) { - return sizeof(dummy_cdrom_ioctl_t); + return 0; +} + +static int +ioctl_has_audio(UNUSED(const void *local)) +{ + return 0; +} + +static int +ioctl_ext_medium_changed(UNUSED(void *local)) +{ +#if 0 + ioctl_t *ioctl = (ioctl_t *) local; +#endif + int ret = 0; + + ioctl_log("ioctl_ext_medium_changed(): %i\n", ret); + + return ret; +} + +static void +ioctl_close(void *local) +{ + ioctl_t *ioctl = (ioctl_t *) local; + + ioctl_close_handle(ioctl); + ioctl->handle = NULL; + + ioctl_log(ioctl->log, "Log closed\n"); + + log_close(ioctl->log); + ioctl->log = NULL; +} + +static const cdrom_ops_t ioctl_ops = { + ioctl_get_track_info, + ioctl_get_raw_track_info, + ioctl_is_track_pre, + ioctl_read_sector, + ioctl_get_track_type, + ioctl_get_last_block, + ioctl_read_dvd_structure, + ioctl_is_dvd, + ioctl_has_audio, + ioctl_ext_medium_changed, + ioctl_close +}; + +/* Public functions. */ +void * +ioctl_open(cdrom_t *dev, const char *drv) +{ + ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t)); + + if (ioctl != NULL) { + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i IOCtl", dev->id + 1); + ioctl->log = log_open(n); + + memset(ioctl->path, 0x00, sizeof(ioctl->path)); + + wsprintf(ioctl->path, L"%S", &(drv[8])); + ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); + + ioctl->dev = dev; + ioctl->toc_valid = 0; + + dev->ops = &ioctl_ops; + } + + return ioctl; } diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index ebc18e198..d1335873c 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -369,12 +369,12 @@ MachineStatus::iterateNIC(const std::function &cb) } static int -hdd_count(int bus) +hdd_count(const int bus_type) { int c = 0; for (uint8_t i = 0; i < HDD_NUM; i++) { - if (hdd[i].bus == bus) { + if (hdd[i].bus_type == bus_type) { c++; } } diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 902ca10d6..fdea16c2a 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -537,10 +537,7 @@ MediaMenu::cdromMount(int i, const QString &filename) if ((fn.data() != NULL) && (strlen(fn.data()) >= 1) && (fn.data()[strlen(fn.data()) - 1] == '\\')) fn.data()[strlen(fn.data()) - 1] = '/'; #endif - if ((fn.data() != nullptr) && fn.contains("ioctl://")) - cdrom_ioctl_open(&(cdrom[i]), fn.data()); - else - cdrom_image_open(&(cdrom[i]), fn.data()); + cdrom_load(&(cdrom[i]), fn.data(), 1); /* Signal media change to the emulated machine. */ if (cdrom[i].insert) { @@ -806,14 +803,21 @@ MediaMenu::zipSelectImage(int i, bool wp) void MediaMenu::zipMount(int i, const QString &filename, bool wp) { - const auto dev = static_cast(zip_drives[i].priv); + const auto dev = static_cast(zip_drives[i].priv); + int was_empty = zip_is_empty(i); zip_disk_close(dev); zip_drives[i].read_only = wp; if (!filename.isEmpty()) { QByteArray filenameBytes = filename.toUtf8(); - zip_load(dev, filenameBytes.data()); + zip_load(dev, filenameBytes.data(), 1); + + /* Signal media change to the emulated machine. */ zip_insert(dev); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + zip_insert(dev); } mhm.addImageToHistory(i, ui::MediaType::Zip, zip_drives[i].prev_image_path, zip_drives[i].image_path); @@ -935,14 +939,21 @@ MediaMenu::moSelectImage(int i, bool wp) void MediaMenu::moMount(int i, const QString &filename, bool wp) { - const auto dev = static_cast(mo_drives[i].priv); + const auto dev = static_cast(mo_drives[i].priv); + int was_empty = mo_is_empty(i); mo_disk_close(dev); mo_drives[i].read_only = wp; if (!filename.isEmpty()) { QByteArray filenameBytes = filename.toUtf8(); - mo_load(dev, filenameBytes.data()); + mo_load(dev, filenameBytes.data(), 1); + + /* Signal media change to the emulated machine. */ mo_insert(dev); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + mo_insert(dev); } mhm.addImageToHistory(i, ui::MediaType::Mo, mo_drives[i].prev_image_path, mo_drives[i].image_path); diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index db54315e4..cc58d3cde 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -90,6 +90,14 @@ setCDROMSpeed(QAbstractItemModel *model, const QModelIndex &idx, uint8_t speed) model->setData(i, speed, Qt::UserRole); } +static QString +CDROMName(int type) +{ + char temp[512]; + cdrom_get_name(type, temp); + return QObject::tr((const char *) temp); +} + static void setCDROMType(QAbstractItemModel *model, const QModelIndex &idx, int type) { @@ -97,7 +105,7 @@ setCDROMType(QAbstractItemModel *model, const QModelIndex &idx, int type) if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() == CDROM_BUS_DISABLED) model->setData(i, QCoreApplication::translate("", "None")); else if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() != CDROM_BUS_MITSUMI) - model->setData(i, QObject::tr(cdrom_getname(type))); + model->setData(i, CDROMName(type)); model->setData(i, type, Qt::UserRole); } @@ -156,8 +164,12 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) auto idx = model->index(i, 0); int type = cdrom_get_type(i); setCDROMBus(model, idx, cdrom[i].bus_type, cdrom[i].res); - setCDROMSpeed(model, idx.siblingAtColumn(1), cdrom[i].speed); setCDROMType(model, idx.siblingAtColumn(2), type); + int speed = cdrom_get_speed(type); + if (speed == -1) + setCDROMSpeed(model, idx.siblingAtColumn(1), cdrom[i].speed); + else + setCDROMSpeed(model, idx.siblingAtColumn(1), speed); if (cdrom[i].bus_type == CDROM_BUS_ATAPI) Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, cdrom[i].ide_channel); else if (cdrom[i].bus_type == CDROM_BUS_SCSI) @@ -186,7 +198,7 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) if (((bus_type == CDROM_BUS_ATAPI) || (bus_type == CDROM_BUS_SCSI)) && ((cdrom_drive_types[j].bus_type == bus_type) || (cdrom_drive_types[j].bus_type == BUS_TYPE_BOTH))) { - QString name = tr(cdrom_getname(j)); + QString name = CDROMName(j); Models::AddEntry(modelType, name, j); if ((cdrom[cdromIdx].bus_type == bus_type) && (cdrom[cdromIdx].type == j)) selectedTypeRow = eligibleRows; @@ -246,7 +258,6 @@ SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) { uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); - uint8_t speed = current.siblingAtColumn(1).data(Qt::UserRole).toUInt(); int type = current.siblingAtColumn(2).data(Qt::UserRole).toInt(); ui->comboBoxBus->setCurrentIndex(-1); @@ -260,7 +271,14 @@ SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) if (!match.isEmpty()) ui->comboBoxChannel->setCurrentIndex(match.first().row()); + int speed = cdrom_get_speed(type); + if (speed == -1) { + speed = current.siblingAtColumn(1).data(Qt::UserRole).toUInt(); + ui->comboBoxSpeed->setEnabled(true); + } else + ui->comboBoxSpeed->setEnabled(false); ui->comboBoxSpeed->setCurrentIndex(speed == 0 ? 7 : speed - 1); + ui->comboBoxCDROMType->setCurrentIndex(type); enableCurrentlySelectedChannel(); } @@ -351,7 +369,7 @@ SettingsFloppyCDROM::on_comboBoxBus_activated(int) if (((bus_type == CDROM_BUS_ATAPI) || (bus_type == CDROM_BUS_SCSI)) && ((cdrom_drive_types[j].bus_type == bus_type) || (cdrom_drive_types[j].bus_type == BUS_TYPE_BOTH))) { - QString name = tr(cdrom_getname(j)); + QString name = CDROMName(j); Models::AddEntry(modelType, name, j); if ((cdrom[cdromIdx].bus_type == bus_type) && (cdrom[cdromIdx].type == j)) selectedTypeRow = eligibleRows; @@ -401,9 +419,22 @@ SettingsFloppyCDROM::on_comboBoxChannel_activated(int) void SettingsFloppyCDROM::on_comboBoxCDROMType_activated(int) { + int type = ui->comboBoxCDROMType->currentData().toUInt(); + setCDROMType(ui->tableViewCDROM->model(), ui->tableViewCDROM->selectionModel()->currentIndex(), - ui->comboBoxCDROMType->currentData().toUInt()); + type); ui->tableViewCDROM->resizeColumnsToContents(); ui->tableViewCDROM->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + + int speed = cdrom_get_speed(type); + if (speed == -1) { + speed = ui->comboBoxSpeed->currentData().toUInt(); + ui->comboBoxSpeed->setEnabled(true); + } else + ui->comboBoxSpeed->setEnabled(false); + ui->comboBoxSpeed->setCurrentIndex(speed == 0 ? 7 : speed - 1); + + auto idx = ui->tableViewCDROM->selectionModel()->currentIndex(); + setCDROMSpeed(ui->tableViewCDROM->model(), idx.siblingAtColumn(1), speed); } diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp index 4f6811ff1..e679dafa5 100644 --- a/src/qt/qt_settingsharddisks.cpp +++ b/src/qt/qt_settingsharddisks.cpp @@ -55,7 +55,7 @@ normalize_hd_list() memset(ihdd, 0x00, HDD_NUM * sizeof(hard_disk_t)); for (uint8_t i = 0; i < HDD_NUM; i++) { - if (temp_hdd[i].bus != HDD_BUS_DISABLED) { + if (temp_hdd[i].bus_type != HDD_BUS_DISABLED) { memcpy(&(ihdd[j]), &(temp_hdd[i]), sizeof(hard_disk_t)); j++; } @@ -79,14 +79,14 @@ addRow(QAbstractItemModel *model, hard_disk_t *hd) int row = model->rowCount(); model->insertRow(row); - QString busName = Harddrives::BusChannelName(hd->bus, hd->channel); + QString busName = Harddrives::BusChannelName(hd->bus_type, hd->channel); model->setData(model->index(row, ColumnBus), busName); model->setData(model->index(row, ColumnBus), ProgSettings::loadIcon("/hard_disk.ico"), Qt::DecorationRole); - model->setData(model->index(row, ColumnBus), hd->bus, DataBus); - model->setData(model->index(row, ColumnBus), hd->bus, DataBusPrevious); + model->setData(model->index(row, ColumnBus), hd->bus_type, DataBus); + model->setData(model->index(row, ColumnBus), hd->bus_type, DataBusPrevious); model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel); model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannelPrevious); - Harddrives::busTrackClass->device_track(1, DEV_HDD, hd->bus, hd->channel); + Harddrives::busTrackClass->device_track(1, DEV_HDD, hd->bus_type, hd->channel); QString fileName = hd->fn; if (fileName.startsWith(userPath, Qt::CaseInsensitive)) { model->setData(model->index(row, ColumnFilename), fileName.mid(userPath.size())); @@ -120,7 +120,7 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) ui->tableView->setModel(model); for (int i = 0; i < HDD_NUM; i++) { - if (hdd[i].bus > 0) { + if (hdd[i].bus_type > 0) { addRow(model, &hdd[i]); } } @@ -153,7 +153,7 @@ SettingsHarddisks::save() int rows = model->rowCount(); for (int i = 0; i < rows; ++i) { auto idx = model->index(i, ColumnBus); - hdd[i].bus = idx.data(DataBus).toUInt(); + hdd[i].bus_type = idx.data(DataBus).toUInt(); hdd[i].channel = idx.data(DataBusChannel).toUInt(); hdd[i].tracks = idx.siblingAtColumn(ColumnCylinders).data().toUInt(); hdd[i].hpc = idx.siblingAtColumn(ColumnHeads).data().toUInt(); @@ -313,11 +313,11 @@ addDriveFromDialog(Ui::SettingsHarddisks *ui, const HarddiskDialog &dlg) hard_disk_t hd; memset(&hd, 0, sizeof(hd)); - hd.bus = dlg.bus(); - hd.channel = dlg.channel(); - hd.tracks = dlg.cylinders(); - hd.hpc = dlg.heads(); - hd.spt = dlg.sectors(); + hd.bus_type = dlg.bus(); + hd.channel = dlg.channel(); + hd.tracks = dlg.cylinders(); + hd.hpc = dlg.heads(); + hd.spt = dlg.sectors(); strncpy(hd.fn, fn.data(), sizeof(hd.fn) - 1); hd.speed_preset = dlg.speed(); diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 9d82d68cc..271f7226f 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -19,32 +19,28 @@ #define UNICODE #define BITMAP WINDOWS_BITMAP #include -#include #undef BITMAP #include -#include #include "ntddcdrm.h" #include "ntddscsi.h" +#ifdef ENABLE_IOCTL_LOG #include -#include +#endif #include #include #include #include #include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/scsi_device.h> #include <86box/cdrom.h> -#include <86box/plat_unused.h> -#include <86box/plat_cdrom.h> +#include <86box/log.h> +#include <86box/plat_cdrom_ioctl.h> -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) - -typedef struct win_cdrom_ioctl_t { +typedef struct ioctl_t { + cdrom_t *dev; + void *log; + int is_dvd; + int has_audio; + int32_t tracks_num; int toc_valid; uint8_t cur_toc[65536]; CDROM_READ_TOC_EX cur_read_toc_ex; @@ -52,109 +48,112 @@ typedef struct win_cdrom_ioctl_t { uint8_t cur_rti[65536]; HANDLE handle; WCHAR path[256]; - WCHAR old_path[256]; -} win_cdrom_ioctl_t; +} ioctl_t; -#ifdef ENABLE_WIN_CDROM_IOCTL_LOG -int win_cdrom_ioctl_do_log = ENABLE_WIN_CDROM_IOCTL_LOG; +static void ioctl_read_toc(ioctl_t *ioctl); +static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format, + uint8_t *buffer, uint32_t *info); + +#ifdef ENABLE_IOCTL_LOG +int ioctl_do_log = ENABLE_IOCTL_LOG; void -win_cdrom_ioctl_log(const char *fmt, ...) +ioctl_log(void *priv, const char *fmt, ...) { - va_list ap; - - if (win_cdrom_ioctl_do_log) { + if (ioctl_do_log) { + va_list ap; va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define win_cdrom_ioctl_log(fmt, ...) +# define ioctl_log(priv, fmt, ...) #endif +/* Internal functions. */ static void -plat_cdrom_close_handle(win_cdrom_ioctl_t *ioctl) +ioctl_close_handle(const ioctl_t *ioctl) { if (ioctl->handle != NULL) CloseHandle(ioctl->handle); } static int -plat_cdrom_open(void *local) +ioctl_open_handle(ioctl_t *ioctl) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - - plat_cdrom_close_handle(local); - + ioctl_log(ioctl->log, "ioctl->path = \"%ls\"\n", ioctl->path); ioctl->handle = CreateFileW((LPCWSTR) ioctl->path, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - win_cdrom_ioctl_log("handle=%p, error=%x\n", ioctl->handle, (unsigned int) GetLastError()); + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + + ioctl_log(ioctl->log, "handle=%p, error=%x\n", + ioctl->handle, (unsigned int) GetLastError()); return (ioctl->handle != INVALID_HANDLE_VALUE); } static int -plat_cdrom_load(void *local) +ioctl_load(ioctl_t *ioctl) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; + int ret = 0; - plat_cdrom_close(local); - - ioctl->handle = CreateFileW((LPCWSTR) ioctl->path, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - win_cdrom_ioctl_log("handle=%p, error=%x\n", ioctl->handle, (unsigned int) GetLastError()); - if (ioctl->handle != INVALID_HANDLE_VALUE) { + if (ioctl_open_handle(ioctl)) { long size; - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, (LPDWORD) &size, NULL); - return 1; + DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, + NULL, 0, NULL, 0, + (LPDWORD) &size, NULL); + ret = 1; + ioctl_close_handle(ioctl); + + ioctl_read_toc(ioctl); } - return 0; + + return ret; } static int -plat_cdrom_read_normal_toc(win_cdrom_ioctl_t *ioctl, uint8_t *toc_buf) +ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) { long size = 0; PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + ioctl->tracks_num = 0; memset(toc_buf, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - if (ioctl->blocks_num != 0) { - memset(ioctl->cur_rti, 0x00, ioctl->blocks_num * 11); - ioctl->blocks_num = 0; - } ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_TOC; - win_cdrom_ioctl_log("cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 0; + ioctl->cur_read_toc_ex.SessionTrack = 1; - plat_cdrom_open(ioctl); - int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, (LPDWORD) &size, NULL); - plat_cdrom_close(ioctl); - win_cdrom_ioctl_log("temp = %i\n", temp); + ioctl_open_handle(ioctl); + const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, + &ioctl->cur_read_toc_ex, 65535, + cur_full_toc, 65535, + (LPDWORD) &size, NULL); + ioctl_close_handle(ioctl); + ioctl_log(ioctl->log, "temp = %i\n", temp); if (temp != 0) { - int length = ((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) + 2; + const int length = ((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) + 2; memcpy(toc_buf, cur_full_toc, length); + ioctl->tracks_num = (length - 4) / 8; } free(cur_full_toc); -#ifdef ENABLE_WIN_CDROM_IOCTL_LOG +#ifdef ENABLE_IOCTL_LOG PCDROM_TOC toc = (PCDROM_TOC) toc_buf; - const int tracks_num = (((toc->Length[0] << 8) | toc->Length[1]) - 2) / 8; - win_cdrom_ioctl_log("%i tracks: %02X %02X %02X %02X\n", - tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); + ioctl_log(ioctl->log, "%i tracks: %02X %02X %02X %02X\n", + ioctl->tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); - for (int i = 0; i < tracks_num; i++) { - uint8_t *t = (uint8_t *) &toc->TrackData[i]; - win_cdrom_ioctl_log("Track %03i: %02X %02X %02X %02X %02X %02X %02X %02X\n", - i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]); + for (int i = 0; i < ioctl->tracks_num; i++) { + const uint8_t *t = (const uint8_t *) &toc->TrackData[i]; + ioctl_log(ioctl->log, "Track %03i: %02X %02X %02X %02X %02X %02X %02X %02X\n", + i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]); } #endif @@ -162,427 +161,626 @@ plat_cdrom_read_normal_toc(win_cdrom_ioctl_t *ioctl, uint8_t *toc_buf) } static void -plat_cdrom_read_raw_toc(win_cdrom_ioctl_t *ioctl) +ioctl_read_raw_toc(ioctl_t *ioctl) { - long size = 0; - PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + long size = 0; + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; + uint8_t *buffer = (uint8_t *) calloc (1, 2052); + ioctl->is_dvd = (ioctl_read_dvd_structure(ioctl, 0, 0, buffer, NULL) > 0); + free(buffer); + + ioctl->has_audio = 0; + ioctl->blocks_num = 0; memset(ioctl->cur_rti, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - if (ioctl->blocks_num != 0) { - memset(ioctl->cur_rti, 0x00, ioctl->blocks_num * 11); - ioctl->blocks_num = 0; - } ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; - win_cdrom_ioctl_log("cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 0; + ioctl->cur_read_toc_ex.SessionTrack = 1; - plat_cdrom_open(ioctl); - int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, (LPDWORD) &size, NULL); - plat_cdrom_close(ioctl); - win_cdrom_ioctl_log("status = %i\n", status); + ioctl_open_handle(ioctl); + const int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, + &ioctl->cur_read_toc_ex, 65535, + cur_full_toc, 65535, + (LPDWORD) &size, NULL); + ioctl_close_handle(ioctl); + ioctl_log(ioctl->log, "status = %i\n", status); - if (status != 0) { - ioctl->blocks_num = (((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) - 2) / 11; + if ((status == 0) && (ioctl->tracks_num >= 1)) { + /* + This is needed because in some circumstances (eg. a DVD .MDS + mounted in Daemon Tools), reading the raw TOC fails but + reading the cooked TOC does not, so we have to construct the + raw TOC from the cooked TOC. + */ + const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; + const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); + + rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + rti[0].point = 0xa0; + rti[0].pm = toc->FirstTrack; + + rti[1].adr_ctl = rti[0].adr_ctl; + rti[1].point = 0xa1; + rti[1].pm = toc->LastTrack; + + rti[2].adr_ctl = rti[0].adr_ctl; + rti[2].point = 0xa2; + rti[2].pm = ct->Address[1]; + rti[2].ps = ct->Address[2]; + rti[2].pf = ct->Address[3]; + + ioctl->blocks_num = 3; + + for (int i = 0; i < (ioctl->tracks_num - 1); i++) { + raw_track_info_t *crt = &(rti[ioctl->blocks_num]); + + ct = &(toc->TrackData[i]); + + crt->adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + crt->point = ct->TrackNumber; + crt->pm = ct->Address[1]; + crt->ps = ct->Address[2]; + crt->pf = ct->Address[3]; + + ioctl->blocks_num++; + } + } else if (status != 0) { + ioctl->blocks_num = (((cur_full_toc->Length[0] << 8) | + cur_full_toc->Length[1]) - 2) / 11; memcpy(ioctl->cur_rti, cur_full_toc->Descriptors, ioctl->blocks_num * 11); } -#ifdef ENABLE_WIN_CDROM_IOCTL_LOG - uint8_t *u = (uint8_t *) cur_full_toc; + if (ioctl->blocks_num) for (int i = 0; i < ioctl->tracks_num; i++) { + const raw_track_info_t *crt = &(rti[i]); - win_cdrom_ioctl_log("%i blocks: %02X %02X %02X %02X\n", - ioctl->blocks_num, u[0], u[1], u[2], u[3]); + if ((crt->point >= 1) && (crt->point <= 99) && !(crt->adr_ctl & 0x04)) { + ioctl->has_audio = 1; + break; + } + } + +#ifdef ENABLE_IOCTL_LOG + uint8_t *u = (uint8_t *) cur_full_toc; + + ioctl_log(ioctl->log, "%i blocks: %02X %02X %02X %02X\n", + ioctl->blocks_num, u[0], u[1], u[2], u[3]); - raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; for (int i = 0; i < ioctl->blocks_num; i++) { uint8_t *t = (uint8_t *) &rti[i]; - win_cdrom_ioctl_log("Block %03i: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10]); + ioctl_log(ioctl->log, "Block %03i: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X\n", + i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], + t[9], t[10]); } #endif free(cur_full_toc); } -void -plat_cdrom_get_raw_track_info(void *local, int *num, raw_track_info_t *rti) +static void +ioctl_read_toc(ioctl_t *ioctl) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; + if (!ioctl->toc_valid) { + ioctl->toc_valid = 1; + (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); + ioctl_read_raw_toc(ioctl); + } +} + +static int +ioctl_get_track(const ioctl_t *ioctl, const uint32_t sector) { + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; + int track = -1; + + for (int i = (ioctl->blocks_num - 1); i >= 0; i--) { + const raw_track_info_t *ct = &(rti[i]); + const uint32_t start = (ct->pm * 60 * 75) + (ct->ps * 75) + ct->pf - 150; + + ioctl_log(ioctl->log, "ioctl_get_track(): ct: %02X, %08X\n", + ct->point, start); + + if ((ct->point >= 1) && (ct->point <= 99) && (sector >= start)) { + track = i; + ioctl_log(ioctl->log, "ioctl_get_track(): found track: %i\n", i); + break; + } + } + + return track; +} + +static int +ioctl_is_track_audio(const ioctl_t *ioctl, const uint32_t pos) +{ + const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; + int ret = 0; + + ioctl_read_toc((ioctl_t *) ioctl); + + if (ioctl->has_audio && !ioctl->is_dvd) { + const int track = ioctl_get_track(ioctl, pos); + const int control = rti[track].adr_ctl; + + ret = !(control & 0x04); + + ioctl_log(ioctl->log, "ioctl_is_track_audio(%08X, %02X): %i\n", pos, track, ret); + } + + return ret; +} + +/* Shared functions. */ +static int +ioctl_get_track_info(const void *local, const uint32_t track, + int end, track_info_t *ti) +{ + const ioctl_t * ioctl = (const ioctl_t *) local; + const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; + int ret = 1; + + ioctl_read_toc((ioctl_t *) ioctl); + + if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { + ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track); + ret = 0; + } else { + const TRACK_DATA * td = &toc->TrackData[track - 1]; + + ti->m = td->Address[1]; + ti->s = td->Address[2]; + ti->f = td->Address[3]; + + ti->number = td->TrackNumber; + ti->attr = td->Control; + ti->attr |= ((td->Adr << 4) & 0xf0); + + ioctl_log(ioctl->log, "ioctl_get_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", + track, ti->m, ti->s, ti->f, ti->number, ti->attr); + } + + return ret; +} + +static void +ioctl_get_raw_track_info(const void *local, int *num, uint8_t *rti) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; *num = ioctl->blocks_num; memcpy(rti, ioctl->cur_rti, ioctl->blocks_num * 11); } -static void -plat_cdrom_read_toc(win_cdrom_ioctl_t *ioctl) +static int +ioctl_is_track_pre(const void *local, const uint32_t sector) { - if (!ioctl->toc_valid) { - ioctl->toc_valid = 1; - (void) plat_cdrom_read_normal_toc(ioctl, ioctl->cur_toc); - plat_cdrom_read_raw_toc(ioctl); + const ioctl_t *ioctl = (const ioctl_t *) local; + const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; + int ret = 0; + + ioctl_read_toc((ioctl_t *) ioctl); + + if (ioctl->has_audio && !ioctl->is_dvd) { + const int track = ioctl_get_track(ioctl, sector); + const int control = rti[track].adr_ctl; + + ret = control & 0x01; + + ioctl_log(ioctl->log, "ioctl_is_track_pre(%08X, %02X): %i\n", sector, track, ret); } -} - -int -plat_cdrom_is_track_audio(void *local, uint32_t sector) -{ - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - int control = 0; - uint32_t cur_addr = 0; - uint32_t next_addr = 0; - - plat_cdrom_read_toc(ioctl); - - for (int c = 0; toc->TrackData[c].TrackNumber != 0xaa; c++) { - PTRACK_DATA cur_td = &toc->TrackData[c]; - PTRACK_DATA next_td = &toc->TrackData[c + 1]; - - cur_addr = MSFtoLBA(cur_td->Address[1], cur_td->Address[2], cur_td->Address[3]) - 150; - next_addr = MSFtoLBA(next_td->Address[1], next_td->Address[2], next_td->Address[3]) - 150; - - win_cdrom_ioctl_log("F: %i, L: %i, C: %i (%i), c: %02X, A: %08X, S: %08X\n", - toc->FirstTrack, toc->LastTrack, cur_td->TrackNumber, c, - cur_td->Control, cur_addr, sector); - - if ((cur_td->TrackNumber >= toc->FirstTrack) && (cur_td->TrackNumber <= toc->LastTrack) && - (sector >= cur_addr) && (sector < next_addr)) { - control = cur_td->Control; - break; - } - } - - const int ret = !(control & 0x04); - - win_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); return ret; } -int -plat_cdrom_is_track_pre(void *local, uint32_t sector) +static int +ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - int control = 0; - uint32_t cur_addr = 0; - uint32_t next_addr = 0; + typedef struct SCSI_PASS_THROUGH_DIRECT_BUF { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR SenseBuf[64]; + } SCSI_PASS_THROUGH_DIRECT_BUF; - plat_cdrom_read_toc(ioctl); + const ioctl_t * ioctl = (const ioctl_t *) local; + const raw_track_info_t * rti = (raw_track_info_t *) ioctl->cur_rti; + unsigned long int unused = 0; + const int sc_offs = (sector == 0xffffffff) ? 0 : 2352; + int len = (sector == 0xffffffff) ? 16 : 2368; + int m = 0; + int s = 0; + int f = 0; + uint32_t lba = sector; + int ret; + SCSI_PASS_THROUGH_DIRECT_BUF req; - for (int c = 0; toc->TrackData[c].TrackNumber != 0xaa; c++) { - PTRACK_DATA cur_td = &toc->TrackData[c]; - PTRACK_DATA next_td = &toc->TrackData[c + 1]; + ioctl_open_handle((ioctl_t *) ioctl); - cur_addr = MSFtoLBA(cur_td->Address[1], cur_td->Address[2], cur_td->Address[3]) - 150; - next_addr = MSFtoLBA(next_td->Address[1], next_td->Address[2], next_td->Address[3]) - 150; + if (ioctl->is_dvd) { + int track; - win_cdrom_ioctl_log("F: %i, L: %i, C: %i (%i), c: %02X, A: %08X, S: %08X\n", - toc->FirstTrack, toc->LastTrack, cur_td->TrackNumber, c, - cur_td->Control, cur_addr, sector); + req.spt.DataTransferLength = 0; + ret = 0; - if ((cur_td->TrackNumber >= toc->FirstTrack) && (cur_td->TrackNumber <= toc->LastTrack) && - (sector >= cur_addr) && (sector < next_addr)) { - control = cur_td->Control; - break; + if (lba == 0xffffffff) { + lba = ioctl->dev->seek_pos; + track = ioctl_get_track(ioctl, lba); + + if (track != -1) { + req.spt.DataTransferLength = len; + ret = 1; + } + } else { + len = COOKED_SECTOR_SIZE; + track = ioctl_get_track(ioctl, lba); + + if (track != -1) { + DWORD newPos = SetFilePointer(ioctl->handle, (long) lba * COOKED_SECTOR_SIZE, + 0, FILE_BEGIN); + + if (newPos != 0xffffffff) + ret = ReadFile(ioctl->handle, &(buffer[16]), + COOKED_SECTOR_SIZE, (LPDWORD) &req.spt.DataTransferLength, + NULL); + } } + + if (ret && (req.spt.DataTransferLength >= len) && (track != -1)) { + const raw_track_info_t *ct = &(rti[track]); + const uint32_t start = (ct->pm * 60 * 75) + (ct->ps * 75) + ct->pf; + + m = s = f = 0; + + /* Construct sector header and sub-header. */ + if (sector != 0xffffffff) { + /* Sync bytes. */ + buffer[0] = 0x00; + memset(&(buffer[1]), 0xff, 10); + buffer[11] = 0x00; + + /* Sector header. */ + FRAMES_TO_MSF(lba + 150, &m, &s, &f); + buffer[12] = bin2bcd(m); + buffer[13] = bin2bcd(s); + buffer[14] = bin2bcd(f); + + /* Mode 1 data. */ + buffer[15] = 0x01; + } + + /* Construct Q. */ + buffer[sc_offs + 0] = (ct->adr_ctl >> 4) | ((ct->adr_ctl & 0xf) << 4); + buffer[sc_offs + 1] = bin2bcd(ct->point); + buffer[sc_offs + 2] = 1; + FRAMES_TO_MSF((int32_t) (lba + 150 - start), &m, &s, &f); + buffer[sc_offs + 3] = bin2bcd(m); + buffer[sc_offs + 4] = bin2bcd(s); + buffer[sc_offs + 5] = bin2bcd(f); + FRAMES_TO_MSF(lba + 150, &m, &s, &f); + buffer[sc_offs + 7] = bin2bcd(m); + buffer[sc_offs + 8] = bin2bcd(s); + buffer[sc_offs + 9] = bin2bcd(f); + } + } else { + memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); + req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + req.spt.PathId = 0; + req.spt.TargetId = 1; + req.spt.Lun = 0; + req.spt.CdbLength = 12; + req.spt.DataIn = SCSI_IOCTL_DATA_IN; + req.spt.SenseInfoLength = sizeof(req.SenseBuf); + req.spt.DataTransferLength = len; + req.spt.TimeOutValue = 6; + req.spt.DataBuffer = buffer; + req.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_BUF, SenseBuf); + + /* Fill in the CDB. */ + req.spt.Cdb[0] = 0xbe; /* READ CD */ + req.spt.Cdb[1] = 0x00; + req.spt.Cdb[2] = (sector >> 24) & 0xff; + req.spt.Cdb[3] = (sector >> 16) & 0xff; + req.spt.Cdb[4] = (sector >> 8) & 0xff; + req.spt.Cdb[5] = sector & 0xff; /* Starting Logical Block Address. */ + req.spt.Cdb[6] = 0x00; + req.spt.Cdb[7] = 0x00; + req.spt.Cdb[8] = 0x01; /* Transfer Length. */ + /* If sector is FFFFFFFF, only return the subchannel. */ + req.spt.Cdb[9] = (sector == 0xffffffff) ? 0x00 : 0xf8; + req.spt.Cdb[10] = 0x02; + req.spt.Cdb[11] = 0x00; + DWORD length = sizeof(SCSI_PASS_THROUGH_DIRECT_BUF); + +#ifdef ENABLE_IOCTL_LOG + uint8_t *cdb = (uint8_t *) req.spt.Cdb; + ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X\n", + ioctl->dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], + cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); +#endif + + ret = DeviceIoControl(ioctl->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &req, length, + &req, length, &unused, NULL); } - const int ret = (control & 0x01); + ioctl_log(ioctl->log, "ioctl_read_sector: ret = %d, req.spt.DataTransferLength = %lu\n", + ret, req.spt.DataTransferLength); + ioctl_log(ioctl->log, "Sense: %08X, %08X\n", req.spt.SenseInfoLength, req.spt.SenseInfoOffset); + if (req.spt.SenseInfoLength >= 16) { + uint8_t *cdb = (uint8_t *) req.SenseBuf; + if ((cdb[2] == 0x03) && (cdb[12] == 0x11)) + /* Treat this as an error to corectly indicate CIRC error to the guest. */ + ret = 0; + ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdb[0], cdb[1], cdb[ 2], cdb[ 3], cdb[ 4], cdb[ 5], cdb[ 6], cdb[ 7]); + ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]); + } - win_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); + ret = (!!ret > 0) ? (req.spt.DataTransferLength >= len) : -1; + ioctl_log(ioctl->log, "iocl_read_sector: final ret = %i\n", ret); + + /* Construct raw subchannel data from Q only. */ + if ((ret > 0) && (req.spt.DataTransferLength >= len)) + for (int i = 11; i >= 0; i--) + for (int j = 7; j >= 0; j--) + buffer[2352 + (i * 8) + j] = ((buffer[sc_offs + i] >> (7 - j)) & 0x01) << 6; + + ioctl_close_handle((ioctl_t *) ioctl); return ret; } -uint32_t -plat_cdrom_get_track_start(void *local, uint32_t sector, uint8_t *attr, uint8_t *track) +static uint8_t +ioctl_get_track_type(const void *local, const uint32_t sector) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - uint32_t cur_addr = 0; - uint32_t next_addr = 0; + ioctl_t * ioctl = (ioctl_t *) local; + int track = ioctl_get_track(ioctl, sector); + raw_track_info_t * rti = (raw_track_info_t *) ioctl->cur_rti; + const raw_track_info_t *trk = &(rti[track]); + uint8_t ret = 0x00; - plat_cdrom_read_toc(ioctl); + if (ioctl_is_track_audio(ioctl, sector)) + ret = CD_TRACK_AUDIO; + else if (track != -1) for (int i = 0; i < ioctl->blocks_num; i++) { + const raw_track_info_t *ct = &(rti[i]); + const raw_track_info_t *nt = &(rti[i + 1]); - for (int c = 0; toc->TrackData[c].TrackNumber != 0xaa; c++) { - PTRACK_DATA cur_td = &toc->TrackData[c]; - PTRACK_DATA next_td = &toc->TrackData[c + 1]; + if (ct->point == 0xa0) { + uint8_t first = ct->pm; + uint8_t last = nt->pm; - cur_addr = MSFtoLBA(cur_td->Address[1], cur_td->Address[2], cur_td->Address[3]) - 150; - next_addr = MSFtoLBA(next_td->Address[1], next_td->Address[2], next_td->Address[3]) - 150; - - win_cdrom_ioctl_log("F: %i, L: %i, C: %i (%i), c: %02X, a: %02X, A: %08X, S: %08X\n", - toc->FirstTrack, toc->LastTrack, cur_td->TrackNumber, c, - cur_td->Control, cur_td->Adr, cur_addr, sector); - - if ((cur_td->TrackNumber >= toc->FirstTrack) && (cur_td->TrackNumber <= toc->LastTrack) && - (sector >= cur_addr) && (sector < next_addr)) { - *track = cur_td->TrackNumber; - *attr = cur_td->Control; - *attr |= ((cur_td->Adr << 4) & 0xf0); - break; + if ((trk->point >= first) && (trk->point <= last)) { + ret = ct->ps; + break; + } } } - win_cdrom_ioctl_log("plat_cdrom_get_track_start(%08X): %i\n", sector, cur_addr); - - return cur_addr; + return ret; } -uint32_t -plat_cdrom_get_last_block(void *local) +static uint32_t +ioctl_get_last_block(const void *local) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - uint32_t lb = 0; - uint32_t address = 0; + const ioctl_t *ioctl = (const ioctl_t *) local; + const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; + uint32_t lb = 0; - plat_cdrom_read_toc(ioctl); + ioctl_read_toc((ioctl_t *) ioctl); for (int c = 0; c <= toc->LastTrack; c++) { - PTRACK_DATA td = &toc->TrackData[c]; - - address = MSFtoLBA(td->Address[1], td->Address[2], td->Address[3]) - 150; + const TRACK_DATA *td = &toc->TrackData[c]; + const uint32_t address = MSFtoLBA(td->Address[1], td->Address[2], + td->Address[3]) - 150; if (address > lb) lb = address; } - win_cdrom_ioctl_log("LBCapacity=%d\n", lb); + ioctl_log(ioctl->log, "LBCapacity=%d\n", lb); return lb; } -int -plat_cdrom_ext_medium_changed(void *local) -{ - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - uint8_t new_toc_buf[65536] = { 0 }; - PCDROM_TOC new_toc = (PCDROM_TOC) new_toc_buf; - int ret = 0; - int temp = plat_cdrom_read_normal_toc(ioctl, new_toc_buf); - PTRACK_DATA cur_ltd = &toc->TrackData[toc->LastTrack]; - - if (temp != 0) - plat_cdrom_read_raw_toc(ioctl); - - PTRACK_DATA new_ltd = &new_toc->TrackData[new_toc->LastTrack]; - - if (temp == 0) - /* There has been some kind of error - not a medium change, but a not ready - condition. */ - ret = -1; - else if (!ioctl->toc_valid || (memcmp(ioctl->path, ioctl->old_path, sizeof(ioctl->path)) != 0)) { - /* Changed to a different host drive - we already detect such medium changes. */ - ioctl->toc_valid = 1; - memcpy(toc, new_toc, 65535); - if (memcmp(ioctl->path, ioctl->old_path, sizeof(ioctl->path)) != 0) - memcpy(ioctl->old_path, ioctl->path, sizeof(ioctl->path)); - } else if (memcmp(&(new_ltd->Address[1]), &(cur_ltd->Address[1]), 3)) { - /* The TOC has changed. */ - ioctl->toc_valid = 1; - memcpy(toc, new_toc, 65535); - if (memcmp(ioctl->path, ioctl->old_path, sizeof(ioctl->path)) != 0) - memcpy(ioctl->old_path, ioctl->path, sizeof(ioctl->path)); - ret = 1; - } - - win_cdrom_ioctl_log("plat_cdrom_ext_medium_changed(): %i\n", ret); - - return ret; -} - -/* This replaces both Info and EndInfo, they are specified by a variable. */ -int -plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) -{ - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - PCDROM_TOC toc = (PCDROM_TOC) ioctl->cur_toc; - - plat_cdrom_read_toc(ioctl); - - if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { - win_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i)\n", track); - return 0; - } - - PTRACK_DATA td = &toc->TrackData[track - 1]; - - start->min = td->Address[1]; - start->sec = td->Address[2]; - start->fr = td->Address[3]; - - *track_num = td->TrackNumber; - *attr = td->Control; - *attr |= ((td->Adr << 4) & 0xf0); - - win_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", - track, start->min, start->sec, start->fr, *track_num, *attr); - - return 1; -} - -/* TODO: See if track start is adjusted by 150 or not. */ -int -plat_cdrom_get_audio_sub(void *local, UNUSED(uint32_t sector), uint8_t *attr, uint8_t *track, uint8_t *index, - TMSF *rel_pos, TMSF *abs_pos) -{ - win_cdrom_ioctl_t * ioctl = (win_cdrom_ioctl_t *) local; - CDROM_SUB_Q_DATA_FORMAT insub; - SUB_Q_CHANNEL_DATA sub; - long size = 0; - - insub.Format = IOCTL_CDROM_CURRENT_POSITION; - - plat_cdrom_open(ioctl); - DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_Q_CHANNEL, &insub, sizeof(insub), &sub, sizeof(sub), - (LPDWORD) &size, NULL); - plat_cdrom_close(ioctl); - - if (sub.CurrentPosition.TrackNumber < 1) - return 0; - - *track = sub.CurrentPosition.TrackNumber; - *attr = sub.CurrentPosition.Control; - *attr |= ((sub.CurrentPosition.ADR << 4) & 0xf0); - *index = sub.CurrentPosition.IndexNumber; - - rel_pos->min = sub.CurrentPosition.TrackRelativeAddress[1]; - rel_pos->sec = sub.CurrentPosition.TrackRelativeAddress[2]; - rel_pos->fr = sub.CurrentPosition.TrackRelativeAddress[3]; - abs_pos->min = sub.CurrentPosition.AbsoluteAddress[1]; - abs_pos->sec = sub.CurrentPosition.AbsoluteAddress[2]; - abs_pos->fr = sub.CurrentPosition.AbsoluteAddress[3]; - - win_cdrom_ioctl_log("plat_cdrom_get_audio_sub(): %02i, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - *track, *attr, *index, rel_pos->min, rel_pos->sec, rel_pos->fr, abs_pos->min, abs_pos->sec, - abs_pos->fr); - - return 1; -} - -int -plat_cdrom_get_sector_size(void *local, UNUSED(uint32_t sector)) -{ - win_cdrom_ioctl_t * ioctl = (win_cdrom_ioctl_t *) local; - long size; - DISK_GEOMETRY dgCDROM; - - plat_cdrom_open(ioctl); - DeviceIoControl(ioctl->handle, IOCTL_CDROM_GET_DRIVE_GEOMETRY, NULL, 0, &dgCDROM, sizeof(dgCDROM), - (LPDWORD) &size, NULL); - plat_cdrom_close(ioctl); - - win_cdrom_ioctl_log("BytesPerSector=%d\n", dgCDROM.BytesPerSector); - return dgCDROM.BytesPerSector; -} - -int -plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector) +static int +ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t format, + uint8_t *buffer, uint32_t *info) { typedef struct SCSI_PASS_THROUGH_DIRECT_BUF { SCSI_PASS_THROUGH_DIRECT spt; ULONG Filler; - UCHAR SenseBuf[32]; + UCHAR SenseBuf[64]; } SCSI_PASS_THROUGH_DIRECT_BUF; - win_cdrom_ioctl_t * ioctl = (win_cdrom_ioctl_t *) local; - int sc_offs = (sector == 0xffffffff) ? 0 : 2352; + const ioctl_t * ioctl = (const ioctl_t *) local; unsigned long int unused = 0; - int ret; + const int len = 2052; SCSI_PASS_THROUGH_DIRECT_BUF req; - memset(&req, 0x00, sizeof(req)); - req.Filler = 0; + ioctl_open_handle((ioctl_t *) ioctl); + + memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + req.spt.PathId = 0; + req.spt.TargetId = 1; + req.spt.Lun = 0; req.spt.CdbLength = 12; req.spt.DataIn = SCSI_IOCTL_DATA_IN; - req.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_BUF, SenseBuf); req.spt.SenseInfoLength = sizeof(req.SenseBuf); + req.spt.DataTransferLength = len; req.spt.TimeOutValue = 6; - req.spt.DataTransferLength = 2368; req.spt.DataBuffer = buffer; + req.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_BUF, SenseBuf); /* Fill in the CDB. */ - req.spt.Cdb[0] = 0xbe; /* READ CD */ - req.spt.Cdb[1] = 0x00; /* DAP = 0, Any Sector Type. */ - req.spt.Cdb[2] = (sector >> 24) & 0xff; - req.spt.Cdb[3] = (sector >> 16) & 0xff; - req.spt.Cdb[4] = (sector >> 8) & 0xff; - req.spt.Cdb[5] = sector & 0xff; /* Starting Logical Block Address. */ - req.spt.Cdb[6] = 0x00; - req.spt.Cdb[7] = 0x00; - req.spt.Cdb[8] = 0x01; /* Transfer Length. */ - /* If sector is FFFFFFFF, only return the subchannel. */ - req.spt.Cdb[9] = (sector == 0xffffffff) ? 0x00 : 0xf8; - req.spt.Cdb[10] = 0x02; + req.spt.Cdb[0] = 0xad; + req.spt.Cdb[1] = 0x00; + req.spt.Cdb[2] = 0x00; + req.spt.Cdb[3] = 0x00; + req.spt.Cdb[4] = 0x00; + req.spt.Cdb[5] = 0x00; + req.spt.Cdb[6] = layer; /* Layer Number */ + req.spt.Cdb[7] = format; /* Format */ + req.spt.Cdb[8] = 0x08; /* Allocation Length */ + req.spt.Cdb[9] = 0x04; + req.spt.Cdb[10] = 0x00; /* AGID */ req.spt.Cdb[11] = 0x00; - plat_cdrom_open(ioctl); - ret = DeviceIoControl(ioctl->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, &req, sizeof(req), &req, sizeof(req), - &unused, NULL); - plat_cdrom_close(ioctl); + DWORD length = sizeof(SCSI_PASS_THROUGH_DIRECT_BUF); - /* Construct raw subchannel data from Q only. */ - if (ret && (req.spt.DataTransferLength >= 2368)) - for (int i = 11; i >= 0; i--) - for (int j = 7; j >= 0; j--) - buffer[2352 + (i * 8) + j] = ((buffer[sc_offs + i] >> (7 - j)) & 0x01) << 6; +#ifdef ENABLE_IOCTL_LOG + uint8_t *cdb = (uint8_t *) req.spt.Cdb; + ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X\n", + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], + cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); +#endif - win_cdrom_ioctl_log("plat_cdrom_read_scsi_direct: ret = %d, req.spt.DataTransferLength = %lu\n", - ret, req.spt.DataTransferLength); - win_cdrom_ioctl_log("Sense: %08X, %08X\n", req.spt.SenseInfoLength, req.spt.SenseInfoOffset); - return ret && (req.spt.DataTransferLength >= 2368); + int ret = DeviceIoControl(ioctl->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &req, length, + &req, length, + &unused, NULL); + + ioctl_log(ioctl->log, "ioctl_read_dvd_structure(): ret = %d, " + "req.spt.DataTransferLength = %lu\n", + ret, req.spt.DataTransferLength); + ioctl_log(ioctl->log, "Sense: %08X, %08X\n", req.spt.SenseInfoLength, + req.spt.SenseInfoOffset); + + if (req.spt.SenseInfoLength >= 16) { + uint8_t *sb = (uint8_t *) req.SenseBuf; + /* Return sense to the host as is. */ + ret = -((sb[2] << 16) | (sb[12] << 8) | sb[13]); + if (info != NULL) + *info = *(uint32_t *) &(sb[3]); + ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[0], sb[1], sb[ 2], sb[ 3], sb[ 4], sb[ 5], sb[ 6], sb[ 7]); + ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[8], sb[9], sb[10], sb[11], sb[12], sb[13], sb[14], sb[15]); + } else + ret = ret ? (req.spt.DataTransferLength >= len) : 0; + + ioctl_close_handle((ioctl_t *) ioctl); + + return ret; } -void -plat_cdrom_eject(void *local) +static int +ioctl_is_dvd(const void *local) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; - long size; + const ioctl_t *ioctl = (const ioctl_t *) local; - plat_cdrom_open(ioctl); - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, (LPDWORD) &size, NULL); - plat_cdrom_close(ioctl); + return ioctl->is_dvd; } -void -plat_cdrom_close(void *local) +static int +ioctl_has_audio(const void *local) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; + const ioctl_t *ioctl = (const ioctl_t *) local; - plat_cdrom_close_handle(ioctl); + return ioctl->has_audio; +} + +static int +ioctl_ext_medium_changed(void *local) +{ + ioctl_t * ioctl = (ioctl_t *) local; + const CDROM_TOC *toc = (CDROM_TOC *) ioctl->cur_toc; + const TRACK_DATA *ltd = &toc->TrackData[toc->LastTrack]; + const uint32_t old_addr = *(uint32_t *) ltd->Address; + const int temp = ioctl_read_normal_toc(ioctl, ioctl->cur_toc); + int ret = 0; + + if (temp == 1) { + if (ioctl->toc_valid && ((*(uint32_t *) ltd->Address) != old_addr)) { + /* The TOC has changed. */ + ioctl->toc_valid = 0; + ret = 1; + } + + if (!ioctl->toc_valid) { + ioctl->toc_valid = 1; + ioctl_read_raw_toc(ioctl); + } + } else { + /* There has been some kind of error - not a medium change, but a not ready + condition. */ + ret = -1; + } + + if (ret == 1) { + if (ioctl->is_dvd) + ioctl->dev->cd_status = CD_STATUS_DVD; + else + ioctl->dev->cd_status = ioctl->has_audio ? CD_STATUS_STOPPED : + CD_STATUS_DATA_ONLY; + + ioctl->dev->cdrom_capacity = ioctl_get_last_block(ioctl); + } else if (ret == -1) + ioctl->dev->cd_status = CD_STATUS_EMPTY; + + ioctl_log(ioctl->log, "ioctl_ext_medium_changed(): %i\n", ret); + + return ret; +} + +static void +ioctl_close(void *local) +{ + ioctl_t *ioctl = (ioctl_t *) local; + + ioctl_close_handle(ioctl); ioctl->handle = NULL; + + ioctl_log(ioctl->log, "Log closed\n"); + + log_close(ioctl->log); + ioctl->log = NULL; } -int -plat_cdrom_set_drive(void *local, const char *drv) +static const cdrom_ops_t ioctl_ops = { + ioctl_get_track_info, + ioctl_get_raw_track_info, + ioctl_is_track_pre, + ioctl_read_sector, + ioctl_get_track_type, + ioctl_get_last_block, + ioctl_read_dvd_structure, + ioctl_is_dvd, + ioctl_has_audio, + ioctl_ext_medium_changed, + ioctl_close +}; + +/* Public functions. */ +void * +ioctl_open(cdrom_t *dev, const char *drv) { - win_cdrom_ioctl_t *ioctl = (win_cdrom_ioctl_t *) local; + ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t)); - plat_cdrom_close(ioctl); + if (ioctl != NULL) { + char n[1024] = { 0 }; - memcpy(ioctl->old_path, ioctl->path, sizeof(ioctl->path)); - memset(ioctl->path, 0x00, sizeof(ioctl->path)); + sprintf(n, "CD-ROM %i IOCtl", dev->id + 1); + ioctl->log = log_open(n); - wsprintf(ioctl->path, L"%S", drv); - win_cdrom_ioctl_log("Path is %S\n", ioctl->path); + memset(ioctl->path, 0x00, sizeof(ioctl->path)); - ioctl->toc_valid = 0; + wsprintf(ioctl->path, L"%S", &(drv[8])); + ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); - plat_cdrom_load(ioctl); + ioctl->dev = dev; + ioctl->toc_valid = 0; - return 1; -} - -int -plat_cdrom_get_local_size(void) -{ - return sizeof(win_cdrom_ioctl_t); + dev->ops = &ioctl_ops; + + ioctl_load(ioctl); + } + + return ioctl; } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 91773c62c..65604758d 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -9,46 +9,41 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * - * * Authors: Miran Grca, * - * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ -#include #include #include +#ifdef ENABLE_SCSI_CDROM_LOG +#include +#endif #include #include #include #include -#include -#define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/config.h> #include <86box/timer.h> +#include <86box/cdrom.h> #include <86box/device.h> -#include <86box/scsi.h> -#include <86box/scsi_device.h> +#include <86box/log.h> #include <86box/machine.h> #include <86box/nvr.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> -#include <86box/sound.h> #include <86box/plat.h> -#include <86box/ui.h> -#include <86box/cdrom.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/hdc_ide.h> #include <86box/scsi_cdrom.h> -#include <86box/version.h> +#include <86box/ui.h> #define IDE_ATAPI_IS_EARLY id->sc->pad0 #pragma pack(push, 1) typedef struct gesn_cdb_t { - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; uint8_t reserved3[2]; uint16_t len; uint8_t control; @@ -61,411 +56,192 @@ typedef struct gesn_event_header_t { } gesn_event_header_t; #pragma pack(pop) -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +// clang-format off +/* + Table of all SCSI commands and their flags, needed for the new disc change / + not ready handler. + */ uint8_t scsi_cdrom_command_flags[0x100] = { - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, /* 0x02 */ - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - 0, 0, 0, 0, /* 0x04-0x07 */ - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, 0, /* 0x09-0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, /* 0x0C */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x0D */ - 0, 0, 0, 0, /* 0x0E-0x11 */ - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, /* 0x14 */ - IMPLEMENTED, /* 0x15 */ - 0, 0, 0, 0, /* 0x16-0x19 */ - IMPLEMENTED, /* 0x1A */ - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, 0, /* 0x1C-0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, /* 0x1F-0x21*/ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x22*/ - 0, 0, /* 0x23-0x24 */ - IMPLEMENTED | CHECK_READY, /* 0x25 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x26 */ - 0, /* 0x27 */ - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, 0, /* 0x29-0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - 0, 0, 0, /* 0x2C-0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ - 0, 0, /* 0x40-0x41 */ - IMPLEMENTED | CHECK_READY, /* 0x42 */ - IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS - NOTE: The ATAPI reference says otherwise, but I think this is a question of - interpreting things right - the UNIT ATTENTION condition we have here - is a tradition from not ready to ready, by definition the drive - eventually becomes ready, make the condition go away. */ - IMPLEMENTED | CHECK_READY, /* 0x44 */ - IMPLEMENTED | CHECK_READY, /* 0x45 */ - IMPLEMENTED | ALLOW_UA, /* 0x46 */ - IMPLEMENTED | CHECK_READY, /* 0x47 */ - IMPLEMENTED | CHECK_READY, /* 0x48 */ - IMPLEMENTED | CHECK_READY, /* 0x49 */ - IMPLEMENTED | ALLOW_UA, /* 0x4A */ - IMPLEMENTED | CHECK_READY, /* 0x4B */ - 0, 0, /* 0x4C-0x4D */ - IMPLEMENTED | CHECK_READY, /* 0x4E */ - 0, 0, /* 0x4F-0x50 */ - IMPLEMENTED | CHECK_READY, /* 0x51 */ - IMPLEMENTED | CHECK_READY, /* 0x52 */ - 0, 0, /* 0x53-0x54 */ - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, /* 0x56-0x59 */ - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, /* 0x5B-0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ - 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ - IMPLEMENTED | CHECK_READY, /* 0xA5 */ - 0, 0, /* 0xA6-0xA7 */ - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - IMPLEMENTED | CHECK_READY, /* 0xA9 */ - 0, 0, 0, /* 0xAA-0xAC */ - IMPLEMENTED | CHECK_READY, /* 0xAD */ - 0, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, /* 0xB0-0xB3 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ - 0, 0, 0, /* 0xB5-0xB7 */ - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ - IMPLEMENTED | CHECK_READY, /* 0xB9 */ - IMPLEMENTED | CHECK_READY, /* 0xBA */ - IMPLEMENTED, /* 0xBB */ - IMPLEMENTED | CHECK_READY, /* 0xBC */ - IMPLEMENTED, /* 0xBD */ - IMPLEMENTED | CHECK_READY, /* 0xBE */ - IMPLEMENTED | CHECK_READY, /* 0xBF */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC0 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC1 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC3 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC4 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC5 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC6 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC7 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC8 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC9 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCA */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCB */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCC */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD7 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xD8 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xD9 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDA */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDB */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDC */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDD */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDE */ - 0, /* 0xDF */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE0 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE1 */ - 0, /* 0xE2 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE3 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE4 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE5 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE6 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE7 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE8 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE9 */ - 0, /* 0xEA */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xEB */ - 0, /* 0xEC */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xED */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xEE */ - 0, /* 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ + [0x00] = IMPLEMENTED | CHECK_READY, + [0x01] = IMPLEMENTED | ALLOW_UA | SCSI_ONLY, + [0x03] = IMPLEMENTED | ALLOW_UA, + [0x08] = IMPLEMENTED | CHECK_READY, + [0x0b] = IMPLEMENTED | CHECK_READY, + [0x0d] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x12] = IMPLEMENTED | ALLOW_UA, + [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x15] = IMPLEMENTED, + [0x1a] = IMPLEMENTED, + [0x1b] = IMPLEMENTED | CHECK_READY, + [0x1e] = IMPLEMENTED | CHECK_READY, + [0x22] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x25] = IMPLEMENTED | CHECK_READY, + [0x26] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x28] = IMPLEMENTED | CHECK_READY, + [0x2b] = IMPLEMENTED | CHECK_READY, + [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x42] = IMPLEMENTED | CHECK_READY, + /* + Read TOC/PMA/ATIP - can get through UNIT_ATTENTION, per VIDE-CDD.SYS. + + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. + */ + [0x43 ... 0x45] = IMPLEMENTED | CHECK_READY, + [0x46] IMPLEMENTED | ALLOW_UA, + [0x47 ... 0x49] = IMPLEMENTED | CHECK_READY, + [0x4a] = IMPLEMENTED | ALLOW_UA, + [0x4b] = IMPLEMENTED | CHECK_READY, + [0x4e] = IMPLEMENTED | CHECK_READY, + [0x51 ... 0x52] = IMPLEMENTED | CHECK_READY, + [0x55] = IMPLEMENTED, + [0x5a] = IMPLEMENTED, + [0xa5] = IMPLEMENTED | CHECK_READY, + [0xa8 ... 0xa9] = IMPLEMENTED | CHECK_READY, + [0xad] = IMPLEMENTED, + [0xaf] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xb4] = IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + [0xb8] = IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + [0xb9 ... 0xba] = IMPLEMENTED | CHECK_READY, + [0xbb] = IMPLEMENTED, + [0xbc] = IMPLEMENTED | CHECK_READY, + [0xbd] = IMPLEMENTED, + [0xbe ... 0xbf] = IMPLEMENTED | CHECK_READY, + [0xc0 ... 0xcd] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xd8 ... 0xde] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xe0 ... 0xe1] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xe3 ... 0xe9] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xeb] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xed ... 0xee] = IMPLEMENTED | CHECK_READY | SCSI_ONLY }; -static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_UNIT_ATN_PAGE | GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_FORMAT_DEVICE_PAGE | GPMODEP_CDROM_PAGE | GPMODEP_CDROM_AUDIO_PAGE | (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); -static uint64_t scsi_cdrom_mode_sense_page_flags_sony = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_CDROM_PAGE_SONY | GPMODEP_CDROM_AUDIO_PAGE_SONY | (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); -static uint64_t scsi_cdrom_drive_status_page_flags = ((1ULL << 0x01ULL) | (1ULL << 0x02ULL) | (1ULL << 0x0fULL) | GPMODEP_ALL_PAGES); +static uint64_t scsi_cdrom_ms_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_CDROM_PAGE | + GPMODEP_CDROM_AUDIO_PAGE | (1ULL << 0x0fULL) | + GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); +static uint64_t scsi_cdrom_ms_page_flags_scsi = (GPMODEP_UNIT_ATN_PAGE | GPMODEP_R_W_ERROR_PAGE | + GPMODEP_DISCONNECT_PAGE | GPMODEP_FORMAT_DEVICE_PAGE | + GPMODEP_CDROM_PAGE | GPMODEP_CDROM_AUDIO_PAGE | + (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); +static uint64_t scsi_cdrom_ms_page_flags_sony_scsi = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | + GPMODEP_CDROM_PAGE_SONY | GPMODEP_CDROM_AUDIO_PAGE_SONY | + (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); + +static uint64_t scsi_cdrom_drive_status_page_flags = ((1ULL << 0x01ULL) | (1ULL << 0x02ULL) | + (1ULL << 0x0fULL) | GPMODEP_ALL_PAGES); static const mode_sense_pages_t scsi_cdrom_drive_status_pages = { - {{ 0, 0 }, - { 0x01, 0, 2, 0x0f, 0xbf }, /*Drive Status Data Format*/ - { 0x02, 0, 1, 0 }, /*Audio Play Status Format*/ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }} + { [0x01] = { 0x01, 0x00, 0x02, 0x0f, 0xbf }, /* Drive Status Data Format */ + [0x02] = { 0x02, 0x00, 0x01, 0x00 } } /* Audio Play Status Format */ }; -static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = { - {{ 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 7, 0, 0x3f, 1, 0x0d, 3, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 }} +static const mode_sense_pages_t scsi_cdrom_ms_pages_default = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x4b }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, + 0x01, 0xff, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x07, 0x00, 0x7f, 0x01, 0x0d, 0x03, + 0x02, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x02, 0xc2, + 0x00, 0x00, 0x00, 0x00 } } }; -static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = { - {{ GPMODE_UNIT_ATN_PAGE, 6, 0, 0, 0, 0, 0, 0 }, /*Guess-work*/ - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 5, 4, 0, 128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 7, 0, 0x3f, 1, 0x0d, 3, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 }} +static const mode_sense_pages_t scsi_cdrom_ms_pages_default_scsi = { + { [0x00] = { GPMODE_UNIT_ATN_PAGE, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Guesswork */ + [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x03] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x4b }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0x05, 0x04, 0x00, 0x80, 0x00, 0x4b, + 0x01, 0xff, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x07, 0x00, 0x7f, 0x01, 0x0d, 0x03, + 0x02, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x02, 0xc2, + 0x00, 0x00, 0x00, 0x00 } } }; -static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_sony_scsi = { - {{ 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0e, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE_SONY, 2, 0, 5 }, - { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0xE, 5, 0, 0, 0, 0, 0, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 5, 4, 0, 128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, - { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 7, 0, 0x3f, 1, 0x0d, 3, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 }} +static const mode_sense_pages_t scsi_cdrom_ms_pages_default_sony_scsi = { + { { 0, 0 }, + [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x08] = { GPMODE_CDROM_PAGE_SONY, 0x02, 0x00, 0x05 }, + [0x09] = { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xff, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x4b }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0x05, 0x04, 0x00, 0x80, 0x00, 0x4b, + 0x01, 0xff, 0x02, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x07, 0x00, 0x7f, 0x01, 0x0d, 0x03, + 0x02, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x02, 0xc2, + 0x00, 0x00, 0x00, 0x00 } } }; -static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { - {{ GPMODE_UNIT_ATN_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, /*Guess-work*/ - { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0E, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, - { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} +static const mode_sense_pages_t scsi_cdrom_ms_pages_changeable = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } } }; -static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable_sony = { - {{ 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, - { GPMODE_DISCONNECT_PAGE, 0x0E, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE_SONY, 2, 0xFF, 0xFF }, - { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} +static const mode_sense_pages_t scsi_cdrom_ms_pages_changeable_scsi = { + { [0x00] = { GPMODE_UNIT_ATN_PAGE, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, /* Guesswork */ + [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x03] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } } }; +static const mode_sense_pages_t scsi_cdrom_ms_pages_changeable_sony_scsi = { + { [0x01] = { GPMODE_R_W_ERROR_PAGE, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x02] = { GPMODE_DISCONNECT_PAGE, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, + [0x08] = { GPMODE_CDROM_PAGE_SONY, 0x02, 0xff, 0xff }, + [0x09] = { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0d] = { GPMODE_CDROM_PAGE, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0e] = { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + [0x0f] = { 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x2a] = { GPMODE_CAPABILITIES_PAGE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 } } +}; +// clang-format on + static gesn_cdb_t *gesn_cdb; static gesn_event_header_t *gesn_event_header; @@ -480,22 +256,21 @@ static void scsi_cdrom_init(scsi_cdrom_t *dev); int scsi_cdrom_do_log = ENABLE_SCSI_CDROM_LOG; static void -scsi_cdrom_log(const char *format, ...) +scsi_cdrom_log(void *priv, const char *format, ...) { - va_list ap; - if (scsi_cdrom_do_log) { + va_list ap; va_start(ap, format); - pclog_ex(format, ap); + log_out(priv, format, ap); va_end(ap); } } #else -# define scsi_cdrom_log(format, ...) +# define scsi_cdrom_log(priv, format, ...) #endif static void -scsi_cdrom_set_callback(scsi_cdrom_t *dev) +scsi_cdrom_set_callback(const scsi_cdrom_t *dev) { if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback); @@ -504,47 +279,51 @@ scsi_cdrom_set_callback(scsi_cdrom_t *dev) static void scsi_cdrom_init(scsi_cdrom_t *dev) { - if (!dev) - return; + if (dev != NULL) { + /* Do a reset (which will also rezero it). */ + scsi_cdrom_reset((scsi_common_t *) dev); - /* Do a reset (which will also rezero it). */ - scsi_cdrom_reset((scsi_common_t *) dev); + /* Configure the drive. */ + dev->requested_blocks = 1; - /* Configure the drive. */ - dev->requested_blocks = 1; + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= CDROM_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < CDROM_BUS_SCSI) + dev->drv->bus_mode |= 1; + scsi_cdrom_log(dev->log, "Bus type %i, bus mode %i\n", + dev->drv->bus_type, dev->drv->bus_mode); - dev->drv->bus_mode = 0; - if (dev->drv->bus_type >= CDROM_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus_type < CDROM_BUS_SCSI) - dev->drv->bus_mode |= 1; - scsi_cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", - dev->id, dev->drv->bus_type, dev->drv->bus_mode); + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + /* NEC only */ + if (dev->drv->is_early) + dev->tf->status = READY_STAT | DSC_STAT; + else + dev->tf->status = 0; + dev->tf->pos = 0; + dev->packet_status = PHASE_NONE; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_info = 0x00000000; + dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + dev->drv->cur_speed = dev->drv->real_speed; + scsi_cdrom_mode_sense_load(dev); - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - /* NEC only */ - if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) - dev->tf->status = READY_STAT | DSC_STAT; - else - dev->tf->status = 0; - dev->tf->pos = 0; - dev->packet_status = PHASE_NONE; - scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; - dev->drv->cur_speed = dev->drv->speed; - scsi_cdrom_mode_sense_load(dev); - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_2403) - scsi_cdrom_drive_status_load(dev); + const char *vendor = cdrom_get_vendor(dev->drv->type); + + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && !strcmp(vendor, "PIONEER")) + scsi_cdrom_drive_status_load(dev); + } } /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ static int -scsi_cdrom_current_mode(scsi_cdrom_t *dev) +scsi_cdrom_current_mode(const scsi_cdrom_t *dev) { if (dev->drv->bus_type == CDROM_BUS_SCSI) return 2; else if (dev->drv->bus_type == CDROM_BUS_ATAPI) { - scsi_cdrom_log("CD-ROM %i: ATAPI drive, setting to %s\n", dev->id, + scsi_cdrom_log(dev->log, "ATAPI drive, setting to %s\n", (dev->tf->features & 1) ? "DMA" : "PIO", dev->id); return (dev->tf->features & 1) ? 2 : 1; @@ -554,50 +333,25 @@ scsi_cdrom_current_mode(scsi_cdrom_t *dev) } static uint32_t -scsi_cdrom_get_channel(void *priv, int channel) +scsi_cdrom_get_channel(void *priv, const int channel) { const scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; - uint32_t ret; + uint32_t ret = channel + 1; - if (!dev) - return channel + 1; - - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? - GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE] - [channel ? 10 : 8]; - break; - default: - ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; - break; - } + if (dev != NULL) + ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; return ret; } static uint32_t -scsi_cdrom_get_volume(void *priv, int channel) +scsi_cdrom_get_volume(void *priv, const int channel) { const scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; - uint32_t ret; + uint32_t ret = 255; - if (!dev) - return 255; - - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : - GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; - break; - default: - ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; - break; - } + if (dev != NULL) + ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; return ret; } @@ -605,129 +359,90 @@ scsi_cdrom_get_volume(void *priv, int channel) static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) { - FILE *fp; - char file_name[512]; + char file_name[512] = { 0 }; - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - memset(&dev->ms_pages_saved_sony, 0, sizeof(mode_sense_pages_t)); - memcpy(&dev->ms_pages_saved_sony, &scsi_cdrom_mode_sense_pages_default_sony_scsi, - sizeof(mode_sense_pages_t)); + memset(&dev->ms_pages_saved, 0x00, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &dev->ms_pages_default, + sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512); - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "rb"); - if (fp) { - if (fread(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, - 0x10, fp) != 0x10) - fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); - fclose(fp); - } - break; - default: - memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, - sizeof(mode_sense_pages_t)); - else - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, - sizeof(mode_sense_pages_t)); - - memset(file_name, 0, 512); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "rb"); - if (fp) { - if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp) != 0x10) - fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); - fclose(fp); - } - break; + if (dev->drv->bus_type == CDROM_BUS_SCSI) + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + FILE *fp = plat_fopen(nvr_path(file_name), "rb"); + if (fp) { + if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp) != 0x10) + log_fatal(dev->log, "scsi_cdrom_mode_sense_load(): Error reading data\n"); + (void) fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, + 0x10, fp); + fclose(fp); } } static void -scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) +scsi_cdrom_mode_sense_save(const scsi_cdrom_t *dev) { - FILE *fp; - char file_name[512]; + char file_name[512] = { 0 }; - memset(file_name, 0, 512); - - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "wb"); - if (fp) { - fwrite(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp); - fclose(fp); - } - break; - default: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "wb"); - if (fp) { - fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp); - fclose(fp); - } - break; + if (dev->drv->bus_type == CDROM_BUS_SCSI) + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + FILE *fp = plat_fopen(nvr_path(file_name), "wb"); + if (fp) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp); + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp); + fclose(fp); } } -/*SCSI Drive Status (Pioneer only)*/ +/* SCSI Drive Status (Pioneer only). */ static void scsi_cdrom_drive_status_load(scsi_cdrom_t *dev) { - memset(&dev->ms_drive_status_pages_saved, 0, sizeof(mode_sense_pages_t)); - memcpy(&dev->ms_drive_status_pages_saved, &scsi_cdrom_drive_status_pages, sizeof(mode_sense_pages_t)); + memset(&dev->ms_drive_status_pages_saved, 0x00, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_drive_status_pages_saved, &scsi_cdrom_drive_status_pages, + sizeof(mode_sense_pages_t)); } static uint8_t -scsi_cdrom_drive_status_read(scsi_cdrom_t *dev, UNUSED(uint8_t page_control), uint8_t page, uint8_t pos) +scsi_cdrom_drive_status_read(const scsi_cdrom_t *dev, const uint8_t page, + const uint8_t pos) { return dev->ms_drive_status_pages_saved.pages[page][pos]; } static uint32_t -scsi_cdrom_drive_status(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t page) +scsi_cdrom_drive_status(const scsi_cdrom_t *dev, uint8_t *buf, uint8_t page) { - uint8_t page_control = (page >> 6) & 3; - uint16_t msplen; + uint32_t pos = 0; page &= 0x3f; for (uint8_t i = 0; i < 0x40; i++) { - if (page == i) { - if (scsi_cdrom_drive_status_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { - buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 0); - msplen = (scsi_cdrom_drive_status_read(dev, page_control, i, 1) << 8); - msplen |= scsi_cdrom_drive_status_read(dev, page_control, i, 2); - buf[pos++] = (msplen >> 8) & 0xff; - buf[pos++] = msplen & 0xff; - scsi_cdrom_log("CD-ROM %i: DRIVE STATUS: Page [%02X] length %i\n", dev->id, i, msplen); - for (uint16_t j = 0; j < msplen; j++) { - if (i == 0x01) { - buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 3 + j); - if (!(j & 1)) { /*MSB of Drive Status*/ - if (dev->drv->ops) /*Bit 11 of Drive Status, */ - buf[pos] &= ~0x08; /*Disc is present*/ - else - buf[pos] |= 0x08; /*Disc not present*/ - } - } else if ((i == 0x02) && (j == 0)) { - buf[pos++] = ((dev->drv->cd_status == CD_STATUS_PLAYING) ? 0x01 : 0x00); - } else - buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 3 + j); - } + if ((page == i) && (scsi_cdrom_drive_status_page_flags & + (1LL << ((uint64_t) (page & 0x3f))))) { + buf[pos++] = scsi_cdrom_drive_status_read(dev, i, 0); + uint16_t len = (scsi_cdrom_drive_status_read(dev, i, 1) << 8); + len |= scsi_cdrom_drive_status_read(dev, i, 2); + buf[pos++] = (len >> 8) & 0xff; + buf[pos++] = len & 0xff; + scsi_cdrom_log(dev->log, "CD-ROM %i: DRIVE STATUS: Page [%02X] length %i\n", + i, len); + for (uint16_t j = 0; j < len; j++) { + if (i == 0x01) { + buf[pos++] = scsi_cdrom_drive_status_read(dev, i, 3 + j); + if (!(j & 1)) { /* MSB of Drive Status. */ + if (dev->drv->ops) /* Bit 11 of Drive Status, */ + buf[pos] &= ~0x08; /* Disc is present. */ + else + buf[pos] |= 0x08; /* Disc not present. */ + } + } else if ((i == 0x02) && (j == 0)) + buf[pos++] = ((dev->drv->cd_status == CD_STATUS_PLAYING) ? + 0x01 : 0x00); + else + buf[pos++] = scsi_cdrom_drive_status_read(dev, i, 3 + j); } } } @@ -737,52 +452,36 @@ scsi_cdrom_drive_status(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t p /*SCSI Mode Sense 6/10*/ static uint8_t -scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +scsi_cdrom_mode_sense_read(const scsi_cdrom_t *dev, const uint8_t pgctl, + const uint8_t page, const uint8_t pos) { - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - switch (page_control) { - case 0: - case 3: - return dev->ms_pages_saved_sony.pages[page][pos]; - case 1: - return scsi_cdrom_mode_sense_pages_changeable_sony.pages[page][pos]; - case 2: - return scsi_cdrom_mode_sense_pages_default_sony_scsi.pages[page][pos]; + uint8_t ret = 0; - default: - break; - } + switch (pgctl) { + case 0: case 3: + ret = dev->ms_pages_saved.pages[page][pos]; break; + + case 1: + ret = dev->ms_pages_changeable.pages[page][pos]; + break; + + case 2: + ret = dev->ms_pages_default.pages[page][pos]; + break; + default: - switch (page_control) { - case 0: - case 3: - return dev->ms_pages_saved.pages[page][pos]; - case 1: - return scsi_cdrom_mode_sense_pages_changeable.pages[page][pos]; - case 2: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - return scsi_cdrom_mode_sense_pages_default_scsi.pages[page][pos]; - else - return scsi_cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } - default: - break; - } - break; - } - - return 0; + return ret; } static uint32_t -scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +scsi_cdrom_mode_sense(const scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, + uint8_t page, const uint8_t block_descriptor_len) { - uint8_t page_control = (page >> 6) & 3; - uint8_t msplen; + const uint8_t pgctl = (page >> 6) & 3; page &= 0x3f; @@ -799,45 +498,45 @@ scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t pag for (uint8_t i = 0; i < 0x40; i++) { if ((page == GPMODE_ALL_PAGES) || (page == i)) { - if (scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { - buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 0); - msplen = scsi_cdrom_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - scsi_cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + if (dev->ms_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { + const uint8_t msplen = scsi_cdrom_mode_sense_read(dev, pgctl, i, 1); + + buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, i, 0); + buf[pos++] = msplen; + + scsi_cdrom_log(dev->log, "MODE SENSE: Page [%02X] length %i\n", + i, msplen); + for (uint8_t j = 0; j < msplen; j++) { - /* If we are returning changeable values, always return them from the page, - so they are all correctly. */ - if (page_control == 1) - buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j); + /* + If we are returning changeable values, always return + them from the page, so they are all correct. + */ + if (pgctl == 1) + buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, i, 2 + j); else { if ((i == GPMODE_CAPABILITIES_PAGE) && (j == 4)) { - buf[pos] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j) & 0x1f; - /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and - early vendor SCSI CD-ROM models) are caddy drives, the later - ones are tray drives. */ - if (dev->drv->bus_type == CDROM_BUS_SCSI) - buf[pos++] |= ((dev->drv->type == CDROM_TYPE_86BOX_100) ? 0x20 : 0x00); - else - buf[pos++] |= ((dev->drv->type == CDROM_TYPE_NEC_260_100) || - ((dev->drv->type == CDROM_TYPE_NEC_260_101)) ? 0x00 : 0x20); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { + buf[pos] = scsi_cdrom_mode_sense_read(dev, pgctl, i, 2 + j) & 0x1f; + buf[pos++] |= (cdrom_is_caddy(dev->drv->type) ? 0x00 : 0x20); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && + (j <= 7)) { if (j & 1) - buf[pos++] = ((dev->drv->speed * 176) & 0xff); + buf[pos++] = ((dev->drv->real_speed * 176) & 0xff); else - buf[pos++] = ((dev->drv->speed * 176) >> 8); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 8) && (j <= 9) && - (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_2403)) { - if (j & 1) - buf[pos++] = ((dev->drv->speed * 176) & 0xff); - else - buf[pos++] = ((dev->drv->speed * 176) >> 8); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { + buf[pos++] = ((dev->drv->real_speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && + (j <= 13)) { if (j & 1) buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); else buf[pos++] = ((dev->drv->cur_speed * 176) >> 8); - } else - buf[pos++] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j); + } else if (dev->is_sony && (i == GPMODE_CDROM_AUDIO_PAGE_SONY) && + (j >= 6) && (j <= 13)) + buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, + GPMODE_CDROM_AUDIO_PAGE, 2 + j); + else + buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, + i, 2 + j); } } } @@ -848,15 +547,17 @@ scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t pag } static void -scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) +scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len) { - int32_t bt; int32_t min_len = 0; - double dlen; + int32_t bt; dev->max_transfer_len = dev->tf->request_length; - /* For media access commands, make sure the requested DRQ length matches the block length. */ + /* + For media access commands, make sure the requested DRQ length + matches the block length. + */ switch (dev->current_cdb[0]) { case 0x08: case 0x28: @@ -865,21 +566,26 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) case 0xbe: /* Round it to the nearest (block length) bytes. */ if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { - /* READ CD MSF and READ CD: Round the request length to the sector size - the device must ensure - that a media access comand does not DRQ in the middle of a sector. One of the drivers that - relies on the correctness of this behavior is MTMCDAI.SYS (the Mitsumi CD-ROM driver) for DOS - which uses the READ CD command to read data on some CD types. */ + /* + READ CD MSF and READ CD: Round the request length to the sector size - the + device must ensure that a media access comand does not DRQ in the middle + of a sector. One of the drivers that relies on the correctness of this + behavior is MTMCDAI.SYS (the Mitsumi CD-ROM driver) for DOS which uses + the READ CD command to read data on some CD types. + */ /* Round to sector length. */ - dlen = ((double) dev->max_transfer_len) / ((double) block_len); + const double dlen = ((double) dev->max_transfer_len) / ((double) block_len); dev->max_transfer_len = ((uint16_t) floor(dlen)) * block_len; } else { /* Round it to the nearest 2048 bytes. */ - dev->max_transfer_len = (dev->max_transfer_len >> 11) << 11; + dev->max_transfer_len = (dev->max_transfer_len / dev->drv->sector_size) * dev->drv->sector_size; } - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ + /* + Make sure total length is not bigger than sum of the lengths of + all the requested blocks. + */ bt = (dev->requested_blocks * block_len); if (len > bt) len = bt; @@ -901,10 +607,16 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) dev->packet_len = len; break; } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + /* + If the DRQ length is odd, and the total remaining length is bigger, + make sure it's even. + */ if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + /* + If the DRQ length is smaller or equal in size to the total remaining length, + set it to that. + */ if (!dev->max_transfer_len) dev->max_transfer_len = 65534; @@ -939,8 +651,7 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) static void scsi_cdrom_command_common(scsi_cdrom_t *dev) { - double bytes_per_second = 0.0; - double period; + const uint8_t cmd = dev->current_cdb[0]; /* MAP: BUSY_STAT, no DRQ, phase 1. */ dev->tf->status = BUSY_STAT; @@ -948,19 +659,22 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->tf->pos = 0; dev->callback = 0; - scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); + scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0; else { - switch (dev->current_cdb[0]) { + double bytes_per_second; + double period; + + switch (cmd) { case GPCMD_REZERO_UNIT: case 0x0b: case 0x2b: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); - scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (uint64_t) period); + scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; scsi_cdrom_set_callback(dev); return; @@ -969,11 +683,12 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xa8: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); - scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (uint64_t) period); - scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us, speed: %" PRIu64 " bytes per second, " - "should be: %" PRIu64 " bytes per second\n", - dev->id, (uint64_t) period, (uint64_t) (1000000.0 / period), + scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); + scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us, speed: %" + PRIu64 " bytes per second, should be: %" + PRIu64 " bytes per second\n", + (uint64_t) period, (uint64_t) (1000000.0 / period), (uint64_t) (176400.0 * (double) dev->drv->cur_speed)); dev->callback += period; fallthrough; @@ -990,54 +705,17 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; + case 0xc0 ... 0xc3: case 0xc6 ... 0xc7: - switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } - case 0xc0: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } - case 0xc1: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_PIONEER_DRM604X_2403: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } - case 0xc2 ... 0xc3: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_PIONEER_DRM604X_2403: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - if (dev->current_cdb[0] == 0xc2) - dev->callback += 40.0; - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } case 0xdd ... 0xde: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; + if (dev->ven_cmd_is_data[cmd]) { + if (dev->current_cdb[0] == 0xc2) + dev->callback += 40.0; + /* Account for seek time. */ + /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ + bytes_per_second = 176400.0; + bytes_per_second *= (double) dev->drv->cur_speed; + break; } fallthrough; default: @@ -1050,9 +728,11 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) } period = 1000000.0 / bytes_per_second; - scsi_cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", + (uint64_t) period); period = period * (double) (dev->packet_len); - scsi_cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; } scsi_cdrom_set_callback(dev); @@ -1096,16 +776,18 @@ scsi_cdrom_command_write_dma(scsi_cdrom_t *dev) scsi_cdrom_command_common(dev); } -/* id = Current CD-ROM device ID; +/* + dev = Pointer to current CD-ROM device; len = Total transfer length; block_len = Length of a single block (it matters because media access commands on ATAPI); alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ + direction = Transfer direction (0 = read from host, 1 = write to host). + */ static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int alloc_len, int direction) { - scsi_cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, + scsi_cdrom_log(dev->log, "Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); dev->tf->pos = 0; if (alloc_len >= 0) { @@ -1135,72 +817,74 @@ scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int al } } - scsi_cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, - dev->tf->phase); + scsi_cdrom_log(dev->log, "Status: %i, cylinder %i, packet length: %i, position: %i, " + "phase: %i\n", dev->packet_status, dev->tf->request_length, dev->packet_len, + dev->tf->pos, dev->tf->phase); } static void scsi_cdrom_sense_clear(scsi_cdrom_t *dev, UNUSED(int command)) { scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; + scsi_cdrom_info = 0x00000000; } static void -scsi_cdrom_set_phase(scsi_cdrom_t *dev, uint8_t phase) +scsi_cdrom_set_phase(const scsi_cdrom_t *dev, const uint8_t phase) { - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + const uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; - if (dev->drv->bus_type != CDROM_BUS_SCSI) - return; - - scsi_devices[scsi_bus][scsi_id].phase = phase; + if (dev->drv->bus_type == CDROM_BUS_SCSI) + scsi_devices[scsi_bus][scsi_id].phase = phase; } static void scsi_cdrom_cmd_error(scsi_cdrom_t *dev) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->tf->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; - dev->tf->status = READY_STAT | ERR_STAT; - dev->tf->phase = 3; - dev->tf->pos = 0; - dev->packet_status = PHASE_ERROR; - dev->callback = 50.0 * CDROM_TIME; - scsi_cdrom_set_callback(dev); - ui_sb_update_icon(SB_CDROM | dev->id, 0); - scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); -} - -static void -scsi_cdrom_unit_attention(scsi_cdrom_t *dev) -{ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->error = ((scsi_cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + dev->tf->status = READY_STAT | ERR_STAT; dev->tf->phase = 3; dev->tf->pos = 0; dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); ui_sb_update_icon(SB_CDROM | dev->id, 0); - scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); + scsi_cdrom_log(dev->log, "ERROR: %02X/%02X/%02X\n", scsi_cdrom_sense_key, + scsi_cdrom_asc, scsi_cdrom_ascq); } static void -scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) +scsi_cdrom_unit_attention(scsi_cdrom_t *dev) { - if (!dev->buffer) + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + dev->tf->status = READY_STAT | ERR_STAT; + dev->tf->phase = 3; + dev->tf->pos = 0; + dev->packet_status = PHASE_ERROR; + dev->callback = 50.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_log(dev->log, "UNIT ATTENTION\n"); +} + +static void +scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, const uint32_t len) +{ + if (dev->buffer == NULL) dev->buffer = (uint8_t *) malloc(len); - scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i, buffer = %p\n", dev->id, len, dev->buffer); + + scsi_cdrom_log(dev->log, "Allocated buffer length: %i, buffer = %p\n", + len, dev->buffer); } static void scsi_cdrom_buf_free(scsi_cdrom_t *dev) { if (dev->buffer) { - scsi_cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + scsi_cdrom_log(dev->log, "Freeing buffer...\n"); free(dev->buffer); dev->buffer = NULL; } @@ -1211,179 +895,218 @@ scsi_cdrom_bus_master_error(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - scsi_cdrom_log("CD-ROM %i: Bus master error\n", dev->id); + scsi_cdrom_log(dev->log, "Bus master error\n"); scsi_cdrom_buf_free(dev); scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; + scsi_cdrom_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); + scsi_cdrom_cmd_error(dev); +} + +static void +scsi_cdrom_error_common(scsi_cdrom_t *dev, uint8_t sense_key, uint8_t asc, uint8_t ascq, uint32_t info) +{ + scsi_cdrom_log(dev->log, "Medium not present\n"); + scsi_cdrom_sense_key = sense_key; + scsi_cdrom_asc = asc; + scsi_cdrom_ascq = ascq; + scsi_cdrom_info = info; scsi_cdrom_cmd_error(dev); } static void scsi_cdrom_not_ready(scsi_cdrom_t *dev) { - scsi_cdrom_log("CD-ROM %i: Medium not present\n", dev->id); + scsi_cdrom_log(dev->log, "Medium not present\n"); scsi_cdrom_sense_key = SENSE_NOT_READY; scsi_cdrom_asc = ASC_MEDIUM_NOT_PRESENT; scsi_cdrom_ascq = 0; + scsi_cdrom_info = 0x00000000; scsi_cdrom_cmd_error(dev); } static void scsi_cdrom_circ_error(scsi_cdrom_t *dev) { - scsi_cdrom_log("CD-ROM %i: CIRC unrecovered error\n", dev->id); + scsi_cdrom_log(dev->log, "CIRC unrecovered error\n"); scsi_cdrom_sense_key = SENSE_MEDIUM_ERROR; scsi_cdrom_asc = ASC_UNRECOVERED_READ_ERROR; scsi_cdrom_ascq = ASCQ_CIRC_UNRECOVERED_ERROR; + scsi_cdrom_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_cdrom_cmd_error(dev); } static void -scsi_cdrom_invalid_lun(scsi_cdrom_t *dev) +scsi_cdrom_invalid_lun(scsi_cdrom_t *dev, const uint8_t lun) { - scsi_cdrom_log("CD-ROM %i: Invalid LUN\n", dev->id); + scsi_cdrom_log(dev->log, "Invalid LUN\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_LUN; scsi_cdrom_ascq = 0; + scsi_cdrom_info = lun << 24; scsi_cdrom_cmd_error(dev); } static void -scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev) +scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev, const uint8_t opcode) { - scsi_cdrom_log("CD-ROM %i: Illegal opcode\n", dev->id); + scsi_cdrom_log(dev->log, "Illegal opcode\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; scsi_cdrom_ascq = 0; + scsi_cdrom_info = opcode << 24; scsi_cdrom_cmd_error(dev); } static void scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) { - scsi_cdrom_log("CD-ROM %i: LBA out of range\n", dev->id); + scsi_cdrom_log(dev->log, "LBA out of range\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; scsi_cdrom_ascq = 0; + scsi_cdrom_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_cdrom_cmd_error(dev); } static void -scsi_cdrom_invalid_field(scsi_cdrom_t *dev) +scsi_cdrom_invalid_field(scsi_cdrom_t *dev, const uint32_t field) { - scsi_cdrom_log("CD-ROM %i: Invalid field in command packet\n", dev->id); + scsi_cdrom_log(dev->log, "Invalid field in command packet\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; scsi_cdrom_ascq = 0; + scsi_cdrom_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); scsi_cdrom_cmd_error(dev); dev->tf->status = 0x53; } static void -scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) +scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev, const uint32_t field) { - scsi_cdrom_log("CD-ROM %i: Invalid field in parameter list\n", dev->id); + scsi_cdrom_log(dev->log, "Invalid field in parameter list\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; scsi_cdrom_ascq = 0; + scsi_cdrom_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); scsi_cdrom_cmd_error(dev); dev->tf->status = 0x53; } +static void +scsi_cdrom_incompatible_format(scsi_cdrom_t *dev, const uint32_t val) +{ + scsi_cdrom_log(dev->log, "Incompatible format\n"); + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + scsi_cdrom_ascq = 2; + scsi_cdrom_info = (val >> 24) | + ((val >> 16) << 8) | + ((val >> 8) << 16) | + ( val << 24); + scsi_cdrom_cmd_error(dev); +} + +static void +scsi_cdrom_data_phase_error(scsi_cdrom_t *dev, const uint32_t info) +{ + scsi_cdrom_log(dev->log, "Data phase error\n"); + scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_cdrom_asc = ASC_DATA_PHASE_ERROR; + scsi_cdrom_ascq = 0; + scsi_cdrom_info = (info >> 24) | + ((info >> 16) << 8) | + ((info >> 8) << 16) | + ( info << 24); + scsi_cdrom_cmd_error(dev); +} + static void scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) { - scsi_cdrom_log("CD-ROM %i: Illegal mode for this track\n", dev->id); + scsi_cdrom_log(dev->log, "Illegal mode for this track\n"); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; scsi_cdrom_ascq = 0; - scsi_cdrom_cmd_error(dev); -} - -static void -scsi_cdrom_incompatible_format(scsi_cdrom_t *dev) -{ - scsi_cdrom_log("CD-ROM %i: Incompatible format\n", dev->id); - scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_cdrom_asc = ASC_INCOMPATIBLE_FORMAT; - scsi_cdrom_ascq = 2; - scsi_cdrom_cmd_error(dev); -} - -static void -scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) -{ - scsi_cdrom_log("CD-ROM %i: Data phase error\n", dev->id); - scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_cdrom_asc = ASC_DATA_PHASE_ERROR; - scsi_cdrom_ascq = 0; + scsi_cdrom_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_cdrom_cmd_error(dev); } static int -scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len, int vendor_type) +scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int flags, + int32_t *len, const int vendor_type) { - int ret = 0; - int data_pos = 0; int temp_len = 0; - uint32_t cdsize = 0; + int ret = 0; - if (dev->drv->cd_status == CD_STATUS_EMPTY) { + if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); - return 0; - } + else { + const uint32_t cdsize = dev->drv->cdrom_capacity; - cdsize = dev->drv->cdrom_capacity; + if (dev->sector_pos >= cdsize) { + scsi_cdrom_log(dev->log, "Trying to read from beyond the end of " + "disc (%i >= %i)\n", dev->sector_pos, cdsize); + scsi_cdrom_lba_out_of_range(dev); + ret = -1; + } else { + int data_pos = 0; - if (dev->sector_pos >= cdsize) { - scsi_cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, - dev->sector_pos, cdsize); - scsi_cdrom_lba_out_of_range(dev); - return -1; - } + dev->old_len = 0; + *len = 0; -/* FIXME: Temporarily disabled this because the Triones ATAPI DMA driver seems to - always request a 4-sector read but sets the DMA bus master to transfer less - data than that. */ -#if 0 - if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { - scsi_cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, - (dev->sector_pos + dev->sector_len - 1), cdsize); - scsi_cdrom_lba_out_of_range(dev); - return -1; - } -#endif + ret = 1; - dev->old_len = 0; - *len = 0; + for (int i = 0; i < dev->requested_blocks; i++) { + ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, + dev->sector_pos + i, msf, type, + flags, &temp_len, vendor_type); - for (int i = 0; i < dev->requested_blocks; i++) { - ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, - dev->sector_pos + i, msf, type, flags, &temp_len, vendor_type); + data_pos += temp_len; + dev->old_len += temp_len; - data_pos += temp_len; - dev->old_len += temp_len; + *len += temp_len; - *len += temp_len; + if (ret == 0) { + scsi_cdrom_illegal_mode(dev); + break; + } - if (!ret) { - scsi_cdrom_illegal_mode(dev); - return 0; - } else if (ret < 0) { - scsi_cdrom_circ_error(dev); - return -1; + if (ret < 0) { + scsi_cdrom_circ_error(dev); + break; + } + } } } - return 1; + return ret; } static int -scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch, int vendor_type) +scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) { - int ret = 0; + int ret = 1; int msf = 0; - int type = 0; - int flags = 0; + int type = dev->sector_type; + int flags = dev->sector_flags; switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: @@ -1395,152 +1118,40 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch, int ven type = (dev->current_cdb[1] >> 2) & 7; flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); break; + case GPCMD_READ_HEADER: + type = 0x00; + flags = 0x20; + break; default: - type = 8; /* Internal type code indicating both Mode 1 and Mode 2 Form 1 are allowed. */ - flags = (dev->drv->sector_size == 2340) ? 0x78 : 0x10; + if (dev->sector_type == 0xff) { + scsi_cdrom_illegal_mode(dev); + ret = 0; + } break; } - if (!dev->sector_len) { - scsi_cdrom_command_complete(dev); - return -1; + if (ret) { + if (!dev->sector_len) { + scsi_cdrom_command_complete(dev); + return -1; + } + + scsi_cdrom_log(dev->log, "Reading %i blocks starting from %i...\n", + dev->requested_blocks, dev->sector_pos); + + ret = scsi_cdrom_read_data(dev, msf, type, flags, len, vendor_type); + + scsi_cdrom_log(dev->log, "Read %i bytes of blocks (ret = %i)...\n", *len, ret); } - scsi_cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); + if ((ret > 0) && (dev->current_cdb[0] != GPCMD_READ_HEADER)) { + dev->sector_pos += dev->requested_blocks; + dev->drv->seek_pos = dev->sector_pos; - ret = scsi_cdrom_read_data(dev, msf, type, flags, len, vendor_type); - - scsi_cdrom_log("Read %i bytes of blocks...\n", *len); - - if (ret == -1) - return ret; - else if (!ret || (!first_batch && (dev->old_len != *len))) { - if (!first_batch && (dev->old_len != *len)) - scsi_cdrom_illegal_mode(dev); - - return 0; + dev->sector_len -= dev->requested_blocks; } - dev->sector_pos += dev->requested_blocks; - dev->drv->seek_pos = dev->sector_pos; - dev->sector_len -= dev->requested_blocks; - return 1; -} - -/*SCSI Read DVD Structure*/ -static int -scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) -{ - int layer = packet[6]; - uint64_t total_sectors = 0; - - switch (format) { - case 0x00: /* Physical format information */ - if (dev->drv->cd_status == CD_STATUS_EMPTY) { - scsi_cdrom_not_ready(dev); - return 0; - } - - total_sectors = (uint64_t) dev->drv->cdrom_capacity; - - if (layer != 0) { - scsi_cdrom_invalid_field(dev); - return 0; - } - - total_sectors >>= 2; - if (total_sectors == 0) { - /* return -ASC_MEDIUM_NOT_PRESENT; */ - scsi_cdrom_not_ready(dev); - return 0; - } - - buf[4] = 18; /* Length of Layer Information */ - buf[5] = 0; - - buf[6] = 1; /* DVD-ROM, part version 1 */ - buf[7] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[8] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[9] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[10] = 0x00; - buf[11] = 0x03; - buf[12] = buf[13] = 0; /* start sector */ - - buf[14] = 0x00; - buf[15] = (total_sectors >> 16) & 0xff; /* end sector */ - buf[16] = (total_sectors >> 8) & 0xff; - buf[17] = total_sectors & 0xff; - - buf[18] = 0x00; - buf[19] = (total_sectors >> 16) & 0xff; /* l0 end sector */ - buf[20] = (total_sectors >> 8) & 0xff; - buf[21] = total_sectors & 0xff; - - /* 20 bytes of data + 4 byte header */ - return (20 + 4); - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4 + 2) >> 8) & 0xff; - buf[1] = (4 + 2) & 0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - scsi_cdrom_invalid_field(dev); - return 0; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 + 2) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((20 + 4) >> 8) & 0xff; - buf[7] = (20 + 4) & 0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4 + 4) >> 8) & 0xff; - buf[11] = (4 + 4) & 0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188 + 4) >> 8) & 0xff; - buf[15] = (188 + 4) & 0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048 + 4) >> 8) & 0xff; - buf[19] = (2048 + 4) & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16 + 2) >> 8) & 0xff; - buf[7] = (16 + 2) & 0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - scsi_cdrom_invalid_field(dev); - return 0; - } + return ret; } static void @@ -1554,16 +1165,16 @@ scsi_cdrom_insert(void *priv) if (dev->drv->ops == NULL) { dev->unit_attention = 0; dev->drv->cd_status = CD_STATUS_EMPTY; - scsi_cdrom_log("CD-ROM %i: Media removal\n", dev->id); + scsi_cdrom_log(dev->log, "Media removal\n"); } else if (dev->drv->cd_status & CD_STATUS_TRANSITION) { dev->unit_attention = 1; /* Turn off the medium changed status. */ dev->drv->cd_status &= ~CD_STATUS_TRANSITION; - scsi_cdrom_log("CD-ROM %i: Media insert\n", dev->id); + scsi_cdrom_log(dev->log, "Media insert\n"); } else { dev->unit_attention = 0; dev->drv->cd_status |= CD_STATUS_TRANSITION; - scsi_cdrom_log("CD-ROM %i: Media transition\n", dev->id); + scsi_cdrom_log(dev->log, "Media transition\n"); } } @@ -1578,80 +1189,76 @@ scsi_cdrom_ext_insert(void *priv, int ext_medium_changed) if ((dev->drv->ops == NULL) || (ext_medium_changed == -1)) { dev->unit_attention = 0; dev->drv->cd_status = CD_STATUS_EMPTY; - scsi_cdrom_log("CD-ROM %i: External media removal\n", dev->id); + scsi_cdrom_log(dev->log, "External media removal\n"); } else if (ext_medium_changed == 1) { dev->unit_attention = 0; dev->drv->cd_status |= CD_STATUS_TRANSITION; - scsi_cdrom_log("CD-ROM %i: External media transition\n", dev->id); + scsi_cdrom_log(dev->log, "External media transition\n"); } } static int -scsi_command_check_ready(scsi_cdrom_t *dev, uint8_t *cdb) +scsi_command_check_ready(const scsi_cdrom_t *dev, const uint8_t *cdb) { int ret = 0; if (scsi_cdrom_command_flags[cdb[0]] & CHECK_READY) { - /*Note by TC1995: Some vendor commands from X vendor don't really check for ready status - but they do on Y vendor. Quite confusing I know.*/ - if (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY) switch (dev->drv->type) { - default: - ret = 1; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - if (cdb[0] == 0xc0) - break; - ret = 1; - break; - } else + /* + Note by TC1995: Some vendor commands from X vendor don't really + check for ready status but they do on Y vendor. + Quite confusing I know. + */ + if (!dev->is_sony || (cdb[0] != 0xc0)) ret = 1; - } + } else if ((cdb[0] == GPCMD_READ_DVD_STRUCTURE) && (cdb[7] < 0xc0)) + ret = 1; return ret; } static int -scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) +scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) { - int ready = 0; - int ext_medium_changed = 0; + int ready; + const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); - if (dev->drv && dev->drv->ops && dev->drv->ops->ext_medium_changed) - ext_medium_changed = dev->drv->ops->ext_medium_changed(dev->drv); - - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->tf->request_length >> 5) & 7)); - scsi_cdrom_invalid_lun(dev); + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && + (cdb[1] & 0xe0)) { + scsi_cdrom_log(dev->log, "Attempting to execute a unknown command targeted " + "at SCSI LUN %i\n", ((dev->tf->request_length >> 5) & 7)); + scsi_cdrom_invalid_lun(dev, cdb[1] >> 5); return 0; } if (!(scsi_cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { - scsi_cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); + scsi_cdrom_log(dev->log, "Attempting to execute unknown command %02X over %s\n", + cdb[0], (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); - scsi_cdrom_illegal_opcode(dev); + scsi_cdrom_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { - scsi_cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - scsi_cdrom_illegal_opcode(dev); + if ((dev->drv->bus_type < CDROM_BUS_SCSI) && + (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { + scsi_cdrom_log(dev->log, "Attempting to execute SCSI-only command %02X over " + "ATAPI\n", cdb[0]); + scsi_cdrom_illegal_opcode(dev, cdb[0]); return 0; } - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { - scsi_cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); - scsi_cdrom_illegal_opcode(dev); + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && + (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + scsi_cdrom_log(dev->log, "Attempting to execute ATAPI-only command %02X over " + "SCSI\n", cdb[0]); + scsi_cdrom_illegal_opcode(dev, cdb[0]); return 0; } if (ext_medium_changed != 0) scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); - if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { + if ((dev->drv->cd_status == CD_STATUS_PLAYING) || + (dev->drv->cd_status == CD_STATUS_PAUSED)) { ready = 1; goto skip_ready_check; } @@ -1660,8 +1267,9 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) ready = 0; else { - if ((ext_medium_changed != 0) || !(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - scsi_cdrom_log("(ext_medium_changed != 0): scsi_cdrom_insert()\n"); + if ((ext_medium_changed != 0) || + !(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + scsi_cdrom_log(dev->log, "(ext_medium_changed != 0): scsi_cdrom_insert()\n"); scsi_cdrom_insert((void *) dev); } @@ -1671,33 +1279,42 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) ready = (dev->drv->cd_status != CD_STATUS_EMPTY); skip_ready_check: - /* If the drive is not ready, there is no reason to keep the + /* + If the drive is not ready, there is no reason to keep the UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ + disc changes. + */ if (!ready && (dev->unit_attention > 0)) dev->unit_attention = 0; - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ + /* + If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. + */ if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ + /* + Only increment the unit attention phase if the command can + not pass through it. + */ if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - scsi_cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); + scsi_cdrom_log(dev->log, "Unit attention now 2\n"); dev->unit_attention++; - scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", - dev->id, cdb[0]); + scsi_cdrom_log(dev->log, "UNIT ATTENTION: Command %02X not allowed to " + "pass through\n", cdb[0]); scsi_cdrom_unit_attention(dev); return 0; } } else if (dev->unit_attention == 2) { if (cdb[0] != GPCMD_REQUEST_SENSE) { - scsi_cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); + scsi_cdrom_log(dev->log, "Unit attention now 0\n"); dev->unit_attention = 0; } } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear - the UNIT ATTENTION condition if it's set. */ + /* + Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear + the UNIT ATTENTION condition if it's set. + */ if (cdb[0] != GPCMD_REQUEST_SENSE) scsi_cdrom_sense_clear(dev, cdb[0]); @@ -1708,12 +1325,12 @@ skip_ready_check: dev->media_status = MEC_MEDIA_REMOVAL; if (!ready && scsi_command_check_ready(dev, cdb)) { - scsi_cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); + scsi_cdrom_log(dev->log, "Not ready (%02X)\n", cdb[0]); scsi_cdrom_not_ready(dev); return 0; } - scsi_cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); + scsi_cdrom_log(dev->log, "Continuing with command %02X\n", cdb[0]); return 1; } @@ -1724,41 +1341,103 @@ scsi_cdrom_rezero(scsi_cdrom_t *dev) cdrom_seek(dev->drv, 0, 0); } +static int +scsi_cdrom_update_sector_flags(scsi_cdrom_t *dev) +{ + int ret = 0; + + switch (dev->drv->sector_size) { + default: + dev->sector_type = 0xff; + scsi_cdrom_log(dev->log, "Invalid sector size: %i\n", dev->drv->sector_size); + scsi_cdrom_invalid_field_pl(dev, dev->drv->sector_size); + ret = 1; + break; + case 128: case 256: case 512: case 2048: + /* + Internal type code indicating both Mode 1 and Mode 2 Form 1 are allowed. + Upper 4 bits indicate the divisor. + */ + dev->sector_type = 0x08 | ((2048 / dev->drv->sector_size) << 4); + dev->sector_flags = 0x0010; + break; + case 2056: + dev->sector_type = 0x18; + dev->sector_flags = 0x0050; + break; + case 2324: case 2328: + dev->sector_type = (dev->drv->sector_size == 2328) ? 0x1a : 0x1b; + dev->sector_flags = 0x0018; + break; + case 2332: case 2336: + dev->sector_type = (dev->drv->sector_size == 2336) ? 0x1c : 0x1d; + dev->sector_flags = 0x0058; + break; + case 2340: + dev->sector_type = 0x18; + dev->sector_flags = 0x0078; + break; + case 2352: + dev->sector_type = 0x00; + dev->sector_flags = 0x00f8; + break; + case 2368: + dev->sector_type = 0x00; + dev->sector_flags = 0x01f8; + break; + case 2448: + dev->sector_type = 0x00; + dev->sector_flags = 0x02f8; + break; + } + + return ret; +} + void scsi_cdrom_reset(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - if (!dev) - return; + if (dev != NULL) { + scsi_cdrom_rezero(dev); + dev->tf->status = 0; + dev->callback = 0.0; + scsi_cdrom_set_callback(dev); + dev->tf->phase = 1; + dev->tf->request_length = 0xeb14; + dev->packet_status = PHASE_NONE; + dev->unit_attention = 0xff; + dev->cur_lun = SCSI_LUN_USE_CDB; - scsi_cdrom_rezero(dev); - dev->tf->status = 0; - dev->callback = 0.0; - scsi_cdrom_set_callback(dev); - dev->tf->phase = 1; - dev->tf->request_length = 0xeb14; - dev->packet_status = PHASE_NONE; - dev->unit_attention = 0xff; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->drv->sector_size = 2048; + (void) scsi_cdrom_update_sector_flags(dev); + + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_info = 0x00000000; + dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + } } static void scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) { - /*Will return 18 bytes of 0*/ + /* Will return 18 bytes of 0x00. */ if (alloc_length != 0) { - memset(buffer, 0, alloc_length); + memset(buffer, 0x00, alloc_length); memcpy(buffer, dev->sense, alloc_length); } - buffer[0] = 0x70; + buffer[0] = 0xf0; + buffer[7] = 0x0a; if ((scsi_cdrom_sense_key > 0) && (dev->drv->cd_status == CD_STATUS_PLAYING_COMPLETED)) { buffer[2] = SENSE_ILLEGAL_REQUEST; buffer[12] = ASC_AUDIO_PLAY_OPERATION; buffer[13] = ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } else if ((scsi_cdrom_sense_key == 0) && ((dev->drv->cd_status == CD_STATUS_PAUSED) || ((dev->drv->cd_status >= CD_STATUS_PLAYING) && (dev->drv->cd_status != CD_STATUS_STOPPED)))) { + } else if ((scsi_cdrom_sense_key == 0) && + ((dev->drv->cd_status == CD_STATUS_PAUSED) || ((dev->drv->cd_status >= CD_STATUS_PLAYING) && + (dev->drv->cd_status != CD_STATUS_STOPPED)))) { buffer[2] = SENSE_ILLEGAL_REQUEST; buffer[12] = ASC_AUDIO_PLAY_OPERATION; buffer[13] = (dev->drv->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; @@ -1768,7 +1447,8 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt buffer[13] = 0; } - scsi_cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + scsi_cdrom_log(dev->log, "Reporting sense: %02X %02X %02X\n", buffer[2], buffer[12], + buffer[13]); if (buffer[2] == SENSE_UNIT_ATTENTION) { /* If the last remaining sense is unit attention, clear @@ -1777,7 +1457,7 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt } if (dev->drv->cd_status & CD_STATUS_TRANSITION) { - scsi_cdrom_log("CD_STATUS_TRANSITION: scsi_cdrom_insert()\n"); + scsi_cdrom_log(dev->log, "CD_STATUS_TRANSITION: scsi_cdrom_insert()\n"); scsi_cdrom_insert((void *) dev); } } @@ -1786,18 +1466,16 @@ void scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int ext_medium_changed = 0; - - if (dev->drv && dev->drv->ops && dev->drv->ops->ext_medium_changed) - ext_medium_changed = dev->drv->ops->ext_medium_changed(dev->drv); + const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); if (ext_medium_changed != 0) scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ + /* + If the drive is not ready, there is no reason to keep the UNIT ATTENTION + condition present, as we only use it to mark disc changes. + */ dev->unit_attention = 0; } @@ -1806,7 +1484,7 @@ scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t al } static void -scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) +scsi_cdrom_set_buf_len(const scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) { if (dev->drv->bus_type == CDROM_BUS_SCSI) { if (*BufLen == -1) @@ -1815,44 +1493,45 @@ scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) *BufLen = MIN(*src_len, *BufLen); *src_len = *BufLen; } - scsi_cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); + scsi_cdrom_log(dev->log, "Actual transfer length: %i\n", *BufLen); } } static void -scsi_cdrom_stop(scsi_common_t *sc) +scsi_cdrom_stop(const scsi_common_t *sc) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const scsi_cdrom_t *dev = (const scsi_cdrom_t *) sc; cdrom_stop(dev->drv); } static void -scsi_cdrom_set_speed(scsi_cdrom_t *dev, uint8_t *cdb) +scsi_cdrom_set_speed(scsi_cdrom_t *dev, const uint8_t *cdb) { dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; if (dev->drv->cur_speed < 1) dev->drv->cur_speed = 1; - else if (dev->drv->cur_speed > dev->drv->speed) - dev->drv->cur_speed = dev->drv->speed; + else if (dev->drv->cur_speed > dev->drv->real_speed) + dev->drv->cur_speed = dev->drv->real_speed; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); } static uint8_t -scsi_cdrom_command_chinon(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; uint8_t cmd_stat = 0x00; switch (cdb[0]) { + default: + break; + case GPCMD_UNKNOWN_CHINON: - if (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - scsi_cdrom_command_complete(dev); - cmd_stat = 0x01; - } + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; break; case GPCMD_EJECT_CHINON: @@ -1875,12 +1554,10 @@ scsi_cdrom_command_chinon(void *sc, uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int msf = 0; - int pos = dev->drv->seek_pos; - int ret = 1; + int msf; uint8_t cmd_stat = 0x00; int len; int max_len; @@ -1888,9 +1565,11 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) int real_pos; switch (cdb[0]) { + default: + break; + case GPCMD_SET_ADDRESS_FORMAT_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->sony_vendor = 1; dev->drv->sony_msf = cdb[8] & 1; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; @@ -1899,7 +1578,6 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_TOC_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); msf = dev->drv->sony_msf; - dev->sony_vendor = 1; max_len = cdb[7]; max_len <<= 8; @@ -1907,14 +1585,14 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_buf_alloc(dev, 65536); - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else { len = cdrom_read_toc_sony(dev->drv, dev->buffer, cdb[5], msf, max_len); if (len == -1) /* If the returned length is -1, this means cdrom_read_toc_sony() has encountered an error. */ - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -1925,15 +1603,14 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_SUBCHANNEL_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - dev->sony_vendor = 1; max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; msf = dev->drv->sony_msf; - scsi_cdrom_log("CD-ROM %i: Getting sub-channel type (%s), code-q = %02x\n", - dev->id, msf ? "MSF" : "LBA", cdb[2] & 0x40); + scsi_cdrom_log(dev->log, "Getting sub-channel type (%s), code-q = %02x\n", + msf ? "MSF" : "LBA", cdb[2] & 0x40); if (cdb[2] & 0x40) { scsi_cdrom_buf_alloc(dev, 9); @@ -1945,7 +1622,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: Drive Status All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "Drive Status All done - callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -1955,7 +1632,6 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_HEADER_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - dev->sony_vendor = 1; alloc_length = ((cdb[7] << 8) | cdb[8]); scsi_cdrom_buf_alloc(dev, 4); @@ -1979,7 +1655,6 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PLAYBACK_STATUS_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - dev->sony_vendor = 1; max_len = cdb[7]; max_len <<= 8; @@ -1999,7 +1674,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) &dev->buffer[6], msf); dev->buffer[5] = 0x00; - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[4]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[4]); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -2010,7 +1685,6 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PAUSE_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->sony_vendor = 1; cdrom_audio_pause_resume(dev->drv, !(cdb[1] & 0x10)); scsi_cdrom_command_complete(dev); cmd_stat = 0x01; @@ -2018,19 +1692,19 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PLAY_TRACK_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->sony_vendor = 1; msf = 3; if ((cdb[5] != 1) || (cdb[8] != 1)) scsi_cdrom_illegal_mode(dev); else { - pos = cdb[4]; + const int pos = cdb[4]; - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || + (dev->drv->cd_status <= CD_STATUS_DVD)) scsi_cdrom_illegal_mode(dev); else { /* In this case, len is unused so just pass a fixed value of 1 intead. */ - ret = cdrom_audio_play(dev->drv, pos, 1 /*len*/, msf); + const int ret = cdrom_audio_play(dev->drv, pos, 1, msf); if (ret) scsi_cdrom_command_complete(dev); @@ -2042,27 +1716,29 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) break; case GPCMD_PLAY_MSF_SONY: - cdb[0] = GPCMD_PLAY_AUDIO_MSF; - dev->current_cdb[0] = cdb[0]; - dev->sony_vendor = 1; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_MSF. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_MSF; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_MSF. + */ break; case GPCMD_PLAY_AUDIO_SONY: - cdb[0] = GPCMD_PLAY_AUDIO_10; - dev->current_cdb[0] = cdb[0]; - dev->sony_vendor = 1; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_10. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_10; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_10. + */ break; case GPCMD_PLAYBACK_CONTROL_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - dev->sony_vendor = 1; len = (cdb[7] << 8) | cdb[8]; if (len == 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: PlayBack Control Sony All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "PlayBack Control Sony All done - " + "callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2079,70 +1755,93 @@ scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_matsushita(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_matsushita(void *sc, const uint8_t *cdb, int32_t *BufLen) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - uint8_t cmd_stat = 0x00; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const uint8_t cmd_stat = 0x00; switch (cdb[0]) { + default: + break; + case GPCMD_READ_SUBCHANNEL_MATSUSHITA: - cdb[0] = GPCMD_READ_SUBCHANNEL; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_SUBCHANNEL. */ + dev->current_cdb[0] = GPCMD_READ_SUBCHANNEL; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_READ_SUBCHANNEL. + */ break; case GPCMD_READ_TOC_MATSUSHITA: - cdb[0] = GPCMD_READ_TOC_PMA_ATIP; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_TOC_PMA_ATIP. */ + dev->current_cdb[0] = GPCMD_READ_TOC_PMA_ATIP; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_READ_TOC_PMA_ATIP. + */ break; case GPCMD_READ_HEADER_MATSUSHITA: - cdb[0] = GPCMD_READ_HEADER; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_HEADER. */ + dev->current_cdb[0] = GPCMD_READ_HEADER; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_READ_HEADER. + */ break; case GPCMD_PLAY_AUDIO_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_10; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_10. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_10; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_10. + */ break; case GPCMD_PLAY_AUDIO_MSF_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_MSF; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_MSF. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_MSF; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_MSF. + */ break; case GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_INDEX; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_INDEX. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_TRACK_INDEX; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_TRACK_INDEX. + */ break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10. + */ break; case GPCMD_PAUSE_RESUME_MATSUSHITA: - cdb[0] = GPCMD_PAUSE_RESUME; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PAUSE_RESUME. */ + dev->current_cdb[0] = GPCMD_PAUSE_RESUME; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PAUSE_RESUME. + */ break; case GPCMD_PLAY_AUDIO_12_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_12; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_12. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_12; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_12. + */ break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12_MATSUSHITA: - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12; - dev->current_cdb[0] = cdb[0]; - /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12. */ + dev->current_cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12; + /* + Keep cmd_stat at 0x00, therefore, it's going to process it + as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12. + */ break; } @@ -2150,16 +1849,19 @@ scsi_cdrom_command_matsushita(void *sc, uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int pos = dev->drv->seek_pos; - int ret = 1; uint8_t cmd_stat = 0x00; + int pos; + int ret; int len; int alloc_length; switch (cdb[0]) { + default: + break; + case GPCMD_NO_OPERATION_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); @@ -2174,7 +1876,7 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) scsi_cdrom_illegal_mode(dev); else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; @@ -2191,7 +1893,7 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PLAY_AUDIO_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) ret = 0; else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; @@ -2234,11 +1936,11 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) alloc_length = cdb[1] & 0x1f; len = 10; - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else if (alloc_length <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: Subcode Q All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "Subcode Q All done - callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2248,7 +1950,7 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); dev->buffer[0] = cdrom_get_current_subcodeq_playstatus(dev->drv, &dev->buffer[1]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -2264,17 +1966,14 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) */ scsi_cdrom_buf_alloc(dev, 22); - if (!dev->drv->ops) - scsi_cdrom_not_ready(dev); - else { - ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - len = 22; - if (ret) { - scsi_cdrom_set_buf_len(dev, BufLen, &len); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); - } else - scsi_cdrom_invalid_field(dev); - } + ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); + len = 22; + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } else + scsi_cdrom_invalid_field(dev, dev->drv->inv_field); + cmd_stat = 0x01; break; } @@ -2283,17 +1982,20 @@ scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int pos = dev->drv->seek_pos; - int ret = 1; uint8_t cmd_stat = 0x00; + int pos; + int ret; int len; int max_len; int alloc_length; switch (cdb[0]) { + default: + break; + case GPCMD_MAGAZINE_EJECT_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); @@ -2306,7 +2008,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_cdrom_buf_alloc(dev, 4); - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else { ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); @@ -2316,7 +2018,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, dev->drv->inv_field); } cmd_stat = 0x01; break; @@ -2327,11 +2029,11 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) alloc_length = cdb[1] & 0x1f; len = 9; - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else if (!alloc_length) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: Subcode Q All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "Subcode Q All done - callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2341,7 +2043,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); cdrom_get_current_subcodeq(dev->drv, &dev->buffer[1]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -2351,7 +2053,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) ret = 0; else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; @@ -2370,7 +2072,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PLAY_AUDIO_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) ret = 0; else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; @@ -2412,7 +2114,7 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, 6); dev->buffer[0] = cdrom_get_audio_status_pioneer(dev->drv, &dev->buffer[1]); /*Audio status*/ - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[4]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[4]); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -2428,10 +2130,10 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_buf_alloc(dev, 65536); if (!(scsi_cdrom_drive_status_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, cdb[2]); else if (len <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: Drive Status All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "Drive Status All done - callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2439,12 +2141,13 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); alloc_length = len; - len = scsi_cdrom_drive_status(dev, dev->buffer, 0, cdb[2]); + len = scsi_cdrom_drive_status(dev, dev->buffer, cdb[2]); len = MIN(len, alloc_length); scsi_cdrom_set_buf_len(dev, BufLen, &len); - scsi_cdrom_log("CD-ROM %i: Reading drive status page: %02X...\n", dev->id, cdb[2]); + scsi_cdrom_log(dev->log, "Reading drive status page: %02X...\n", + cdb[2]); scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); } @@ -2456,16 +2159,19 @@ scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int pos = dev->drv->seek_pos; - int ret = 1; uint8_t cmd_stat = 0x00; + int pos; + int ret; int len; int alloc_length; switch (cdb[0]) { + default: + break; + case GPCMD_NO_OPERATION_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); @@ -2474,7 +2180,7 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) { scsi_cdrom_illegal_mode(dev); break; } @@ -2492,7 +2198,7 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) case GPCMD_PLAY_AUDIO_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) scsi_cdrom_illegal_mode(dev); else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; @@ -2534,11 +2240,11 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) alloc_length = cdb[1] & 0x1f; len = 10; - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else if (alloc_length <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: Subcode Q All done - callback set\n", dev->id); + scsi_cdrom_log(dev->log, "Subcode Q All done - callback set\n"); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2548,7 +2254,7 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); dev->buffer[0] = cdrom_get_current_subcodeq_playstatus(dev->drv, &dev->buffer[1]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -2560,7 +2266,7 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_cdrom_buf_alloc(dev, 4); - if (!dev->drv->ops) + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); else { ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); @@ -2569,7 +2275,7 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, dev->drv->inv_field); } cmd_stat = 0x01; break; @@ -2579,22 +2285,19 @@ scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) } void -scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) +scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int msf = 0; int pos = dev->drv->seek_pos; int idx = 0; - int block_desc = 0; int ret = 1; - int format = 0; - int track = 0; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int32_t blen = 0; uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + char model[2048] = { 0 }; + int msf; + int block_desc; int len; int max_len; int used_len; @@ -2603,9 +2306,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) uint32_t feature; unsigned preamble_len; int toc_format; - int real_pos; int32_t *BufLen; - uint8_t *b; if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; @@ -2618,33 +2319,29 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; - device_identify[7] = dev->id + 0x30; - - device_identify_ex[7] = dev->id + 0x30; - device_identify_ex[10] = EMU_VERSION_EX[0]; - device_identify_ex[12] = EMU_VERSION_EX[2]; - device_identify_ex[13] = EMU_VERSION_EX[3]; - memcpy(dev->current_cdb, cdb, 12); - dev->sony_vendor = 0; - // if (cdb[0] != 0) { - scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", - dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, - dev->unit_attention); - scsi_cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->tf->request_length); +#if ENABLE_SCSI_CDROM_LOG == 2 + scsi_cdrom_log(dev->log, "Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, " + "Unit attention: %i\n", cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, + scsi_cdrom_ascq, dev->unit_attention); + scsi_cdrom_log(dev->log, "Request length: %04X\n", dev->tf->request_length); - scsi_cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - dev->id, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + scsi_cdrom_log(dev->log, "CDB: %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X\n", + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); - // } +#endif msf = cdb[1] & 2; dev->sector_len = 0; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + /* + This handles the Not Ready/Unit Attention check if it has to be + handled at this point. + */ if (scsi_cdrom_pre_execution_check(dev, cdb) == 0) return; @@ -2653,7 +2350,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_sense_clear(dev, cdb[0]); } - if ((dev->ven_cmd == NULL) || (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (cdb[0]) { + if ((dev->ven_cmd == NULL) || (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (dev->current_cdb[0]) { case GPCMD_TEST_UNIT_READY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); @@ -2668,8 +2365,6 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); max_len = cdb[4]; @@ -2695,7 +2390,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_AUDIO_SCAN: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + if ((dev->drv->image_path[0] == 0x00) || + (dev->drv->cd_status <= CD_STATUS_DVD)) { scsi_cdrom_illegal_mode(dev); break; } @@ -2737,22 +2433,19 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; - if (!dev->drv->ops) { + if (dev->drv->ops == NULL) scsi_cdrom_not_ready(dev); - return; - } - - if (toc_format < 3) { + else if (toc_format < 3) { len = cdrom_read_toc(dev->drv, dev->buffer, toc_format, cdb[6], msf, max_len); /* If the returned length is -1, this means cdrom_read_toc() has encountered an error. */ if (len == -1) - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } } else - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, toc_format); break; case GPCMD_READ_6: @@ -2763,32 +2456,38 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_READ_CD: case GPCMD_READ_CD_MSF: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = 2048; + alloc_length = dev->drv->sector_size; switch (cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; - /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sectors. */ + /* + For READ (6) and WRITE (6), a length of 0 indicates a transfer of + 256 sectors. + */ if (dev->sector_len == 0) dev->sector_len = 256; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | - ((uint32_t) cdb[3]); - scsi_cdrom_log("CD-ROM %i: READ (6): Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | + (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_cdrom_log(dev->log, "READ (6): Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_cdrom_log("CD-ROM %i: READ (10): Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + scsi_cdrom_log(dev->log, "READ (10): Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - scsi_cdrom_log("CD-ROM %i: READ (12): Length: %i, LBA: %i\n", dev->id, dev->sector_len, - dev->sector_pos); + scsi_cdrom_log(dev->log, "READ (12): Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); break; case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD_MSF: @@ -2806,15 +2505,20 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len++; } else { dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; } - if (((cdb[9] & 0xf8) == 0x08) || ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00))) { + if (((cdb[9] & 0xf8) == 0x08) || ((cdb[9] == 0x00) && + ((cdb[10] & 0x07) != 0x00))) { /* Illegal mode */ - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, cdb[9]); ret = 0; } else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) - /* If all the flag bits are cleared, then treat it as a non-data command. */ + /* + If all the flag bits are cleared, then treat it as a + non-data command. + */ dev->sector_len = 0; break; @@ -2825,39 +2529,30 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (ret) { if (dev->sector_len > 0) { max_len = dev->sector_len; - dev->requested_blocks = max_len; /* - If we're reading all blocks in one go for DMA, - why not also for PIO, it should NOT matter - anyway, this step should be identical and only - the way the read dat is transferred to the host - should be different. - */ + dev->requested_blocks = max_len; dev->packet_len = max_len * alloc_length; scsi_cdrom_buf_alloc(dev, dev->packet_len); dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); + dev->drv->seek_pos = dev->sector_pos; - if ((cdb[0] == GPCMD_READ_10) || (cdb[0] == GPCMD_READ_12)) { - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, cdb[9] & 0xc0); - break; - default: - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); - break; - } - } else - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); + if (dev->use_cdb_9 && ((cdb[0] == GPCMD_READ_10) || + (cdb[0] == GPCMD_READ_12))) + ret = scsi_cdrom_read_blocks(dev, &alloc_length, + cdb[9] & 0xc0); + else + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); if (ret > 0) { dev->requested_blocks = max_len; dev->packet_len = alloc_length; - scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + scsi_cdrom_set_buf_len(dev, BufLen, + (int32_t *) &dev->packet_len); - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + scsi_cdrom_data_command_finish(dev, alloc_length, + alloc_length / dev->requested_blocks, alloc_length, 0); if (dev->packet_status != PHASE_COMPLETE) @@ -2872,7 +2567,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } } else { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + /* scsi_cdrom_log(dev->log, "All done - callback set\n"); */ dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); @@ -2882,39 +2577,80 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_READ_HEADER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 2352; - alloc_length = ((cdb[7] << 8) | cdb[8]); - scsi_cdrom_buf_alloc(dev, 8); - + len = (cdb[7] << 8) | cdb[8]; dev->sector_len = 1; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if (msf) - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - else - real_pos = dev->sector_pos; - dev->buffer[0] = 1; /*2048 bytes user data*/ - dev->buffer[1] = dev->buffer[2] = dev->buffer[3] = 0; - dev->buffer[4] = (real_pos >> 24); - dev->buffer[5] = ((real_pos >> 16) & 0xff); - dev->buffer[6] = ((real_pos >> 8) & 0xff); - dev->buffer[7] = real_pos & 0xff; + scsi_cdrom_log(dev->log, "READ HEADER: Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); - len = 8; - len = MIN(len, alloc_length); + if (len > 0) { + max_len = 1; + dev->requested_blocks = max_len; - scsi_cdrom_set_buf_len(dev, BufLen, &len); + dev->packet_len = len; + scsi_cdrom_buf_alloc(dev, 2352); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); + dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); + dev->drv->seek_pos = dev->sector_pos; + + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); + + if (ret > 0) { + uint8_t header[4] = { 0 }; + + memcpy(header, dev->buffer, 4); + + dev->buffer[0] = header[3]; + + if (cdb[1] & 0x02) { + memset(&(dev->buffer[1]), 0x00, 4); + dev->buffer[5] = header[0]; + dev->buffer[6] = header[1]; + dev->buffer[7] = header[2]; + } else { + memset(&(dev->buffer[1]), 0x00, 3); + uint32_t lba = ((header[0] * 60 * 75) + + (header[1] * 75) + + header[2]) - 150; + dev->buffer[4] = (lba >> 24) & 0xff; + dev->buffer[5] = (lba >> 16) & 0xff; + dev->buffer[6] = (lba >> 8) & 0xff; + dev->buffer[7] = lba & 0xff; + } + + len = MIN(8, len); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, + len, 0); + + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log(dev->log, "All done - callback set\n"); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else + if (dev->drv->bus_type == CDROM_BUS_ATAPI) block_desc = 0; + else + block_desc = !((cdb[1] >> 3) & 1); if (cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; @@ -2924,32 +2660,23 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); } - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - if (!(scsi_cdrom_mode_sense_page_flags_sony & (1LL << (uint64_t) (cdb[2] & 0x3f)))) - ret = 0; - break; - default: - if (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) - ret = 0; - break; - } + if (!(dev->ms_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) + ret = 0; if (ret == 1) { memset(dev->buffer, 0, len); alloc_length = len; - /* This determines the media type ID to return - this is - a SCSI/ATAPI-specific thing, so it makes the most sense - to keep this here. - Also, the max_len variable is reused as this command - does otherwise not use it, to avoid having to declare - another variable. */ + /* + This determines the media type ID to return which is a SCSI/ATAPI-specific + thing, so it makes the most sense to keep this here. + + Also, the max_len variable is reused as this command does otherwise not + use it, to avoid having to declare another variable. + */ if (dev->drv->cd_status == CD_STATUS_EMPTY) max_len = 70; /* No media inserted. */ - else if (dev->drv->cdrom_capacity > CD_MAX_SECTORS) + else if (dev->drv->cd_status == CD_STATUS_DVD) max_len = 65; /* DVD. */ else if (dev->drv->cd_status == CD_STATUS_DATA_ONLY) max_len = 1; /* Data CD. */ @@ -2964,7 +2691,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (block_desc) dev->buffer[3] = 8; } else { - len = scsi_cdrom_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); + len = scsi_cdrom_mode_sense(dev, dev->buffer, 8, + cdb[2], block_desc); len = MIN(len, alloc_length); dev->buffer[0] = (len - 2) >> 8; dev->buffer[1] = (len - 2) & 255; @@ -2977,11 +2705,11 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + scsi_cdrom_log(dev->log, "Reading mode page: %02X...\n", cdb[2]); scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); } else - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, cdb[2]); break; case GPCMD_MODE_SELECT_6: @@ -3014,21 +2742,17 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) /* Only feature 0 is supported */ if ((feature > 3) && (feature != 0x010) && (feature != 0x1d) && (feature != 0x01e) && (feature != 0x01f) && (feature != 0x103)) - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, feature); else { scsi_cdrom_buf_alloc(dev, 65536); memset(dev->buffer, 0, max_len); - alloc_length = 0; - b = dev->buffer; + uint8_t *b = dev->buffer; + + alloc_length = 0; - /* - The number of sectors from the media tells us which profile - to use as current. 0 means there is no media. - */ if (dev->drv->cd_status != CD_STATUS_EMPTY) { - len = dev->drv->cdrom_capacity; - if (len > CD_MAX_SECTORS) { + if (dev->drv->cd_status == CD_STATUS_DVD) { b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; b[7] = MMC_PROFILE_DVD_ROM & 0xff; ret = 1; @@ -3044,7 +2768,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) b += 8; if ((feature == 0) || ((cdb[1] & 3) < 2)) { - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (0 << 2) | 0x02 | 0x01; b[3] = 8; alloc_length += 4; @@ -3062,8 +2787,9 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } } if ((feature == 1) || ((cdb[1] & 3) < 2)) { + /* Persistent and current. */ b[1] = 1; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[2] = (2 << 2) | 0x02 | 0x01; b[3] = 8; if (dev->drv->bus_type == CDROM_BUS_SCSI) @@ -3086,25 +2812,18 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } if ((feature == 3) || ((cdb[1] & 3) < 2)) { b[1] = 2; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (0 << 2) | 0x02 | 0x01; b[3] = 4; - b[4] = 0x0d; - - /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and - early vendor SCSI CD-ROM models) are caddy drives, the later - ones are tray drives. */ - if (dev->drv->bus_type == CDROM_BUS_SCSI) - b[4] |= ((dev->drv->type == CDROM_TYPE_86BOX_100) ? 0x20 : 0x00); - else - b[4] |= ((dev->drv->type == CDROM_TYPE_NEC_260_100) || - ((dev->drv->type == CDROM_TYPE_NEC_260_101)) ? 0x00 : 0x20); + b[4] = 0x0d | (cdrom_is_caddy(dev->drv->type) ? 0x00 : 0x20); alloc_length += 8; b += 8; } if ((feature == 0x10) || ((cdb[1] & 3) < 2)) { b[1] = 0x10; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (0 << 2) | 0x02 | 0x01; b[3] = 8; b[6] = 8; @@ -3115,7 +2834,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } if ((feature == 0x1d) || ((cdb[1] & 3) < 2)) { b[1] = 0x1d; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (0 << 2) | 0x02 | 0x01; b[3] = 0; alloc_length += 4; @@ -3123,7 +2843,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } if ((feature == 0x1e) || ((cdb[1] & 3) < 2)) { b[1] = 0x1e; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (2 << 2) | 0x02 | 0x01; b[3] = 4; b[4] = 0; @@ -3141,14 +2862,14 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if ((feature == 0x103) || ((cdb[1] & 3) < 2)) { b[0] = 1; b[1] = 3; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + /* Persistent and current. */ + b[2] = (0 << 2) | 0x02 | 0x01; b[3] = 0; b[4] = 7; b[6] = 1; alloc_length += 8; - b += 8; } dev->buffer[0] = ((alloc_length - 4) >> 24) & 0xff; @@ -3160,7 +2881,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, + alloc_length, 0); } break; @@ -3174,37 +2896,40 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (gesn_cdb->polled & 0x01) { /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. + These are the supported events. + + We currently only support requests of the 'media' type. + Notification class requests and supported event classes are bitmasks, + but they are built from the same values as the "notification class" + field. */ gesn_event_header->supported_events = 1 << GESN_MEDIA; /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. + We use |= below to set the class field; other bits in this byte + are reserved now but this is useful to do if we have to use the + reserved fields later. */ gesn_event_header->notification_class = 0; /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. + Responses to requests are to be based on request priority. The + notification_class_request_type enum above specifies the + priority: upper elements are higher prio than lower ones. */ if (gesn_cdb->class & (1 << GESN_MEDIA)) { gesn_event_header->notification_class |= GESN_MEDIA; - dev->buffer[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ - dev->buffer[5] = 1; /* Power Status (1 = Active) */ + /* Bits 7-4 = Reserved, Bits 4-1 = Media Status. */ + dev->buffer[4] = dev->media_status; + /* Power Status (1 = Active). */ + dev->buffer[5] = 1; dev->buffer[6] = 0; dev->buffer[7] = 0; used_len = 8; } else { - gesn_event_header->notification_class = 0x80; /* No event available */ + /* No event available. */ + gesn_event_header->notification_class = 0x80; used_len = sizeof(*gesn_event_header); } gesn_event_header->len = used_len - sizeof(*gesn_event_header); @@ -3214,14 +2939,12 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &used_len); scsi_cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); - } else { + } else /* Only polling is supported, asynchronous mode is not. It is fine by the MMC spec to not support async mode operations. */ - scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - } + scsi_cdrom_invalid_field(dev, gesn_cdb->polled); break; case GPCMD_READ_DISC_INFORMATION: @@ -3233,16 +2956,9 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); - memset(dev->buffer, 0, 34); - memset(dev->buffer, 1, 9); - dev->buffer[0] = 0; - dev->buffer[1] = 32; - dev->buffer[2] = 0xe; /* last session complete, disc finalized */ - dev->buffer[7] = 0x20; /* unrestricted use */ - dev->buffer[8] = 0x00; /* CD-ROM */ + cdrom_read_disc_information(dev->drv, dev->buffer); - len = 34; - len = MIN(len, max_len); + len = MIN(34, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -3258,32 +2974,10 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); - track = ((uint32_t) cdb[2]) << 24; - track |= ((uint32_t) cdb[3]) << 16; - track |= ((uint32_t) cdb[4]) << 8; - track |= (uint32_t) cdb[5]; + ret = cdrom_read_track_information(dev->drv, cdb, dev->buffer); - if (((cdb[1] & 0x03) != 1) || (track != 1)) - scsi_cdrom_invalid_field(dev); - else { - len = 36; - - memset(dev->buffer, 0, 36); - dev->buffer[0] = 0; - dev->buffer[1] = 34; - dev->buffer[2] = 1; /* track number (LSB) */ - dev->buffer[3] = 1; /* session number (LSB) */ - dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | /* not reserved track, not blank, */ - (0 << 6) | (1 << 0); /* not packet writing, not fixed packet, */ - /* data mode 1 */ - dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, */ - /* next recordable address not valid */ - - dev->buffer[24] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; /* track size */ - dev->buffer[25] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; /* track size */ - dev->buffer[26] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; /* track size */ - dev->buffer[27] = (dev->drv->cdrom_capacity - 1) & 0xff; /* track size */ + if (ret > 0) { + len = ret; if (len > max_len) { len = max_len; @@ -3293,7 +2987,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); - } + } else + scsi_cdrom_invalid_field(dev, -ret); break; case GPCMD_PLAY_AUDIO_10: @@ -3345,7 +3040,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) break; } - if (ret && (dev->drv->image_path[0] != 0x00) && (dev->drv->cd_status > CD_STATUS_DATA_ONLY)) + if (ret && (dev->drv->image_path[0] != 0x00) && + (dev->drv->cd_status > CD_STATUS_DVD)) ret = cdrom_audio_play(dev->drv, pos, len, msf); else ret = 0; @@ -3366,13 +3062,14 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 32); - scsi_cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); + scsi_cdrom_log(dev->log, "Getting page %i (%s)\n", cdb[3], + msf ? "MSF" : "LBA"); - if (cdb[3] > 3) { - /* scsi_cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, - cdb[3]); */ - scsi_cdrom_invalid_field(dev); - } else if (max_len <= 0) { + if (cdb[3] > 3) + scsi_cdrom_invalid_field(dev, cdb[3]); + else if ((cdb[3] != 3) && (cdb[6] != 0)) + scsi_cdrom_invalid_field(dev, cdb[6]); + else if (max_len <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; @@ -3382,7 +3079,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) alloc_length = 4; else switch (cdb[3]) { case 0: - /* SCSI-2: Q-type subchannel, ATAPI: reserved */ + /* SCSI-2: Q-type subchannel, ATAPI: reserved. */ alloc_length = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 48 : 4; break; case 1: @@ -3404,32 +3101,14 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[pos++] = cdb[3]; /* Format code */ if (alloc_length != 4) { - dev->buffer[1] = cdrom_get_current_status(dev->drv); - cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); dev->buffer[2] = alloc_length - 4; } - switch (dev->drv->cd_status) { - case CD_STATUS_PLAYING: - dev->buffer[1] = 0x11; - break; - case CD_STATUS_PAUSED: - dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || - (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x15 : 0x12; - break; - case CD_STATUS_DATA_ONLY: - dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || - (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x00 : 0x15; - break; - default: - dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || - (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x00 : 0x13; - break; - } + dev->buffer[1] = cdrom_get_current_status(dev->drv); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[1]); + scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[1]); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -3445,23 +3124,29 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, alloc_length); - if ((cdb[7] < 0xc0) && (dev->drv->cdrom_capacity <= CD_MAX_SECTORS)) - scsi_cdrom_incompatible_format(dev); + if ((cdb[7] < 0xc0) && (dev->drv->cd_status != CD_STATUS_DVD)) + scsi_cdrom_incompatible_format(dev, cdb[7]); else { memset(dev->buffer, 0, alloc_length); if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + uint32_t info = 0x00000000; + if (cdb[1] == 0) { - format = cdb[7]; - ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, dev->buffer); - dev->buffer[0] = (ret >> 8); - dev->buffer[1] = (ret & 0xff); - dev->buffer[2] = dev->buffer[3] = 0x00; - if (ret) { + ret = cdrom_read_dvd_structure(dev->drv, cdb[6], cdb[7], dev->buffer, &info); + if (ret > 0) { + dev->buffer[0] = (ret >> 8); + dev->buffer[1] = (ret & 0xff); + dev->buffer[2] = dev->buffer[3] = 0x00; + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, + scsi_cdrom_data_command_finish(dev, alloc_length, + alloc_length, alloc_length, 0); - } else { + } else if (ret < 0) + scsi_cdrom_error_common(dev, (ret >> 16) & 0xff, + (ret >> 8) & 0xff, ret & 0xff, info); + else { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; @@ -3469,7 +3154,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } } } else - scsi_cdrom_invalid_field(dev); + scsi_cdrom_invalid_field(dev, cdb[7]); } break; @@ -3481,8 +3166,10 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_stop(sc); break; case 1: /* Start the disc and read the TOC. */ - /* This makes no sense under emulation as this would do - absolutely nothing, so just break. */ + /* + This makes no sense under emulation as this would do + absolutely nothing, so just break. + */ break; case 2: /* Eject the disc if possible. */ scsi_cdrom_stop(sc); @@ -3512,11 +3199,15 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) preamble_len = 4; size_idx = 3; - dev->buffer[idx++] = 5; - dev->buffer[idx++] = cdb[2]; - dev->buffer[idx++] = 0; + if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) + dev->buffer[idx++] = 0x7f; /* No physical device on this LUN */ + else + dev->buffer[idx++] = 0x05; /* CD-ROM */ - idx++; + dev->buffer[idx++] = cdb[2]; + + dev->buffer[idx++] = 0x00; + dev->buffer[idx++] = 0x00; switch (cdb[2]) { case 0x00: @@ -3525,7 +3216,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) break; case 0x83: if (idx + 24 > max_len) { - scsi_cdrom_data_phase_error(dev); + scsi_cdrom_data_phase_error(dev, idx + 24); scsi_cdrom_buf_free(dev); return; } @@ -3533,37 +3224,33 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[idx++] = 0x02; dev->buffer[idx++] = 0x00; dev->buffer[idx++] = 0x00; - dev->buffer[idx++] = 20; - ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ + dev->buffer[idx++] = 0x14; + ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ idx += 20; if (idx + 72 > cdb[4]) goto atapi_out; + dev->buffer[idx++] = 0x02; dev->buffer[idx++] = 0x01; dev->buffer[idx++] = 0x00; - dev->buffer[idx++] = 68; - - if (dev->drv->type == CDROM_TYPE_86BOX_100) - ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ - else - ide_padstr8(dev->buffer + idx, 8, cdrom_drive_types[dev->drv->type].vendor); /* Vendor */ + dev->buffer[idx++] = 34; + ide_padstr8(dev->buffer + idx, 8, + cdrom_get_vendor(dev->drv->type)); /* Vendor */ idx += 8; - if (dev->drv->type == CDROM_TYPE_86BOX_100) - ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ - else - ide_padstr8(dev->buffer + idx, 40, cdrom_drive_types[dev->drv->type].model); /* Product */ + cdrom_get_model(dev->drv->type, model, dev->id); + ide_padstr8(dev->buffer + idx, 16, model); /* Product */ + idx += 16; - idx += 40; - ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ - idx += 20; + ide_padstr8(dev->buffer + idx, 10, "53R141"); /* Serial */ + idx += 10; break; default: - scsi_cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - scsi_cdrom_invalid_field(dev); + scsi_cdrom_log(dev->log, "INQUIRY: Invalid page: %02X\n", cdb[2]); + scsi_cdrom_invalid_field(dev, cdb[2]); scsi_cdrom_buf_free(dev); return; } @@ -3575,99 +3262,44 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) dev->buffer[0] = 0x7f; /* No physical device on this LUN */ else - dev->buffer[0] = 5; /* CD-ROM */ + dev->buffer[0] = 0x05; /* CD-ROM */ + dev->buffer[1] = 0x80; /* Removable */ if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->buffer[3] = 0x02; - switch (dev->drv->type) { - case CDROM_TYPE_CHINON_CDS431_H42: - case CDROM_TYPE_CHINON_CDX435_M62: - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_MATSHITA_501_10b: - case CDROM_TYPE_ShinaKen_DM3x1S_104: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_TEXEL_DM3024_100: - dev->buffer[2] = 0x00; - dev->buffer[3] = 0x01; /* SCSI-1 compliant */ - break; - case CDROM_TYPE_TEXEL_DM3028_106: - dev->buffer[2] = 0x02; - dev->buffer[3] = 0x01; /* SCSI-2 compliant */ - break; - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - dev->buffer[3] = 0x00; /* SCSI unknown version per NEC manuals */ - break; - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - dev->buffer[2] = 0x01; - dev->buffer[3] = 0x01; /* SCSI-1 compliant */ - break; - default: - dev->buffer[2] = 0x02; /* SCSI-2 compliant */ - break; - } + dev->buffer[3] = cdrom_get_scsi_std(dev->drv->type); + + if (!strcmp(cdrom_get_vendor(dev->drv->type), "TOSHIBA")) + /* Linked Command and Relative Addressing supported */ + dev->buffer[7] = 0x88; } else { dev->buffer[2] = 0x00; dev->buffer[3] = 0x21; } - dev->buffer[4] = 31; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_XM5701TA_3136: - dev->buffer[4] = 91; /* - Always 91 on Toshiba SCSI-1 (or SCSI-2) - CD-ROM drives from 1989-1990 - */ - dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ - break; - case CDROM_TYPE_PIONEER_DRM604X_2403: - dev->buffer[4] = 42; - break; - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - break; - default: - dev->buffer[6] = 0x01; /* 16-bit transfers supported */ - dev->buffer[7] = 0x20; /* Wide bus supported */ - break; - } + if (cdrom_is_generic(dev->drv->type)) { + dev->buffer[6] = 0x01; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ } - if (dev->drv->type == CDROM_TYPE_86BOX_100) { - ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ - } else { - ide_padstr8(dev->buffer + 8, 8, cdrom_drive_types[dev->drv->type].vendor); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, cdrom_drive_types[dev->drv->type].model); /* Product */ - ide_padstr8(dev->buffer + 32, 4, cdrom_drive_types[dev->drv->type].revision); /* Revision */ - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_2403) { - dev->buffer[36] = 0x20; - ide_padstr8(dev->buffer + 37, 10, "1991/01/01"); /* Date */ - } + ide_padstr8(dev->buffer + 8, 8, + cdrom_get_vendor(dev->drv->type)); /* Vendor */ + cdrom_get_model(dev->drv->type, model, dev->id); + ide_padstr8(dev->buffer + 16, 16, model); /* Product */ + ide_padstr8(dev->buffer + 32, 4, + cdrom_get_revision(dev->drv->type)); /* Revision */ + + if (cdrom_has_date(dev->drv->type)) { + dev->buffer[36] = 0x20; + ide_padstr8(dev->buffer + 37, 10, "1991/01/01"); /* Date */ } - idx = 36; - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_2403) - idx = 47; - else { - switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_XM5701TA_3136: - idx = 96; - break; - default: - if (max_len == 96) { - dev->buffer[4] = 91; - idx = 96; - } - break; - } - } + if (max_len == 96) + idx = 96; + else + idx = cdrom_get_inquiry_len(dev->drv->bus_type); + + dev->buffer[4] = idx - 5; } atapi_out: @@ -3677,7 +3309,8 @@ atapi_out: len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &max_len); - scsi_cdrom_log("Inquiry = %d, max = %d, BufLen = %d.\n", len, max_len, *BufLen); + scsi_cdrom_log(dev->log, "Inquiry = %d, max = %d, BufLen = %d.\n", len, + max_len, *BufLen); scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); break; @@ -3712,17 +3345,9 @@ atapi_out: dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); - if (cdb[0] == GPCMD_SEEK_10) { - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: - cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); - break; - default: - cdrom_seek(dev->drv, pos, 0); - break; - } - } else + if (dev->use_cdb_9 && (cdb[0] == GPCMD_SEEK_10)) + cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); + else cdrom_seek(dev->drv, pos, 0); scsi_cdrom_command_complete(dev); @@ -3742,7 +3367,8 @@ atapi_out: dev->buffer[6] = 8; len = 8; - scsi_cdrom_log("CD-ROM Capacity=%x.\n", dev->drv->cdrom_capacity - 1); + scsi_cdrom_log(dev->log, "CD-ROM Capacity: %08X\n", + dev->drv->cdrom_capacity - 1); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -3751,7 +3377,7 @@ atapi_out: case GPCMD_STOP_PLAY_SCAN: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if (dev->drv->cd_status <= CD_STATUS_DATA_ONLY) { + if (dev->drv->cd_status <= CD_STATUS_DVD) { scsi_cdrom_illegal_mode(dev); break; } @@ -3761,11 +3387,11 @@ atapi_out: break; default: - scsi_cdrom_illegal_opcode(dev); + scsi_cdrom_illegal_opcode(dev, cdb[0]); break; } - /* scsi_cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->tf->phase, + /* scsi_cdrom_log(dev->log, "Phase: %02X, request length: %i\n", dev->tf->phase, dev->tf->request_length); */ if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) @@ -3789,15 +3415,14 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) uint16_t block_desc_len; uint16_t pos; uint16_t param_list_len; - uint16_t i = 0; - - uint8_t error = 0; - uint8_t page; - uint8_t page_len; - uint8_t hdr_len; - uint8_t val; - uint8_t old_val; - uint8_t ch; + uint16_t i; + uint8_t error = 0; + uint8_t page; + uint8_t page_len; + uint8_t hdr_len; + uint8_t val; + uint8_t old_val; + uint8_t ch; switch (dev->current_cdb[0]) { case GPCMD_MODE_SELECT_6: @@ -3817,7 +3442,8 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) block_desc_len = dev->buffer[2]; block_desc_len <<= 8; block_desc_len |= dev->buffer[3]; - scsi_cdrom_log("BlockDescLen (6)=%d, ParamListLen (6)=%d.\n", block_desc_len, param_list_len); + scsi_cdrom_log(dev->log, "BlockDescLen (6): %d, " + "ParamListLen (6): %d\n", block_desc_len, param_list_len); } else { block_desc_len = dev->buffer[6]; block_desc_len <<= 8; @@ -3829,21 +3455,28 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) if (block_desc_len >= 8) { pos = hdr_len + 5; - dev->drv->sector_size = (dev->drv->sector_size & 0x0000ffff) | (dev->buffer[pos++] << 16); - dev->drv->sector_size = (dev->drv->sector_size & 0x00ff00ff) | (dev->buffer[pos++] << 8); - dev->drv->sector_size = (dev->drv->sector_size & 0x00ffff00) | (dev->buffer[pos++]); - scsi_cdrom_log("CD-ROM %i: Sector size now %i bytes\n", dev->id, dev->drv->sector_size); + dev->drv->sector_size = (dev->drv->sector_size & 0x0000ffff) | + (dev->buffer[pos++] << 16); + dev->drv->sector_size = (dev->drv->sector_size & 0x00ff00ff) | + (dev->buffer[pos++] << 8); + dev->drv->sector_size = (dev->drv->sector_size & 0x00ffff00) | + (dev->buffer[pos]); + scsi_cdrom_log(dev->log, "Sector size now %i bytes\n", + dev->drv->sector_size); + + error |= scsi_cdrom_update_sector_flags(dev); } pos = hdr_len + block_desc_len; #ifdef ENABLE_SCSI_CDROM_LOG for (uint16_t j = 0; j < pos; j++) - scsi_cdrom_log("Buffer Mode Select, pos=%d, data=%02x.\n", j, dev->buffer[j]); + scsi_cdrom_log(dev->log, "Buffer Mode Select, pos=%d, data=%02x.\n", + j, dev->buffer[j]); #endif - while (1) { + if (!error) while (1) { if (pos >= param_list_len) { - scsi_cdrom_log("CD-ROM %i: Buffer has only block descriptor\n", dev->id); + scsi_cdrom_log(dev->log, "Buffer has only block descriptor\n"); break; } @@ -3852,71 +3485,39 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - if ((page == 0x08) && (page_len == 0x02)) - dev->drv->sony_msf = dev->buffer[pos] & 0x01; + if (dev->is_sony && (page == 0x08) && (page_len == 0x02)) + dev->drv->sony_msf = dev->buffer[pos] & 0x01; - if (!(scsi_cdrom_mode_sense_page_flags_sony & (1LL << ((uint64_t) page)))) { - scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); - error |= 1; - } else { - for (i = 0; i < page_len; i++) { - ch = scsi_cdrom_mode_sense_pages_changeable_sony.pages[page][i + 2]; - val = dev->buffer[pos + i]; - old_val = dev->ms_pages_saved_sony.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved_sony.pages[page][i + 2] = val; - else { - scsi_cdrom_log("CD-ROM %i: Unchangeable value on position " - "%02X on page %02X\n", dev->id, i + 2, page); - error |= 1; - } - } + if (!(dev->ms_page_flags & (1LL << ((uint64_t) page)))) { + scsi_cdrom_log(dev->log, "Unimplemented page %02X\n", page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + uint8_t pg = page; + + if (dev->is_sony && (page == GPMODE_CDROM_AUDIO_PAGE_SONY) && (i >= 6) && (i <= 13)) + pg = GPMODE_CDROM_AUDIO_PAGE; + + ch = dev->ms_pages_changeable.pages[pg][i + 2]; + val = dev->buffer[pos + i]; + old_val = dev->ms_pages_saved.pages[pg][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[pg][i + 2] = val; + else { + scsi_cdrom_log(dev->log, "Unchangeable value on position " + "%02X on page %02X\n", i + 2, page); + scsi_cdrom_invalid_field_pl(dev, val); + error |= 1; } } - break; - default: - if (!(scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { - scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); - error |= 1; - } else { - for (i = 0; i < page_len; i++) { - ch = scsi_cdrom_mode_sense_pages_changeable.pages[page][i + 2]; - val = dev->buffer[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else { - scsi_cdrom_log("CD-ROM %i: Unchangeable value on position " - "%02X on page %02X\n", dev->id, i + 2, page); - error |= 1; - } - } - } - } - break; + } } pos += page_len; - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - val = scsi_cdrom_mode_sense_pages_default_sony_scsi.pages[page][0] & 0x80; - break; - default: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - val = scsi_cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = scsi_cdrom_mode_sense_pages_default.pages[page][0] & 0x80; - break; - } + val = dev->ms_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) scsi_cdrom_mode_sense_save(dev); @@ -3925,21 +3526,20 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) } if (error) { - scsi_cdrom_invalid_field_pl(dev); scsi_cdrom_buf_free(dev); return 0; } break; - case 0xC9: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - for (i = 0; i < 18; i++) - dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY][i] = dev->buffer[i]; - break; - default: - break; + case 0xc9: + if (dev->is_sony) { + for (i = 0; i < 18; i++) { + if ((i >= 8) && (i <= 15)) + dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][i] = + dev->buffer[i]; + else + dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY][i] = + dev->buffer[i]; + } } break; @@ -3956,30 +3556,31 @@ scsi_cdrom_close(void *priv) { scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; - if (dev->tf) - free(dev->tf); + if (dev != NULL) { + if (dev->tf != NULL) + free(dev->tf); + + if (dev->log != NULL) { + scsi_cdrom_log(dev->log, "Log closed\n"); + + log_close(dev->log); + dev->log = NULL; + } - if (dev) free(dev); + } } static int -scsi_cdrom_get_max(int ide_has_dma, int type) +scsi_cdrom_get_max(const ide_t *ide, const int ide_has_dma, const int type) { - int ret; + const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; + int ret; switch (type) { - case TYPE_PIO: - ret = ide_has_dma ? 4 : 0; - break; - case TYPE_SDMA: - ret = ide_has_dma ? 2 : -1; - break; - case TYPE_MDMA: - ret = ide_has_dma ? 2 : -1; - break; - case TYPE_UDMA: - ret = ide_has_dma ? 5 : -1; + case TYPE_PIO: case TYPE_SDMA: + case TYPE_MDMA: case TYPE_UDMA: + ret = cdrom_get_transfer_max(dev->drv->type, type); break; default: ret = -1; @@ -3990,16 +3591,18 @@ scsi_cdrom_get_max(int ide_has_dma, int type) } static int -scsi_cdrom_get_timings(int ide_has_dma, int type) +scsi_cdrom_get_timings(const ide_t *ide, const int ide_has_dma, const int type) { - int ret; + const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; + int has_dma = cdrom_has_dma(dev->drv->type); + int ret; switch (type) { case TIMINGS_DMA: - ret = ide_has_dma ? 120 : 0; + ret = has_dma ? 120 : 0; break; case TIMINGS_PIO: - ret = ide_has_dma ? 120 : 0; + ret = has_dma ? 120 : 0; break; case TIMINGS_PIO_FC: ret = 0; @@ -4016,194 +3619,29 @@ scsi_cdrom_get_timings(int ide_has_dma, int type) * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command */ static void -scsi_cdrom_identify(ide_t *ide, int ide_has_dma) +scsi_cdrom_identify(const ide_t *ide, const int ide_has_dma) { - const scsi_cdrom_t *dev; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; + char model[2048] = { 0 }; + const int has_dma = cdrom_has_dma(dev->drv->type); - dev = (scsi_cdrom_t *) ide->sc; + cdrom_get_identify_model(dev->drv->type, model, dev->id); - device_identify[7] = dev->id + 0x30; - scsi_cdrom_log("ATAPI Identify: %s\n", device_identify); + scsi_cdrom_log(dev->log, "ATAPI Identify: %s\n", model); - if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) /*NEC only*/ + if (dev->drv->is_early) ide->buffer[0] = 0x8000 | (5 << 8) | 0x80 | (1 << 5); /* ATAPI device, CD-ROM drive, removable media, interrupt DRQ */ else ide->buffer[0] = 0x8000 | (5 << 8) | 0x80 | (2 << 5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - if (dev->drv->type == CDROM_TYPE_86BOX_100) { - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ - } else { - switch (dev->drv->type) { - case CDROM_TYPE_ASUS_CDS500_141: - ide_padstr((char *) (ide->buffer + 23), "1.41 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "ASUS CD-S500/A ", 40); /* Model */ - break; - case CDROM_TYPE_ASUS_CDS520_132: - ide_padstr((char *) (ide->buffer + 23), "1.32 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "ASUS CD-S520/A4 ", 40); /* Model */ - break; - case CDROM_TYPE_AZT_CDA46802I_115: - ide_padstr((char *) (ide->buffer + 23), "1.15 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "AZT CDA46802I ", 40); /* Model */ - break; - case CDROM_TYPE_BTC_BCD36XH_U10: - ide_padstr((char *) (ide->buffer + 23), "U1.0 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "BTC CD-ROM BCD36XH ", 40); /* Model */ - break; - case CDROM_TYPE_GOLDSTAR_CRD_8160B_314: - ide_padstr((char *) (ide->buffer + 23), "3.14 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "GOLDSTAR CRD-8160B ", 40); /* Model */ - break; - case CDROM_TYPE_HITACHI_CDR_8130_0020: - ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ - break; - case CDROM_TYPE_HITACHI_GD7500_A1: - ide_padstr((char *) (ide->buffer + 23), "A1 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HITACHI GD-7500 ", 40); /* Model */ - break; - case CDROM_TYPE_HLDTST_GCR8526B_101: - ide_padstr((char *) (ide->buffer + 23), "1.01 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST CD-ROM GCR-8526B ", 40); /* Model */ - break; - case CDROM_TYPE_HLDTST_GSA4160_A302: - ide_padstr((char *) (ide->buffer + 23), "A302 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HL-DT-ST DVDRAM GSA-4160 ", 40); /* Model */ - break; - case CDROM_TYPE_KENWOOD_UCR_421_208E: - ide_padstr((char *) (ide->buffer + 23), "208E ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "KENWOOD CD-ROM UCR-421 ", 40); /* Model */ - break; - case CDROM_TYPE_LG_CRN8245B_130: - ide_padstr((char *) (ide->buffer + 23), "1.30 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRN-8245B ", 40); /* Model */ - break; - case CDROM_TYPE_LG_CRD8322B_106: - ide_padstr((char *) (ide->buffer + 23), "1.06 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "LG CD-ROM CRD-8322B ", 40); /* Model */ - break; - case CDROM_TYPE_LTN48125S_1S07: - ide_padstr((char *) (ide->buffer + 23), "1S07 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "LTN48125S ", 40); /* Model */ - break; - case CDROM_TYPE_LTN526D_YSR5: - ide_padstr((char *) (ide->buffer + 23), "YSR5 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "LTN526D ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_583_107: - ide_padstr((char *) (ide->buffer + 23), "1.07 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-583 ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_585_Z18P: - ide_padstr((char *) (ide->buffer + 23), "Z18P ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-585 ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_587_7S13: - ide_padstr((char *) (ide->buffer + 23), "7S13 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-587 ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_588_LS15: - ide_padstr((char *) (ide->buffer + 23), "LS15 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-588 ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_571_10e: - ide_padstr((char *) (ide->buffer + 23), "1.0e ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CR-571 ", 40); /* Model */ - break; - case CDROM_TYPE_MATSHITA_572_10j: - ide_padstr((char *) (ide->buffer + 23), "1.0j ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MATSHITA CR-572 ", 40); /* Model */ - break; - case CDROM_TYPE_MITSUMI_FX4820T_D02A: - ide_padstr((char *) (ide->buffer + 23), "D02A ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "MITSUMI CRMC-FX4820T ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_260_100: - ide_padstr((char *) (ide->buffer + 23), ".100 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "EN C DCR-MOD IREV2:06 ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_260_101: - ide_padstr((char *) (ide->buffer + 23), ".110 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "EN C DCR-MOD IREV2:06 ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_273_420: - ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_280_105: - ide_padstr((char *) (ide->buffer + 23), "1.05 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:280 ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_280_308: - ide_padstr((char *) (ide->buffer + 23), "3.08 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:280 ", 40); /* Model */ - break; - case CDROM_TYPE_NEC_CDR_1900A_100: - ide_padstr((char *) (ide->buffer + 23), "1.00 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CDR-1900A ", 40); /* Model */ - break; - case CDROM_TYPE_PHILIPS_PCA403CD_U31P: - ide_padstr((char *) (ide->buffer + 23), "U31P ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "PHILIPS CD-ROM PCA403CD ", 40); /* Model */ - break; - case CDROM_TYPE_SONY_CDU76_10i: - ide_padstr((char *) (ide->buffer + 23), "1.0i ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU76 ", 40); /* Model */ - break; - case CDROM_TYPE_SONY_CDU311_30h: - ide_padstr((char *) (ide->buffer + 23), "3.0h ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU311 ", 40); /* Model */ - break; - case CDROM_TYPE_SONY_CDU5225_NYS4: - ide_padstr((char *) (ide->buffer + 23), "NYS4 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU5225 ", 40); /* Model */ - break; - case CDROM_TYPE_TEAC_CD516E_10G: - ide_padstr((char *) (ide->buffer + 23), "1.0G ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TEAC CD-516E ", 40); /* Model */ - break; - case CDROM_TYPE_TEAC_CD524EA_30D: - ide_padstr((char *) (ide->buffer + 23), "3.0D ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TEAC CD-524EA ", 40); /* Model */ - break; - case CDROM_TYPE_TEAC_CD532E_20A: - ide_padstr((char *) (ide->buffer + 23), "2.0A ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TEAC CD-532E ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_5302TA_0305: - ide_padstr((char *) (ide->buffer + 23), "0305 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5302TA ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_5702B_TA70: - ide_padstr((char *) (ide->buffer + 23), "TA70 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5702B ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_6202B_1512: - ide_padstr((char *) (ide->buffer + 23), "1512 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6202B ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_6402B_1008: - ide_padstr((char *) (ide->buffer + 23), "1008 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6402B ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_6702B_1007: - ide_padstr((char *) (ide->buffer + 23), "1007 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-6702B ", 40); /* Model */ - break; - case CDROM_TYPE_TOSHIBA_M1802_1051: - ide_padstr((char *) (ide->buffer + 23), "1051 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "TOSHIBA DVD-ROM SD-M1802 ", 40); /* Model */ - break; - } - } + ide_padstr((char *) (ide->buffer + 23), cdrom_get_revision(dev->drv->type), 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), model, 40); /* Model */ ide->buffer[49] = 0x200; /* LBA supported */ ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - if (ide_has_dma) { + if (has_dma) { ide->buffer[71] = 30; ide->buffer[72] = 30; ide->buffer[80] = 0x7e; /*ATA-1 to ATA-6 supported*/ @@ -4212,14 +3650,11 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) } void -scsi_cdrom_drive_reset(int c) +scsi_cdrom_drive_reset(const int c) { cdrom_t *drv = &cdrom[c]; - scsi_cdrom_t *dev; - scsi_device_t *sd; - ide_t *id; - uint8_t scsi_bus = (drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = drv->scsi_device_id & 0x0f; + const uint8_t scsi_bus = (drv->scsi_device_id >> 4) & 0x0f; + const uint8_t scsi_id = drv->scsi_device_id & 0x0f; uint8_t valid = 0; if (drv->bus_type == CDROM_BUS_SCSI) { @@ -4236,12 +3671,17 @@ scsi_cdrom_drive_reset(int c) if ((drv->bus_type == CDROM_BUS_ATAPI) && (drv->ide_channel > 7)) return; - if (!drv->priv) { - drv->priv = (scsi_cdrom_t *) malloc(sizeof(scsi_cdrom_t)); - memset(drv->priv, 0, sizeof(scsi_cdrom_t)); + if (drv->priv == NULL) { + drv->priv = (scsi_cdrom_t *) calloc(1, sizeof(scsi_cdrom_t)); + scsi_cdrom_t *dev = (scsi_cdrom_t *) drv->priv; + + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i SCSI ", c + 1); + dev->log = log_open(n); } - dev = (scsi_cdrom_t *) drv->priv; + scsi_cdrom_t *dev = (scsi_cdrom_t *) drv->priv; dev->id = c; dev->drv = drv; @@ -4254,80 +3694,106 @@ scsi_cdrom_drive_reset(int c) drv->close = scsi_cdrom_close; drv->sector_size = 2048; + (void) scsi_cdrom_update_sector_flags(dev); if (drv->bus_type == CDROM_BUS_SCSI) { - valid = 1; + char *vendor = cdrom_get_vendor(dev->drv->type); - if (!dev->tf) - dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); + dev->ven_cmd = NULL; + memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); + dev->is_sony = 0; + dev->use_cdb_9 = 0; + dev->ms_page_flags = scsi_cdrom_ms_page_flags_scsi; + dev->ms_pages_default = scsi_cdrom_ms_pages_default_scsi; + dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_scsi; + + if (!strcmp(vendor, "CHINON")) + dev->ven_cmd = scsi_cdrom_command_chinon; + else if (!strcmp(vendor, "DEC") || !strcmp(vendor, "ShinaKen") || + !strcmp(vendor, "SONY") || !strcmp(vendor, "TEXEL")) { + dev->ven_cmd = scsi_cdrom_command_dec_sony_texel; + dev->ven_cmd_is_data[0xc0] = 1; + dev->ven_cmd_is_data[0xc1] = 1; + dev->ven_cmd_is_data[0xc2] = 1; + dev->ven_cmd_is_data[0xc3] = 1; + dev->is_sony = 1; + dev->ms_page_flags = scsi_cdrom_ms_page_flags_sony_scsi; + dev->ms_pages_default = scsi_cdrom_ms_pages_default_sony_scsi; + dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_sony_scsi; + } else if (!strcmp(vendor, "MATSHITA")) + dev->ven_cmd = scsi_cdrom_command_matsushita; + else if (!strcmp(vendor, "NEC")) { + dev->ven_cmd = scsi_cdrom_command_nec; + dev->ven_cmd_is_data[0xdd] = 1; + dev->ven_cmd_is_data[0xde] = 1; + } else if (!strcmp(vendor, "PIONEER")) { + dev->ven_cmd = scsi_cdrom_command_pioneer; + dev->ven_cmd_is_data[0xc1] = 1; + dev->ven_cmd_is_data[0xc2] = 1; + dev->ven_cmd_is_data[0xc3] = 1; + } else if (!strcmp(vendor, "TOSHIBA")) { + dev->ven_cmd = scsi_cdrom_command_toshiba; + dev->ven_cmd_is_data[0xc6] = 1; + dev->ven_cmd_is_data[0xc7] = 1; + dev->use_cdb_9 = 1; + } + + if (dev->tf == NULL) + dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); /* SCSI CD-ROM, attach to the SCSI bus. */ - sd = &scsi_devices[scsi_bus][scsi_id]; + scsi_device_t *sd = &scsi_devices[scsi_bus][scsi_id]; - sd->sc = (scsi_common_t *) dev; - sd->command = scsi_cdrom_command; - sd->request_sense = scsi_cdrom_request_sense_for_scsi; - sd->reset = scsi_cdrom_reset; - sd->phase_data_out = scsi_cdrom_phase_data_out; - sd->command_stop = scsi_cdrom_command_stop; - sd->type = SCSI_REMOVABLE_CDROM; + sd->sc = (scsi_common_t *) dev; + sd->command = scsi_cdrom_command; + sd->request_sense = scsi_cdrom_request_sense_for_scsi; + sd->reset = scsi_cdrom_reset; + sd->phase_data_out = scsi_cdrom_phase_data_out; + sd->command_stop = scsi_cdrom_command_stop; + sd->type = SCSI_REMOVABLE_CDROM; - scsi_cdrom_log("SCSI CD-ROM drive %i attached to SCSI ID %i\n", c, cdrom[c].scsi_device_id); + valid = 1; + + scsi_cdrom_log(dev->log, "SCSI CD-ROM drive %i attached to SCSI ID %i\n", + c, cdrom[c].scsi_device_id); } else if (drv->bus_type == CDROM_BUS_ATAPI) { /* ATAPI CD-ROM, attach to the IDE bus. */ - id = ide_get_drive(drv->ide_channel); - /* If the IDE channel is initialized, we attach to it, - otherwise, we do nothing - it's going to be a drive - that's not attached to anything. */ - if (id) { - valid = 1; + ide_t *id = ide_get_drive(drv->ide_channel); - id->sc = (scsi_common_t *) dev; - dev->tf = id->tf; - if ((dev->drv->type == CDROM_TYPE_NEC_260_100) || (dev->drv->type == CDROM_TYPE_NEC_260_101)) - IDE_ATAPI_IS_EARLY = 1; - id->get_max = scsi_cdrom_get_max; - id->get_timings = scsi_cdrom_get_timings; - id->identify = scsi_cdrom_identify; - id->stop = scsi_cdrom_stop; - id->packet_command = scsi_cdrom_command; - id->device_reset = scsi_cdrom_reset; - id->phase_data_out = scsi_cdrom_phase_data_out; - id->command_stop = scsi_cdrom_command_stop; - id->bus_master_error = scsi_cdrom_bus_master_error; - id->interrupt_drq = ((dev->drv->type == CDROM_TYPE_NEC_260_100) || - (dev->drv->type == CDROM_TYPE_NEC_260_101)); + /* + If the IDE channel is initialized, we attach to it, otherwise, we do + nothing - it's going to be a drive that's not attached to anything. + */ + if (id) { + dev->ven_cmd = NULL; + memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); + dev->is_sony = 0; + dev->use_cdb_9 = 0; + dev->ms_page_flags = scsi_cdrom_ms_page_flags; + dev->ms_pages_default = scsi_cdrom_ms_pages_default; + dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable; + + id->sc = (scsi_common_t *) dev; + dev->tf = id->tf; + IDE_ATAPI_IS_EARLY = dev->drv->is_early; + id->get_max = scsi_cdrom_get_max; + id->get_timings = scsi_cdrom_get_timings; + id->identify = scsi_cdrom_identify; + id->stop = scsi_cdrom_stop; + id->packet_command = scsi_cdrom_command; + id->device_reset = scsi_cdrom_reset; + id->phase_data_out = scsi_cdrom_phase_data_out; + id->command_stop = scsi_cdrom_command_stop; + id->bus_master_error = scsi_cdrom_bus_master_error; + id->interrupt_drq = dev->drv->is_early; + + valid = 1; ide_atapi_attach(id); } - scsi_cdrom_log("ATAPI CD-ROM drive %i attached to IDE channel %i\n", c, cdrom[c].ide_channel); - } - - switch (dev->drv->type) { - case CDROM_TYPE_CHINON_CDS431_H42: - dev->ven_cmd = scsi_cdrom_command_chinon; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: - dev->ven_cmd = scsi_cdrom_command_dec_sony_texel; - break; - case CDROM_TYPE_MATSHITA_501_10b: - dev->ven_cmd = scsi_cdrom_command_matsushita; - break; - case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: - dev->ven_cmd = scsi_cdrom_command_nec; - break; - case CDROM_TYPE_PIONEER_DRM604X_2403: - dev->ven_cmd = scsi_cdrom_command_pioneer; - break; - case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: - dev->ven_cmd = scsi_cdrom_command_toshiba; - break; - default: - dev->ven_cmd = NULL; - break; + scsi_cdrom_log(dev->log, "ATAPI CD-ROM drive %i attached to IDE channel %i\n", + c, cdrom[c].ide_channel); } if (valid) diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 10fdf04a6..c11f09443 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -12,26 +12,24 @@ * * Copyright 2017-2018 Miran Grca. */ -#include #include #include -#include +#ifdef ENABLE_SCSI_DISK_LOG +#include +#endif #include +#include #include #include -#include -#define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/config.h> #include <86box/timer.h> #include <86box/device.h> +#include <86box/log.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/machine.h> #include <86box/nvr.h> -#include <86box/hdc.h> #include <86box/hdc_ide.h> -#include <86box/sound.h> #include <86box/plat.h> #include <86box/ui.h> #include <86box/hdd.h> @@ -42,86 +40,71 @@ #define scsi_disk_sense_error dev->sense[0] #define scsi_disk_sense_key dev->sense[2] +#define scsi_disk_info *(uint32_t *) &(dev->sense[3]) #define scsi_disk_asc dev->sense[12] #define scsi_disk_ascq dev->sense[13] -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +// clang-format off +/* + Table of all SCSI commands and their flags, needed for the new disc change / + not ready handler. + */ const uint8_t scsi_disk_command_flags[0x100] = { - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x0A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, - IMPLEMENTED, /* 0x15 */ - IMPLEMENTED | SCSI_ONLY, /* 0x16 */ - IMPLEMENTED | SCSI_ONLY, /* 0x17 */ - 0, 0, - IMPLEMENTED, /* 0x1A */ - 0, 0, - IMPLEMENTED, /* 0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2A */ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - IMPLEMENTED | CHECK_READY, /* 0x41 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0xBD */ - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + [0x00] = IMPLEMENTED | CHECK_READY, + [0x01] = IMPLEMENTED | ALLOW_UA | SCSI_ONLY, + [0x03] = IMPLEMENTED | ALLOW_UA, + [0x04] = IMPLEMENTED | CHECK_READY | ALLOW_UA | SCSI_ONLY, + [0x08] = IMPLEMENTED | CHECK_READY, + [0x0a ... 0x0b] = IMPLEMENTED | CHECK_READY, + [0x12] = IMPLEMENTED | ALLOW_UA, + [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x15] = IMPLEMENTED, + [0x16 ... 0x17] = IMPLEMENTED | SCSI_ONLY, + [0x1a] = IMPLEMENTED, + [0x1d] = IMPLEMENTED, + [0x1e] = IMPLEMENTED | CHECK_READY, + [0x25] = IMPLEMENTED | CHECK_READY, + [0x28] = IMPLEMENTED | CHECK_READY, + [0x2a ... 0x2b] = IMPLEMENTED | CHECK_READY, + [0x2e] = IMPLEMENTED | CHECK_READY, + [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x41] = IMPLEMENTED | CHECK_READY, + [0x55] = IMPLEMENTED, + [0x5a] = IMPLEMENTED, + [0xa8] = IMPLEMENTED | CHECK_READY, + [0xaa] = IMPLEMENTED | CHECK_READY, + [0xae] = IMPLEMENTED | CHECK_READY, + [0xaf] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xbd] = IMPLEMENTED }; -uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_FORMAT_DEVICE_PAGE | GPMODEP_RIGID_DISK_PAGE | GPMODEP_UNK_VENDOR_PAGE | GPMODEP_ALL_PAGES); +uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_FORMAT_DEVICE_PAGE | GPMODEP_RIGID_DISK_PAGE | + GPMODEP_UNK_VENDOR_PAGE | GPMODEP_ALL_PAGES); -/* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = { - {[GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [GPMODE_RIGID_DISK_PAGE] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 200, 0xff, 0xff, 0xff, 0, 0, 0, 0x15, 0x18, 0, 0 }, - [GPMODE_UNK_VENDOR_PAGE] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }} + { [0x03] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x04] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x15, 0x18, 0x00, 0x00 }, + [0x30] = { GPMODE_UNK_VENDOR_PAGE | 0x80, 0x16, '8' , '6' , 'B' , 'o' , 'x' , ' ' , + ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , + ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' ' } } }; static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = { - {[GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [GPMODE_RIGID_DISK_PAGE] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [GPMODE_UNK_VENDOR_PAGE] = { 0xB0, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }} + { [0x03] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x04] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + [0x30] = { GPMODE_UNK_VENDOR_PAGE | 0x80, 0x16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } }; +// clang-format on static void scsi_disk_command_complete(scsi_disk_t *dev); @@ -133,116 +116,116 @@ static void scsi_disk_init(scsi_disk_t *dev); int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; static void -scsi_disk_log(const char *fmt, ...) +scsi_disk_log(void *priv, const char *fmt, ...) { va_list ap; if (scsi_disk_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define scsi_disk_log(fmt, ...) +# define scsi_disk_log(priv, fmt, ...) #endif static void -scsi_disk_set_callback(scsi_disk_t *dev) +scsi_disk_set_callback(const scsi_disk_t *dev) { - if (dev->drv->bus != HDD_BUS_SCSI) + if (dev->drv->bus_type != HDD_BUS_SCSI) ide_set_callback(ide_drives[dev->drv->ide_channel], dev->callback); } static void scsi_disk_init(scsi_disk_t *dev) { - if (!dev) - return; + if (dev != NULL) { + /* Do a reset (which will also rezero it). */ + scsi_disk_reset((scsi_common_t *) dev); - /* Do a reset (which will also rezero it). */ - scsi_disk_reset((scsi_common_t *) dev); + /* Configure the drive. */ + dev->requested_blocks = 1; - /* Configure the drive. */ - dev->requested_blocks = 1; + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= HDD_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < HDD_BUS_SCSI) + dev->drv->bus_mode |= 1; + scsi_disk_log(dev->log, "Bus type %i, bus mode %i\n", + dev->drv->bus_type, dev->drv->bus_mode); - dev->drv->bus_mode = 0; - if (dev->drv->bus >= HDD_BUS_ATAPI) - dev->drv->bus_mode |= 2; - if (dev->drv->bus < HDD_BUS_SCSI) - dev->drv->bus_mode |= 1; - scsi_disk_log("SCSI HDD %i: Bus type %i, bus mode %i\n", - dev->id, dev->drv->bus, dev->drv->bus_mode); + dev->sense[0] = 0xf0; + dev->sense[7] = 10; - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - /* NEC only */ - dev->tf->status = 0; - dev->tf->pos = 0; - dev->packet_status = PHASE_NONE; - scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = dev->unit_attention = 0; - scsi_disk_mode_sense_load(dev); + dev->tf->status = 0; + dev->tf->pos = 0; + dev->packet_status = PHASE_NONE; + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = dev->unit_attention = 0; + scsi_disk_info = 0x00; + scsi_disk_mode_sense_load(dev); + } } /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ static int -scsi_disk_current_mode(scsi_disk_t *dev) +scsi_disk_current_mode(const scsi_disk_t *dev) { - if (dev->drv->bus == HDD_BUS_SCSI) - return 2; - else if (dev->drv->bus == HDD_BUS_ATAPI) { - scsi_disk_log("SCSI DISK %i: ATAPI drive, setting to %s\n", dev->id, + int ret = 0; + + if (dev->drv->bus_type == HDD_BUS_SCSI) + ret = 2; + else if (dev->drv->bus_type == HDD_BUS_ATAPI) { + scsi_disk_log(dev->log, "ATAPI drive, setting to %s\n", (dev->tf->features & 1) ? "DMA" : "PIO", dev->id); - return (dev->tf->features & 1) ? 2 : 1; + ret = (dev->tf->features & 1) ? 2 : 1; } - return 0; + return ret; } -void +static void scsi_disk_mode_sense_load(scsi_disk_t *dev) { - FILE *fp; - char file_name[512]; + char file_name[512] = { 0 }; memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, + sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512); sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "rb"); + FILE *fp = plat_fopen(nvr_path(file_name), "rb"); if (fp) { if (fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, fp) != 0x18) - fatal("scsi_disk_mode_sense_load(): Error reading data\n"); + log_fatal(dev->log, "scsi_disk_mode_sense_load(): Error reading data\n"); fclose(fp); } } -void -scsi_disk_mode_sense_save(scsi_disk_t *dev) +static void +scsi_disk_mode_sense_save(const scsi_disk_t *dev) { - FILE *fp; - char file_name[512]; + char file_name[512] = { 0 }; - memset(file_name, 0, 512); sprintf(file_name, "scsi_disk_%02i_mode_sense.bin", dev->id); - fp = plat_fopen(nvr_path(file_name), "wb"); + FILE *fp = plat_fopen(nvr_path(file_name), "wb"); if (fp) { fwrite(dev->ms_pages_saved.pages[0x30], 1, 0x18, fp); fclose(fp); } } -/*SCSI Mode Sense 6/10*/ +/* SCSI Mode Sense 6/10 */ uint8_t -scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +scsi_disk_mode_sense_read(const scsi_disk_t *dev, const uint8_t pgctl, + const uint8_t page, const uint8_t pos) { - if (page_control == 1) + if (pgctl == 1) return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; if (page == GPMODE_RIGID_DISK_PAGE) - switch (page_control) { + switch (pgctl) { /* Rigid disk geometry page. */ case 0: case 2: @@ -272,7 +255,7 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, break; } else if (page == GPMODE_FORMAT_DEVICE_PAGE) - switch (page_control) { + switch (pgctl) { /* Format device page. */ case 0: case 2: @@ -293,7 +276,7 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, break; } else - switch (page_control) { + switch (pgctl) { case 0: case 3: return dev->ms_pages_saved.pages[page][pos]; @@ -308,16 +291,13 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, } uint32_t -scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len) +scsi_disk_mode_sense(const scsi_disk_t *dev, uint8_t *buf, uint32_t pos, + uint8_t page, const uint8_t block_descriptor_len) { - uint8_t msplen; - uint8_t page_control = (page >> 6) & 3; - int size = 0; + int size = hdd_image_get_last_sector(dev->id); page &= 0x3f; - size = hdd_image_get_last_sector(dev->id); - if (block_descriptor_len) { buf[pos++] = 1; /* Density code. */ buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ @@ -332,12 +312,14 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, for (uint8_t i = 0; i < 0x40; i++) { if ((page == GPMODE_ALL_PAGES) || (page == i)) { if (scsi_disk_mode_sense_page_flags & (1LL << (uint64_t) page)) { - buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0); - msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1); - buf[pos++] = msplen; - scsi_disk_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + const uint8_t pgctl = (page >> 6) & 3; + const uint8_t msplen = scsi_disk_mode_sense_read(dev, pgctl, i, 1); + buf[pos++] = scsi_disk_mode_sense_read(dev, pgctl, i, 0); + buf[pos++] = msplen; + scsi_disk_log(dev->log, "MODE SENSE: Page [%02X] length %i\n", + i, msplen); for (uint8_t j = 0; j < msplen; j++) - buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 2 + j); + buf[pos++] = scsi_disk_mode_sense_read(dev, pgctl, i, 2 + j); } } } @@ -346,7 +328,7 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, } static void -scsi_disk_update_request_length(scsi_disk_t *dev, int len, int block_len) +scsi_disk_update_request_length(scsi_disk_t *dev, int len, const int block_len) { int bt; int min_len = 0; @@ -407,7 +389,7 @@ scsi_disk_bus_speed(scsi_disk_t *dev) { double ret = -1.0; - if (dev && dev->drv && (dev->drv->bus == HDD_BUS_SCSI)) { + if (dev && dev->drv && (dev->drv->bus_type == HDD_BUS_SCSI)) { dev->callback = -1.0; /* Speed depends on SCSI controller */ return 0.0; } else { @@ -425,7 +407,7 @@ scsi_disk_bus_speed(scsi_disk_t *dev) void scsi_disk_command_common(scsi_disk_t *dev) { - double bytes_per_second = 0.0; + double bytes_per_second; double period; /* MAP: BUSY_STAT, no DRQ, phase 1. */ @@ -435,6 +417,7 @@ scsi_disk_command_common(scsi_disk_t *dev) dev->callback = 0; if (dev->packet_status == PHASE_COMPLETE) { + switch (dev->current_cdb[0]) { case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: @@ -446,18 +429,19 @@ scsi_disk_command_common(scsi_disk_t *dev) case GPCMD_WRITE_AND_VERIFY_12: case GPCMD_WRITE_SAME_10: /* Seek time is in us. */ - period = hdd_timing_write(dev->drv, dev->drv->seek_pos, dev->drv->seek_len); - scsi_disk_log("SCSI HD %i: Seek period: %" PRIu64 " us\n", - dev->id, (uint64_t) period); + period = hdd_timing_write(dev->drv, dev->drv->seek_pos, + dev->drv->seek_len); + scsi_disk_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; /* Account for seek time. */ bytes_per_second = scsi_bus_get_speed(dev->drv->scsi_id >> 4); period = 1000000.0 / bytes_per_second; - scsi_disk_log("SCSI HD %i: Byte transfer period: %" PRIu64 " us\n", dev->id, + scsi_disk_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); period = period * (double) (dev->packet_len); - scsi_disk_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, + scsi_disk_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); dev->callback += period; break; @@ -473,8 +457,8 @@ scsi_disk_command_common(scsi_disk_t *dev) /* Seek time is in us. */ period = hdd_seek_get_time(dev->drv, (dev->current_cdb[0] == GPCMD_REZERO_UNIT) ? 0 : dev->sector_pos, HDD_OP_SEEK, 0, 0.0); - scsi_disk_log("SCSI HD %i: Seek period: %" PRIu64 " us\n", - dev->id, (uint64_t) period); + scsi_disk_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; scsi_disk_set_callback(dev); return; @@ -482,9 +466,10 @@ scsi_disk_command_common(scsi_disk_t *dev) case 0x28: case 0xa8: /* Seek time is in us. */ - period = hdd_timing_read(dev->drv, dev->drv->seek_pos, dev->drv->seek_len); - scsi_disk_log("SCSI HD %i: Seek period: %" PRIu64 " us\n", - dev->id, (uint64_t) period); + period = hdd_timing_read(dev->drv, dev->drv->seek_pos, + dev->drv->seek_len); + scsi_disk_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; /* Account for seek time. */ bytes_per_second = scsi_bus_get_speed(dev->drv->scsi_id >> 4); @@ -500,9 +485,11 @@ scsi_disk_command_common(scsi_disk_t *dev) } period = 1000000.0 / bytes_per_second; - scsi_disk_log("SCSI HD %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + scsi_disk_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", + (uint64_t) period); period = period * (double) (dev->packet_len); - scsi_disk_log("SCSI HD %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + scsi_disk_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", + (uint64_t) period); dev->callback += period; } scsi_disk_set_callback(dev); @@ -543,16 +530,19 @@ scsi_disk_command_write_dma(scsi_disk_t *dev) scsi_disk_command_common(dev); } -/* id = Current ZIP device ID; +/* + dev = Pointer to current SCSI disk device; len = Total transfer length; block_len = Length of a single block (why does it matter?!); alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ + direction = Transfer direction (0 = read from host, 1 = write to host). + */ static void -scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int alloc_len, int direction) +scsi_disk_data_command_finish(scsi_disk_t *dev, int len, const int block_len, + const int alloc_len, const int direction) { - scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", - dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, + scsi_disk_log(dev->log, "Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length); dev->tf->pos = 0; if (alloc_len >= 0) { @@ -560,13 +550,13 @@ scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int allo len = alloc_len; } if ((len == 0) || (scsi_disk_current_mode(dev) == 0)) { - if (dev->drv->bus != HDD_BUS_SCSI) + if (dev->drv->bus_type != HDD_BUS_SCSI) dev->packet_len = 0; scsi_disk_command_complete(dev); } else { if (scsi_disk_current_mode(dev) == 2) { - if (dev->drv->bus != HDD_BUS_SCSI) + if (dev->drv->bus_type != HDD_BUS_SCSI) dev->packet_len = alloc_len; if (direction == 0) @@ -582,27 +572,27 @@ scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int allo } } - scsi_disk_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", - dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos, - dev->tf->phase); + scsi_disk_log(dev->log, "Status: %i, cylinder %i, packet length: %i, position: %i, " + "phase: %i\n", + dev->packet_status, dev->tf->request_length, dev->packet_len, + dev->tf->pos, dev->tf->phase); } static void scsi_disk_sense_clear(scsi_disk_t *dev, UNUSED(int command)) { scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0; + scsi_disk_info = 0x00000000; } static void -scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) +scsi_disk_set_phase(const scsi_disk_t *dev, const uint8_t phase) { - uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_id & 0x0f; + const uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_id & 0x0f; - if (dev->drv->bus != HDD_BUS_SCSI) - return; - - scsi_devices[scsi_bus][scsi_id].phase = phase; + if (dev->drv->bus_type == HDD_BUS_SCSI) + scsi_devices[scsi_bus][scsi_id].phase = phase; } static void @@ -615,15 +605,16 @@ scsi_disk_cmd_error(scsi_disk_t *dev) dev->packet_status = PHASE_ERROR; dev->callback = 50.0 * SCSI_TIME; scsi_disk_set_callback(dev); - ui_sb_update_icon(SB_HDD | dev->drv->bus, 0); - scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); + ui_sb_update_icon(SB_HDD | dev->drv->bus_type, 0); + scsi_disk_log(dev->log, "ERROR: %02X/%02X/%02X\n", scsi_disk_sense_key, + scsi_disk_asc, scsi_disk_ascq); } static void scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len) { - scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->temp_buffer) + scsi_disk_log(dev->log, "Allocated buffer length: %i\n", len); + if (dev->temp_buffer == NULL) dev->temp_buffer = (uint8_t *) malloc(len); } @@ -631,7 +622,7 @@ static void scsi_disk_buf_free(scsi_disk_t *dev) { if (dev->temp_buffer) { - scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id); + scsi_disk_log(dev->log, "Freeing buffer...\n"); free(dev->temp_buffer); dev->temp_buffer = NULL; } @@ -644,6 +635,10 @@ scsi_disk_bus_master_error(scsi_common_t *sc) scsi_disk_buf_free(dev); scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0; + scsi_disk_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_disk_cmd_error(dev); } @@ -653,6 +648,10 @@ scsi_disk_write_error(scsi_disk_t *dev) scsi_disk_sense_key = SENSE_MEDIUM_ERROR; scsi_disk_asc = ASC_WRITE_ERROR; scsi_disk_ascq = 0; + scsi_disk_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_disk_cmd_error(dev); } @@ -662,25 +661,31 @@ scsi_disk_read_error(scsi_disk_t *dev) scsi_disk_sense_key = SENSE_MEDIUM_ERROR; scsi_disk_asc = ASC_UNRECOVERED_READ_ERROR; scsi_disk_ascq = 0; + scsi_disk_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_disk_cmd_error(dev); } static void -scsi_disk_invalid_lun(scsi_disk_t *dev) +scsi_disk_invalid_lun(scsi_disk_t *dev, const uint8_t lun) { scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_INV_LUN; scsi_disk_ascq = 0; scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_info = lun << 24; scsi_disk_cmd_error(dev); } static void -scsi_disk_illegal_opcode(scsi_disk_t *dev) +scsi_disk_illegal_opcode(scsi_disk_t *dev, const uint8_t opcode) { scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_ILLEGAL_OPCODE; scsi_disk_ascq = 0; + scsi_disk_info = opcode << 24; scsi_disk_cmd_error(dev); } @@ -690,54 +695,72 @@ scsi_disk_lba_out_of_range(scsi_disk_t *dev) scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_LBA_OUT_OF_RANGE; scsi_disk_ascq = 0; + scsi_disk_info = (dev->sector_pos >> 24) | + ((dev->sector_pos >> 16) << 8) | + ((dev->sector_pos >> 8) << 16) | + ( dev->sector_pos << 24); scsi_disk_cmd_error(dev); } static void -scsi_disk_invalid_field(scsi_disk_t *dev) +scsi_disk_invalid_field(scsi_disk_t *dev, const uint32_t field) { scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_INV_FIELD_IN_CMD_PACKET; scsi_disk_ascq = 0; + scsi_disk_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); scsi_disk_cmd_error(dev); dev->tf->status = 0x53; } static void -scsi_disk_invalid_field_pl(scsi_disk_t *dev) +scsi_disk_invalid_field_pl(scsi_disk_t *dev, const uint32_t field) { scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; scsi_disk_ascq = 0; + scsi_disk_info = (field >> 24) | + ((field >> 16) << 8) | + ((field >> 8) << 16) | + ( field << 24); scsi_disk_cmd_error(dev); dev->tf->status = 0x53; } static void -scsi_disk_data_phase_error(scsi_disk_t *dev) +scsi_disk_data_phase_error(scsi_disk_t *dev, const uint32_t info) { scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; scsi_disk_asc = ASC_DATA_PHASE_ERROR; scsi_disk_ascq = 0; + scsi_disk_info = (info >> 24) | + ((info >> 16) << 8) | + ((info >> 8) << 16) | + ( info << 24); scsi_disk_cmd_error(dev); } static int -scsi_disk_blocks(scsi_disk_t *dev, int32_t *len, UNUSED(int first_batch), int out) +scsi_disk_blocks(scsi_disk_t *dev, int32_t *len, UNUSED(int first_batch), const int out) { + const uint32_t medium_size = hdd_image_get_last_sector(dev->id) + 1; + *len = 0; - uint32_t medium_size = hdd_image_get_last_sector(dev->id) + 1; if (!dev->sector_len) { scsi_disk_command_complete(dev); return -1; } - scsi_disk_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", + scsi_disk_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); if (dev->sector_pos >= medium_size) { - scsi_disk_log("SCSI HD %i: Trying to %s beyond the end of disk\n", dev->id, out ? "write" : "read"); + scsi_disk_log(dev->log, "Trying to %s beyond the end of disk\n", + out ? "write" : "read"); scsi_disk_lba_out_of_range(dev); return 0; } @@ -746,68 +769,90 @@ scsi_disk_blocks(scsi_disk_t *dev, int32_t *len, UNUSED(int first_batch), int ou for (int i = 0; i < dev->requested_blocks; i++) { if (out) { - if (hdd_image_write(dev->id, dev->sector_pos + i, 1, dev->temp_buffer + (i << 9)) < 0) { + if (hdd_image_write(dev->id, dev->sector_pos, 1, dev->temp_buffer + + (i << 9)) < 0) { scsi_disk_write_error(dev); return -1; } } else { - if (hdd_image_read(dev->id, dev->sector_pos + i, 1, dev->temp_buffer + (i << 9)) < 0) { + if (hdd_image_read(dev->id, dev->sector_pos, 1, dev->temp_buffer + + (i << 9)) < 0) { scsi_disk_read_error(dev); return -1; } } + dev->sector_pos++; } - scsi_disk_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + scsi_disk_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - dev->sector_pos += dev->requested_blocks; dev->sector_len -= dev->requested_blocks; return 1; } static int -scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb) +scsi_disk_pre_execution_check(scsi_disk_t *dev, const uint8_t *cdb) { - if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { - scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", - dev->id, ((dev->tf->request_length >> 5) & 7)); - scsi_disk_invalid_lun(dev); + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && + (cdb[1] & 0xe0)) { + scsi_disk_log(dev->log, "Attempting to execute a unknown command " + "targeted at SCSI LUN %i\n", + ((dev->tf->request_length >> 5) & 7)); + scsi_disk_invalid_lun(dev, cdb[1] >> 5); return 0; } if (!(scsi_disk_command_flags[cdb[0]] & IMPLEMENTED)) { - scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus == HDD_BUS_SCSI) ? "SCSI" : "ATAPI"); - scsi_disk_illegal_opcode(dev); + scsi_disk_log(dev->log, "Attempting to execute unknown " + "command %02X over %s\n", cdb[0], + (dev->drv->bus_type == HDD_BUS_SCSI) ? "SCSI" : "ATAPI"); + scsi_disk_illegal_opcode(dev, cdb[0]); return 0; } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ + if ((dev->drv->bus_type < HDD_BUS_SCSI) && + (scsi_disk_command_flags[cdb[0]] & SCSI_ONLY)) { + scsi_disk_log(dev->log, "Attempting to execute SCSI-only command %02X " + "over ATAPI\n", cdb[0]); + scsi_disk_illegal_opcode(dev, cdb[0]); + return 0; + } + + if ((dev->drv->bus_type == HDD_BUS_SCSI) && + (scsi_disk_command_flags[cdb[0]] & ATAPI_ONLY)) { + scsi_disk_log(dev->log, "Attempting to execute ATAPI-only command %02X " + "over SCSI\n", cdb[0]); + scsi_disk_illegal_opcode(dev, cdb[0]); + return 0; + } + + /* + Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. + */ if (cdb[0] != GPCMD_REQUEST_SENSE) scsi_disk_sense_clear(dev, cdb[0]); - scsi_disk_log("SCSI HD %i: Continuing with command\n", dev->id); + scsi_disk_log(dev->log, "Continuing with command %02X\n", cdb[0]); return 1; } static void -scsi_disk_seek(scsi_disk_t *dev, uint32_t pos) +scsi_disk_seek(const scsi_disk_t *dev, const uint32_t pos) { - /* scsi_disk_log("SCSI HD %i: Seek %08X\n", dev->id, pos); */ + /* scsi_disk_log(dev->log, "Seek %08X\n", pos); */ hdd_image_seek(dev->id, pos); } static void scsi_disk_rezero(scsi_disk_t *dev) { - if (dev->id == 0xff) - return; - - dev->sector_pos = dev->sector_len = 0; - scsi_disk_seek(dev, 0); + if (dev->id != 0xff) { + dev->sector_pos = dev->sector_len = 0; + scsi_disk_seek(dev, 0); + } } void @@ -824,34 +869,38 @@ scsi_disk_reset(scsi_common_t *sc) dev->packet_status = PHASE_NONE; dev->unit_attention = 0; dev->cur_lun = SCSI_LUN_USE_CDB; + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = dev->unit_attention = 0; + scsi_disk_info = 0x00; } void -scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, + const uint8_t alloc_length, const int desc) { - /*Will return 18 bytes of 0*/ + /* Will return 18 bytes of 0. */ if (alloc_length != 0) { memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, dev->sense, alloc_length); - else { + if (desc) { buffer[1] = scsi_disk_sense_key; buffer[2] = scsi_disk_asc; buffer[3] = scsi_disk_ascq; - } - } else - return; + } else + memcpy(buffer, dev->sense, alloc_length); - buffer[0] = 0x70; + buffer[0] = desc ? 0x70 : 0xf0; + buffer[7] = 10; - scsi_disk_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + scsi_disk_log(dev->log, "Reporting sense: %02X %02X %02X\n", + buffer[2], buffer[12], buffer[13]); - /* Clear the sense stuff as per the spec. */ - scsi_disk_sense_clear(dev, GPCMD_REQUEST_SENSE); + /* Clear the sense stuff as per the spec. */ + scsi_disk_sense_clear(dev, GPCMD_REQUEST_SENSE); + } } static void -scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) +scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, + const uint8_t alloc_length) { scsi_disk_t *dev = (scsi_disk_t *) sc; @@ -859,41 +908,42 @@ scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t all } static void -scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) +scsi_disk_set_buf_len(const scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) { - if (dev->drv->bus == HDD_BUS_SCSI) { + if (dev->drv->bus_type == HDD_BUS_SCSI) { if (*BufLen == -1) *BufLen = *src_len; else { *BufLen = MIN(*src_len, *BufLen); *src_len = *BufLen; } - scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen); + scsi_disk_log(dev->log, "Actual transfer length: %i\n", *BufLen); } } static void -scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) +scsi_disk_command(scsi_common_t *sc, const uint8_t *cdb) { - scsi_disk_t *dev = (scsi_disk_t *) sc; - int ret; - int32_t blen = 0; - int32_t *BufLen; - int32_t len; - int32_t max_len; - int32_t alloc_length; - int pos = 0; - int idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t last_sector = 0; - char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - int block_desc = 0; - uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_id & 0x0f; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', + 'v', '1', '.', '0', '0', 0 }; + scsi_disk_t * dev = (scsi_disk_t *) sc; + const uint32_t last_sector = hdd_image_get_last_sector(dev->id); + const uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_id & 0x0f; + int32_t blen = 0; + int pos = 0; + int idx = 0; + int block_desc; + int ret; + int32_t * BufLen; + int32_t len; + int32_t max_len; + int32_t alloc_length; + unsigned size_idx; + unsigned preamble_len; - if (dev->drv->bus == HDD_BUS_SCSI) { + if (dev->drv->bus_type == HDD_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->tf->status &= ~ERR_STAT; } else { @@ -901,8 +951,6 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->tf->error = 0; } - last_sector = hdd_image_get_last_sector(dev->id); - dev->packet_len = 0; dev->request_pos = 0; @@ -918,11 +966,12 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) memcpy(dev->current_cdb, cdb, 12); if (cdb[0] != 0) { - scsi_disk_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", - dev->id, cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); - scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->tf->request_length); + scsi_disk_log(dev->log, "Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", + cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); + scsi_disk_log(dev->log, "Request length: %04X\n", dev->tf->request_length); - scsi_disk_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + scsi_disk_log(dev->log, "CDB: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X\n", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); } @@ -931,14 +980,17 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + /* + This handles the Not Ready/Unit Attention check if it has to be + handled at this point. + */ if (scsi_disk_pre_execution_check(dev, cdb) == 0) return; switch (cdb[0]) { case GPCMD_SEND_DIAGNOSTIC: if (!(cdb[1] & (1 << 2))) { - scsi_disk_invalid_field(dev); + scsi_disk_invalid_field(dev, cdb[1]); return; } fallthrough; @@ -961,9 +1013,6 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not - ready, a standalone REQUEST SENSE should forget about the not - ready, and report unit attention straight away. */ len = cdb[4]; if (!len) { @@ -977,14 +1026,11 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_buf_alloc(dev, 256); scsi_disk_set_buf_len(dev, BufLen, &len); - if (*BufLen < cdb[4]) - cdb[4] = *BufLen; - len = (cdb[1] & 1) ? 8 : 18; scsi_disk_request_sense(dev, dev->temp_buffer, *BufLen, cdb[1] & 1); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); - scsi_disk_data_command_finish(dev, len, len, cdb[4], 0); + scsi_disk_data_command_finish(dev, len, len, *BufLen, 0); break; case GPCMD_MECHANISM_STATUS: @@ -1020,12 +1066,15 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; @@ -1033,54 +1082,45 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; } - if (dev->sector_pos > last_sector) { + if (dev->sector_pos > last_sector) scsi_disk_lba_out_of_range(dev); - return; + else { + if (dev->sector_len) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + dev->packet_len = max_len * alloc_length; + scsi_disk_buf_alloc(dev, dev->packet_len); + + dev->drv->seek_pos = dev->sector_pos; + dev->drv->seek_len = dev->sector_len; + + ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + if (ret > 0) { + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_disk_data_command_finish(dev, alloc_length, 512, alloc_length, 0); + + ui_sb_update_icon(SB_HDD | dev->drv->bus_type, dev->packet_status != PHASE_COMPLETE); + } else { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); + scsi_disk_buf_free(dev); + } + } else { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log(dev->log, "All done - callback set\n"); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); + } } - - if (!dev->sector_len) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * SCSI_TIME; - scsi_disk_set_callback(dev); - break; - } - - max_len = dev->sector_len; - /* - If we're reading all blocks in one go for DMA, why not also for - PIO, it should NOT matter anyway, this step should be identical - and only the way the read dat is transferred to the host should - be different. - */ - dev->requested_blocks = max_len; - - dev->packet_len = max_len * alloc_length; - scsi_disk_buf_alloc(dev, dev->packet_len); - - dev->drv->seek_pos = dev->sector_pos; - dev->drv->seek_len = dev->sector_len; - - ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); - if (ret <= 0) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; - dev->callback = 20.0 * SCSI_TIME; - scsi_disk_set_callback(dev); - scsi_disk_buf_free(dev); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - scsi_disk_data_command_finish(dev, alloc_length, 512, alloc_length, 0); - - ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: @@ -1111,23 +1151,26 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = 256; dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, + scsi_disk_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_10: case GPCMD_WRITE_10: case GPCMD_WRITE_AND_VERIFY_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + scsi_disk_log(dev->log, "Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; case GPCMD_VERIFY_12: case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + dev->sector_len = (((uint32_t) cdb[6]) << 24) | + (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | + (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); break; @@ -1135,90 +1178,79 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; } - if (dev->sector_pos > last_sector) { + if (dev->sector_pos > last_sector) scsi_disk_lba_out_of_range(dev); - return; + else { + if (dev->sector_len) { + dev->drv->seek_pos = dev->sector_pos; + dev->drv->seek_len = dev->sector_len; + + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + dev->packet_len = max_len * alloc_length; + scsi_disk_buf_alloc(dev, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_disk_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + + ui_sb_update_icon(SB_HDD | dev->drv->bus_type, dev->packet_status != PHASE_COMPLETE); + } else { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log(dev->log, "All done - callback set\n"); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); + } } - - if (!dev->sector_len) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * SCSI_TIME; - scsi_disk_set_callback(dev); - break; - } - - dev->drv->seek_pos = dev->sector_pos; - dev->drv->seek_len = dev->sector_len; - - max_len = dev->sector_len; - /* - If we're writing all blocks in one go for DMA, why not also for - PIO, it should NOT matter anyway, this step should be identical - and only the way the read dat is transferred to the host should - be different. - */ - dev->requested_blocks = max_len; - - dev->packet_len = max_len * alloc_length; - scsi_disk_buf_alloc(dev, dev->packet_len); - - dev->requested_blocks = max_len; - dev->packet_len = max_len << 9; - - scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - scsi_disk_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - - ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_WRITE_SAME_10: alloc_length = 512; - if ((cdb[1] & 6) == 6) { - scsi_disk_invalid_field(dev); - return; + if ((cdb[1] & 6) == 6) + scsi_disk_invalid_field(dev, cdb[1]); + else { + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (dev->sector_pos > last_sector) + scsi_disk_lba_out_of_range(dev); + else { + if (dev->sector_len) { + scsi_disk_buf_alloc(dev, alloc_length); + scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + dev->requested_blocks = 1; + + dev->packet_len = alloc_length; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); + + ui_sb_update_icon(SB_HDD | dev->drv->bus_type, + dev->packet_status != PHASE_COMPLETE); + } else { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log(dev->log, "All done - callback set\n"); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * SCSI_TIME; + scsi_disk_set_callback(dev); + } + } } - - dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - if (dev->sector_pos > last_sector) { - scsi_disk_lba_out_of_range(dev); - return; - } - - if (!dev->sector_len) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * SCSI_TIME; - scsi_disk_set_callback(dev); - break; - } - - scsi_disk_buf_alloc(dev, alloc_length); - scsi_disk_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - max_len = 1; - dev->requested_blocks = 1; - - dev->packet_len = alloc_length; - - scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); - - scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); - - ui_sb_update_icon(SB_HDD | dev->drv->bus, dev->packet_status != PHASE_COMPLETE); - return; + break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); - if (dev->drv->bus == HDD_BUS_SCSI) + if (dev->drv->bus_type == HDD_BUS_SCSI) block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; else block_desc = 0; @@ -1235,7 +1267,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) alloc_length = len; if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc); + len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, + cdb[2], block_desc); if (len > alloc_length) len = alloc_length; dev->temp_buffer[0] = len - 1; @@ -1261,10 +1294,10 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) alloc_length = len; scsi_disk_set_buf_len(dev, BufLen, &alloc_length); - scsi_disk_log("SCSI HDD %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + scsi_disk_log(dev->log, "Reading mode page: %02X...\n", cdb[2]); scsi_disk_data_command_finish(dev, len, len, alloc_length, 0); - return; + break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: @@ -1282,7 +1315,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->total_length = len; dev->do_page_save = cdb[1] & 1; scsi_disk_data_command_finish(dev, len, len, len, 1); - return; + break; case GPCMD_INQUIRY: max_len = cdb[3]; @@ -1291,7 +1324,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) if ((!max_len) || (*BufLen == 0)) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ + /* scsi_disk_log(dev->log, "All done - callback set\n"); */ dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * SCSI_TIME; break; @@ -1317,7 +1350,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) case 0x83: if (idx + 24 > max_len) { scsi_disk_buf_free(dev); - scsi_disk_data_phase_error(dev); + scsi_disk_data_phase_error(dev, idx + 24); return; } @@ -1325,7 +1358,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->temp_buffer[idx++] = 0x00; dev->temp_buffer[idx++] = 0x00; dev->temp_buffer[idx++] = 20; - ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Serial */ + /* Serial */ + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); idx += 20; if (idx + 72 > cdb[4]) @@ -1334,16 +1368,19 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->temp_buffer[idx++] = 0x01; dev->temp_buffer[idx++] = 0x00; dev->temp_buffer[idx++] = 68; - ide_padstr8(dev->temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + /* Vendor */ + ide_padstr8(dev->temp_buffer + idx, 8, EMU_NAME); idx += 8; - ide_padstr8(dev->temp_buffer + idx, 40, device_identify_ex); /* Product */ + /* Product */ + ide_padstr8(dev->temp_buffer + idx, 40, device_identify_ex); idx += 40; - ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Product */ + /* Product */ + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); idx += 20; break; default: - scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - scsi_disk_invalid_field(dev); + scsi_disk_log(dev->log, "INQUIRY: Invalid page: %02X\n", cdb[2]); + scsi_disk_invalid_field(dev, cdb[2]); scsi_disk_buf_free(dev); return; } @@ -1353,19 +1390,23 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->temp_buffer, 0, 8); if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) - dev->temp_buffer[0] = 0x7f; /*No physical device on this LUN*/ + dev->temp_buffer[0] = 0x7f; /* No physical device on this LUN */ else - dev->temp_buffer[0] = 0; /*SCSI HD*/ - dev->temp_buffer[1] = 0; /*Fixed*/ - dev->temp_buffer[2] = (dev->drv->bus == HDD_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - dev->temp_buffer[3] = (dev->drv->bus == HDD_BUS_SCSI) ? 0x02 : 0x21; + dev->temp_buffer[0] = 0; /* SCSI HD */ + dev->temp_buffer[1] = 0; /* Fixed */ + /* SCSI-2 compliant */ + dev->temp_buffer[2] = (dev->drv->bus_type == HDD_BUS_SCSI) ? 0x02 : 0x00; + dev->temp_buffer[3] = (dev->drv->bus_type == HDD_BUS_SCSI) ? 0x02 : 0x21; dev->temp_buffer[4] = 31; - dev->temp_buffer[6] = 1; /* 16-bit transfers supported */ - dev->temp_buffer[7] = 0x20; /* Wide bus supported */ + dev->temp_buffer[6] = 1; /* 16-bit transfers supported */ + dev->temp_buffer[7] = 0x20; /* Wide bus supported */ - ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(dev->temp_buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION_EX); /* Revision */ + /* Vendor */ + ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); + /* Product */ + ide_padstr8(dev->temp_buffer + 16, 16, device_identify); + /* Revision */ + ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION_EX); idx = 36; if (max_len == 96) { @@ -1437,12 +1478,12 @@ atapi_out: break; default: - scsi_disk_illegal_opcode(dev); + scsi_disk_illegal_opcode(dev, cdb[0]); break; } - /* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, - dev->tf->request_length); */ + /* scsi_disk_log(dev->log, "Phase: %02X, request length: %i\n", + dev->tf->phase, dev->tf->request_length); */ if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) scsi_disk_buf_free(dev); @@ -1460,35 +1501,30 @@ scsi_disk_command_stop(scsi_common_t *sc) static uint8_t scsi_disk_phase_data_out(scsi_common_t *sc) { - scsi_disk_t *dev = (scsi_disk_t *) sc; - uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_id & 0x0f; + scsi_disk_t *dev = (scsi_disk_t *) sc; + const uint8_t scsi_bus = (dev->drv->scsi_id >> 4) & 0x0f; + const uint8_t scsi_id = dev->drv->scsi_id & 0x0f; + const int32_t *BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; + const uint32_t last_sector = hdd_image_get_last_sector(dev->id); + int len = 0; + uint8_t error = 0; + int ret = 1; int i; - const int32_t *BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; - uint32_t last_sector = hdd_image_get_last_sector(dev->id); - uint32_t c; - uint32_t h; - uint32_t s; - int len = 0; - uint32_t last_to_write = 0; + uint32_t last_to_write; uint16_t block_desc_len; uint16_t pos; uint16_t param_list_len; uint8_t hdr_len; uint8_t val; - uint8_t old_val; - uint8_t ch; - uint8_t error = 0; - uint8_t page; - uint8_t page_len; - if (!*BufLen) { + if (!*BufLen) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + else switch (dev->current_cdb[0]) { + default: + log_fatal(dev->log, "Bad Command for phase 2 (%02X)\n", dev->current_cdb[0]); + ret = 0; + break; - return 1; - } - - switch (dev->current_cdb[0]) { case GPCMD_VERIFY_6: case GPCMD_VERIFY_10: case GPCMD_VERIFY_12: @@ -1514,9 +1550,9 @@ scsi_disk_phase_data_out(scsi_common_t *sc) dev->temp_buffer[2] = (i >> 8) & 0xff; dev->temp_buffer[3] = i & 0xff; } else if (dev->current_cdb[1] & 4) { - s = (i % dev->drv->spt); - h = ((i - s) / dev->drv->spt) % dev->drv->hpc; - c = ((i - s) / dev->drv->spt) / dev->drv->hpc; + uint32_t s = (i % dev->drv->spt); + uint32_t h = ((i - s) / dev->drv->spt) % dev->drv->hpc; + uint32_t c = ((i - s) / dev->drv->spt) / dev->drv->hpc; dev->temp_buffer[0] = (c >> 16) & 0xff; dev->temp_buffer[1] = (c >> 8) & 0xff; dev->temp_buffer[2] = c & 0xff; @@ -1542,7 +1578,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) param_list_len = dev->current_cdb[4]; } - if (dev->drv->bus == HDD_BUS_SCSI) { + if (dev->drv->bus_type == HDD_BUS_SCSI) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { block_desc_len = dev->temp_buffer[2]; block_desc_len <<= 8; @@ -1559,27 +1595,29 @@ scsi_disk_phase_data_out(scsi_common_t *sc) while (1) { if (pos >= param_list_len) { - scsi_disk_log("SCSI HD %i: Buffer has only block descriptor\n", dev->id); + scsi_disk_log(dev->log, "Buffer has only block descriptor\n"); break; } - page = dev->temp_buffer[pos] & 0x3F; - page_len = dev->temp_buffer[pos + 1]; + const uint8_t page = dev->temp_buffer[pos] & 0x3f; + const uint8_t page_len = dev->temp_buffer[pos + 1]; pos += 2; if (!(scsi_disk_mode_sense_page_flags & (1LL << ((uint64_t) page)))) error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; - val = dev->temp_buffer[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else - error |= 1; + else for (i = 0; i < page_len; i++) { + const uint8_t old = dev->ms_pages_saved.pages[page][i + 2]; + const uint8_t ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; + + val = dev->temp_buffer[pos + i]; + + if (val != old) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + scsi_disk_invalid_field_pl(dev, val); + error |= 1; } } } @@ -1594,22 +1632,17 @@ scsi_disk_phase_data_out(scsi_common_t *sc) break; } - if (error) { + if (error) scsi_disk_buf_free(dev); - scsi_disk_invalid_field_pl(dev); - } - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); break; } scsi_disk_command_stop((scsi_common_t *) dev); - return 1; + return ret; } static int -scsi_disk_get_max(int ide_has_dma, int type) +scsi_disk_get_max(const ide_t *ide, int ide_has_dma, const int type) { int ret; @@ -1635,7 +1668,7 @@ scsi_disk_get_max(int ide_has_dma, int type) } static int -scsi_disk_get_timings(int ide_has_dma, int type) +scsi_disk_get_timings(const ide_t *ide, const int ide_has_dma, const int type) { int ret; @@ -1657,29 +1690,28 @@ scsi_disk_get_timings(int ide_has_dma, int type) return ret; } -/** - * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command +/* + Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command */ static void -scsi_disk_identify(ide_t *ide, int ide_has_dma) +scsi_disk_identify(const ide_t *ide, const int ide_has_dma) { - const scsi_disk_t *dev; - char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; - - dev = (scsi_disk_t *) ide->sc; + const scsi_disk_t *dev = (scsi_disk_t *) ide->sc; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; device_identify[7] = dev->id + 0x30; - scsi_disk_log("ATAPI Identify: %s\n", device_identify); + scsi_disk_log(dev->log, "ATAPI Identify: %s\n", device_identify); /* ATAPI device, direct-access device, non-removable media, accelerated DRQ */ ide->buffer[0] = 0x8000 | (0 << 8) | 0x00 | (2 << 5); - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + ide->buffer[49] = 0x200; /* LBA supported */ + /* Interpret zero byte count limit as maximum length. */ + ide->buffer[126] = 0xfffe; if (ide_has_dma) { ide->buffer[71] = 30; @@ -1693,19 +1725,13 @@ void scsi_disk_hard_reset(void) { scsi_disk_t *dev; - scsi_device_t *sd; - ide_t *id; - uint8_t scsi_bus; - uint8_t scsi_id; - uint8_t valid = 0; for (uint8_t c = 0; c < HDD_NUM; c++) { - valid = 0; - if (hdd[c].bus == HDD_BUS_SCSI) { - scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); + uint8_t valid = 0; - scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; - scsi_id = hdd[c].scsi_id & 0x0f; + if (hdd[c].bus_type == HDD_BUS_SCSI) { + const uint8_t scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; + const uint8_t scsi_id = hdd[c].scsi_id & 0x0f; /* Make sure to ignore any SCSI disk that has an out of range SCSI bus. */ if (scsi_bus >= SCSI_BUS_MAX) @@ -1727,16 +1753,25 @@ scsi_disk_hard_reset(void) hdd_preset_apply(c); - if (!hdd[c].priv) - hdd[c].priv = (scsi_disk_t *) calloc(1, sizeof(scsi_disk_t)); + if (hdd[c].priv == NULL) { + hdd[c].priv = (scsi_disk_t *) calloc(1, sizeof(scsi_disk_t)); + dev = (scsi_disk_t *) hdd[c].priv; + + char n[1024] = { 0 }; + + sprintf(n, "HDD %i SCSI ", c + 1); + dev->log = log_open(n); + } dev = (scsi_disk_t *) hdd[c].priv; - if (!dev->tf) + scsi_disk_log(dev->log, "SCSI disk hard_reset drive=%d\n", c); + + if (dev->tf == NULL) dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t)); /* SCSI disk, attach to the SCSI bus. */ - sd = &scsi_devices[scsi_bus][scsi_id]; + scsi_device_t *sd = &scsi_devices[scsi_bus][scsi_id]; sd->sc = (scsi_common_t *) dev; sd->command = scsi_disk_command; @@ -1746,18 +1781,22 @@ scsi_disk_hard_reset(void) sd->command_stop = scsi_disk_command_stop; sd->type = SCSI_FIXED_DISK; - scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); - } else if (hdd[c].bus == HDD_BUS_ATAPI) { + scsi_disk_log(dev->log, "SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id); + } else if (hdd[c].bus_type == HDD_BUS_ATAPI) { /* Make sure to ignore any SCSI disk whose image file name is empty. */ if (strlen(hdd[c].fn) == 0) continue; /* Make sure to ignore any SCSI disk whose image fails to load. */ + /* ATAPI hard disk, attach to the IDE bus. */ - id = ide_get_drive(hdd[c].ide_channel); - /* If the IDE channel is initialized, we attach to it, + ide_t *id = ide_get_drive(hdd[c].ide_channel); + + /* + If the IDE channel is initialized, we attach to it, otherwise, we do nothing - it's going to be a drive - that's not attached to anything. */ + that's not attached to anything. + */ if (id) { if (!hdd_image_load(c)) continue; @@ -1766,7 +1805,7 @@ scsi_disk_hard_reset(void) hdd_preset_apply(c); - if (!hdd[c].priv) + if (hdd[c].priv == NULL) hdd[c].priv = (scsi_disk_t *) calloc(1, sizeof(scsi_disk_t)); dev = (scsi_disk_t *) hdd[c].priv; @@ -1786,12 +1825,15 @@ scsi_disk_hard_reset(void) id->interrupt_drq = 0; ide_atapi_attach(id); - } - scsi_disk_log("ATAPI hard disk drive %i attached to IDE channel %i\n", c, hdd[c].ide_channel); + scsi_disk_log(dev->log, "ATAPI hard disk drive %i attached to IDE channel %i\n", + c, hdd[c].ide_channel); + } } if (valid) { + dev = (scsi_disk_t *) hdd[c].priv; + dev->id = c; dev->drv = &hdd[c]; @@ -1807,28 +1849,32 @@ scsi_disk_hard_reset(void) void scsi_disk_close(void) { - scsi_disk_t *dev; - uint8_t scsi_bus; - uint8_t scsi_id; - for (uint8_t c = 0; c < HDD_NUM; c++) { - if ((hdd[c].bus == HDD_BUS_SCSI) || (hdd[c].bus == HDD_BUS_ATAPI)) { - if (hdd[c].bus == HDD_BUS_SCSI) { - scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; - scsi_id = hdd[c].scsi_id & 0x0f; + if ((hdd[c].bus_type == HDD_BUS_SCSI) || (hdd[c].bus_type == HDD_BUS_ATAPI)) { + if (hdd[c].bus_type == HDD_BUS_SCSI) { + const uint8_t scsi_bus = (hdd[c].scsi_id >> 4) & 0x0f; + const uint8_t scsi_id = hdd[c].scsi_id & 0x0f; memset(&scsi_devices[scsi_bus][scsi_id], 0x00, sizeof(scsi_device_t)); } hdd_image_close(c); - dev = hdd[c].priv; + scsi_disk_t *dev = hdd[c].priv; if (dev) { if (dev->tf) free(dev->tf); + if (dev->log != NULL) { + scsi_disk_log(dev->log, "Log closed\n"); + + log_close(dev->log); + dev->log = NULL; + } + free(dev); + hdd[c].priv = NULL; } } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 016e50c40..2f4f5da14 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -5913,7 +5913,7 @@ const device_t sb_16_pnp_device = { .init = sb_16_pnp_init, .close = sb_close, .reset = NULL, - { .available = sb_16_pnp_noide_available }, + .available = sb_16_pnp_noide_available, .speed_changed = sb_speed_changed, .force_redraw = NULL, .config = sb_16_pnp_config @@ -6039,7 +6039,7 @@ const device_t sb_awe64_device = { .init = sb_awe32_pnp_init, .close = sb_awe32_close, .reset = NULL, - { .available = sb_awe64_noide_available }, + .available = sb_awe64_noide_available, .speed_changed = sb_speed_changed, .force_redraw = NULL, .config = sb_awe64_config diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index fb0224bc6..c85628e01 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -17,16 +17,18 @@ * Copyright 2023 Miran Grca. */ #include +#ifdef ENABLE_IOCTL_LOG #include +#endif #include #include #include #include #include #define HAVE_STDARG_H -#include <86box/86box.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> +#include <86box/log.h> #include <86box/plat_unused.h> #include <86box/plat_cdrom.h> @@ -35,223 +37,203 @@ of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) -typedef struct dummy_cdrom_ioctl_t { +typedef struct ioctl_t { + cdrom_t *dev; + void *log; int toc_valid; -} dummy_cdrom_ioctl_t; +} ioctl_t; -#ifdef ENABLE_DUMMY_CDROM_IOCTL_LOG -int dummy_cdrom_ioctl_do_log = ENABLE_DUMMY_CDROM_IOCTL_LOG; +#ifdef ENABLE_IOCTL_LOG +int ioctl_do_log = ENABLE_IOCTL_LOG; void -dummy_cdrom_ioctl_log(const char *fmt, ...) +ioctl_log(void *priv, const char *fmt, ...) { - va_list ap; - - if (dummy_cdrom_ioctl_do_log) { + if (ioctl_do_log) { + va_list ap; va_start(ap, fmt); - pclog_ex(fmt, ap); + log_out(priv, fmt, ap); va_end(ap); } } #else -# define dummy_cdrom_ioctl_log(fmt, ...) +# define ioctl_log(priv, fmt, ...) #endif -static int -plat_cdrom_open(void *local) +/* Internal functions. */ +static void +ioctl_close_handle(UNUSED(const ioctl_t *ioctl)) { return 0; } static int -plat_cdrom_load(void *local) +ioctl_open_handle(UNUSED(ioctl_t *ioctl)) { return 0; } static void -plat_cdrom_read_toc(void *local) +ioctl_read_toc(ioctl_t *ioctl) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + if (!ioctl->toc_valid) { + ioctl->toc_valid = 1; + } +} + +/* Shared functions. */ +static int +ioctl_get_track_info(UNUSED(const void *local), UNUSED(const uint32_t track), + UNUSED(int end), UNUSED(track_info_t *ti)) +{ + return 0; +} + +static void +ioctl_get_raw_track_info(const void *local, UNUSED(int *num), UNUSED(uint8_t *rti)) +{ + ioctl_t *ioctl = (ioctl_t *) local; if (!ioctl->toc_valid) ioctl->toc_valid = 1; } -void -plat_cdrom_get_raw_track_info(UNUSED(void *local), int *num, raw_track_info_t *rti) +static void +ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) { *num = 1; memset(rti, 0x00, 11); } -int -plat_cdrom_is_track_audio(void *local, uint32_t sector) +static int +ioctl_is_track_pre(const void *local, const uint32_t sector) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - const int ret = 0; - - dummy_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); - - return ret; -} - -int -plat_cdrom_is_track_pre(void *local, uint32_t sector) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + ioctl_t *ioctl = (ioctl_t *) local; plat_cdrom_read_toc(ioctl); const int ret = 0; - dummy_cdrom_ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); + ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); return ret; } -uint32_t -plat_cdrom_get_track_start(void *local, uint32_t sector, uint8_t *attr, uint8_t *track) +static int +ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - return 0x00000000; -} - -uint32_t -plat_cdrom_get_last_block(void *local) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - return 0x00000000; -} - -int -plat_cdrom_ext_medium_changed(UNUSED(void *local)) -{ -#if 0 - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); -#endif - - int ret = 0; - - dummy_cdrom_ioctl_log("plat_cdrom_ext_medium_changed(): %i\n", ret); - - return ret; -} - -/* This replaces both Info and EndInfo, they are specified by a variable. */ -int -plat_cdrom_get_audio_track_info(void *local, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_read_toc(ioctl); - - if ((track < 1) || (track == 0xaa)) { - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i)\n", track); - return 0; - } - - start->min = 0; - start->sec = 0; - start->fr = 2; - - *track_num = 1; - *attr = 0x14; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", - track, start->min, start->sec, start->fr, *track_num, *attr); - - return 1; -} - -/* TODO: See if track start is adjusted by 150 or not. */ -int -plat_cdrom_get_audio_sub(UNUSED(void *local), UNUSED(uint32_t sector), uint8_t *attr, uint8_t *track, uint8_t *index, - TMSF *rel_pos, TMSF *abs_pos) -{ - *track = 1; - *attr = 0x14; - *index = 1; - - rel_pos->min = 0; - rel_pos->sec = 0; - rel_pos->fr = 0; - abs_pos->min = 0; - abs_pos->sec = 0; - abs_pos->fr = 2; - - dummy_cdrom_ioctl_log("plat_cdrom_get_audio_sub(): %02i, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - *track, *attr, *index, rel_pos->min, rel_pos->sec, rel_pos->fr, abs_pos->min, abs_pos->sec, abs_pos->fr); - - return 1; -} - -int -plat_cdrom_get_sector_size(UNUSED(void *local), UNUSED(uint32_t sector)) -{ - dummy_cdrom_ioctl_log("BytesPerSector=2048\n"); - - return 2048; -} - -int -plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector) -{ - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; + ioctl_t *ioctl = (ioctl_t *) local; plat_cdrom_open(ioctl); /* Raw */ - dummy_cdrom_ioctl_log("Raw\n"); + ioctl_log("Raw\n"); plat_cdrom_close(ioctl); - dummy_cdrom_ioctl_log("ReadSector sector=%d.\n", sector); + ioctl_log("ReadSector sector=%d.\n", sector); return 0; } -void -plat_cdrom_eject(void *local) +static uint8_t +ioctl_get_track_type(UNUSED(const void *local), UNUSED(const uint32_t sector)) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_open(ioctl); - plat_cdrom_close(ioctl); + return 0x00; } -void -plat_cdrom_close(UNUSED(void *local)) +static uint32_t +ioctl_get_last_block(const void *local) { + ioctl_t *ioctl = (ioctl_t *) local; + + ioctl_read_toc(ioctl); + + return 0x00000000; } -int -plat_cdrom_set_drive(void *local, const char *drv) +static int +ioctl_read_dvd_structure(UNUSED(const void *local), UNUSED(const uint8_t layer), UNUSED(const uint8_t format), + UNUSED(uint8_t *buffer), UNUSED(uint32_t *info)) { - dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; - - plat_cdrom_close(ioctl); - - ioctl->toc_valid = 0; - - plat_cdrom_load(ioctl); - - return 1; + return -0x00052100; } -int -plat_cdrom_get_local_size(void) +static int +ioctl_is_dvd(UNUSED(const void *local)) { - return sizeof(dummy_cdrom_ioctl_t); + return 0; +} + +static int +ioctl_has_audio(UNUSED(const void *local)) +{ + return 0; +} + +static int +ioctl_ext_medium_changed(UNUSED(void *local)) +{ +#if 0 + ioctl_t *ioctl = (ioctl_t *) local; +#endif + int ret = 0; + + ioctl_log("ioctl_ext_medium_changed(): %i\n", ret); + + return ret; +} + +static void +ioctl_close(void *local) +{ + ioctl_t *ioctl = (ioctl_t *) local; + + ioctl_close_handle(ioctl); + ioctl->handle = NULL; + + ioctl_log(ioctl->log, "Log closed\n"); + + log_close(ioctl->log); + ioctl->log = NULL; +} + +static const cdrom_ops_t ioctl_ops = { + ioctl_get_track_info, + ioctl_get_raw_track_info, + ioctl_is_track_pre, + ioctl_read_sector, + ioctl_get_track_type, + ioctl_get_last_block, + ioctl_read_dvd_structure, + ioctl_is_dvd, + ioctl_has_audio, + ioctl_ext_medium_changed, + ioctl_close +}; + +/* Public functions. */ +void * +ioctl_open(cdrom_t *dev, const char *drv) +{ + ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t)); + + if (ioctl != NULL) { + char n[1024] = { 0 }; + + sprintf(n, "CD-ROM %i IOCtl", dev->id + 1); + ioctl->log = log_open(n); + + memset(ioctl->path, 0x00, sizeof(ioctl->path)); + + wsprintf(ioctl->path, L"%S", &(drv[8])); + ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); + + ioctl->dev = dev; + ioctl->toc_valid = 0; + + dev->ops = &ioctl_ops; + } + + return ioctl; } From 7c6f45b4cd59e3d54f731f22965bc004f62fa9e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 18:39:26 +0100 Subject: [PATCH 0160/1190] Fixed CD-ROM image mounting crashes and, hopefully, Linux compiles. --- src/CMakeLists.txt | 1 + src/cdrom/cdrom.c | 9 +++++---- src/cdrom/cdrom_image.c | 4 ++-- src/qt/dummy_cdrom_ioctl.c | 2 +- src/unix/dummy_cdrom_ioctl.c | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d6daff9c..4e2a2313d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ endif() add_executable(86Box 86box.c + all_devices.c config.c log.c random.c diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 5ddd788cb..2c439e76a 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -22,6 +22,7 @@ #include #include #include +#include #include <86box/86box.h> #include <86box/device.h> #include <86box/config.h> @@ -1522,14 +1523,14 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) case 0x00: dev->cd_end = pos2; break; - case 0x40: + case 0x40: { const int m = bcd2bin((pos >> 24) & 0xff); const int s = bcd2bin((pos >> 16) & 0xff); const int f = bcd2bin((pos >> 8) & 0xff); pos2 = MSFtoLBA(m, s, f) - 150; dev->cd_end = pos2; break; - case 0x80: + } case 0x80: dev->cd_end = (pos2 >> 24) & 0xff; break; case 0xc0: @@ -1572,7 +1573,7 @@ cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type) } dev->seek_pos = pos2; break; - case 0x40: + case 0x40: { const int m = bcd2bin((pos >> 24) & 0xff); const int s = bcd2bin((pos >> 16) & 0xff); const int f = bcd2bin((pos >> 8) & 0xff); @@ -1584,7 +1585,7 @@ cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type) dev->seek_pos = pos2; break; - case 0x80: + } case 0x80: dev->seek_pos = (pos >> 24) & 0xff; break; default: diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index e4a425c78..ba4f0164a 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -2006,6 +2006,8 @@ image_open(cdrom_t *dev, const char *path) int ret; const int is_cue = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE")); + img->dev = dev; + if (is_cue) { ret = image_load_cue(img, path); @@ -2029,8 +2031,6 @@ image_open(cdrom_t *dev, const char *path) sprintf(n, "CD-ROM %i Image", dev->id + 1); img->log = log_open(n); - img->dev = dev; - dev->ops = &image_ops; } } diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index c85628e01..a0f95f213 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -30,7 +30,7 @@ #include <86box/cdrom.h> #include <86box/log.h> #include <86box/plat_unused.h> -#include <86box/plat_cdrom.h> +#include <86box/plat_cdrom_ioctl.h> /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index c85628e01..a0f95f213 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -30,7 +30,7 @@ #include <86box/cdrom.h> #include <86box/log.h> #include <86box/plat_unused.h> -#include <86box/plat_cdrom.h> +#include <86box/plat_cdrom_ioctl.h> /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start From ab2d1a3b75f695de65d3dcd826e9efb3fc30d266 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 28 Jan 2025 12:56:44 -0500 Subject: [PATCH 0161/1190] Remove incorrect addition to cmakelist. --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e2a2313d..7d6daff9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,7 +22,6 @@ endif() add_executable(86Box 86box.c - all_devices.c config.c log.c random.c From 1843ad39fdce4b48a47643a8a3e1a489ff2b5704 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 19:25:47 +0100 Subject: [PATCH 0162/1190] More *nix compile fixes. --- src/qt/dummy_cdrom_ioctl.c | 13 +++++++------ src/unix/dummy_cdrom_ioctl.c | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index a0f95f213..59ebee6f3 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -41,6 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; + char path[256]; } ioctl_t; #ifdef ENABLE_IOCTL_LOG @@ -110,11 +111,11 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) { ioctl_t *ioctl = (ioctl_t *) local; - plat_cdrom_read_toc(ioctl); + ioctl_read_toc(ioctl); const int ret = 0; - ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); + ioctl_log("ioctl_is_track_audio(%08X): %i\n", sector, ret); return ret; } @@ -124,12 +125,12 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) { ioctl_t *ioctl = (ioctl_t *) local; - plat_cdrom_open(ioctl); + ioctl_open_handle(ioctl); /* Raw */ ioctl_log("Raw\n"); - plat_cdrom_close(ioctl); + ioctl_close_handle(ioctl); ioctl_log("ReadSector sector=%d.\n", sector); @@ -226,8 +227,8 @@ ioctl_open(cdrom_t *dev, const char *drv) memset(ioctl->path, 0x00, sizeof(ioctl->path)); - wsprintf(ioctl->path, L"%S", &(drv[8])); - ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); + sprintf(ioctl->path, "%s", drv); + ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; ioctl->toc_valid = 0; diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index a0f95f213..59ebee6f3 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -41,6 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; + char path[256]; } ioctl_t; #ifdef ENABLE_IOCTL_LOG @@ -110,11 +111,11 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) { ioctl_t *ioctl = (ioctl_t *) local; - plat_cdrom_read_toc(ioctl); + ioctl_read_toc(ioctl); const int ret = 0; - ioctl_log("plat_cdrom_is_track_audio(%08X): %i\n", sector, ret); + ioctl_log("ioctl_is_track_audio(%08X): %i\n", sector, ret); return ret; } @@ -124,12 +125,12 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) { ioctl_t *ioctl = (ioctl_t *) local; - plat_cdrom_open(ioctl); + ioctl_open_handle(ioctl); /* Raw */ ioctl_log("Raw\n"); - plat_cdrom_close(ioctl); + ioctl_close_handle(ioctl); ioctl_log("ReadSector sector=%d.\n", sector); @@ -226,8 +227,8 @@ ioctl_open(cdrom_t *dev, const char *drv) memset(ioctl->path, 0x00, sizeof(ioctl->path)); - wsprintf(ioctl->path, L"%S", &(drv[8])); - ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); + sprintf(ioctl->path, "%s", drv); + ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; ioctl->toc_valid = 0; From 3cc677ededd0bd2021f0d1a63a9e7c58ce76a1d4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 19:27:28 +0100 Subject: [PATCH 0163/1190] And another. --- src/qt/dummy_cdrom_ioctl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index 59ebee6f3..c849869cb 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -65,7 +65,6 @@ ioctl_log(void *priv, const char *fmt, ...) static void ioctl_close_handle(UNUSED(const ioctl_t *ioctl)) { - return 0; } static int From d52e01bf8f223abca81024a6fc2143d776ebf785 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 19:45:41 +0100 Subject: [PATCH 0164/1190] And yet more *nix compile fixes. --- src/qt/dummy_cdrom_ioctl.c | 16 ++-------------- src/unix/dummy_cdrom_ioctl.c | 17 ++--------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index c849869cb..a2ea26e3f 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -41,6 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; + HANDLE handle; char path[256]; } ioctl_t; @@ -76,9 +77,8 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) { + if (!ioctl->toc_valid) ioctl->toc_valid = 1; - } } /* Shared functions. */ @@ -89,15 +89,6 @@ ioctl_get_track_info(UNUSED(const void *local), UNUSED(const uint32_t track), return 0; } -static void -ioctl_get_raw_track_info(const void *local, UNUSED(int *num), UNUSED(uint8_t *rti)) -{ - ioctl_t *ioctl = (ioctl_t *) local; - - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; -} - static void ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) { @@ -126,9 +117,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) ioctl_open_handle(ioctl); - /* Raw */ - ioctl_log("Raw\n"); - ioctl_close_handle(ioctl); ioctl_log("ReadSector sector=%d.\n", sector); diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 59ebee6f3..a2ea26e3f 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -41,6 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; + HANDLE handle; char path[256]; } ioctl_t; @@ -65,7 +66,6 @@ ioctl_log(void *priv, const char *fmt, ...) static void ioctl_close_handle(UNUSED(const ioctl_t *ioctl)) { - return 0; } static int @@ -77,9 +77,8 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) { + if (!ioctl->toc_valid) ioctl->toc_valid = 1; - } } /* Shared functions. */ @@ -90,15 +89,6 @@ ioctl_get_track_info(UNUSED(const void *local), UNUSED(const uint32_t track), return 0; } -static void -ioctl_get_raw_track_info(const void *local, UNUSED(int *num), UNUSED(uint8_t *rti)) -{ - ioctl_t *ioctl = (ioctl_t *) local; - - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; -} - static void ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) { @@ -127,9 +117,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) ioctl_open_handle(ioctl); - /* Raw */ - ioctl_log("Raw\n"); - ioctl_close_handle(ioctl); ioctl_log("ReadSector sector=%d.\n", sector); From 1968a36350fd15143b137c3d7b3f33182fdf3c8b Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 20:07:18 +0100 Subject: [PATCH 0165/1190] Make handle a void pointer on *nix. --- src/qt/dummy_cdrom_ioctl.c | 2 +- src/unix/dummy_cdrom_ioctl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index a2ea26e3f..ae4eb1727 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -41,7 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; - HANDLE handle; + void *handle; char path[256]; } ioctl_t; diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index a2ea26e3f..ae4eb1727 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -41,7 +41,7 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; int toc_valid; - HANDLE handle; + void *handle; char path[256]; } ioctl_t; From 2d7fb728308e6f27d444dc701c7d42dd2afe7ca3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 28 Jan 2025 23:22:06 +0100 Subject: [PATCH 0166/1190] CD-ROM Image: close log before closing the file, fixes segmentation fault on image unload. --- src/cdrom/cdrom_image.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index ba4f0164a..afc70bda7 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -357,18 +357,15 @@ index_file_init(const uint8_t id, const char *filename, int *error, int *is_viso *is_viso = 1; } - return tf; + return tf; } static void index_file_close(track_index_t *idx) { - if ((idx == NULL) || (idx->file == NULL) || - (idx->file->close == NULL)) + if ((idx == NULL) || (idx->file == NULL)) return; - idx->file->close(idx->file); - image_log(idx->file->log, "Log closed\n"); if (idx->file->log != NULL) { @@ -376,6 +373,9 @@ index_file_close(track_index_t *idx) idx->file->log = NULL; } + if (idx->file->close != NULL) + idx->file->close(idx->file); + idx->file = NULL; } @@ -567,7 +567,7 @@ image_cue_get_buffer(char *str, char **line, const int up) static int image_cue_get_keyword(char **dest, char **line) { - int success = image_cue_get_buffer(temp_keyword, line, 1); + const int success = image_cue_get_buffer(temp_keyword, line, 1); if (success) *dest = temp_keyword; @@ -1676,16 +1676,16 @@ image_clear_tracks(cd_image_t *img) if (((cur->point >= 1) && (cur->point <= 99)) || (cur->point == 0xa2)) for (int j = 0; j < 3; j++) { - idx = &(cur->idx[j]); - /* Make sure we do not attempt to close a NULL file. */ - if ((idx->file != NULL) && (idx->type == INDEX_NORMAL)) { - if (idx->file != last) { - last = idx->file; - index_file_close(idx); - } else - idx->file = NULL; + idx = &(cur->idx[j]); + /* Make sure we do not attempt to close a NULL file. */ + if ((idx->file != NULL) && (idx->type == INDEX_NORMAL)) { + if (idx->file != last) { + last = idx->file; + index_file_close(idx); + } else + idx->file = NULL; + } } - } } /* Now free the array. */ @@ -1905,8 +1905,8 @@ image_get_track_type(const void *local, const uint32_t sector) const track_t *nt = &(img->tracks[i + 1]); if (ct->point == 0xa0) { - uint8_t first = (ct->idx[1].start / 75 / 60); - uint8_t last = (nt->idx[1].start / 75 / 60); + const uint8_t first = (ct->idx[1].start / 75 / 60); + const uint8_t last = (nt->idx[1].start / 75 / 60); if ((trk->point >= first) && (trk->point <= last)) { ret = (ct->idx[1].start / 75) % 60; From b7100a6169579ef89eff96b836fbf935d8486cd7 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 29 Jan 2025 00:33:24 +0100 Subject: [PATCH 0167/1190] Video changes of the night (January 29th, 2025) Matrox MGA: A break from work can save the day all so to say. Fixes bitblt'ing on WinNT4.0/Win2000 using 32bpp modes and possibly other stuff using said Matrox chip. --- src/video/vid_mga.c | 48 ++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 2b9e63af4..ee422fd3f 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -5558,6 +5558,7 @@ blit_bitblt(mystique_t *mystique) mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; src_addr = mystique->dwgreg.ar[3]; + break; } else src_addr += x_dir; @@ -5670,6 +5671,7 @@ blit_bitblt(mystique_t *mystique) mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; src_addr = mystique->dwgreg.ar[3]; + break; } else src_addr += x_dir; @@ -5756,6 +5758,7 @@ blit_bitblt(mystique_t *mystique) mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; src_addr = mystique->dwgreg.ar[3]; + break; } else src_addr += x_dir; @@ -5852,6 +5855,7 @@ blit_bitblt(mystique_t *mystique) mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; src_addr = mystique->dwgreg.ar[3]; + break; } else src_addr += x_dir; @@ -6521,6 +6525,7 @@ mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) mystique->pci_regs[addr] = val; if (addr == 0x30) mystique->pci_regs[addr] &= 1; + if (mystique->pci_regs[0x30] & 0x01) { uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); mem_mapping_set_addr(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); @@ -6533,26 +6538,24 @@ mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) return; case 0x40: - mystique->pci_regs[addr] = val & 0x3f; + mystique->pci_regs[0x40] = val & 0x3f; break; case 0x41: - mystique->pci_regs[addr] = val; + mystique->pci_regs[0x41] = val; break; case 0x42: - mystique->pci_regs[addr] = val & 0x1f; + mystique->pci_regs[0x42] = val & 0x1f; break; case 0x43: - mystique->pci_regs[addr] = val; - if (addr == 0x43) { - if (val & 0x40) { - if (mystique->pci_regs[0x30] & 0x01) { - uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); - mem_mapping_set_addr(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); - } else - mem_mapping_disable(&mystique->bios_rom.mapping); + mystique->pci_regs[0x43] = val; + if (val & 0x40) { + if (mystique->pci_regs[0x30] & 0x01) { + uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); + mem_mapping_set_addr(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); } else - mem_mapping_set_addr(&mystique->bios_rom.mapping, 0x000c0000, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); - } + mem_mapping_disable(&mystique->bios_rom.mapping); + } else + mem_mapping_set_addr(&mystique->bios_rom.mapping, 0x000c0000, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); break; case 0x4c: @@ -6580,17 +6583,17 @@ mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) mystique_ctrl_write_b(addr, val, mystique); break; - case 0xf8: - mystique->pci_regs[0xf8] = val & 0x7; - break; + case 0xf8: + mystique->pci_regs[0xf8] = val & 0x7; + break; - case 0xf9: - mystique->pci_regs[0xf9] = val & 0x3; - break; + case 0xf9: + mystique->pci_regs[0xf9] = val & 0x3; + break; - case 0xfb: - mystique->pci_regs[0xfb] = val; - break; + case 0xfb: + mystique->pci_regs[0xfb] = val; + break; default: break; @@ -6677,6 +6680,7 @@ mystique_init(const device_t *info) mystique->svga.conv_16to32 = tvp3026_conv_16to32; if (mystique->type == MGA_2164W) mystique->svga.decode_mask = 0xffffff; + tvp3026_gpio(mystique_tvp3026_gpio_read, mystique_tvp3026_gpio_write, mystique, mystique->svga.ramdac); } else { video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); From 4457456b010aa1a12bf5286cff353873dc1ab176 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 29 Jan 2025 00:56:57 +0100 Subject: [PATCH 0168/1190] Unix SDL: Fix compile-breaking errors. --- src/unix/unix_cdrom.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c index 186c7649b..7fe64bee6 100644 --- a/src/unix/unix_cdrom.c +++ b/src/unix/unix_cdrom.c @@ -140,8 +140,8 @@ void cdrom_mount(uint8_t id, char *fn) { strcpy(cdrom[id].prev_image_path, cdrom[id].image_path); - if (cdrom[id].ops && cdrom[id].ops->exit) - cdrom[id].ops->exit(&(cdrom[id])); + if (cdrom[id].ops && cdrom[id].ops->close) + cdrom[id].ops->close(cdrom[id].local); cdrom[id].ops = NULL; memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path)); if ((fn != NULL) && (strlen(fn) >= 1) && (fn[strlen(fn) - 1] == '\\')) @@ -187,8 +187,7 @@ mo_mount(uint8_t id, char *fn, uint8_t wp) mo_disk_close(dev); mo_drives[id].read_only = wp; - mo_load(dev, fn); - mo_insert(dev); + mo_load(dev, fn, 0); ui_sb_update_icon_state(SB_MO | id, strlen(mo_drives[id].image_path) ? 0 : 1); #if 0 @@ -245,8 +244,7 @@ zip_mount(uint8_t id, char *fn, uint8_t wp) zip_disk_close(dev); zip_drives[id].read_only = wp; - zip_load(dev, fn); - zip_insert(dev); + zip_load(dev, fn, 0); ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1); #if 0 From 2db2fef78b2ba9c3a2cec950134711ba7c5aefd1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 29 Jan 2025 01:08:36 +0100 Subject: [PATCH 0169/1190] And a missing include file. --- src/unix/unix_cdrom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c index 7fe64bee6..8655865a1 100644 --- a/src/unix/unix_cdrom.c +++ b/src/unix/unix_cdrom.c @@ -32,6 +32,7 @@ #include <86box/hdd.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> +#include <86box/cdrom_image.h> #include <86box/mo.h> #include <86box/zip.h> #include <86box/scsi_disk.h> From b57281c57e31a70605bd87691a001c6cf83337e3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 29 Jan 2025 23:48:09 +0100 Subject: [PATCH 0170/1190] CD-ROM: No longer fatal when encountering a mode 1 sector on a XA disc - apparently such discs actually exist. --- src/cdrom/cdrom.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 2c439e76a..3a6f17d7b 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2207,7 +2207,11 @@ cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, cons if (mode2) { if (raw_buffer[0x000f] == 0x01) - log_fatal(dev->log, "Mode 1 sector on CD-I/XA disc\n"); + /* + Use Mode 1, since evidently specification-violating discs + exist. + */ + mode2 = 0; else if (raw_buffer[0x0012] != raw_buffer[0x0016]) { cdrom_log(dev->log, "[%s] XA Mode 2 sector with malformed " "sub-header\n", cdrom_req_modes[cdrom_sector_type], From 76fb3365cd1623dfc28087ec504727e1d1acc191 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 30 Jan 2025 05:39:17 +0100 Subject: [PATCH 0171/1190] It's image_open(), no longer cdrom_image_open(). --- src/unix/unix_cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c index 8655865a1..5223b08ba 100644 --- a/src/unix/unix_cdrom.c +++ b/src/unix/unix_cdrom.c @@ -147,7 +147,7 @@ cdrom_mount(uint8_t id, char *fn) memset(cdrom[id].image_path, 0, sizeof(cdrom[id].image_path)); if ((fn != NULL) && (strlen(fn) >= 1) && (fn[strlen(fn) - 1] == '\\')) fn[strlen(fn) - 1] = '/'; - cdrom_image_open(&(cdrom[id]), fn); + image_open(&(cdrom[id]), fn); /* Signal media change to the emulated machine. */ if (cdrom[id].insert) cdrom[id].insert(cdrom[id].priv); From 8a1862c4b2838b4107f81f53850de3bee4d2688e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 30 Jan 2025 06:38:05 +0100 Subject: [PATCH 0172/1190] CD-ROM: Correctly return from read sector with the return code from the back-end in case of error, fixes System Shock 2 CD detection. --- src/cdrom/cdrom.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 3a6f17d7b..33e8b0cf1 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2192,13 +2192,22 @@ cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, cons if (audio) { if (!track_type_is_valid(dev, cdrom_sector_type, cdrom_sector_flags, 1, 0x00)) ret = 0; - else + else { ret = read_audio(dev, lba, temp_b); + + /* Return with error if we had one. */ + if (ret < 0) + return ret; + } } else { int form = 0; ret = read_data(dev, lba); + /* Return with error if we had one. */ + if (ret < 0) + return ret; + if ((raw_buffer[0x000f] == 0x00) || (raw_buffer[0x000f] > 0x02)) { cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", cdrom_req_modes[cdrom_sector_type], raw_buffer[0x000f]); From e11b5535e1896927abd3cdd8bf06af94ae2b786e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 30 Jan 2025 08:15:39 +0100 Subject: [PATCH 0173/1190] Fixed some CD-ROM commands not stopping audio play when they should have (fixes data playing as audio, producing nasty artifacts, in some games), and increased the media history for all drive types from 4 to 10, also refactored cdrom_read_sector() and moved the last module-wide variables into the cdrom_t struct. --- src/cdrom/cdrom.c | 458 +++++++++++++++++----------------- src/include/86box/86box.h | 2 +- src/include/86box/cartridge.h | 2 +- src/include/86box/cassette.h | 2 +- src/include/86box/cdrom.h | 22 +- src/include/86box/fdd.h | 2 +- src/include/86box/mo.h | 2 +- src/include/86box/zip.h | 2 +- src/scsi/scsi_cdrom.c | 9 + 9 files changed, 262 insertions(+), 239 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 33e8b0cf1..595d89f70 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -43,11 +43,6 @@ #define MIN_SEEK 2000 #define MAX_SEEK 333333 -static int cdrom_sector_size; -/* Needs some extra breathing space in case of overflows. */ -static uint8_t raw_buffer[4096]; -static uint8_t extra_buffer[296]; - cdrom_t cdrom[CDROM_NUM] = { 0 }; int cdrom_interface_current; @@ -69,16 +64,16 @@ cdrom_log(void *priv, const char *fmt, ...) # define cdrom_log(priv, fmt, ...) #endif -static void process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, +static void process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b); -static void process_mode2_non_xa(const cdrom_t *dev, const int cdrom_sector_flags, +static void process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b); -static void process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, +static void process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b); -static void process_mode2_xa_form2(const cdrom_t *dev, const int cdrom_sector_flags, +static void process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b); -typedef void (*cdrom_process_data_t)(const cdrom_t *dev, const int cdrom_sector_flags, +typedef void (*cdrom_process_data_t)(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b); static cdrom_process_data_t cdrom_process_data[4] = { process_mode1, process_mode2_non_xa, @@ -289,13 +284,13 @@ msf_to_bcd(int *m, int *s, int *f) } static int -read_data(const cdrom_t *dev, const uint32_t lba) +read_data(cdrom_t *dev, const uint32_t lba) { - return dev->ops->read_sector(dev->local, raw_buffer, lba); + return dev->ops->read_sector(dev->local, dev->raw_buffer, lba); } static void -cdrom_get_subchannel(const cdrom_t *dev, const uint32_t lba, +cdrom_get_subchannel(cdrom_t *dev, const uint32_t lba, subchannel_t *subc, const int cooked) { const uint8_t *scb; @@ -306,10 +301,10 @@ cdrom_get_subchannel(const cdrom_t *dev, const uint32_t lba, ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))) scb = dev->subch_buffer; else { - scb = (const uint8_t *) raw_buffer; + scb = (const uint8_t *) dev->raw_buffer; scb_offs = 2352; - memset(raw_buffer, 0, 2448); + memset(dev->raw_buffer, 0, 2448); (void) read_data(dev, lba); } @@ -645,36 +640,36 @@ track_type_is_valid(const cdrom_t *dev, const int type, const int flags, const i } static int -read_audio(const cdrom_t *dev, const uint32_t lba, uint8_t *b) +read_audio(cdrom_t *dev, const uint32_t lba, uint8_t *b) { - const int ret = dev->ops->read_sector(dev->local, raw_buffer, lba); + const int ret = dev->ops->read_sector(dev->local, dev->raw_buffer, lba); - memcpy(b, raw_buffer, 2352); + memcpy(b, dev->raw_buffer, 2352); - cdrom_sector_size = 2352; + dev->cdrom_sector_size = 2352; return ret; } static void -process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) { - cdrom_sector_size = 0; + dev->cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 1] Sync\n"); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; + memcpy(b, dev->raw_buffer, 12); + dev->cdrom_sector_size += 12; b += 12; } if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 1] Header\n"); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; + memcpy(b, dev->raw_buffer + 12, 4); + dev->cdrom_sector_size += 4; b += 4; } @@ -683,8 +678,8 @@ process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (!(cdrom_sector_flags & 0x10)) { /* No user data */ cdrom_log(dev->log, "[Mode 1] Sub-header\n"); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; + memcpy(b, dev->raw_buffer + 16, 8); + dev->cdrom_sector_size += 8; b += 8; } } @@ -693,12 +688,13 @@ process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) /* User data */ cdrom_log(dev->log, "[Mode 1] User data\n"); if (mult > 1) { - memcpy(b, raw_buffer + 16 + (part * dev->sector_size), dev->sector_size); - cdrom_sector_size += dev->sector_size; + memcpy(b, dev->raw_buffer + 16 + (part * dev->sector_size), + dev->sector_size); + dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, raw_buffer + 16, 2048); - cdrom_sector_size += 2048; + memcpy(b, dev->raw_buffer + 16, 2048); + dev->cdrom_sector_size += 2048; b += 2048; } } @@ -706,29 +702,30 @@ process_mode1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[Mode 1] EDC/ECC\n"); - memcpy(b, raw_buffer + 2064, (288 - ecc_diff)); - cdrom_sector_size += (288 - ecc_diff); + memcpy(b, dev->raw_buffer + 2064, (288 - ecc_diff)); + dev->cdrom_sector_size += (288 - ecc_diff); } } static void -process_mode2_non_xa(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) { - cdrom_sector_size = 0; + dev->cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 2 Formless] Sync\n"); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; + memcpy(b, dev->raw_buffer, 12); + dev->cdrom_sector_size += 12; b += 12; } if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 2 Formless] Header\n"); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; + memcpy(b, dev->raw_buffer + 12, 4); + dev->cdrom_sector_size += 4; b += 4; } @@ -736,45 +733,46 @@ process_mode2_non_xa(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t * if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[Mode 2 Formless] Sub-header\n"); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; + memcpy(b, dev->raw_buffer + 16, 8); + dev->cdrom_sector_size += 8; b += 8; } if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[Mode 2 Formless] User data\n"); - memcpy(b, raw_buffer + 24, (2336 - ecc_diff)); - cdrom_sector_size += (2336 - ecc_diff); + memcpy(b, dev->raw_buffer + 24, (2336 - ecc_diff)); + dev->cdrom_sector_size += (2336 - ecc_diff); } } static void -process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) { - cdrom_sector_size = 0; + dev->cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sync\n"); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; + memcpy(b, dev->raw_buffer, 12); + dev->cdrom_sector_size += 12; b += 12; } if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Header\n"); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; + memcpy(b, dev->raw_buffer + 12, 4); + dev->cdrom_sector_size += 4; b += 4; } if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sub-header\n"); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; + memcpy(b, dev->raw_buffer + 16, 8); + dev->cdrom_sector_size += 8; b += 8; } @@ -782,12 +780,13 @@ process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 1] User data\n"); if (mult > 1) { - memcpy(b, raw_buffer + 24 + (part * dev->sector_size), dev->sector_size); - cdrom_sector_size += dev->sector_size; + memcpy(b, dev->raw_buffer + 24 + (part * dev->sector_size), + dev->sector_size); + dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, raw_buffer + 24, 2048); - cdrom_sector_size += 2048; + memcpy(b, dev->raw_buffer + 24, 2048); + dev->cdrom_sector_size += 2048; b += 2048; } } @@ -795,48 +794,80 @@ process_mode2_xa_form1(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[XA Mode 2 Form 1] EDC/ECC\n"); - memcpy(b, raw_buffer + 2072, (280 - ecc_diff)); - cdrom_sector_size += (280 - ecc_diff); + memcpy(b, dev->raw_buffer + 2072, (280 - ecc_diff)); + dev->cdrom_sector_size += (280 - ecc_diff); } } static void -process_mode2_xa_form2(const cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) +process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) { - cdrom_sector_size = 0; + dev->cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sync\n"); - memcpy(b, raw_buffer, 12); - cdrom_sector_size += 12; + memcpy(b, dev->raw_buffer, 12); + dev->cdrom_sector_size += 12; b += 12; } if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Header\n"); - memcpy(b, raw_buffer + 12, 4); - cdrom_sector_size += 4; + memcpy(b, dev->raw_buffer + 12, 4); + dev->cdrom_sector_size += 4; b += 4; } if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sub-header\n"); - memcpy(b, raw_buffer + 16, 8); - cdrom_sector_size += 8; + memcpy(b, dev->raw_buffer + 16, 8); + dev->cdrom_sector_size += 8; b += 8; } if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 2] User data\n"); - memcpy(b, raw_buffer + 24, (2328 - ecc_diff)); - cdrom_sector_size += (2328 - ecc_diff); + memcpy(b, dev->raw_buffer + 24, (2328 - ecc_diff)); + dev->cdrom_sector_size += (2328 - ecc_diff); } } +static void +process_ecc_and_subch(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) +{ + if ((cdrom_sector_flags & 0x06) == 0x02) { + /* Add error flags. */ + cdrom_log(dev->log, "Error flags\n"); + memcpy(b + dev->cdrom_sector_size, dev->extra_buffer, 294); + dev->cdrom_sector_size += 294; + } else if ((cdrom_sector_flags & 0x06) == 0x04) { + /* Add error flags. */ + cdrom_log(dev->log, "Full error flags\n"); + memcpy(b + dev->cdrom_sector_size, dev->extra_buffer, 296); + dev->cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) { + cdrom_log(dev->log, "Raw subchannel data\n"); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + dev->cdrom_sector_size += 96; + } else if ((cdrom_sector_flags & 0x700) == 0x200) { + cdrom_log(dev->log, "Q subchannel data\n"); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 16); + dev->cdrom_sector_size += 16; + } else if ((cdrom_sector_flags & 0x700) == 0x400) { + cdrom_log(dev->log, "R/W subchannel data\n"); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + dev->cdrom_sector_size += 96; + } +} + static void cdrom_drive_reset(cdrom_t *dev) { @@ -855,7 +886,9 @@ cdrom_drive_reset(cdrom_t *dev) static void cdrom_unload(cdrom_t *dev) { - cdrom_log(dev->log, "CDROM: cdrom_unload(%s)\n", dev->image_path); + if (dev->log != NULL) { + cdrom_log(dev->log, "CDROM: cdrom_unload(%s)\n", dev->image_path); + } dev->cd_status = CD_STATUS_EMPTY; @@ -1624,7 +1657,7 @@ cdrom_get_current_status(const cdrom_t *dev) } void -cdrom_get_current_subchannel(const cdrom_t *dev, uint8_t *b, const int msf) +cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) { subchannel_t subc; @@ -1709,7 +1742,7 @@ cdrom_get_current_subchannel(const cdrom_t *dev, uint8_t *b, const int msf) } void -cdrom_get_current_subchannel_sony(const cdrom_t *dev, uint8_t *b, const int msf) +cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, const int msf) { subchannel_t subc; @@ -1743,7 +1776,7 @@ cdrom_get_current_subchannel_sony(const cdrom_t *dev, uint8_t *b, const int msf) } uint8_t -cdrom_get_audio_status_pioneer(const cdrom_t *dev, uint8_t *b) +cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b) { uint8_t ret; subchannel_t subc; @@ -1769,7 +1802,7 @@ cdrom_get_audio_status_pioneer(const cdrom_t *dev, uint8_t *b) } uint8_t -cdrom_get_audio_status_sony(const cdrom_t *dev, uint8_t *b, const int msf) +cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, const int msf) { uint8_t ret; subchannel_t subc; @@ -1803,7 +1836,7 @@ cdrom_get_audio_status_sony(const cdrom_t *dev, uint8_t *b, const int msf) } void -cdrom_get_current_subcodeq(const cdrom_t *dev, uint8_t *b) +cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) { subchannel_t subc; @@ -2098,16 +2131,12 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, } int -cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, +cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, int cdrom_sector_type, const int cdrom_sector_flags, int *len, const uint8_t vendor_type) { - uint8_t *temp_b; - uint32_t lba; - int audio = 0; - int mode2 = 0; int pos = sector; - int ret; + int ret = 0; if ((cdrom_sector_type & 0x0f) >= 0x08) { mult = cdrom_sector_type >> 4; @@ -2121,164 +2150,143 @@ cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, cons ecc_diff = 0; } - if (dev->cd_status == CD_STATUS_EMPTY) - return 0; + if (dev->cd_status != CD_STATUS_EMPTY) { + uint8_t *temp_b; + uint8_t *b = temp_b = buffer; + int audio = 0; + uint32_t lba; + int mode2 = 0; - uint8_t *b = temp_b = buffer; + *len = 0; - *len = 0; + if (ismsf) { + const int m = (pos >> 16) & 0xff; + const int s = (pos >> 8) & 0xff; + const int f = pos & 0xff; - if (ismsf) { - const int m = (pos >> 16) & 0xff; - const int s = (pos >> 8) & 0xff; - const int f = pos & 0xff; + lba = MSFtoLBA(m, s, f) - 150; + } else { + switch (vendor_type) { + case 0x00: + lba = pos; + break; + case 0x40: { + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); - lba = MSFtoLBA(m, s, f) - 150; - } else { - switch (vendor_type) { - case 0x00: - lba = pos; - break; - case 0x40: { - const int m = bcd2bin((pos >> 24) & 0xff); - const int s = bcd2bin((pos >> 16) & 0xff); - const int f = bcd2bin((pos >> 8) & 0xff); - - lba = MSFtoLBA(m, s, f) - 150; - break; - } case 0x80: - lba = bcd2bin((pos >> 24) & 0xff); - break; - /* Never used values but the compiler complains. */ - default: - lba = 0; - } - } - - if (dev->ops->get_track_type) - audio = dev->ops->get_track_type(dev->local, lba); - - int dm = audio & CD_TRACK_MODE_MASK; - audio &= CD_TRACK_AUDIO; - - if (dm != CD_TRACK_NORMAL) - mode2 = 1; - - memset(raw_buffer, 0, 2448); - memset(extra_buffer, 0, 296); - - if ((cdrom_sector_flags & 0xf8) == 0x08) { - /* 0x08 is an illegal mode */ - cdrom_log(dev->log, "[Mode 1] 0x08 is an illegal mode\n"); - return 0; - } - - if ((cdrom_sector_type > 5) && (cdrom_sector_type < 8)) { - cdrom_log(dev->log, "Attempting to read an unrecognized sector " - "type from an image\n"); - return 0; - } else { - if ((cdrom_sector_type > 1) && audio && (dev->cd_status & CD_STATUS_HAS_AUDIO)) { - cdrom_log(dev->log, "[%s] Attempting to read a data sector " - "from an audio track\n", cdrom_req_modes[cdrom_sector_type]); - return 0; - } else if ((cdrom_sector_type == 1) && - (!audio || !(dev->cd_status & CD_STATUS_HAS_AUDIO))) { - cdrom_log(dev->log, "[Audio] Attempting to read an audio sector " - "from a data track\n"); - return 0; + lba = MSFtoLBA(m, s, f) - 150; + break; + } case 0x80: + lba = bcd2bin((pos >> 24) & 0xff); + break; + /* Never used values but the compiler complains. */ + default: + lba = 0; + } } - if (audio) { - if (!track_type_is_valid(dev, cdrom_sector_type, cdrom_sector_flags, 1, 0x00)) - ret = 0; - else { - ret = read_audio(dev, lba, temp_b); + if (dev->ops->get_track_type) + audio = dev->ops->get_track_type(dev->local, lba); + + const int dm = audio & CD_TRACK_MODE_MASK; + audio &= CD_TRACK_AUDIO; + + if (dm != CD_TRACK_NORMAL) + mode2 = 1; + + memset(dev->raw_buffer, 0, 2448); + memset(dev->extra_buffer, 0, 296); + + if ((cdrom_sector_flags & 0xf8) == 0x08) { + /* 0x08 is an illegal mode */ + cdrom_log(dev->log, "[Mode 1] 0x08 is an illegal mode\n"); + } else if ((cdrom_sector_type > 5) && (cdrom_sector_type < 8)) { + cdrom_log(dev->log, "Attempting to read an unrecognized sector " + "type from an image\n"); + return 0; + } else { + if ((cdrom_sector_type > 1) && audio && + (dev->cd_status & CD_STATUS_HAS_AUDIO)) { + cdrom_log(dev->log, "[%s] Attempting to read a data sector " + "from an audio track\n", + cdrom_req_modes[cdrom_sector_type]); + } else if ((cdrom_sector_type == 1) && + (!audio || !(dev->cd_status & CD_STATUS_HAS_AUDIO))) { + cdrom_log(dev->log, "[Audio] Attempting to read an audio " + "sector from a data track\n"); + } else if (audio) { + if (!track_type_is_valid(dev, cdrom_sector_type, + cdrom_sector_flags, 1, 0x00)) + ret = 0; + else + ret = read_audio(dev, lba, temp_b); + } else { + ret = read_data(dev, lba); /* Return with error if we had one. */ - if (ret < 0) - return ret; - } - } else { - int form = 0; + if (ret > 0) { + int form = 0; - ret = read_data(dev, lba); + if ((dev->raw_buffer[0x000f] == 0x00) || + (dev->raw_buffer[0x000f] > 0x02)) { + cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", + cdrom_req_modes[cdrom_sector_type], + dev->raw_buffer[0x000f]); + ret = 0; + } else if (mode2) { + if (dev->raw_buffer[0x000f] == 0x01) + /* + Use Mode 1, since evidently specification-violating + discs exist. + */ + mode2 = 0; + else if (dev->raw_buffer[0x0012] != + dev->raw_buffer[0x0016]) { + cdrom_log(dev->log, "[%s] XA Mode 2 sector with " + "malformed sub-header\n", + cdrom_req_modes[cdrom_sector_type]); + ret = 0; + } else + form = ((dev->raw_buffer[0x0012] & 0x20) >> 5) + 1; + } else if (dev->raw_buffer[0x000f] == 0x02) + mode2 = 1; - /* Return with error if we had one. */ - if (ret < 0) - return ret; + if (ret > 0) { + const int mode_id = mode2 + form; - if ((raw_buffer[0x000f] == 0x00) || (raw_buffer[0x000f] > 0x02)) { - cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", - cdrom_req_modes[cdrom_sector_type], raw_buffer[0x000f]); - return 0; + cdrom_log(dev->log, "[%s] %s detected\n", + cdrom_req_modes[cdrom_sector_type], + cdrom_modes[mode_id]); + + if (!track_type_is_valid(dev, cdrom_sector_type, + cdrom_sector_flags, 0, + (mode2 << 2) + form)) { + cdrom_log(dev->log, "[%s] Invalid track type\n", + cdrom_req_modes[cdrom_sector_type]); + ret = 0; + } else if (cdrom_mode_masks[cdrom_sector_type] & + (1 << mode_id)) + cdrom_process_data[mode_id](dev, cdrom_sector_flags, + temp_b); + else { + cdrom_log(dev->log, "[%s] Attempting to read a " + "%s sector\n", + cdrom_req_modes[cdrom_sector_type], + cdrom_modes[mode_id]); + ret = 0; + } + } + } } - if (mode2) { - if (raw_buffer[0x000f] == 0x01) - /* - Use Mode 1, since evidently specification-violating discs - exist. - */ - mode2 = 0; - else if (raw_buffer[0x0012] != raw_buffer[0x0016]) { - cdrom_log(dev->log, "[%s] XA Mode 2 sector with malformed " - "sub-header\n", cdrom_req_modes[cdrom_sector_type], - raw_buffer[0x000f]); - return 0; - } else - form = ((raw_buffer[0x0012] & 0x20) >> 5) + 1; - } else if (raw_buffer[0x000f] == 0x02) - mode2 = 1; - - const int mode_id = mode2 + form; - - cdrom_log(dev->log, "[%s] %s detected\n", cdrom_req_modes[cdrom_sector_type], - cdrom_modes[mode_id]); - - if (!track_type_is_valid(dev, cdrom_sector_type, cdrom_sector_flags, 0, - (mode2 << 2) + form)) - return 0; - - /* It just so happens that only modes with even ID's have a sector user data size of 2048. */ - if (cdrom_mode_masks[cdrom_sector_type] & (1 << mode_id)) - cdrom_process_data[mode_id](dev, cdrom_sector_flags, temp_b); - else { - cdrom_log(dev->log, "[%s] Attempting to read a %s sector\n", - cdrom_req_modes[cdrom_sector_type], cdrom_modes[mode_id]); - return 0; + if (ret > 0) { + process_ecc_and_subch(dev, cdrom_sector_flags, b); + *len = dev->cdrom_sector_size; } } } - if ((cdrom_sector_flags & 0x06) == 0x02) { - /* Add error flags. */ - cdrom_log(dev->log, "Error flags\n"); - memcpy(b + cdrom_sector_size, extra_buffer, 294); - cdrom_sector_size += 294; - } else if ((cdrom_sector_flags & 0x06) == 0x04) { - /* Add error flags. */ - cdrom_log(dev->log, "Full error flags\n"); - memcpy(b + cdrom_sector_size, extra_buffer, 296); - cdrom_sector_size += 296; - } - - if ((cdrom_sector_flags & 0x700) == 0x100) { - cdrom_log(dev->log, "Raw subchannel data\n"); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } else if ((cdrom_sector_flags & 0x700) == 0x200) { - cdrom_log(dev->log, "Q subchannel data\n"); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); - cdrom_sector_size += 16; - } else if ((cdrom_sector_flags & 0x700) == 0x400) { - cdrom_log(dev->log, "R/W subchannel data\n"); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } - - *len = cdrom_sector_size; - return ret; } @@ -2495,7 +2503,7 @@ cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer) } int -cdrom_read_track_information(const cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) +cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) { uint8_t rti[65536] = { 0 }; const raw_track_info_t *t = (raw_track_info_t *) rti; @@ -2609,7 +2617,7 @@ cdrom_read_track_information(const cdrom_t *dev, const uint8_t *cdb, uint8_t *bu if (track->adr_ctl & 0x04) { ret = read_data(dev, start); - mode = raw_buffer[3]; + mode = dev->raw_buffer[3]; } } else if (track->point != 0xa2) start = 0x00000000; @@ -2763,9 +2771,7 @@ cdrom_hard_reset(void) cdrom_t *dev = &cdrom[i]; if (dev->bus_type) { - cdrom_log(dev->log, "Hard reset\n"); - - dev->id = i; + dev->id = i; dev->is_early = cdrom_is_early(dev->type); dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && @@ -2778,6 +2784,8 @@ cdrom_hard_reset(void) sprintf(n, "CD-ROM %i ", i + 1); dev->log = log_open(n); + cdrom_log(dev->log, "Hard reset\n"); + switch (dev->bus_type) { case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 96aeb645c..5dc0116fc 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -33,7 +33,7 @@ #define SCREENSHOT_PATH "screenshots" /* Recently used images */ -#define MAX_PREV_IMAGES 4 +#define MAX_PREV_IMAGES 10 #define MAX_IMAGE_PATH_LEN 2048 /* Max UUID Length */ diff --git a/src/include/86box/cartridge.h b/src/include/86box/cartridge.h index 2ea7ec734..2b0662703 100644 --- a/src/include/86box/cartridge.h +++ b/src/include/86box/cartridge.h @@ -21,7 +21,7 @@ extern "C" { #endif -#define CART_IMAGE_HISTORY 4 +#define CART_IMAGE_HISTORY 10 extern char cart_fns[2][512]; extern char *cart_image_history[2][CART_IMAGE_HISTORY]; diff --git a/src/include/86box/cassette.h b/src/include/86box/cassette.h index bb0899e24..168d82099 100644 --- a/src/include/86box/cassette.h +++ b/src/include/86box/cassette.h @@ -153,7 +153,7 @@ void pc_cas_print_state(const pc_cassette_t *cas); void pc_cas_clock(pc_cassette_t *cas, unsigned long cnt); void pc_cas_advance(pc_cassette_t *cas); -#define CASSETTE_IMAGE_HISTORY 4 +#define CASSETTE_IMAGE_HISTORY 10 extern pc_cassette_t *cassette; diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index b9dbccb4b..de20facdb 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -48,7 +48,7 @@ #define CD_TOC_SESSION 1 #define CD_TOC_RAW 2 -#define CD_IMAGE_HISTORY 4 +#define CD_IMAGE_HISTORY 10 #define BUF_SIZE 32768 @@ -333,6 +333,12 @@ typedef struct cdrom { int16_t cd_buffer[BUF_SIZE]; uint8_t subch_buffer[96]; + + int cdrom_sector_size; + + /* Needs some extra breathing space in case of overflows. */ + uint8_t raw_buffer[4096]; + uint8_t extra_buffer[296]; } cdrom_t; extern cdrom_t cdrom[CDROM_NUM]; @@ -394,11 +400,11 @@ extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const extern void cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume); extern uint8_t cdrom_get_current_status(const cdrom_t *dev); -extern void cdrom_get_current_subchannel(const cdrom_t *dev, uint8_t *b, const int msf); -extern void cdrom_get_current_subchannel_sony(const cdrom_t *dev, uint8_t *b, const int msf); -extern uint8_t cdrom_get_audio_status_pioneer(const cdrom_t *dev, uint8_t *b); -extern uint8_t cdrom_get_audio_status_sony(const cdrom_t *dev, uint8_t *b, const int msf); -extern void cdrom_get_current_subcodeq(const cdrom_t *dev, uint8_t *b); +extern void cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf); +extern void cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, const int msf); +extern uint8_t cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b); +extern uint8_t cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, const int msf); +extern void cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b); extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); extern int cdrom_read_toc(const cdrom_t *dev, uint8_t *b, const int type, const uint8_t start_track, const int msf, const int max_len); @@ -411,13 +417,13 @@ extern uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint #endif extern uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, const uint8_t track, const int type); -extern int cdrom_readsector_raw(const cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, +extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, int cdrom_sector_type, const int cdrom_sector_flags, int *len, const uint8_t vendor_type); extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_t layer, const uint8_t format, uint8_t *buffer, uint32_t *info); extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); -extern int cdrom_read_track_information(const cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); +extern int cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); extern int cdrom_ext_medium_changed(const cdrom_t *dev); extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); diff --git a/src/include/86box/fdd.h b/src/include/86box/fdd.h index 0331f4fcc..ff9315f1d 100644 --- a/src/include/86box/fdd.h +++ b/src/include/86box/fdd.h @@ -22,7 +22,7 @@ #define EMU_FDD_H #define FDD_NUM 4 -#define FLOPPY_IMAGE_HISTORY 4 +#define FLOPPY_IMAGE_HISTORY 10 #define SEEK_RECALIBRATE -999 #ifdef __cplusplus diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 0b494952c..1df16c3fe 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -27,7 +27,7 @@ #define MO_TIME 10.0 -#define MO_IMAGE_HISTORY 4 +#define MO_IMAGE_HISTORY 10 typedef struct mo_type_t { uint32_t sectors; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index 59b78b64e..06c6e8485 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -29,7 +29,7 @@ #define ZIP_250_SECTORS (489532) -#define ZIP_IMAGE_HISTORY 4 +#define ZIP_IMAGE_HISTORY 10 enum { ZIP_BUS_DISABLED = 0, diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 65604758d..33858ebbc 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1108,6 +1108,9 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) int type = dev->sector_type; int flags = dev->sector_flags; + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD_MSF: @@ -1508,6 +1511,9 @@ scsi_cdrom_stop(const scsi_common_t *sc) static void scsi_cdrom_set_speed(scsi_cdrom_t *dev, const uint8_t *cdb) { + /* Stop the audio playing. */ + cdrom_stop(dev->drv); + dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; if (dev->drv->cur_speed < 1) dev->drv->cur_speed = 1; @@ -3345,6 +3351,9 @@ atapi_out: dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); + /* Stop the audio playing. */ + cdrom_stop(dev->drv); + if (dev->use_cdb_9 && (cdb[0] == GPCMD_SEEK_10)) cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); else From 9dbdc14af5e72df99360f5648dfc925bd8d30d0a Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Fri, 31 Jan 2025 01:09:43 +0700 Subject: [PATCH 0174/1190] Make the HDD models' speed accurate Also make some, but few, of HDD model names more accurate. --- src/disk/hdd.c | 194 ++++++++++++++++++++++++------------------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 25257e878..8292dc472 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -415,35 +415,35 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, { .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, { .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[PIO IDE] IBM WDA-L42", .internal_name = "WDAL42", .model = "IBM-WDA-L42", .zones = 1, .avg_spt = 85, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 2.5, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 1 }, + { .name = "[PIO IDE] IBM WDA-L42", .internal_name = "WDAL42", .model = "WDA-L42", .zones = 1, .avg_spt = 85, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 2.5, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 1 }, { .name = "[ATA-1] Conner CP3024", .internal_name = "CP3024", .model = "Conner Peripherals 20MB - CP3024", .zones = 1, .avg_spt = 33, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work { .name = "[ATA-1] Conner CP3044", .internal_name = "CP3044", .model = "Conner Peripherals 40MB - CP3044", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work { .name = "[ATA-1] Conner CP3104", .internal_name = "CP3104", .model = "Conner Peripherals 104MB - CP3104", .zones = 1, .avg_spt = 33, .heads = 8, .rpm = 3500, .full_stroke_ms = 45, .track_seek_ms = 8, .rcache_num_seg = 4, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work - { .name = "[ATA-1] Conner CFS420A", .internal_name = "CFS420A", .model = "Conner Peripherals 420MB - CFS420A", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] HP Kittyhawk", .internal_name = "C3014A", .model = "HP C3014A", .zones = 6, .avg_spt = 180, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[ATA-1] IBM H3256-A3", .internal_name = "H3256A3", .model = "IBM-H3256-A3", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, - { .name = "[ATA-1] IBM H3342-A4", .internal_name = "H3342A4", .model = "IBM-H3342-A4", .zones = 1, .avg_spt = 140, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, - { .name = "[ATA-1] Kalok KL343", .internal_name = "KL343", .model = "KALOK KL-343", .zones = 1, .avg_spt = 280, .heads = 6, .rpm = 3600, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, - { .name = "[ATA-1] Kalok KL3100", .internal_name = "KL3100", .model = "KALOK KL-3100", .zones = 1, .avg_spt = 200, .heads = 6, .rpm = 3662, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7060AT", .internal_name = "7060AT", .model = "Maxtor 7060AT", .zones = 1, .avg_spt = 162, .heads = 2, .rpm = 3524, .full_stroke_ms = 30, .track_seek_ms = 3.6, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7131AT", .internal_name = "7131AT", .model = "Maxtor 7131AT", .zones = 2, .avg_spt = 154, .heads = 2, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7213AT", .internal_name = "7213AT", .model = "Maxtor 7213AT", .zones = 4, .avg_spt = 155, .heads = 4, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7245AT", .internal_name = "7245AT", .model = "Maxtor 7245AT", .zones = 4, .avg_spt = 149, .heads = 4, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Quantum ProDrive LPS 105", .internal_name = "LPS105AT", .model = "QUANTUM PRODRIVE 105", .zones = 1, .avg_spt = 170, .heads = 2, .rpm = 3662, .full_stroke_ms = 45, .track_seek_ms = 5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Quantum ProDrive LPS 120AT", .internal_name = "GM12A012", .model = "QUANTUM PRODRIVE 120AT", .zones = 1, .avg_spt = 150, .heads = 2, .rpm = 3605, .full_stroke_ms = 45, .track_seek_ms = 4, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Seagate ST3243A", .internal_name = "ST3243A", .model = "ST3243A", .zones = 1, .avg_spt = 140, .heads = 4, .rpm = 3811, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "AC140", .model = "WDC AC140", .zones = 4, .avg_spt = 170, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "AC280", .model = "WDC AC280", .zones = 4, .avg_spt = 170, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "AC1210", .model = "WDC AC1210F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "AC2120", .model = "WDC AC2120M", .zones = 4, .avg_spt = 140, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-2] IBM DBOA-2720", .internal_name = "DBOA2720", .model = "IBM-DBOA-2720", .zones = 2, .avg_spt = 135, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-32880)", .internal_name = "DCAA32880", .model = "IBM-DCAA-32880", .zones = 8, .avg_spt = 85, .heads = 2, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-33610)", .internal_name = "DCAA33610", .model = "IBM-DCAA-33610", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-34330)", .internal_name = "DCAA34330", .model = "IBM-DCAA-34330", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] Maxtor 7540AV", .internal_name = "7540AV", .model = "Maxtor 7540AV", .zones = 2, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 4.3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 7546AT", .internal_name = "7546AT", .model = "Maxtor 7546AT", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 4500, .full_stroke_ms = 28, .track_seek_ms = 2.3, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 7850AV", .internal_name = "7850AV", .model = "Maxtor 7850AV", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 3.7, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 71336AP", .internal_name = "71336AP", .model = "Maxtor 71336AP", .zones = 4, .avg_spt = 105, .heads = 4, .rpm = 4480, .full_stroke_ms = 12, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-1] Conner CFS420A", .internal_name = "CFS420A", .model = "Conner Peripherals 420MB - CFS420A", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] HP Kittyhawk", .internal_name = "C3014A", .model = "HP C3014A", .zones = 6, .avg_spt = 80, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[ATA-1] IBM H3256-A3", .internal_name = "H3256A3", .model = "H3256-A3", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, + { .name = "[ATA-1] IBM H3342-A4", .internal_name = "H3342A4", .model = "H3342-A4", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, + { .name = "[ATA-1] Kalok KL343", .internal_name = "KL343", .model = "KALOK KL-343", .zones = 1, .avg_spt = 80, .heads = 6, .rpm = 3600, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, + { .name = "[ATA-1] Kalok KL3100", .internal_name = "KL3100", .model = "KALOK KL-3100", .zones = 1, .avg_spt = 100, .heads = 6, .rpm = 3662, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7060AT", .internal_name = "7060AT", .model = "Maxtor 7060 AT", .zones = 1, .avg_spt = 62, .heads = 2, .rpm = 3524, .full_stroke_ms = 30, .track_seek_ms = 3.6, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7131AT", .internal_name = "7131AT", .model = "Maxtor 7131 AT", .zones = 2, .avg_spt = 54, .heads = 2, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7213AT", .internal_name = "7213AT", .model = "Maxtor 7213 AT", .zones = 4, .avg_spt = 55, .heads = 4, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7245AT", .internal_name = "7245AT", .model = "Maxtor 7245 AT", .zones = 4, .avg_spt = 49, .heads = 4, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Quantum ProDrive LPS 105", .internal_name = "LPS105AT", .model = "QUANTUM PRODRIVE 105", .zones = 1, .avg_spt = 70, .heads = 2, .rpm = 3662, .full_stroke_ms = 45, .track_seek_ms = 5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Quantum ProDrive LPS 120AT", .internal_name = "GM12A012", .model = "QUANTUM PRODRIVE 120AT", .zones = 1, .avg_spt = 50, .heads = 2, .rpm = 3605, .full_stroke_ms = 45, .track_seek_ms = 4, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Seagate ST3243A", .internal_name = "ST3243A", .model = "ST3243A", .zones = 1, .avg_spt = 40, .heads = 4, .rpm = 3811, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "AC140", .model = "WDC AC140", .zones = 4, .avg_spt = 70, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "AC280", .model = "WDC AC280", .zones = 4, .avg_spt = 70, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "AC1210", .model = "WDC AC1210F", .zones = 4, .avg_spt = 30, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "AC2120", .model = "WDC AC2120M", .zones = 4, .avg_spt = 40, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-2] IBM DBOA-2720", .internal_name = "DBOA2720", .model = "DBOA-2720", .zones = 2, .avg_spt = 135, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-32880)", .internal_name = "DCAA32880", .model = "IBM-DCAA-32880", .zones = 8, .avg_spt = 185, .heads = 2, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-33610)", .internal_name = "DCAA33610", .model = "IBM-DCAA-33610", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-34330)", .internal_name = "DCAA34330", .model = "IBM-DCAA-34330", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] Maxtor 7540AV", .internal_name = "7540AV", .model = "Maxtor 7540 AV", .zones = 2, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 4.3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 7546AT", .internal_name = "7546AT", .model = "Maxtor 7546 AT", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 4500, .full_stroke_ms = 28, .track_seek_ms = 2.3, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 7850AV", .internal_name = "7850AV", .model = "Maxtor 7850 AV", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 3.7, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 71336AP", .internal_name = "71336AP", .model = "Maxtor 71336 AP", .zones = 4, .avg_spt = 105, .heads = 4, .rpm = 4480, .full_stroke_ms = 12, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Quantum Bigfoot 1.2AT", .internal_name = "BF12A011", .model = "QUANTUM BIGFOOT BF1.2A", .zones = 2, .avg_spt = 155, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Quantum Bigfoot (CY4320A)", .internal_name = "CY4320A", .model = "QUANTUM BIGFOOT_CY4320A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4000, .full_stroke_ms = 29, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // from Hardcore Windows NT Final Segment by Kugee { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, @@ -458,89 +458,89 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Seagate Medalist 545xe", .internal_name = "ST3660A", .model = "ST3660A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, { .name = "[ATA-2] Seagate Medalist 640xe", .internal_name = "ST3630A", .model = "ST3630A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.5, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, { .name = "[ATA-2] Seagate Medalist 850xe", .internal_name = "ST3850A", .model = "ST3850A", .zones = 8, .avg_spt = 150, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.8, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 1270SL", .internal_name = "ST51270A", .model = "ST51270A", .zones = 8, .avg_spt = 105, .heads = 3, .rpm = 5736, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Seagate Medalist 3240", .internal_name = "ST33240A", .model = "ST33240A", .zones = 16, .avg_spt = 125, .heads = 8, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist 1270SL", .internal_name = "ST51270A", .model = "ST51270A", .zones = 8, .avg_spt = 205, .heads = 3, .rpm = 5736, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist 3240", .internal_name = "ST33240A", .model = "ST33240A", .zones = 16, .avg_spt = 225, .heads = 8, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Toshiba MK2101MAN (HDD2616)", .internal_name = "HDD2616", .model = "TOSHIBA MK2101MAN", .zones = 8, .avg_spt = 130, .heads = 10, .rpm = 4200, .full_stroke_ms = 36, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "AC2540", .model = "WDC AC2540H", .zones = 4, .avg_spt = 250, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "AC2850", .model = "WDC AC2850F", .zones = 4, .avg_spt = 230, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "AC2540", .model = "WDC AC2540H", .zones = 4, .avg_spt = 150, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "AC2850", .model = "WDC AC2850F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 11000", .internal_name = "AC11000", .model = "WDC AC11000H", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 21200", .internal_name = "AC21200", .model = "WDC AC21200H", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 5200, .full_stroke_ms = 39, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 21600", .internal_name = "AC21600", .model = "WDC AC21600H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 210, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, { .name = "[ATA-3] Connor CFS1275A", .internal_name = "CFS1275A", .model = "Connor Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 - { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3043AT", .internal_name = "MPA3043AT", .model = "FUJITSU MPA3043AT", .zones = 15, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3052AT", .internal_name = "MPA3052AT", .model = "FUJITSU MPA3052AT", .zones = 16, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Samsung Voyager 6", .internal_name = "SV0844A", .model = "SAMSUNG SV0844A", .zones = 8, .avg_spt = 105, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-3] Samsung Winner 5X", .internal_name = "WU33205A", .model = "SAMSUNG WU33205A", .zones = 16, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3043AT", .internal_name = "MPA3043AT", .model = "FUJITSU MPA3043AT", .zones = 15, .avg_spt = 195, .heads = 5, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3052AT", .internal_name = "MPA3052AT", .model = "FUJITSU MPA3052AT", .zones = 16, .avg_spt = 195, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Samsung Voyager 6", .internal_name = "SV0844A", .model = "SAMSUNG SV0844A", .zones = 8, .avg_spt = 205, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-3] Samsung Winner 5X", .internal_name = "WU33205A", .model = "SAMSUNG WU33205A", .zones = 16, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Seagate Medalist 636", .internal_name = "ST3636A", .model = "Seagate Technology 636MB - ST3636A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, { .name = "[ATA-3] Seagate Medalist 1082", .internal_name = "ST31082A", .model = "Seagate Technology 1082MB - ST31082A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, { .name = "[ATA-3] Seagate Medalist 1276", .internal_name = "ST31276A", .model = "Seagate Technology 1275MB - ST31276A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, { .name = "[ATA-3] Seagate Medalist 1720", .internal_name = "ST31720A", .model = "ST31720A", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Seagate Medalist 2132", .internal_name = "ST32132A", .model = "ST32132A", .zones = 8, .avg_spt = 125, .heads = 6, .rpm = 4500, .full_stroke_ms = 30, .track_seek_ms = 2.3, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 16 }, - { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "AC21700", .model = "WDC AC21700H", .zones = 8, .avg_spt = 85, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version - { .name = "[ATA-4] Fujitsu MPB3021AT", .internal_name = "MPB3021AT", .model = "FUJITSU MPB3021AT", .zones = 7, .avg_spt = 100, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3043AT", .internal_name = "MPD3043AT", .model = "FUJITSU MPD3043AT", .zones = 5, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 29, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3064AT", .internal_name = "MPD3064AT", .model = "FUJITSU MPD3064AT", .zones = 7, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3084AT", .internal_name = "MPD3084AT", .model = "FUJITSU MPD3084AT", .zones = 7, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPE3064AT", .internal_name = "MPE3064AT", .model = "FUJITSU MPE3064AT", .zones = 7, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 2160", .internal_name = "86480D6", .model = "Maxtor 86480D6", .zones = 8, .avg_spt = 97, .heads = 4, .rpm = 5200, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 2880", .internal_name = "90432D3", .model = "Maxtor 90432D3", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 3400", .internal_name = "90644D3", .model = "Maxtor 90644D3", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 4320 (90432D2)", .internal_name = "90432D2", .model = "Maxtor 90432D2", .zones = 16, .avg_spt = 90, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 4320 (90845D4)", .internal_name = "90845D4", .model = "Maxtor 90845D4", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (90683U2)", .internal_name = "90683U2", .model = "Maxtor 90683U2", .zones = 16, .avg_spt = 90, .heads = 2, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91024U3)", .internal_name = "91024U3", .model = "Maxtor 91024U3", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91366U4)", .internal_name = "91366U4", .model = "Maxtor 91366U4", .zones = 16, .avg_spt = 90, .heads = 4, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92049U6)", .internal_name = "92049U6", .model = "Maxtor 92049U6", .zones = 16, .avg_spt = 90, .heads = 6, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 90, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE4.3A", .internal_name = "SE43A011", .model = "QUANTUM FIREBALL SE4.3A", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 115, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 6531", .internal_name = "ST36531A", .model = "ST36531A", .zones = 16, .avg_spt = 115, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 90, .heads = 4, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Seagate Medalist 13030", .internal_name = "ST313030A", .model = "ST313030A", .zones = 16, .avg_spt = 90, .heads = 6, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Seagate Medalist 17240", .internal_name = "ST317240A", .model = "ST317240A", .zones = 16, .avg_spt = 90, .heads = 8, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Toshiba MK4006MAV", .internal_name = "MK4006MAV", .model = "TOSHIBA MK4006MAV", .zones = 8, .avg_spt = 130, .heads = 6, .rpm = 4200, .full_stroke_ms = 25, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300RT", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200LB", .zones = 16, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400RN", .zones = 16, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200LA", .zones = 16, .avg_spt = 110, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 92, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 92, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 92, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM - { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 90, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91021U2)", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91531U3)", .internal_name = "91531U3", .model = "Maxtor 91531U3", .zones = 16, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (92041U4)", .internal_name = "92041U4", .model = "Maxtor 92041U4", .zones = 16, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 110, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 95, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 95, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 95, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 95, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV2046D", .zones = 8, .avg_spt = 95, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 89, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 89, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 89, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 17.2gb", .internal_name = "ST317221A", .model = "ST317221A", .zones = 16, .avg_spt = 89, .heads = 3, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Western Digital Caviar 102AA", .internal_name = "WD102AA", .model = "WDC WD102AA-00ANA0", .zones = 16, .avg_spt = 95, .heads = 8, .rpm = 5400, .full_stroke_ms = 12, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "AC21700", .model = "WDC AC21700H", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version + { .name = "[ATA-4] Fujitsu MPB3021AT", .internal_name = "MPB3021AT", .model = "FUJITSU MPB3021AT", .zones = 7, .avg_spt = 200, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3043AT", .internal_name = "MPD3043AT", .model = "FUJITSU MPD3043AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 29, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3064AT", .internal_name = "MPD3064AT", .model = "FUJITSU MPD3064AT", .zones = 7, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3084AT", .internal_name = "MPD3084AT", .model = "FUJITSU MPD3084AT", .zones = 7, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPE3064AT", .internal_name = "MPE3064AT", .model = "FUJITSU MPE3064AT", .zones = 7, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 2160", .internal_name = "86480D6", .model = "Maxtor 86480D6", .zones = 8, .avg_spt = 197, .heads = 4, .rpm = 5200, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 2880", .internal_name = "90432D3", .model = "Maxtor 90432D3", .zones = 16, .avg_spt = 190, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 3400", .internal_name = "90644D3", .model = "Maxtor 90644D3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 4320 (90432D2)", .internal_name = "90432D2", .model = "Maxtor 90432D2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 4320 (90845D4)", .internal_name = "90845D4", .model = "Maxtor 90845D4", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (90683U2)", .internal_name = "90683U2", .model = "Maxtor 90683U2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91024U3)", .internal_name = "91024U3", .model = "Maxtor 91024U3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91366U4)", .internal_name = "91366U4", .model = "Maxtor 91366U4", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92049U6)", .internal_name = "92049U6", .model = "Maxtor 92049U6", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 220, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE4.3A", .internal_name = "SE43A011", .model = "QUANTUM FIREBALL SE4.3A", .zones = 2, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 200, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 200, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 215, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 6531", .internal_name = "ST36531A", .model = "ST36531A", .zones = 16, .avg_spt = 215, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 13030", .internal_name = "ST313030A", .model = "ST313030A", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 17240", .internal_name = "ST317240A", .model = "ST317240A", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Toshiba MK4006MAV", .internal_name = "MK4006MAV", .model = "TOSHIBA MK4006MAV", .zones = 8, .avg_spt = 230, .heads = 6, .rpm = 4200, .full_stroke_ms = 25, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300RT", .zones = 16, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200LB", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400RN", .zones = 16, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200LA", .zones = 16, .avg_spt = 310, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 292, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 292, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 292, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM + { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91021U2)", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91531U3)", .internal_name = "91531U3", .model = "Maxtor 91531U3", .zones = 16, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (92041U4)", .internal_name = "92041U4", .model = "Maxtor 92041U4", .zones = 16, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 210, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 210, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 210, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 210, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 310, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 310, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 310, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 310, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV2046D", .zones = 8, .avg_spt = 295, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 289, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 289, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 289, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 17.2gb", .internal_name = "ST317221A", .model = "ST317221A", .zones = 16, .avg_spt = 289, .heads = 3, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Western Digital Caviar 102AA", .internal_name = "WD102AA", .model = "WDC WD102AA-00ANA0", .zones = 16, .avg_spt = 295, .heads = 8, .rpm = 5400, .full_stroke_ms = 12, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, { .name = "[ATA-5] Western Digital Expert", .internal_name = "WD135BA", .model = "WDC WD135BA-60AK", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 1920, .max_multiple = 32 }, // clang-format on }; From 6725d93b37d42cc317eee10060d196cba95b681d Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 26 Jan 2025 03:01:19 -0500 Subject: [PATCH 0175/1190] Fixes to tmacm --- src/game/gameport.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 8d2a684fc..ae2135a39 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -48,6 +48,11 @@ typedef struct _gameport_ { struct _gameport_ *next; } gameport_t; +typedef struct _tmacm_ { + struct gameport_t *port1; + struct gameport_t *port2; +} tmacm_t; + typedef struct _joystick_instance_ { uint8_t state; g_axis_t axis[4]; @@ -402,25 +407,24 @@ gameport_init(const device_t *info) static void * tmacm_init(UNUSED(const device_t *info)) { - uint16_t port = 0x0000; - gameport_t *dev = NULL; + uint16_t port = 0x0000; + tmacm_t *dev = NULL; - dev = malloc(sizeof(gameport_t)); - memset(dev, 0x00, sizeof(gameport_t)); + dev = calloc(1, sizeof(tmacm_t)); port = (uint16_t) device_get_config_hex16("port1_addr"); switch (port) { case 0x201: - dev = gameport_add(&gameport_201_device); + dev->port1 = gameport_add(&gameport_201_device); break; case 0x203: - dev = gameport_add(&gameport_203_device); + dev->port1 = gameport_add(&gameport_203_device); break; case 0x205: - dev = gameport_add(&gameport_205_device); + dev->port1 = gameport_add(&gameport_205_device); break; case 0x207: - dev = gameport_add(&gameport_207_device); + dev->port1 = gameport_add(&gameport_207_device); break; default: break; @@ -429,16 +433,16 @@ tmacm_init(UNUSED(const device_t *info)) port = (uint16_t) device_get_config_hex16("port2_addr"); switch (port) { case 0x209: - dev = gameport_add(&gameport_209_device); + dev->port2 = gameport_add(&gameport_209_device); break; case 0x20b: - dev = gameport_add(&gameport_20b_device); + dev->port2 = gameport_add(&gameport_20b_device); break; case 0x20d: - dev = gameport_add(&gameport_20d_device); + dev->port2 = gameport_add(&gameport_20d_device); break; case 0x20f: - dev = gameport_add(&gameport_20f_device); + dev->port2 = gameport_add(&gameport_20f_device); break; default: break; From 26fb3bf69479c8bb8fdd04c51ab4633d31b2a711 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 26 Jan 2025 03:01:44 -0500 Subject: [PATCH 0176/1190] Actually close cartridge on error --- src/device/cartridge.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/device/cartridge.c b/src/device/cartridge.c index 52f36a4ca..22b36484a 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -104,6 +104,7 @@ cart_image_load(int drive, char *fn) if (size < 0x1200) { cartridge_log("cart_image_load(): File size %i is too small\n", size); cart_load_error(drive, fn); + fclose(fp); return; } if (size & 0x00000fff) { From e96c6579ba12b5c492d187ffffa5b32d4d8c3508 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 30 Nov 2024 15:26:06 -0500 Subject: [PATCH 0177/1190] Gameport backend work --- src/86box.c | 4 ++- src/game/gameport.c | 70 ++++++++++++++++++++++++++++++++++-- src/include/86box/86box.h | 5 +-- src/include/86box/gameport.h | 25 +++++++++++-- 4 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/86box.c b/src/86box.c index 97c211bee..e2cc55e75 100644 --- a/src/86box.c +++ b/src/86box.c @@ -11,6 +11,7 @@ * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, + * Jasmine Iwanek, * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. @@ -18,7 +19,7 @@ * Copyright 2021 Laci bá' * Copyright 2021 dob205 * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #include #include @@ -178,6 +179,7 @@ int bugger_enabled = 0; /* (C) enable int novell_keycard_enabled = 0; /* (C) enable Novell NetWare 2.x key card emulation. */ int postcard_enabled = 0; /* (C) enable POST card */ int unittester_enabled = 0; /* (C) enable unit tester device */ +int gameport_type[GAMEPORT_MAX] = { 0, 0 }; /* (C) enable gameports */ int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */ int isartc_type = 0; /* (C) enable ISA RTC card */ int gfxcard[GFXCARD_MAX] = { 0, 0 }; /* (C) graphics/video card */ diff --git a/src/game/gameport.c b/src/game/gameport.c index ae2135a39..079f8edb4 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -8,8 +8,6 @@ * * Implementation of a generic Game Port. * - * - * * Authors: Miran Grca, * Sarah Walker, * RichardG, @@ -18,7 +16,7 @@ * Copyright 2016-2022 Miran Grca. * Copyright 2008-2018 Sarah Walker. * Copyright 2021 RichardG. - * Copyright 2021-2024 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #include #include @@ -35,6 +33,12 @@ #include <86box/gameport.h> #include <86box/plat_unused.h> +device_t game_ports[GAMEPORT_MAX]; + +typedef struct { + const device_t *device; +} GAMEPORT; + typedef struct g_axis_t { pc_timer_t timer; int axis_nr; @@ -733,3 +737,63 @@ const device_t gameport_sio_1io_device = { .force_redraw = NULL, .config = NULL }; + +static const GAMEPORT gameports[] = { + { &device_none }, + { &device_internal }, + { &gameport_device }, + { &gameport_208_device }, + { &gameport_pnp_device }, + { &gameport_tm_acm_device }, + { NULL } + // clang-format on +}; + +/* UI */ +int +gameport_available(int port) +{ + if (gameports[port].device) + return (device_available(gameports[port].device)); + + return 1; +} + +/* UI */ +const device_t * +gameports_getdevice(int port) +{ + return (gameports[port].device); +} + +/* UI */ +int +gameport_has_config(int port) +{ + if (!gameports[port].device) + return 0; + + return (device_has_config(gameports[port].device) ? 1 : 0); +} + +/* UI */ +const char * +gameport_get_internal_name(int port) +{ + return device_get_internal_name(gameports[port].device); +} + +/* UI */ +int +gameport_get_from_internal_name(const char *str) +{ + int c = 0; + + while (gameports[c].device != NULL) { + if (!strcmp(gameports[c].device->internal_name, str)) + return c; + c++; + } + + return 0; +} diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 5dc0116fc..6f6caf743 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -8,14 +8,14 @@ * * Main include file for the application. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, + * Jasmine Iwanek, * * Copyright 2016-2020 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. * Copyright 2021 Laci bá' + * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef EMU_86BOX_H #define EMU_86BOX_H @@ -131,6 +131,7 @@ extern int bugger_enabled; /* (C) enable ISAbugger */ extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */ extern int postcard_enabled; /* (C) enable POST card */ extern int unittester_enabled; /* (C) enable unit tester device */ +extern int gameport_type[]; /* (C) enable gameports */ extern int isamem_type[]; /* (C) enable ISA mem cards */ extern int isartc_type; /* (C) enable ISA RTC card */ extern int sound_is_float; /* (C) sound uses FP values */ diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 3d3a253e8..6dda4b400 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -8,8 +8,6 @@ * * Definitions for the generic game port handlers. * - * - * * Authors: Miran Grca, * Sarah Walker, * RichardG, @@ -18,11 +16,13 @@ * Copyright 2016-2022 Miran Grca. * Copyright 2008-2018 Sarah Walker. * Copyright 2021 RichardG. - * Copyright 2021-2024 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef EMU_GAMEPORT_H #define EMU_GAMEPORT_H +#define GAMEPORT_MAX 2 + #define MAX_PLAT_JOYSTICKS 8 #define MAX_JOYSTICKS 4 @@ -110,10 +110,20 @@ typedef struct joystick_if_t { const char *pov_names[MAX_JOY_POVS]; } joystick_if_t; +extern device_t game_ports[GAMEPORT_MAX]; + #ifdef __cplusplus extern "C" { #endif +extern int gameport_available(int port); +#ifdef EMU_DEVICE_H +extern const device_t *gameport_getdevice(int port); +#endif +extern int gameport_has_config(int port); +extern const char *gameport_get_internal_name(int port); +extern int gameport_get_from_internal_name(const char *str); + #ifdef EMU_DEVICE_H extern const device_t gameport_device; extern const device_t gameport_201_device; @@ -173,6 +183,15 @@ extern const joystick_if_t joystick_ch_flightstick_pro; extern const joystick_if_t joystick_sw_pad; extern const joystick_if_t joystick_tm_fcs; + +extern int gameport_available(int); +extern int gameport_has_config(int); +extern const char *gameport_get_internal_name(int); +extern int gampeport_get_from_internal_name(char *); +#ifdef EMU_DEVICE_H +extern const device_t *gameport_getdevice(int); +#endif + #ifdef __cplusplus } #endif From 3b29b769c36ba9afd7476a7173b768da9e8a3383 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 30 Nov 2024 18:48:22 -0500 Subject: [PATCH 0178/1190] Config --- src/config.c | 55 +++++++++++++++++++++++++++++++++++--- src/include/86box/config.h | 5 ++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/config.c b/src/config.c index 83b010eb2..22f94a9b3 100644 --- a/src/config.c +++ b/src/config.c @@ -8,20 +8,19 @@ * * Configuration file handler. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * Overdoze, * David Hrdlička, + * Jasmine Iwanek, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2018-2019 David Hrdlička. * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. * * NOTE: Forcing config files to be in Unicode encoding breaks * it on Windows XP, and possibly also Vista. Use the @@ -760,6 +759,28 @@ load_ports(void) p = ini_section_get_string(cat, temp, "none"); lpt_ports[c].device = lpt_device_get_from_internal_name(p); } + +#if 0 +// TODO: Load + for (c = 0; c < GAMEPORT_MAX; c++) { + sprintf(temp, "gameport%d_enabled", c + 1); + game_ports[c].enabled = !!ini_section_get_int(cat, temp, (c == 0) ? 1 : 0); + + sprintf(temp, "gameport%d_device", c + 1); + p = ini_section_get_string(cat, temp, "none"); + game_ports[c].device = gameport_get_from_internal_name(p); + } + + for (uint8_t c = 0; c < GAMEPORT_MAX; c++) { + sprintf(temp, "gameport%d_type", c); + + p = ini_section_get_string(cat, temp, "none"); + gameport_type[c] = gameport_get_from_internal_name(p); + + if (!strcmp(p, "none")) + ini_section_delete_var(cat, temp); + } +#endif } /* Load "Storage Controllers" section. */ @@ -2377,6 +2398,34 @@ save_ports(void) lpt_device_get_internal_name(lpt_ports[c].device)); } +#if 0 +// TODO: Save + for (c = 0; c < GAMEPORT_MAX; c++) { + sprintf(temp, "gameport%d_enabled", c + 1); + d = (c == 0) ? 1 : 0; + if (game_ports[c].enabled == d) + ini_section_delete_var(cat, temp); + else + ini_section_set_int(cat, temp, game_ports[c].enabled); + + sprintf(temp, "gameport%d_device", c + 1); + if (game_ports[c].device == 0) + ini_section_delete_var(cat, temp); + else + ini_section_set_string(cat, temp, + gameport_get_internal_name(game_ports[c].device)); + } + + for (uint8_t c = 0; c < GAMEPORT_MAX; c++) { + sprintf(temp, "gameport%d_enabled", c); + if (gameport_type[c] == 0) + ini_section_delete_var(cat, temp); + else + ini_section_set_string(cat, temp, + gameport_get_internal_name(gameport_type[c])); + } +#endif + ini_delete_section_if_empty(config, cat); } diff --git a/src/include/86box/config.h b/src/include/86box/config.h index a043fb22a..693f38ab7 100644 --- a/src/include/86box/config.h +++ b/src/include/86box/config.h @@ -8,16 +8,16 @@ * * Configuration file handler header. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * Overdoze, + * Jasmine Iwanek, * * Copyright 2008-2017 Sarah Walker. * Copyright 2016-2017 Miran Grca. * Copyright 2017 Fred N. van Kempen. + * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef EMU_CONFIG_H #define EMU_CONFIG_H @@ -111,6 +111,7 @@ typedef struct config_t { # ifdef USE_SERIAL_DEVICES char serial_devices[SERIAL_MAX][32]; /* Serial device names */ # endif + char gameport_devices[GAMEPORT_MAX][32]; /* gameport device names */ /* Other peripherals category */ int fdc_current[FDC_MAX]; /* Floppy disk controller type */ From ac891a05a5863d331b2bcac0a1ee090e9e3a8811 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 10 Jan 2025 18:42:09 -0500 Subject: [PATCH 0179/1190] Initial code for joystick port instancing --- src/config.c | 26 ++++----- src/game/gameport.c | 54 ++++++++--------- src/game/joystick_ch_flightstick_pro.c | 28 ++++----- src/game/joystick_standard.c | 80 +++++++++++++------------- src/game/joystick_sw_pad.c | 18 +++--- src/game/joystick_tm_fcs.c | 26 ++++----- src/include/86box/gameport.h | 4 +- src/qt/qt_joystickconfiguration.cpp | 8 +-- src/qt/qt_settingsinput.cpp | 16 +++--- src/qt/sdl_joystick.c | 46 +++++++-------- src/qt/win_joystick_rawinput.c | 38 ++++++------ src/unix/unix.c | 2 +- 12 files changed, 172 insertions(+), 174 deletions(-) diff --git a/src/config.c b/src/config.c index 22f94a9b3..c52ec48ad 100644 --- a/src/config.c +++ b/src/config.c @@ -524,23 +524,23 @@ load_input_devices(void) for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { sprintf(temp, "joystick_%i_nr", js); - joystick_state[js].plat_joystick_nr = ini_section_get_int(cat, temp, 0); + joystick_state[0][js].plat_joystick_nr = ini_section_get_int(cat, temp, 0); - if (joystick_state[js].plat_joystick_nr) { + if (joystick_state[0][js].plat_joystick_nr) { for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) { sprintf(temp, "joystick_%i_axis_%i", js, axis_nr); - joystick_state[js].axis_mapping[axis_nr] = ini_section_get_int(cat, temp, axis_nr); + joystick_state[0][js].axis_mapping[axis_nr] = ini_section_get_int(cat, temp, axis_nr); } for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) { sprintf(temp, "joystick_%i_button_%i", js, button_nr); - joystick_state[js].button_mapping[button_nr] = ini_section_get_int(cat, temp, button_nr); + joystick_state[0][js].button_mapping[button_nr] = ini_section_get_int(cat, temp, button_nr); } for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { sprintf(temp, "joystick_%i_pov_%i", js, pov_nr); p = ini_section_get_string(cat, temp, "0, 0"); - joystick_state[js].pov_mapping[pov_nr][0] = joystick_state[js].pov_mapping[pov_nr][1] = 0; - sscanf(p, "%i, %i", &joystick_state[js].pov_mapping[pov_nr][0], - &joystick_state[js].pov_mapping[pov_nr][1]); + joystick_state[0][js].pov_mapping[pov_nr][0] = joystick_state[0][js].pov_mapping[pov_nr][1] = 0; + sscanf(p, "%i, %i", &joystick_state[0][js].pov_mapping[pov_nr][0], + &joystick_state[0][js].pov_mapping[pov_nr][1]); } } } @@ -2195,21 +2195,21 @@ save_input_devices(void) for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { sprintf(tmp2, "joystick_%i_nr", js); - ini_section_set_int(cat, tmp2, joystick_state[js].plat_joystick_nr); + ini_section_set_int(cat, tmp2, joystick_state[0][js].plat_joystick_nr); - if (joystick_state[js].plat_joystick_nr) { + if (joystick_state[0][js].plat_joystick_nr) { for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) { sprintf(tmp2, "joystick_%i_axis_%i", js, axis_nr); - ini_section_set_int(cat, tmp2, joystick_state[js].axis_mapping[axis_nr]); + ini_section_set_int(cat, tmp2, joystick_state[0][js].axis_mapping[axis_nr]); } for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) { sprintf(tmp2, "joystick_%i_button_%i", js, button_nr); - ini_section_set_int(cat, tmp2, joystick_state[js].button_mapping[button_nr]); + ini_section_set_int(cat, tmp2, joystick_state[0][js].button_mapping[button_nr]); } for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { sprintf(tmp2, "joystick_%i_pov_%i", js, pov_nr); - sprintf(temp, "%i, %i", joystick_state[js].pov_mapping[pov_nr][0], - joystick_state[js].pov_mapping[pov_nr][1]); + sprintf(temp, "%i, %i", joystick_state[0][js].pov_mapping[pov_nr][0], + joystick_state[0][js].pov_mapping[pov_nr][1]); ini_section_set_string(cat, tmp2, temp); } } diff --git a/src/game/gameport.c b/src/game/gameport.c index 079f8edb4..9f61a2fbd 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -102,7 +102,7 @@ static const struct { { NULL } }; -static joystick_instance_t *joystick_instance = NULL; +static joystick_instance_t *joystick_instance[GAMEPORT_MAX] = { NULL, NULL }; static uint8_t gameport_pnp_rom[] = { 0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */ @@ -284,10 +284,10 @@ gameport_update_joystick_type(void) gameport_add(standalone_gameport_type); /* Reset the joystick interface. */ - if (joystick_instance) { - joystick_instance->intf->close(joystick_instance->dat); - joystick_instance->intf = joysticks[joystick_type].joystick; - joystick_instance->dat = joystick_instance->intf->init(); + if (joystick_instance[0]) { + joystick_instance[0]->intf->close(joystick_instance[0]->dat); + joystick_instance[0]->intf = joysticks[joystick_type].joystick; + joystick_instance[0]->dat = joystick_instance[0]->intf->init(); } } @@ -372,30 +372,30 @@ gameport_init(const device_t *info) memset(dev, 0x00, sizeof(gameport_t)); /* Allocate global instance. */ - if (!joystick_instance && joystick_type) { - joystick_instance = malloc(sizeof(joystick_instance_t)); - memset(joystick_instance, 0x00, sizeof(joystick_instance_t)); + if (!joystick_instance[0] && joystick_type) { + joystick_instance[0] = malloc(sizeof(joystick_instance_t)); + memset(joystick_instance[0], 0x00, sizeof(joystick_instance_t)); - joystick_instance->axis[0].joystick = joystick_instance; - joystick_instance->axis[1].joystick = joystick_instance; - joystick_instance->axis[2].joystick = joystick_instance; - joystick_instance->axis[3].joystick = joystick_instance; + joystick_instance[0]->axis[0].joystick = joystick_instance[0]; + joystick_instance[0]->axis[1].joystick = joystick_instance[0]; + joystick_instance[0]->axis[2].joystick = joystick_instance[0]; + joystick_instance[0]->axis[3].joystick = joystick_instance[0]; - joystick_instance->axis[0].axis_nr = 0; - joystick_instance->axis[1].axis_nr = 1; - joystick_instance->axis[2].axis_nr = 2; - joystick_instance->axis[3].axis_nr = 3; + joystick_instance[0]->axis[0].axis_nr = 0; + joystick_instance[0]->axis[1].axis_nr = 1; + joystick_instance[0]->axis[2].axis_nr = 2; + joystick_instance[0]->axis[3].axis_nr = 3; - timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0); - timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0); - timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0); - timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0); + timer_add(&joystick_instance[0]->axis[0].timer, timer_over, &joystick_instance[0]->axis[0], 0); + timer_add(&joystick_instance[0]->axis[1].timer, timer_over, &joystick_instance[0]->axis[1], 0); + timer_add(&joystick_instance[0]->axis[2].timer, timer_over, &joystick_instance[0]->axis[2], 0); + timer_add(&joystick_instance[0]->axis[3].timer, timer_over, &joystick_instance[0]->axis[3], 0); - joystick_instance->intf = joysticks[joystick_type].joystick; - joystick_instance->dat = joystick_instance->intf->init(); + joystick_instance[0]->intf = joysticks[joystick_type].joystick; + joystick_instance[0]->dat = joystick_instance[0]->intf->init(); } - dev->joystick = joystick_instance; + dev->joystick = joystick_instance[0]; /* Map game port to the default address. Not applicable on PnP-only ports. */ dev->len = (info->local >> 16) & 0xff; @@ -464,11 +464,11 @@ gameport_close(void *priv) gameport_remap(dev, 0); /* Free the global instance here, if it wasn't already freed. */ - if (joystick_instance) { - joystick_instance->intf->close(joystick_instance->dat); + if (joystick_instance[0]) { + joystick_instance[0]->intf->close(joystick_instance[0]->dat); - free(joystick_instance); - joystick_instance = NULL; + free(joystick_instance[0]); + joystick_instance[0] = NULL; } free(dev); diff --git a/src/game/joystick_ch_flightstick_pro.c b/src/game/joystick_ch_flightstick_pro.c index 8ca51d531..6aaaa5dc5 100644 --- a/src/game/joystick_ch_flightstick_pro.c +++ b/src/game/joystick_ch_flightstick_pro.c @@ -62,23 +62,23 @@ ch_flightstick_pro_read(UNUSED(void *priv)) { uint8_t ret = 0xf0; - if (JOYSTICK_PRESENT(0)) { - if (joystick_state[0].button[0]) + if (JOYSTICK_PRESENT(0, 0)) { + if (joystick_state[0][0].button[0]) ret &= ~0x10; - if (joystick_state[0].button[1]) + if (joystick_state[0][0].button[1]) ret &= ~0x20; - if (joystick_state[0].button[2]) + if (joystick_state[0][0].button[2]) ret &= ~0x40; - if (joystick_state[0].button[3]) + if (joystick_state[0][0].button[3]) ret &= ~0x80; - if (joystick_state[0].pov[0] != -1) { - if (joystick_state[0].pov[0] > 315 || joystick_state[0].pov[0] < 45) + if (joystick_state[0][0].pov[0] != -1) { + if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45) ret &= ~0xf0; - else if (joystick_state[0].pov[0] >= 45 && joystick_state[0].pov[0] < 135) + else if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135) ret &= ~0xb0; - else if (joystick_state[0].pov[0] >= 135 && joystick_state[0].pov[0] < 225) + else if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225) ret &= ~0x70; - else if (joystick_state[0].pov[0] >= 225 && joystick_state[0].pov[0] < 315) + else if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315) ret &= ~0x30; } } @@ -95,18 +95,18 @@ ch_flightstick_pro_write(UNUSED(void *priv)) static int ch_flightstick_pro_read_axis(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: return 0; case 3: - return joystick_state[0].axis[2]; + return joystick_state[0][0].axis[2]; default: return 0; } diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index 201574126..122d2c65f 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -63,10 +63,10 @@ joystick_standard_read(UNUSED(void *priv)) uint8_t ret = 0xf0; for (int js = 0; js < 2; js++) { - if (JOYSTICK_PRESENT(js)) { - if (joystick_state[js].button[0]) + if (JOYSTICK_PRESENT(0, js)) { + if (joystick_state[0][js].button[0]) ret &= ~0x10; - if (joystick_state[js].button[1]) + if (joystick_state[0][js].button[1]) ret &= ~0x20; } } @@ -79,14 +79,14 @@ joystick_standard_read_4button(UNUSED(void *priv)) { uint8_t ret = 0xf0; - if (JOYSTICK_PRESENT(0)) { - if (joystick_state[0].button[0]) + if (JOYSTICK_PRESENT(0, 0)) { + if (joystick_state[0][0].button[0]) ret &= ~0x10; - if (joystick_state[0].button[1]) + if (joystick_state[0][0].button[1]) ret &= ~0x20; - if (joystick_state[0].button[2]) + if (joystick_state[0][0].button[2]) ret &= ~0x40; - if (joystick_state[0].button[3]) + if (joystick_state[0][0].button[3]) ret &= ~0x80; } @@ -104,21 +104,21 @@ joystick_standard_read_axis(UNUSED(void *priv), int axis) { switch (axis) { case 0: - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: - if (!JOYSTICK_PRESENT(1)) + if (!JOYSTICK_PRESENT(0, 1)) return AXIS_NOT_PRESENT; - return joystick_state[1].axis[0]; + return joystick_state[0][1].axis[0]; case 3: - if (!JOYSTICK_PRESENT(1)) + if (!JOYSTICK_PRESENT(0, 1)) return AXIS_NOT_PRESENT; - return joystick_state[1].axis[1]; + return joystick_state[0][1].axis[1]; default: return 0; } @@ -127,14 +127,14 @@ joystick_standard_read_axis(UNUSED(void *priv), int axis) static int joystick_standard_read_axis_4button(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: case 3: default: @@ -145,16 +145,16 @@ joystick_standard_read_axis_4button(UNUSED(void *priv), int axis) static int joystick_standard_read_axis_3axis(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: - return joystick_state[0].axis[2]; + return joystick_state[0][0].axis[2]; case 3: default: return 0; @@ -164,18 +164,18 @@ joystick_standard_read_axis_3axis(UNUSED(void *priv), int axis) static int joystick_standard_read_axis_4axis(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: - return joystick_state[0].axis[2]; + return joystick_state[0][0].axis[2]; case 3: - return joystick_state[0].axis[3]; + return joystick_state[0][0].axis[3]; default: return 0; } @@ -184,18 +184,18 @@ joystick_standard_read_axis_4axis(UNUSED(void *priv), int axis) static int joystick_standard_read_axis_6button(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: - return joystick_state[0].button[4] ? -32767 : 32768; + return joystick_state[0][0].button[4] ? -32767 : 32768; case 3: - return joystick_state[0].button[5] ? -32767 : 32768; + return joystick_state[0][0].button[5] ? -32767 : 32768; default: return 0; } @@ -203,24 +203,24 @@ joystick_standard_read_axis_6button(UNUSED(void *priv), int axis) static int joystick_standard_read_axis_8button(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: - if (joystick_state[0].button[4]) + if (joystick_state[0][0].button[4]) return -32767; - if (joystick_state[0].button[6]) + if (joystick_state[0][0].button[6]) return 32768; return 0; case 3: - if (joystick_state[0].button[5]) + if (joystick_state[0][0].button[5]) return -32767; - if (joystick_state[0].button[7]) + if (joystick_state[0][0].button[7]) return 32768; return 0; default: diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index 238e84d11..bfdc0e025 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -141,7 +141,7 @@ sw_read(void *priv) sw_data *sw = (sw_data *) priv; uint8_t temp = 0; - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return 0xff; if (timer_is_enabled(&sw->poll_timer)) { @@ -167,7 +167,7 @@ sw_write(void *priv) sw_data *sw = (sw_data *) priv; int64_t time_since_last = timer_get_remaining_us(&sw->trigger_timer); - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return; if (!sw->poll_left) { @@ -193,20 +193,20 @@ sw_write(void *priv) for (uint8_t js = 0; js < 4; js++) { uint16_t data = 0x3fff; - if (!JOYSTICK_PRESENT(js)) + if (!JOYSTICK_PRESENT(0, js)) break; - if (joystick_state[js].axis[1] < -16383) + if (joystick_state[0][js].axis[1] < -16383) data &= ~1; - if (joystick_state[js].axis[1] > 16383) + if (joystick_state[0][js].axis[1] > 16383) data &= ~2; - if (joystick_state[js].axis[0] > 16383) + if (joystick_state[0][js].axis[0] > 16383) data &= ~4; - if (joystick_state[js].axis[0] < -16383) + if (joystick_state[0][js].axis[0] < -16383) data &= ~8; for (uint8_t button_nr = 0; button_nr < 10; button_nr++) { - if (joystick_state[js].button[button_nr]) + if (joystick_state[0][js].button[button_nr]) data &= ~(1 << (button_nr + 4)); } @@ -230,7 +230,7 @@ sw_write(void *priv) static int sw_read_axis(UNUSED(void *priv), UNUSED(int axis)) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; return 0; /*No analogue support on Sidewinder game pad*/ diff --git a/src/game/joystick_tm_fcs.c b/src/game/joystick_tm_fcs.c index f5c1e64e6..4440b039e 100644 --- a/src/game/joystick_tm_fcs.c +++ b/src/game/joystick_tm_fcs.c @@ -62,14 +62,14 @@ tm_fcs_read(UNUSED(void *priv)) { uint8_t ret = 0xf0; - if (JOYSTICK_PRESENT(0)) { - if (joystick_state[0].button[0]) + if (JOYSTICK_PRESENT(0, 0)) { + if (joystick_state[0][0].button[0]) ret &= ~0x10; - if (joystick_state[0].button[1]) + if (joystick_state[0][0].button[1]) ret &= ~0x20; - if (joystick_state[0].button[2]) + if (joystick_state[0][0].button[2]) ret &= ~0x40; - if (joystick_state[0].button[3]) + if (joystick_state[0][0].button[3]) ret &= ~0x80; } @@ -85,26 +85,26 @@ tm_fcs_write(UNUSED(void *priv)) static int tm_fcs_read_axis(UNUSED(void *priv), int axis) { - if (!JOYSTICK_PRESENT(0)) + if (!JOYSTICK_PRESENT(0, 0)) return AXIS_NOT_PRESENT; switch (axis) { case 0: - return joystick_state[0].axis[0]; + return joystick_state[0][0].axis[0]; case 1: - return joystick_state[0].axis[1]; + return joystick_state[0][0].axis[1]; case 2: return 0; case 3: - if (joystick_state[0].pov[0] == -1) + if (joystick_state[0][0].pov[0] == -1) return 32767; - if (joystick_state[0].pov[0] > 315 || joystick_state[0].pov[0] < 45) + if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45) return -32768; - if (joystick_state[0].pov[0] >= 45 && joystick_state[0].pov[0] < 135) + if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135) return -16384; - if (joystick_state[0].pov[0] >= 135 && joystick_state[0].pov[0] < 225) + if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225) return 0; - if (joystick_state[0].pov[0] >= 225 && joystick_state[0].pov[0] < 315) + if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315) return 16384; return 0; default: diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 6dda4b400..c5fc1d192 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -45,7 +45,7 @@ #define AXIS_NOT_PRESENT -99999 -#define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) +#define JOYSTICK_PRESENT(gp, js) (joystick_state[gp][js].plat_joystick_nr != 0) #define GAMEPORT_1ADDR 0x010000 #define GAMEPORT_6ADDR 0x060000 @@ -146,7 +146,7 @@ extern const device_t *standalone_gameport_type; #endif extern int gameport_instance_id; extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -extern joystick_t joystick_state[MAX_JOYSTICKS]; +extern joystick_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS]; extern int joysticks_present; extern int joystick_type; diff --git a/src/qt/qt_joystickconfiguration.cpp b/src/qt/qt_joystickconfiguration.cpp index 8489dfd22..62a9302d1 100644 --- a/src/qt/qt_joystickconfiguration.cpp +++ b/src/qt/qt_joystickconfiguration.cpp @@ -41,7 +41,7 @@ JoystickConfiguration::JoystickConfiguration(int type, int joystick_nr, QWidget Models::AddEntry(model, plat_joystick_state[c].name, c + 1); } - ui->comboBoxDevice->setCurrentIndex(joystick_state[joystick_nr].plat_joystick_nr); + ui->comboBoxDevice->setCurrentIndex(joystick_state[0][joystick_nr].plat_joystick_nr); layout()->setSizeConstraint(QLayout::SetFixedSize); } @@ -119,7 +119,7 @@ JoystickConfiguration::on_comboBoxDevice_currentIndexChanged(int index) } int nr_axes = plat_joystick_state[joystick].nr_axes; - int mapping = joystick_state[joystick_nr].axis_mapping[c]; + int mapping = joystick_state[0][joystick_nr].axis_mapping[c]; if (mapping & POV_X) cbox->setCurrentIndex(nr_axes + (mapping & 3) * 2); else if (mapping & POV_Y) @@ -147,7 +147,7 @@ JoystickConfiguration::on_comboBoxDevice_currentIndexChanged(int index) Models::AddEntry(model, plat_joystick_state[joystick].button[d].name, 0); } - cbox->setCurrentIndex(joystick_state[joystick_nr].button_mapping[c]); + cbox->setCurrentIndex(joystick_state[0][joystick_nr].button_mapping[c]); ui->ct->addWidget(label, row, 0); ui->ct->addWidget(cbox, row, 1); @@ -179,7 +179,7 @@ JoystickConfiguration::on_comboBoxDevice_currentIndexChanged(int index) Models::AddEntry(model, plat_joystick_state[joystick].axis[d].name, 0); } - int mapping = joystick_state[joystick_nr].pov_mapping[c / 2][c & 1]; + int mapping = joystick_state[0][joystick_nr].pov_mapping[c / 2][c & 1]; int nr_povs = plat_joystick_state[joystick].nr_povs; if (mapping & POV_X) cbox->setCurrentIndex((mapping & 3) * 2); diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index d7b69442c..d7c61e8d2 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -136,7 +136,7 @@ static int get_axis(JoystickConfiguration &jc, int axis, int joystick_nr) { int axis_sel = jc.selectedAxis(axis); - int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_axes; + int nr_axes = plat_joystick_state[joystick_state[0][joystick_nr].plat_joystick_nr - 1].nr_axes; if (axis_sel < nr_axes) { return axis_sel; @@ -153,7 +153,7 @@ static int get_pov(JoystickConfiguration &jc, int pov, int joystick_nr) { int pov_sel = jc.selectedPov(pov); - int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr - 1].nr_povs * 2; + int nr_povs = plat_joystick_state[joystick_state[0][joystick_nr].plat_joystick_nr - 1].nr_povs * 2; if (pov_sel < nr_povs) { if (pov_sel & 1) @@ -176,19 +176,19 @@ updateJoystickConfig(int type, int joystick_nr, QWidget *parent) break; } - joystick_state[joystick_nr].plat_joystick_nr = jc.selectedDevice(); - if (joystick_state[joystick_nr].plat_joystick_nr) { + joystick_state[0][joystick_nr].plat_joystick_nr = jc.selectedDevice(); + if (joystick_state[0][joystick_nr].plat_joystick_nr) { for (int axis_nr = 0; axis_nr < joystick_get_axis_count(type); axis_nr++) { - joystick_state[joystick_nr].axis_mapping[axis_nr] = get_axis(jc, axis_nr, joystick_nr); + joystick_state[0][joystick_nr].axis_mapping[axis_nr] = get_axis(jc, axis_nr, joystick_nr); } for (int button_nr = 0; button_nr < joystick_get_button_count(type); button_nr++) { - joystick_state[joystick_nr].button_mapping[button_nr] = jc.selectedButton(button_nr); + joystick_state[0][joystick_nr].button_mapping[button_nr] = jc.selectedButton(button_nr); } for (int pov_nr = 0; pov_nr < joystick_get_pov_count(type) * 2; pov_nr += 2) { - joystick_state[joystick_nr].pov_mapping[pov_nr][0] = get_pov(jc, pov_nr, joystick_nr); - joystick_state[joystick_nr].pov_mapping[pov_nr][1] = get_pov(jc, pov_nr + 1, joystick_nr); + joystick_state[0][joystick_nr].pov_mapping[pov_nr][0] = get_pov(jc, pov_nr, joystick_nr); + joystick_state[0][joystick_nr].pov_mapping[pov_nr][1] = get_pov(jc, pov_nr + 1, joystick_nr); } } } diff --git a/src/qt/sdl_joystick.c b/src/qt/sdl_joystick.c index 03159ba7f..83a2a67b1 100644 --- a/src/qt/sdl_joystick.c +++ b/src/qt/sdl_joystick.c @@ -8,13 +8,13 @@ * * SDL2 joystick interface. * - * - * * Authors: Sarah Walker, - * Joakim L. Gilje + * Joakim L. Gilje, + * Jasmine Iwanek, jriwanek@gmail.com> * - * Copyright 2017-2021 Sarah Walker - * Copyright 2021 Joakim L. Gilje + * Copyright 2017-2021 Sarah Walker. + * Copyright 2021 Joakim L. Gilje. + * Copyright 2021-2025 Jasmine Iwanek. */ #include @@ -33,8 +33,8 @@ #include <86box/gameport.h> #include <86box/plat_unused.h> -int joysticks_present; -joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present = 0; +joystick_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS]; plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; static SDL_Joystick *sdl_joy[MAX_PLAT_JOYSTICKS]; @@ -89,7 +89,7 @@ joystick_close(void) } static int -joystick_get_axis(int joystick_nr, int mapping) +joystick_get_axis(int gameport, int joystick_nr, int mapping) { if (mapping & POV_X) { switch (plat_joystick_state[joystick_nr].p[mapping & 3]) { @@ -144,44 +144,44 @@ joystick_process(void) #if 0 pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", js, - joystick_state[js].x, - joystick_state[js].y, - joystick_state[js].b[0], - joystick_state[js].b[1], + joystick_state[0][js].x, + joystick_state[0][js].y, + joystick_state[0][js].b[0], + joystick_state[0][js].b[1], joysticks_present); #endif } for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { - if (joystick_state[js].plat_joystick_nr) { - int joystick_nr = joystick_state[js].plat_joystick_nr - 1; + if (joystick_state[0][js].plat_joystick_nr) { + int joystick_nr = joystick_state[0][js].plat_joystick_nr - 1; for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) - joystick_state[js].axis[axis_nr] = joystick_get_axis(joystick_nr, joystick_state[js].axis_mapping[axis_nr]); + joystick_state[0][js].axis[axis_nr] = joystick_get_axis(0, joystick_nr, joystick_state[0][js].axis_mapping[axis_nr]); for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) - joystick_state[js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[js].button_mapping[button_nr]]; + joystick_state[0][js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[0][js].button_mapping[button_nr]]; for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { - int x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); - int y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); + int x = joystick_get_axis(0, joystick_nr, joystick_state[0][js].pov_mapping[pov_nr][0]); + int y = joystick_get_axis(0, joystick_nr, joystick_state[0][js].pov_mapping[pov_nr][1]); double angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); double magnitude = sqrt((double) x * (double) x + (double) y * (double) y); if (magnitude < 16384) - joystick_state[js].pov[pov_nr] = -1; + joystick_state[0][js].pov[pov_nr] = -1; else - joystick_state[js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; + joystick_state[0][js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; } } else { for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) - joystick_state[js].axis[axis_nr] = 0; + joystick_state[0][js].axis[axis_nr] = 0; for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) - joystick_state[js].button[button_nr] = 0; + joystick_state[0][js].button[button_nr] = 0; for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) - joystick_state[js].pov[pov_nr] = -1; + joystick_state[0][js].pov[pov_nr] = -1; } } } diff --git a/src/qt/win_joystick_rawinput.c b/src/qt/win_joystick_rawinput.c index c293dcaca..5173d4f05 100644 --- a/src/qt/win_joystick_rawinput.c +++ b/src/qt/win_joystick_rawinput.c @@ -8,15 +8,13 @@ * * RawInput joystick interface. * - * - * * Authors: Miran Grca, * GH Cao, - * Jasmine Iwanek, + * Jasmine Iwanek, * * Copyright 2016-2018 Miran Grca. * Copyright 2020 GH Cao. - * Copyright 2021-2023 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #include #include @@ -98,9 +96,9 @@ typedef struct { } pov[MAX_JOY_POVS]; } raw_joystick_t; -plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -joystick_t joystick_state[MAX_JOYSTICKS]; int joysticks_present = 0; +joystick_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS]; +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; raw_joystick_t raw_joystick_state[MAX_PLAT_JOYSTICKS]; @@ -419,7 +417,7 @@ win_joystick_handle(PRAWINPUT raw) if (r == HIDP_STATUS_SUCCESS) { for (int i = 0; i < usage_length; i++) { - int button = raw_joystick_state[j].usage_button[usage_list[i]]; + int button = raw_joystick_state[j].usage_button[usage_list[i]]; plat_joystick_state[j].b[button] = 128; } } @@ -455,7 +453,7 @@ win_joystick_handle(PRAWINPUT raw) plat_joystick_state[j].a[axis_nr] = value; #if 0 - joystick_log("%s %-06d ", plat_joystick_state[j].axis[axis_nr].name, plat_joystick_state[j].a[axis_nr]); + joystick_log("%s %-06d ", plat_joystick_state[0][j].axis[axis_nr].name, plat_joystick_state[j].a[axis_nr]); #endif } @@ -477,7 +475,7 @@ win_joystick_handle(PRAWINPUT raw) plat_joystick_state[j].p[pov_nr] = value; #if 0 - joystick_log("%s %-3d ", plat_joystick_state[j].pov[pov_nr].name, plat_joystick_state[j].p[pov_nr]); + joystick_log("%s %-3d ", plat_joystick_state[0][j].pov[pov_nr].name, plat_joystick_state[j].p[pov_nr]); #endif } #if 0 @@ -512,35 +510,35 @@ joystick_process(void) return; for (int js = 0; js < joystick_get_max_joysticks(joystick_type); js++) { - if (joystick_state[js].plat_joystick_nr) { - int joystick_nr = joystick_state[js].plat_joystick_nr - 1; + if (joystick_state[0][js].plat_joystick_nr) { + int joystick_nr = joystick_state[0][js].plat_joystick_nr - 1; for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) - joystick_state[js].axis[axis_nr] = joystick_get_axis(joystick_nr, joystick_state[js].axis_mapping[axis_nr]); + joystick_state[0][js].axis[axis_nr] = joystick_get_axis(joystick_nr, joystick_state[0][js].axis_mapping[axis_nr]); for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) - joystick_state[js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[js].button_mapping[button_nr]]; + joystick_state[0][js].button[button_nr] = plat_joystick_state[joystick_nr].b[joystick_state[0][js].button_mapping[button_nr]]; for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) { - int x = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][0]); - int y = joystick_get_axis(joystick_nr, joystick_state[js].pov_mapping[pov_nr][1]); + int x = joystick_get_axis(joystick_nr, joystick_state[0][js].pov_mapping[pov_nr][0]); + int y = joystick_get_axis(joystick_nr, joystick_state[0][js].pov_mapping[pov_nr][1]); double angle = (atan2((double) y, (double) x) * 360.0) / (2 * M_PI); double magnitude = sqrt((double) x * (double) x + (double) y * (double) y); if (magnitude < 16384) - joystick_state[js].pov[pov_nr] = -1; + joystick_state[0][js].pov[pov_nr] = -1; else - joystick_state[js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; + joystick_state[0][js].pov[pov_nr] = ((int) angle + 90 + 360) % 360; } } else { for (int axis_nr = 0; axis_nr < joystick_get_axis_count(joystick_type); axis_nr++) - joystick_state[js].axis[axis_nr] = 0; + joystick_state[0][js].axis[axis_nr] = 0; for (int button_nr = 0; button_nr < joystick_get_button_count(joystick_type); button_nr++) - joystick_state[js].button[button_nr] = 0; + joystick_state[0][js].button[button_nr] = 0; for (int pov_nr = 0; pov_nr < joystick_get_pov_count(joystick_type); pov_nr++) - joystick_state[js].pov[pov_nr] = -1; + joystick_state[0][js].pov[pov_nr] = -1; } } } diff --git a/src/unix/unix.c b/src/unix/unix.c index 911905ef2..8e070d372 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -61,7 +61,7 @@ int fixed_size_y = 480; extern int title_set; extern wchar_t sdl_win_title[512]; plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -joystick_t joystick_state[MAX_JOYSTICKS]; +joystick_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS]; int joysticks_present; SDL_mutex *blitmtx; SDL_threadID eventthread; From 81b8038bc5115674db8a1c84fa0af70fa6ee9825 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 7 Jan 2025 01:12:42 -0500 Subject: [PATCH 0180/1190] Clean up .available & .poll --- src/acpi.c | 16 +- src/apm.c | 6 +- src/chipset/82c100.c | 2 +- src/chipset/acc2168.c | 2 +- src/chipset/ali1409.c | 2 +- src/chipset/ali1429.c | 4 +- src/chipset/ali1435.c | 2 +- src/chipset/ali1489.c | 2 +- src/chipset/ali1531.c | 2 +- src/chipset/ali1541.c | 2 +- src/chipset/ali1543.c | 4 +- src/chipset/ali1621.c | 2 +- src/chipset/ali6117.c | 4 +- src/chipset/compaq_386.c | 4 +- src/chipset/contaq_82c59x.c | 4 +- src/chipset/cs4031.c | 2 +- src/chipset/cs8230.c | 2 +- src/chipset/et6000.c | 2 +- src/chipset/gc100.c | 4 +- src/chipset/headland.c | 14 +- src/chipset/ims8848.c | 2 +- src/chipset/intel_420ex.c | 4 +- src/chipset/intel_4x0.c | 32 +-- src/chipset/intel_82335.c | 2 +- src/chipset/intel_i450kx.c | 2 +- src/chipset/intel_piix.c | 16 +- src/chipset/intel_sio.c | 4 +- src/chipset/neat.c | 2 +- src/chipset/olivetti_eva.c | 2 +- src/chipset/opti283.c | 2 +- src/chipset/opti291.c | 2 +- src/chipset/opti391.c | 6 +- src/chipset/opti495.c | 4 +- src/chipset/opti499.c | 2 +- src/chipset/opti5x7.c | 4 +- src/chipset/opti602.c | 4 +- src/chipset/opti822.c | 2 +- src/chipset/opti895.c | 6 +- src/chipset/scamp.c | 2 +- src/chipset/scat.c | 6 +- src/chipset/sis_5511.c | 2 +- src/chipset/sis_5511_h2p.c | 2 +- src/chipset/sis_5513_ide.c | 8 +- src/chipset/sis_5513_p2i.c | 10 +- src/chipset/sis_5571.c | 2 +- src/chipset/sis_5571_h2p.c | 2 +- src/chipset/sis_5571_old.c | 2 +- src/chipset/sis_5572_usb.c | 6 +- src/chipset/sis_5581.c | 2 +- src/chipset/sis_5581_h2p.c | 2 +- src/chipset/sis_5591.c | 4 +- src/chipset/sis_5591_h2p.c | 2 +- src/chipset/sis_5595_pmu.c | 4 +- src/chipset/sis_55xx.c | 2 +- src/chipset/sis_5600.c | 4 +- src/chipset/sis_5600_h2p.c | 2 +- src/chipset/sis_85c310.c | 2 +- src/chipset/sis_85c496.c | 4 +- src/chipset/sis_85c4xx.c | 8 +- src/chipset/sis_85c50x.c | 8 +- src/chipset/stpc.c | 12 +- src/chipset/umc_8886.c | 6 +- src/chipset/umc_8890.c | 2 +- src/chipset/umc_hb4.c | 2 +- src/chipset/via_apollo.c | 16 +- src/chipset/via_pipc.c | 12 +- src/chipset/via_vt82c49x.c | 8 +- src/chipset/via_vt82c505.c | 2 +- src/chipset/vl82c480.c | 4 +- src/chipset/wd76c10.c | 2 +- src/ddma.c | 2 +- src/device/bugger.c | 2 +- src/device/cassette.c | 2 +- src/device/hwm_gl518sm.c | 8 +- src/device/hwm_lm75.c | 4 +- src/device/hwm_lm78.c | 12 +- src/device/hwm_vt82c686.c | 2 +- src/device/ibm_5161.c | 2 +- src/device/isamem.c | 38 ++-- src/device/isapnp.c | 2 +- src/device/kbc_at.c | 50 ++--- src/device/keyboard_xt.c | 26 +-- src/device/mouse_bus.c | 6 +- src/device/mouse_microtouch_touchscreen.c | 2 +- src/device/mouse_ps2.c | 2 +- src/device/mouse_serial.c | 6 +- src/device/mouse_wacom_tablet.c | 6 +- src/device/nec_mate_unk.c | 2 +- src/device/novell_cardkey.c | 2 +- src/device/pci_bridge.c | 22 +- src/device/phoenix_486_jumper.c | 4 +- src/device/postcard.c | 2 +- src/device/serial.c | 16 +- src/device/serial_passthrough.c | 14 +- src/device/smbus_ali7101.c | 2 +- src/device/smbus_piix4.c | 4 +- src/device/smbus_sis5595.c | 2 +- src/device/unittester.c | 18 +- src/disk/hdc_esdi_at.c | 2 +- src/disk/hdc_esdi_mca.c | 2 +- src/disk/hdc_ide.c | 22 +- src/disk/hdc_ide_ali5213.c | 4 +- src/disk/hdc_ide_cmd640.c | 20 +- src/disk/hdc_ide_cmd646.c | 6 +- src/disk/hdc_ide_opti611.c | 4 +- src/disk/hdc_ide_sff8038i.c | 2 +- src/disk/hdc_ide_um8673f.c | 4 +- src/disk/hdc_ide_w83769f.c | 11 +- src/disk/hdc_st506_at.c | 2 +- src/disk/hdc_st506_xt.c | 26 +-- src/disk/hdc_xta.c | 36 +-- src/disk/hdc_xtide.c | 8 +- src/disk/lba_enhancer.c | 2 +- src/floppy/fdc.c | 42 ++-- src/floppy/fdc_magitronic.c | 2 +- src/floppy/fdc_monster.c | 2 +- src/floppy/fdc_pii15xb.c | 4 +- src/game/gameport.c | 32 +-- src/ioapic.c | 2 +- src/machine/m_amstrad.c | 12 +- src/machine/m_at_compaq.c | 2 +- src/machine/m_at_grid.c | 2 +- src/machine/m_at_t3100e_vid.c | 2 +- src/machine/m_europc.c | 2 +- src/machine/m_pcjr.c | 2 +- src/machine/m_ps1.c | 2 +- src/machine/m_ps1_hdc.c | 2 +- src/machine/m_tandy.c | 10 +- src/machine/m_xt_olivetti.c | 4 +- src/machine/m_xt_philips.c | 2 +- src/machine/m_xt_t1000_vid.c | 4 +- src/machine/m_xt_xi8088.c | 2 +- src/machine/m_xt_zenith.c | 2 +- src/mem/catalyst_flash.c | 2 +- src/mem/intel_flash.c | 6 +- src/mem/row.c | 18 +- src/mem/spd.c | 2 +- src/mem/sst_flash.c | 60 ++--- src/network/net_3c501.c | 2 +- src/network/net_3c503.c | 18 +- src/network/net_dp8390.c | 2 +- src/network/net_eeprom_nmc93cxx.c | 2 +- src/network/net_modem.c | 2 +- src/network/net_ne2000.c | 18 +- src/network/net_null.c | 8 +- src/network/net_pcap.c | 8 +- src/network/net_pcnet.c | 14 +- src/network/net_plip.c | 2 +- src/network/net_rtl8139.c | 2 +- src/network/net_slirp.c | 7 +- src/network/net_tulip.c | 8 +- src/network/net_vde.c | 8 +- src/network/net_wd8003.c | 12 +- src/nvr_at.c | 32 +-- src/nvr_ps2.c | 4 +- src/pci_dummy.c | 4 +- src/pit.c | 32 +-- src/pit_fast.c | 30 +-- src/port_6x.c | 8 +- src/port_92.c | 10 +- src/scsi/scsi_aha154x.c | 12 +- src/scsi/scsi_buslogic.c | 16 +- src/scsi/scsi_ncr53c400.c | 10 +- src/scsi/scsi_ncr53c8xx.c | 14 +- src/scsi/scsi_pcscsi.c | 6 +- src/scsi/scsi_spock.c | 4 +- src/scsi/scsi_t128.c | 6 +- src/sio/sio_82091aa.c | 8 +- src/sio/sio_acc3221.c | 2 +- src/sio/sio_ali5123.c | 2 +- src/sio/sio_detect.c | 2 +- src/sio/sio_f82c710.c | 4 +- src/sio/sio_fdc37c669.c | 4 +- src/sio/sio_fdc37c67x.c | 2 +- src/sio/sio_fdc37c6xx.c | 24 +- src/sio/sio_fdc37c93x.c | 18 +- src/sio/sio_fdc37m60x.c | 4 +- src/sio/sio_it86x1f.c | 4 +- src/sio/sio_pc87306.c | 2 +- src/sio/sio_pc87307.c | 8 +- src/sio/sio_pc87309.c | 4 +- src/sio/sio_pc87310.c | 6 +- src/sio/sio_pc87311.c | 4 +- src/sio/sio_pc87332.c | 10 +- src/sio/sio_prime3b.c | 4 +- src/sio/sio_prime3c.c | 4 +- src/sio/sio_um8663f.c | 12 +- src/sio/sio_um8669f.c | 6 +- src/sio/sio_vl82c113.c | 2 +- src/sio/sio_vt82c686.c | 2 +- src/sio/sio_w83787f.c | 10 +- src/sio/sio_w83877f.c | 8 +- src/sio/sio_w83977f.c | 10 +- src/sound/snd_sb.c | 4 +- src/usb.c | 2 +- src/video/agpgart.c | 2 +- src/video/vid_8514a.c | 12 +- src/video/vid_ati18800.c | 10 +- src/video/vid_ati28800.c | 22 +- src/video/vid_ati68860_ramdac.c | 2 +- src/video/vid_ati68875_ramdac.c | 2 +- src/video/vid_ati_mach64.c | 16 +- src/video/vid_ati_mach8.c | 124 +++++------ src/video/vid_att20c49x_ramdac.c | 6 +- src/video/vid_att2xc498_ramdac.c | 2 +- src/video/vid_av9194.c | 2 +- src/video/vid_bochs_vbe.c | 6 +- src/video/vid_bt481_ramdac.c | 2 +- src/video/vid_bt48x_ramdac.c | 10 +- src/video/vid_cga.c | 8 +- src/video/vid_chips_69000.c | 4 +- src/video/vid_cl54xx.c | 106 ++++----- src/video/vid_colorplus.c | 6 +- src/video/vid_compaq_cga.c | 4 +- src/video/vid_ega.c | 16 +- src/video/vid_et3000.c | 4 +- src/video/vid_et4000.c | 24 +- src/video/vid_et4000w32.c | 32 ++- src/video/vid_f82c425.c | 2 +- src/video/vid_genius.c | 2 +- src/video/vid_hercules.c | 6 +- src/video/vid_herculesplus.c | 6 +- src/video/vid_ht216.c | 16 +- src/video/vid_ibm_rgb528_ramdac.c | 2 +- src/video/vid_icd2061.c | 4 +- src/video/vid_ics2494.c | 8 +- src/video/vid_ics2595.c | 2 +- src/video/vid_im1024.c | 2 +- src/video/vid_incolor.c | 2 +- src/video/vid_mda.c | 6 +- src/video/vid_mga.c | 14 +- src/video/vid_nga.c | 6 +- src/video/vid_oak_oti.c | 28 +-- src/video/vid_ogc.c | 8 +- src/video/vid_paradise.c | 22 +- src/video/vid_pgc.c | 2 +- src/video/vid_rtg310x.c | 12 +- src/video/vid_s3.c | 257 +++++++++++----------- src/video/vid_s3_virge.c | 48 ++-- src/video/vid_sc1148x_ramdac.c | 8 +- src/video/vid_sc1502x_ramdac.c | 2 +- src/video/vid_sdac_ramdac.c | 8 +- src/video/vid_sigma.c | 6 +- src/video/vid_stg_ramdac.c | 2 +- src/video/vid_tgui9440.c | 22 +- src/video/vid_ti_cf62011.c | 2 +- src/video/vid_tkd8001_ramdac.c | 2 +- src/video/vid_tvga.c | 94 ++++---- src/video/vid_tvp3026_ramdac.c | 2 +- src/video/vid_vga.c | 6 +- src/video/vid_voodoo.c | 6 +- src/video/vid_voodoo_banshee.c | 44 ++-- src/video/vid_wy700.c | 2 +- src/video/vid_xga.c | 6 +- 254 files changed, 1214 insertions(+), 1313 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 339ea7dcf..0d5c1fe00 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -2576,7 +2576,7 @@ const device_t acpi_ali_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2590,7 +2590,7 @@ const device_t acpi_intel_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2604,7 +2604,7 @@ const device_t acpi_via_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2618,7 +2618,7 @@ const device_t acpi_via_596b_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2632,7 +2632,7 @@ const device_t acpi_smc_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2646,7 +2646,7 @@ const device_t acpi_sis_5582_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2660,7 +2660,7 @@ const device_t acpi_sis_5595_1997_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL @@ -2674,7 +2674,7 @@ const device_t acpi_sis_5595_device = { .init = acpi_init, .close = acpi_close, .reset = acpi_reset, - { .available = NULL }, + .available = NULL, .speed_changed = acpi_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/apm.c b/src/apm.c index d7ce262a3..3973f2b23 100644 --- a/src/apm.c +++ b/src/apm.c @@ -122,7 +122,7 @@ const device_t apm_device = { .init = apm_init, .close = apm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -136,7 +136,7 @@ const device_t apm_pci_device = { .init = apm_init, .close = apm_close, .reset = apm_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -150,7 +150,7 @@ const device_t apm_pci_acpi_device = { .init = apm_init, .close = apm_close, .reset = apm_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/82c100.c b/src/chipset/82c100.c index 689234ebb..05c3522d8 100644 --- a/src/chipset/82c100.c +++ b/src/chipset/82c100.c @@ -393,7 +393,7 @@ const device_t ct_82c100_device = { .init = ct_82c100_init, .close = ct_82c100_close, .reset = ct_82c100_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c index 9ce29bdff..982f50e82 100644 --- a/src/chipset/acc2168.c +++ b/src/chipset/acc2168.c @@ -201,7 +201,7 @@ const device_t acc2168_device = { .init = acc2168_init, .close = acc2168_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1409.c b/src/chipset/ali1409.c index 3e4286f80..8cda1a22b 100644 --- a/src/chipset/ali1409.c +++ b/src/chipset/ali1409.c @@ -191,7 +191,7 @@ const device_t ali1409_device = { .init = ali1409_init, .close = ali1409_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index 34c3e18c2..4a6a5cfa9 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -358,7 +358,7 @@ const device_t ali1429_device = { .init = ali1429_init, .close = ali1429_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -372,7 +372,7 @@ const device_t ali1429g_device = { .init = ali1429_init, .close = ali1429_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1435.c b/src/chipset/ali1435.c index 9476d2b45..8360267c9 100644 --- a/src/chipset/ali1435.c +++ b/src/chipset/ali1435.c @@ -308,7 +308,7 @@ const device_t ali1435_device = { .init = ali1435_init, .close = ali1435_close, .reset = ali1435_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index 3550f1da6..c61dd1511 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -499,7 +499,7 @@ const device_t ali1489_device = { .init = ali1489_init, .close = ali1489_close, .reset = ali1489_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index 06d0a0a60..1ff0689ad 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -389,7 +389,7 @@ const device_t ali1531_device = { .init = ali1531_init, .close = ali1531_close, .reset = ali1531_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c index d57ef51e7..3d7c1c546 100644 --- a/src/chipset/ali1541.c +++ b/src/chipset/ali1541.c @@ -665,7 +665,7 @@ const device_t ali1541_device = { .init = ali1541_init, .close = ali1541_close, .reset = ali1541_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index f35ec7590..2b9c93cb4 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -1673,7 +1673,7 @@ const device_t ali1543_device = { .init = ali1543_init, .close = ali1543_close, .reset = ali1543_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1687,7 +1687,7 @@ const device_t ali1543c_device = { .init = ali1543_init, .close = ali1543_close, .reset = ali1543_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c index 6194dce19..96748ce34 100644 --- a/src/chipset/ali1621.c +++ b/src/chipset/ali1621.c @@ -692,7 +692,7 @@ const device_t ali1621_device = { .init = ali1621_init, .close = ali1621_close, .reset = ali1621_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index cc2e465a2..2d66ba9d1 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -499,7 +499,7 @@ const device_t ali1217_device = { .init = ali6117_init, .close = ali6117_close, .reset = ali6117_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -513,7 +513,7 @@ const device_t ali6117d_device = { .init = ali6117_init, .close = ali6117_close, .reset = ali6117_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/compaq_386.c b/src/chipset/compaq_386.c index 8c241e087..bc81c5472 100644 --- a/src/chipset/compaq_386.c +++ b/src/chipset/compaq_386.c @@ -772,7 +772,7 @@ const device_t compaq_386_device = { .init = compaq_386_init, .close = compaq_386_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -786,7 +786,7 @@ const device_t compaq_genoa_device = { .init = compaq_genoa_init, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 5c2910227..90667c42f 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -359,7 +359,7 @@ const device_t contaq_82c596a_device = { .init = contaq_82c59x_init, .close = contaq_82c59x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -373,7 +373,7 @@ const device_t contaq_82c597_device = { .init = contaq_82c59x_init, .close = contaq_82c59x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/cs4031.c b/src/chipset/cs4031.c index fb439ec3a..b482fa254 100644 --- a/src/chipset/cs4031.c +++ b/src/chipset/cs4031.c @@ -185,7 +185,7 @@ const device_t cs4031_device = { .init = cs4031_init, .close = cs4031_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/cs8230.c b/src/chipset/cs8230.c index 93a7f1bba..62852b88d 100644 --- a/src/chipset/cs8230.c +++ b/src/chipset/cs8230.c @@ -178,7 +178,7 @@ const device_t cs8230_device = { .init = cs8230_init, .close = cs8230_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/et6000.c b/src/chipset/et6000.c index f2cffd7f7..608f2cc9b 100644 --- a/src/chipset/et6000.c +++ b/src/chipset/et6000.c @@ -162,7 +162,7 @@ const device_t et6000_device = { .init = et6000_init, .close = et6000_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c index 0b4717903..fc2321fae 100644 --- a/src/chipset/gc100.c +++ b/src/chipset/gc100.c @@ -238,7 +238,7 @@ const device_t gc100_device = { .init = gc100_init, .close = gc100_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -252,7 +252,7 @@ const device_t gc100a_device = { .init = gc100_init, .close = gc100_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/headland.c b/src/chipset/headland.c index db5922470..9d7cf97c7 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -699,7 +699,7 @@ const device_t headland_gc10x_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -713,7 +713,7 @@ const device_t headland_gc113_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -727,7 +727,7 @@ const device_t headland_ht18a_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -741,7 +741,7 @@ const device_t headland_ht18b_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -755,7 +755,7 @@ const device_t headland_ht18c_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -769,7 +769,7 @@ const device_t headland_ht21c_d_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -783,7 +783,7 @@ const device_t headland_ht21e_device = { .init = headland_init, .close = headland_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/ims8848.c b/src/chipset/ims8848.c index 3e86a44e1..0ce3a5e44 100644 --- a/src/chipset/ims8848.c +++ b/src/chipset/ims8848.c @@ -416,7 +416,7 @@ const device_t ims8848_device = { .init = ims8848_init, .close = ims8848_close, .reset = ims8848_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_420ex.c b/src/chipset/intel_420ex.c index 34335d53c..7b069cce3 100644 --- a/src/chipset/intel_420ex.c +++ b/src/chipset/intel_420ex.c @@ -579,7 +579,7 @@ const device_t i420ex_device = { .init = i420ex_init, .close = i420ex_close, .reset = i420ex_reset, - { .available = NULL }, + .available = NULL, .speed_changed = i420ex_speed_changed, .force_redraw = NULL, .config = NULL @@ -593,7 +593,7 @@ const device_t i420ex_ide_device = { .init = i420ex_init, .close = i420ex_close, .reset = i420ex_reset, - { .available = NULL }, + .available = NULL, .speed_changed = i420ex_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 2f6afa940..36303deb7 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -1967,7 +1967,7 @@ const device_t i420tx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1981,7 +1981,7 @@ const device_t i420zx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1995,7 +1995,7 @@ const device_t i430lx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2009,7 +2009,7 @@ const device_t i430nx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2023,7 +2023,7 @@ const device_t i430fx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2037,7 +2037,7 @@ const device_t i430fx_rev02_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2051,7 +2051,7 @@ const device_t i430hx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2065,7 +2065,7 @@ const device_t i430vx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2079,7 +2079,7 @@ const device_t i430tx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2093,7 +2093,7 @@ const device_t i440fx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2107,7 +2107,7 @@ const device_t i440lx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2121,7 +2121,7 @@ const device_t i440ex_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2135,7 +2135,7 @@ const device_t i440bx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2149,7 +2149,7 @@ const device_t i440bx_no_agp_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2163,7 +2163,7 @@ const device_t i440gx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2177,7 +2177,7 @@ const device_t i440zx_device = { .init = i4x0_init, .close = i4x0_close, .reset = i4x0_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_82335.c b/src/chipset/intel_82335.c index da0cc30f6..cc7f07c3a 100644 --- a/src/chipset/intel_82335.c +++ b/src/chipset/intel_82335.c @@ -209,7 +209,7 @@ const device_t intel_82335_device = { .init = intel_82335_init, .close = intel_82335_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_i450kx.c b/src/chipset/intel_i450kx.c index 2f6547309..1dfd6f315 100644 --- a/src/chipset/intel_i450kx.c +++ b/src/chipset/intel_i450kx.c @@ -824,7 +824,7 @@ const device_t i450kx_device = { .init = i450kx_init, .close = i450kx_close, .reset = i450kx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index c6a6fc0ac..e52492df9 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1674,7 +1674,7 @@ const device_t piix_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1688,7 +1688,7 @@ const device_t piix_no_mirq_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1702,7 +1702,7 @@ const device_t piix_rev02_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1716,7 +1716,7 @@ const device_t piix3_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1730,7 +1730,7 @@ const device_t piix3_ioapic_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1744,7 +1744,7 @@ const device_t piix4_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1758,7 +1758,7 @@ const device_t piix4e_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL @@ -1772,7 +1772,7 @@ const device_t slc90e66_device = { .init = piix_init, .close = piix_close, .reset = piix_reset, - { .available = NULL }, + .available = NULL, .speed_changed = piix_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index 03a292da8..c66b5ce04 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -568,7 +568,7 @@ const device_t sio_device = { .init = sio_init, .close = sio_close, .reset = sio_reset, - { .available = NULL }, + .available = NULL, .speed_changed = sio_speed_changed, .force_redraw = NULL, .config = NULL @@ -582,7 +582,7 @@ const device_t sio_zb_device = { .init = sio_init, .close = sio_close, .reset = sio_reset, - { .available = NULL }, + .available = NULL, .speed_changed = sio_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 000492d14..6f7dc5be3 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -1124,7 +1124,7 @@ const device_t neat_device = { .init = neat_init, .close = neat_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/olivetti_eva.c b/src/chipset/olivetti_eva.c index 1f5eacc6c..bdb5440c9 100644 --- a/src/chipset/olivetti_eva.c +++ b/src/chipset/olivetti_eva.c @@ -171,7 +171,7 @@ const device_t olivetti_eva_device = { .init = olivetti_eva_init, .close = olivetti_eva_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index 63976985b..b708eb0ab 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -324,7 +324,7 @@ const device_t opti283_device = { .init = opti283_init, .close = opti283_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti291.c b/src/chipset/opti291.c index 6d2256974..0ff037434 100644 --- a/src/chipset/opti291.c +++ b/src/chipset/opti291.c @@ -161,7 +161,7 @@ const device_t opti291_device = { .init = opti291_init, .close = opti291_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti391.c b/src/chipset/opti391.c index c22c2a04b..7d3c10c98 100644 --- a/src/chipset/opti391.c +++ b/src/chipset/opti391.c @@ -374,7 +374,7 @@ const device_t opti381_device = { .init = opti391_init, .close = opti391_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -388,7 +388,7 @@ const device_t opti481_device = { .init = opti391_init, .close = opti391_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -402,7 +402,7 @@ const device_t opti391_device = { .init = opti391_init, .close = opti391_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index 84ef6a202..f53ae0899 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -271,7 +271,7 @@ const device_t opti493_device = { .init = opti495_init, .close = opti495_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -285,7 +285,7 @@ const device_t opti495_device = { .init = opti495_init, .close = opti495_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index ecadd2224..81c5bee5a 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -265,7 +265,7 @@ const device_t opti499_device = { .init = opti499_init, .close = opti499_close, .reset = opti499_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti5x7.c b/src/chipset/opti5x7.c index 494fdee64..015ffb9f4 100644 --- a/src/chipset/opti5x7.c +++ b/src/chipset/opti5x7.c @@ -193,7 +193,7 @@ const device_t opti5x7_device = { .init = opti5x7_init, .close = opti5x7_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -207,7 +207,7 @@ const device_t opti5x7_pci_device = { .init = opti5x7_init, .close = opti5x7_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti602.c b/src/chipset/opti602.c index 3b5614ff4..7082408c7 100644 --- a/src/chipset/opti602.c +++ b/src/chipset/opti602.c @@ -218,7 +218,7 @@ const device_t opti601_device = { .init = opti602_init, .close = opti602_close, .reset = opti602_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -232,7 +232,7 @@ const device_t opti602_device = { .init = opti602_init, .close = opti602_close, .reset = opti602_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti822.c b/src/chipset/opti822.c index 3e9316f2b..9dd835412 100644 --- a/src/chipset/opti822.c +++ b/src/chipset/opti822.c @@ -412,7 +412,7 @@ const device_t opti822_device = { .init = opti822_init, .close = opti822_close, .reset = opti822_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index f1878a51b..4ce31c362 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -306,7 +306,7 @@ const device_t opti802g_device = { .init = opti895_init, .close = opti895_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -320,7 +320,7 @@ const device_t opti802g_pci_device = { .init = opti895_init, .close = opti895_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -334,7 +334,7 @@ const device_t opti895_device = { .init = opti895_init, .close = opti895_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 31e24eeba..6a38f4ec2 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -1204,7 +1204,7 @@ const device_t vlsi_scamp_device = { .init = scamp_init, .close = scamp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/scat.c b/src/chipset/scat.c index d168b643f..edbaf41e3 100644 --- a/src/chipset/scat.c +++ b/src/chipset/scat.c @@ -1559,7 +1559,7 @@ const device_t scat_device = { .init = scat_init, .close = scat_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1573,7 +1573,7 @@ const device_t scat_4_device = { .init = scat_init, .close = scat_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1587,7 +1587,7 @@ const device_t scat_sx_device = { .init = scat_init, .close = scat_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5511.c b/src/chipset/sis_5511.c index aa841ed9c..38fcfe717 100644 --- a/src/chipset/sis_5511.c +++ b/src/chipset/sis_5511.c @@ -165,7 +165,7 @@ const device_t sis_5511_device = { .init = sis_5511_init, .close = sis_5511_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5511_h2p.c b/src/chipset/sis_5511_h2p.c index 7916d6ae2..543fcacc5 100644 --- a/src/chipset/sis_5511_h2p.c +++ b/src/chipset/sis_5511_h2p.c @@ -454,7 +454,7 @@ const device_t sis_5511_h2p_device = { .init = sis_5511_host_to_pci_init, .close = sis_5511_host_to_pci_close, .reset = sis_5511_host_to_pci_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5513_ide.c b/src/chipset/sis_5513_ide.c index 5cbfbdea8..9e3a0ad07 100644 --- a/src/chipset/sis_5513_ide.c +++ b/src/chipset/sis_5513_ide.c @@ -456,7 +456,7 @@ const device_t sis_5513_ide_device = { .init = sis_5513_ide_init, .close = sis_5513_ide_close, .reset = sis_5513_ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -470,7 +470,7 @@ const device_t sis_5572_ide_device = { .init = sis_5513_ide_init, .close = sis_5513_ide_close, .reset = sis_5513_ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -484,7 +484,7 @@ const device_t sis_5582_ide_device = { .init = sis_5513_ide_init, .close = sis_5513_ide_close, .reset = sis_5513_ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -498,7 +498,7 @@ const device_t sis_5591_5600_ide_device = { .init = sis_5513_ide_init, .close = sis_5513_ide_close, .reset = sis_5513_ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5513_p2i.c b/src/chipset/sis_5513_p2i.c index 4205db161..e7012e1b6 100644 --- a/src/chipset/sis_5513_p2i.c +++ b/src/chipset/sis_5513_p2i.c @@ -1318,7 +1318,7 @@ const device_t sis_5513_p2i_device = { .init = sis_5513_pci_to_isa_init, .close = sis_5513_pci_to_isa_close, .reset = sis_5513_pci_to_isa_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1332,7 +1332,7 @@ const device_t sis_5572_p2i_device = { .init = sis_5513_pci_to_isa_init, .close = sis_5513_pci_to_isa_close, .reset = sis_5513_pci_to_isa_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1347,7 +1347,7 @@ const device_t sis_5582_p2i_device = { .init = sis_5513_pci_to_isa_init, .close = sis_5513_pci_to_isa_close, .reset = sis_5513_pci_to_isa_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1362,7 +1362,7 @@ const device_t sis_5595_1997_p2i_device = { .init = sis_5513_pci_to_isa_init, .close = sis_5513_pci_to_isa_close, .reset = sis_5513_pci_to_isa_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1376,7 +1376,7 @@ const device_t sis_5595_p2i_device = { .init = sis_5513_pci_to_isa_init, .close = sis_5513_pci_to_isa_close, .reset = sis_5513_pci_to_isa_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c index 3fb111978..3980704fd 100644 --- a/src/chipset/sis_5571.c +++ b/src/chipset/sis_5571.c @@ -177,7 +177,7 @@ const device_t sis_5571_device = { .init = sis_5571_init, .close = sis_5571_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5571_h2p.c b/src/chipset/sis_5571_h2p.c index 4a4ee9b83..d04964581 100644 --- a/src/chipset/sis_5571_h2p.c +++ b/src/chipset/sis_5571_h2p.c @@ -451,7 +451,7 @@ const device_t sis_5571_h2p_device = { .init = sis_5571_host_to_pci_init, .close = sis_5571_host_to_pci_close, .reset = sis_5571_host_to_pci_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5571_old.c b/src/chipset/sis_5571_old.c index f130ecd8a..422ed4bb8 100644 --- a/src/chipset/sis_5571_old.c +++ b/src/chipset/sis_5571_old.c @@ -765,7 +765,7 @@ const device_t sis_5571_device = { .init = sis_5571_init, .close = sis_5571_close, .reset = sis_5571_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5572_usb.c b/src/chipset/sis_5572_usb.c index 250c32587..bc7dc7d38 100644 --- a/src/chipset/sis_5572_usb.c +++ b/src/chipset/sis_5572_usb.c @@ -288,7 +288,7 @@ const device_t sis_5572_usb_device = { .init = sis_5572_usb_init, .close = sis_5572_usb_close, .reset = sis_5572_usb_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -302,7 +302,7 @@ const device_t sis_5582_usb_device = { .init = sis_5572_usb_init, .close = sis_5572_usb_close, .reset = sis_5572_usb_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -316,7 +316,7 @@ const device_t sis_5595_usb_device = { .init = sis_5572_usb_init, .close = sis_5572_usb_close, .reset = sis_5572_usb_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5581.c b/src/chipset/sis_5581.c index e2308c2d9..998ac5350 100644 --- a/src/chipset/sis_5581.c +++ b/src/chipset/sis_5581.c @@ -177,7 +177,7 @@ const device_t sis_5581_device = { .init = sis_5581_init, .close = sis_5581_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5581_h2p.c b/src/chipset/sis_5581_h2p.c index 30bd70bfe..d01e9dd28 100644 --- a/src/chipset/sis_5581_h2p.c +++ b/src/chipset/sis_5581_h2p.c @@ -545,7 +545,7 @@ const device_t sis_5581_h2p_device = { .init = sis_5581_host_to_pci_init, .close = sis_5581_host_to_pci_close, .reset = sis_5581_host_to_pci_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5591.c b/src/chipset/sis_5591.c index 969fcb8dd..3cb11cb5b 100644 --- a/src/chipset/sis_5591.c +++ b/src/chipset/sis_5591.c @@ -189,7 +189,7 @@ const device_t sis_5591_1997_device = { .init = sis_5591_init, .close = sis_5591_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -203,7 +203,7 @@ const device_t sis_5591_device = { .init = sis_5591_init, .close = sis_5591_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5591_h2p.c b/src/chipset/sis_5591_h2p.c index 8fcbeeb6f..048e7deea 100644 --- a/src/chipset/sis_5591_h2p.c +++ b/src/chipset/sis_5591_h2p.c @@ -486,7 +486,7 @@ const device_t sis_5591_h2p_device = { .init = sis_5591_host_to_pci_init, .close = sis_5591_host_to_pci_close, .reset = sis_5591_host_to_pci_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5595_pmu.c b/src/chipset/sis_5595_pmu.c index de351ad7c..2f5aa10b1 100644 --- a/src/chipset/sis_5595_pmu.c +++ b/src/chipset/sis_5595_pmu.c @@ -433,7 +433,7 @@ const device_t sis_5595_1997_pmu_device = { .init = sis_5595_pmu_init, .close = sis_5595_pmu_close, .reset = sis_5595_pmu_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -447,7 +447,7 @@ const device_t sis_5595_pmu_device = { .init = sis_5595_pmu_init, .close = sis_5595_pmu_close, .reset = sis_5595_pmu_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_55xx.c b/src/chipset/sis_55xx.c index 2cad21f22..1cb0744eb 100644 --- a/src/chipset/sis_55xx.c +++ b/src/chipset/sis_55xx.c @@ -89,7 +89,7 @@ const device_t sis_55xx_common_device = { .init = sis_55xx_common_init, .close = sis_55xx_common_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5600.c b/src/chipset/sis_5600.c index ed7384740..1ed7f9ad0 100644 --- a/src/chipset/sis_5600.c +++ b/src/chipset/sis_5600.c @@ -189,7 +189,7 @@ const device_t sis_5600_1997_device = { .init = sis_5600_init, .close = sis_5600_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -203,7 +203,7 @@ const device_t sis_5600_device = { .init = sis_5600_init, .close = sis_5600_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_5600_h2p.c b/src/chipset/sis_5600_h2p.c index f6ee926da..a15c6fff5 100644 --- a/src/chipset/sis_5600_h2p.c +++ b/src/chipset/sis_5600_h2p.c @@ -427,7 +427,7 @@ const device_t sis_5600_h2p_device = { .init = sis_5600_host_to_pci_init, .close = sis_5600_host_to_pci_close, .reset = sis_5600_host_to_pci_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_85c310.c b/src/chipset/sis_85c310.c index 296307fe1..d62cc3b24 100644 --- a/src/chipset/sis_85c310.c +++ b/src/chipset/sis_85c310.c @@ -146,7 +146,7 @@ const device_t rabbit_device = { .init = rabbit_init, .close = rabbit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_85c496.c b/src/chipset/sis_85c496.c index 3c3d5bd8c..5ba315822 100644 --- a/src/chipset/sis_85c496.c +++ b/src/chipset/sis_85c496.c @@ -702,7 +702,7 @@ const device_t sis_85c496_device = { .init = sis_85c496_init, .close = sis_85c496_close, .reset = sis_85c496_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -716,7 +716,7 @@ const device_t sis_85c496_ls486e_device = { .init = sis_85c496_init, .close = sis_85c496_close, .reset = sis_85c496_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index f80ecf99e..1f98ee8a6 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -403,7 +403,7 @@ const device_t sis_85c401_device = { .init = sis_85c4xx_init, .close = sis_85c4xx_close, .reset = sis_85c4xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -417,7 +417,7 @@ const device_t sis_85c460_device = { .init = sis_85c4xx_init, .close = sis_85c4xx_close, .reset = sis_85c4xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -432,7 +432,7 @@ const device_t sis_85c461_device = { .init = sis_85c4xx_init, .close = sis_85c4xx_close, .reset = sis_85c4xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -446,7 +446,7 @@ const device_t sis_85c471_device = { .init = sis_85c4xx_init, .close = sis_85c4xx_close, .reset = sis_85c4xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c index 2286105ce..192ae3767 100644 --- a/src/chipset/sis_85c50x.c +++ b/src/chipset/sis_85c50x.c @@ -684,7 +684,7 @@ const device_t sis_85c50x_device = { .init = sis_85c50x_init, .close = sis_85c50x_close, .reset = sis_85c50x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -698,7 +698,7 @@ const device_t sis_550x_85c503_device = { .init = sis_85c50x_init, .close = sis_85c50x_close, .reset = sis_85c50x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -712,7 +712,7 @@ const device_t sis_85c50x_5503_device = { .init = sis_85c50x_init, .close = sis_85c50x_close, .reset = sis_85c50x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -726,7 +726,7 @@ const device_t sis_550x_device = { .init = sis_85c50x_init, .close = sis_85c50x_close, .reset = sis_85c50x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index dbe39ec5c..3bb3a7c2a 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -1096,7 +1096,7 @@ const device_t stpc_client_device = { .init = stpc_init, .close = stpc_close, .reset = stpc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1110,7 +1110,7 @@ const device_t stpc_consumer2_device = { .init = stpc_init, .close = stpc_close, .reset = stpc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1124,7 +1124,7 @@ const device_t stpc_elite_device = { .init = stpc_init, .close = stpc_close, .reset = stpc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1138,7 +1138,7 @@ const device_t stpc_atlas_device = { .init = stpc_init, .close = stpc_close, .reset = stpc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1153,7 +1153,7 @@ const device_t stpc_serial_device = { .init = stpc_serial_init, .close = stpc_serial_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1167,7 +1167,7 @@ const device_t stpc_lpt_device = { .init = stpc_lpt_init, .close = stpc_lpt_close, .reset = stpc_lpt_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index 4242062c6..30b0ecb71 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -431,7 +431,7 @@ const device_t umc_8886f_device = { .init = umc_8886_init, .close = umc_8886_close, .reset = umc_8886_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -445,7 +445,7 @@ const device_t umc_8886af_device = { .init = umc_8886_init, .close = umc_8886_close, .reset = umc_8886_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -459,7 +459,7 @@ const device_t umc_8886bf_device = { .init = umc_8886_init, .close = umc_8886_close, .reset = umc_8886_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/umc_8890.c b/src/chipset/umc_8890.c index 7de2ca1d0..37862e2fc 100644 --- a/src/chipset/umc_8890.c +++ b/src/chipset/umc_8890.c @@ -234,7 +234,7 @@ const device_t umc_8890_device = { .init = umc_8890_init, .close = umc_8890_close, .reset = umc_8890_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index c1f359f26..98bdfc82c 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -477,7 +477,7 @@ const device_t umc_hb4_device = { .init = hb4_init, .close = hb4_close, .reset = hb4_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/via_apollo.c b/src/chipset/via_apollo.c index 20e2c7f74..fa96c4927 100644 --- a/src/chipset/via_apollo.c +++ b/src/chipset/via_apollo.c @@ -793,7 +793,7 @@ const device_t via_vpx_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -807,7 +807,7 @@ const device_t amd640_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -821,7 +821,7 @@ const device_t via_vp3_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -835,7 +835,7 @@ const device_t via_mvp3_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -849,7 +849,7 @@ const device_t via_apro_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -863,7 +863,7 @@ const device_t via_apro133_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -877,7 +877,7 @@ const device_t via_apro133a_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -891,7 +891,7 @@ const device_t via_vt8601_device = { .init = via_apollo_init, .close = via_apollo_close, .reset = via_apollo_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 1f153092b..3a6e6fc5c 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1721,7 +1721,7 @@ const device_t via_vt82c586b_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1735,7 +1735,7 @@ const device_t via_vt82c596a_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1749,7 +1749,7 @@ const device_t via_vt82c596b_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1763,7 +1763,7 @@ const device_t via_vt82c686a_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1777,7 +1777,7 @@ const device_t via_vt82c686b_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1791,7 +1791,7 @@ const device_t via_vt8231_device = { .init = pipc_init, .close = pipc_close, .reset = pipc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index de55f7060..f36dad2e7 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -375,7 +375,7 @@ const device_t via_vt82c49x_device = { .init = vt82c49x_init, .close = vt82c49x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -389,7 +389,7 @@ const device_t via_vt82c49x_pci_device = { .init = vt82c49x_init, .close = vt82c49x_close, .reset = vt82c49x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -403,7 +403,7 @@ const device_t via_vt82c49x_ide_device = { .init = vt82c49x_init, .close = vt82c49x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -417,7 +417,7 @@ const device_t via_vt82c49x_pci_ide_device = { .init = vt82c49x_init, .close = vt82c49x_close, .reset = vt82c49x_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/via_vt82c505.c b/src/chipset/via_vt82c505.c index 34efbead9..8cb6c67a0 100644 --- a/src/chipset/via_vt82c505.c +++ b/src/chipset/via_vt82c505.c @@ -232,7 +232,7 @@ const device_t via_vt82c505_device = { .init = vt82c505_init, .close = vt82c505_close, .reset = vt82c505_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 00adcc2a4..38a6bdfb9 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -207,7 +207,7 @@ const device_t vl82c480_device = { .init = vl82c480_init, .close = vl82c480_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -221,7 +221,7 @@ const device_t vl82c486_device = { .init = vl82c480_init, .close = vl82c480_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index df8558b05..6de921af1 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -1022,7 +1022,7 @@ const device_t wd76c10_device = { .init = wd76c10_init, .close = wd76c10_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/ddma.c b/src/ddma.c index 7cbe2831e..0ca1bb879 100644 --- a/src/ddma.c +++ b/src/ddma.c @@ -193,7 +193,7 @@ const device_t ddma_device = { .init = ddma_init, .close = ddma_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/bugger.c b/src/device/bugger.c index c2678d66a..56cac91bc 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -351,7 +351,7 @@ const device_t bugger_device = { .init = bug_init, .close = bug_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/cassette.c b/src/device/cassette.c index a239c6393..608de7463 100644 --- a/src/device/cassette.c +++ b/src/device/cassette.c @@ -722,7 +722,7 @@ const device_t cassette_device = { .init = cassette_init, .close = cassette_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index 6ba1083d9..23763ebb8 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -325,7 +325,7 @@ const device_t gl518sm_2c_device = { .init = gl518sm_init, .close = gl518sm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -340,7 +340,7 @@ const device_t gl518sm_2d_device = { .init = gl518sm_init, .close = gl518sm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -355,7 +355,7 @@ const device_t gl520sm_2c_device = { .init = gl518sm_init, .close = gl518sm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -371,7 +371,7 @@ const device_t gl520sm_2d_device = { .init = gl518sm_init, .close = gl518sm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 14b638365..831d16ded 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -243,7 +243,7 @@ const device_t lm75_1_4a_device = { .init = lm75_init, .close = lm75_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -259,7 +259,7 @@ const device_t lm75_w83781d_device = { .init = lm75_init, .close = lm75_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index f3003db26..3219e87e6 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -857,7 +857,7 @@ const device_t lm78_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -872,7 +872,7 @@ const device_t w83781d_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -887,7 +887,7 @@ const device_t w83781d_p5a_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -903,7 +903,7 @@ const device_t as99127f_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -918,7 +918,7 @@ const device_t as99127f_rev2_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -933,7 +933,7 @@ const device_t w83782d_device = { .init = lm78_init, .close = lm78_close, .reset = lm78_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c index b6a0dddda..7d764bcb9 100644 --- a/src/device/hwm_vt82c686.c +++ b/src/device/hwm_vt82c686.c @@ -222,7 +222,7 @@ const device_t via_vt82c686_hwm_device = { .init = vt82c686_init, .close = vt82c686_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/ibm_5161.c b/src/device/ibm_5161.c index 762a379a1..456227676 100644 --- a/src/device/ibm_5161.c +++ b/src/device/ibm_5161.c @@ -116,7 +116,7 @@ const device_t ibm_5161_device = { .init = ibm_5161_init, .close = ibm_5161_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/isamem.c b/src/device/isamem.c index f63a5a5a1..5d3164757 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -895,7 +895,7 @@ static const device_t ibmxt_32k_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ibmxt_32k_config @@ -943,7 +943,7 @@ static const device_t ibmxt_64k_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ibmxt_64k_config @@ -991,7 +991,7 @@ static const device_t ibmxt_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ibmxt_config @@ -1039,7 +1039,7 @@ static const device_t genericxt_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = genericxt_config @@ -1087,7 +1087,7 @@ static const device_t msramcard_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = msramcard_config @@ -1135,7 +1135,7 @@ static const device_t mssystemcard_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = mssystemcard_config @@ -1149,7 +1149,7 @@ static const device_t ibmat_128k_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1197,7 +1197,7 @@ static const device_t ibmat_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ibmat_config @@ -1245,7 +1245,7 @@ static const device_t genericat_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = genericat_config @@ -1293,7 +1293,7 @@ static const device_t p5pak_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = p5pak_config @@ -1341,7 +1341,7 @@ static const device_t a6pak_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = a6pak_config @@ -1392,7 +1392,7 @@ static const device_t ems5150_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ems5150_config @@ -1534,7 +1534,7 @@ static const device_t ev159_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ev159_config @@ -1629,7 +1629,7 @@ static const device_t ev165a_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ev165a_config @@ -1693,7 +1693,7 @@ static const device_t brxt_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = brxt_config @@ -1799,7 +1799,7 @@ static const device_t brat_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = brat_config @@ -1865,7 +1865,7 @@ static const device_t lotech_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = lotech_config @@ -1934,7 +1934,7 @@ static const device_t rampage_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = rampage_config @@ -2033,7 +2033,7 @@ static const device_t iab_device = { .init = isamem_init, .close = isamem_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = iab_config diff --git a/src/device/isapnp.c b/src/device/isapnp.c index f69c69612..479b6b9b2 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -1231,7 +1231,7 @@ static const device_t isapnp_device = { .init = isapnp_init, .close = isapnp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 74be59017..aef3b2cc6 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2417,7 +2417,7 @@ const device_t keyboard_at_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2431,7 +2431,7 @@ const device_t keyboard_at_siemens_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2445,7 +2445,7 @@ const device_t keyboard_at_ami_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2459,7 +2459,7 @@ const device_t keyboard_at_tg_ami_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2473,7 +2473,7 @@ const device_t keyboard_at_toshiba_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2487,7 +2487,7 @@ const device_t keyboard_at_olivetti_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2501,7 +2501,7 @@ const device_t keyboard_at_ncr_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2515,7 +2515,7 @@ const device_t keyboard_at_compaq_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2529,7 +2529,7 @@ const device_t keyboard_ps2_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2543,7 +2543,7 @@ const device_t keyboard_ps2_ps1_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2557,7 +2557,7 @@ const device_t keyboard_ps2_ps1_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2571,7 +2571,7 @@ const device_t keyboard_ps2_xi8088_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2585,7 +2585,7 @@ const device_t keyboard_ps2_ami_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2599,7 +2599,7 @@ const device_t keyboard_ps2_holtek_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2613,7 +2613,7 @@ const device_t keyboard_ps2_phoenix_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2627,7 +2627,7 @@ const device_t keyboard_ps2_tg_ami_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2641,7 +2641,7 @@ const device_t keyboard_ps2_mca_1_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2655,7 +2655,7 @@ const device_t keyboard_ps2_mca_2_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2669,7 +2669,7 @@ const device_t keyboard_ps2_quadtel_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2683,7 +2683,7 @@ const device_t keyboard_ps2_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2697,7 +2697,7 @@ const device_t keyboard_ps2_ami_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2711,7 +2711,7 @@ const device_t keyboard_ps2_ali_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2725,7 +2725,7 @@ const device_t keyboard_ps2_intel_ami_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2739,7 +2739,7 @@ const device_t keyboard_ps2_tg_ami_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2753,7 +2753,7 @@ const device_t keyboard_ps2_acer_pci_device = { .init = kbc_at_init, .close = kbc_at_close, .reset = kbc_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index b90f4a77a..c614bad8c 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -1188,7 +1188,7 @@ const device_t keyboard_pc_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1202,7 +1202,7 @@ const device_t keyboard_pc82_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1216,7 +1216,7 @@ const device_t keyboard_pravetz_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1230,7 +1230,7 @@ const device_t keyboard_xt_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1244,7 +1244,7 @@ const device_t keyboard_xt86_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1258,7 +1258,7 @@ const device_t keyboard_xt_compaq_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1272,7 +1272,7 @@ const device_t keyboard_tandy_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1286,7 +1286,7 @@ const device_t keyboard_xt_t1x00_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1301,7 +1301,7 @@ const device_t keyboard_xt_lxt3_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1316,7 +1316,7 @@ const device_t keyboard_xt_olivetti_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1330,7 +1330,7 @@ const device_t keyboard_xt_zenith_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1344,7 +1344,7 @@ const device_t keyboard_xt_hyundai_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1358,7 +1358,7 @@ const device_t keyboard_xtclone_device = { .init = kbd_init, .close = kbd_close, .reset = kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index fdd58b404..9c0d8b02e 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -812,7 +812,7 @@ const device_t mouse_logibus_device = { .init = bm_init, .close = bm_close, .reset = NULL, - { .poll = bm_poll }, + .poll = bm_poll, .speed_changed = NULL, .force_redraw = NULL, .config = lt_config @@ -826,7 +826,7 @@ const device_t mouse_logibus_onboard_device = { .init = bm_init, .close = bm_close, .reset = NULL, - { .poll = bm_poll }, + .poll = bm_poll, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -840,7 +840,7 @@ const device_t mouse_msinport_device = { .init = bm_init, .close = bm_close, .reset = NULL, - { .poll = bm_poll }, + .poll = bm_poll, .speed_changed = NULL, .force_redraw = NULL, .config = ms_config diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index 442b25b91..c6bef89dc 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -599,7 +599,7 @@ const device_t mouse_mtouch_device = { .init = mtouch_init, .close = mtouch_close, .reset = NULL, - { .poll = mtouch_poll }, + .poll = mtouch_poll, .speed_changed = NULL, .force_redraw = NULL, .config = mtouch_config diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index e5f9dd410..53af97b78 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -396,7 +396,7 @@ const device_t mouse_ps2_device = { .init = mouse_ps2_init, .close = ps2_close, .reset = NULL, - { .poll = ps2_poll }, + .poll = ps2_poll, .speed_changed = NULL, .force_redraw = NULL, .config = ps2_config diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index fa3190536..99d08cd37 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -1061,7 +1061,7 @@ const device_t mouse_mssystems_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - { .poll = sermouse_poll }, + .poll = sermouse_poll, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = msssermouse_config @@ -1075,7 +1075,7 @@ const device_t mouse_msserial_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - { .poll = sermouse_poll }, + .poll = sermouse_poll, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = mssermouse_config @@ -1089,7 +1089,7 @@ const device_t mouse_ltserial_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - { .poll = sermouse_poll }, + .poll = sermouse_poll, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = ltsermouse_config diff --git a/src/device/mouse_wacom_tablet.c b/src/device/mouse_wacom_tablet.c index d299d8bab..d74e58411 100644 --- a/src/device/mouse_wacom_tablet.c +++ b/src/device/mouse_wacom_tablet.c @@ -720,7 +720,7 @@ const device_t mouse_wacom_device = { .init = wacom_init, .close = wacom_close, .reset = NULL, - { .poll = wacom_poll }, + .poll = wacom_poll, .speed_changed = wacom_speed_changed, .force_redraw = NULL, .config = wacom_config @@ -730,11 +730,11 @@ const device_t mouse_wacom_artpad_device = { .name = "Wacom ArtPad", .internal_name = "wacom_serial_artpad", .flags = DEVICE_COM, - .local = (uintptr_t)&artpad_id, + .local = (uintptr_t) &artpad_id, .init = wacom_init, .close = wacom_close, .reset = NULL, - { .poll = wacom_poll }, + .poll = wacom_poll, .speed_changed = wacom_speed_changed, .force_redraw = NULL, .config = wacom_config diff --git a/src/device/nec_mate_unk.c b/src/device/nec_mate_unk.c index 165962f30..3244733c9 100644 --- a/src/device/nec_mate_unk.c +++ b/src/device/nec_mate_unk.c @@ -68,7 +68,7 @@ const device_t nec_mate_unk_device = { .init = nec_mate_unk_init, .close = nec_mate_unk_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/novell_cardkey.c b/src/device/novell_cardkey.c index 4730b6bb4..737b4104d 100644 --- a/src/device/novell_cardkey.c +++ b/src/device/novell_cardkey.c @@ -116,7 +116,7 @@ const device_t novell_keycard_device = { .init = novell_cardkey_init, .close = novell_cardkey_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = keycard_config diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index c1f551162..4321bf433 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -542,7 +542,7 @@ const device_t dec21150_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -557,7 +557,7 @@ const device_t ali5243_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -572,7 +572,7 @@ const device_t ali5247_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -586,7 +586,7 @@ const device_t i440lx_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -600,7 +600,7 @@ const device_t i440bx_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -614,7 +614,7 @@ const device_t i440gx_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -628,7 +628,7 @@ const device_t via_vp3_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -642,7 +642,7 @@ const device_t via_mvp3_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -656,7 +656,7 @@ const device_t via_apro_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -670,7 +670,7 @@ const device_t via_vt8601_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -684,7 +684,7 @@ const device_t sis_5xxx_agp_device = { .init = pci_bridge_init, .close = NULL, .reset = pci_bridge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c index a3c891c90..6032a59dc 100644 --- a/src/device/phoenix_486_jumper.c +++ b/src/device/phoenix_486_jumper.c @@ -130,7 +130,7 @@ const device_t phoenix_486_jumper_device = { .init = phoenix_486_jumper_init, .close = phoenix_486_jumper_close, .reset = phoenix_486_jumper_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -144,7 +144,7 @@ const device_t phoenix_486_jumper_pci_device = { .init = phoenix_486_jumper_init, .close = phoenix_486_jumper_close, .reset = phoenix_486_jumper_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/postcard.c b/src/device/postcard.c index dbae3232a..9e2c629c1 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -187,7 +187,7 @@ const device_t postcard_device = { .init = postcard_init, .close = postcard_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/serial.c b/src/device/serial.c index dcaff0f7f..1e2618449 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -996,7 +996,7 @@ const device_t ns8250_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1010,7 +1010,7 @@ const device_t ns8250_pcjr_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1024,7 +1024,7 @@ const device_t ns16450_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1038,7 +1038,7 @@ const device_t ns16550_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1052,7 +1052,7 @@ const device_t ns16650_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1066,7 +1066,7 @@ const device_t ns16750_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1080,7 +1080,7 @@ const device_t ns16850_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL @@ -1094,7 +1094,7 @@ const device_t ns16950_device = { .init = serial_init, .close = serial_close, .reset = serial_reset, - { .available = NULL }, + .available = NULL, .speed_changed = serial_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index ed5abe618..445b67d04 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -370,13 +370,13 @@ static const device_config_t serial_passthrough_config[] = { // clang-format on const device_t serial_passthrough_device = { - .name = "Serial Passthrough Device", - .flags = 0, - .local = 0, - .init = serial_passthrough_dev_init, - .close = serial_passthrough_dev_close, - .reset = NULL, - { .poll = NULL }, + .name = "Serial Passthrough Device", + .flags = 0, + .local = 0, + .init = serial_passthrough_dev_init, + .close = serial_passthrough_dev_close, + .reset = NULL, + .poll = NULL, .speed_changed = serial_passthrough_speed_changed, .force_redraw = NULL, .config = serial_passthrough_config diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index 349de470d..de487ef73 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -307,7 +307,7 @@ const device_t ali7101_smbus_device = { .init = smbus_ali7101_init, .close = smbus_ali7101_close, .reset = smbus_ali7101_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index 6f2b1632e..d72712cc6 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -392,7 +392,7 @@ const device_t piix4_smbus_device = { .init = smbus_piix4_init, .close = smbus_piix4_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -406,7 +406,7 @@ const device_t via_smbus_device = { .init = smbus_piix4_init, .close = smbus_piix4_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/smbus_sis5595.c b/src/device/smbus_sis5595.c index 191e7a6a5..e7cffc577 100644 --- a/src/device/smbus_sis5595.c +++ b/src/device/smbus_sis5595.c @@ -379,7 +379,7 @@ const device_t sis5595_smbus_device = { .init = smbus_sis5595_init, .close = smbus_sis5595_close, .reset = smbus_sis5595_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/unittester.c b/src/device/unittester.c index 614438fcb..5f0fa5712 100644 --- a/src/device/unittester.c +++ b/src/device/unittester.c @@ -115,12 +115,16 @@ static struct unittester_state unittester_defaults = { }; static const device_config_t unittester_config[] = { - { .name = "exit_enabled", - .description = "Enable 0x04 \"Exit 86Box\" command", - .type = CONFIG_BINARY, - .default_int = 1, - .default_string = "" }, - { .type = CONFIG_END } +// clang-format off + { + .name = "exit_enabled", + .description = "Enable 0x04 \"Exit 86Box\" command", + .type = CONFIG_BINARY, + .default_int = 1, + .default_string = "" + }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on }; /* Kept separate, as we will be reusing this object */ @@ -628,7 +632,7 @@ const device_t unittester_device = { .init = unittester_init, .close = unittester_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = unittester_config, diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 82314e6db..d9dc02da0 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -990,7 +990,7 @@ const device_t esdi_at_wd1007vse1_device = { .init = wd1007vse1_init, .close = wd1007vse1_close, .reset = NULL, - { .available = wd1007vse1_available }, + .available = wd1007vse1_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 539684b81..83d2dc3b7 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1342,7 +1342,7 @@ const device_t esdi_ps2_device = { .init = esdi_init, .close = esdi_close, .reset = NULL, - { .available = esdi_available }, + .available = esdi_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3af561989..49d23daee 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3269,7 +3269,7 @@ const device_t ide_isa_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3283,7 +3283,7 @@ const device_t ide_isa_2ch_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3297,7 +3297,7 @@ const device_t ide_vlb_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3311,7 +3311,7 @@ const device_t ide_vlb_2ch_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3325,7 +3325,7 @@ const device_t ide_pci_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3339,7 +3339,7 @@ const device_t ide_pci_2ch_device = { .init = ide_init, .close = ide_close, .reset = ide_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3353,7 +3353,7 @@ const device_t mcide_device = { .init = mcide_init, .close = mcide_close, .reset = mcide_reset, - { .available = mcide_available }, + .available = mcide_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3422,7 +3422,7 @@ const device_t ide_ter_device = { .init = ide_ter_init, .close = ide_ter_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ide_ter_config @@ -3436,7 +3436,7 @@ const device_t ide_ter_pnp_device = { .init = ide_ter_init, .close = ide_ter_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -3450,7 +3450,7 @@ const device_t ide_qua_device = { .init = ide_qua_init, .close = ide_qua_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ide_qua_config @@ -3464,7 +3464,7 @@ const device_t ide_qua_pnp_device = { .init = ide_qua_init, .close = ide_qua_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_ali5213.c b/src/disk/hdc_ide_ali5213.c index 8ff3d392c..67f959e1a 100644 --- a/src/disk/hdc_ide_ali5213.c +++ b/src/disk/hdc_ide_ali5213.c @@ -246,7 +246,7 @@ const device_t ide_ali1489_device = { .init = ali5213_init, .close = ali5213_close, .reset = ali5213_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -260,7 +260,7 @@ const device_t ide_ali5213_device = { .init = ali5213_init, .close = ali5213_close, .reset = ali5213_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_cmd640.c b/src/disk/hdc_ide_cmd640.c index 3e77730a2..9c0178a47 100644 --- a/src/disk/hdc_ide_cmd640.c +++ b/src/disk/hdc_ide_cmd640.c @@ -563,7 +563,7 @@ const device_t ide_cmd640_vlb_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -577,7 +577,7 @@ const device_t ide_cmd640_vlb_178_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -591,7 +591,7 @@ const device_t ide_cmd640_vlb_pri_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -605,7 +605,7 @@ const device_t ide_cmd640_vlb_pri_178_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -619,7 +619,7 @@ const device_t ide_cmd640_vlb_sec_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -633,7 +633,7 @@ const device_t ide_cmd640_vlb_sec_178_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -647,7 +647,7 @@ const device_t ide_cmd640_pci_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -661,7 +661,7 @@ const device_t ide_cmd640_pci_legacy_only_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -675,7 +675,7 @@ const device_t ide_cmd640_pci_single_channel_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -689,7 +689,7 @@ const device_t ide_cmd640_pci_single_channel_sec_device = { .init = cmd640_init, .close = cmd640_close, .reset = cmd640_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c index 8367b9a41..b79f84f03 100644 --- a/src/disk/hdc_ide_cmd646.c +++ b/src/disk/hdc_ide_cmd646.c @@ -431,7 +431,7 @@ const device_t ide_cmd646_device = { .init = cmd646_init, .close = cmd646_close, .reset = cmd646_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -445,7 +445,7 @@ const device_t ide_cmd646_legacy_only_device = { .init = cmd646_init, .close = cmd646_close, .reset = cmd646_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -459,7 +459,7 @@ const device_t ide_cmd646_single_channel_device = { .init = cmd646_init, .close = cmd646_close, .reset = cmd646_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_opti611.c b/src/disk/hdc_ide_opti611.c index 480331201..67cdfc779 100644 --- a/src/disk/hdc_ide_opti611.c +++ b/src/disk/hdc_ide_opti611.c @@ -341,7 +341,7 @@ const device_t ide_opti611_vlb_device = { .init = opti611_init, .close = opti611_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -355,7 +355,7 @@ const device_t ide_opti611_vlb_sec_device = { .init = opti611_init, .close = opti611_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 3b8da3f2e..ec4c7228c 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -611,7 +611,7 @@ const device_t sff8038i_device = { .init = sff_init, .close = sff_close, .reset = sff_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_um8673f.c b/src/disk/hdc_ide_um8673f.c index bc046dd26..b40595750 100644 --- a/src/disk/hdc_ide_um8673f.c +++ b/src/disk/hdc_ide_um8673f.c @@ -191,7 +191,7 @@ const device_t ide_um8886af_device = { .init = um8673f_init, .close = um8673f_close, .reset = um8673f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -205,7 +205,7 @@ const device_t ide_um8673f_device = { .init = um8673f_init, .close = um8673f_close, .reset = um8673f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_ide_w83769f.c b/src/disk/hdc_ide_w83769f.c index 608d7a8a7..897a26593 100644 --- a/src/disk/hdc_ide_w83769f.c +++ b/src/disk/hdc_ide_w83769f.c @@ -410,7 +410,7 @@ const device_t ide_w83769f_vlb_device = { .init = w83769f_init, .close = w83769f_close, .reset = w83769f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -424,7 +424,7 @@ const device_t ide_w83769f_vlb_34_device = { .init = w83769f_init, .close = w83769f_close, .reset = w83769f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -438,7 +438,7 @@ const device_t ide_w83769f_pci_device = { .init = w83769f_init, .close = w83769f_close, .reset = w83769f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -452,7 +452,7 @@ const device_t ide_w83769f_pci_34_device = { .init = w83769f_init, .close = w83769f_close, .reset = w83769f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -466,9 +466,8 @@ const device_t ide_w83769f_pci_single_channel_device = { .init = w83769f_init, .close = w83769f_close, .reset = w83769f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL }; - diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index 8cc5fe20a..abd379646 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -801,7 +801,7 @@ const device_t st506_at_wd1003_device = { .init = mfm_init, .close = mfm_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index 5d310e96b..d950fbe34 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -2258,7 +2258,7 @@ const device_t st506_xt_xebec_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = xebec_available }, + .available = xebec_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2272,7 +2272,7 @@ const device_t st506_xt_wdxt_gen_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wdxt_available }, + .available = wdxt_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2286,7 +2286,7 @@ const device_t st506_xt_dtc5150x_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = dtc5150x_available }, + .available = dtc5150x_available, .speed_changed = NULL, .force_redraw = NULL, .config = dtc_config @@ -2300,7 +2300,7 @@ const device_t st506_xt_st11_m_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = st11_m_available }, + .available = st11_m_available, .speed_changed = NULL, .force_redraw = NULL, .config = st11_config @@ -2314,7 +2314,7 @@ const device_t st506_xt_st11_r_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = st11_r_available }, + .available = st11_r_available, .speed_changed = NULL, .force_redraw = NULL, .config = st11_config @@ -2328,7 +2328,7 @@ const device_t st506_xt_wd1002a_wx1_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1002a_wx1_available }, + .available = wd1002a_wx1_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd_config @@ -2342,7 +2342,7 @@ const device_t st506_xt_wd1002a_wx1_nobios_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1002a_wx1_available }, + .available = wd1002a_wx1_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd_nobios_config @@ -2356,7 +2356,7 @@ const device_t st506_xt_wd1002a_27x_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1002a_27x_available }, + .available = wd1002a_27x_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd_rll_config @@ -2370,7 +2370,7 @@ const device_t st506_xt_wd1004a_wx1_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1004a_wx1_available }, + .available = wd1004a_wx1_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd1004a_config @@ -2384,7 +2384,7 @@ const device_t st506_xt_wd1004_27x_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1004_27x_available }, + .available = wd1004_27x_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd1004_rll_config @@ -2398,7 +2398,7 @@ const device_t st506_xt_wd1004a_27x_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = wd1004a_27x_available }, + .available = wd1004a_27x_available, .speed_changed = NULL, .force_redraw = NULL, .config = wd_rll_config @@ -2412,7 +2412,7 @@ const device_t st506_xt_victor_v86p_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = victor_v86p_available }, + .available = victor_v86p_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2426,7 +2426,7 @@ const device_t st506_xt_toshiba_t1200_device = { .init = st506_init, .close = st506_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 91bdd709d..1ddbd33e2 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1170,29 +1170,29 @@ static const device_config_t wdxt150_config[] = { }; const device_t xta_wdxt150_device = { - .name = "WDXT-150 XTA Fixed Disk Controller", + .name = "WDXT-150 XTA Fixed Disk Controller", .internal_name = "xta_wdxt150", - .flags = DEVICE_ISA, - .local = 0, - .init = xta_init, - .close = xta_close, - .reset = NULL, - { .available = NULL /*xta_available*/ }, + .flags = DEVICE_ISA, + .local = 0, + .init = xta_init, + .close = xta_close, + .reset = NULL, + .available = NULL /*xta_available*/, .speed_changed = NULL, - .force_redraw = NULL, - .config = wdxt150_config + .force_redraw = NULL, + .config = wdxt150_config }; const device_t xta_hd20_device = { - .name = "EuroPC HD20 Fixed Disk Controller", + .name = "EuroPC HD20 Fixed Disk Controller", .internal_name = "xta_hd20", - .flags = DEVICE_ISA, - .local = 1, - .init = xta_init, - .close = xta_close, - .reset = NULL, - { .available = NULL }, + .flags = DEVICE_ISA, + .local = 1, + .init = xta_init, + .close = xta_close, + .reset = NULL, + .available = NULL, .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL + .force_redraw = NULL, + .config = NULL }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index b324b4d32..623f68cb5 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -281,7 +281,7 @@ const device_t xtide_device = { .init = xtide_init, .close = xtide_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = xtide_config @@ -295,7 +295,7 @@ const device_t xtide_at_device = { .init = xtide_at_init, .close = xtide_at_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = xtide_at_config @@ -309,7 +309,7 @@ const device_t xtide_acculogic_device = { .init = xtide_acculogic_init, .close = xtide_close, .reset = NULL, - { .available = xtide_acculogic_available }, + .available = xtide_acculogic_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -323,7 +323,7 @@ const device_t xtide_at_ps2_device = { .init = xtide_at_ps2_init, .close = xtide_at_close, .reset = NULL, - { .available = xtide_at_ps2_available }, + .available = xtide_at_ps2_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/disk/lba_enhancer.c b/src/disk/lba_enhancer.c index 35c845c16..c7f3fd969 100644 --- a/src/disk/lba_enhancer.c +++ b/src/disk/lba_enhancer.c @@ -92,7 +92,7 @@ const device_t lba_enhancer_device = { .init = lba_enhancer_init, .close = lba_enhancer_close, .reset = NULL, - { .available = lba_enhancer_available }, + .available = lba_enhancer_available, .speed_changed = NULL, .force_redraw = NULL, .config = lba_enhancer_config diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 4cb2a8491..5c377f95f 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -2371,7 +2371,7 @@ const device_t fdc_xt_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2385,7 +2385,7 @@ const device_t fdc_xt_sec_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2399,7 +2399,7 @@ const device_t fdc_xt_ter_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2413,7 +2413,7 @@ const device_t fdc_xt_qua_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2427,7 +2427,7 @@ const device_t fdc_xt_t1x00_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2441,7 +2441,7 @@ const device_t fdc_xt_amstrad_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2455,7 +2455,7 @@ const device_t fdc_xt_tandy_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2469,7 +2469,7 @@ const device_t fdc_xt_umc_um8398_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2483,7 +2483,7 @@ const device_t fdc_pcjr_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2497,7 +2497,7 @@ const device_t fdc_at_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2511,7 +2511,7 @@ const device_t fdc_at_sec_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2525,7 +2525,7 @@ const device_t fdc_at_ter_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2539,7 +2539,7 @@ const device_t fdc_at_qua_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2553,7 +2553,7 @@ const device_t fdc_at_actlow_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2567,7 +2567,7 @@ const device_t fdc_at_smc_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2581,7 +2581,7 @@ const device_t fdc_at_ali_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2595,7 +2595,7 @@ const device_t fdc_at_winbond_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2609,7 +2609,7 @@ const device_t fdc_at_nsc_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2623,7 +2623,7 @@ const device_t fdc_at_nsc_dp8473_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2638,7 +2638,7 @@ const device_t fdc_ps2_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2653,7 +2653,7 @@ const device_t fdc_ps2_mca_device = { .init = fdc_init, .close = fdc_close, .reset = fdc_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/floppy/fdc_magitronic.c b/src/floppy/fdc_magitronic.c index 306440b9c..09b766d6c 100644 --- a/src/floppy/fdc_magitronic.c +++ b/src/floppy/fdc_magitronic.c @@ -135,7 +135,7 @@ const device_t fdc_b215_device = { .init = b215_init, .close = b215_close, .reset = NULL, - { .available = b215_available }, + .available = b215_available, .speed_changed = NULL, .force_redraw = NULL, .config = b215_config diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 00b6d37f5..bb210fb44 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -286,7 +286,7 @@ const device_t fdc_monster_device = { .init = monster_fdc_init, .close = monster_fdc_close, .reset = NULL, - { .available = monster_fdc_available }, + .available = monster_fdc_available, .speed_changed = NULL, .force_redraw = NULL, .config = monster_fdc_config diff --git a/src/floppy/fdc_pii15xb.c b/src/floppy/fdc_pii15xb.c index 013d6d39b..6a8bbbd43 100644 --- a/src/floppy/fdc_pii15xb.c +++ b/src/floppy/fdc_pii15xb.c @@ -150,7 +150,7 @@ const device_t fdc_pii151b_device = { .init = pii_init, .close = pii_close, .reset = NULL, - { .available = pii_151b_available }, + .available = pii_151b_available, .speed_changed = NULL, .force_redraw = NULL, .config = pii_config @@ -164,7 +164,7 @@ const device_t fdc_pii158b_device = { .init = pii_init, .close = pii_close, .reset = NULL, - { .available = pii_158_available }, + .available = pii_158_available, .speed_changed = NULL, .force_redraw = NULL, .config = pii_config diff --git a/src/game/gameport.c b/src/game/gameport.c index ae2135a39..0b2a641bc 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -478,7 +478,7 @@ const device_t gameport_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -492,7 +492,7 @@ const device_t gameport_201_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -506,7 +506,7 @@ const device_t gameport_203_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -520,7 +520,7 @@ const device_t gameport_205_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -534,7 +534,7 @@ const device_t gameport_207_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -548,7 +548,7 @@ const device_t gameport_208_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -562,7 +562,7 @@ const device_t gameport_209_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -576,7 +576,7 @@ const device_t gameport_20b_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -590,7 +590,7 @@ const device_t gameport_20d_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -604,7 +604,7 @@ const device_t gameport_20f_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -658,7 +658,7 @@ const device_t gameport_tm_acm_device = { .init = tmacm_init, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = tmacm_config @@ -672,7 +672,7 @@ const device_t gameport_pnp_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -686,7 +686,7 @@ const device_t gameport_pnp_1io_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -700,7 +700,7 @@ const device_t gameport_pnp_6io_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -714,7 +714,7 @@ const device_t gameport_sio_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -728,7 +728,7 @@ const device_t gameport_sio_1io_device = { .init = gameport_init, .close = gameport_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/ioapic.c b/src/ioapic.c index c3939f249..b5ca4c7a7 100644 --- a/src/ioapic.c +++ b/src/ioapic.c @@ -122,7 +122,7 @@ const device_t ioapic_device = { .init = ioapic_init, .close = ioapic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 530362b89..891f02e84 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -726,7 +726,7 @@ const device_t vid_1512_device = { .init = NULL, .close = vid_close_1512, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_change_1512, .force_redraw = NULL, .config = vid_1512_config @@ -906,7 +906,7 @@ const device_t vid_1640_device = { .init = NULL, .close = vid_close_1640, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed_1640, .force_redraw = NULL, .config = vid_1640_config @@ -1831,7 +1831,7 @@ const device_t vid_200_device = { .init = NULL, .close = vid_close_200, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed_200, .force_redraw = NULL, .config = vid_200_config @@ -1931,7 +1931,7 @@ const device_t vid_ppc512_device = { .init = NULL, .close = vid_close_200, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed_200, .force_redraw = NULL, .config = vid_ppc512_config @@ -1965,7 +1965,7 @@ const device_t vid_pc2086_device = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = vid_pc2086_config @@ -1999,7 +1999,7 @@ const device_t vid_pc3086_device = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = vid_pc3086_config diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 0ac541e90..3b9462f90 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -714,7 +714,7 @@ const device_t compaq_plasma_device = { .init = compaq_plasma_init, .close = compaq_plasma_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = compaq_plasma_speed_changed, .force_redraw = NULL, .config = compaq_plasma_config diff --git a/src/machine/m_at_grid.c b/src/machine/m_at_grid.c index 2fc757129..443607382 100644 --- a/src/machine/m_at_grid.c +++ b/src/machine/m_at_grid.c @@ -324,7 +324,7 @@ const device_t grid_device = { .init = grid_init, .close = grid_close, .reset = grid_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index 50c9ec05a..80af959af 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -711,7 +711,7 @@ const device_t t3100e_device = { .init = t3100e_init, .close = t3100e_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = t3100e_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 42034e2f6..b98a1f51e 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -703,7 +703,7 @@ const device_t europc_device = { .init = europc_boot, .close = europc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = europc_config diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 16020826d..847053bdb 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -1513,7 +1513,7 @@ const device_t pcjr_device = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = speed_changed, .force_redraw = NULL, .config = pcjr_config diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 3c9f1819f..8b2a096c7 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -287,7 +287,7 @@ const device_t ps1_2011_device = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = &ps1_2011_config[0] diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index e3f6428a7..06c7a2c95 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -1386,7 +1386,7 @@ const device_t ps1_hdc_device = { .init = ps1_hdc_init, .close = ps1_hdc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 11bd41a66..8e46c6154 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -1416,7 +1416,7 @@ const device_t vid_device = { .init = NULL, .close = vid_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed, .force_redraw = NULL, .config = vid_config @@ -1430,7 +1430,7 @@ const device_t vid_device_hx = { .init = NULL, .close = vid_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed, .force_redraw = NULL, .config = vid_config @@ -1444,7 +1444,7 @@ const device_t vid_device_sl = { .init = NULL, .close = vid_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed, .force_redraw = NULL, .config = NULL @@ -1592,7 +1592,7 @@ static const device_t eep_1000hx_device = { .init = eep_init, .close = eep_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1606,7 +1606,7 @@ static const device_t eep_1000sl2_device = { .init = eep_init, .close = eep_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 817b0d0cc..3b907f4df 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -2075,7 +2075,7 @@ const device_t m24_kbd_device = { .init = NULL, .close = m24_kbd_close, .reset = m24_kbd_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2119,7 +2119,7 @@ const device_t m19_vid_device = { .init = NULL, .close = m19_vid_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = m19_vid_speed_changed, .force_redraw = NULL, .config = m19_vid_config diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c index 1fc284a46..604ccebaf 100644 --- a/src/machine/m_xt_philips.c +++ b/src/machine/m_xt_philips.c @@ -142,7 +142,7 @@ const device_t philips_device = { .init = philips_init, .close = philips_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 4ec13b5c4..0d1ba714b 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -741,7 +741,7 @@ const device_t t1000_video_device = { .init = t1000_init, .close = t1000_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = t1000_speed_changed, .force_redraw = NULL, .config = t1000_config @@ -755,7 +755,7 @@ const device_t t1200_video_device = { .init = t1000_init, .close = t1000_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = t1000_speed_changed, .force_redraw = NULL, .config = t1000_config diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index 9b55dc021..886c1be6e 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -168,7 +168,7 @@ const device_t xi8088_device = { .init = xi8088_init, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = xi8088_config diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index f5e231772..776e10c9f 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -103,7 +103,7 @@ static const device_t zenith_scratchpad_device = { .init = zenith_scratchpad_init, .close = zenith_scratchpad_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c index 7cd40e9d7..4bb9b585a 100644 --- a/src/mem/catalyst_flash.c +++ b/src/mem/catalyst_flash.c @@ -240,7 +240,7 @@ const device_t catalyst_flash_device = { .init = catalyst_flash_init, .close = catalyst_flash_close, .reset = catalyst_flash_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index 7949f302a..56a7ad0e0 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -564,7 +564,7 @@ const device_t intel_flash_bxt_ami_device = { .init = intel_flash_init, .close = intel_flash_close, .reset = intel_flash_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -578,7 +578,7 @@ const device_t intel_flash_bxt_device = { .init = intel_flash_init, .close = intel_flash_close, .reset = intel_flash_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -592,7 +592,7 @@ const device_t intel_flash_bxb_device = { .init = intel_flash_init, .close = intel_flash_close, .reset = intel_flash_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/mem/row.c b/src/mem/row.c index ccd0325a4..633d0e31a 100644 --- a/src/mem/row.c +++ b/src/mem/row.c @@ -334,15 +334,15 @@ row_init(const device_t *info) /* NOTE: NOT const, so that we can patch it at init. */ device_t row_device = { - .name = "DRAM Rows", + .name = "DRAM Rows", .internal_name = "dram_rows", - .flags = DEVICE_AT, - .local = 0x0000, - .init = row_init, - .close = row_close, - .reset = row_reset, - { .available = NULL }, + .flags = DEVICE_AT, + .local = 0x0000, + .init = row_init, + .close = row_close, + .reset = row_reset, + .available = NULL, .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL + .force_redraw = NULL, + .config = NULL }; diff --git a/src/mem/spd.c b/src/mem/spd.c index a0896a05a..fee9b0b11 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -595,7 +595,7 @@ static const device_t spd_device = { .init = spd_init, .close = spd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index cd6ec7cd9..3dce35444 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -576,7 +576,7 @@ const device_t sst_flash_29ee010_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -590,7 +590,7 @@ const device_t sst_flash_29ee020_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -604,7 +604,7 @@ const device_t winbond_flash_w29c512_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -618,7 +618,7 @@ const device_t winbond_flash_w29c010_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -632,7 +632,7 @@ const device_t winbond_flash_w29c020_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -646,7 +646,7 @@ const device_t winbond_flash_w29c040_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -660,7 +660,7 @@ const device_t sst_flash_39sf512_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -674,7 +674,7 @@ const device_t sst_flash_39sf010_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -688,7 +688,7 @@ const device_t sst_flash_39sf020_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -702,7 +702,7 @@ const device_t sst_flash_39sf040_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -716,7 +716,7 @@ const device_t sst_flash_39lf512_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -730,7 +730,7 @@ const device_t sst_flash_39lf010_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -744,7 +744,7 @@ const device_t sst_flash_39lf020_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -758,7 +758,7 @@ const device_t sst_flash_39lf040_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -772,7 +772,7 @@ const device_t sst_flash_39lf080_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -786,7 +786,7 @@ const device_t sst_flash_39lf016_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -808,7 +808,7 @@ const device_t sst_flash_49lf002_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -822,7 +822,7 @@ const device_t sst_flash_49lf020_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -836,7 +836,7 @@ const device_t sst_flash_49lf020a_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -850,7 +850,7 @@ const device_t sst_flash_49lf003_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -864,7 +864,7 @@ const device_t sst_flash_49lf030_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -878,7 +878,7 @@ const device_t sst_flash_49lf004_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -892,7 +892,7 @@ const device_t sst_flash_49lf004c_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -906,7 +906,7 @@ const device_t sst_flash_49lf040_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -920,7 +920,7 @@ const device_t sst_flash_49lf008_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -934,7 +934,7 @@ const device_t sst_flash_49lf008c_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -948,7 +948,7 @@ const device_t sst_flash_49lf080_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -962,7 +962,7 @@ const device_t sst_flash_49lf016_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -977,7 +977,7 @@ const device_t sst_flash_49lf160_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -991,7 +991,7 @@ const device_t amd_flash_29f020a_device = { .init = sst_init, .close = sst_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/network/net_3c501.c b/src/network/net_3c501.c index 2cafb1d46..21d71d75e 100644 --- a/src/network/net_3c501.c +++ b/src/network/net_3c501.c @@ -1222,7 +1222,7 @@ const device_t threec501_device = { .init = threec501_nic_init, .close = threec501_nic_close, .reset = elnkR3Reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = threec501_config diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index 6191c02bf..f96e76a11 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -739,15 +739,15 @@ static const device_config_t threec503_config[] = { }; const device_t threec503_device = { - .name = "3Com EtherLink II", + .name = "3Com EtherLink II", .internal_name = "3c503", - .flags = DEVICE_ISA, - .local = 0, - .init = threec503_nic_init, - .close = threec503_nic_close, - .reset = NULL, - { .available = NULL }, + .flags = DEVICE_ISA, + .local = 0, + .init = threec503_nic_init, + .close = threec503_nic_close, + .reset = NULL, + .available = NULL, .speed_changed = NULL, - .force_redraw = NULL, - .config = threec503_config + .force_redraw = NULL, + .config = threec503_config }; diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index d6062604f..297e11424 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -1047,7 +1047,7 @@ const device_t dp8390_device = { .init = dp8390_init, .close = dp8390_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/network/net_eeprom_nmc93cxx.c b/src/network/net_eeprom_nmc93cxx.c index 3ad6bd030..b4fdce1e6 100644 --- a/src/network/net_eeprom_nmc93cxx.c +++ b/src/network/net_eeprom_nmc93cxx.c @@ -277,7 +277,7 @@ const device_t nmc93cxx_device = { .init = nmc93cxx_eeprom_init, .close = nmc93cxx_eeprom_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/network/net_modem.c b/src/network/net_modem.c index bb312ec31..732190254 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1608,7 +1608,7 @@ const device_t modem_device = { .init = modem_init, .close = modem_close, .reset = NULL, - { .poll = NULL }, + .poll = NULL, .speed_changed = modem_speed_changed, .force_redraw = NULL, .config = modem_config diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 324154947..1f191e047 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1633,7 +1633,7 @@ const device_t ne1000_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ne1000_config @@ -1647,7 +1647,7 @@ const device_t ne1000_compat_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ne1000_compat_config @@ -1661,7 +1661,7 @@ const device_t ne2000_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ne2000_config @@ -1675,7 +1675,7 @@ const device_t ne2000_compat_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ne2000_compat_config @@ -1689,7 +1689,7 @@ const device_t ne2000_compat_8bit_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ne2000_compat_8bit_config @@ -1703,7 +1703,7 @@ const device_t ethernext_mc_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = mca_mac_config @@ -1717,7 +1717,7 @@ const device_t rtl8019as_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = rtl8019as_available }, + .available = rtl8019as_available, .speed_changed = NULL, .force_redraw = NULL, .config = rtl8019as_config @@ -1731,7 +1731,7 @@ const device_t de220p_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = de220p_available }, + .available = de220p_available, .speed_changed = NULL, .force_redraw = NULL, .config = rtl8019as_config @@ -1745,7 +1745,7 @@ const device_t rtl8029as_device = { .init = nic_init, .close = nic_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = rtl8029as_config diff --git a/src/network/net_null.c b/src/network/net_null.c index 6fb3f3440..6d5f68e46 100644 --- a/src/network/net_null.c +++ b/src/network/net_null.c @@ -218,8 +218,8 @@ net_null_close(void *priv) } const netdrv_t net_null_drv = { - &net_null_in_available, - &net_null_init, - &net_null_close, - NULL + .notify_in = &net_null_in_available, + .init = &net_null_init, + .close = &net_null_close, + .priv = NULL }; diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 852191c55..2af34d786 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -572,8 +572,8 @@ net_pcap_close(void *priv) } const netdrv_t net_pcap_drv = { - &net_pcap_in_available, - &net_pcap_init, - &net_pcap_close, - NULL + .notify_in = &net_pcap_in_available, + .init = &net_pcap_init, + .close = &net_pcap_close, + .priv = NULL }; diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index b1fca8feb..c9323e702 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -3220,7 +3220,7 @@ const device_t pcnet_am79c960_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_isa_config @@ -3234,7 +3234,7 @@ const device_t pcnet_am79c960_eb_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_isa_config @@ -3248,7 +3248,7 @@ const device_t pcnet_am79c960_vlb_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_vlb_config @@ -3262,7 +3262,7 @@ const device_t pcnet_am79c961_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_pci_config @@ -3276,7 +3276,7 @@ const device_t pcnet_am79c970a_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_pci_config @@ -3290,7 +3290,7 @@ const device_t pcnet_am79c973_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_pci_config @@ -3304,7 +3304,7 @@ const device_t pcnet_am79c973_onboard_device = { .init = pcnet_init, .close = pcnet_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = pcnet_pci_config diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 8b0bf460c..b1264b045 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -508,7 +508,7 @@ const device_t plip_device = { .init = plip_net_init, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index 0dac29a8c..b9b7fc957 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -3333,7 +3333,7 @@ const device_t rtl8139c_plus_device = { .init = nic_init, .close = nic_close, .reset = rtl8139_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = rtl8139c_config diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 92434973d..22fdc722d 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -544,7 +544,8 @@ net_slirp_close(void *priv) } const netdrv_t net_slirp_drv = { - &net_slirp_in_available, - &net_slirp_init, - &net_slirp_close + .notify_in = &net_slirp_in_available, + .init = &net_slirp_init, + .close = &net_slirp_close, + .priv = NULL }; diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index ca43b0844..af30c5505 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -1700,7 +1700,7 @@ const device_t dec_tulip_device = { .init = nic_init, .close = nic_close, .reset = tulip_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = dec_tulip_21143_config @@ -1714,7 +1714,7 @@ const device_t dec_tulip_21140_device = { .init = nic_init, .close = nic_close, .reset = tulip_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = dec_tulip_21140_config @@ -1728,7 +1728,7 @@ const device_t dec_tulip_21140_vpc_device = { .init = nic_init, .close = nic_close, .reset = tulip_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = dec_tulip_21140_config @@ -1742,7 +1742,7 @@ const device_t dec_tulip_21040_device = { .init = nic_init, .close = nic_close, .reset = tulip_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = dec_tulip_21143_config diff --git a/src/network/net_vde.c b/src/network/net_vde.c index d783c9c9d..4f8d5c21f 100644 --- a/src/network/net_vde.c +++ b/src/network/net_vde.c @@ -302,9 +302,9 @@ void *net_vde_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, c // VDE Driver structure //- const netdrv_t net_vde_drv = { - &net_vde_in_available, - &net_vde_init, - &net_vde_close, - NULL + .notify_in = &net_vde_in_available, + .init = &net_vde_init, + .close = &net_vde_close, + .priv = NULL }; diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 72a4b7fd0..d22b6076c 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -1084,7 +1084,7 @@ const device_t wd8003e_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = wd8003_config @@ -1098,7 +1098,7 @@ const device_t wd8003eb_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = wd8003eb_config @@ -1112,7 +1112,7 @@ const device_t wd8013ebt_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = wd8013_config @@ -1126,7 +1126,7 @@ const device_t wd8003eta_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = mca_mac_config @@ -1140,7 +1140,7 @@ const device_t wd8003ea_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = mca_mac_config @@ -1154,7 +1154,7 @@ const device_t wd8013epa_device = { .init = wd_init, .close = wd_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = wd8013epa_config diff --git a/src/nvr_at.c b/src/nvr_at.c index 9465839a7..147795f8e 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1224,7 +1224,7 @@ const device_t at_nvr_old_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1238,7 +1238,7 @@ const device_t at_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1252,7 +1252,7 @@ const device_t at_mb_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1266,7 +1266,7 @@ const device_t ps_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1280,7 +1280,7 @@ const device_t amstrad_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1294,7 +1294,7 @@ const device_t ibmat_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1308,7 +1308,7 @@ const device_t piix4_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1322,7 +1322,7 @@ const device_t ps_no_nmi_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1336,7 +1336,7 @@ const device_t amstrad_no_nmi_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1350,7 +1350,7 @@ const device_t ami_1992_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1364,7 +1364,7 @@ const device_t ami_1994_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1378,7 +1378,7 @@ const device_t ami_1995_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1392,7 +1392,7 @@ const device_t via_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1406,7 +1406,7 @@ const device_t p6rp4_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1420,7 +1420,7 @@ const device_t amstrad_megapc_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL @@ -1434,7 +1434,7 @@ const device_t elt_nvr_device = { .init = nvr_at_init, .close = nvr_at_close, .reset = nvr_at_reset, - { .available = NULL }, + .available = NULL, .speed_changed = nvr_at_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 67eaccc38..809083395 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -170,7 +170,7 @@ const device_t ps2_nvr_device = { .init = ps2_nvr_init, .close = ps2_nvr_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -184,7 +184,7 @@ const device_t ps2_nvr_55ls_device = { .init = ps2_nvr_init, .close = ps2_nvr_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/pci_dummy.c b/src/pci_dummy.c index 704f85d8c..bceb58c22 100644 --- a/src/pci_dummy.c +++ b/src/pci_dummy.c @@ -278,7 +278,7 @@ pci_dummy_card_init(UNUSED(const device_t *info)) { pci_dummy_t *dev = (pci_dummy_t *) calloc(1, sizeof(pci_dummy_t)); - pci_add_card(PCI_ADD_NORMAL, pci_dummy_pci_read, pci_dummy_pci_write, dev, &dev->pci_slot); + pci_add_card(PCI_ADD_NORMAL, pci_dummy_pci_read, pci_dummy_pci_write, dev, &dev->pci_slot); return dev; } @@ -291,7 +291,7 @@ const device_t pci_dummy_device = { .init = pci_dummy_card_init, .close = pci_dummy_close, .reset = pci_dummy_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/pit.c b/src/pit.c index 8b9f23a79..a283d1205 100644 --- a/src/pit.c +++ b/src/pit.c @@ -960,7 +960,7 @@ const device_t i8253_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pit_speed_changed, .force_redraw = NULL, .config = NULL @@ -974,7 +974,7 @@ const device_t i8253_ext_io_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -988,7 +988,7 @@ const device_t i8254_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pit_speed_changed, .force_redraw = NULL, .config = NULL @@ -1002,7 +1002,7 @@ const device_t i8254_sec_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pit_speed_changed, .force_redraw = NULL, .config = NULL @@ -1016,7 +1016,7 @@ const device_t i8254_ext_io_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1030,7 +1030,7 @@ const device_t i8254_ps2_device = { .init = pit_init, .close = pit_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pit_speed_changed, .force_redraw = NULL, .config = NULL @@ -1250,14 +1250,14 @@ pit_set_clock(uint32_t clock) } const pit_intf_t pit_classic_intf = { - &pit_read, - &pit_write, - &pit_ctr_get_count, - &pit_ctr_set_gate, - &pit_ctr_set_using_timer, - &pit_ctr_set_out_func, - &pit_ctr_set_load_func, - &ctr_clock, - &pit_set_pit_const, - NULL, + .read = &pit_read, + .write = &pit_write, + .get_count = &pit_ctr_get_count, + .set_gate = &pit_ctr_set_gate, + .set_using_timer = &pit_ctr_set_using_timer, + .set_out_func = &pit_ctr_set_out_func, + .set_load_func = &pit_ctr_set_load_func, + .ctr_clock = &ctr_clock, + .set_pit_const = &pit_set_pit_const, + .data = NULL, }; diff --git a/src/pit_fast.c b/src/pit_fast.c index 0d56a6616..b92b59f3c 100644 --- a/src/pit_fast.c +++ b/src/pit_fast.c @@ -751,7 +751,7 @@ const device_t i8253_fast_device = { .init = pitf_init, .close = pitf_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pitf_speed_changed, .force_redraw = NULL, .config = NULL @@ -765,7 +765,7 @@ const device_t i8254_fast_device = { .init = pitf_init, .close = pitf_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pitf_speed_changed, .force_redraw = NULL, .config = NULL @@ -779,7 +779,7 @@ const device_t i8254_sec_fast_device = { .init = pitf_init, .close = pitf_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pitf_speed_changed, .force_redraw = NULL, .config = NULL @@ -793,7 +793,7 @@ const device_t i8254_ext_io_fast_device = { .init = pitf_init, .close = pitf_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -807,21 +807,21 @@ const device_t i8254_ps2_fast_device = { .init = pitf_init, .close = pitf_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pitf_speed_changed, .force_redraw = NULL, .config = NULL }; const pit_intf_t pit_fast_intf = { - &pitf_read, - &pitf_write, - &pitf_ctr_get_count, - &pitf_ctr_set_gate, - &pitf_ctr_set_using_timer, - &pitf_ctr_set_out_func, - &pitf_ctr_set_load_func, - &pitf_ctr_clock, - &pitf_set_pit_const, - NULL, + .read = &pitf_read, + .write = &pitf_write, + .get_count = &pitf_ctr_get_count, + .set_gate = &pitf_ctr_set_gate, + .set_using_timer = &pitf_ctr_set_using_timer, + .set_out_func = &pitf_ctr_set_out_func, + .set_load_func = &pitf_ctr_set_load_func, + .ctr_clock = &pitf_ctr_clock, + .set_pit_const = &pitf_set_pit_const, + .data = NULL, }; diff --git a/src/port_6x.c b/src/port_6x.c index 971b92d28..b8183d651 100644 --- a/src/port_6x.c +++ b/src/port_6x.c @@ -212,7 +212,7 @@ const device_t port_6x_device = { .init = port_6x_init, .close = port_6x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -226,7 +226,7 @@ const device_t port_6x_xi8088_device = { .init = port_6x_init, .close = port_6x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -240,7 +240,7 @@ const device_t port_6x_ps2_device = { .init = port_6x_init, .close = port_6x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -254,7 +254,7 @@ const device_t port_6x_olivetti_device = { .init = port_6x_init, .close = port_6x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/port_92.c b/src/port_92.c index 18e60326c..d1a53a321 100644 --- a/src/port_92.c +++ b/src/port_92.c @@ -235,7 +235,7 @@ const device_t port_92_device = { .init = port_92_init, .close = port_92_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -249,7 +249,7 @@ const device_t port_92_key_device = { .init = port_92_init, .close = port_92_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -263,7 +263,7 @@ const device_t port_92_inv_device = { .init = port_92_init, .close = port_92_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -277,7 +277,7 @@ const device_t port_92_word_device = { .init = port_92_init, .close = port_92_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -291,7 +291,7 @@ const device_t port_92_pci_device = { .init = port_92_init, .close = port_92_close, .reset = port_92_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 937213b85..9e19e8524 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -1447,7 +1447,7 @@ const device_t aha154xa_device = { .init = aha_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = aha_154xb_config @@ -1461,7 +1461,7 @@ const device_t aha154xb_device = { .init = aha_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = aha_154xb_config @@ -1475,7 +1475,7 @@ const device_t aha154xc_device = { .init = aha_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = aha_154x_config @@ -1489,7 +1489,7 @@ const device_t aha154xcf_device = { .init = aha_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = aha_154xcf_config @@ -1503,7 +1503,7 @@ const device_t aha154xcp_device = { .init = aha_init, .close = aha1542cp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = aha_154xcp_config @@ -1517,7 +1517,7 @@ const device_t aha1640_device = { .init = aha_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index b0aeedfa4..6d95ce44a 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1870,7 +1870,7 @@ const device_t buslogic_542b_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1884,7 +1884,7 @@ const device_t buslogic_545s_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1898,7 +1898,7 @@ const device_t buslogic_542bh_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1912,7 +1912,7 @@ const device_t buslogic_545c_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1926,7 +1926,7 @@ const device_t buslogic_640a_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1940,7 +1940,7 @@ const device_t buslogic_445s_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1954,7 +1954,7 @@ const device_t buslogic_445c_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT_ISA_Config @@ -1968,7 +1968,7 @@ const device_t buslogic_958d_pci_device = { .init = buslogic_init, .close = x54x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = BT958D_Config diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index fcfda69e4..def001624 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -954,7 +954,7 @@ const device_t scsi_lcs6821n_device = { .init = ncr53c400_init, .close = ncr53c400_close, .reset = NULL, - { .available = lcs6821n_available }, + .available = lcs6821n_available, .speed_changed = NULL, .force_redraw = NULL, .config = ncr53c400_mmio_config @@ -968,7 +968,7 @@ const device_t scsi_rt1000b_device = { .init = ncr53c400_init, .close = ncr53c400_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = rt1000b_config @@ -982,7 +982,7 @@ const device_t scsi_rt1000mc_device = { .init = ncr53c400_init, .close = ncr53c400_close, .reset = NULL, - { .available = rt1000b_mc_available }, + .available = rt1000b_mc_available, .speed_changed = NULL, .force_redraw = NULL, .config = rt1000b_mc_config @@ -996,7 +996,7 @@ const device_t scsi_t130b_device = { .init = ncr53c400_init, .close = ncr53c400_close, .reset = NULL, - { .available = t130b_available }, + .available = t130b_available, .speed_changed = NULL, .force_redraw = NULL, .config = t130b_config @@ -1010,7 +1010,7 @@ const device_t scsi_ls2000_device = { .init = ncr53c400_init, .close = ncr53c400_close, .reset = NULL, - { .available = corel_ls2000_available }, + .available = corel_ls2000_available, .speed_changed = NULL, .force_redraw = NULL, .config = ncr53c400_mmio_config diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index 1425f468b..27542028a 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -2692,7 +2692,7 @@ const device_t ncr53c810_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2706,7 +2706,7 @@ const device_t ncr53c810_onboard_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2720,7 +2720,7 @@ const device_t ncr53c815_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, ncr53c8xx_pci_config @@ -2734,7 +2734,7 @@ const device_t ncr53c820_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2748,7 +2748,7 @@ const device_t ncr53c825a_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ncr53c8xx_pci_config @@ -2762,7 +2762,7 @@ const device_t ncr53c860_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ncr53c8xx_pci_config @@ -2776,7 +2776,7 @@ const device_t ncr53c875_pci_device = { .init = ncr53c8xx_init, .close = ncr53c8xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ncr53c8xx_pci_config diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c index c2e5c9168..e8f256bed 100644 --- a/src/scsi/scsi_pcscsi.c +++ b/src/scsi/scsi_pcscsi.c @@ -2482,7 +2482,7 @@ const device_t dc390_pci_device = { .init = dc390_init, .close = esp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = bios_enable_config @@ -2496,7 +2496,7 @@ const device_t am53c974_pci_device = { .init = dc390_init, .close = esp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -2510,7 +2510,7 @@ const device_t ncr53c90a_mca_device = { .init = ncr53c9x_mca_init, .close = esp_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index e308d0788..8be075833 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1257,7 +1257,7 @@ const device_t spock_device = { .init = spock_init, .close = spock_close, .reset = NULL, - { .available = spock_available }, + .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, .config = spock_rom_config @@ -1271,7 +1271,7 @@ const device_t tribble_device = { .init = spock_init, .close = spock_close, .reset = NULL, - { .available = spock_available }, + .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, .config = spock_rom_config diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 0d653469a..92de9d17b 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -608,7 +608,7 @@ const device_t scsi_t128_device = { .init = t128_init, .close = t128_close, .reset = NULL, - { .available = t128_available }, + .available = t128_available, .speed_changed = NULL, .force_redraw = NULL, .config = t128_config @@ -623,7 +623,7 @@ const device_t scsi_t228_device = { .init = t128_init, .close = t128_close, .reset = NULL, - { .available = t128_available }, + .available = t128_available, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -637,7 +637,7 @@ const device_t scsi_pas_device = { .init = t128_init, .close = t128_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c index cbe89c682..59349dcbe 100644 --- a/src/sio/sio_82091aa.c +++ b/src/sio/sio_82091aa.c @@ -290,7 +290,7 @@ const device_t i82091aa_device = { .init = i82091aa_init, .close = i82091aa_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -304,7 +304,7 @@ const device_t i82091aa_398_device = { .init = i82091aa_init, .close = i82091aa_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -318,7 +318,7 @@ const device_t i82091aa_ide_pri_device = { .init = i82091aa_init, .close = i82091aa_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -332,7 +332,7 @@ const device_t i82091aa_ide_device = { .init = i82091aa_init, .close = i82091aa_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_acc3221.c b/src/sio/sio_acc3221.c index 275d9ae2e..6fcac024c 100644 --- a/src/sio/sio_acc3221.c +++ b/src/sio/sio_acc3221.c @@ -477,7 +477,7 @@ const device_t acc3221_device = { .init = acc3221_init, .close = acc3221_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c index 78c585c11..ce250ff2b 100644 --- a/src/sio/sio_ali5123.c +++ b/src/sio/sio_ali5123.c @@ -492,7 +492,7 @@ const device_t ali5123_device = { .init = ali5123_init, .close = ali5123_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index 38faf3c2c..ae34730ac 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -110,7 +110,7 @@ const device_t sio_detect_device = { .init = sio_detect_init, .close = sio_detect_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_f82c710.c b/src/sio/sio_f82c710.c index d4afb11da..04dcf109a 100644 --- a/src/sio/sio_f82c710.c +++ b/src/sio/sio_f82c710.c @@ -393,7 +393,7 @@ const device_t f82c606_device = { .init = f82c710_init, .close = f82c710_close, .reset = f82c710_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -407,7 +407,7 @@ const device_t f82c710_device = { .init = f82c710_init, .close = f82c710_close, .reset = f82c710_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index 0cd686991..7f02026e5 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -364,7 +364,7 @@ const device_t fdc37c669_device = { .init = fdc37c669_init, .close = fdc37c669_close, .reset = fdc37c669_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -378,7 +378,7 @@ const device_t fdc37c669_370_device = { .init = fdc37c669_init, .close = fdc37c669_close, .reset = fdc37c669_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_fdc37c67x.c b/src/sio/sio_fdc37c67x.c index 871f3b1c8..bac4685f5 100644 --- a/src/sio/sio_fdc37c67x.c +++ b/src/sio/sio_fdc37c67x.c @@ -625,7 +625,7 @@ const device_t fdc37c67x_device = { .init = fdc37c67x_init, .close = fdc37c67x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index c1fb2c1a5..6340218b7 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -346,7 +346,7 @@ const device_t fdc37c651_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -360,7 +360,7 @@ const device_t fdc37c651_ide_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -374,7 +374,7 @@ const device_t fdc37c661_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -388,7 +388,7 @@ const device_t fdc37c661_ide_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -402,7 +402,7 @@ const device_t fdc37c661_ide_sec_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -416,7 +416,7 @@ const device_t fdc37c663_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -430,7 +430,7 @@ const device_t fdc37c663_ide_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -444,7 +444,7 @@ const device_t fdc37c665_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -458,7 +458,7 @@ const device_t fdc37c665_ide_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -472,7 +472,7 @@ const device_t fdc37c665_ide_pri_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -486,7 +486,7 @@ const device_t fdc37c665_ide_sec_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -500,7 +500,7 @@ const device_t fdc37c666_device = { .init = fdc37c6xx_init, .close = fdc37c6xx_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index a0152c34a..0279903c6 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -932,7 +932,7 @@ static const device_t access_bus_device = { .init = access_bus_init, .close = access_bus_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1014,7 +1014,7 @@ const device_t fdc37c931apm_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1028,7 +1028,7 @@ const device_t fdc37c931apm_compaq_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1042,7 +1042,7 @@ const device_t fdc37c932_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1056,7 +1056,7 @@ const device_t fdc37c932fr_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1070,7 +1070,7 @@ const device_t fdc37c932qf_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1084,7 +1084,7 @@ const device_t fdc37c935_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1098,7 +1098,7 @@ const device_t fdc37c935_370_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -1112,7 +1112,7 @@ const device_t fdc37c935_no_nvr_device = { .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_fdc37m60x.c b/src/sio/sio_fdc37m60x.c index 38a163538..aab4d8968 100644 --- a/src/sio/sio_fdc37m60x.c +++ b/src/sio/sio_fdc37m60x.c @@ -329,7 +329,7 @@ const device_t fdc37m60x_device = { .init = fdc37m60x_init, .close = fdc37m60x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -343,7 +343,7 @@ const device_t fdc37m60x_370_device = { .init = fdc37m60x_init, .close = fdc37m60x_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c index 00524863a..610d69197 100644 --- a/src/sio/sio_it86x1f.c +++ b/src/sio/sio_it86x1f.c @@ -844,7 +844,7 @@ const device_t it8661f_device = { .init = it86x1f_init, .close = it86x1f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -858,7 +858,7 @@ const device_t it8671f_device = { .init = it86x1f_init, .close = it86x1f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index ab7f8597e..b21c2d1fc 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -495,7 +495,7 @@ const device_t pc87306_device = { .init = pc87306_init, .close = pc87306_close, .reset = pc87306_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index cb772aa5b..1f84152f5 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -625,7 +625,7 @@ const device_t pc87307_device = { .init = pc87307_init, .close = pc87307_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -639,7 +639,7 @@ const device_t pc87307_15c_device = { .init = pc87307_init, .close = pc87307_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -653,7 +653,7 @@ const device_t pc87307_both_device = { .init = pc87307_init, .close = pc87307_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -667,7 +667,7 @@ const device_t pc97307_device = { .init = pc87307_init, .close = pc87307_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index d10cb3e0b..f445ee189 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -497,7 +497,7 @@ const device_t pc87309_device = { .init = pc87309_init, .close = pc87309_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -511,7 +511,7 @@ const device_t pc87309_15c_device = { .init = pc87309_init, .close = pc87309_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87310.c b/src/sio/sio_pc87310.c index 075b819ff..674db6364 100644 --- a/src/sio/sio_pc87310.c +++ b/src/sio/sio_pc87310.c @@ -309,7 +309,7 @@ const device_t pc87310_device = { .init = pc87310_init, .close = pc87310_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -323,7 +323,7 @@ const device_t pc87310_ide_device = { .init = pc87310_init, .close = pc87310_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -337,7 +337,7 @@ const device_t ali5105_device = { .init = pc87310_init, .close = pc87310_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87311.c b/src/sio/sio_pc87311.c index 9740753d1..f1b823e47 100644 --- a/src/sio/sio_pc87311.c +++ b/src/sio/sio_pc87311.c @@ -298,7 +298,7 @@ const device_t pc87311_device = { .init = pc87311_init, .close = pc87311_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -312,7 +312,7 @@ const device_t pc87311_ide_device = { .init = pc87311_init, .close = pc87311_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c index 5cbf9f694..494c6d8bb 100644 --- a/src/sio/sio_pc87332.c +++ b/src/sio/sio_pc87332.c @@ -354,7 +354,7 @@ const device_t pc87332_device = { .init = pc87332_init, .close = pc87332_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -368,7 +368,7 @@ const device_t pc87332_398_device = { .init = pc87332_init, .close = pc87332_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -382,7 +382,7 @@ const device_t pc87332_398_ide_device = { .init = pc87332_init, .close = pc87332_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -396,7 +396,7 @@ const device_t pc87332_398_ide_sec_device = { .init = pc87332_init, .close = pc87332_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -410,7 +410,7 @@ const device_t pc87332_398_ide_fdcon_device = { .init = pc87332_init, .close = pc87332_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_prime3b.c b/src/sio/sio_prime3b.c index c93630516..1633c844b 100644 --- a/src/sio/sio_prime3b.c +++ b/src/sio/sio_prime3b.c @@ -290,7 +290,7 @@ const device_t prime3b_device = { .init = prime3b_init, .close = prime3b_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -304,7 +304,7 @@ const device_t prime3b_ide_device = { .init = prime3b_init, .close = prime3b_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_prime3c.c b/src/sio/sio_prime3c.c index b19f861bf..68361d3e0 100644 --- a/src/sio/sio_prime3c.c +++ b/src/sio/sio_prime3c.c @@ -335,7 +335,7 @@ const device_t prime3c_device = { .init = prime3c_init, .close = prime3c_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -349,7 +349,7 @@ const device_t prime3c_ide_device = { .init = prime3c_init, .close = prime3c_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_um8663f.c b/src/sio/sio_um8663f.c index 7391b029f..79cb37da4 100644 --- a/src/sio/sio_um8663f.c +++ b/src/sio/sio_um8663f.c @@ -289,7 +289,7 @@ const device_t um8663af_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -303,7 +303,7 @@ const device_t um8663af_ide_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -317,7 +317,7 @@ const device_t um8663af_ide_sec_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -331,7 +331,7 @@ const device_t um8663bf_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -345,7 +345,7 @@ const device_t um8663bf_ide_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -359,7 +359,7 @@ const device_t um8663bf_ide_sec_device = { .init = um8663f_init, .close = um8663f_close, .reset = um8663f_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index 136b1add6..e3ef81e11 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -362,7 +362,7 @@ const device_t um8669f_device = { .init = um8669f_init, .close = um8669f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -376,7 +376,7 @@ const device_t um8669f_ide_device = { .init = um8669f_init, .close = um8669f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -390,7 +390,7 @@ const device_t um8669f_ide_sec_device = { .init = um8669f_init, .close = um8669f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_vl82c113.c b/src/sio/sio_vl82c113.c index 6a02ef359..ecfc7ba09 100644 --- a/src/sio/sio_vl82c113.c +++ b/src/sio/sio_vl82c113.c @@ -155,7 +155,7 @@ const device_t vl82c113_device = { .init = vl82c113_init, .close = vl82c113_close, .reset = vl82c113_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_vt82c686.c b/src/sio/sio_vt82c686.c index f22af07df..47b5e1c09 100644 --- a/src/sio/sio_vt82c686.c +++ b/src/sio/sio_vt82c686.c @@ -311,7 +311,7 @@ const device_t via_vt82c686_sio_device = { .init = vt82c686_init, .close = vt82c686_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_w83787f.c b/src/sio/sio_w83787f.c index 2e4b82059..69bdb1220 100644 --- a/src/sio/sio_w83787f.c +++ b/src/sio/sio_w83787f.c @@ -474,7 +474,7 @@ const device_t w83787f_88h_device = { .init = w83787f_init, .close = w83787f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -488,7 +488,7 @@ const device_t w83787f_device = { .init = w83787f_init, .close = w83787f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -502,7 +502,7 @@ const device_t w83787f_ide_device = { .init = w83787f_init, .close = w83787f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -516,7 +516,7 @@ const device_t w83787f_ide_en_device = { .init = w83787f_init, .close = w83787f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -530,7 +530,7 @@ const device_t w83787f_ide_sec_device = { .init = w83787f_init, .close = w83787f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_w83877f.c b/src/sio/sio_w83877f.c index c9a437630..a6ea6f4e4 100644 --- a/src/sio/sio_w83877f.c +++ b/src/sio/sio_w83877f.c @@ -467,7 +467,7 @@ const device_t w83877f_device = { .init = w83877f_init, .close = w83877f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -481,7 +481,7 @@ const device_t w83877f_president_device = { .init = w83877f_init, .close = w83877f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -495,7 +495,7 @@ const device_t w83877tf_device = { .init = w83877f_init, .close = w83877f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -509,7 +509,7 @@ const device_t w83877tf_acorp_device = { .init = w83877f_init, .close = w83877f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index 063f0ca69..7df0163a5 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -624,7 +624,7 @@ const device_t w83977f_device = { .init = w83977f_init, .close = w83977f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -638,7 +638,7 @@ const device_t w83977f_370_device = { .init = w83977f_init, .close = w83977f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -652,7 +652,7 @@ const device_t w83977tf_device = { .init = w83977f_init, .close = w83977f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -666,7 +666,7 @@ const device_t w83977ef_device = { .init = w83977f_init, .close = w83977f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -680,7 +680,7 @@ const device_t w83977ef_370_device = { .init = w83977f_init, .close = w83977f_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 2f4f5da14..692a53aa3 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -5913,7 +5913,7 @@ const device_t sb_16_pnp_device = { .init = sb_16_pnp_init, .close = sb_close, .reset = NULL, - .available = sb_16_pnp_noide_available, + .available = sb_16_pnp_noide_available, .speed_changed = sb_speed_changed, .force_redraw = NULL, .config = sb_16_pnp_config @@ -6039,7 +6039,7 @@ const device_t sb_awe64_device = { .init = sb_awe32_pnp_init, .close = sb_awe32_close, .reset = NULL, - .available = sb_awe64_noide_available, + .available = sb_awe64_noide_available, .speed_changed = sb_speed_changed, .force_redraw = NULL, .config = sb_awe64_config diff --git a/src/usb.c b/src/usb.c index 6bdc8e6c0..222062f4f 100644 --- a/src/usb.c +++ b/src/usb.c @@ -433,7 +433,7 @@ const device_t usb_device = { .init = usb_init, .close = usb_close, .reset = usb_reset, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/agpgart.c b/src/video/agpgart.c index b8ae2bdc8..bf1976b73 100644 --- a/src/video/agpgart.c +++ b/src/video/agpgart.c @@ -167,7 +167,7 @@ const device_t agpgart_device = { .init = agpgart_init, .close = agpgart_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 470642884..1c81e8166 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -4038,9 +4038,7 @@ static const device_config_t isa_ext8514_config[] = { { .description = "" } }, }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format off @@ -4083,9 +4081,7 @@ static const device_config_t mca_ext8514_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format off @@ -4097,7 +4093,7 @@ const device_t gen8514_isa_device = { .init = ibm8514_init, .close = ibm8514_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ibm8514_speed_changed, .force_redraw = ibm8514_force_redraw, .config = isa_ext8514_config @@ -4111,7 +4107,7 @@ const device_t ibm8514_mca_device = { .init = ibm8514_init, .close = ibm8514_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ibm8514_speed_changed, .force_redraw = ibm8514_force_redraw, .config = mca_ext8514_config diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index df41e5d3f..59688087f 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -347,9 +347,7 @@ static const device_config_t ati18800_wonder_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; const device_t ati18800_wonder_device = { @@ -360,7 +358,7 @@ const device_t ati18800_wonder_device = { .init = ati18800_init, .close = ati18800_close, .reset = NULL, - { .available = ati18800_wonder_available }, + .available = ati18800_wonder_available, .speed_changed = ati18800_speed_changed, .force_redraw = ati18800_force_redraw, .config = ati18800_wonder_config @@ -374,7 +372,7 @@ const device_t ati18800_vga88_device = { .init = ati18800_init, .close = ati18800_close, .reset = NULL, - { .available = ati18800_vga88_available }, + .available = ati18800_vga88_available, .speed_changed = ati18800_speed_changed, .force_redraw = ati18800_force_redraw, .config = NULL @@ -388,7 +386,7 @@ const device_t ati18800_device = { .init = ati18800_init, .close = ati18800_close, .reset = NULL, - { .available = ati18800_available }, + .available = ati18800_available, .speed_changed = ati18800_speed_changed, .force_redraw = ati18800_force_redraw, .config = NULL diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index b3cf8aad1..4c039d9e6 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -766,9 +766,7 @@ static const device_config_t ati28800_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; #ifdef USE_XL24 @@ -796,9 +794,7 @@ static const device_config_t ati28800_wonderxl_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; #endif /* USE_XL24 */ // clang-format on @@ -811,7 +807,7 @@ const device_t ati28800_device = { .init = ati28800_init, .close = ati28800_close, .reset = NULL, - { .available = ati28800_available }, + .available = ati28800_available, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = ati28800_config @@ -825,7 +821,7 @@ const device_t ati28800k_device = { .init = ati28800k_init, .close = ati28800_close, .reset = NULL, - { .available = ati28800k_available }, + .available = ati28800k_available, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = ati28800_config @@ -839,7 +835,7 @@ const device_t ati28800k_spc4620p_device = { .init = ati28800k_init, .close = ati28800_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = NULL @@ -853,7 +849,7 @@ const device_t ati28800k_spc6033p_device = { .init = ati28800k_init, .close = ati28800_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = NULL @@ -867,7 +863,7 @@ const device_t compaq_ati28800_device = { .init = ati28800_init, .close = ati28800_close, .reset = NULL, - { .available = compaq_ati28800_available }, + .available = compaq_ati28800_available, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = ati28800_config @@ -881,7 +877,7 @@ const device_t ati28800_wonder1024d_xl_plus_device = { .init = ati28800_init, .close = ati28800_close, .reset = NULL, - { .available = ati28800_wonder1024d_xl_plus_available }, + .available = ati28800_wonder1024d_xl_plus_available, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = NULL @@ -896,7 +892,7 @@ const device_t ati28800_wonderxl24_device = { .init = ati28800_init, .close = ati28800_close, .reset = NULL, - { .available = ati28800_wonderxl24_available }, + .available = ati28800_wonderxl24_available, .speed_changed = ati28800_speed_changed, .force_redraw = ati28800_force_redraw, .config = ati28800_wonderxl_config diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index cb6de4353..bb5ccbf31 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -314,7 +314,7 @@ const device_t ati68860_ramdac_device = { .init = ati68860_ramdac_init, .close = ati68860_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_ati68875_ramdac.c b/src/video/vid_ati68875_ramdac.c index 447a8eca8..5d573a282 100644 --- a/src/video/vid_ati68875_ramdac.c +++ b/src/video/vid_ati68875_ramdac.c @@ -160,7 +160,7 @@ const device_t ati68875_ramdac_device = { .init = ati68875_ramdac_init, .close = ati68875_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 1c79ae1d5..b3a544fc1 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -4733,9 +4733,7 @@ static const device_config_t mach64gx_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mach64vt2_config[] = { @@ -4758,9 +4756,7 @@ static const device_config_t mach64vt2_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -4772,7 +4768,7 @@ const device_t mach64gx_isa_device = { .init = mach64gx_init, .close = mach64_close, .reset = NULL, - { .available = mach64gx_isa_available }, + .available = mach64gx_isa_available, .speed_changed = mach64_speed_changed, .force_redraw = mach64_force_redraw, .config = mach64gx_config @@ -4786,7 +4782,7 @@ const device_t mach64gx_vlb_device = { .init = mach64gx_init, .close = mach64_close, .reset = NULL, - { .available = mach64gx_vlb_available }, + .available = mach64gx_vlb_available, .speed_changed = mach64_speed_changed, .force_redraw = mach64_force_redraw, .config = mach64gx_config @@ -4800,7 +4796,7 @@ const device_t mach64gx_pci_device = { .init = mach64gx_init, .close = mach64_close, .reset = NULL, - { .available = mach64gx_available }, + .available = mach64gx_available, .speed_changed = mach64_speed_changed, .force_redraw = mach64_force_redraw, .config = mach64gx_config @@ -4814,7 +4810,7 @@ const device_t mach64vt2_device = { .init = mach64vt2_init, .close = mach64_close, .reset = NULL, - { .available = mach64vt2_available }, + .available = mach64vt2_available, .speed_changed = mach64_speed_changed, .force_redraw = mach64_force_redraw, .config = mach64vt2_config diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 812885559..c9cdca0db 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -6329,12 +6329,9 @@ static const device_config_t mach8_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; -// clang-format off static const device_config_t mach32_config[] = { { .name = "memory", @@ -6363,12 +6360,9 @@ static const device_config_t mach32_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; -// clang-format off static const device_config_t mach32_pci_config[] = { { .name = "ramdac", @@ -6416,92 +6410,90 @@ static const device_config_t mach32_pci_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; +// clang-format on const device_t mach8_vga_isa_device = { - .name = "ATI Mach8 (ATI Graphics Ultra) (ISA)", + .name = "ATI Mach8 (ATI Graphics Ultra) (ISA)", .internal_name = "mach8_vga_isa", - .flags = DEVICE_ISA, - .local = 1, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = mach8_vga_available }, + .flags = DEVICE_ISA, + .local = 1, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = mach8_vga_available, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach8_config + .force_redraw = mach_force_redraw, + .config = mach8_config }; const device_t mach32_isa_device = { - .name = "ATI Mach32 (ISA)", + .name = "ATI Mach32 (ISA)", .internal_name = "mach32_isa", - .flags = DEVICE_ISA, - .local = 2, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = mach32_isa_available }, + .flags = DEVICE_ISA, + .local = 2, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = mach32_isa_available, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach32_config + .force_redraw = mach_force_redraw, + .config = mach32_config }; const device_t mach32_vlb_device = { - .name = "ATI Mach32 (VLB)", + .name = "ATI Mach32 (VLB)", .internal_name = "mach32_vlb", - .flags = DEVICE_VLB, - .local = 2, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = mach32_vlb_available }, + .flags = DEVICE_VLB, + .local = 2, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = mach32_vlb_available, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach32_config + .force_redraw = mach_force_redraw, + .config = mach32_config }; const device_t mach32_mca_device = { - .name = "ATI Mach32 (MCA)", + .name = "ATI Mach32 (MCA)", .internal_name = "mach32_mca", - .flags = DEVICE_MCA, - .local = 2, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = mach32_mca_available }, + .flags = DEVICE_MCA, + .local = 2, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = mach32_mca_available, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach32_config + .force_redraw = mach_force_redraw, + .config = mach32_config }; const device_t mach32_pci_device = { - .name = "ATI Mach32 (PCI)", + .name = "ATI Mach32 (PCI)", .internal_name = "mach32_pci", - .flags = DEVICE_PCI, - .local = 2, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = mach32_pci_available }, + .flags = DEVICE_PCI, + .local = 2, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = mach32_pci_available, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach32_pci_config + .force_redraw = mach_force_redraw, + .config = mach32_pci_config }; const device_t mach32_onboard_pci_device = { - .name = "ATI Mach32 (PCI) On-Board", + .name = "ATI Mach32 (PCI) On-Board", .internal_name = "mach32_pci_onboard", - .flags = DEVICE_PCI, - .local = 2 | 0x100, - .init = mach8_init, - .close = mach_close, - .reset = NULL, - { .available = NULL }, + .flags = DEVICE_PCI, + .local = 2 | 0x100, + .init = mach8_init, + .close = mach_close, + .reset = NULL, + .available = NULL, .speed_changed = mach_speed_changed, - .force_redraw = mach_force_redraw, - .config = mach32_pci_config + .force_redraw = mach_force_redraw, + .config = mach32_pci_config }; - diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/vid_att20c49x_ramdac.c index f13740d34..7815f79be 100644 --- a/src/video/vid_att20c49x_ramdac.c +++ b/src/video/vid_att20c49x_ramdac.c @@ -182,7 +182,7 @@ const device_t att490_ramdac_device = { .init = att49x_ramdac_init, .close = att49x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -196,7 +196,7 @@ const device_t att491_ramdac_device = { .init = att49x_ramdac_init, .close = att49x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -210,7 +210,7 @@ const device_t att492_ramdac_device = { .init = att49x_ramdac_init, .close = att49x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_att2xc498_ramdac.c b/src/video/vid_att2xc498_ramdac.c index 47eebccae..f52b1432f 100644 --- a/src/video/vid_att2xc498_ramdac.c +++ b/src/video/vid_att2xc498_ramdac.c @@ -183,7 +183,7 @@ const device_t att498_ramdac_device = { .init = att498_ramdac_init, .close = att498_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_av9194.c b/src/video/vid_av9194.c index e7cf75dee..951f3519c 100644 --- a/src/video/vid_av9194.c +++ b/src/video/vid_av9194.c @@ -103,7 +103,7 @@ const device_t av9194_device = { .init = av9194_init, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index a4459ce4c..473b10983 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -962,9 +962,7 @@ static const device_config_t bochs_vbe_config[] = { }, .default_int = 16 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -976,7 +974,7 @@ const device_t bochs_svga_device = { .init = bochs_vbe_init, .close = bochs_vbe_close, .reset = bochs_vbe_reset, - { .available = bochs_vbe_available }, + .available = bochs_vbe_available, .speed_changed = bochs_vbe_speed_changed, .force_redraw = bochs_vbe_force_redraw, .config = bochs_vbe_config diff --git a/src/video/vid_bt481_ramdac.c b/src/video/vid_bt481_ramdac.c index 6cf5f2b1b..d1c85dcfe 100644 --- a/src/video/vid_bt481_ramdac.c +++ b/src/video/vid_bt481_ramdac.c @@ -153,7 +153,7 @@ const device_t bt481_ramdac_device = { .init = bt481_ramdac_init, .close = bt481_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c index 6b0ec300b..d608750e3 100644 --- a/src/video/vid_bt48x_ramdac.c +++ b/src/video/vid_bt48x_ramdac.c @@ -538,7 +538,7 @@ const device_t bt484_ramdac_device = { .init = bt48x_ramdac_init, .close = bt48x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -552,7 +552,7 @@ const device_t att20c504_ramdac_device = { .init = bt48x_ramdac_init, .close = bt48x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -566,7 +566,7 @@ const device_t bt485_ramdac_device = { .init = bt48x_ramdac_init, .close = bt48x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -580,7 +580,7 @@ const device_t att20c505_ramdac_device = { .init = bt48x_ramdac_init, .close = bt48x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -594,7 +594,7 @@ const device_t bt485a_ramdac_device = { .init = bt48x_ramdac_init, .close = bt48x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index c58c319df..375830f3c 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -914,9 +914,7 @@ const device_config_t cga_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -928,7 +926,7 @@ const device_t cga_device = { .init = cga_standalone_init, .close = cga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = cga_speed_changed, .force_redraw = NULL, .config = cga_config @@ -942,7 +940,7 @@ const device_t cga_pravetz_device = { .init = cga_pravetz_init, .close = cga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = cga_speed_changed, .force_redraw = NULL, .config = cga_config diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 5d41dc4a7..de66a37aa 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -2567,7 +2567,7 @@ const device_t chips_69000_device = { .init = chips_69000_init, .close = chips_69000_close, .reset = chips_69000_reset, - { .available = chips_69000_available }, + .available = chips_69000_available, .speed_changed = chips_69000_speed_changed, .force_redraw = chips_69000_force_redraw, .config = NULL @@ -2581,7 +2581,7 @@ const device_t chips_69000_onboard_device = { .init = chips_69000_init, .close = chips_69000_close, .reset = chips_69000_reset, - { .available = chips_69000_available }, + .available = chips_69000_available, .speed_changed = chips_69000_speed_changed, .force_redraw = chips_69000_force_redraw, .config = NULL diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 08a8c7677..51e4ba335 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4719,9 +4719,7 @@ static const device_config_t gd542x_config[] = { }, .default_int = 512 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5426_config[] = { @@ -4748,9 +4746,7 @@ static const device_config_t gd5426_config[] = { }, .default_int = 2048 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5428_onboard_config[] = { @@ -4777,9 +4773,7 @@ static const device_config_t gd5428_onboard_config[] = { }, .default_int = 2048 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5429_config[] = { @@ -4802,9 +4796,7 @@ static const device_config_t gd5429_config[] = { }, .default_int = 2 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5440_onboard_config[] = { @@ -4827,9 +4819,7 @@ static const device_config_t gd5440_onboard_config[] = { }, .default_int = 2 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5434_config[] = { @@ -4856,9 +4846,7 @@ static const device_config_t gd5434_config[] = { }, .default_int = 4 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5434_onboard_config[] = { @@ -4885,9 +4873,7 @@ static const device_config_t gd5434_onboard_config[] = { }, .default_int = 4 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5480_config[] = { @@ -4910,9 +4896,7 @@ static const device_config_t gd5480_config[] = { }, .default_int = 4 }, - { - .type = -1 - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -4924,7 +4908,7 @@ const device_t gd5401_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5401_available }, + .available = gd5401_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = NULL, @@ -4938,7 +4922,7 @@ const device_t gd5402_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5402_available }, + .available = gd5402_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = NULL, @@ -4952,7 +4936,7 @@ const device_t gd5402_onboard_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = NULL, @@ -4966,7 +4950,7 @@ const device_t gd5420_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5420_available }, + .available = gd5420_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd542x_config, @@ -4980,7 +4964,7 @@ const device_t gd5422_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5422_available }, /* Common BIOS between 5422 and 5424 */ + .available = gd5422_available, /* Common BIOS between 5422 and 5424 */ .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd542x_config, @@ -4994,7 +4978,7 @@ const device_t gd5424_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5422_available }, /* Common BIOS between 5422 and 5424 */ + .available = gd5422_available, /* Common BIOS between 5422 and 5424 */ .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd542x_config, @@ -5008,7 +4992,7 @@ const device_t gd5426_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_isa_available }, + .available = gd5428_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5023,7 +5007,7 @@ const device_t gd5426_diamond_speedstar_pro_a1_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5426_diamond_a1_available }, + .available = gd5426_diamond_a1_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5037,7 +5021,7 @@ const device_t gd5426_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_available }, + .available = gd5428_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5051,7 +5035,7 @@ const device_t gd5426_onboard_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = NULL @@ -5065,7 +5049,7 @@ const device_t gd5428_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_isa_available }, + .available = gd5428_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5079,7 +5063,7 @@ const device_t gd5428_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_available }, + .available = gd5428_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5094,7 +5078,7 @@ const device_t gd5428_diamond_speedstar_pro_b1_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_diamond_b1_available }, + .available = gd5428_diamond_b1_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5108,7 +5092,7 @@ const device_t gd5428_boca_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_boca_isa_available }, + .available = gd5428_boca_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5122,7 +5106,7 @@ const device_t gd5428_mca_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_mca_available }, + .available = gd5428_mca_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = NULL @@ -5136,7 +5120,7 @@ const device_t gd5426_mca_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5426_mca_available }, + .available = gd5426_mca_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5426_config @@ -5150,7 +5134,7 @@ const device_t gd5428_onboard_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5428_isa_available }, + .available = gd5428_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5428_onboard_config @@ -5164,7 +5148,7 @@ const device_t gd5428_vlb_onboard_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5428_onboard_config @@ -5178,7 +5162,7 @@ const device_t gd5429_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5429_available }, + .available = gd5429_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5192,7 +5176,7 @@ const device_t gd5429_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5429_available }, + .available = gd5429_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5207,7 +5191,7 @@ const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5430_diamond_a8_available }, + .available = gd5430_diamond_a8_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5221,7 +5205,7 @@ const device_t gd5430_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5430_orchid_vlb_available }, + .available = gd5430_orchid_vlb_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5235,7 +5219,7 @@ const device_t gd5430_onboard_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5249,7 +5233,7 @@ const device_t gd5430_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5430_available }, + .available = gd5430_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5263,7 +5247,7 @@ const device_t gd5430_onboard_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5277,7 +5261,7 @@ const device_t gd5434_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5434_isa_available }, + .available = gd5434_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5292,7 +5276,7 @@ const device_t gd5434_diamond_speedstar_64_a3_isa_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5434_diamond_a3_available }, + .available = gd5434_diamond_a3_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5306,7 +5290,7 @@ const device_t gd5434_onboard_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_onboard_config @@ -5320,7 +5304,7 @@ const device_t gd5434_vlb_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5430_orchid_vlb_available }, + .available = gd5430_orchid_vlb_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5334,7 +5318,7 @@ const device_t gd5434_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5434_available }, + .available = gd5434_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5348,7 +5332,7 @@ const device_t gd5436_onboard_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5362,7 +5346,7 @@ const device_t gd5436_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5436_available }, + .available = gd5436_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5376,7 +5360,7 @@ const device_t gd5440_onboard_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = NULL }, + .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5440_onboard_config @@ -5390,7 +5374,7 @@ const device_t gd5440_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5440_available }, + .available = gd5440_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5429_config @@ -5404,7 +5388,7 @@ const device_t gd5446_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5446_available }, + .available = gd5446_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5418,7 +5402,7 @@ const device_t gd5446_stb_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5446_stb_available }, + .available = gd5446_stb_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5434_config @@ -5432,7 +5416,7 @@ const device_t gd5480_pci_device = { .init = gd54xx_init, .close = gd54xx_close, .reset = gd54xx_reset, - { .available = gd5480_available }, + .available = gd5480_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, .config = gd5480_config diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index dcc72a76b..98d6adea7 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -425,9 +425,7 @@ static const device_config_t colorplus_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -439,7 +437,7 @@ const device_t colorplus_device = { .init = colorplus_standalone_init, .close = colorplus_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = colorplus_speed_changed, .force_redraw = NULL, .config = colorplus_config diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c index 430c7a64d..13fc399eb 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_compaq_cga.c @@ -481,7 +481,7 @@ const device_t compaq_cga_device = { .init = compaq_cga_init, .close = compaq_cga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = compaq_cga_speed_changed, .force_redraw = NULL, .config = cga_config @@ -495,7 +495,7 @@ const device_t compaq_cga_2_device = { .init = compaq_cga_init, .close = compaq_cga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = compaq_cga_speed_changed, .force_redraw = NULL, .config = cga_config diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index fccd4f629..faf4b9066 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1655,9 +1655,7 @@ static const device_config_t ega_config[] = { }, .default_int = 9 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -1669,7 +1667,7 @@ const device_t ega_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = ega_standalone_available }, + .available = ega_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config @@ -1683,7 +1681,7 @@ const device_t cpqega_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = cpqega_standalone_available }, + .available = cpqega_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config @@ -1697,7 +1695,7 @@ const device_t sega_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = sega_standalone_available }, + .available = sega_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config @@ -1711,7 +1709,7 @@ const device_t atiega800p_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = atiega800p_standalone_available }, + .available = atiega800p_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config @@ -1725,7 +1723,7 @@ const device_t iskra_ega_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = iskra_ega_standalone_available }, + .available = iskra_ega_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config @@ -1739,7 +1737,7 @@ const device_t et2000_device = { .init = ega_standalone_init, .close = ega_close, .reset = NULL, - { .available = et2000_standalone_available }, + .available = et2000_standalone_available, .speed_changed = ega_speed_changed, .force_redraw = NULL, .config = ega_config diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index 45a2fc199..8585fedff 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -560,7 +560,7 @@ static const device_config_t et3000_config[] = { { .description = "" } } }, - { .type = CONFIG_END } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -572,7 +572,7 @@ const device_t et3000_isa_device = { .init = et3000_init, .close = et3000_close, .reset = NULL, - { .available = et3000_available }, + .available = et3000_available, .speed_changed = et3000_speed_changed, .force_redraw = et3000_force_redraw, .config = et3000_config diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index ad8cf5c46..169dc659b 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -981,9 +981,7 @@ static const device_config_t et4000_tc6058af_config[] = { { .files_no = 0 } }, }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -1028,9 +1026,7 @@ static const device_config_t et4000_bios_config[] = { { .files_no = 0 } }, }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -1059,9 +1055,7 @@ static const device_config_t et4000_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -1073,7 +1067,7 @@ const device_t et4000_tc6058af_isa_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_tc6058af_config @@ -1087,7 +1081,7 @@ const device_t et4000_isa_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_bios_config @@ -1101,7 +1095,7 @@ const device_t et4000_mca_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = et4000_available }, + .available = et4000_available, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_config @@ -1115,7 +1109,7 @@ const device_t et4000k_isa_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = et4000k_available }, + .available = et4000k_available, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_config @@ -1129,7 +1123,7 @@ const device_t et4000k_tg286_isa_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = et4000k_available }, + .available = et4000k_available, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_config @@ -1143,7 +1137,7 @@ const device_t et4000_kasan_isa_device = { .init = et4000_init, .close = et4000_close, .reset = NULL, - { .available = et4000_kasan_available }, + .available = et4000_kasan_available, .speed_changed = et4000_speed_changed, .force_redraw = et4000_force_redraw, .config = et4000_config diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 2f086f3c7..351dfba5d 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -2961,9 +2961,7 @@ static const device_config_t et4000w32p_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -2975,7 +2973,7 @@ const device_t et4000w32_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32_available }, + .available = et4000w32_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = NULL @@ -2989,7 +2987,7 @@ const device_t et4000w32_onboard_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32_available }, + .available = et4000w32_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = NULL @@ -3003,7 +3001,7 @@ const device_t et4000w32i_isa_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32i_isa_available }, + .available = et4000w32i_isa_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = NULL @@ -3017,7 +3015,7 @@ const device_t et4000w32i_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32i_vlb_available }, + .available = et4000w32i_vlb_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3031,7 +3029,7 @@ const device_t et4000w32p_videomagic_revb_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_videomagic_revb_vlb_available }, + .available = et4000w32p_videomagic_revb_vlb_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3045,7 +3043,7 @@ const device_t et4000w32p_videomagic_revb_pci_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_videomagic_revb_vlb_available }, + .available = et4000w32p_videomagic_revb_vlb_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3059,7 +3057,7 @@ const device_t et4000w32p_revc_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_revc_available }, + .available = et4000w32p_revc_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3073,7 +3071,7 @@ const device_t et4000w32p_revc_pci_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_revc_available }, + .available = et4000w32p_revc_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3087,7 +3085,7 @@ const device_t et4000w32p_noncardex_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_noncardex_available }, + .available = et4000w32p_noncardex_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3101,7 +3099,7 @@ const device_t et4000w32p_noncardex_pci_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_noncardex_available }, + .available = et4000w32p_noncardex_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3115,7 +3113,7 @@ const device_t et4000w32p_cardex_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_cardex_available }, + .available = et4000w32p_cardex_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3129,7 +3127,7 @@ const device_t et4000w32p_cardex_pci_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_cardex_available }, + .available = et4000w32p_cardex_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3143,7 +3141,7 @@ const device_t et4000w32p_vlb_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_available }, + .available = et4000w32p_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config @@ -3157,7 +3155,7 @@ const device_t et4000w32p_pci_device = { .init = et4000w32p_init, .close = et4000w32p_close, .reset = NULL, - { .available = et4000w32p_available }, + .available = et4000w32p_available, .speed_changed = et4000w32p_speed_changed, .force_redraw = et4000w32p_force_redraw, .config = et4000w32p_config diff --git a/src/video/vid_f82c425.c b/src/video/vid_f82c425.c index 772926e1e..c607cda14 100644 --- a/src/video/vid_f82c425.c +++ b/src/video/vid_f82c425.c @@ -631,7 +631,7 @@ const device_t f82c425_video_device = { .init = f82c425_init, .close = f82c425_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = f82c425_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 4ae8e6fd1..c7a91aac6 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -826,7 +826,7 @@ const device_t genius_device = { .init = genius_init, .close = genius_close, .reset = NULL, - { .available = genius_available }, + .available = genius_available, .speed_changed = genius_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 2a725488d..8d99e9c7b 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -647,9 +647,7 @@ static const device_config_t hercules_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -661,7 +659,7 @@ const device_t hercules_device = { .init = hercules_init, .close = hercules_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = speed_changed, .force_redraw = NULL, .config = hercules_config diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index 429632f19..1b6b74033 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -732,9 +732,7 @@ static const device_config_t herculesplus_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -746,7 +744,7 @@ const device_t herculesplus_device = { .init = herculesplus_init, .close = herculesplus_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = speed_changed, .force_redraw = NULL, .config = herculesplus_config diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index f349864df..3ed9e2bce 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1731,7 +1731,7 @@ static const device_config_t v7_vga_1024i_config[] = { { .description = "" } } }, - { .type = CONFIG_END } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ht216_32_standalone_config[] = { @@ -1748,7 +1748,7 @@ static const device_config_t ht216_32_standalone_config[] = { { .description = "" } } }, - { .type = CONFIG_END } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -1760,7 +1760,7 @@ const device_t g2_gc205_device = { .init = g2_gc205_init, .close = ht216_close, .reset = NULL, - { .available = g2_gc205_available }, + .available = g2_gc205_available, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = NULL @@ -1774,7 +1774,7 @@ const device_t v7_vga_1024i_device = { .init = v7_vga_1024i_init, .close = ht216_close, .reset = NULL, - { .available = v7_vga_1024i_available }, + .available = v7_vga_1024i_available, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = v7_vga_1024i_config @@ -1788,7 +1788,7 @@ const device_t ht216_32_pb410a_device = { .init = ht216_pb410a_init, .close = ht216_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = NULL @@ -1802,7 +1802,7 @@ const device_t ht216_32_standalone_device = { .init = ht216_standalone_init, .close = ht216_close, .reset = NULL, - { .available = ht216_standalone_available }, + .available = ht216_standalone_available, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = ht216_32_standalone_config @@ -1816,7 +1816,7 @@ const device_t radius_svga_multiview_isa_device = { .init = radius_svga_multiview_init, .close = ht216_close, .reset = NULL, - { .available = radius_svga_multiview_available }, + .available = radius_svga_multiview_available, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = NULL @@ -1830,7 +1830,7 @@ const device_t radius_svga_multiview_mca_device = { .init = radius_svga_multiview_init, .close = ht216_close, .reset = NULL, - { .available = radius_svga_multiview_available }, + .available = radius_svga_multiview_available, .speed_changed = ht216_speed_changed, .force_redraw = ht216_force_redraw, .config = NULL diff --git a/src/video/vid_ibm_rgb528_ramdac.c b/src/video/vid_ibm_rgb528_ramdac.c index 1b19a3a0f..dcdbbb25b 100644 --- a/src/video/vid_ibm_rgb528_ramdac.c +++ b/src/video/vid_ibm_rgb528_ramdac.c @@ -982,7 +982,7 @@ const device_t ibm_rgb528_ramdac_device = { .init = ibm_rgb528_ramdac_init, .close = ibm_rgb528_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_icd2061.c b/src/video/vid_icd2061.c index 4c23d6ec5..7b80a5484 100644 --- a/src/video/vid_icd2061.c +++ b/src/video/vid_icd2061.c @@ -179,7 +179,7 @@ const device_t icd2061_device = { .init = icd2061_init, .close = icd2061_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -193,7 +193,7 @@ const device_t ics9161_device = { .init = icd2061_init, .close = icd2061_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_ics2494.c b/src/video/vid_ics2494.c index e85b4539e..350a490cc 100644 --- a/src/video/vid_ics2494.c +++ b/src/video/vid_ics2494.c @@ -168,7 +168,7 @@ const device_t ics2494an_305_device = { .init = ics2494_init, .close = ics2494_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -182,7 +182,7 @@ const device_t ati18810_device = { .init = ics2494_init, .close = ics2494_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -196,7 +196,7 @@ const device_t ati18811_0_device = { .init = ics2494_init, .close = ics2494_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -210,7 +210,7 @@ const device_t ati18811_1_device = { .init = ics2494_init, .close = ics2494_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_ics2595.c b/src/video/vid_ics2595.c index ecb414f2b..b5da3d7e2 100644 --- a/src/video/vid_ics2595.c +++ b/src/video/vid_ics2595.c @@ -129,7 +129,7 @@ const device_t ics2595_device = { .init = ics2595_init, .close = ics2595_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c index c7602ffd0..a77ad09c3 100644 --- a/src/video/vid_im1024.c +++ b/src/video/vid_im1024.c @@ -1090,7 +1090,7 @@ const device_t im1024_device = { .init = im1024_init, .close = im1024_close, .reset = NULL, - { .available = im1024_available }, + .available = im1024_available, .speed_changed = im1024_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_incolor.c b/src/video/vid_incolor.c index e3f37ec65..0abb4a6c2 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_incolor.c @@ -1053,7 +1053,7 @@ const device_t incolor_device = { .init = incolor_init, .close = incolor_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 702fb7e32..edadb4e46 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -379,9 +379,7 @@ static const device_config_t mda_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -393,7 +391,7 @@ const device_t mda_device = { .init = mda_standalone_init, .close = mda_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = mda_speed_changed, .force_redraw = NULL, .config = mda_config diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index ee422fd3f..a0d92ef9e 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -6872,7 +6872,7 @@ static const device_config_t mystique_config[] = { }, .default_int = 8 }, - { .type = CONFIG_END } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -6899,7 +6899,7 @@ static const device_config_t millennium_ii_config[] = { }, .default_int = 8 }, - { .type = CONFIG_END } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -6911,7 +6911,7 @@ const device_t millennium_device = { .init = mystique_init, .close = mystique_close, .reset = NULL, - { .available = millennium_available }, + .available = millennium_available, .speed_changed = mystique_speed_changed, .force_redraw = mystique_force_redraw, .config = mystique_config @@ -6925,7 +6925,7 @@ const device_t mystique_device = { .init = mystique_init, .close = mystique_close, .reset = NULL, - { .available = mystique_available }, + .available = mystique_available, .speed_changed = mystique_speed_changed, .force_redraw = mystique_force_redraw, .config = mystique_config @@ -6939,7 +6939,7 @@ const device_t mystique_220_device = { .init = mystique_init, .close = mystique_close, .reset = NULL, - { .available = mystique_220_available }, + .available = mystique_220_available, .speed_changed = mystique_speed_changed, .force_redraw = mystique_force_redraw, .config = mystique_config @@ -6953,7 +6953,7 @@ const device_t millennium_ii_device = { .init = mystique_init, .close = mystique_close, .reset = NULL, - { .available = millennium_ii_available }, + .available = millennium_ii_available, .speed_changed = mystique_speed_changed, .force_redraw = mystique_force_redraw, .config = millennium_ii_config @@ -6968,7 +6968,7 @@ const device_t productiva_g100_device = { .init = mystique_init, .close = mystique_close, .reset = NULL, - { .available = matrox_g100_available }, + .available = matrox_g100_available, .speed_changed = mystique_speed_changed, .force_redraw = mystique_force_redraw, .config = millennium_ii_config diff --git a/src/video/vid_nga.c b/src/video/vid_nga.c index 32c103a8b..3cb7426b8 100644 --- a/src/video/vid_nga.c +++ b/src/video/vid_nga.c @@ -682,9 +682,7 @@ const device_config_t nga_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -696,7 +694,7 @@ const device_t nga_device = { .init = nga_init, .close = nga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = nga_speed_changed, .force_redraw = NULL, .config = nga_config diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index 715ba0df3..c7d42275d 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -589,9 +589,7 @@ static const device_config_t oti067_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti067_ama932j_config[] = { @@ -614,9 +612,7 @@ static const device_config_t oti067_ama932j_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti077_acer100t_config[] = { @@ -643,9 +639,7 @@ static const device_config_t oti077_acer100t_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti077_config[] = { @@ -672,9 +666,7 @@ static const device_config_t oti077_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -686,7 +678,7 @@ const device_t oti037c_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti037c_available }, + .available = oti037c_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = NULL @@ -700,7 +692,7 @@ const device_t oti067_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti067_077_available }, + .available = oti067_077_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = oti067_config @@ -714,7 +706,7 @@ const device_t oti067_m300_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti067_m300_available }, + .available = oti067_m300_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = oti067_config @@ -728,7 +720,7 @@ const device_t oti067_ama932j_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti067_ama932j_available }, + .available = oti067_ama932j_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = oti067_ama932j_config @@ -742,7 +734,7 @@ const device_t oti077_acer100t_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti077_acer100t_available }, + .available = oti077_acer100t_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = oti077_acer100t_config @@ -757,7 +749,7 @@ const device_t oti077_device = { .init = oti_init, .close = oti_close, .reset = NULL, - { .available = oti067_077_available }, + .available = oti067_077_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, .config = oti077_config diff --git a/src/video/vid_ogc.c b/src/video/vid_ogc.c index 9ac94169c..d430d2e14 100644 --- a/src/video/vid_ogc.c +++ b/src/video/vid_ogc.c @@ -666,9 +666,7 @@ const device_config_t ogc_m24_config[] = { .type = CONFIG_BINARY, .default_int = 1, }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -680,7 +678,7 @@ const device_t ogc_m24_device = { .init = ogc_init, .close = ogc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ogc_speed_changed, .force_redraw = NULL, .config = ogc_m24_config @@ -694,7 +692,7 @@ const device_t ogc_device = { .init = ogc_init, .close = ogc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = ogc_speed_changed, .force_redraw = NULL, .config = cga_config diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 27e98d32d..8e3241efd 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -712,7 +712,7 @@ const device_t paradise_pvga1a_pc2086_device = { .init = paradise_pvga1a_pc2086_init, .close = paradise_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = NULL @@ -726,7 +726,7 @@ const device_t paradise_pvga1a_pc3086_device = { .init = paradise_pvga1a_pc3086_init, .close = paradise_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = NULL @@ -753,9 +753,7 @@ static const device_config_t paradise_pvga1a_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -767,7 +765,7 @@ const device_t paradise_pvga1a_ncr3302_device = { .init = paradise_pvga1a_ncr3302_init, .close = paradise_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = paradise_pvga1a_config @@ -781,7 +779,7 @@ const device_t paradise_pvga1a_device = { .init = paradise_pvga1a_standalone_init, .close = paradise_close, .reset = NULL, - { .available = paradise_pvga1a_standalone_available }, + .available = paradise_pvga1a_standalone_available, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = paradise_pvga1a_config @@ -795,7 +793,7 @@ const device_t paradise_wd90c11_megapc_device = { .init = paradise_wd90c11_megapc_init, .close = paradise_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = NULL @@ -809,7 +807,7 @@ const device_t paradise_wd90c11_device = { .init = paradise_wd90c11_standalone_init, .close = paradise_close, .reset = NULL, - { .available = paradise_wd90c11_standalone_available }, + .available = paradise_wd90c11_standalone_available, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = NULL @@ -840,9 +838,7 @@ static const device_config_t paradise_wd90c30_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -854,7 +850,7 @@ const device_t paradise_wd90c30_device = { .init = paradise_wd90c30_standalone_init, .close = paradise_close, .reset = NULL, - { .available = paradise_wd90c30_standalone_available }, + .available = paradise_wd90c30_standalone_available, .speed_changed = paradise_speed_changed, .force_redraw = paradise_force_redraw, .config = paradise_wd90c30_config diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index 354c7e265..5cb35dc4e 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -2743,7 +2743,7 @@ const device_t pgc_device = { .init = pgc_standalone_init, .close = pgc_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = pgc_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c index e82763d15..b6e0085f8 100644 --- a/src/video/vid_rtg310x.c +++ b/src/video/vid_rtg310x.c @@ -405,9 +405,7 @@ static const device_config_t rtg3105_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -436,9 +434,7 @@ static const device_config_t rtg3106_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -450,7 +446,7 @@ const device_t realtek_rtg3105_device = { .init = rtg_init, .close = rtg_close, .reset = NULL, - { .available = rtg3105_available }, + .available = rtg3105_available, .speed_changed = rtg_speed_changed, .force_redraw = rtg_force_redraw, .config = rtg3105_config @@ -464,7 +460,7 @@ const device_t realtek_rtg3106_device = { .init = rtg_init, .close = rtg_close, .reset = NULL, - { .available = rtg3106_available }, + .available = rtg3106_available, .speed_changed = rtg_speed_changed, .force_redraw = rtg_force_redraw, .config = rtg3106_config diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 7839a602a..7e3b7a2ef 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10544,97 +10544,98 @@ s3_force_redraw(void *priv) } static const device_config_t s3_orchid_86c911_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1, - .selection = { - { .description = "512 KB", - .value = 0 }, - { .description = "1 MB", - .value = 1 }, - { .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 1, + .selection = { + { .description = "512 KB", .value = 0 }, + { .description = "1 MB", .value = 1 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_9fx_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { - { .description = "1 MB", - .value = 1 }, - { .description = "2 MB", - .value = 2 }, - /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ - { - .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + /* Trio64 also supports 4 MB, however the Number Nine BIOS does not */ + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_phoenix_trio32_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { - { .description = "512 KB", - .value = 0 }, - { .description = "1 MB", - .value = 1 }, - { .description = "2 MB", - .value = 2 }, - { .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { .description = "512 KB", .value = 0 }, + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_standard_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { .description = "1 MB", - .value = 1 }, - { .description = "2 MB", - .value = 2 }, - { .description = "4 MB", - .value = 4 }, - { .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_968_config[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { .description = "1 MB", - .value = 1 }, - { .description = "2 MB", - .value = 2 }, - { .description = "4 MB", - .value = 4 }, - { .description = "8 MB", - .value = 8 }, - { .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_standard_config2[] = { - { .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { .description = "2 MB", - .value = 2 }, - { .description = "4 MB", - .value = 4 }, - { .description = "" } } }, - { .type = CONFIG_END } + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } }; const device_t s3_orchid_86c911_isa_device = { @@ -10645,7 +10646,7 @@ const device_t s3_orchid_86c911_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_orchid_86c911_available }, + .available = s3_orchid_86c911_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_orchid_86c911_config @@ -10659,7 +10660,7 @@ const device_t s3_diamond_stealth_vram_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth_vram_available }, + .available = s3_diamond_stealth_vram_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_orchid_86c911_config @@ -10673,7 +10674,7 @@ const device_t s3_ami_86c924_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_ami_86c924_available }, + .available = s3_ami_86c924_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_orchid_86c911_config @@ -10687,7 +10688,7 @@ const device_t s3_spea_mirage_86c801_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_spea_mirage_86c801_available }, + .available = s3_spea_mirage_86c801_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10701,7 +10702,7 @@ const device_t s3_86c805_onboard_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10715,7 +10716,7 @@ const device_t s3_spea_mirage_86c805_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_spea_mirage_86c805_available }, + .available = s3_spea_mirage_86c805_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10729,7 +10730,7 @@ const device_t s3_mirocrystal_8s_805_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirocrystal_8s_805_available }, + .available = s3_mirocrystal_8s_805_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10743,7 +10744,7 @@ const device_t s3_mirocrystal_10sd_805_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirocrystal_10sd_805_available }, + .available = s3_mirocrystal_10sd_805_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10757,7 +10758,7 @@ const device_t s3_phoenix_86c801_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_86c80x_available }, + .available = s3_phoenix_86c80x_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10771,7 +10772,7 @@ const device_t s3_phoenix_86c805_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_86c80x_available }, + .available = s3_phoenix_86c80x_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10785,7 +10786,7 @@ const device_t s3_metheus_86c928_isa_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_metheus_86c928_available }, + .available = s3_metheus_86c928_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10799,7 +10800,7 @@ const device_t s3_metheus_86c928_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_metheus_86c928_available }, + .available = s3_metheus_86c928_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10813,7 +10814,7 @@ const device_t s3_spea_mercury_lite_86c928_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_spea_mercury_lite_pci_available }, + .available = s3_spea_mercury_lite_pci_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_orchid_86c911_config @@ -10827,7 +10828,7 @@ const device_t s3_mirocrystal_20sd_864_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirocrystal_20sd_864_vlb_available }, + .available = s3_mirocrystal_20sd_864_vlb_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10841,7 +10842,7 @@ const device_t s3_bahamas64_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_bahamas64_available }, + .available = s3_bahamas64_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10855,7 +10856,7 @@ const device_t s3_bahamas64_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_bahamas64_available }, + .available = s3_bahamas64_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10869,7 +10870,7 @@ const device_t s3_mirocrystal_20sv_964_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirocrystal_20sv_964_vlb_available }, + .available = s3_mirocrystal_20sv_964_vlb_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10883,7 +10884,7 @@ const device_t s3_mirocrystal_20sv_964_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirocrystal_20sv_964_pci_available }, + .available = s3_mirocrystal_20sv_964_pci_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -10897,7 +10898,7 @@ const device_t s3_diamond_stealth64_964_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_964_available }, + .available = s3_diamond_stealth64_964_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10911,7 +10912,7 @@ const device_t s3_diamond_stealth64_964_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_964_available }, + .available = s3_diamond_stealth64_964_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10925,7 +10926,7 @@ const device_t s3_diamond_stealth64_968_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_968_available }, + .available = s3_diamond_stealth64_968_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config2 @@ -10939,7 +10940,7 @@ const device_t s3_diamond_stealth64_968_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_968_available }, + .available = s3_diamond_stealth64_968_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config2 @@ -10953,7 +10954,7 @@ const device_t s3_9fx_771_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_9fx_771_available }, + .available = s3_9fx_771_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_968_config @@ -10967,7 +10968,7 @@ const device_t s3_phoenix_vision968_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_vision968_available }, + .available = s3_phoenix_vision968_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10981,7 +10982,7 @@ const device_t s3_mirovideo_40sv_ergo_968_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_mirovideo_40sv_ergo_968_pci_available }, + .available = s3_mirovideo_40sv_ergo_968_pci_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -10995,7 +10996,7 @@ const device_t s3_spea_mercury_p64v_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_spea_mercury_p64v_pci_available }, + .available = s3_spea_mercury_p64v_pci_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11009,7 +11010,7 @@ const device_t s3_9fx_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_9fx_available }, + .available = s3_9fx_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11023,7 +11024,7 @@ const device_t s3_9fx_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_9fx_available }, + .available = s3_9fx_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11037,7 +11038,7 @@ const device_t s3_phoenix_trio32_onboard_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11051,7 +11052,7 @@ const device_t s3_phoenix_trio32_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_trio32_available }, + .available = s3_phoenix_trio32_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11065,7 +11066,7 @@ const device_t s3_phoenix_trio32_onboard_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11079,7 +11080,7 @@ const device_t s3_phoenix_trio32_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_trio32_available }, + .available = s3_phoenix_trio32_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11093,7 +11094,7 @@ const device_t s3_diamond_stealth_se_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth_se_available }, + .available = s3_diamond_stealth_se_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11107,7 +11108,7 @@ const device_t s3_diamond_stealth_se_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth_se_available }, + .available = s3_diamond_stealth_se_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11121,7 +11122,7 @@ const device_t s3_phoenix_trio64_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_trio64_available }, + .available = s3_phoenix_trio64_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11135,7 +11136,7 @@ const device_t s3_phoenix_trio64_onboard_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11149,7 +11150,7 @@ const device_t s3_phoenix_trio64_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_trio64_available }, + .available = s3_phoenix_trio64_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11163,7 +11164,7 @@ const device_t s3_stb_powergraph_64_video_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_stb_powergraph_64_video_available }, + .available = s3_stb_powergraph_64_video_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_phoenix_trio32_config @@ -11177,7 +11178,7 @@ const device_t s3_phoenix_trio64vplus_onboard_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11191,7 +11192,7 @@ const device_t s3_phoenix_trio64vplus_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_trio64vplus_available }, + .available = s3_phoenix_trio64vplus_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11205,7 +11206,7 @@ const device_t s3_cardex_trio64vplus_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_cardex_trio64vplus_available }, + .available = s3_cardex_trio64vplus_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11219,7 +11220,7 @@ const device_t s3_phoenix_vision864_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_vision864_available }, + .available = s3_phoenix_vision864_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11233,7 +11234,7 @@ const device_t s3_phoenix_vision864_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_vision864_available }, + .available = s3_phoenix_vision864_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11247,7 +11248,7 @@ const device_t s3_9fx_531_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_9fx_531_available }, + .available = s3_9fx_531_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11261,7 +11262,7 @@ const device_t s3_phoenix_vision868_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_phoenix_vision868_available }, + .available = s3_phoenix_vision868_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11275,7 +11276,7 @@ const device_t s3_diamond_stealth64_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_764_available }, + .available = s3_diamond_stealth64_764_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11289,7 +11290,7 @@ const device_t s3_diamond_stealth64_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_diamond_stealth64_764_available }, + .available = s3_diamond_stealth64_764_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11303,7 +11304,7 @@ const device_t s3_spea_mirage_p64_vlb_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_spea_mirage_p64_vlb_available }, + .available = s3_spea_mirage_p64_vlb_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_9fx_config @@ -11317,7 +11318,7 @@ const device_t s3_elsa_winner2000_pro_x_964_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_elsa_winner2000_pro_x_964_available }, + .available = s3_elsa_winner2000_pro_x_964_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_968_config @@ -11331,7 +11332,7 @@ const device_t s3_elsa_winner2000_pro_x_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_elsa_winner2000_pro_x_available }, + .available = s3_elsa_winner2000_pro_x_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_968_config @@ -11345,7 +11346,7 @@ const device_t s3_trio64v2_dx_pci_device = { .init = s3_init, .close = s3_close, .reset = s3_reset, - { .available = s3_trio64v2_dx_available }, + .available = s3_trio64v2_dx_available, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config @@ -11359,7 +11360,7 @@ const device_t s3_trio64v2_dx_onboard_pci_device = { .init = s3_init, .close = s3_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, .config = s3_standard_config diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 08a01dbd6..3c61f3a57 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -4734,9 +4734,7 @@ static const device_config_t s3_virge_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -4777,9 +4775,7 @@ static const device_config_t s3_virge_stb_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -4797,9 +4793,7 @@ static const device_config_t s3_virge_357_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -4836,9 +4830,7 @@ static const device_config_t s3_trio3d2x_config[] = { .type = CONFIG_BINARY, .default_int = 1 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -4850,7 +4842,7 @@ const device_t s3_virge_325_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_325_available }, + .available = s3_virge_325_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4864,7 +4856,7 @@ const device_t s3_virge_325_onboard_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4878,7 +4870,7 @@ const device_t s3_diamond_stealth_2000_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_325_diamond_available }, + .available = s3_virge_325_diamond_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4892,7 +4884,7 @@ const device_t s3_mirocrystal_3d_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_mirocrystal_3d_available }, + .available = s3_mirocrystal_3d_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4906,7 +4898,7 @@ const device_t s3_diamond_stealth_3000_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_988_diamond_available }, + .available = s3_virge_988_diamond_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_stb_config @@ -4920,7 +4912,7 @@ const device_t s3_stb_velocity_3d_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_988_stb_available }, + .available = s3_virge_988_stb_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_stb_config @@ -4934,7 +4926,7 @@ const device_t s3_virge_375_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_375_available }, + .available = s3_virge_375_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4948,7 +4940,7 @@ const device_t s3_virge_375_onboard_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = NULL }, + .available = NULL, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4962,7 +4954,7 @@ const device_t s3_diamond_stealth_2000pro_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_375_diamond_available }, + .available = s3_virge_375_diamond_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4976,7 +4968,7 @@ const device_t s3_virge_385_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_385_available }, + .available = s3_virge_385_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_config @@ -4990,7 +4982,7 @@ const device_t s3_virge_357_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_357_available }, + .available = s3_virge_357_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_357_config @@ -5004,7 +4996,7 @@ const device_t s3_virge_357_agp_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_357_available }, + .available = s3_virge_357_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_357_config @@ -5018,7 +5010,7 @@ const device_t s3_diamond_stealth_4000_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_357_diamond_available }, + .available = s3_virge_357_diamond_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_357_config @@ -5032,7 +5024,7 @@ const device_t s3_diamond_stealth_4000_agp_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_virge_357_diamond_available }, + .available = s3_virge_357_diamond_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_virge_357_config @@ -5046,7 +5038,7 @@ const device_t s3_trio3d2x_pci_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_trio3d2x_available }, + .available = s3_trio3d2x_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_trio3d2x_config @@ -5060,7 +5052,7 @@ const device_t s3_trio3d2x_agp_device = { .init = s3_virge_init, .close = s3_virge_close, .reset = s3_virge_reset, - { .available = s3_trio3d2x_available }, + .available = s3_trio3d2x_available, .speed_changed = s3_virge_speed_changed, .force_redraw = s3_virge_force_redraw, .config = s3_trio3d2x_config diff --git a/src/video/vid_sc1148x_ramdac.c b/src/video/vid_sc1148x_ramdac.c index 24ca4aeec..0ebcb49b6 100644 --- a/src/video/vid_sc1148x_ramdac.c +++ b/src/video/vid_sc1148x_ramdac.c @@ -156,7 +156,7 @@ const device_t sc11483_ramdac_device = { .init = sc1148x_ramdac_init, .close = sc1148x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -170,7 +170,7 @@ const device_t sc11487_ramdac_device = { .init = sc1148x_ramdac_init, .close = sc1148x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -184,7 +184,7 @@ const device_t sc11484_nors2_ramdac_device = { .init = sc1148x_ramdac_init, .close = sc1148x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -198,7 +198,7 @@ const device_t sc11486_ramdac_device = { .init = sc1148x_ramdac_init, .close = sc1148x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/vid_sc1502x_ramdac.c index 7315c65ad..1c7d4014d 100644 --- a/src/video/vid_sc1502x_ramdac.c +++ b/src/video/vid_sc1502x_ramdac.c @@ -249,7 +249,7 @@ const device_t sc1502x_ramdac_device = { .init = sc1502x_ramdac_init, .close = sc1502x_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index 83796506e..4e6deacdc 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -313,7 +313,7 @@ const device_t gendac_ramdac_device = { .init = sdac_ramdac_init, .close = sdac_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -327,7 +327,7 @@ const device_t tseng_ics5301_ramdac_device = { .init = sdac_ramdac_init, .close = sdac_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -341,7 +341,7 @@ const device_t tseng_ics5341_ramdac_device = { .init = sdac_ramdac_init, .close = sdac_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -355,7 +355,7 @@ const device_t sdac_ramdac_device = { .init = sdac_ramdac_init, .close = sdac_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 56f8b99aa..161331918 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -951,9 +951,7 @@ device_config_t sigma_config[] = { } }, }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -965,7 +963,7 @@ const device_t sigma_device = { .init = sigma_init, .close = sigma_close, .reset = NULL, - { .available = sigma_available }, + .available = sigma_available, .speed_changed = sigma_speed_changed, .force_redraw = NULL, .config = sigma_config diff --git a/src/video/vid_stg_ramdac.c b/src/video/vid_stg_ramdac.c index 187139b3b..85d492ce7 100644 --- a/src/video/vid_stg_ramdac.c +++ b/src/video/vid_stg_ramdac.c @@ -263,7 +263,7 @@ const device_t stg_ramdac_device = { .init = stg_ramdac_init, .close = stg_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 9ec7e6105..efab288de 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -3382,9 +3382,7 @@ static const device_config_t tgui9440_config[] = { }, .default_int = 2 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t tgui96xx_config[] = { @@ -3411,9 +3409,7 @@ static const device_config_t tgui96xx_config[] = { }, .default_int = 4 }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -3425,7 +3421,7 @@ const device_t tgui9400cxi_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = tgui9400cxi_available }, + .available = tgui9400cxi_available, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui9440_config @@ -3439,7 +3435,7 @@ const device_t tgui9440_vlb_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = tgui9440_vlb_available }, + .available = tgui9440_vlb_available, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui9440_config @@ -3453,7 +3449,7 @@ const device_t tgui9440_pci_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = tgui9440_pci_available }, + .available = tgui9440_pci_available, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui9440_config @@ -3467,7 +3463,7 @@ const device_t tgui9440_onboard_pci_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui9440_config @@ -3481,7 +3477,7 @@ const device_t tgui9660_pci_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = tgui96xx_available }, + .available = tgui96xx_available, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui96xx_config @@ -3495,7 +3491,7 @@ const device_t tgui9660_onboard_pci_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui96xx_config @@ -3509,7 +3505,7 @@ const device_t tgui9680_pci_device = { .init = tgui_init, .close = tgui_close, .reset = NULL, - { .available = tgui96xx_available }, + .available = tgui96xx_available, .speed_changed = tgui_speed_changed, .force_redraw = tgui_force_redraw, .config = tgui96xx_config diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index f23cb7396..fcc046cb4 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -266,7 +266,7 @@ const device_t ibm_ps1_2121_device = { .init = vid_init, .close = vid_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vid_speed_changed, .force_redraw = vid_force_redraw, .config = NULL diff --git a/src/video/vid_tkd8001_ramdac.c b/src/video/vid_tkd8001_ramdac.c index 4108b9a4e..c8ad1c421 100644 --- a/src/video/vid_tkd8001_ramdac.c +++ b/src/video/vid_tkd8001_ramdac.c @@ -129,7 +129,7 @@ const device_t tkd8001_ramdac_device = { .init = tkd8001_ramdac_init, .close = tkd8001_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index eb0d1a780..9f329a604 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -544,78 +544,76 @@ static const device_config_t tvga_config[] = { } } }, - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format off }; const device_t tvga8900b_device = { - .name = "Trident TVGA 8900B", + .name = "Trident TVGA 8900B", .internal_name = "tvga8900b", - .flags = DEVICE_ISA, - .local = TVGA8900B_ID, - .init = tvga_init, - .close = tvga_close, - .reset = NULL, - { .available = tvga8900b_available }, + .flags = DEVICE_ISA, + .local = TVGA8900B_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + .available = tvga8900b_available, .speed_changed = tvga_speed_changed, - .force_redraw = tvga_force_redraw, - .config = tvga_config + .force_redraw = tvga_force_redraw, + .config = tvga_config }; const device_t tvga8900d_device = { - .name = "Trident TVGA 8900D", + .name = "Trident TVGA 8900D", .internal_name = "tvga8900d", - .flags = DEVICE_ISA, - .local = TVGA8900CLD_ID, - .init = tvga_init, - .close = tvga_close, - .reset = NULL, - { .available = tvga8900d_available }, + .flags = DEVICE_ISA, + .local = TVGA8900CLD_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + .available = tvga8900d_available, .speed_changed = tvga_speed_changed, - .force_redraw = tvga_force_redraw, - .config = tvga_config + .force_redraw = tvga_force_redraw, + .config = tvga_config }; const device_t tvga8900dr_device = { - .name = "Trident TVGA 8900D-R", + .name = "Trident TVGA 8900D-R", .internal_name = "tvga8900dr", - .flags = DEVICE_ISA, - .local = TVGA8900CLD_ID | 0x0100, - .init = tvga_init, - .close = tvga_close, - .reset = NULL, - { .available = tvga8900dr_available }, + .flags = DEVICE_ISA, + .local = TVGA8900CLD_ID | 0x0100, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + .available = tvga8900dr_available, .speed_changed = tvga_speed_changed, - .force_redraw = tvga_force_redraw, - .config = tvga_config + .force_redraw = tvga_force_redraw, + .config = tvga_config }; const device_t tvga9000b_device = { - .name = "Trident TVGA 9000B", + .name = "Trident TVGA 9000B", .internal_name = "tvga9000b", - .flags = DEVICE_ISA, - .local = TVGA9000B_ID, - .init = tvga_init, - .close = tvga_close, - .reset = NULL, - { .available = tvga9000b_available }, + .flags = DEVICE_ISA, + .local = TVGA9000B_ID, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + .available = tvga9000b_available, .speed_changed = tvga_speed_changed, - .force_redraw = tvga_force_redraw, - .config = NULL + .force_redraw = tvga_force_redraw, + .config = NULL }; const device_t nec_sv9000_device = { - .name = "NEC SV9000 (Trident TVGA 9000B)", + .name = "NEC SV9000 (Trident TVGA 9000B)", .internal_name = "nec_sv9000", - .flags = DEVICE_ISA, - .local = TVGA9000B_ID | 0x100, - .init = tvga_init, - .close = tvga_close, - .reset = NULL, - { .available = tvga9000b_nec_sv9000_available }, + .flags = DEVICE_ISA, + .local = TVGA9000B_ID | 0x100, + .init = tvga_init, + .close = tvga_close, + .reset = NULL, + .available = tvga9000b_nec_sv9000_available, .speed_changed = tvga_speed_changed, - .force_redraw = tvga_force_redraw, - .config = NULL + .force_redraw = tvga_force_redraw, + .config = NULL }; diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/vid_tvp3026_ramdac.c index 6c001b461..bd5a83fd0 100644 --- a/src/video/vid_tvp3026_ramdac.c +++ b/src/video/vid_tvp3026_ramdac.c @@ -733,7 +733,7 @@ const device_t tvp3026_ramdac_device = { .init = tvp3026_ramdac_init, .close = tvp3026_ramdac_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 881a3c6fd..ad66192ac 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -194,7 +194,7 @@ const device_t vga_device = { .init = vga_init, .close = vga_close, .reset = NULL, - { .available = vga_available }, + .available = vga_available, .speed_changed = vga_speed_changed, .force_redraw = vga_force_redraw, .config = NULL @@ -208,7 +208,7 @@ const device_t ps1vga_device = { .init = ps1vga_init, .close = vga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vga_speed_changed, .force_redraw = vga_force_redraw, .config = NULL @@ -222,7 +222,7 @@ const device_t ps1vga_mca_device = { .init = ps1vga_init, .close = vga_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = vga_speed_changed, .force_redraw = vga_force_redraw, .config = NULL diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index a9981333b..bf3b63736 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -1423,9 +1423,7 @@ static const device_config_t voodoo_config[] = { .default_int = 1 }, #endif - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; @@ -1437,7 +1435,7 @@ const device_t voodoo_device = { .init = voodoo_init, .close = voodoo_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = voodoo_speed_changed, .force_redraw = voodoo_force_blit, .config = voodoo_config diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 4fa27e2e4..93b557fec 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -3228,9 +3228,7 @@ static const device_config_t banshee_sgram_config[] = { .default_int = 1 }, #endif - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t banshee_sgram_16mbonly_config[] = { @@ -3283,9 +3281,7 @@ static const device_config_t banshee_sgram_16mbonly_config[] = { .default_int = 1 }, #endif - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t banshee_sdram_config[] = { @@ -3338,9 +3334,7 @@ static const device_config_t banshee_sdram_config[] = { .default_int = 1 }, #endif - { - .type = CONFIG_END - } + { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on @@ -3743,7 +3737,7 @@ const device_t voodoo_banshee_device = { .init = banshee_init, .close = banshee_close, .reset = NULL, - { .available = banshee_available }, + .available = banshee_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sgram_config @@ -3757,7 +3751,7 @@ const device_t creative_voodoo_banshee_device = { .init = creative_banshee_init, .close = banshee_close, .reset = NULL, - { .available = creative_banshee_available }, + .available = creative_banshee_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3771,7 +3765,7 @@ const device_t voodoo_3_1000_device = { .init = v3_1000_init, .close = banshee_close, .reset = NULL, - { .available = v3_1000_available }, + .available = v3_1000_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sgram_config @@ -3785,7 +3779,7 @@ const device_t voodoo_3_1000_agp_device = { .init = v3_1000_agp_init, .close = banshee_close, .reset = NULL, - { .available = v3_1000_agp_available }, + .available = v3_1000_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sgram_16mbonly_config @@ -3799,7 +3793,7 @@ const device_t voodoo_3_2000_device = { .init = v3_2000_init, .close = banshee_close, .reset = NULL, - { .available = v3_2000_available }, + .available = v3_2000_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3813,7 +3807,7 @@ const device_t voodoo_3_2000_agp_device = { .init = v3_2000_agp_init, .close = banshee_close, .reset = NULL, - { .available = v3_2000_agp_available }, + .available = v3_2000_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3827,7 +3821,7 @@ const device_t voodoo_3_2000_agp_onboard_8m_device = { .init = v3_2000_agp_onboard_init, .close = banshee_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sgram_config @@ -3841,7 +3835,7 @@ const device_t voodoo_3_3000_device = { .init = v3_3000_init, .close = banshee_close, .reset = NULL, - { .available = v3_3000_available }, + .available = v3_3000_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3855,7 +3849,7 @@ const device_t voodoo_3_3000_agp_device = { .init = v3_3000_agp_init, .close = banshee_close, .reset = NULL, - { .available = v3_3000_agp_available }, + .available = v3_3000_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3869,7 +3863,7 @@ const device_t voodoo_3_3500_agp_ntsc_device = { .init = v3_3500_agp_ntsc_init, .close = banshee_close, .reset = NULL, - { .available = v3_3500_agp_ntsc_available }, + .available = v3_3500_agp_ntsc_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3883,7 +3877,7 @@ const device_t voodoo_3_3500_agp_pal_device = { .init = v3_3500_agp_pal_init, .close = banshee_close, .reset = NULL, - { .available = v3_3500_agp_pal_available }, + .available = v3_3500_agp_pal_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3897,7 +3891,7 @@ const device_t compaq_voodoo_3_3500_agp_device = { .init = compaq_v3_3500_agp_init, .close = banshee_close, .reset = NULL, - { .available = compaq_v3_3500_agp_available }, + .available = compaq_v3_3500_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3911,7 +3905,7 @@ const device_t voodoo_3_3500_se_agp_device = { .init = v3_3500_se_agp_init, .close = banshee_close, .reset = NULL, - { .available = v3_3500_se_agp_available }, + .available = v3_3500_se_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3925,7 +3919,7 @@ const device_t voodoo_3_3500_si_agp_device = { .init = v3_3500_si_agp_init, .close = banshee_close, .reset = NULL, - { .available = v3_3500_si_agp_available }, + .available = v3_3500_si_agp_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3939,7 +3933,7 @@ const device_t velocity_100_agp_device = { .init = velocity_100_agp_init, .close = banshee_close, .reset = NULL, - { .available = velocity_100_available }, + .available = velocity_100_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sdram_config @@ -3953,7 +3947,7 @@ const device_t velocity_200_agp_device = { .init = velocity_200_agp_init, .close = banshee_close, .reset = NULL, - { .available = velocity_200_available }, + .available = velocity_200_available, .speed_changed = banshee_speed_changed, .force_redraw = banshee_force_redraw, .config = banshee_sgram_16mbonly_config diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index 600fa21a8..a52bad4ee 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -1004,7 +1004,7 @@ const device_t wy700_device = { .init = wy700_init, .close = wy700_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = wy700_speed_changed, .force_redraw = NULL, .config = NULL diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 8bdc72fc6..862dbd1cf 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -3813,7 +3813,7 @@ const device_t xga_device = { .init = xga_init, .close = xga_close, .reset = xga_reset, - { .available = xga_available }, + .available = xga_available, .speed_changed = xga_speed_changed, .force_redraw = xga_force_redraw, .config = xga_mca_configuration @@ -3827,7 +3827,7 @@ const device_t xga_isa_device = { .init = xga_init, .close = xga_close, .reset = xga_reset, - { .available = xga_available }, + .available = xga_available, .speed_changed = xga_speed_changed, .force_redraw = xga_force_redraw, .config = xga_isa_configuration @@ -3841,7 +3841,7 @@ const device_t inmos_isa_device = { .init = svga_xga_init, .close = xga_close, .reset = xga_reset, - { .available = inmos_xga_available }, + .available = inmos_xga_available, .speed_changed = xga_speed_changed, .force_redraw = xga_force_redraw, .config = xga_inmos_isa_configuration From 4e6f29a7d585452bdede8c4ee866adf5f015ced2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 7 Jan 2025 00:42:06 -0500 Subject: [PATCH 0181/1190] malloc to calloc --- src/chipset/82c100.c | 3 +-- src/chipset/acc2168.c | 3 +-- src/chipset/ali1409.c | 3 +-- src/chipset/ali1429.c | 3 +-- src/chipset/ali1435.c | 3 +-- src/chipset/ali1489.c | 3 +-- src/chipset/ali1531.c | 3 +-- src/chipset/ali1541.c | 3 +-- src/chipset/ali1543.c | 3 +-- src/chipset/ali1621.c | 3 +-- src/chipset/ali6117.c | 3 +-- src/chipset/contaq_82c59x.c | 3 +-- src/chipset/cs4031.c | 3 +-- src/chipset/cs8230.c | 3 +-- src/chipset/et6000.c | 3 +-- src/chipset/gc100.c | 3 +-- src/chipset/headland.c | 3 +-- src/chipset/ims8848.c | 3 +-- src/chipset/intel_420ex.c | 3 +-- src/chipset/intel_4x0.c | 4 +--- src/chipset/intel_82335.c | 3 +-- src/chipset/intel_i450kx.c | 4 ++-- src/chipset/intel_piix.c | 3 +-- src/chipset/intel_sio.c | 3 +-- src/chipset/neat.c | 3 +-- src/chipset/olivetti_eva.c | 3 +-- src/chipset/opti283.c | 3 +-- src/chipset/opti291.c | 3 +-- src/chipset/opti495.c | 3 +-- src/chipset/opti499.c | 3 +-- src/chipset/opti5x7.c | 3 +-- src/chipset/opti822.c | 3 +-- src/chipset/opti895.c | 3 +-- src/chipset/scamp.c | 3 +-- src/chipset/scat.c | 3 +-- src/chipset/sis_5571_old.c | 3 +-- src/chipset/sis_85c310.c | 3 +-- src/chipset/sis_85c496.c | 3 +-- src/chipset/sis_85c4xx.c | 3 +-- src/chipset/stpc.c | 9 +++----- src/chipset/umc_8886.c | 3 +-- src/chipset/umc_hb4.c | 3 +-- src/chipset/via_apollo.c | 3 +-- src/chipset/via_pipc.c | 3 +-- src/chipset/via_vt82c49x.c | 3 +-- src/chipset/via_vt82c505.c | 5 ++-- src/chipset/vl82c480.c | 3 +-- src/chipset/wd76c10.c | 2 +- src/device/cartridge.c | 6 ++--- src/device/cassette.c | 4 +--- src/device/clock_ics9xxx.c | 6 ++--- src/device/hasp.c | 3 +-- src/device/hwm_gl518sm.c | 3 +-- src/device/hwm_lm75.c | 3 +-- src/device/hwm_lm78.c | 3 +-- src/device/hwm_vt82c686.c | 3 +-- src/device/i2c.c | 6 ++--- src/device/i2c_gpio.c | 3 +-- src/device/isamem.c | 3 +-- src/device/isapnp.c | 5 ++-- src/device/isartc.c | 3 +-- src/device/kbc_at.c | 6 ++--- src/device/keyboard_xt.c | 3 +-- src/device/mouse_bus.c | 3 +-- src/device/mouse_microtouch_touchscreen.c | 3 +-- src/device/mouse_serial.c | 3 +-- src/device/pci_bridge.c | 3 +-- src/device/phoenix_486_jumper.c | 3 +-- src/device/serial.c | 3 +-- src/device/serial_passthrough.c | 3 +-- src/device/smbus_ali7101.c | 2 +- src/device/smbus_piix4.c | 3 +-- src/device/smbus_sis5595.c | 3 +-- src/disk/hdc_esdi_at.c | 3 +-- src/disk/hdc_esdi_mca.c | 3 +-- src/disk/hdc_ide_cmd640.c | 3 +-- src/disk/hdc_ide_cmd646.c | 3 +-- src/disk/hdc_ide_opti611.c | 3 +-- src/disk/hdc_ide_sff8038i.c | 3 +-- src/disk/hdc_ide_w83769f.c | 3 +-- src/disk/hdc_st506_at.c | 3 +-- src/disk/hdc_st506_xt.c | 3 +-- src/disk/hdc_xta.c | 3 +-- src/disk/hdc_xtide.c | 28 ++++++++--------------- src/floppy/fdc.c | 3 +-- src/floppy/fdc_magitronic.c | 3 +-- src/floppy/fdc_monster.c | 2 +- src/floppy/fdc_pii15xb.c | 3 +-- src/floppy/fdd_86f.c | 6 ++--- src/floppy/fdd_fdi.c | 4 +--- src/floppy/fdd_imd.c | 3 +-- src/floppy/fdd_img.c | 3 +-- src/floppy/fdd_mfm.c | 3 +-- src/floppy/fdd_pcjs.c | 3 +-- src/floppy/fdd_td0.c | 3 +-- src/game/gameport.c | 8 ++----- src/machine/m_amstrad.c | 12 ++++------ src/machine/m_at_compaq.c | 3 +-- src/machine/m_at_t3100e_vid.c | 3 +-- src/machine/m_pcjr.c | 3 +-- src/machine/m_ps1.c | 3 +-- src/machine/m_ps1_hdc.c | 3 +-- src/machine/m_ps2_isa.c | 3 +-- src/machine/m_tandy.c | 6 ++--- src/machine/m_xt_olivetti.c | 15 ++++-------- src/machine/m_xt_t1000_vid.c | 3 +-- src/machine/m_xt_zenith.c | 3 +-- src/mem/catalyst_flash.c | 3 +-- src/mem/i2c_eeprom.c | 3 +-- src/mem/intel_flash.c | 3 +-- src/mem/smram.c | 5 ++-- src/mem/spd.c | 3 +-- src/mem/sst_flash.c | 3 +-- src/network/net_3c501.c | 3 +-- src/network/net_3c503.c | 3 +-- src/network/net_dp8390.c | 6 ++--- src/network/net_ne2000.c | 6 ++--- src/network/net_pcnet.c | 3 +-- src/network/net_plip.c | 3 +-- src/network/net_slirp.c | 5 ++-- src/network/net_wd8003.c | 3 +-- src/nvr_ps2.c | 3 +-- src/printer/prt_escp.c | 5 ++-- src/printer/prt_ps.c | 9 +++----- src/printer/prt_text.c | 6 ++--- src/qt/win_opendir.c | 6 ++--- src/scsi/scsi_aha154x.c | 3 +-- src/scsi/scsi_buslogic.c | 3 +-- src/scsi/scsi_ncr53c400.c | 8 ++----- src/scsi/scsi_ncr53c8xx.c | 5 +--- src/scsi/scsi_pcscsi.c | 10 ++------ src/scsi/scsi_spock.c | 3 +-- src/scsi/scsi_t128.c | 8 ++----- src/scsi/scsi_x54x.c | 18 +++++---------- src/sio/sio_82091aa.c | 3 +-- src/sio/sio_acc3221.c | 3 +-- src/sio/sio_ali5123.c | 3 +-- src/sio/sio_detect.c | 3 +-- src/sio/sio_f82c710.c | 3 +-- src/sio/sio_fdc37c669.c | 3 +-- src/sio/sio_fdc37c67x.c | 3 +-- src/sio/sio_fdc37c6xx.c | 3 +-- src/sio/sio_fdc37c93x.c | 6 ++--- src/sio/sio_fdc37m60x.c | 3 +-- src/sio/sio_it86x1f.c | 3 +-- src/sio/sio_pc87306.c | 3 +-- src/sio/sio_pc87307.c | 3 +-- src/sio/sio_pc87309.c | 3 +-- src/sio/sio_pc87311.c | 3 +-- src/sio/sio_pc87332.c | 3 +-- src/sio/sio_prime3b.c | 3 +-- src/sio/sio_prime3c.c | 3 +-- src/sio/sio_um8669f.c | 3 +-- src/sio/sio_vt82c686.c | 3 +-- src/sio/sio_w83787f.c | 3 +-- src/sio/sio_w83877f.c | 3 +-- src/sio/sio_w83977f.c | 3 +-- src/sound/midi.c | 9 +++----- src/sound/midi_fluidsynth.c | 3 +-- src/sound/midi_mt32.c | 3 +-- src/sound/midi_opl4.c | 3 +-- src/sound/midi_rtmidi.cpp | 6 ++--- src/sound/snd_ac97_codec.c | 3 +-- src/sound/snd_ac97_via.c | 3 +-- src/sound/snd_adlib.c | 3 +-- src/sound/snd_adlibgold.c | 3 +-- src/sound/snd_audiopci.c | 6 ++--- src/sound/snd_azt2316a.c | 9 +++----- src/sound/snd_cmi8x38.c | 3 +-- src/sound/snd_cms.c | 3 +-- src/sound/snd_cs423x.c | 6 ++--- src/sound/snd_emu8k.c | 6 ++--- src/sound/snd_gus.c | 6 ++--- src/sound/snd_lpt_dac.c | 3 +-- src/sound/snd_lpt_dss.c | 3 +-- src/sound/snd_opl2board.c | 3 +-- src/sound/snd_optimc.c | 3 +-- src/sound/snd_pas16.c | 3 +-- src/sound/snd_ps1.c | 3 +-- src/sound/snd_pssj.c | 9 +++----- src/sound/snd_sn76489.c | 9 +++----- src/sound/snd_ssi2001.c | 9 +++----- src/sound/snd_wss.c | 6 ++--- 183 files changed, 245 insertions(+), 493 deletions(-) diff --git a/src/chipset/82c100.c b/src/chipset/82c100.c index 05c3522d8..a9d61b3b9 100644 --- a/src/chipset/82c100.c +++ b/src/chipset/82c100.c @@ -358,8 +358,7 @@ ct_82c100_init(UNUSED(const device_t *info)) { ct_82c100_t *dev; - dev = (ct_82c100_t *) malloc(sizeof(ct_82c100_t)); - memset(dev, 0x00, sizeof(ct_82c100_t)); + dev = (ct_82c100_t *) calloc(1, sizeof(ct_82c100_t)); ct_82c100_reset(dev); diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c index 982f50e82..dbbdc99f6 100644 --- a/src/chipset/acc2168.c +++ b/src/chipset/acc2168.c @@ -184,8 +184,7 @@ acc2168_close(void *priv) static void * acc2168_init(UNUSED(const device_t *info)) { - acc2168_t *dev = (acc2168_t *) malloc(sizeof(acc2168_t)); - memset(dev, 0, sizeof(acc2168_t)); + acc2168_t *dev = (acc2168_t *) calloc(1, sizeof(acc2168_t)); device_add(&port_92_device); io_sethandler(0x00f2, 0x0002, acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev); diff --git a/src/chipset/ali1409.c b/src/chipset/ali1409.c index 8cda1a22b..5644d4077 100644 --- a/src/chipset/ali1409.c +++ b/src/chipset/ali1409.c @@ -163,8 +163,7 @@ ali1409_close(void *priv) static void * ali1409_init(const device_t *info) { - ali1409_t *dev = (ali1409_t *) malloc(sizeof(ali1409_t)); - memset(dev, 0, sizeof(ali1409_t)); + ali1409_t *dev = (ali1409_t *) calloc(1, sizeof(ali1409_t)); dev->cfg_locked = 1; diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c index 4a6a5cfa9..e2478078f 100644 --- a/src/chipset/ali1429.c +++ b/src/chipset/ali1429.c @@ -331,8 +331,7 @@ ali1429_defaults(ali1429_t *dev) static void * ali1429_init(const device_t *info) { - ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t)); - memset(dev, 0, sizeof(ali1429_t)); + ali1429_t *dev = (ali1429_t *) calloc(1, sizeof(ali1429_t)); dev->cfg_locked = 1; GREEN = info->local; diff --git a/src/chipset/ali1435.c b/src/chipset/ali1435.c index 8360267c9..ff096ac55 100644 --- a/src/chipset/ali1435.c +++ b/src/chipset/ali1435.c @@ -282,8 +282,7 @@ ali1435_close(void *priv) static void * ali1435_init(UNUSED(const device_t *info)) { - ali1435_t *dev = (ali1435_t *) malloc(sizeof(ali1435_t)); - memset(dev, 0, sizeof(ali1435_t)); + ali1435_t *dev = (ali1435_t *) calloc(1, sizeof(ali1435_t)); dev->cfg_locked = 1; diff --git a/src/chipset/ali1489.c b/src/chipset/ali1489.c index c61dd1511..fc51bbed2 100644 --- a/src/chipset/ali1489.c +++ b/src/chipset/ali1489.c @@ -470,8 +470,7 @@ ali1489_close(void *priv) static void * ali1489_init(UNUSED(const device_t *info)) { - ali1489_t *dev = (ali1489_t *) malloc(sizeof(ali1489_t)); - memset(dev, 0, sizeof(ali1489_t)); + ali1489_t *dev = (ali1489_t *) calloc(1, sizeof(ali1489_t)); /* M1487/M1489 22h Index Port diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index 1ff0689ad..e765e6d45 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -369,8 +369,7 @@ ali1531_close(void *priv) static void * ali1531_init(UNUSED(const device_t *info)) { - ali1531_t *dev = (ali1531_t *) malloc(sizeof(ali1531_t)); - memset(dev, 0, sizeof(ali1531_t)); + ali1531_t *dev = (ali1531_t *) calloc(1, sizeof(ali1531_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, ali1531_read, ali1531_write, dev, &dev->pci_slot); diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c index 3d7c1c546..eed6ddbc5 100644 --- a/src/chipset/ali1541.c +++ b/src/chipset/ali1541.c @@ -643,8 +643,7 @@ ali1541_close(void *priv) static void * ali1541_init(UNUSED(const device_t *info)) { - ali1541_t *dev = (ali1541_t *) malloc(sizeof(ali1541_t)); - memset(dev, 0, sizeof(ali1541_t)); + ali1541_t *dev = (ali1541_t *) calloc(1, sizeof(ali1541_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, ali1541_read, ali1541_write, dev, &dev->pci_slot); diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 2b9c93cb4..69a8990e9 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -1599,8 +1599,7 @@ ali1543_close(void *priv) static void * ali1543_init(const device_t *info) { - ali1543_t *dev = (ali1543_t *) malloc(sizeof(ali1543_t)); - memset(dev, 0, sizeof(ali1543_t)); + ali1543_t *dev = (ali1543_t *) calloc(1, sizeof(ali1543_t)); /* Device 02: M1533 Southbridge */ pci_add_card(PCI_ADD_SOUTHBRIDGE, ali1533_read, ali1533_write, dev, &dev->pci_slot); diff --git a/src/chipset/ali1621.c b/src/chipset/ali1621.c index 96748ce34..d44c0f5a9 100644 --- a/src/chipset/ali1621.c +++ b/src/chipset/ali1621.c @@ -669,8 +669,7 @@ ali1621_close(void *priv) static void * ali1621_init(UNUSED(const device_t *info)) { - ali1621_t *dev = (ali1621_t *) malloc(sizeof(ali1621_t)); - memset(dev, 0, sizeof(ali1621_t)); + ali1621_t *dev = (ali1621_t *) calloc(1, sizeof(ali1621_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, ali1621_read, ali1621_write, dev, &dev->pci_slot); diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index 2d66ba9d1..c351a0cfa 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -466,8 +466,7 @@ ali6117_init(const device_t *info) ali6117_log("ALI6117: init()\n"); - ali6117_t *dev = (ali6117_t *) malloc(sizeof(ali6117_t)); - memset(dev, 0, sizeof(ali6117_t)); + ali6117_t *dev = (ali6117_t *) calloc(1, sizeof(ali6117_t)); dev->local = info->local; diff --git a/src/chipset/contaq_82c59x.c b/src/chipset/contaq_82c59x.c index 90667c42f..1981fd11c 100644 --- a/src/chipset/contaq_82c59x.c +++ b/src/chipset/contaq_82c59x.c @@ -322,8 +322,7 @@ contaq_82c59x_close(void *priv) static void * contaq_82c59x_init(const device_t *info) { - contaq_82c59x_t *dev = (contaq_82c59x_t *) malloc(sizeof(contaq_82c59x_t)); - memset(dev, 0x00, sizeof(contaq_82c59x_t)); + contaq_82c59x_t *dev = (contaq_82c59x_t *) calloc(1, sizeof(contaq_82c59x_t)); dev->green = info->local; diff --git a/src/chipset/cs4031.c b/src/chipset/cs4031.c index b482fa254..cfec9ad30 100644 --- a/src/chipset/cs4031.c +++ b/src/chipset/cs4031.c @@ -164,8 +164,7 @@ cs4031_close(void *priv) static void * cs4031_init(UNUSED(const device_t *info)) { - cs4031_t *dev = (cs4031_t *) malloc(sizeof(cs4031_t)); - memset(dev, 0, sizeof(cs4031_t)); + cs4031_t *dev = (cs4031_t *) calloc(1, sizeof(cs4031_t)); dev->port_92 = device_add(&port_92_device); diff --git a/src/chipset/cs8230.c b/src/chipset/cs8230.c index 62852b88d..0374a44a6 100644 --- a/src/chipset/cs8230.c +++ b/src/chipset/cs8230.c @@ -157,8 +157,7 @@ cs8230_close(void *priv) static void * cs8230_init(UNUSED(const device_t *info)) { - cs8230_t *cs8230 = (cs8230_t *) malloc(sizeof(cs8230_t)); - memset(cs8230, 0, sizeof(cs8230_t)); + cs8230_t *cs8230 = (cs8230_t *) calloc(1, sizeof(cs8230_t)); io_sethandler(0x0022, 0x0002, cs8230_read, NULL, NULL, cs8230_write, NULL, NULL, cs8230); diff --git a/src/chipset/et6000.c b/src/chipset/et6000.c index 608f2cc9b..14ebf852e 100644 --- a/src/chipset/et6000.c +++ b/src/chipset/et6000.c @@ -137,8 +137,7 @@ et6000_close(void *priv) static void * et6000_init(UNUSED(const device_t *info)) { - et6000_t *dev = (et6000_t *) malloc(sizeof(et6000_t)); - memset(dev, 0, sizeof(et6000_t)); + et6000_t *dev = (et6000_t *) calloc(1, sizeof(et6000_t)); /* Port 92h */ device_add(&port_92_device); diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c index fc2321fae..23455b952 100644 --- a/src/chipset/gc100.c +++ b/src/chipset/gc100.c @@ -208,8 +208,7 @@ gc100_close(void *priv) static void * gc100_init(const device_t *info) { - gc100_t *dev = (gc100_t *) malloc(sizeof(gc100_t)); - memset(dev, 0, sizeof(gc100_t)); + gc100_t *dev = (gc100_t *) calloc(1, sizeof(gc100_t)); dev->reg[0x2] = 0xff; dev->reg[0x3] = 0x0; diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 9d7cf97c7..1172d105d 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -594,8 +594,7 @@ headland_init(const device_t *info) headland_t *dev; int ht386 = 0; - dev = (headland_t *) malloc(sizeof(headland_t)); - memset(dev, 0x00, sizeof(headland_t)); + dev = (headland_t *) calloc(1, sizeof(headland_t)); dev->has_cri = (info->local & HEADLAND_HAS_CRI); dev->has_sleep = (info->local & HEADLAND_HAS_SLEEP); diff --git a/src/chipset/ims8848.c b/src/chipset/ims8848.c index 0ce3a5e44..094ee31f8 100644 --- a/src/chipset/ims8848.c +++ b/src/chipset/ims8848.c @@ -381,8 +381,7 @@ ims8848_close(void *priv) static void * ims8848_init(UNUSED(const device_t *info)) { - ims8848_t *dev = (ims8848_t *) malloc(sizeof(ims8848_t)); - memset(dev, 0, sizeof(ims8848_t)); + ims8848_t *dev = (ims8848_t *) calloc(1, sizeof(ims8848_t)); device_add(&port_92_device); diff --git a/src/chipset/intel_420ex.c b/src/chipset/intel_420ex.c index 7b069cce3..662fd0509 100644 --- a/src/chipset/intel_420ex.c +++ b/src/chipset/intel_420ex.c @@ -533,8 +533,7 @@ i420ex_speed_changed(void *priv) static void * i420ex_init(const device_t *info) { - i420ex_t *dev = (i420ex_t *) malloc(sizeof(i420ex_t)); - memset(dev, 0, sizeof(i420ex_t)); + i420ex_t *dev = (i420ex_t *) calloc(1, sizeof(i420ex_t)); dev->smram = smram_add(); diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 36303deb7..f9d6af150 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -1608,11 +1608,9 @@ i4x0_close(void *priv) static void * i4x0_init(const device_t *info) { - i4x0_t *dev = (i4x0_t *) malloc(sizeof(i4x0_t)); + i4x0_t *dev = (i4x0_t *) calloc(1, sizeof(i4x0_t)); uint8_t *regs; - memset(dev, 0, sizeof(i4x0_t)); - dev->smram_low = smram_add(); dev->smram_high = smram_add(); diff --git a/src/chipset/intel_82335.c b/src/chipset/intel_82335.c index cc7f07c3a..bd53e0d05 100644 --- a/src/chipset/intel_82335.c +++ b/src/chipset/intel_82335.c @@ -171,8 +171,7 @@ intel_82335_close(void *priv) static void * intel_82335_init(UNUSED(const device_t *info)) { - intel_82335_t *dev = (intel_82335_t *) malloc(sizeof(intel_82335_t)); - memset(dev, 0, sizeof(intel_82335_t)); + intel_82335_t *dev = (intel_82335_t *) calloc(1, sizeof(intel_82335_t)); memset(dev->regs, 0, sizeof(dev->regs)); diff --git a/src/chipset/intel_i450kx.c b/src/chipset/intel_i450kx.c index 1dfd6f315..34cc6a62f 100644 --- a/src/chipset/intel_i450kx.c +++ b/src/chipset/intel_i450kx.c @@ -799,8 +799,8 @@ i450kx_close(void *priv) static void * i450kx_init(UNUSED(const device_t *info)) { - i450kx_t *dev = (i450kx_t *) malloc(sizeof(i450kx_t)); - memset(dev, 0, sizeof(i450kx_t)); + i450kx_t *dev = (i450kx_t *) calloc(1, sizeof(i450kx_t)); + pci_add_card(PCI_ADD_NORTHBRIDGE, pb_read, pb_write, dev, &dev->pb_slot); /* Device 19h: Intel 450KX PCI Bridge PB */ pci_add_card(PCI_ADD_NORTHBRIDGE_SEC, mc_read, mc_write, dev, &dev->mc_slot); /* Device 14h: Intel 450KX Memory Controller MC */ diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index e52492df9..6969d3274 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1538,8 +1538,7 @@ piix_speed_changed(void *priv) static void * piix_init(const device_t *info) { - piix_t *dev = (piix_t *) malloc(sizeof(piix_t)); - memset(dev, 0, sizeof(piix_t)); + piix_t *dev = (piix_t *) calloc(1, sizeof(piix_t)); dev->type = info->local & 0x0f; /* If (dev->type == 4) and (dev->rev & 0x08), then this is PIIX4E. */ diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index c66b5ce04..9b6d28ab1 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -508,8 +508,7 @@ sio_speed_changed(void *priv) static void * sio_init(const device_t *info) { - sio_t *dev = (sio_t *) malloc(sizeof(sio_t)); - memset(dev, 0, sizeof(sio_t)); + sio_t *dev = (sio_t *) calloc(1, sizeof(sio_t)); pci_add_card(PCI_ADD_SOUTHBRIDGE, sio_read, sio_write, dev, &dev->pci_slot); diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 6f7dc5be3..069fa87e4 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -906,8 +906,7 @@ neat_init(UNUSED(const device_t *info)) uint8_t j; /* Create an instance. */ - dev = (neat_t *) malloc(sizeof(neat_t)); - memset(dev, 0x00, sizeof(neat_t)); + dev = (neat_t *) calloc(1, sizeof(neat_t)); /* Get configured I/O address. */ j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; diff --git a/src/chipset/olivetti_eva.c b/src/chipset/olivetti_eva.c index bdb5440c9..7defac6ae 100644 --- a/src/chipset/olivetti_eva.c +++ b/src/chipset/olivetti_eva.c @@ -134,8 +134,7 @@ olivetti_eva_close(void *priv) static void * olivetti_eva_init(UNUSED(const device_t *info)) { - olivetti_eva_t *dev = (olivetti_eva_t *) malloc(sizeof(olivetti_eva_t)); - memset(dev, 0, sizeof(olivetti_eva_t)); + olivetti_eva_t *dev = (olivetti_eva_t *) calloc(1, sizeof(olivetti_eva_t)); /* GA98 registers */ dev->reg_065 = 0x00; diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index b708eb0ab..395ad4212 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -284,8 +284,7 @@ opti283_close(void *priv) static void * opti283_init(UNUSED(const device_t *info)) { - opti283_t *dev = (opti283_t *) malloc(sizeof(opti283_t)); - memset(dev, 0x00, sizeof(opti283_t)); + opti283_t *dev = (opti283_t *) calloc(1, sizeof(opti283_t)); io_sethandler(0x0022, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); io_sethandler(0x0023, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); diff --git a/src/chipset/opti291.c b/src/chipset/opti291.c index 0ff037434..91b9010e2 100644 --- a/src/chipset/opti291.c +++ b/src/chipset/opti291.c @@ -138,8 +138,7 @@ opti291_close(void *priv) static void * opti291_init(UNUSED(const device_t *info)) { - opti291_t *dev = (opti291_t *) malloc(sizeof(opti291_t)); - memset(dev, 0, sizeof(opti291_t)); + opti291_t *dev = (opti291_t *) calloc(1, sizeof(opti291_t)); io_sethandler(0x022, 0x0001, opti291_read, NULL, NULL, opti291_write, NULL, NULL, dev); io_sethandler(0x024, 0x0001, opti291_read, NULL, NULL, opti291_write, NULL, NULL, dev); diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index f53ae0899..aa4e4b4c5 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -219,8 +219,7 @@ opti495_close(void *priv) static void * opti495_init(const device_t *info) { - opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t)); - memset(dev, 0, sizeof(opti495_t)); + opti495_t *dev = (opti495_t *) calloc(1, sizeof(opti495_t)); device_add(&port_92_device); diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index 81c5bee5a..d54e8184e 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -242,8 +242,7 @@ opti499_close(void *priv) static void * opti499_init(UNUSED(const device_t *info)) { - opti499_t *dev = (opti499_t *) malloc(sizeof(opti499_t)); - memset(dev, 0, sizeof(opti499_t)); + opti499_t *dev = (opti499_t *) calloc(1, sizeof(opti499_t)); device_add(&port_92_device); diff --git a/src/chipset/opti5x7.c b/src/chipset/opti5x7.c index 015ffb9f4..03fde4173 100644 --- a/src/chipset/opti5x7.c +++ b/src/chipset/opti5x7.c @@ -172,8 +172,7 @@ opti5x7_close(void *priv) static void * opti5x7_init(const device_t *info) { - opti5x7_t *dev = (opti5x7_t *) malloc(sizeof(opti5x7_t)); - memset(dev, 0, sizeof(opti5x7_t)); + opti5x7_t *dev = (opti5x7_t *) calloc(1, sizeof(opti5x7_t)); dev->is_pci = info->local; diff --git a/src/chipset/opti822.c b/src/chipset/opti822.c index 9dd835412..471fbe393 100644 --- a/src/chipset/opti822.c +++ b/src/chipset/opti822.c @@ -394,8 +394,7 @@ opti822_close(void *priv) static void * opti822_init(UNUSED(const device_t *info)) { - opti822_t *dev = (opti822_t *) malloc(sizeof(opti822_t)); - memset(dev, 0, sizeof(opti822_t)); + opti822_t *dev = (opti822_t *) calloc(1, sizeof(opti822_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, opti822_pci_read, opti822_pci_write, dev, &dev->pci_slot); diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 4ce31c362..cb55ef2a7 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -259,8 +259,7 @@ opti895_close(void *priv) static void * opti895_init(const device_t *info) { - opti895_t *dev = (opti895_t *) malloc(sizeof(opti895_t)); - memset(dev, 0, sizeof(opti895_t)); + opti895_t *dev = (opti895_t *) calloc(1, sizeof(opti895_t)); device_add(&port_92_device); diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 6a38f4ec2..8e7892c2e 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -1046,8 +1046,7 @@ static void * scamp_init(UNUSED(const device_t *info)) { uint32_t addr; - scamp_t *dev = (scamp_t *) malloc(sizeof(scamp_t)); - memset(dev, 0x00, sizeof(scamp_t)); + scamp_t *dev = (scamp_t *) calloc(1, sizeof(scamp_t)); dev->cfg_regs[CFG_ID] = ID_VL82C311; dev->cfg_enable = 1; diff --git a/src/chipset/scat.c b/src/chipset/scat.c index edbaf41e3..43f93649e 100644 --- a/src/chipset/scat.c +++ b/src/chipset/scat.c @@ -1403,8 +1403,7 @@ scat_init(const device_t *info) uint32_t k; int sx; - dev = (scat_t *) malloc(sizeof(scat_t)); - memset(dev, 0x00, sizeof(scat_t)); + dev = (scat_t *) calloc(1, sizeof(scat_t)); dev->type = info->local; sx = (dev->type == 32) ? 1 : 0; diff --git a/src/chipset/sis_5571_old.c b/src/chipset/sis_5571_old.c index 422ed4bb8..495137aed 100644 --- a/src/chipset/sis_5571_old.c +++ b/src/chipset/sis_5571_old.c @@ -732,8 +732,7 @@ sis_5571_close(void *priv) static void * sis_5571_init(UNUSED(const device_t *info)) { - sis_5571_t *dev = (sis_5571_t *) malloc(sizeof(sis_5571_t)); - memset(dev, 0x00, sizeof(sis_5571_t)); + sis_5571_t *dev = (sis_5571_t *) calloc(1, sizeof(sis_5571_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, memory_pci_bridge_read, memory_pci_bridge_write, dev, &dev->nb_slot); pci_add_card(PCI_ADD_SOUTHBRIDGE, pci_isa_bridge_read, pci_isa_bridge_write, dev, &dev->sb_slot); diff --git a/src/chipset/sis_85c310.c b/src/chipset/sis_85c310.c index d62cc3b24..dfbd4b465 100644 --- a/src/chipset/sis_85c310.c +++ b/src/chipset/sis_85c310.c @@ -130,8 +130,7 @@ rabbit_close(void *priv) static void * rabbit_init(UNUSED(const device_t *info)) { - rabbit_t *dev = (rabbit_t *) malloc(sizeof(rabbit_t)); - memset(dev, 0, sizeof(rabbit_t)); + rabbit_t *dev = (rabbit_t *) calloc(1, sizeof(rabbit_t)); io_sethandler(0x0022, 0x0002, rabbit_read, NULL, NULL, rabbit_write, NULL, NULL, dev); diff --git a/src/chipset/sis_85c496.c b/src/chipset/sis_85c496.c index 5ba315822..10bccc1c8 100644 --- a/src/chipset/sis_85c496.c +++ b/src/chipset/sis_85c496.c @@ -637,8 +637,7 @@ static void * sis_85c496_init(const device_t *info) { - sis_85c496_t *dev = malloc(sizeof(sis_85c496_t)); - memset(dev, 0x00, sizeof(sis_85c496_t)); + sis_85c496_t *dev = calloc(1, sizeof(sis_85c496_t)); dev->smram = smram_add(); diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 1f98ee8a6..6e26a4751 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -368,8 +368,7 @@ sis_85c4xx_close(void *priv) static void * sis_85c4xx_init(const device_t *info) { - sis_85c4xx_t *dev = (sis_85c4xx_t *) malloc(sizeof(sis_85c4xx_t)); - memset(dev, 0, sizeof(sis_85c4xx_t)); + sis_85c4xx_t *dev = (sis_85c4xx_t *) calloc(1, sizeof(sis_85c4xx_t)); dev->is_471 = (info->local >> 8) & 0xff; diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 3bb3a7c2a..23cc56bd3 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -912,8 +912,7 @@ stpc_init(const device_t *info) { stpc_log("STPC: init()\n"); - stpc_t *dev = (stpc_t *) malloc(sizeof(stpc_t)); - memset(dev, 0, sizeof(stpc_t)); + stpc_t *dev = (stpc_t *) calloc(1, sizeof(stpc_t)); dev->local = info->local; @@ -963,8 +962,7 @@ stpc_serial_init(UNUSED(const device_t *info)) { stpc_log("STPC: serial_init()\n"); - stpc_serial_t *dev = (stpc_serial_t *) malloc(sizeof(stpc_serial_t)); - memset(dev, 0, sizeof(stpc_serial_t)); + stpc_serial_t *dev = (stpc_serial_t *) calloc(1, sizeof(stpc_serial_t)); dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); @@ -1076,8 +1074,7 @@ stpc_lpt_init(UNUSED(const device_t *info)) { stpc_log("STPC: lpt_init()\n"); - stpc_lpt_t *dev = (stpc_lpt_t *) malloc(sizeof(stpc_lpt_t)); - memset(dev, 0, sizeof(stpc_lpt_t)); + stpc_lpt_t *dev = (stpc_lpt_t *) calloc(1, sizeof(stpc_lpt_t)); stpc_lpt_reset(dev); diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index 30b0ecb71..f96480c2c 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -392,8 +392,7 @@ umc_8886_close(void *priv) static void * umc_8886_init(const device_t *info) { - umc_8886_t *dev = (umc_8886_t *) malloc(sizeof(umc_8886_t)); - memset(dev, 0, sizeof(umc_8886_t)); + umc_8886_t *dev = (umc_8886_t *) calloc(1, sizeof(umc_8886_t)); /* Device 12: UMC 8886xx */ pci_add_card(PCI_ADD_SOUTHBRIDGE, umc_8886_read, umc_8886_write, dev, &dev->pci_slot); diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index 98bdfc82c..889691988 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -450,8 +450,7 @@ ims8848_read(uint16_t addr, void *priv) static void * hb4_init(UNUSED(const device_t *info)) { - hb4_t *dev = (hb4_t *) malloc(sizeof(hb4_t)); - memset(dev, 0, sizeof(hb4_t)); + hb4_t *dev = (hb4_t *) calloc(1, sizeof(hb4_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, hb4_read, hb4_write, dev, &dev->pci_slot); /* Device 10: UMC 8881x */ diff --git a/src/chipset/via_apollo.c b/src/chipset/via_apollo.c index fa96c4927..110b1f8e1 100644 --- a/src/chipset/via_apollo.c +++ b/src/chipset/via_apollo.c @@ -725,8 +725,7 @@ via_apollo_reset(void *priv) static void * via_apollo_init(const device_t *info) { - via_apollo_t *dev = (via_apollo_t *) malloc(sizeof(via_apollo_t)); - memset(dev, 0, sizeof(via_apollo_t)); + via_apollo_t *dev = (via_apollo_t *) calloc(1, sizeof(via_apollo_t)); dev->smram = smram_add(); if (dev->id != VIA_8601) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 3a6e6fc5c..dcfe41811 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1627,8 +1627,7 @@ pipc_reset(void *priv) static void * pipc_init(const device_t *info) { - pipc_t *dev = (pipc_t *) malloc(sizeof(pipc_t)); - memset(dev, 0, sizeof(pipc_t)); + pipc_t *dev = (pipc_t *) calloc(1, sizeof(pipc_t)); pipc_log("PIPC: init()\n"); diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index f36dad2e7..3aaef55a6 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -342,8 +342,7 @@ vt82c49x_close(void *priv) static void * vt82c49x_init(const device_t *info) { - vt82c49x_t *dev = (vt82c49x_t *) malloc(sizeof(vt82c49x_t)); - memset(dev, 0x00, sizeof(vt82c49x_t)); + vt82c49x_t *dev = (vt82c49x_t *) calloc(1, sizeof(vt82c49x_t)); dev->smram_smm = smram_add(); dev->smram_low = smram_add(); diff --git a/src/chipset/via_vt82c505.c b/src/chipset/via_vt82c505.c index 8cb6c67a0..dbbb447c7 100644 --- a/src/chipset/via_vt82c505.c +++ b/src/chipset/via_vt82c505.c @@ -167,7 +167,7 @@ vt82c505_in(uint16_t addr, void *priv) static void vt82c505_reset(void *priv) { - vt82c505_t *dev = (vt82c505_t *) malloc(sizeof(vt82c505_t)); + vt82c505_t *dev = (vt82c505_t *) calloc(1, sizeof(vt82c505_t)); dev->pci_conf[0x04] = 0x07; dev->pci_conf[0x07] = 0x00; @@ -204,8 +204,7 @@ vt82c505_close(void *priv) static void * vt82c505_init(UNUSED(const device_t *info)) { - vt82c505_t *dev = (vt82c505_t *) malloc(sizeof(vt82c505_t)); - memset(dev, 0, sizeof(vt82c505_t)); + vt82c505_t *dev = (vt82c505_t *) calloc(1, sizeof(vt82c505_t)); pci_add_card(PCI_ADD_NORTHBRIDGE, vt82c505_read, vt82c505_write, dev, &dev->pci_slot); diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 38a6bdfb9..496544c63 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -180,8 +180,7 @@ vl82c480_close(void *priv) static void * vl82c480_init(const device_t *info) { - vl82c480_t *dev = (vl82c480_t *) malloc(sizeof(vl82c480_t)); - memset(dev, 0, sizeof(vl82c480_t)); + vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index 6de921af1..9b13dc5da 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -884,7 +884,7 @@ wd76c10_init(const device_t *info) wd76c10_t *dev = (wd76c10_t *) calloc(1, sizeof(wd76c10_t)); uint32_t total_mem = mem_size << 10; uint32_t accum_mem = 0x00000000; - ram_bank_t *rb; + ram_bank_t *rb = NULL; /* Calculate the physical RAM banks. */ for (uint8_t i = 0; i < 4; i++) { diff --git a/src/device/cartridge.c b/src/device/cartridge.c index 22b36484a..d2e91ecb3 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -113,8 +113,7 @@ cart_image_load(int drive, char *fn) (void) !fread(&base, 1, 2, fp); base <<= 4; fseek(fp, 0x00000200, SEEK_SET); - carts[drive].buf = (uint8_t *) malloc(size); - memset(carts[drive].buf, 0x00, size); + carts[drive].buf = (uint8_t *) calloc(1, size); (void) !fread(carts[drive].buf, 1, size, fp); fclose(fp); } else { @@ -122,8 +121,7 @@ cart_image_load(int drive, char *fn) if (size == 32768) base += 0x8000; fseek(fp, 0x00000000, SEEK_SET); - carts[drive].buf = (uint8_t *) malloc(size); - memset(carts[drive].buf, 0x00, size); + carts[drive].buf = (uint8_t *) calloc(1, size); (void) !fread(carts[drive].buf, 1, size, fp); fclose(fp); } diff --git a/src/device/cassette.c b/src/device/cassette.c index 608de7463..ac79edff2 100644 --- a/src/device/cassette.c +++ b/src/device/cassette.c @@ -131,9 +131,7 @@ pc_cas_free(pc_cassette_t *cas) pc_cassette_t * pc_cas_new(void) { - pc_cassette_t *cas; - - cas = malloc(sizeof(pc_cassette_t)); + pc_cassette_t *cas = calloc(1, sizeof( pc_cassette_t)); if (cas == NULL) { return (NULL); diff --git a/src/device/clock_ics9xxx.c b/src/device/clock_ics9xxx.c index 263170741..02f033e9b 100644 --- a/src/device/clock_ics9xxx.c +++ b/src/device/clock_ics9xxx.c @@ -1181,8 +1181,7 @@ ics9xxx_find_bus_match(ics9xxx_t *dev, uint32_t bus, uint8_t preset_mask, uint8_ static void * ics9xxx_init(const device_t *info) { - ics9xxx_t *dev = (ics9xxx_t *) malloc(sizeof(ics9xxx_t)); - memset(dev, 0, sizeof(ics9xxx_t)); + ics9xxx_t *dev = (ics9xxx_t *) calloc(1, sizeof(ics9xxx_t)); dev->model_idx = info->local; dev->model = (ics9xxx_model_t *) &ics9xxx_models[dev->model_idx]; @@ -1267,8 +1266,7 @@ ics9xxx_close(void *priv) device_t * ics9xxx_get(uint8_t model) { - device_t *dev = (device_t *) malloc(sizeof(device_t)); - memset(dev, 0, sizeof(device_t)); + device_t *dev = (device_t *) calloc(1, sizeof(device_t)); dev->name = "ICS9xxx-xx Clock Generator"; dev->local = model; diff --git a/src/device/hasp.c b/src/device/hasp.c index 9873c3460..3834af4cd 100644 --- a/src/device/hasp.c +++ b/src/device/hasp.c @@ -305,8 +305,7 @@ hasp_read_status(void *priv) static void * hasp_init(void *lpt, int type) { - hasp_t *dev = malloc(sizeof(hasp_t)); - memset(dev, 0, sizeof(hasp_t)); + hasp_t *dev = calloc(1, sizeof(hasp_t)); hasp_log("HASP: init(%d)\n", type); diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index 23763ebb8..cfc16664a 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -282,8 +282,7 @@ gl518sm_close(void *priv) static void * gl518sm_init(const device_t *info) { - gl518sm_t *dev = (gl518sm_t *) malloc(sizeof(gl518sm_t)); - memset(dev, 0, sizeof(gl518sm_t)); + gl518sm_t *dev = (gl518sm_t *) calloc(1, sizeof(gl518sm_t)); dev->local = info->local; diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 831d16ded..29fe2024f 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -216,8 +216,7 @@ lm75_close(void *priv) static void * lm75_init(const device_t *info) { - lm75_t *dev = (lm75_t *) malloc(sizeof(lm75_t)); - memset(dev, 0, sizeof(lm75_t)); + lm75_t *dev = (lm75_t *) calloc(1, sizeof(lm75_t)); dev->local = info->local; diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 3219e87e6..1e61168ac 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -771,8 +771,7 @@ lm78_close(void *priv) static void * lm78_init(const device_t *info) { - lm78_t *dev = (lm78_t *) malloc(sizeof(lm78_t)); - memset(dev, 0, sizeof(lm78_t)); + lm78_t *dev = (lm78_t *) calloc(1, sizeof(lm78_t)); dev->local = info->local; diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c index 7d764bcb9..8623a9f6b 100644 --- a/src/device/hwm_vt82c686.c +++ b/src/device/hwm_vt82c686.c @@ -183,8 +183,7 @@ vt82c686_close(void *priv) static void * vt82c686_init(UNUSED(const device_t *info)) { - vt82c686_t *dev = (vt82c686_t *) malloc(sizeof(vt82c686_t)); - memset(dev, 0, sizeof(vt82c686_t)); + vt82c686_t *dev = (vt82c686_t *) calloc(1, sizeof(vt82c686_t)); /* Set default values. Since this hardware monitor has a complex voltage factor system, the values struct contains voltage values *before* applying their respective factors. */ diff --git a/src/device/i2c.c b/src/device/i2c.c index 56e6f8f4c..eb80f413b 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -67,8 +67,7 @@ i2c_log(const char *fmt, ...) void * i2c_addbus(char *name) { - i2c_bus_t *bus = (i2c_bus_t *) malloc(sizeof(i2c_bus_t)); - memset(bus, 0, sizeof(i2c_bus_t)); + i2c_bus_t *bus = (i2c_bus_t *) calloc(1, sizeof(i2c_bus_t)); bus->name = name; @@ -127,8 +126,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size, for (int c = 0; c < size; c++) { p = bus->last[base + c]; - q = (i2c_t *) malloc(sizeof(i2c_t)); - memset(q, 0, sizeof(i2c_t)); + q = (i2c_t *) calloc(1, sizeof(i2c_t)); if (p) { p->next = q; q->prev = p; diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index 22bdaffd3..61a3dbe05 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -59,8 +59,7 @@ i2c_gpio_log(int level, const char *fmt, ...) void * i2c_gpio_init(char *bus_name) { - i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t)); - memset(dev, 0, sizeof(i2c_gpio_t)); + i2c_gpio_t *dev = (i2c_gpio_t *) calloc(1, sizeof(i2c_gpio_t)); i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name); diff --git a/src/device/isamem.c b/src/device/isamem.c index 5d3164757..4dc88cc6c 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -483,8 +483,7 @@ isamem_init(const device_t *info) uint8_t *ptr; /* Find our device and create an instance. */ - dev = (memdev_t *) malloc(sizeof(memdev_t)); - memset(dev, 0x00, sizeof(memdev_t)); + dev = (memdev_t *) calloc(1, sizeof(memdev_t)); dev->name = info->name; dev->board = info->local; diff --git a/src/device/isapnp.c b/src/device/isapnp.c index 479b6b9b2..1ee8be040 100644 --- a/src/device/isapnp.c +++ b/src/device/isapnp.c @@ -679,7 +679,7 @@ isapnp_write_data(UNUSED(uint16_t addr), uint8_t val, void *priv) static void * isapnp_init(UNUSED(const device_t *info)) { - isapnp_t *dev = (isapnp_t *) malloc(sizeof(isapnp_t)); + isapnp_t *dev = (isapnp_t *) calloc(1, sizeof(isapnp_t)); memset(dev, 0, sizeof(isapnp_t)); io_sethandler(0x279, 1, NULL, NULL, NULL, isapnp_write_addr, NULL, NULL, dev); @@ -728,8 +728,7 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size, if (!dev) dev = (isapnp_t *) device_add(&isapnp_device); - isapnp_card_t *card = (isapnp_card_t *) malloc(sizeof(isapnp_card_t)); - memset(card, 0, sizeof(isapnp_card_t)); + isapnp_card_t *card = (isapnp_card_t *) calloc(1, sizeof(isapnp_card_t)); card->enable = 1; card->priv = priv; diff --git a/src/device/isartc.c b/src/device/isartc.c index 77f35ffc7..f24ffb72b 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -520,8 +520,7 @@ isartc_init(const device_t *info) is_at = is_at || !strcmp(machine_get_internal_name(), "xi8088"); /* Create a device instance. */ - dev = (rtcdev_t *) malloc(sizeof(rtcdev_t)); - memset(dev, 0x00, sizeof(rtcdev_t)); + dev = (rtcdev_t *) calloc(1, sizeof(rtcdev_t)); dev->name = info->name; dev->board = info->local; dev->irq = -1; diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index aef3b2cc6..ad1625873 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2282,8 +2282,7 @@ kbc_at_init(const device_t *info) atkbc_t *dev; int max_ports; - dev = (atkbc_t *) malloc(sizeof(atkbc_t)); - memset(dev, 0x00, sizeof(atkbc_t)); + dev = (atkbc_t *) calloc(1, sizeof(atkbc_t)); dev->flags = info->local; @@ -2393,8 +2392,7 @@ kbc_at_init(const device_t *info) #endif for (int i = 0; i < max_ports; i++) { - kbc_at_ports[i] = (kbc_at_port_t *) malloc(sizeof(kbc_at_port_t)); - memset(kbc_at_ports[i], 0x00, sizeof(kbc_at_port_t)); + kbc_at_ports[i] = (kbc_at_port_t *) calloc(1, sizeof(kbc_at_port_t)); kbc_at_ports[i]->out_new = -1; } diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index c614bad8c..644168004 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -1000,8 +1000,7 @@ kbd_init(const device_t *info) { xtkbd_t *kbd; - kbd = (xtkbd_t *) malloc(sizeof(xtkbd_t)); - memset(kbd, 0x00, sizeof(xtkbd_t)); + kbd = (xtkbd_t *) calloc(1, sizeof(xtkbd_t)); io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index 9c0d8b02e..b56a3cc18 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -614,8 +614,7 @@ bm_init(const device_t *info) mouse_t *dev; int hz; - dev = (mouse_t *) malloc(sizeof(mouse_t)); - memset(dev, 0x00, sizeof(mouse_t)); + dev = (mouse_t *) calloc(1, sizeof(mouse_t)); if ((info->local & ~MOUSE_TYPE_ONBOARD) == MOUSE_TYPE_INPORT) dev->flags = FLAG_INPORT; diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index c6bef89dc..80e89df1f 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -128,8 +128,7 @@ mtouch_initnvr(void *priv) FILE *fp; /* Allocate and initialize the EEPROM. */ - dev->nvr = (uint8_t *) malloc(NVR_SIZE); - memset(dev->nvr, 0x00, NVR_SIZE); + dev->nvr = (uint8_t *) calloc(1, NVR_SIZE); fp = nvr_fopen(dev->nvr_path, "rb"); if (fp) { diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 99d08cd37..c64be5a6d 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -845,8 +845,7 @@ sermouse_init(const device_t *info) void (*dev_write)(struct serial_s *serial, void *priv, uint8_t data); void (*transmit_period_callback)(struct serial_s *serial, void *priv, double transmit_period); - dev = (mouse_t *) malloc(sizeof(mouse_t)); - memset(dev, 0x00, sizeof(mouse_t)); + dev = (mouse_t *) calloc(1, sizeof(mouse_t)); dev->name = info->name; dev->but = device_get_config_int("buttons"); dev->rev = device_get_config_int("revision"); diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 4321bf433..7dda00aee 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -491,8 +491,7 @@ pci_bridge_init(const device_t *info) uint8_t interrupt_mask; uint8_t slot_count; - pci_bridge_t *dev = (pci_bridge_t *) malloc(sizeof(pci_bridge_t)); - memset(dev, 0, sizeof(pci_bridge_t)); + pci_bridge_t *dev = (pci_bridge_t *) calloc(1, sizeof(pci_bridge_t)); dev->local = info->local; dev->bus_index = pci_register_bus(); diff --git a/src/device/phoenix_486_jumper.c b/src/device/phoenix_486_jumper.c index 6032a59dc..a3e2f0e7e 100644 --- a/src/device/phoenix_486_jumper.c +++ b/src/device/phoenix_486_jumper.c @@ -110,8 +110,7 @@ phoenix_486_jumper_close(void *priv) static void * phoenix_486_jumper_init(const device_t *info) { - phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) malloc(sizeof(phoenix_486_jumper_t)); - memset(dev, 0, sizeof(phoenix_486_jumper_t)); + phoenix_486_jumper_t *dev = (phoenix_486_jumper_t *) calloc(1, sizeof(phoenix_486_jumper_t)); dev->type = info->local; diff --git a/src/device/serial.c b/src/device/serial.c index 1e2618449..0ba60551c 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -914,8 +914,7 @@ serial_reset(void *priv) static void * serial_init(const device_t *info) { - serial_t *dev = (serial_t *) malloc(sizeof(serial_t)); - memset(dev, 0, sizeof(serial_t)); + serial_t *dev = (serial_t *) calloc(1, sizeof(serial_t)); dev->inst = next_inst; diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 445b67d04..bb2378a22 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -178,8 +178,7 @@ serial_passthrough_dev_init(const device_t *info) { serial_passthrough_t *dev; - dev = (serial_passthrough_t *) malloc(sizeof(serial_passthrough_t)); - memset(dev, 0, sizeof(serial_passthrough_t)); + dev = (serial_passthrough_t *) calloc(1, sizeof(serial_passthrough_t)); dev->mode = device_get_config_int("mode"); dev->port = device_get_instance() - 1; diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index de487ef73..3907a065e 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -273,7 +273,7 @@ smbus_ali7101_reset(void *priv) static void * smbus_ali7101_init(const device_t *info) { - smbus_ali7101_t *dev = (smbus_ali7101_t *) malloc(sizeof(smbus_ali7101_t)); + smbus_ali7101_t *dev = (smbus_ali7101_t *) calloc(1, sizeof(smbus_ali7101_t)); memset(dev, 0, sizeof(smbus_ali7101_t)); dev->local = info->local; diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index d72712cc6..a9ffcd847 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -357,8 +357,7 @@ smbus_piix4_setclock(smbus_piix4_t *dev, int clock) static void * smbus_piix4_init(const device_t *info) { - smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); - memset(dev, 0, sizeof(smbus_piix4_t)); + smbus_piix4_t *dev = (smbus_piix4_t *) calloc(1, sizeof(smbus_piix4_t)); dev->local = info->local; /* We save the I2C bus handle on dev but use i2c_smbus for all operations because diff --git a/src/device/smbus_sis5595.c b/src/device/smbus_sis5595.c index e7cffc577..0a24d2355 100644 --- a/src/device/smbus_sis5595.c +++ b/src/device/smbus_sis5595.c @@ -343,8 +343,7 @@ smbus_sis5595_reset(void *priv) static void * smbus_sis5595_init(const device_t *info) { - smbus_sis5595_t *dev = (smbus_sis5595_t *) malloc(sizeof(smbus_sis5595_t)); - memset(dev, 0, sizeof(smbus_sis5595_t)); + smbus_sis5595_t *dev = (smbus_sis5595_t *) calloc(1, sizeof(smbus_sis5595_t)); dev->local = info->local; diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index d9dc02da0..adc39d509 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -920,8 +920,7 @@ wd1007vse1_init(UNUSED(const device_t *info)) { int c; - esdi_t *esdi = malloc(sizeof(esdi_t)); - memset(esdi, 0x00, sizeof(esdi_t)); + esdi_t *esdi = calloc(1, sizeof(esdi_t)); c = 0; for (uint8_t d = 0; d < HDD_NUM; d++) { diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 83d2dc3b7..b7ab5ff9f 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1249,10 +1249,9 @@ esdi_init(UNUSED(const device_t *info)) uint8_t c; uint8_t i; - dev = malloc(sizeof(esdi_t)); + dev = calloc(1, sizeof(esdi_t)); if (dev == NULL) return (NULL); - memset(dev, 0x00, sizeof(esdi_t)); /* Mark as unconfigured. */ dev->irq_status = 0xff; diff --git a/src/disk/hdc_ide_cmd640.c b/src/disk/hdc_ide_cmd640.c index 9c0178a47..84a40efa4 100644 --- a/src/disk/hdc_ide_cmd640.c +++ b/src/disk/hdc_ide_cmd640.c @@ -504,8 +504,7 @@ cmd640_close(void *priv) static void * cmd640_init(const device_t *info) { - cmd640_t *dev = (cmd640_t *) malloc(sizeof(cmd640_t)); - memset(dev, 0x00, sizeof(cmd640_t)); + cmd640_t *dev = (cmd640_t *) calloc(1, sizeof(cmd640_t)); dev->id = next_id | 0x60; diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c index b79f84f03..b548390fd 100644 --- a/src/disk/hdc_ide_cmd646.c +++ b/src/disk/hdc_ide_cmd646.c @@ -391,8 +391,7 @@ cmd646_close(void *priv) static void * cmd646_init(const device_t *info) { - cmd646_t *dev = (cmd646_t *) malloc(sizeof(cmd646_t)); - memset(dev, 0x00, sizeof(cmd646_t)); + cmd646_t *dev = (cmd646_t *) calloc(1, sizeof(cmd646_t)); dev->local = info->local; diff --git a/src/disk/hdc_ide_opti611.c b/src/disk/hdc_ide_opti611.c index 67cdfc779..4927b5fe3 100644 --- a/src/disk/hdc_ide_opti611.c +++ b/src/disk/hdc_ide_opti611.c @@ -317,8 +317,7 @@ opti611_close(void *priv) static void * opti611_init(UNUSED(const device_t *info)) { - opti611_t *dev = (opti611_t *) malloc(sizeof(opti611_t)); - memset(dev, 0, sizeof(opti611_t)); + opti611_t *dev = (opti611_t *) calloc(1, sizeof(opti611_t)); dev->is_sec = info->local; diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index ec4c7228c..73dc5f36b 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -578,8 +578,7 @@ sff_close(void *priv) static void * sff_init(UNUSED(const device_t *info)) { - sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t)); - memset(dev, 0, sizeof(sff8038i_t)); + sff8038i_t *dev = (sff8038i_t *) calloc(1, sizeof(sff8038i_t)); /* Make sure to only add IDE once. */ if (next_id == 0) diff --git a/src/disk/hdc_ide_w83769f.c b/src/disk/hdc_ide_w83769f.c index 897a26593..9c0f744b2 100644 --- a/src/disk/hdc_ide_w83769f.c +++ b/src/disk/hdc_ide_w83769f.c @@ -353,8 +353,7 @@ w83769f_close(void *priv) static void * w83769f_init(const device_t *info) { - w83769f_t *dev = (w83769f_t *) malloc(sizeof(w83769f_t)); - memset(dev, 0x00, sizeof(w83769f_t)); + w83769f_t *dev = (w83769f_t *) calloc(1, sizeof(w83769f_t)); dev->id = next_id | 0x60; diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index abd379646..eeb242a94 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -744,8 +744,7 @@ mfm_init(UNUSED(const device_t *info)) int c; st506_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); - mfm = malloc(sizeof(mfm_t)); - memset(mfm, 0x00, sizeof(mfm_t)); + mfm = calloc(1, sizeof(mfm_t)); c = 0; for (uint8_t d = 0; d < HDD_NUM; d++) { diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index d950fbe34..789e7e6c4 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -1627,8 +1627,7 @@ st506_init(const device_t *info) int i; int c; - dev = (hdc_t *) malloc(sizeof(hdc_t)); - memset(dev, 0x00, sizeof(hdc_t)); + dev = (hdc_t *) calloc(1, sizeof(hdc_t)); dev->type = info->local & 255; /* Set defaults for the controller. */ diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 1ddbd33e2..553e53b48 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1000,8 +1000,7 @@ xta_init(const device_t *info) int max = XTA_NUM; /* Allocate and initialize device block. */ - dev = malloc(sizeof(hdc_t)); - memset(dev, 0x00, sizeof(hdc_t)); + dev = calloc(1, sizeof(hdc_t)); dev->type = info->local; /* Do per-controller-type setup. */ diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 623f68cb5..7ec7695b3 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -132,13 +132,11 @@ xtide_read(uint16_t port, void *priv) static void * xtide_init(const device_t *info) { - xtide_t *xtide = malloc(sizeof(xtide_t)); + xtide_t *xtide = calloc(1, sizeof(xtide_t)); - memset(xtide, 0x00, sizeof(xtide_t)); - - rom_init(&xtide->bios_rom, - device_get_bios_file(info, device_get_config_bios("bios"), 0), - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&xtide->bios_rom, + device_get_bios_file(info, device_get_config_bios("bios"), 0), + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); @@ -152,13 +150,11 @@ xtide_init(const device_t *info) static void * xtide_at_init(const device_t *info) { - xtide_t *xtide = malloc(sizeof(xtide_t)); + xtide_t *xtide = calloc(1, sizeof(xtide_t)); - memset(xtide, 0x00, sizeof(xtide_t)); - - rom_init(&xtide->bios_rom, - device_get_bios_file(info, device_get_config_bios("bios"), 0), - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&xtide->bios_rom, + device_get_bios_file(info, device_get_config_bios("bios"), 0), + 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); device_add(&ide_isa_2ch_device); @@ -168,9 +164,7 @@ xtide_at_init(const device_t *info) static void * xtide_acculogic_init(UNUSED(const device_t *info)) { - xtide_t *xtide = malloc(sizeof(xtide_t)); - - memset(xtide, 0x00, sizeof(xtide_t)); + xtide_t *xtide = calloc(1, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_PS2, 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); @@ -203,9 +197,7 @@ xtide_close(void *priv) static void * xtide_at_ps2_init(UNUSED(const device_t *info)) { - xtide_t *xtide = malloc(sizeof(xtide_t)); - - memset(xtide, 0x00, sizeof(xtide_t)); + xtide_t *xtide = calloc(1, sizeof(xtide_t)); rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 5c377f95f..300d775c5 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -2314,8 +2314,7 @@ fdc_close(void *priv) static void * fdc_init(const device_t *info) { - fdc_t *fdc = (fdc_t *) malloc(sizeof(fdc_t)); - memset(fdc, 0, sizeof(fdc_t)); + fdc_t *fdc = (fdc_t *) calloc(1, sizeof(fdc_t)); fdc->flags = info->local; diff --git a/src/floppy/fdc_magitronic.c b/src/floppy/fdc_magitronic.c index 09b766d6c..2b708a121 100644 --- a/src/floppy/fdc_magitronic.c +++ b/src/floppy/fdc_magitronic.c @@ -90,8 +90,7 @@ b215_close(void *priv) static void * b215_init(UNUSED(const device_t *info)) { - b215_t *dev = (b215_t *) malloc(sizeof(b215_t)); - memset(dev, 0, sizeof(b215_t)); + b215_t *dev = (b215_t *) calloc(1, sizeof(b215_t)); rom_init(&dev->rom, ROM_B215, ROM_ADDR, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index bb210fb44..51fb108d6 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -13,7 +13,7 @@ * Authors: Jasmine Iwanek, * Miran Grca, * - * Copyright 2022-2024 Jasmine Iwanek. + * Copyright 2022-2025 Jasmine Iwanek. * Copyright 2024 Miran Grca. */ #include diff --git a/src/floppy/fdc_pii15xb.c b/src/floppy/fdc_pii15xb.c index 6a8bbbd43..587eb64fa 100644 --- a/src/floppy/fdc_pii15xb.c +++ b/src/floppy/fdc_pii15xb.c @@ -97,8 +97,7 @@ pii_init(const device_t *info) { pii_t *dev; - dev = (pii_t *) malloc(sizeof(pii_t)); - memset(dev, 0, sizeof(pii_t)); + dev = (pii_t *) calloc(1, sizeof(pii_t)); if (BIOS_ADDR != 0) rom_init(&dev->bios_rom, DTK_VARIANT, BIOS_ADDR, 0x2000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 0e8a6590a..140e87899 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -2731,8 +2731,7 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t uint16_t datadam_mfm = 0x4A55; if (fdd_get_turbo(drive) && (dev->version == 0x0063)) { - s = (sector_t *) malloc(sizeof(sector_t)); - memset(s, 0, sizeof(sector_t)); + s = (sector_t *) calloc(1, sizeof(sector_t)); s->c = id_buf[0]; s->h = id_buf[1]; s->r = id_buf[2]; @@ -3921,8 +3920,7 @@ d86f_setup(int drive) d86f_t *dev; /* Allocate a drive structure. */ - dev = (d86f_t *) malloc(sizeof(d86f_t)); - memset(dev, 0x00, sizeof(d86f_t)); + dev = (d86f_t *) calloc(1, sizeof(d86f_t)); dev->state = STATE_IDLE; dev->last_side_sector[0] = NULL; diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index f14bf2cd4..97b6441a0 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -316,15 +316,13 @@ fdi_load(int drive, char *fn) writeprot[drive] = fwriteprot[drive] = 1; /* Allocate a drive block. */ - dev = (fdi_t *) malloc(sizeof(fdi_t)); + dev = (fdi_t *) calloc(1, sizeof(fdi_t)); if (dev == NULL) { memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); return; } - memset(dev, 0x00, sizeof(fdi_t)); - d86f_unregister(drive); dev->fp = plat_fopen(fn, "rb"); diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 0839c2900..7994530ed 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -635,8 +635,7 @@ imd_load(int drive, char *fn) writeprot[drive] = 0; /* Allocate a drive block. */ - dev = (imd_t *) malloc(sizeof(imd_t)); - memset(dev, 0x00, sizeof(imd_t)); + dev = (imd_t *) calloc(1, sizeof(imd_t)); dev->fp = plat_fopen(fn, "rb+"); if (dev->fp == NULL) { diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 69a753ef5..30e0212cd 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -681,8 +681,7 @@ img_load(int drive, char *fn) writeprot[drive] = 0; /* Allocate a drive block. */ - dev = (img_t *) malloc(sizeof(img_t)); - memset(dev, 0x00, sizeof(img_t)); + dev = (img_t *) calloc(1, sizeof(img_t)); dev->fp = plat_fopen(fn, "rb+"); if (dev->fp == NULL) { diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c index a332d25c9..87da4e08b 100644 --- a/src/floppy/fdd_mfm.c +++ b/src/floppy/fdd_mfm.c @@ -396,8 +396,7 @@ mfm_load(int drive, char *fn) writeprot[drive] = fwriteprot[drive] = 1; /* Allocate a drive block. */ - dev = (mfm_t *) malloc(sizeof(mfm_t)); - memset(dev, 0x00, sizeof(mfm_t)); + dev = (mfm_t *) calloc(1, sizeof(mfm_t)); dev->fp = plat_fopen(fn, "rb"); if (dev->fp == NULL) { diff --git a/src/floppy/fdd_pcjs.c b/src/floppy/fdd_pcjs.c index 76f8ca7dc..41db65a1a 100644 --- a/src/floppy/fdd_pcjs.c +++ b/src/floppy/fdd_pcjs.c @@ -617,8 +617,7 @@ pcjs_load(int drive, char *fn) d86f_unregister(drive); /* Allocate a drive block */ - dev = (pcjs_t *) malloc(sizeof(pcjs_t)); - memset(dev, 0x00, sizeof(pcjs_t)); + dev = (pcjs_t *) calloc(1, sizeof(pcjs_t)); /* Open the image file, read-only */ dev->fp = plat_fopen(fn, "rb"); diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index 0bf4b1c71..f5882158b 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -1214,8 +1214,7 @@ td0_load(int drive, char *fn) writeprot[drive] = 1; - dev = (td0_t *) malloc(sizeof(td0_t)); - memset(dev, 0x00, sizeof(td0_t)); + dev = (td0_t *) calloc(1, sizeof(td0_t)); td0[drive] = dev; dev->fp = plat_fopen(fn, "rb"); diff --git a/src/game/gameport.c b/src/game/gameport.c index f3b54c803..579f5c235 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -366,15 +366,11 @@ gameport_add(const device_t *gameport_type) static void * gameport_init(const device_t *info) { - gameport_t *dev = NULL; - - dev = malloc(sizeof(gameport_t)); - memset(dev, 0x00, sizeof(gameport_t)); + gameport_t *dev = calloc(1, sizeof(gameport_t)); /* Allocate global instance. */ if (!joystick_instance[0] && joystick_type) { - joystick_instance[0] = malloc(sizeof(joystick_instance_t)); - memset(joystick_instance[0], 0x00, sizeof(joystick_instance_t)); + joystick_instance[0] = calloc(1, sizeof(joystick_instance_t)); joystick_instance[0]->axis[0].joystick = joystick_instance[0]; joystick_instance[0]->axis[1].joystick = joystick_instance[0]; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 891f02e84..3dba578bd 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -619,8 +619,7 @@ vid_init_1512(amstrad_t *ams) amsvid_t *vid; /* Allocate a video controller block. */ - vid = (amsvid_t *) malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); + vid = (amsvid_t *) calloc(1, sizeof(amsvid_t)); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc1512); @@ -823,8 +822,7 @@ vid_init_1640(amstrad_t *ams) amsvid_t *vid; /* Allocate a video controller block. */ - vid = (amsvid_t *) malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); + vid = (amsvid_t *) calloc(1, sizeof(amsvid_t)); rom_init(&vid->bios_rom, "roms/machines/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); @@ -1620,8 +1618,7 @@ vid_init_200(amstrad_t *ams) mda_t *mda; /* Allocate a video controller block. */ - vid = (amsvid_t *) malloc(sizeof(amsvid_t)); - memset(vid, 0x00, sizeof(amsvid_t)); + vid = (amsvid_t *) calloc(1, sizeof(amsvid_t)); vid->emulation = device_get_config_int("video_emulation"); @@ -2870,8 +2867,7 @@ machine_amstrad_init(const machine_t *model, int type) { amstrad_t *ams; - ams = (amstrad_t *) malloc(sizeof(amstrad_t)); - memset(ams, 0x00, sizeof(amstrad_t)); + ams = (amstrad_t *) calloc(1, sizeof(amstrad_t)); ams->type = type; amstrad_latch = 0x80000000; diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 3b9462f90..904122bad 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -629,8 +629,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) static void * compaq_plasma_init(UNUSED(const device_t *info)) { - compaq_plasma_t *self = malloc(sizeof(compaq_plasma_t)); - memset(self, 0, sizeof(compaq_plasma_t)); + compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); if (compaq_machine_type == COMPAQ_PORTABLEIII) diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index 80af959af..c827a05e5 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -655,8 +655,7 @@ t3100e_recalcattrs(t3100e_t *t3100e) void * t3100e_init(UNUSED(const device_t *info)) { - t3100e_t *t3100e = malloc(sizeof(t3100e_t)); - memset(t3100e, 0, sizeof(t3100e_t)); + t3100e_t *t3100e = calloc(1, sizeof(t3100e_t)); loadfont("roms/machines/t3100e/t3100e_font.bin", 5); cga_init(&t3100e->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t3100e); diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 847053bdb..ca9e72fca 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -1532,8 +1532,7 @@ machine_pcjr_init(UNUSED(const machine_t *model)) if (bios_only || !ret) return ret; - pcjr = malloc(sizeof(pcjr_t)); - memset(pcjr, 0x00, sizeof(pcjr_t)); + pcjr = calloc(1, sizeof(pcjr_t)); pic_init_pcjr(); pit_common_init(0, pit_irq0_timer_pcjr, NULL); diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 8b2a096c7..92846c401 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -299,8 +299,7 @@ ps1_setup(int model) ps1_t *ps; void *priv; - ps = (ps1_t *) malloc(sizeof(ps1_t)); - memset(ps, 0x00, sizeof(ps1_t)); + ps = (ps1_t *) calloc(1, sizeof(ps1_t)); ps->model = model; io_sethandler(0x0091, 1, diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index 06c7a2c95..d407953b4 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -1297,8 +1297,7 @@ ps1_hdc_init(UNUSED(const device_t *info)) int c; /* Allocate and initialize device block. */ - dev = malloc(sizeof(hdc_t)); - memset(dev, 0x00, sizeof(hdc_t)); + dev = calloc(1, sizeof(hdc_t)); /* Set up controller parameters for PS/1 2011. */ dev->base = 0x0320; diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index c0c4f7c79..7d024c335 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -151,8 +151,7 @@ ps2_isa_setup(int model, int cpu_type) ps2_isa_t *ps2; void *priv; - ps2 = (ps2_isa_t *) malloc(sizeof(ps2_isa_t)); - memset(ps2, 0x00, sizeof(ps2_isa_t)); + ps2 = (ps2_isa_t *) calloc(1, sizeof(ps2_isa_t)); ps2->model = model; ps2->cpu_type = cpu_type; diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 8e46c6154..7072c5e78 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -1359,8 +1359,7 @@ vid_init(tandy_t *dev) int display_type; t1kvid_t *vid; - vid = malloc(sizeof(t1kvid_t)); - memset(vid, 0x00, sizeof(t1kvid_t)); + vid = calloc(1, sizeof(t1kvid_t)); vid->memctrl = -1; video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); @@ -1540,8 +1539,7 @@ eep_init(const device_t *info) t1keep_t *eep; FILE *fp = NULL; - eep = (t1keep_t *) malloc(sizeof(t1keep_t)); - memset(eep, 0x00, sizeof(t1keep_t)); + eep = (t1keep_t *) calloc(1, sizeof(t1keep_t)); switch (info->local) { case TYPE_TANDY1000HX: diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 3b907f4df..b6e4fb94a 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -2313,8 +2313,7 @@ machine_xt_m24_init(const machine_t *model) if (bios_only || !ret) return ret; - m24_kbd = (m24_kbd_t *) malloc(sizeof(m24_kbd_t)); - memset(m24_kbd, 0x00, sizeof(m24_kbd_t)); + m24_kbd = (m24_kbd_t *) calloc(1, sizeof(m24_kbd_t)); machine_common_init(model); @@ -2330,10 +2329,9 @@ machine_xt_m24_init(const machine_t *model) nmi_init(); /* Allocate an NVR for this machine. */ - nvr = (nvr_t *) malloc(sizeof(nvr_t)); + nvr = (nvr_t *) calloc(1, sizeof(nvr_t)); if (nvr == NULL) return 0; - memset(nvr, 0x00, sizeof(nvr_t)); mm58174_init(nvr, model->nvrmask + 1); @@ -2374,8 +2372,7 @@ machine_xt_m240_init(const machine_t *model) if (bios_only || !ret) return ret; - m24_kbd = (m24_kbd_t *) malloc(sizeof(m24_kbd_t)); - memset(m24_kbd, 0x00, sizeof(m24_kbd_t)); + m24_kbd = (m24_kbd_t *) calloc(1, sizeof(m24_kbd_t)); machine_common_init(model); @@ -2404,10 +2401,9 @@ machine_xt_m240_init(const machine_t *model) nmi_init(); /* Allocate an NVR for this machine. */ - nvr = (nvr_t *) malloc(sizeof(nvr_t)); + nvr = (nvr_t *) calloc(1, sizeof(nvr_t)); if (nvr == NULL) return 0; - memset(nvr, 0x00, sizeof(nvr_t)); mm58274_init(nvr, model->nvrmask + 1); @@ -2438,8 +2434,7 @@ machine_xt_m19_init(const machine_t *model) m19_vid_t *vid; /* Do not move memory allocation elsewhere. */ - vid = (m19_vid_t *) malloc(sizeof(m19_vid_t)); - memset(vid, 0x00, sizeof(m19_vid_t)); + vid = (m19_vid_t *) calloc(1, sizeof(m19_vid_t)); machine_common_init(model); diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 0d1ba714b..efad869e1 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -651,8 +651,7 @@ t1000_recalcattrs(t1000_t *t1000) static void * t1000_init(UNUSED(const device_t *info)) { - t1000_t *t1000 = malloc(sizeof(t1000_t)); - memset(t1000, 0, sizeof(t1000_t)); + t1000_t *t1000 = calloc(1, sizeof(t1000_t)); loadfont("roms/machines/t1000/t1000font.bin", 8); cga_init(&t1000->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t1000); diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index 776e10c9f..833529ffb 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -73,8 +73,7 @@ zenith_scratchpad_init(UNUSED(const device_t *info)) { zenith_t *dev; - dev = (zenith_t *) malloc(sizeof(zenith_t)); - memset(dev, 0x00, sizeof(zenith_t)); + dev = (zenith_t *) calloc(1, sizeof(zenith_t)); dev->scratchpad_ram = malloc(0x4000); diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c index 4bb9b585a..fd2bb739f 100644 --- a/src/mem/catalyst_flash.c +++ b/src/mem/catalyst_flash.c @@ -192,8 +192,7 @@ catalyst_flash_init(UNUSED(const device_t *info)) FILE *fp; flash_t *dev; - dev = malloc(sizeof(flash_t)); - memset(dev, 0, sizeof(flash_t)); + dev = calloc(1, sizeof(flash_t)); sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); diff --git a/src/mem/i2c_eeprom.c b/src/mem/i2c_eeprom.c index 8e4a6cc14..a8ae7ed04 100644 --- a/src/mem/i2c_eeprom.c +++ b/src/mem/i2c_eeprom.c @@ -128,8 +128,7 @@ log2i(uint32_t i) void * i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable) { - i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); - memset(dev, 0, sizeof(i2c_eeprom_t)); + i2c_eeprom_t *dev = (i2c_eeprom_t *) calloc(1, sizeof(i2c_eeprom_t)); /* Round size up to the next power of 2. */ uint32_t pow_size = 1 << log2i(size); diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index 56a7ad0e0..7375b1f42 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -351,8 +351,7 @@ intel_flash_init(const device_t *info) flash_t *dev; uint8_t type = info->local & 0xff; - dev = malloc(sizeof(flash_t)); - memset(dev, 0, sizeof(flash_t)); + dev = calloc(1, sizeof(flash_t)); sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); diff --git a/src/mem/smram.c b/src/mem/smram.c index 0532e2dd5..afbc5475c 100644 --- a/src/mem/smram.c +++ b/src/mem/smram.c @@ -245,12 +245,11 @@ smram_add(void) return NULL; } - temp_smram = (smram_t *) malloc(sizeof(smram_t)); + temp_smram = (smram_t *) calloc(1, sizeof(smram_t)); if (temp_smram == NULL) { - fatal("smram_add(): temp_smram malloc failed\n"); + fatal("smram_add(): temp_smram calloc failed\n"); return NULL; } - memset(temp_smram, 0x00, sizeof(smram_t)); memset(&(temp_smram->mapping), 0x00, sizeof(mem_mapping_t)); /* Add struct to the beginning of the list if necessary.*/ diff --git a/src/mem/spd.c b/src/mem/spd.c index fee9b0b11..01cd7b464 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -221,8 +221,7 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) if (!(slot_mask & (1 << slot))) continue; /* slot disabled */ - spd_modules[slot] = (spd_t *) malloc(sizeof(spd_t)); - memset(spd_modules[slot], 0, sizeof(spd_t)); + spd_modules[slot] = (spd_t *) calloc(1, sizeof(spd_t)); spd_modules[slot]->slot = slot; spd_modules[slot]->size = rows[row]; diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 3dce35444..5a9c9c877 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -505,8 +505,7 @@ static void * sst_init(const device_t *info) { FILE *fp; - sst_t *dev = malloc(sizeof(sst_t)); - memset(dev, 0, sizeof(sst_t)); + sst_t *dev = calloc(1, sizeof(sst_t)); sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); diff --git a/src/network/net_3c501.c b/src/network/net_3c501.c index 21d71d75e..33e9d59bd 100644 --- a/src/network/net_3c501.c +++ b/src/network/net_3c501.c @@ -1080,8 +1080,7 @@ threec501_nic_init(UNUSED(const device_t *info)) uint32_t mac; threec501_t *dev; - dev = malloc(sizeof(threec501_t)); - memset(dev, 0x00, sizeof(threec501_t)); + dev = calloc(1, sizeof(threec501_t)); dev->maclocal[0] = 0x02; /* 02:60:8C (3Com OID) */ dev->maclocal[1] = 0x60; dev->maclocal[2] = 0x8C; diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index f96e76a11..31156fa9a 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -573,8 +573,7 @@ threec503_nic_init(UNUSED(const device_t *info)) uint32_t mac; threec503_t *dev; - dev = malloc(sizeof(threec503_t)); - memset(dev, 0x00, sizeof(threec503_t)); + dev = calloc(1, sizeof(threec503_t)); dev->maclocal[0] = 0x02; /* 02:60:8C (3Com OID) */ dev->maclocal[1] = 0x60; dev->maclocal[2] = 0x8C; diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index 297e11424..623dec56c 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -918,8 +918,7 @@ dp8390_set_defaults(dp8390_t *dev, uint8_t flags) void dp8390_mem_alloc(dp8390_t *dev, uint32_t start, uint32_t size) { - dev->mem = (uint8_t *) malloc(size * sizeof(uint8_t)); - memset(dev->mem, 0, size * sizeof(uint8_t)); + dev->mem = (uint8_t *) calloc(size, sizeof(uint8_t)); dev->mem_start = start; dev->mem_end = start + size; dev->mem_size = size; @@ -1007,8 +1006,7 @@ dp8390_soft_reset(dp8390_t *dev) static void * dp8390_init(UNUSED(const device_t *info)) { - dp8390_t *dp8390 = (dp8390_t *) malloc(sizeof(dp8390_t)); - memset(dp8390, 0, sizeof(dp8390_t)); + dp8390_t *dp8390 = (dp8390_t *) calloc(1, sizeof(dp8390_t)); /* Set values assuming WORD and only the clear IRQ flag - - the NIC can then call dp8390_set_defaults() again to diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 1f191e047..d3de47852 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -912,15 +912,13 @@ nic_init(const device_t *info) { uint32_t mac; uint32_t mac_oui; - char *rom; + char *rom = NULL; nic_t *dev; int set_oui = 0; - dev = malloc(sizeof(nic_t)); - memset(dev, 0x00, sizeof(nic_t)); + dev = calloc(1, sizeof(nic_t)); dev->name = info->name; dev->board = info->local; - rom = NULL; if (dev->board >= NE2K_RTL8019AS) { dev->base_address = 0x340; diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index c9323e702..fea20e3c9 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -2916,8 +2916,7 @@ pcnet_init(const device_t *info) int c; uint16_t checksum; - dev = malloc(sizeof(nic_t)); - memset(dev, 0x00, sizeof(nic_t)); + dev = calloc(1, sizeof(nic_t)); dev->name = info->name; dev->board = info->local & 0xff; diff --git a/src/network/net_plip.c b/src/network/net_plip.c index b1264b045..f80effeec 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -445,8 +445,7 @@ plip_rx(void *priv, uint8_t *buf, int io_len) static void * plip_lpt_init(void *lpt) { - plip_t *dev = (plip_t *) malloc(sizeof(plip_t)); - memset(dev, 0, sizeof(plip_t)); + plip_t *dev = (plip_t *) calloc(1, sizeof(plip_t)); plip_log(1, "PLIP: lpt_init()\n"); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 22fdc722d..11f1a74b2 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -133,7 +133,7 @@ net_slirp_clock_get_ns(UNUSED(void *opaque)) static void * net_slirp_timer_new(SlirpTimerCb cb, void *cb_opaque, UNUSED(void *opaque)) { - pc_timer_t *timer = malloc(sizeof(pc_timer_t)); + pc_timer_t *timer = calloc(1, sizeof(pc_timer_t)); timer_add(timer, cb, cb_opaque, 0); return timer; } @@ -422,8 +422,7 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv #ifndef _WIN32 slirp->pfd_size = 16 * sizeof(struct pollfd); - slirp->pfd = malloc(slirp->pfd_size); - memset(slirp->pfd, 0, slirp->pfd_size); + slirp->pfd = calloc(1, slirp->pfd_size); #endif /* Set the IP addresses to use. */ diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index d22b6076c..3d50c8f67 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -651,8 +651,7 @@ wd_init(const device_t *info) uint32_t mac; wd_t *dev; - dev = malloc(sizeof(wd_t)); - memset(dev, 0x00, sizeof(wd_t)); + dev = calloc(1, sizeof(wd_t)); dev->name = info->name; dev->board = info->local; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 809083395..3ca0b0ba5 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -114,8 +114,7 @@ ps2_nvr_init(const device_t *info) FILE *fp = NULL; int c; - nvr = (ps2_nvr_t *) malloc(sizeof(ps2_nvr_t)); - memset(nvr, 0x00, sizeof(ps2_nvr_t)); + nvr = (ps2_nvr_t *) calloc(1, sizeof(ps2_nvr_t)); if (info->local) nvr->size = 2048; diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 0b40bec90..0198444a0 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1952,7 +1952,7 @@ read_status(void *priv) static void * escp_init(void *lpt) { - escp_t *dev; + escp_t *dev = NULL; /* Initialize FreeType. */ if (ft_lib == NULL) { @@ -1964,8 +1964,7 @@ escp_init(void *lpt) } /* Initialize a device instance. */ - dev = (escp_t *) malloc(sizeof(escp_t)); - memset(dev, 0x00, sizeof(escp_t)); + dev = (escp_t *) calloc(1, sizeof(escp_t)); dev->ctrl = 0x04; dev->lpt = lpt; diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index dcd018881..1a9d5c0e8 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -366,13 +366,12 @@ ps_read_status(void *priv) static void * ps_init(void *lpt) { - ps_t *dev; + ps_t *dev = (ps_t *) calloc(1, sizeof(ps_t)); gsapi_revision_t rev; - dev = (ps_t *) malloc(sizeof(ps_t)); - memset(dev, 0x00, sizeof(ps_t)); dev->ctrl = 0x04; dev->lpt = lpt; + dev->pcl = false; /* Try loading the DLL. */ ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); @@ -415,11 +414,9 @@ ps_init(void *lpt) static void * pcl_init(void *lpt) { - ps_t *dev; + ps_t *dev = (ps_t *) calloc(1, sizeof(ps_t)); gsapi_revision_t rev; - dev = (ps_t *) malloc(sizeof(ps_t)); - memset(dev, 0x00, sizeof(ps_t)); dev->ctrl = 0x04; dev->lpt = lpt; dev->pcl = true; diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index ddf9faf53..e04ef9680 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -421,11 +421,9 @@ read_status(void *priv) static void * prnt_init(void *lpt) { - prnt_t *dev; - /* Initialize a device instance. */ - dev = (prnt_t *) malloc(sizeof(prnt_t)); - memset(dev, 0x00, sizeof(prnt_t)); + prnt_t *dev = (prnt_t *) calloc(1, sizeof(prnt_t)); + dev->ctrl = 0x04; dev->lpt = lpt; diff --git a/src/qt/win_opendir.c b/src/qt/win_opendir.c index 051ed20bb..46c7eb21e 100644 --- a/src/qt/win_opendir.c +++ b/src/qt/win_opendir.c @@ -40,21 +40,19 @@ opendir(const char *name) DIR *p; /* Create a new control structure. */ - p = (DIR *) malloc(sizeof(DIR)); + p = (DIR *) calloc(1, sizeof(DIR)); if (p == NULL) return (NULL); - memset(p, 0x00, sizeof(DIR)); p->flags = (DIR_F_LOWER | DIR_F_SANE); p->offset = 0; p->sts = 0; /* Create a work area. */ - p->dta = (char *) malloc(sizeof(FINDATA)); + p->dta = (char *) calloc(1, sizeof(FINDATA)); if (p->dta == NULL) { free(p); return (NULL); } - memset(p->dta, 0x00, sizeof(struct _finddata_t)); /* Add search filespec. */ strcpy(p->dir, name); diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 9e19e8524..b6a1698c5 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -925,8 +925,7 @@ aha_setnvr(x54x_t *dev) return; /* Allocate and initialize the EEPROM. */ - dev->nvr = (uint8_t *) malloc(NVR_SIZE); - memset(dev->nvr, 0x00, NVR_SIZE); + dev->nvr = (uint8_t *) calloc(1, NVR_SIZE); fp = nvr_fopen(dev->nvr_path, "rb"); if (fp) { diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 6d95ce44a..b235f2c3c 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1546,8 +1546,7 @@ buslogic_init(const device_t *info) dev = x54x_init(info); dev->bus = scsi_get_bus(); - dev->ven_data = malloc(sizeof(buslogic_data_t)); - memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); + dev->ven_data = calloc(1, sizeof(buslogic_data_t)); bl = (buslogic_data_t *) dev->ven_data; diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index def001624..d8008cf02 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -632,14 +632,10 @@ ncr53c400_init(const device_t *info) { const char *bios_ver = NULL; const char *fn; - ncr53c400_t *ncr400; - ncr_t *ncr; + ncr53c400_t *ncr400 = calloc(1, sizeof(ncr53c400_t)); + ncr_t *ncr = &ncr400->ncr; scsi_bus_t *scsi_bus; - ncr400 = malloc(sizeof(ncr53c400_t)); - memset(ncr400, 0x00, sizeof(ncr53c400_t)); - ncr = &ncr400->ncr; - ncr400->type = info->local; ncr->bus = scsi_get_bus(); diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index 27542028a..d26da3bb3 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -2530,10 +2530,7 @@ ncr53c8xx_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) static void * ncr53c8xx_init(const device_t *info) { - ncr53c8xx_t *dev; - - dev = malloc(sizeof(ncr53c8xx_t)); - memset(dev, 0x00, sizeof(ncr53c8xx_t)); + ncr53c8xx_t *dev = calloc(1, sizeof(ncr53c8xx_t)); dev->bus = scsi_get_bus(); diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c index e8f256bed..012d5524b 100644 --- a/src/scsi/scsi_pcscsi.c +++ b/src/scsi/scsi_pcscsi.c @@ -2204,10 +2204,7 @@ esp_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) static void * dc390_init(UNUSED(const device_t *info)) { - esp_t *dev; - - dev = malloc(sizeof(esp_t)); - memset(dev, 0x00, sizeof(esp_t)); + esp_t *dev = calloc(1, sizeof(esp_t)); dev->bus = scsi_get_bus(); @@ -2419,10 +2416,7 @@ ncr53c9x_mca_feedb(void *priv) static void * ncr53c9x_mca_init(const device_t *info) { - esp_t *dev; - - dev = malloc(sizeof(esp_t)); - memset(dev, 0x00, sizeof(esp_t)); + esp_t *dev = calloc(1, sizeof(esp_t)); dev->bus = scsi_get_bus(); diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 8be075833..cbf6ff205 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1162,8 +1162,7 @@ spock_mca_reset(void *priv) static void * spock_init(const device_t *info) { - spock_t *scsi = malloc(sizeof(spock_t)); - memset(scsi, 0x00, sizeof(spock_t)); + spock_t *scsi = calloc(1, sizeof(spock_t)); scsi->bus = scsi_get_bus(); diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 92de9d17b..ff5f584f1 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -472,14 +472,10 @@ t228_feedb(void *priv) static void * t128_init(const device_t *info) { - t128_t *t128; - ncr_t *ncr; + t128_t *t128 = calloc(1, sizeof(t128_t)); + ncr_t *ncr = &t128->ncr; scsi_bus_t *scsi_bus; - t128 = malloc(sizeof(t128_t)); - memset(t128, 0x00, sizeof(t128_t)); - ncr = &t128->ncr; - ncr->bus = scsi_get_bus(); scsi_bus = &ncr->scsibus; diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index 6876e4385..c248fbe92 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -287,10 +287,9 @@ x54x_bios_scsi_command(scsi_device_t *dev, uint8_t *cdb, uint8_t *buf, int len, static uint8_t x54x_bios_read_capacity(scsi_device_t *sd, uint8_t *buf, int transfer_size) { - uint8_t *cdb; + uint8_t *cdb = (uint8_t *) malloc(12);; uint8_t ret; - cdb = (uint8_t *) malloc(12); memset(cdb, 0, 12); cdb[0] = GPCMD_READ_CDROM_CAPACITY; @@ -305,10 +304,9 @@ x54x_bios_read_capacity(scsi_device_t *sd, uint8_t *buf, int transfer_size) static uint8_t x54x_bios_inquiry(scsi_device_t *sd, uint8_t *buf, int transfer_size) { - uint8_t *cdb; + uint8_t *cdb = (uint8_t *) malloc(12); uint8_t ret; - cdb = (uint8_t *) malloc(12); memset(cdb, 0, 12); cdb[0] = GPCMD_INQUIRY; cdb[4] = 36; @@ -324,14 +322,13 @@ x54x_bios_inquiry(scsi_device_t *sd, uint8_t *buf, int transfer_size) static uint8_t x54x_bios_command_08(scsi_device_t *sd, uint8_t *buffer, int transfer_size) { - uint8_t *rcbuf; + uint8_t *rcbuf = (uint8_t *) malloc(8); uint8_t ret; int i; memset(buffer, 0x00, 6); - rcbuf = (uint8_t *) malloc(8); - ret = x54x_bios_read_capacity(sd, rcbuf, transfer_size); + ret = x54x_bios_read_capacity(sd, rcbuf, transfer_size); if (ret) { free(rcbuf); return ret; @@ -353,13 +350,12 @@ x54x_bios_command_08(scsi_device_t *sd, uint8_t *buffer, int transfer_size) static int x54x_bios_command_15(scsi_device_t *sd, uint8_t *buffer, int transfer_size) { - uint8_t *inqbuf; + uint8_t *inqbuf = (uint8_t *) malloc(36); uint8_t *rcbuf; uint8_t ret; memset(buffer, 0x00, 6); - inqbuf = (uint8_t *) malloc(36); ret = x54x_bios_inquiry(sd, inqbuf, transfer_size); if (ret) { free(inqbuf); @@ -1896,13 +1892,11 @@ x54x_mem_disable(x54x_t *dev) void * x54x_init(const device_t *info) { - x54x_t *dev; + x54x_t *dev = calloc(1, sizeof(x54x_t)); /* Allocate control block and set up basic stuff. */ - dev = malloc(sizeof(x54x_t)); if (dev == NULL) return dev; - memset(dev, 0x00, sizeof(x54x_t)); dev->type = info->local; dev->card_bus = info->flags; diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c index 59349dcbe..76c7ba3f5 100644 --- a/src/sio/sio_82091aa.c +++ b/src/sio/sio_82091aa.c @@ -257,8 +257,7 @@ i82091aa_close(void *priv) static void * i82091aa_init(const device_t *info) { - i82091aa_t *dev = (i82091aa_t *) malloc(sizeof(i82091aa_t)); - memset(dev, 0, sizeof(i82091aa_t)); + i82091aa_t *dev = (i82091aa_t *) calloc(1, sizeof(i82091aa_t)); dev->fdc = device_add(&fdc_at_device); diff --git a/src/sio/sio_acc3221.c b/src/sio/sio_acc3221.c index 6fcac024c..d52949d46 100644 --- a/src/sio/sio_acc3221.c +++ b/src/sio/sio_acc3221.c @@ -454,8 +454,7 @@ acc3221_close(void *priv) static void * acc3221_init(UNUSED(const device_t *info)) { - acc3221_t *dev = (acc3221_t *) malloc(sizeof(acc3221_t)); - memset(dev, 0, sizeof(acc3221_t)); + acc3221_t *dev = (acc3221_t *) calloc(1, sizeof(acc3221_t)); dev->fdc = device_add(&fdc_at_device); diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c index ce250ff2b..5380e065a 100644 --- a/src/sio/sio_ali5123.c +++ b/src/sio/sio_ali5123.c @@ -463,8 +463,7 @@ ali5123_close(void *priv) static void * ali5123_init(const device_t *info) { - ali5123_t *dev = (ali5123_t *) malloc(sizeof(ali5123_t)); - memset(dev, 0, sizeof(ali5123_t)); + ali5123_t *dev = (ali5123_t *) calloc(1, sizeof(ali5123_t)); dev->fdc = device_add(&fdc_at_ali_device); diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index ae34730ac..ffa0ec9d0 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -65,8 +65,7 @@ sio_detect_close(void *priv) static void * sio_detect_init(UNUSED(const device_t *info)) { - sio_detect_t *dev = (sio_detect_t *) malloc(sizeof(sio_detect_t)); - memset(dev, 0, sizeof(sio_detect_t)); + sio_detect_t *dev = (sio_detect_t *) calloc(1, sizeof(sio_detect_t)); device_add(&fdc_at_smc_device); diff --git a/src/sio/sio_f82c710.c b/src/sio/sio_f82c710.c index 04dcf109a..8882f16e0 100644 --- a/src/sio/sio_f82c710.c +++ b/src/sio/sio_f82c710.c @@ -364,8 +364,7 @@ f82c710_close(void *priv) static void * f82c710_init(const device_t *info) { - upc_t *dev = (upc_t *) malloc(sizeof(upc_t)); - memset(dev, 0, sizeof(upc_t)); + upc_t *dev = (upc_t *) calloc(1, sizeof(upc_t)); dev->local = info->local; if (dev->local == 606) { diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index 7f02026e5..7f97e79b0 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -335,8 +335,7 @@ fdc37c669_close(void *priv) static void * fdc37c669_init(const device_t *info) { - fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); - memset(dev, 0, sizeof(fdc37c669_t)); + fdc37c669_t *dev = (fdc37c669_t *) calloc(1, sizeof(fdc37c669_t)); dev->id = next_id; diff --git a/src/sio/sio_fdc37c67x.c b/src/sio/sio_fdc37c67x.c index bac4685f5..f0fb8cd64 100644 --- a/src/sio/sio_fdc37c67x.c +++ b/src/sio/sio_fdc37c67x.c @@ -591,8 +591,7 @@ fdc37c67x_close(void *priv) static void * fdc37c67x_init(const device_t *info) { - fdc37c67x_t *dev = (fdc37c67x_t *) malloc(sizeof(fdc37c67x_t)); - memset(dev, 0, sizeof(fdc37c67x_t)); + fdc37c67x_t *dev = (fdc37c67x_t *) calloc(1, sizeof(fdc37c67x_t)); dev->fdc = device_add(&fdc_at_smc_device); diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index 6340218b7..530fff216 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -312,8 +312,7 @@ fdc37c6xx_close(void *priv) static void * fdc37c6xx_init(const device_t *info) { - fdc37c6xx_t *dev = (fdc37c6xx_t *) malloc(sizeof(fdc37c6xx_t)); - memset(dev, 0, sizeof(fdc37c6xx_t)); + fdc37c6xx_t *dev = (fdc37c6xx_t *) calloc(1, sizeof(fdc37c6xx_t)); dev->fdc = device_add(&fdc_at_smc_device); diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 0279903c6..42908ecaf 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -918,8 +918,7 @@ access_bus_close(void *priv) static void * access_bus_init(UNUSED(const device_t *info)) { - access_bus_t *dev = (access_bus_t *) malloc(sizeof(access_bus_t)); - memset(dev, 0, sizeof(access_bus_t)); + access_bus_t *dev = (access_bus_t *) calloc(1, sizeof(access_bus_t)); return dev; } @@ -950,8 +949,7 @@ static void * fdc37c93x_init(const device_t *info) { int is_compaq; - fdc37c93x_t *dev = (fdc37c93x_t *) malloc(sizeof(fdc37c93x_t)); - memset(dev, 0, sizeof(fdc37c93x_t)); + fdc37c93x_t *dev = (fdc37c93x_t *) calloc(1, sizeof(fdc37c93x_t)); dev->fdc = device_add(&fdc_at_smc_device); diff --git a/src/sio/sio_fdc37m60x.c b/src/sio/sio_fdc37m60x.c index aab4d8968..671b3581b 100644 --- a/src/sio/sio_fdc37m60x.c +++ b/src/sio/sio_fdc37m60x.c @@ -306,8 +306,7 @@ fdc37m60x_close(void *priv) static void * fdc37m60x_init(const device_t *info) { - fdc37m60x_t *dev = (fdc37m60x_t *) malloc(sizeof(fdc37m60x_t)); - memset(dev, 0, sizeof(fdc37m60x_t)); + fdc37m60x_t *dev = (fdc37m60x_t *) calloc(1, sizeof(fdc37m60x_t)); SIO_INDEX_PORT = info->local; dev->fdc = device_add(&fdc_at_smc_device); diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c index 610d69197..aee1b6a1d 100644 --- a/src/sio/sio_it86x1f.c +++ b/src/sio/sio_it86x1f.c @@ -799,8 +799,7 @@ it86x1f_close(void *priv) static void * it86x1f_init(UNUSED(const device_t *info)) { - it86x1f_t *dev = (it86x1f_t *) malloc(sizeof(it86x1f_t)); - memset(dev, 0, sizeof(it86x1f_t)); + it86x1f_t *dev = (it86x1f_t *) calloc(1, sizeof(it86x1f_t)); uint8_t i; for (i = 0; i < (sizeof(it86x1f_models) / sizeof(it86x1f_models[0])); i++) { diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index b21c2d1fc..5da43581f 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -467,8 +467,7 @@ pc87306_close(void *priv) static void * pc87306_init(UNUSED(const device_t *info)) { - pc87306_t *dev = (pc87306_t *) malloc(sizeof(pc87306_t)); - memset(dev, 0, sizeof(pc87306_t)); + pc87306_t *dev = (pc87306_t *) calloc(1, sizeof(pc87306_t)); dev->fdc = device_add(&fdc_at_nsc_device); diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index 1f84152f5..eba0748c9 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -593,8 +593,7 @@ pc87307_close(void *priv) static void * pc87307_init(const device_t *info) { - pc87307_t *dev = (pc87307_t *) malloc(sizeof(pc87307_t)); - memset(dev, 0, sizeof(pc87307_t)); + pc87307_t *dev = (pc87307_t *) calloc(1, sizeof(pc87307_t)); dev->id = info->local & 0xff; diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index f445ee189..1b790bc6b 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -466,8 +466,7 @@ pc87309_close(void *priv) static void * pc87309_init(const device_t *info) { - pc87309_t *dev = (pc87309_t *) malloc(sizeof(pc87309_t)); - memset(dev, 0, sizeof(pc87309_t)); + pc87309_t *dev = (pc87309_t *) calloc(1, sizeof(pc87309_t)); dev->id = info->local & 0xff; diff --git a/src/sio/sio_pc87311.c b/src/sio/sio_pc87311.c index f1b823e47..1f38e6aa8 100644 --- a/src/sio/sio_pc87311.c +++ b/src/sio/sio_pc87311.c @@ -269,8 +269,7 @@ pc87311_close(void *priv) static void * pc87311_init(const device_t *info) { - pc87311_t *dev = (pc87311_t *) malloc(sizeof(pc87311_t)); - memset(dev, 0, sizeof(pc87311_t)); + pc87311_t *dev = (pc87311_t *) calloc(1, sizeof(pc87311_t)); /* Avoid conflicting with machines that make no use of the PC87311 Internal IDE */ HAS_IDE_FUNCTIONALITY = info->local; diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c index 494c6d8bb..f746306bd 100644 --- a/src/sio/sio_pc87332.c +++ b/src/sio/sio_pc87332.c @@ -323,8 +323,7 @@ pc87332_close(void *priv) static void * pc87332_init(const device_t *info) { - pc87332_t *dev = (pc87332_t *) malloc(sizeof(pc87332_t)); - memset(dev, 0, sizeof(pc87332_t)); + pc87332_t *dev = (pc87332_t *) calloc(1, sizeof(pc87332_t)); dev->fdc = device_add(&fdc_at_nsc_device); diff --git a/src/sio/sio_prime3b.c b/src/sio/sio_prime3b.c index 1633c844b..2cadda2ab 100644 --- a/src/sio/sio_prime3b.c +++ b/src/sio/sio_prime3b.c @@ -257,8 +257,7 @@ prime3b_close(void *priv) static void * prime3b_init(const device_t *info) { - prime3b_t *dev = (prime3b_t *) malloc(sizeof(prime3b_t)); - memset(dev, 0, sizeof(prime3b_t)); + prime3b_t *dev = (prime3b_t *) calloc(1, sizeof(prime3b_t)); /* Avoid conflicting with machines that make no use of the Prime3B Internal IDE */ HAS_IDE_FUNCTIONALITY = info->local; diff --git a/src/sio/sio_prime3c.c b/src/sio/sio_prime3c.c index 68361d3e0..e646a3653 100644 --- a/src/sio/sio_prime3c.c +++ b/src/sio/sio_prime3c.c @@ -296,8 +296,7 @@ prime3c_close(void *priv) static void * prime3c_init(const device_t *info) { - prime3c_t *dev = (prime3c_t *) malloc(sizeof(prime3c_t)); - memset(dev, 0, sizeof(prime3c_t)); + prime3c_t *dev = (prime3c_t *) calloc(1, sizeof(prime3c_t)); /* Avoid conflicting with machines that make no use of the Prime3C Internal IDE */ HAS_IDE_FUNCTIONALITY = info->local; diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index e3ef81e11..b3d5259a2 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -328,8 +328,7 @@ um8669f_init(const device_t *info) { um8669f_log("UM8669F: init(%02X)\n", info->local); - um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t)); - memset(dev, 0, sizeof(um8669f_t)); + um8669f_t *dev = (um8669f_t *) calloc(1, sizeof(um8669f_t)); dev->pnp_card = isapnp_add_card(um8669f_pnp_rom, sizeof(um8669f_pnp_rom), um8669f_pnp_config_changed, NULL, NULL, NULL, dev); for (uint8_t i = 0; i < (sizeof(um8669f_pnp_defaults) / sizeof(isapnp_device_config_t)); i++) diff --git a/src/sio/sio_vt82c686.c b/src/sio/sio_vt82c686.c index 47b5e1c09..fa0bf3c63 100644 --- a/src/sio/sio_vt82c686.c +++ b/src/sio/sio_vt82c686.c @@ -287,8 +287,7 @@ vt82c686_close(void *priv) static void * vt82c686_init(UNUSED(const device_t *info)) { - vt82c686_t *dev = (vt82c686_t *) malloc(sizeof(vt82c686_t)); - memset(dev, 0, sizeof(vt82c686_t)); + vt82c686_t *dev = (vt82c686_t *) calloc(1, sizeof(vt82c686_t)); dev->fdc = device_add(&fdc_at_smc_device); dev->fdc_dma = 2; diff --git a/src/sio/sio_w83787f.c b/src/sio/sio_w83787f.c index 69bdb1220..ea5169afc 100644 --- a/src/sio/sio_w83787f.c +++ b/src/sio/sio_w83787f.c @@ -443,8 +443,7 @@ w83787f_close(void *priv) static void * w83787f_init(const device_t *info) { - w83787f_t *dev = (w83787f_t *) malloc(sizeof(w83787f_t)); - memset(dev, 0, sizeof(w83787f_t)); + w83787f_t *dev = (w83787f_t *) calloc(1, sizeof(w83787f_t)); HAS_IDE_FUNCTIONALITY = (info->local & 0x30); diff --git a/src/sio/sio_w83877f.c b/src/sio/sio_w83877f.c index a6ea6f4e4..90a3dba1b 100644 --- a/src/sio/sio_w83877f.c +++ b/src/sio/sio_w83877f.c @@ -444,8 +444,7 @@ w83877f_close(void *priv) static void * w83877f_init(const device_t *info) { - w83877f_t *dev = (w83877f_t *) malloc(sizeof(w83877f_t)); - memset(dev, 0, sizeof(w83877f_t)); + w83877f_t *dev = (w83877f_t *) calloc(1, sizeof(w83877f_t)); dev->fdc = device_add(&fdc_at_winbond_device); diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index 7df0163a5..1d743cc64 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -593,8 +593,7 @@ w83977f_close(void *priv) static void * w83977f_init(const device_t *info) { - w83977f_t *dev = (w83977f_t *) malloc(sizeof(w83977f_t)); - memset(dev, 0, sizeof(w83977f_t)); + w83977f_t *dev = (w83977f_t *) calloc(1, sizeof(w83977f_t)); dev->type = info->local & 0x0f; dev->hefras = info->local & 0x40; diff --git a/src/sound/midi.c b/src/sound/midi.c index e9b4a82b6..9f83e88dc 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -157,8 +157,7 @@ midi_out_device_init(void) void midi_out_init(midi_device_t *device) { - midi_out = (midi_t *) malloc(sizeof(midi_t)); - memset(midi_out, 0, sizeof(midi_t)); + midi_out = (midi_t *) calloc(1, sizeof(midi_t)); midi_out->m_out_device = device; } @@ -166,8 +165,7 @@ midi_out_init(midi_device_t *device) void midi_in_init(midi_device_t *device, midi_t **mididev) { - *mididev = (midi_t *) malloc(sizeof(midi_t)); - memset(*mididev, 0, sizeof(midi_t)); + *mididev = (midi_t *) calloc(1, sizeof(midi_t)); (*mididev)->m_in_device = device; } @@ -394,8 +392,7 @@ midi_in_handler(int set, void (*msg)(void *priv, uint8_t *msg, uint32_t len), in if ((mih_first != NULL) && (mih_last == NULL)) fatal("First MIDI IN handler present with no last MIDI IN handler\n"); - temp = (midi_in_handler_t *) malloc(sizeof(midi_in_handler_t)); - memset(temp, 0, sizeof(midi_in_handler_t)); + temp = (midi_in_handler_t *) calloc(1, sizeof(midi_in_handler_t)); temp->msg = msg; temp->sysex = sysex; temp->priv = priv; diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 51383bdcf..6ba017cd1 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -262,8 +262,7 @@ fluidsynth_init(UNUSED(const device_t *info)) al_set_midi(data->samplerate, data->buf_size); - dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + dev = calloc(1, sizeof(midi_device_t)); dev->play_msg = fluidsynth_msg; dev->play_sysex = fluidsynth_sysex; diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index f95445540..ab2165c52 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -298,8 +298,7 @@ mt32emu_init(char *control_rom, char *pcm_rom) al_set_midi(samplerate, buf_size); - dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + dev = calloc(1, sizeof(midi_device_t)); dev->play_msg = mt32_msg; dev->play_sysex = mt32_sysex; diff --git a/src/sound/midi_opl4.c b/src/sound/midi_opl4.c index cf99e092d..e1f80b0f5 100644 --- a/src/sound/midi_opl4.c +++ b/src/sound/midi_opl4.c @@ -658,8 +658,7 @@ opl4_init(const device_t *info) midi_device_t *dev; extern void al_set_midi(int freq, int buf_size); - dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + dev = calloc(1, sizeof(midi_device_t)); dev->play_msg = opl4_midi_msg; dev->play_sysex = opl4_midi_sysex; diff --git a/src/sound/midi_rtmidi.cpp b/src/sound/midi_rtmidi.cpp index e2458c9fe..9da3fdb91 100644 --- a/src/sound/midi_rtmidi.cpp +++ b/src/sound/midi_rtmidi.cpp @@ -73,8 +73,7 @@ rtmidi_play_sysex(uint8_t *sysex, unsigned int len) void * rtmidi_output_init(UNUSED(const device_t *info)) { - midi_device_t *dev = (midi_device_t *) malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + midi_device_t *dev = (midi_device_t *) calloc(1, sizeof(midi_device_t)); dev->play_msg = rtmidi_play_msg; dev->play_sysex = rtmidi_play_sysex; @@ -156,8 +155,7 @@ rtmidi_input_callback(UNUSED(double timeStamp), std::vector *mess void * rtmidi_input_init(UNUSED(const device_t *info)) { - midi_device_t *dev = (midi_device_t *) malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); + midi_device_t *dev = (midi_device_t *) calloc(1, sizeof(midi_device_t)); try { if (!midiin) diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index f6c01c4ea..e92830f67 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -577,8 +577,7 @@ ac97_codec_getrate(void *priv, uint8_t reg) static void * ac97_codec_init(const device_t *info) { - ac97_codec_t *dev = malloc(sizeof(ac97_codec_t)); - memset(dev, 0, sizeof(ac97_codec_t)); + ac97_codec_t *dev = calloc(1, sizeof(ac97_codec_t)); for (; dev->model < (sizeof(ac97_codecs) / sizeof(ac97_codecs[0])); dev->model++) { if (ac97_codecs[dev->model].device->local == info->local) diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index e3fa9d2e4..8c1e45c40 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -787,8 +787,7 @@ ac97_via_speed_changed(void *priv) static void * ac97_via_init(UNUSED(const device_t *info)) { - ac97_via_t *dev = malloc(sizeof(ac97_via_t)); - memset(dev, 0, sizeof(ac97_via_t)); + ac97_via_t *dev = calloc(1, sizeof(ac97_via_t)); ac97_via_log("AC97 VIA: init()\n"); diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 983ccf7d3..1f307596c 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -103,8 +103,7 @@ adlib_mca_feedb(void *priv) void * adlib_init(UNUSED(const device_t *info)) { - adlib_t *adlib = malloc(sizeof(adlib_t)); - memset(adlib, 0, sizeof(adlib_t)); + adlib_t *adlib = calloc(1, sizeof(adlib_t)); adlib_log("adlib_init\n"); fm_driver_get(FM_YM3812, &adlib->opl); diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 7b5deaac5..8a809803d 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -1066,8 +1066,7 @@ adgold_init(UNUSED(const device_t *info)) FILE *fp; int c; double out; - adgold_t *adgold = malloc(sizeof(adgold_t)); - memset(adgold, 0, sizeof(adgold_t)); + adgold_t *adgold = calloc(1, sizeof(adgold_t)); adgold->dma = device_get_config_int("dma"); adgold->irq = device_get_config_int("irq"); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 07add5062..9e520bcf5 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -2645,8 +2645,7 @@ static void es137x_speed_changed(void *priv); static void * es1370_init(const device_t *info) { - es137x_t *dev = malloc(sizeof(es137x_t)); - memset(dev, 0x00, sizeof(es137x_t)); + es137x_t *dev = calloc(1, sizeof(es137x_t)); dev->type = info->local; if (device_get_config_int("receive_input")) @@ -2689,8 +2688,7 @@ es1370_init(const device_t *info) static void * es1371_init(const device_t *info) { - es137x_t *dev = malloc(sizeof(es137x_t)); - memset(dev, 0x00, sizeof(es137x_t)); + es137x_t *dev = calloc(1, sizeof(es137x_t)); dev->type = info->local & 0xffffff00; if (device_get_config_int("receive_input")) diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index cf05203f3..dfbab2bd3 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -974,8 +974,7 @@ azt_init(const device_t *info) int loaded_from_eeprom = 0; uint16_t addr_setting; uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; - azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); - memset(azt2316a, 0, sizeof(azt2316a_t)); + azt2316a_t *azt2316a = calloc(1, sizeof(azt2316a_t)); azt2316a->type = info->local; @@ -1226,8 +1225,7 @@ azt_init(const device_t *info) 2x4 to 2x5 -> Mixer interface 2x6, 2xA, 2xC, 2xE -> DSP chip 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ - azt2316a->sb = malloc(sizeof(sb_t)); - memset(azt2316a->sb, 0, sizeof(sb_t)); + azt2316a->sb = calloc(1, sizeof(sb_t)); azt2316a->sb->opl_enabled = device_get_config_int("opl"); @@ -1259,8 +1257,7 @@ azt_init(const device_t *info) sound_set_cd_audio_filter(sbpro_filter_cd_audio, azt2316a->sb); if (azt2316a->cur_mpu401_enabled) { - azt2316a->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(azt2316a->mpu, 0, sizeof(mpu_t)); + azt2316a->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); mpu401_init(azt2316a->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); } else azt2316a->mpu = NULL; diff --git a/src/sound/snd_cmi8x38.c b/src/sound/snd_cmi8x38.c index 833124bb2..5f75d0dc3 100644 --- a/src/sound/snd_cmi8x38.c +++ b/src/sound/snd_cmi8x38.c @@ -1434,8 +1434,7 @@ cmi8x38_reset(void *priv) static void * cmi8x38_init(const device_t *info) { - cmi8x38_t *dev = malloc(sizeof(cmi8x38_t)); - memset(dev, 0, sizeof(cmi8x38_t)); + cmi8x38_t *dev = calloc(1, sizeof(cmi8x38_t)); /* Set the chip type. */ if ((info->local == CMEDIA_CMI8738_6CH) && !device_get_config_int("six_channel")) diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 2ec81b53d..f8db04fed 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -181,8 +181,7 @@ cms_read(uint16_t addr, void *priv) void * cms_init(UNUSED(const device_t *info)) { - cms_t *cms = malloc(sizeof(cms_t)); - memset(cms, 0, sizeof(cms_t)); + cms_t *cms = calloc(1, sizeof(cms_t)); uint16_t addr = device_get_config_hex16("base"); io_sethandler(addr, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 0a383e13f..d164e3ac6 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -468,10 +468,9 @@ cs423x_slam_write(UNUSED(uint16_t addr), uint8_t val, void *priv) if (dev->slam_config) cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev); else - dev->slam_config = (isapnp_device_config_t *) malloc(sizeof(isapnp_device_config_t)); + dev->slam_config = (isapnp_device_config_t *) calloc(1, sizeof(isapnp_device_config_t)); /* Start new logical device. */ - memset(dev->slam_config, 0, sizeof(isapnp_device_config_t)); dev->slam_ld = val; break; @@ -846,8 +845,7 @@ cs423x_reset(void *priv) static void * cs423x_init(const device_t *info) { - cs423x_t *dev = malloc(sizeof(cs423x_t)); - memset(dev, 0, sizeof(cs423x_t)); + cs423x_t *dev = calloc(1, sizeof(cs423x_t)); /* Initialize model-specific data. */ dev->type = info->local & 0xff; diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 5f13d2f8e..8eb5260c0 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -2171,8 +2171,7 @@ emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) emu8k->rom[0x7ffff] = 0; } - emu8k->empty = malloc(2 * BLOCK_SIZE_WORDS); - memset(emu8k->empty, 0, 2 * BLOCK_SIZE_WORDS); + emu8k->empty = calloc(2, BLOCK_SIZE_WORDS); int j = 0; for (; j < 0x8; j++) { @@ -2186,8 +2185,7 @@ emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) /*Clip to 28MB, since that's the max that we can address. */ if (onboard_ram > 0x7000) onboard_ram = 0x7000; - emu8k->ram = malloc(onboard_ram * 1024); - memset(emu8k->ram, 0, onboard_ram * 1024); + emu8k->ram = calloc(1024, onboard_ram); const int i_end = onboard_ram >> 7; int i = 0; for (; i < i_end; i++, j++) { diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index b39d77708..9dcf0f00b 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -1348,12 +1348,10 @@ gus_init(UNUSED(const device_t *info)) int c; double out = 1.0; uint8_t gus_ram = device_get_config_int("gus_ram"); - gus_t *gus = malloc(sizeof(gus_t)); - memset(gus, 0x00, sizeof(gus_t)); + gus_t *gus = calloc(1, sizeof(gus_t)); gus->gus_end_ram = 1 << (18 + gus_ram); - gus->ram = (uint8_t *) malloc(gus->gus_end_ram); - memset(gus->ram, 0x00, (gus->gus_end_ram)); + gus->ram = (uint8_t *) calloc(1, gus->gus_end_ram); for (c = 0; c < 32; c++) { gus->ctrl[c] = 1; diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index 8fb526f14..812a649a8 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -82,8 +82,7 @@ dac_get_buffer(int32_t *buffer, int len, void *priv) static void * dac_init(void *lpt) { - lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); - memset(lpt_dac, 0, sizeof(lpt_dac_t)); + lpt_dac_t *lpt_dac = calloc(1, sizeof(lpt_dac_t)); lpt_dac->lpt = lpt; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index bd794fffb..06160ce4c 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -115,8 +115,7 @@ dss_callback(void *priv) static void * dss_init(void *lpt) { - dss_t *dss = malloc(sizeof(dss_t)); - memset(dss, 0, sizeof(dss_t)); + dss_t *dss = calloc(1, sizeof(dss_t)); dss->lpt = lpt; diff --git a/src/sound/snd_opl2board.c b/src/sound/snd_opl2board.c index f1bda3398..a76b6bf4d 100644 --- a/src/sound/snd_opl2board.c +++ b/src/sound/snd_opl2board.c @@ -124,8 +124,7 @@ opl2board_device_mca_feedb(void *priv) void * opl2board_device_init(UNUSED(const device_t *info)) { - opl2board_device_t *serial = malloc(sizeof(opl2board_device_t)); - memset(serial, 0, sizeof(opl2board_device_t)); + opl2board_device_t *serial = calloc(1, sizeof(opl2board_device_t)); opl2board_device_log("opl2board_device_init\n"); fm_driver_get(FM_OPL2BOARD, &serial->opl); diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index d69986d98..7058d918c 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -419,8 +419,7 @@ optimc_init(const device_t *info) music_add_handler(sb_get_music_buffer_sbpro, optimc->sb); sound_set_cd_audio_filter(sbpro_filter_cd_audio, optimc->sb); /* CD audio filter for the default context */ - optimc->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(optimc->mpu, 0, sizeof(mpu_t)); + optimc->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); mpu401_init(optimc->mpu, optimc->cur_mpu401_addr, optimc->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); if (device_get_config_int("receive_input")) diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 110ee95c9..400f176a8 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -2320,8 +2320,7 @@ pas16_init(const device_t *info) fm_driver_get(FM_YMF262, &pas16->opl); sb_dsp_set_real_opl(&pas16->dsp, 1); sb_dsp_init(&pas16->dsp, SB_DSP_201, SB_SUBTYPE_DEFAULT, pas16); - pas16->mpu = (mpu_t *) malloc(sizeof(mpu_t)); - memset(pas16->mpu, 0, sizeof(mpu_t)); + pas16->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); mpu401_init(pas16->mpu, 0, 0, M_UART, device_get_config_int("receive_input401")); sb_dsp_set_mpu(&pas16->dsp, pas16->mpu); diff --git a/src/sound/snd_ps1.c b/src/sound/snd_ps1.c index 531c2a369..15cad0051 100644 --- a/src/sound/snd_ps1.c +++ b/src/sound/snd_ps1.c @@ -166,8 +166,7 @@ ps1snd_get_buffer(int32_t *buffer, int len, void *priv) static void * ps1snd_init(UNUSED(const device_t *info)) { - ps1snd_t *ps1snd = malloc(sizeof(ps1snd_t)); - memset(ps1snd, 0x00, sizeof(ps1snd_t)); + ps1snd_t *ps1snd = calloc(1, sizeof(ps1snd_t)); sn76489_init(&ps1snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 657f94b01..0b09a7b2e 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -193,8 +193,7 @@ pssj_get_buffer(int32_t *buffer, int len, void *priv) void * pssj_init(UNUSED(const device_t *info)) { - pssj_t *pssj = malloc(sizeof(pssj_t)); - memset(pssj, 0, sizeof(pssj_t)); + pssj_t *pssj = calloc(1, sizeof(pssj_t)); sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); @@ -208,8 +207,7 @@ pssj_init(UNUSED(const device_t *info)) void * pssj_1e0_init(UNUSED(const device_t *info)) { - pssj_t *pssj = malloc(sizeof(pssj_t)); - memset(pssj, 0, sizeof(pssj_t)); + pssj_t *pssj = calloc(1, sizeof(pssj_t)); sn76489_init(&pssj->sn76489, 0x01e0, 0x0004, PSSJ, 3579545); @@ -223,8 +221,7 @@ pssj_1e0_init(UNUSED(const device_t *info)) void * pssj_isa_init(UNUSED(const device_t *info)) { - pssj_t *pssj = malloc(sizeof(pssj_t)); - memset(pssj, 0, sizeof(pssj_t)); + pssj_t *pssj = calloc(1, sizeof(pssj_t)); uint16_t addr = device_get_config_hex16("base"); diff --git a/src/sound/snd_sn76489.c b/src/sound/snd_sn76489.c index 8fb8db06e..89064bea4 100644 --- a/src/sound/snd_sn76489.c +++ b/src/sound/snd_sn76489.c @@ -228,8 +228,7 @@ sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int fre void * sn76489_device_init(UNUSED(const device_t *info)) { - sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); - memset(sn76489, 0, sizeof(sn76489_t)); + sn76489_t *sn76489 = calloc(1, sizeof(sn76489_t)); sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); @@ -239,8 +238,7 @@ sn76489_device_init(UNUSED(const device_t *info)) void * ncr8496_device_init(UNUSED(const device_t *info)) { - sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); - memset(sn76489, 0, sizeof(sn76489_t)); + sn76489_t *sn76489 = calloc(1, sizeof(sn76489_t)); sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); @@ -250,8 +248,7 @@ ncr8496_device_init(UNUSED(const device_t *info)) void * tndy_device_init(UNUSED(const device_t *info)) { - sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); - memset(sn76489, 0, sizeof(sn76489_t)); + sn76489_t *sn76489 = calloc(1, sizeof(sn76489_t)); uint16_t addr = device_get_config_hex16("base"); diff --git a/src/sound/snd_ssi2001.c b/src/sound/snd_ssi2001.c index e03be6b4c..762b243be 100644 --- a/src/sound/snd_ssi2001.c +++ b/src/sound/snd_ssi2001.c @@ -70,8 +70,7 @@ ssi2001_write(uint16_t addr, uint8_t val, void *priv) void * ssi2001_init(UNUSED(const device_t *info)) { - ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); - memset(ssi2001, 0, sizeof(ssi2001_t)); + ssi2001_t *ssi2001 = calloc(1, sizeof(ssi2001_t)); ssi2001->psid = sid_init(0); sid_reset(ssi2001->psid); @@ -110,10 +109,8 @@ entertainer_write(uint16_t addr, uint8_t val, void *priv) void * entertainer_init(UNUSED(const device_t *info)) { - ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); - entertainer_t *entertainer = malloc(sizeof(entertainer_t)); - memset(ssi2001, 0, sizeof(ssi2001_t)); - memset(entertainer, 0, sizeof(entertainer_t)); + ssi2001_t *ssi2001 = calloc(1, sizeof(ssi2001_t)); + entertainer_t *entertainer = calloc(1, sizeof(entertainer_t)); ssi2001->psid = sid_init(0); sid_reset(ssi2001->psid); diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 833308280..0f37cbf27 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -107,8 +107,7 @@ wss_get_music_buffer(int32_t *buffer, int len, void *priv) void * wss_init(UNUSED(const device_t *info)) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = calloc(1, sizeof(wss_t)); uint16_t addr = device_get_config_hex16("base"); wss->opl_enabled = device_get_config_int("opl"); @@ -209,8 +208,7 @@ ncr_audio_mca_feedb(void *priv) void * ncr_audio_init(UNUSED(const device_t *info)) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = calloc(1, sizeof(wss_t)); fm_driver_get(FM_YMF262, &wss->opl); ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); From 403a7a995b2719f92d652d291338376f840832d3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 1 Feb 2025 21:39:15 +0100 Subject: [PATCH 0182/1190] New recompiler: read the two bytes of unaligned 16-bit immediates into the correct IR bytes, fixes Windows 95 Setup GPF'ing. --- src/codegen_new/codegen_ops_helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen_new/codegen_ops_helpers.c b/src/codegen_new/codegen_ops_helpers.c index f2a4ce41a..037d91469 100644 --- a/src/codegen_new/codegen_ops_helpers.c +++ b/src/codegen_new/codegen_ops_helpers.c @@ -18,8 +18,8 @@ void LOAD_IMMEDIATE_FROM_RAM_16_unaligned(UNUSED(codeblock_t *block), ir_data_t *ir, int dest_reg, uint32_t addr) { /*Word access that crosses two pages. Perform reads from both pages, shift and combine*/ - uop_MOVZX_REG_PTR_8(ir, IREG_temp3_W, get_ram_ptr(addr)); - uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr + 1)); + uop_MOVZX_REG_PTR_8(ir, IREG_temp3_W, get_ram_ptr(addr + 1)); + uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr)); uop_SHL_IMM(ir, IREG_temp3_W, IREG_temp3_W, 8); uop_OR(ir, dest_reg, dest_reg, IREG_temp3_W); } From d881321268e64e574868b1330b8cfc8443f4b310 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 1 Feb 2025 22:19:55 +0100 Subject: [PATCH 0183/1190] Minor ATI 8514/A Ultra add-on change of the night (February 1st, 2025) Actually make it work on NT by setting bit 0 of the read only config2 reg. --- src/video/vid_ati_mach8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index c9cdca0db..0ef4df6df 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -6239,7 +6239,7 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) if (dev->vram_amount >= 1024) mach->config1 |= 0x20; - mach->config2 = 0x02; + mach->config2 = 0x01 | 0x02; } static int From 5f273265aed164af1280c30a5e84f079345bda7c Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 26 Jan 2025 15:15:53 -0500 Subject: [PATCH 0184/1190] Assorted warning fixes --- src/86box.c | 4 +- src/acpi.c | 2 +- src/cdrom/cdrom.c | 4 +- src/cdrom/cdrom_image_viso.c | 2 +- src/chipset/ali1409.c | 7 +- src/chipset/sis_5513_p2i.c | 4 +- src/chipset/sis_5595_pmu.c | 2 +- src/chipset/umc_8890.c | 3 +- src/chipset/wd76c10.c | 3 +- src/codegen/codegen_ops_arith.h | 60 ++-- src/codegen/codegen_ops_fpu.h | 206 ++++++----- src/codegen/codegen_ops_jump.h | 94 ++--- src/codegen/codegen_ops_logic.h | 48 +-- src/codegen/codegen_ops_misc.h | 16 +- src/codegen/codegen_ops_mmx.h | 80 +++-- src/codegen/codegen_ops_mov.h | 58 +-- src/codegen/codegen_ops_shift.h | 12 +- src/codegen/codegen_ops_stack.h | 144 ++++---- src/codegen/codegen_ops_x86-64.h | 18 +- src/codegen/codegen_ops_xchg.h | 66 ++-- src/codegen/codegen_x86-64.c | 2 +- src/codegen_new/codegen_ir.c | 1 + src/codegen_new/codegen_ir_defs.h | 2 +- src/codegen_new/codegen_ops.c | 1 + src/codegen_new/codegen_ops_3dnow.c | 4 +- src/codegen_new/codegen_ops_arith.c | 28 +- src/codegen_new/codegen_ops_branch.c | 16 +- src/codegen_new/codegen_ops_fpu_arith.c | 52 +-- src/codegen_new/codegen_ops_fpu_constant.c | 4 +- src/codegen_new/codegen_ops_fpu_misc.c | 2 +- src/codegen_new/codegen_ops_helpers.h | 4 +- src/codegen_new/codegen_ops_jump.c | 30 +- src/codegen_new/codegen_ops_logic.c | 16 +- src/codegen_new/codegen_ops_misc.c | 28 +- src/codegen_new/codegen_ops_mmx_arith.c | 5 +- src/codegen_new/codegen_ops_mmx_cmp.c | 5 +- src/codegen_new/codegen_ops_mmx_pack.c | 5 +- src/codegen_new/codegen_ops_mov.c | 22 +- src/codegen_new/codegen_ops_stack.c | 42 +-- src/cpu/386.c | 1 + src/cpu/386_common.c | 8 +- src/cpu/386_dynarec.c | 1 + src/cpu/808x.c | 5 +- src/cpu/codegen_timing_486.c | 2 +- src/cpu/codegen_timing_k5.c | 5 +- src/cpu/codegen_timing_k6.c | 5 +- src/cpu/codegen_timing_p6.c | 4 +- src/cpu/codegen_timing_winchip.c | 2 +- src/cpu/codegen_timing_winchip2.c | 2 +- src/cpu/x86_ops_3dnow.h | 50 +-- src/cpu/x86_ops_arith.h | 6 +- src/cpu/x86_ops_bcd.h | 8 +- src/cpu/x86_ops_call.h | 2 +- src/cpu/x86_ops_cyrix.h | 10 +- src/cpu/x86_ops_flag.h | 30 +- src/cpu/x86_ops_flag_2386.h | 30 +- src/cpu/x86_ops_fpu.h | 2 +- src/cpu/x86_ops_fpu_2386.h | 2 +- src/cpu/x86_ops_inc_dec.h | 2 +- src/cpu/x86_ops_int.h | 6 +- src/cpu/x86_ops_io.h | 12 +- src/cpu/x86_ops_jump.h | 12 +- src/cpu/x86_ops_misc.h | 32 +- src/cpu/x86_ops_mmx.h | 2 +- src/cpu/x86_ops_mov.h | 32 +- src/cpu/x86_ops_msr.h | 4 +- src/cpu/x86_ops_pmode.h | 12 +- src/cpu/x86_ops_rep.h | 42 +-- src/cpu/x86_ops_rep_2386.h | 42 +-- src/cpu/x86_ops_rep_dyn.h | 42 +-- src/cpu/x86_ops_ret.h | 12 +- src/cpu/x86_ops_ret_2386.h | 12 +- src/cpu/x86_ops_stack.h | 30 +- src/cpu/x86_ops_string.h | 84 ++--- src/cpu/x86_ops_string_2386.h | 84 ++--- src/cpu/x86_ops_xchg.h | 32 +- src/cpu/x87.c | 3 +- src/cpu/x87_ops.h | 2 +- src/cpu/x87_ops_arith.h | 24 +- src/cpu/x87_ops_loadstore.h | 36 +- src/cpu/x87_ops_misc.h | 76 ++-- src/cpu/x87_ops_sf.h | 22 +- src/cpu/x87_ops_sf_arith.h | 12 +- src/cpu/x87_ops_sf_compare.h | 2 +- src/cpu/x87_ops_sf_misc.h | 4 +- src/device/mouse_microtouch_touchscreen.c | 4 +- src/device/nec_mate_unk.c | 4 +- src/device/novell_cardkey.c | 2 +- src/disk/hdc_ide.c | 6 +- src/disk/lba_enhancer.c | 2 +- src/disk/mo.c | 4 +- src/disk/zip.c | 4 +- src/floppy/fdc_compaticard.c | 5 +- src/floppy/fdd_pcjs.c | 2 +- src/game/gameport.c | 2 +- src/include/86box/bswap.h | 4 +- src/include/86box/cdrom.h | 17 +- src/machine/m_at_grid.c | 3 +- src/network/net_3c501.c | 1 - src/network/net_3c503.c | 1 - src/network/net_modem.c | 4 +- src/network/net_ne2000.c | 1 - src/network/net_pcnet.c | 2 +- src/network/net_rtl8139.c | 6 +- src/network/net_tulip.c | 2 +- src/network/net_wd8003.c | 1 - src/pic.c | 2 +- src/qt/dummy_cdrom_ioctl.c | 4 +- src/qt/qt_main.cpp | 18 +- src/qt/qt_platform.cpp | 3 +- src/scsi/scsi_cdrom.c | 10 +- src/scsi/scsi_disk.c | 4 +- src/sio/sio_it86x1f.c | 8 +- src/sio/sio_pc87306.c | 2 +- src/sio/sio_vl82c113.c | 3 +- src/sound/midi_opl4.c | 7 +- src/sound/snd_emu8k.c | 2 +- src/sound/snd_opl_esfm.c | 3 +- src/sound/snd_pas16.c | 2 +- src/sound/snd_resid.cpp | 6 +- src/sound/snd_sb.c | 6 +- src/sound/snd_ssi2001.c | 24 +- src/unix/dummy_cdrom_ioctl.c | 4 +- src/unix/unix.c | 29 +- src/unix/unix_cdrom.c | 4 +- src/unix/unix_sdl.c | 6 +- src/video/vid_ati_mach8.c | 2 +- src/video/vid_bt481_ramdac.c | 3 +- src/video/vid_cga.c | 2 +- src/video/vid_chips_69000.c | 80 ++--- src/video/vid_mga.c | 2 +- src/video/vid_svga.c | 2 +- src/video/vid_table.c | 392 ++++++++++----------- src/video/vid_tgui9440.c | 2 +- src/video/vid_voodoo_banshee.c | 2 +- src/video/vid_xga.c | 2 +- 136 files changed, 1374 insertions(+), 1291 deletions(-) diff --git a/src/86box.c b/src/86box.c index e2cc55e75..246d06b16 100644 --- a/src/86box.c +++ b/src/86box.c @@ -293,7 +293,7 @@ void pclog_ensure_stdlog_open(void) * being logged, and catch repeating entries. */ void -pclog_ex(const char *fmt, va_list ap) +pclog_ex(UNUSED(const char *fmt), UNUSED(va_list ap)) { #ifndef RELEASE_BUILD char temp[LOG_SIZE_BUFFER]; @@ -330,7 +330,7 @@ pclog_toggle_suppr(void) /* Log something. We only do this in non-release builds. */ void -pclog(const char *fmt, ...) +pclog(UNUSED(const char *fmt), ...) { #ifndef RELEASE_BUILD va_list ap; diff --git a/src/acpi.c b/src/acpi.c index 0d5c1fe00..2850a340d 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -89,7 +89,7 @@ acpi_timer_get(acpi_t *dev) } static uint8_t -acpi_gp_timer_get(acpi_t *dev) +acpi_gp_timer_get(UNUSED(acpi_t *dev)) { uint64_t clock = acpi_clock_get(); clock -= acpi_last_clock; diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 595d89f70..4ccb81442 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -593,7 +593,7 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra } static int -track_type_is_valid(const cdrom_t *dev, const int type, const int flags, const int audio, +track_type_is_valid(UNUSED(const cdrom_t *dev), const int type, const int flags, const int audio, const int mode2) { if (!(flags & 0x70) && (flags & 0xf8)) { /* 0x08/0x80/0x88 are illegal modes */ @@ -1968,7 +1968,7 @@ cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) /* TODO: Actually implement this properly. */ void -cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode) +cdrom_get_q(UNUSED(cdrom_t *dev), uint8_t *buf, UNUSED(int *curtoctrk), UNUSED(uint8_t mode)) { memset(buf, 0x00, 10); } diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index 52657e38d..4bf976794 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -32,13 +32,13 @@ #include #include #include <86box/86box.h> -#include <86box/bswap.h> #include <86box/cdrom.h> #include <86box/cdrom_image.h> #include <86box/cdrom_image_viso.h> #include <86box/log.h> #include <86box/path.h> #include <86box/plat.h> +#include <86box/bswap.h> #include <86box/plat_dir.h> #include <86box/version.h> #include <86box/nvr.h> diff --git a/src/chipset/ali1409.c b/src/chipset/ali1409.c index 5644d4077..5009a6505 100644 --- a/src/chipset/ali1409.c +++ b/src/chipset/ali1409.c @@ -40,9 +40,8 @@ #include <86box/fdc.h> #include <86box/smram.h> #include <86box/chipset.h> - +#include <86box/plat_unused.h> - #ifdef ENABLE_ALI1409_LOG int ali1409_do_log = ENABLE_ALI1409_LOG; @@ -161,7 +160,7 @@ ali1409_close(void *priv) } static void * -ali1409_init(const device_t *info) +ali1409_init(UNUSED(const device_t *info)) { ali1409_t *dev = (ali1409_t *) calloc(1, sizeof(ali1409_t)); @@ -172,7 +171,7 @@ ali1409_init(const device_t *info) 23h Data Port */ - ali1409_log ("Bus speed: %i",cpu_busspeed); + ali1409_log ("Bus speed: %i", cpu_busspeed); io_sethandler(0x0022, 0x0002, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev); diff --git a/src/chipset/sis_5513_p2i.c b/src/chipset/sis_5513_p2i.c index e7012e1b6..3655ccc3f 100644 --- a/src/chipset/sis_5513_p2i.c +++ b/src/chipset/sis_5513_p2i.c @@ -115,7 +115,7 @@ sis_5513_apc_reset(sis_5513_pci_to_isa_t *dev) } static void -sis_5513_apc_write(uint16_t addr, uint8_t val, void *priv) +sis_5513_apc_write(UNUSED(uint16_t addr), uint8_t val, void *priv) { sis_5513_pci_to_isa_t *dev = (sis_5513_pci_to_isa_t *) priv; uint8_t nvr_index = nvr_get_index(dev->nvr, 0); @@ -135,7 +135,7 @@ sis_5513_apc_write(uint16_t addr, uint8_t val, void *priv) } static uint8_t -sis_5513_apc_read(uint16_t addr, void *priv) +sis_5513_apc_read(UNUSED(uint16_t addr), void *priv) { sis_5513_pci_to_isa_t *dev = (sis_5513_pci_to_isa_t *) priv; uint8_t nvr_index = nvr_get_index(dev->nvr, 0); diff --git a/src/chipset/sis_5595_pmu.c b/src/chipset/sis_5595_pmu.c index 2f5aa10b1..7de9735f1 100644 --- a/src/chipset/sis_5595_pmu.c +++ b/src/chipset/sis_5595_pmu.c @@ -119,7 +119,7 @@ sis_5595_pmu_trap_io_mask(int size, uint16_t addr, uint8_t write, uint8_t val, v } static void -sis_5595_pmu_trap_io_ide_bm(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +sis_5595_pmu_trap_io_ide_bm(UNUSED(int size), UNUSED(uint16_t addr), UNUSED(uint8_t write), UNUSED(uint8_t val), void *priv) { sis_5595_pmu_io_trap_t *trap = (sis_5595_pmu_io_trap_t *) priv; sis_5595_pmu_t *dev = (sis_5595_pmu_t *) trap->priv; diff --git a/src/chipset/umc_8890.c b/src/chipset/umc_8890.c index 37862e2fc..cb69ce6a8 100644 --- a/src/chipset/umc_8890.c +++ b/src/chipset/umc_8890.c @@ -38,6 +38,7 @@ #include <86box/smram.h> #include <86box/chipset.h> +#include <86box/plat_unused.h> #ifdef ENABLE_UMC_8890_LOG int umc_8890_do_log = ENABLE_UMC_8890_LOG; @@ -209,7 +210,7 @@ umc_8890_close(void *priv) static void * -umc_8890_init(const device_t *info) +umc_8890_init(UNUSED(const device_t *info)) { umc_8890_t *dev = (umc_8890_t *) calloc(1, sizeof(umc_8890_t)); diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index 9b13dc5da..d7d8b0fe2 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -37,6 +37,7 @@ #include <86box/port_92.h> #include <86box/serial.h> #include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> #include <86box/chipset.h> /* Lock/Unlock Procedures */ @@ -879,7 +880,7 @@ wd76c10_reset(void *priv) static void * -wd76c10_init(const device_t *info) +wd76c10_init(UNUSED(const device_t *info)) { wd76c10_t *dev = (wd76c10_t *) calloc(1, sizeof(wd76c10_t)); uint32_t total_mem = mem_size << 10; diff --git a/src/codegen/codegen_ops_arith.h b/src/codegen/codegen_ops_arith.h index 28ee6d06c..50ef4310f 100644 --- a/src/codegen/codegen_ops_arith.h +++ b/src/codegen/codegen_ops_arith.h @@ -1,5 +1,5 @@ static uint32_t -ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropINC_rw(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -22,7 +22,7 @@ ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropINC_rl(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -45,7 +45,7 @@ ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropDEC_rw(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -68,7 +68,7 @@ ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropDEC_rl(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -93,7 +93,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod #define ROP_ARITH_RMW(name, op, writeback) \ static uint32_t \ - rop##name##_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_b_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -129,7 +129,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; \ } \ static uint32_t \ - rop##name##_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_w_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -165,7 +165,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; \ } \ static uint32_t \ - rop##name##_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_l_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -203,7 +203,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod #define ROP_ARITH_RM(name, op, writeback) \ static uint32_t \ - rop##name##_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_b_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -233,7 +233,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; \ } \ static uint32_t \ - rop##name##_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_w_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -263,7 +263,7 @@ ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; \ } \ static uint32_t \ - rop##name##_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_l_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -299,7 +299,7 @@ ROP_ARITH_RM(ADD, ADD, 1) ROP_ARITH_RM(SUB, SUB, 1) static uint32_t -ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_b_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -326,7 +326,7 @@ ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + 1; } static uint32_t -ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_w_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -353,7 +353,7 @@ ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + 1; } static uint32_t -ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_l_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -381,7 +381,7 @@ ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c } static uint32_t -ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_b_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -408,7 +408,7 @@ ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_w_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -435,7 +435,7 @@ ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_l_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -463,7 +463,7 @@ ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropADD_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -478,7 +478,7 @@ ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropADD_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -493,7 +493,7 @@ ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropADD_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -510,7 +510,7 @@ ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -525,7 +525,7 @@ ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -540,7 +540,7 @@ ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCMP_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -557,7 +557,7 @@ ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropSUB_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -572,7 +572,7 @@ ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropSUB_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -587,7 +587,7 @@ ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropSUB_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -604,7 +604,7 @@ ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +rop80(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; uint32_t imm; @@ -679,7 +679,7 @@ rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblo } static uint32_t -rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +rop81_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; uint32_t imm; @@ -753,7 +753,7 @@ rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 3; } static uint32_t -rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +rop81_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; uint32_t imm; @@ -827,7 +827,7 @@ rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +rop83_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; uint32_t imm; @@ -904,7 +904,7 @@ rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 2; } static uint32_t -rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +rop83_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; uint32_t imm; diff --git a/src/codegen/codegen_ops_fpu.h b/src/codegen/codegen_ops_fpu.h index 242743dee..a82b10d82 100644 --- a/src/codegen/codegen_ops_fpu.h +++ b/src/codegen/codegen_ops_fpu.h @@ -1,5 +1,5 @@ static uint32_t -ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFXCH(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); @@ -9,7 +9,7 @@ ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFLD(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); @@ -19,7 +19,7 @@ ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codebl } static uint32_t -ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFST(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); @@ -28,7 +28,7 @@ ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codebl return op_pc; } static uint32_t -ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSTP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); @@ -39,7 +39,7 @@ ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFLDs(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -57,7 +57,7 @@ ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 1; } static uint32_t -ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFLDd(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -76,7 +76,7 @@ ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFILDw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -94,7 +94,7 @@ ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc + 1; } static uint32_t -ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFILDl(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -112,7 +112,7 @@ ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc + 1; } static uint32_t -ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFILDq(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -133,7 +133,7 @@ ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code } static uint32_t -ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSTs(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; @@ -153,7 +153,7 @@ ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 1; } static uint32_t -ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSTd(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg1; @@ -194,24 +194,28 @@ ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return new_pc; } -#define ropFarith(name, size, load, op) \ - static uint32_t \ - ropF##name##size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - x86seg *target_seg; \ - \ - FP_ENTER(); \ - op_pc--; \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - \ - CHECK_SEG_READ(target_seg); \ - load(target_seg); \ - \ - op(FPU_##name); \ - \ - return op_pc + 1; \ +#define ropFarith(name, size, load, op) \ + static uint32_t \ + ropF##name##size(UNUSED(uint8_t opcode), \ + uint32_t fetchdat, \ + uint32_t op_32, \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(FPU_##name); \ + \ + return op_pc + 1; \ } ropFarith(ADD, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); @@ -239,32 +243,40 @@ ropFarith(MUL, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); ropFarith(SUB, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); ropFarith(SUBR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); -#define ropFcompare(name, size, load, op) \ - static uint32_t \ - ropF##name##size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - x86seg *target_seg; \ - \ - FP_ENTER(); \ - op_pc--; \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - \ - CHECK_SEG_READ(target_seg); \ - load(target_seg); \ - \ - op(); \ - \ - return op_pc + 1; \ - } \ - static uint32_t ropF##name##P##size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - uint32_t new_pc = ropF##name##size(opcode, fetchdat, op_32, op_pc, block); \ - \ - FP_POP(); \ - \ - return new_pc; \ +#define ropFcompare(name, size, load, op) \ + static uint32_t \ + ropF##name##size(UNUSED(uint8_t opcode), \ + uint32_t fetchdat, \ + uint32_t op_32, \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(); \ + \ + return op_pc + 1; \ + } \ + static uint32_t ropF##name##P##size(uint8_t opcode, \ + uint32_t fetchdat, \ + uint32_t op_32, \ + uint32_t op_pc, \ + codeblock_t *block) \ + { \ + uint32_t new_pc = ropF##name##size(opcode, fetchdat, op_32, op_pc, block); \ + \ + FP_POP(); \ + \ + return new_pc; \ } ropFcompare(COM, s, MEM_LOAD_ADDR_EA_L, FP_COMPARE_S); @@ -348,7 +360,7 @@ ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code #endif static uint32_t -ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFADD(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_ADD, 0, opcode & 7); @@ -356,7 +368,7 @@ ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } static uint32_t -ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFCOM(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_COMPARE_REG(0, opcode & 7); @@ -364,7 +376,7 @@ ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } static uint32_t -ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIV(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIV, 0, opcode & 7); @@ -372,7 +384,7 @@ ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } static uint32_t -ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIVR(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIVR, 0, opcode & 7); @@ -380,7 +392,7 @@ ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFMUL(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_MUL, 0, opcode & 7); @@ -388,7 +400,7 @@ ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } static uint32_t -ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUB(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUB, 0, opcode & 7); @@ -396,7 +408,7 @@ ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } static uint32_t -ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUBR(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUBR, 0, opcode & 7); @@ -405,7 +417,7 @@ ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code } static uint32_t -ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFADDr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_ADD, opcode & 7, 0); @@ -413,7 +425,7 @@ ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIVr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIV, opcode & 7, 0); @@ -421,7 +433,7 @@ ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIVRr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIVR, opcode & 7, 0); @@ -429,7 +441,7 @@ ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFMULr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_MUL, opcode & 7, 0); @@ -437,7 +449,7 @@ ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUBr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUB, opcode & 7, 0); @@ -445,7 +457,7 @@ ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUBRr(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUBR, opcode & 7, 0); @@ -454,7 +466,7 @@ ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFADDP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_ADD, opcode & 7, 0); @@ -463,7 +475,7 @@ ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFCOMP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_COMPARE_REG(0, opcode & 7); @@ -472,7 +484,7 @@ ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIVP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIV, opcode & 7, 0); @@ -481,7 +493,7 @@ ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFDIVRP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_DIVR, opcode & 7, 0); @@ -490,7 +502,7 @@ ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFMULP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_MUL, opcode & 7, 0); @@ -499,7 +511,7 @@ ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUBP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUB, opcode & 7, 0); @@ -508,7 +520,7 @@ ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc; } static uint32_t -ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSUBRP(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_OP_REG(FPU_SUBR, opcode & 7, 0); @@ -518,7 +530,7 @@ ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFCOMPP(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_COMPARE_REG(0, 1); @@ -528,7 +540,7 @@ ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSTSW_AX(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -540,7 +552,7 @@ ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c } static uint32_t -ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFISTw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; @@ -560,7 +572,7 @@ ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc + 1; } static uint32_t -ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFISTl(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; @@ -599,7 +611,7 @@ ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return new_pc; } static uint32_t -ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFISTPq(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg1; @@ -623,7 +635,7 @@ ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFLDCW(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; @@ -640,7 +652,7 @@ ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc + 1; } static uint32_t -ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFSTCW(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; x86seg *target_seg; @@ -658,7 +670,7 @@ ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code } static uint32_t -ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFCHS(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_FCHS(); @@ -666,17 +678,21 @@ ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc; } -#define opFLDimm(name, v) \ - static uint32_t \ - ropFLD##name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - static double fp_imm = v; \ - static uint64_t *fptr = (uint64_t *) &fp_imm; \ - \ - FP_ENTER(); \ - FP_LOAD_IMM_Q(*fptr); \ - \ - return op_pc; \ +#define opFLDimm(name, v) \ + static uint32_t \ + ropFLD##name(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + static double fp_imm = v; \ + static uint64_t *fptr = (uint64_t *) &fp_imm; \ + \ + FP_ENTER(); \ + FP_LOAD_IMM_Q(*fptr); \ + \ + return op_pc; \ } // clang-format off @@ -689,7 +705,7 @@ opFLDimm(Z, 0.0) // clang-format on static uint32_t -ropFLDLN2(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) +ropFLDLN2(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { FP_ENTER(); FP_LOAD_IMM_Q(0x3fe62e42fefa39f0ULL); diff --git a/src/codegen/codegen_ops_jump.h b/src/codegen/codegen_ops_jump.h index da16ce03e..4572b623b 100644 --- a/src/codegen/codegen_ops_jump.h +++ b/src/codegen/codegen_ops_jump.h @@ -1,5 +1,5 @@ static uint32_t -ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropJMP_r8(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t offset = fetchdat & 0xff; @@ -12,7 +12,7 @@ ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropJMP_r16(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint16_t offset = fetchdat & 0xffff; @@ -22,7 +22,7 @@ ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropJMP_r32(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t offset = fastreadl(cs + op_pc); @@ -32,7 +32,7 @@ ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropJCXZ(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t offset = fetchdat & 0xff; @@ -51,7 +51,7 @@ ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropLOOP(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t offset = fetchdat & 0xff; @@ -214,45 +214,51 @@ BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not ) } } -#define ropBRANCH(name, func, not ) \ - static uint32_t \ - rop##name(uint8_t opcode, uint32_t fetchdat, \ - uint32_t op_32, uint32_t op_pc, \ - codeblock_t *block) \ - { \ - uint32_t offset = fetchdat & 0xff; \ - \ - if (offset & 0x80) \ - offset |= 0xffffff00; \ - \ - func(1, op_pc, offset, not ); \ - \ - return op_pc + 1; \ - } \ - static uint32_t \ - rop##name##_w(uint8_t opcode, \ - uint32_t fetchdat, uint32_t op_32, \ - uint32_t op_pc, codeblock_t *block) \ - { \ - uint32_t offset = fetchdat & 0xffff; \ - \ - if (offset & 0x8000) \ - offset |= 0xffff0000; \ - \ - func(2, op_pc, offset, not ); \ - \ - return op_pc + 2; \ - } \ - static uint32_t \ - rop##name##_l(uint8_t opcode, \ - uint32_t fetchdat, uint32_t op_32, \ - uint32_t op_pc, codeblock_t *block) \ - { \ - uint32_t offset = fastreadl(cs + op_pc); \ - \ - func(4, op_pc, offset, not ); \ - \ - return op_pc + 4; \ +#define ropBRANCH(name, func, not ) \ + static uint32_t \ + rop##name(UNUSED(uint8_t opcode), \ + uint32_t fetchdat, \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + uint32_t offset = fetchdat & 0xff; \ + \ + if (offset & 0x80) \ + offset |= 0xffffff00; \ + \ + func(1, op_pc, offset, not ); \ + \ + return op_pc + 1; \ + } \ + static uint32_t \ + rop##name##_w(UNUSED(uint8_t opcode), \ + uint32_t fetchdat, \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + uint32_t offset = fetchdat & 0xffff; \ + \ + if (offset & 0x8000) \ + offset |= 0xffff0000; \ + \ + func(2, op_pc, offset, not ); \ + \ + return op_pc + 2; \ + } \ + static uint32_t \ + rop##name##_l(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + uint32_t offset = fastreadl(cs + op_pc); \ + \ + func(4, op_pc, offset, not ); \ + \ + return op_pc + 4; \ } // clang-format off diff --git a/src/codegen/codegen_ops_logic.h b/src/codegen/codegen_ops_logic.h index 9f23723e2..2c79c4a2d 100644 --- a/src/codegen/codegen_ops_logic.h +++ b/src/codegen/codegen_ops_logic.h @@ -1,6 +1,6 @@ #define ROP_LOGIC(name, op, writeback) \ static uint32_t \ - rop##name##_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_b_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -33,7 +33,7 @@ return op_pc + 1; \ } \ static uint32_t \ - rop##name##_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_w_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -66,7 +66,7 @@ return op_pc + 1; \ } \ static uint32_t \ - rop##name##_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_l_rmw(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -99,7 +99,7 @@ return op_pc + 1; \ } \ static uint32_t \ - rop##name##_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_b_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -126,7 +126,7 @@ return op_pc + 1; \ } \ static uint32_t \ - rop##name##_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_w_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -153,7 +153,7 @@ return op_pc + 1; \ } \ static uint32_t \ - rop##name##_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + rop##name##_l_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int src_reg; \ int dst_reg; \ @@ -185,7 +185,7 @@ ROP_LOGIC(OR, OR, 1) ROP_LOGIC(XOR, XOR, 1) static uint32_t -ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_b_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -209,7 +209,7 @@ ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_w_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -233,7 +233,7 @@ ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_l_rm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -258,7 +258,7 @@ ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropAND_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -270,7 +270,7 @@ ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropAND_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -282,7 +282,7 @@ ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropAND_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -296,7 +296,7 @@ ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropOR_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -308,7 +308,7 @@ ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropOR_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -320,7 +320,7 @@ ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropOR_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -334,7 +334,7 @@ ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -346,7 +346,7 @@ ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc return op_pc + 1; } static uint32_t -ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -358,7 +358,7 @@ ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc return op_pc + 2; } static uint32_t -ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropTEST_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -372,7 +372,7 @@ ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_p } static uint32_t -ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXOR_AL_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B(REG_AL); @@ -384,7 +384,7 @@ ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXOR_AX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W(REG_AX); @@ -396,7 +396,7 @@ ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXOR_EAX_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_L(REG_EAX); @@ -410,7 +410,7 @@ ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropF6(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; @@ -458,7 +458,7 @@ ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblo return 0; } static uint32_t -ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropF7_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; @@ -506,7 +506,7 @@ ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return 0; } static uint32_t -ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropF7_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg; int host_reg; diff --git a/src/codegen/codegen_ops_misc.h b/src/codegen/codegen_ops_misc.h index 61854ab37..db16dc09e 100644 --- a/src/codegen/codegen_ops_misc.h +++ b/src/codegen/codegen_ops_misc.h @@ -1,24 +1,24 @@ static uint32_t -ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropNOP(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { return op_pc; } static uint32_t -ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCLD(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { CLEAR_BITS((uintptr_t) &cpu_state.flags, D_FLAG); return op_pc; } static uint32_t -ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropSTD(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { SET_BITS((uintptr_t) &cpu_state.flags, D_FLAG); return op_pc; } static uint32_t -ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCLI(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; @@ -29,7 +29,7 @@ ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codebl return op_pc; } static uint32_t -ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropSTI(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; @@ -38,7 +38,7 @@ ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codebl } static uint32_t -ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFE(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int host_reg; @@ -88,7 +88,7 @@ ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblo } static uint32_t codegen_temp; static uint32_t -ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFF_16(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int host_reg; @@ -175,7 +175,7 @@ ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return 0; } static uint32_t -ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropFF_32(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int host_reg; diff --git a/src/codegen/codegen_ops_mmx.h b/src/codegen/codegen_ops_mmx.h index 4c5a92c8f..2e07bde77 100644 --- a/src/codegen/codegen_ops_mmx.h +++ b/src/codegen/codegen_ops_mmx.h @@ -1,5 +1,5 @@ static uint32_t -ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVQ_q_mm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg1; int host_reg2 = 0; @@ -25,7 +25,7 @@ ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVQ_mm_q(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { MMX_ENTER(); @@ -50,7 +50,7 @@ ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVD_l_mm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -74,7 +74,7 @@ ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVD_mm_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { MMX_ENTER(); @@ -95,36 +95,40 @@ ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } -#define MMX_OP(name, func) \ - static uint32_t \ - name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - int src_reg1; \ - int src_reg2; \ - int xmm_src; \ - int xmm_dst; \ - \ - MMX_ENTER(); \ - \ - if ((fetchdat & 0xc0) == 0xc0) { \ - xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ - } else { \ - x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - \ - CHECK_SEG_READ(target_seg); \ - \ - MEM_LOAD_ADDR_EA_Q(target_seg); \ - src_reg1 = LOAD_Q_REG_1; \ - src_reg2 = LOAD_Q_REG_2; \ - xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \ - } \ - xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ - func(xmm_dst, xmm_src); \ - STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ - \ - return op_pc + 1; \ +#define MMX_OP(name, func) \ + static uint32_t \ + name(UNUSED(uint8_t opcode), \ + uint32_t fetchdat, \ + uint32_t op_32, \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + int src_reg1; \ + int src_reg2; \ + int xmm_src; \ + int xmm_dst; \ + \ + MMX_ENTER(); \ + \ + if ((fetchdat & 0xc0) == 0xc0) { \ + xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ + } else { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + \ + MEM_LOAD_ADDR_EA_Q(target_seg); \ + src_reg1 = LOAD_Q_REG_1; \ + src_reg2 = LOAD_Q_REG_2; \ + xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \ + } \ + xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ + func(xmm_dst, xmm_src); \ + STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ + \ + return op_pc + 1; \ } MMX_OP(ropPAND, MMX_AND) @@ -179,7 +183,7 @@ MMX_OP(ropPMULHW, MMX_PMULHW); MMX_OP(ropPMADDWD, MMX_PMADDWD); static uint32_t -ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPSxxW_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int xmm_dst; @@ -207,7 +211,7 @@ ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPSxxD_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int xmm_dst; @@ -235,7 +239,7 @@ ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPSxxQ_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int xmm_dst; @@ -264,7 +268,7 @@ ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropEMMS(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc), UNUSED(codeblock_t *block)) { codegen_mmx_entered = 0; diff --git a/src/codegen/codegen_ops_mov.h b/src/codegen/codegen_ops_mov.h index 04c4bf2bc..039489035 100644 --- a/src/codegen/codegen_ops_mov.h +++ b/src/codegen/codegen_ops_mov.h @@ -1,19 +1,19 @@ static uint32_t -ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); return op_pc + 1; } static uint32_t -ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { STORE_IMM_REG_W(opcode & 7, fetchdat & 0xffff); return op_pc + 2; } static uint32_t -ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { fetchdat = fastreadl(cs + op_pc); @@ -23,7 +23,7 @@ ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_b_r(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); @@ -44,7 +44,7 @@ ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co return op_pc + 1; } static uint32_t -ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_w_r(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); @@ -66,7 +66,7 @@ ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_l_r(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -90,7 +90,7 @@ ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_r_b(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_B(fetchdat & 7); @@ -109,7 +109,7 @@ ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co return op_pc + 1; } static uint32_t -ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_r_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_W(fetchdat & 7); @@ -128,7 +128,7 @@ ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co return op_pc + 1; } static uint32_t -ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_r_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_L(fetchdat & 7); @@ -148,7 +148,7 @@ ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_b_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); @@ -167,7 +167,7 @@ ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 2; } static uint32_t -ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_w_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { STORE_IMM_REG_W(fetchdat & 7, (fetchdat >> 8) & 0xffff); @@ -186,7 +186,7 @@ ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 3; } static uint32_t -ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_l_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { uint32_t imm = fastreadl(cs + op_pc + 1); @@ -208,7 +208,7 @@ ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_AL_a(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; @@ -226,7 +226,7 @@ ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t -ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_AX_a(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; @@ -244,7 +244,7 @@ ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t -ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_EAX_a(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; @@ -263,7 +263,7 @@ ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_a_AL(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; int host_reg; @@ -284,7 +284,7 @@ ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t -ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_a_AX(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; int host_reg; @@ -305,7 +305,7 @@ ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc + ((op_32 & 0x200) ? 4 : 2); } static uint32_t -ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_a_EAX(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t addr; int host_reg; @@ -327,7 +327,7 @@ ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropLEA_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int dest_reg = (fetchdat >> 3) & 7; @@ -341,7 +341,7 @@ ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code return op_pc + 1; } static uint32_t -ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropLEA_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int dest_reg = (fetchdat >> 3) & 7; @@ -356,7 +356,7 @@ ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, code } static uint32_t -ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVZX_w_b(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_B(fetchdat & 7); @@ -377,7 +377,7 @@ ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVZX_l_b(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_B(fetchdat & 7); @@ -398,7 +398,7 @@ ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVZX_l_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_W(fetchdat & 7); @@ -420,7 +420,7 @@ ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVSX_w_b(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_B(fetchdat & 7); @@ -441,7 +441,7 @@ ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVSX_l_b(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_B(fetchdat & 7); @@ -462,7 +462,7 @@ ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOVSX_l_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { if ((fetchdat & 0xc0) == 0xc0) { int host_reg = LOAD_REG_W(fetchdat & 7); @@ -484,7 +484,7 @@ ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_w_seg(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -531,7 +531,7 @@ ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return op_pc + 1; } static uint32_t -ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropMOV_seg_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -578,7 +578,7 @@ ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } #define ropLseg(seg, rseg) \ - static uint32_t ropL##seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + static uint32_t ropL##seg(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) \ { \ int dest_reg = (fetchdat >> 3) & 7; \ x86seg *target_seg; \ diff --git a/src/codegen/codegen_ops_shift.h b/src/codegen/codegen_ops_shift.h index d750bfcad..a36fb3fdc 100644 --- a/src/codegen/codegen_ops_shift.h +++ b/src/codegen/codegen_ops_shift.h @@ -43,7 +43,7 @@ } static uint32_t -ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropC0(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count; @@ -57,7 +57,7 @@ ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblo return op_pc + 2; } static uint32_t -ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropC1_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count; @@ -71,7 +71,7 @@ ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 2; } static uint32_t -ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropC1_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count; @@ -86,7 +86,7 @@ ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb } static uint32_t -ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropD0(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count = 1; @@ -100,7 +100,7 @@ ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblo return op_pc + 1; } static uint32_t -ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropD1_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count = 1; @@ -114,7 +114,7 @@ ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeb return op_pc + 1; } static uint32_t -ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropD1_l(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, UNUSED(codeblock_t *block)) { x86seg *target_seg = NULL; int count = 1; diff --git a/src/codegen/codegen_ops_stack.h b/src/codegen/codegen_ops_stack.h index 342ddedd4..b7e3d66fe 100644 --- a/src/codegen/codegen_ops_stack.h +++ b/src/codegen/codegen_ops_stack.h @@ -1,5 +1,5 @@ static uint32_t -ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_16(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -12,7 +12,7 @@ ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co return op_pc; } static uint32_t -ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_32(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -26,7 +26,7 @@ ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, co } static uint32_t -ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_imm_16(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint16_t imm = fetchdat & 0xffff; int host_reg; @@ -40,7 +40,7 @@ ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc return op_pc + 2; } static uint32_t -ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_imm_32(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t imm = fastreadl(cs + op_pc); int host_reg; @@ -55,7 +55,7 @@ ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc } static uint32_t -ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_imm_b16(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint16_t imm = fetchdat & 0xff; int host_reg; @@ -72,7 +72,7 @@ ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_p return op_pc + 1; } static uint32_t -ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPUSH_imm_b32(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t imm = fetchdat & 0xff; int host_reg; @@ -90,7 +90,7 @@ ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_p } static uint32_t -ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPOP_16(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -101,7 +101,7 @@ ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc; } static uint32_t -ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropPOP_32(uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -113,7 +113,7 @@ ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropRET_16(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc), UNUSED(codeblock_t *block)) { STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -124,7 +124,7 @@ ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return -1; } static uint32_t -ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropRET_32(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc), UNUSED(codeblock_t *block)) { STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); @@ -136,7 +136,7 @@ ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod } static uint32_t -ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropRET_imm_16(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc), UNUSED(codeblock_t *block)) { uint16_t offset = fetchdat & 0xffff; @@ -149,7 +149,7 @@ ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, return -1; } static uint32_t -ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropRET_imm_32(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc), UNUSED(codeblock_t *block)) { uint16_t offset = fetchdat & 0xffff; @@ -163,7 +163,7 @@ ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, } static uint32_t -ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCALL_r16(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint16_t offset = fetchdat & 0xffff; int host_reg; @@ -178,7 +178,7 @@ ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return -1; } static uint32_t -ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropCALL_r32(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { uint32_t offset = fastreadl(cs + op_pc); int host_reg; @@ -194,7 +194,7 @@ ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c } static uint32_t -ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropLEAVE_16(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -209,7 +209,7 @@ ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc; } static uint32_t -ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropLEAVE_32(UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int host_reg; @@ -224,32 +224,40 @@ ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, c return op_pc; } -#define ROP_PUSH_SEG(seg) \ - static uint32_t \ - ropPUSH_##seg##_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - int host_reg; \ - \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(-2); \ - host_reg = LOAD_VAR_W((uintptr_t) &seg); \ - MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); \ - SP_MODIFY(-2); \ - \ - return op_pc; \ - } \ - static uint32_t \ - ropPUSH_##seg##_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - int host_reg; \ - \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(-4); \ - host_reg = LOAD_VAR_W((uintptr_t) &seg); \ - MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); \ - SP_MODIFY(-4); \ - \ - return op_pc; \ +#define ROP_PUSH_SEG(seg) \ + static uint32_t \ + ropPUSH_##seg##_16(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-2); \ + host_reg = LOAD_VAR_W((uintptr_t) &seg); \ + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); \ + SP_MODIFY(-2); \ + \ + return op_pc; \ + } \ + static uint32_t \ + ropPUSH_##seg##_32(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-4); \ + host_reg = LOAD_VAR_W((uintptr_t) &seg); \ + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); \ + SP_MODIFY(-4); \ + \ + return op_pc; \ } ROP_PUSH_SEG(CS) @@ -259,28 +267,36 @@ ROP_PUSH_SEG(FS) ROP_PUSH_SEG(GS) ROP_PUSH_SEG(SS) -#define ROP_POP_SEG(seg, rseg) \ - static uint32_t \ - ropPOP_##seg##_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ - LOAD_SEG(0, &rseg); \ - SP_MODIFY(2); \ - \ - return op_pc; \ - } \ - static uint32_t \ - ropPOP_##seg##_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ - LOAD_SEG(0, &rseg); \ - SP_MODIFY(4); \ - \ - return op_pc; \ +#define ROP_POP_SEG(seg, rseg) \ + static uint32_t \ + ropPOP_##seg##_16(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(0); \ + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ + LOAD_SEG(0, &rseg); \ + SP_MODIFY(2); \ + \ + return op_pc; \ + } \ + static uint32_t \ + ropPOP_##seg##_32(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + STORE_IMM_ADDR_L((uintptr_t) &cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(0); \ + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ + LOAD_SEG(0, &rseg); \ + SP_MODIFY(4); \ + \ + return op_pc; \ } ROP_POP_SEG(DS, cpu_state.seg_ds) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index 08b9ee5f2..e46f55a05 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -55,7 +55,7 @@ call_long(uintptr_t func) } static __inline void -load_param_1_32(codeblock_t *block, uint32_t param) +load_param_1_32(UNUSED(codeblock_t *block), uint32_t param) { #if _WIN64 addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ @@ -93,7 +93,7 @@ static __inline void load_param_1_64(codeblock_t *block, uint64_t param) #endif static __inline void -load_param_2_32(codeblock_t *block, uint32_t param) +load_param_2_32(UNUSED(codeblock_t *block), uint32_t param) { #if _WIN64 addbyte(0xba); /*MOVL $fetchdat,%edx*/ @@ -118,7 +118,7 @@ load_param_2_reg_32(int reg) #endif } static __inline void -load_param_2_64(codeblock_t *block, uint64_t param) +load_param_2_64(UNUSED(codeblock_t *block), uint64_t param) { addbyte(0x48); #if _WIN64 @@ -1492,7 +1492,7 @@ MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) /*done:*/ } static __inline void -MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, UNUSED(int host_reg2)) { if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ @@ -3926,7 +3926,7 @@ FP_LOAD_REG(int reg) return REG_EBX; } static __inline void -FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +FP_LOAD_REG_D(int reg, int *host_reg1, UNUSED(int *host_reg2)) { addbyte(0x8b); /*MOV EBX, TOP*/ addbyte(0x5d); @@ -4086,7 +4086,7 @@ FP_LOAD_REG_INT(int reg) return REG_EBX; } static __inline void -FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +FP_LOAD_REG_INT_Q(int reg, int *host_reg1, UNUSED(int *host_reg2)) { addbyte(0x89); /*MOV EBX, EAX*/ addbyte(0xc3); @@ -4693,7 +4693,7 @@ LOAD_MMX_D(int guest_reg) return host_reg; } static __inline void -LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +LOAD_MMX_Q(int guest_reg, int *host_reg1, UNUSED(int *host_reg2)) { int host_reg = REG_EBX; @@ -4725,7 +4725,7 @@ LOAD_MMX_Q_MMX(int guest_reg) } static __inline int -LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +LOAD_INT_TO_MMX(int src_reg1, UNUSED(int src_reg2)) { int dst_reg = find_host_xmm_reg(); host_reg_xmm_mapping[dst_reg] = 100; @@ -4758,7 +4758,7 @@ STORE_MMX_LQ(int guest_reg, int host_reg1) addbyte((uint8_t) cpu_state_offset(MM[guest_reg].l[0])); } static __inline void -STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +STORE_MMX_Q(int guest_reg, int host_reg1, UNUSED(int host_reg2)) { if (host_reg1 & 8) addbyte(0x4c); diff --git a/src/codegen/codegen_ops_xchg.h b/src/codegen/codegen_ops_xchg.h index 28a558078..467f711e4 100644 --- a/src/codegen/codegen_ops_xchg.h +++ b/src/codegen/codegen_ops_xchg.h @@ -1,16 +1,20 @@ -#define OP_XCHG_AX_(reg) \ - static uint32_t \ - ropXCHG_AX_##reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - int ax_reg, host_reg, temp_reg; \ - \ - ax_reg = LOAD_REG_W(REG_AX); \ - host_reg = LOAD_REG_W(REG_##reg); \ - temp_reg = COPY_REG(host_reg); \ - STORE_REG_TARGET_W_RELEASE(ax_reg, REG_##reg); \ - STORE_REG_TARGET_W_RELEASE(temp_reg, REG_AX); \ - \ - return op_pc; \ +#define OP_XCHG_AX_(reg) \ + static uint32_t \ + ropXCHG_AX_##reg(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + int ax_reg, host_reg, temp_reg; \ + \ + ax_reg = LOAD_REG_W(REG_AX); \ + host_reg = LOAD_REG_W(REG_##reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_W_RELEASE(ax_reg, REG_##reg); \ + STORE_REG_TARGET_W_RELEASE(temp_reg, REG_AX); \ + \ + return op_pc; \ } OP_XCHG_AX_(BX) @@ -21,19 +25,23 @@ OP_XCHG_AX_(DI) OP_XCHG_AX_(SP) OP_XCHG_AX_(BP) -#define OP_XCHG_EAX_(reg) \ - static uint32_t \ - ropXCHG_EAX_##reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - int eax_reg, host_reg, temp_reg; \ - \ - eax_reg = LOAD_REG_L(REG_EAX); \ - host_reg = LOAD_REG_L(REG_##reg); \ - temp_reg = COPY_REG(host_reg); \ - STORE_REG_TARGET_L_RELEASE(eax_reg, REG_##reg); \ - STORE_REG_TARGET_L_RELEASE(temp_reg, REG_EAX); \ - \ - return op_pc; \ +#define OP_XCHG_EAX_(reg) \ + static uint32_t \ + ropXCHG_EAX_##reg(UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc, \ + UNUSED(codeblock_t *block)) \ + { \ + int eax_reg, host_reg, temp_reg; \ + \ + eax_reg = LOAD_REG_L(REG_EAX); \ + host_reg = LOAD_REG_L(REG_##reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_L_RELEASE(eax_reg, REG_##reg); \ + STORE_REG_TARGET_L_RELEASE(temp_reg, REG_EAX); \ + \ + return op_pc; \ } OP_XCHG_EAX_(EBX) @@ -45,7 +53,7 @@ OP_XCHG_EAX_(ESP) OP_XCHG_EAX_(EBP) static uint32_t -ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXCHG_b(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -63,7 +71,7 @@ ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; } static uint32_t -ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXCHG_w(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; @@ -81,7 +89,7 @@ ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, cod return op_pc + 1; } static uint32_t -ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +ropXCHG_l(UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc, UNUSED(codeblock_t *block)) { int src_reg; int dst_reg; diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index 59f411612..04c2136ff 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -125,7 +125,7 @@ add_to_block_list(codeblock_t *block) } static void -remove_from_block_list(codeblock_t *block, uint32_t pc) +remove_from_block_list(codeblock_t *block, UNUSED(uint32_t pc)) { if (!block->page_mask) return; diff --git a/src/codegen_new/codegen_ir.c b/src/codegen_new/codegen_ir.c index 6345bbe86..ed8ae051f 100644 --- a/src/codegen_new/codegen_ir.c +++ b/src/codegen_new/codegen_ir.c @@ -2,6 +2,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/plat_unused.h> #include "codegen.h" #include "codegen_allocator.h" diff --git a/src/codegen_new/codegen_ir_defs.h b/src/codegen_new/codegen_ir_defs.h index 26a1c3cb4..9bd2f9afe 100644 --- a/src/codegen_new/codegen_ir_defs.h +++ b/src/codegen_new/codegen_ir_defs.h @@ -410,7 +410,7 @@ uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) } static inline void -uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a) +uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, UNUSED(int arg), int src_reg_a) { uop_t *uop = uop_alloc(ir, uop_type); diff --git a/src/codegen_new/codegen_ops.c b/src/codegen_new/codegen_ops.c index 59e148659..bb7d1f3ee 100644 --- a/src/codegen_new/codegen_ops.c +++ b/src/codegen_new/codegen_ops.c @@ -2,6 +2,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/plat_unused.h> #include "codegen.h" #include "codegen_ir.h" diff --git a/src/codegen_new/codegen_ops_3dnow.c b/src/codegen_new/codegen_ops_3dnow.c index 8b4d471ba..03af718d1 100644 --- a/src/codegen_new/codegen_ops_3dnow.c +++ b/src/codegen_new/codegen_ops_3dnow.c @@ -17,7 +17,7 @@ #include "codegen_ops_helpers.h" #define ropParith(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ int dest_reg = (fetchdat >> 3) & 7; \ \ @@ -192,7 +192,7 @@ ropPFRSQRT(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f } uint32_t -ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MMX_ENTER(ir); diff --git a/src/codegen_new/codegen_ops_arith.c b/src/codegen_new/codegen_ops_arith.c index 9e136ace5..c899c13d8 100644 --- a/src/codegen_new/codegen_ops_arith.c +++ b/src/codegen_new/codegen_ops_arith.c @@ -22,7 +22,7 @@ get_cf(ir_data_t *ir, int dest_reg) } uint32_t -ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -39,7 +39,7 @@ ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -274,7 +274,7 @@ ropADC_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -289,7 +289,7 @@ ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -511,7 +511,7 @@ ropADD_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -526,7 +526,7 @@ ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -734,7 +734,7 @@ ropCMP_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -751,7 +751,7 @@ ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -988,7 +988,7 @@ ropSBB_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -1003,7 +1003,7 @@ ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -2293,7 +2293,7 @@ rebuild_c(ir_data_t *ir) } uint32_t -ropINC_r16(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropINC_r16(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { rebuild_c(ir); @@ -2307,7 +2307,7 @@ ropINC_r16(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opc return op_pc; } uint32_t -ropINC_r32(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropINC_r32(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { rebuild_c(ir); @@ -2322,7 +2322,7 @@ ropINC_r32(UNUSED(UNUSED(codeblock_t *block)), ir_data_t *ir, UNUSED(uint8_t opc } uint32_t -ropDEC_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropDEC_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { rebuild_c(ir); @@ -2336,7 +2336,7 @@ ropDEC_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t f return op_pc; } uint32_t -ropDEC_r32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropDEC_r32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { rebuild_c(ir); diff --git a/src/codegen_new/codegen_ops_branch.c b/src/codegen_new/codegen_ops_branch.c index cedb54177..1e2589f8b 100644 --- a/src/codegen_new/codegen_ops_branch.c +++ b/src/codegen_new/codegen_ops_branch.c @@ -816,7 +816,7 @@ ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t n } #define ropJ(cond) \ - uint32_t ropJ##cond##_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropJ##cond##_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) \ { \ uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); \ uint32_t dest_addr = op_pc + 1 + offset; \ @@ -829,7 +829,7 @@ ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t n codegen_mark_code_present(block, cs + op_pc, 1); \ return ret ? dest_addr : (op_pc + 1); \ } \ - uint32_t ropJ##cond##_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropJ##cond##_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ uint32_t offset = (int32_t) (int16_t) fastreadw(cs + op_pc); \ uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \ @@ -840,7 +840,7 @@ ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t n codegen_mark_code_present(block, cs + op_pc, 2); \ return ret ? dest_addr : (op_pc + 2); \ } \ - uint32_t ropJ##cond##_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropJ##cond##_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ uint32_t offset = fastreadl(cs + op_pc); \ uint32_t dest_addr = op_pc + 4 + offset; \ @@ -852,6 +852,7 @@ ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t n return ret ? dest_addr : (op_pc + 4); \ } +// clang-format off ropJ(O) ropJ(NO) ropJ(B) @@ -868,9 +869,10 @@ ropJ(L) ropJ(NL) ropJ(LE) ropJ(NLE) +// clang-format on uint32_t -ropJCXZ(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropJCXZ(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); uint32_t dest_addr = op_pc + 1 + offset; @@ -892,7 +894,7 @@ ropJCXZ(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetc } uint32_t -ropLOOP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropLOOP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); uint32_t dest_addr = op_pc + 1 + offset; @@ -932,7 +934,7 @@ ropLOOP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetc } uint32_t -ropLOOPE(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropLOOPE(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); uint32_t dest_addr = op_pc + 1 + offset; @@ -965,7 +967,7 @@ ropLOOPE(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet return op_pc + 1; } uint32_t -ropLOOPNE(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropLOOPNE(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); uint32_t dest_addr = op_pc + 1 + offset; diff --git a/src/codegen_new/codegen_ops_fpu_arith.c b/src/codegen_new/codegen_ops_fpu_arith.c index a7b5290f4..43d243c0f 100644 --- a/src/codegen_new/codegen_ops_fpu_arith.c +++ b/src/codegen_new/codegen_ops_fpu_arith.c @@ -79,7 +79,7 @@ ropFCOMP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet return op_pc; } uint32_t -ropFCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); @@ -289,7 +289,7 @@ ropFUCOMP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fe return op_pc; } uint32_t -ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); @@ -301,7 +301,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f } #define ropF_arith_mem(name, load_uop) \ - uint32_t ropFADD##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -318,7 +318,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFCOM##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFCOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -329,12 +329,12 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f codegen_check_seg_read(block, ir, target_seg); \ load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ \ return op_pc + 1; \ } \ - uint32_t ropFCOMP##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFCOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -351,7 +351,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFDIV##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -366,7 +366,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFDIVR##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -381,7 +381,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFMUL##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -396,7 +396,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFSUB##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFSUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -411,7 +411,7 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f \ return op_pc + 1; \ } \ - uint32_t ropFSUBR##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFSUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -433,7 +433,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) // clang-format on #define ropFI_arith_mem(name, temp_reg) \ - uint32_t ropFIADD##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFIADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -449,7 +449,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) \ return op_pc + 1; \ } \ - uint32_t ropFICOM##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFICOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -461,12 +461,12 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ \ return op_pc + 1; \ } \ - uint32_t ropFICOMP##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFICOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -478,13 +478,13 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ fpu_POP(block, ir); \ \ return op_pc + 1; \ } \ - uint32_t ropFIDIV##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFIDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -500,7 +500,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) \ return op_pc + 1; \ } \ - uint32_t ropFIDIVR##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFIDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -516,7 +516,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) \ return op_pc + 1; \ } \ - uint32_t ropFIMUL##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFIMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -532,7 +532,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) \ return op_pc + 1; \ } \ - uint32_t ropFISUB##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFISUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -548,7 +548,7 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) \ return op_pc + 1; \ } \ - uint32_t ropFISUBR##name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropFISUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg; \ \ @@ -565,11 +565,13 @@ ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) return op_pc + 1; \ } +// clang-format off ropFI_arith_mem(l, IREG_temp0) ropFI_arith_mem(w, IREG_temp0_W) +// clang-format on uint32_t -ropFABS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFABS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FABS(ir, IREG_ST(0), IREG_ST(0)); @@ -579,7 +581,7 @@ ropFABS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3 } uint32_t -ropFCHS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFCHS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FCHS(ir, IREG_ST(0), IREG_ST(0)); @@ -588,7 +590,7 @@ ropFCHS(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3 return op_pc; } uint32_t -ropFSQRT(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFSQRT(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FSQRT(ir, IREG_ST(0), IREG_ST(0)); @@ -597,7 +599,7 @@ ropFSQRT(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint return op_pc; } uint32_t -ropFTST(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFTST(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_FTST(ir, IREG_temp0_W, IREG_ST(0)); diff --git a/src/codegen_new/codegen_ops_fpu_constant.c b/src/codegen_new/codegen_ops_fpu_constant.c index a91d675c5..6ec2f6888 100644 --- a/src/codegen_new/codegen_ops_fpu_constant.c +++ b/src/codegen_new/codegen_ops_fpu_constant.c @@ -19,7 +19,7 @@ #include "codegen_ops_helpers.h" uint32_t -ropFLD1(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFLD1(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_MOV_IMM(ir, IREG_temp0, 1); @@ -30,7 +30,7 @@ ropFLD1(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetc return op_pc; } uint32_t -ropFLDZ(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFLDZ(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_MOV_IMM(ir, IREG_temp0, 0); diff --git a/src/codegen_new/codegen_ops_fpu_misc.c b/src/codegen_new/codegen_ops_fpu_misc.c index 31b668488..938204a70 100644 --- a/src/codegen_new/codegen_ops_fpu_misc.c +++ b/src/codegen_new/codegen_ops_fpu_misc.c @@ -98,7 +98,7 @@ ropFSTSW(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet return op_pc + 1; } uint32_t -ropFSTSW_AX(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropFSTSW_AX(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_FP_ENTER(ir); uop_MOV(ir, IREG_AX, IREG_NPXS); diff --git a/src/codegen_new/codegen_ops_helpers.h b/src/codegen_new/codegen_ops_helpers.h index 5a8f1e1c7..92b721099 100644 --- a/src/codegen_new/codegen_ops_helpers.h +++ b/src/codegen_new/codegen_ops_helpers.h @@ -71,7 +71,7 @@ fpu_PUSH(codeblock_t *block, ir_data_t *ir) } static inline void -CHECK_SEG_LIMITS(codeblock_t *block, ir_data_t *ir, x86seg *seg, int addr_reg, int end_offset) +CHECK_SEG_LIMITS(UNUSED(codeblock_t *block), ir_data_t *ir, x86seg *seg, int addr_reg, int end_offset) { if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) return; @@ -85,7 +85,7 @@ CHECK_SEG_LIMITS(codeblock_t *block, ir_data_t *ir, x86seg *seg, int addr_reg, i } static inline void -LOAD_IMMEDIATE_FROM_RAM_8(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +LOAD_IMMEDIATE_FROM_RAM_8(UNUSED(codeblock_t *block), ir_data_t *ir, int dest_reg, uint32_t addr) { uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr)); } diff --git a/src/codegen_new/codegen_ops_jump.c b/src/codegen_new/codegen_ops_jump.c index fb2f1e5ba..430b16b2b 100644 --- a/src/codegen_new/codegen_ops_jump.c +++ b/src/codegen_new/codegen_ops_jump.c @@ -15,7 +15,7 @@ #include "codegen_ops_mov.h" uint32_t -ropJMP_r8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropJMP_r8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); uint32_t dest_addr = op_pc + 1 + offset; @@ -29,7 +29,7 @@ ropJMP_r8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fe return dest_addr; } uint32_t -ropJMP_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropJMP_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t offset = (int32_t) (int16_t) fastreadw(cs + op_pc); uint32_t dest_addr = op_pc + 2 + offset; @@ -42,7 +42,7 @@ ropJMP_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f return dest_addr; } uint32_t -ropJMP_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropJMP_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t offset = fastreadl(cs + op_pc); uint32_t dest_addr = op_pc + 4 + offset; @@ -54,7 +54,7 @@ ropJMP_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f } uint32_t -ropJMP_far_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropJMP_far_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t new_pc = fastreadw(cs + op_pc); uint16_t new_cs = fastreadw(cs + op_pc + 2); @@ -69,7 +69,7 @@ ropJMP_far_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return -1; } uint32_t -ropJMP_far_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropJMP_far_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t new_pc = fastreadl(cs + op_pc); uint16_t new_cs = fastreadw(cs + op_pc + 4); @@ -85,7 +85,7 @@ ropJMP_far_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ } uint32_t -ropCALL_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCALL_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t offset = (int32_t) (int16_t) fastreadw(cs + op_pc); uint16_t ret_addr = op_pc + 2; @@ -104,7 +104,7 @@ ropCALL_r16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t return -1; } uint32_t -ropCALL_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCALL_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t offset = fastreadl(cs + op_pc); uint32_t ret_addr = op_pc + 4; @@ -122,7 +122,7 @@ ropCALL_r32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropRET_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) +ropRET_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -138,7 +138,7 @@ ropRET_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uin return -1; } uint32_t -ropRET_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) +ropRET_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -154,7 +154,7 @@ ropRET_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uin } uint32_t -ropRET_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropRET_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t offset = fastreadw(cs + op_pc); @@ -173,7 +173,7 @@ ropRET_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return -1; } uint32_t -ropRET_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropRET_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t offset = fastreadw(cs + op_pc); @@ -192,7 +192,7 @@ ropRET_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ } uint32_t -ropRETF_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) +ropRETF_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) { if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) return 0; @@ -215,7 +215,7 @@ ropRETF_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), ui return -1; } uint32_t -ropRETF_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) +ropRETF_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), UNUSED(uint32_t op_pc)) { if ((msw & 1) && !(cpu_state.eflags & VM_FLAG)) return 0; @@ -239,7 +239,7 @@ ropRETF_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), ui } uint32_t -ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t offset; @@ -266,7 +266,7 @@ ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 return -1; } uint32_t -ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t offset; diff --git a/src/codegen_new/codegen_ops_logic.c b/src/codegen_new/codegen_ops_logic.c index 684052fea..f289f1cba 100644 --- a/src/codegen_new/codegen_ops_logic.c +++ b/src/codegen_new/codegen_ops_logic.c @@ -16,7 +16,7 @@ #include "codegen_ops_logic.h" uint32_t -ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -29,7 +29,7 @@ ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -226,7 +226,7 @@ ropAND_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -239,7 +239,7 @@ ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t return op_pc + 1; } uint32_t -ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -437,7 +437,7 @@ ropOR_l_rmw(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -449,7 +449,7 @@ ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 return op_pc + 1; } uint32_t -ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); @@ -557,7 +557,7 @@ ropTEST_l_rm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t } uint32_t -ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm_data = fastreadb(cs + op_pc); @@ -570,7 +570,7 @@ ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + 1; } uint32_t -ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm_data = fastreadw(cs + op_pc); diff --git a/src/codegen_new/codegen_ops_misc.c b/src/codegen_new/codegen_ops_misc.c index 545634672..c709dffc9 100644 --- a/src/codegen_new/codegen_ops_misc.c +++ b/src/codegen_new/codegen_ops_misc.c @@ -485,34 +485,34 @@ ropFF_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet } uint32_t -ropNOP(UNUSED(codeblock_t *block), UNUSED(ir_data_t *ir), UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropNOP(UNUSED(codeblock_t *block), UNUSED(ir_data_t *ir), UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { return op_pc; } uint32_t -ropCBW(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCBW(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOVSX(ir, IREG_AX, IREG_AL); return op_pc; } uint32_t -ropCDQ(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCDQ(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_SAR_IMM(ir, IREG_EDX, IREG_EAX, 31); return op_pc; } uint32_t -ropCWD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCWD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_SAR_IMM(ir, IREG_DX, IREG_AX, 15); return op_pc; } uint32_t -ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOVSX(ir, IREG_EAX, IREG_AX); @@ -520,7 +520,7 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3 } #define ropLxS(name, seg) \ - uint32_t rop##name##_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##name##_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg = NULL; \ int dest_reg = (fetchdat >> 3) & 7; \ @@ -542,7 +542,7 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint3 \ return op_pc + 1; \ } \ - uint32_t rop##name##_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##name##_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ x86seg *target_seg = NULL; \ int dest_reg = (fetchdat >> 3) & 7; \ @@ -572,21 +572,21 @@ ropLxS(LGS, &cpu_state.seg_gs) ropLxS(LSS, &cpu_state.seg_ss) uint32_t -ropCLC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCLC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_CALL_FUNC(ir, flags_rebuild); uop_AND_IMM(ir, IREG_flags, IREG_flags, ~C_FLAG); return op_pc; } uint32_t -ropCMC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCMC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_CALL_FUNC(ir, flags_rebuild); uop_XOR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); return op_pc; } uint32_t -ropSTC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSTC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_CALL_FUNC(ir, flags_rebuild); uop_OR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); @@ -594,20 +594,20 @@ ropSTC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32 } uint32_t -ropCLD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCLD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_AND_IMM(ir, IREG_flags, IREG_flags, ~D_FLAG); return op_pc; } uint32_t -ropSTD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSTD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_OR_IMM(ir, IREG_flags, IREG_flags, D_FLAG); return op_pc; } uint32_t -ropCLI(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropCLI(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; @@ -616,7 +616,7 @@ ropCLI(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32 return op_pc; } uint32_t -ropSTI(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropSTI(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; diff --git a/src/codegen_new/codegen_ops_mmx_arith.c b/src/codegen_new/codegen_ops_mmx_arith.c index e99b4c56d..8fd1d1651 100644 --- a/src/codegen_new/codegen_ops_mmx_arith.c +++ b/src/codegen_new/codegen_ops_mmx_arith.c @@ -2,6 +2,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/plat_unused.h> #include "x86.h" #include "x86_flags.h" @@ -16,7 +17,7 @@ #include "codegen_ops_helpers.h" #define ropParith(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ int dest_reg = (fetchdat >> 3) & 7; \ \ @@ -58,4 +59,4 @@ ropParith(PSUBUSW) ropParith(PMADDWD) ropParith(PMULHW) ropParith(PMULLW) - // clang-format on +// clang-format on diff --git a/src/codegen_new/codegen_ops_mmx_cmp.c b/src/codegen_new/codegen_ops_mmx_cmp.c index 6f38cba67..e00e56472 100644 --- a/src/codegen_new/codegen_ops_mmx_cmp.c +++ b/src/codegen_new/codegen_ops_mmx_cmp.c @@ -2,6 +2,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/plat_unused.h> #include "x86.h" #include "x86_flags.h" @@ -16,7 +17,7 @@ #include "codegen_ops_helpers.h" #define ropPcmp(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ int dest_reg = (fetchdat >> 3) & 7; \ \ @@ -45,4 +46,4 @@ ropPcmp(PCMPEQD) ropPcmp(PCMPGTB) ropPcmp(PCMPGTW) ropPcmp(PCMPGTD) - // clang-format on +// clang-format on diff --git a/src/codegen_new/codegen_ops_mmx_pack.c b/src/codegen_new/codegen_ops_mmx_pack.c index d25edd52e..18377e142 100644 --- a/src/codegen_new/codegen_ops_mmx_pack.c +++ b/src/codegen_new/codegen_ops_mmx_pack.c @@ -2,6 +2,7 @@ #include <86box/86box.h> #include "cpu.h" #include <86box/mem.h> +#include <86box/plat_unused.h> #include "x86.h" #include "x86_flags.h" @@ -16,7 +17,7 @@ #include "codegen_ops_helpers.h" #define ropPpack(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ { \ int dest_reg = (fetchdat >> 3) & 7; \ \ @@ -48,4 +49,4 @@ ropPpack(PUNPCKLDQ) ropPpack(PUNPCKHBW) ropPpack(PUNPCKHWD) ropPpack(PUNPCKHDQ) - // clang-format on +// clang-format on diff --git a/src/codegen_new/codegen_ops_mov.c b/src/codegen_new/codegen_ops_mov.c index eae7045a8..031d2ea05 100644 --- a/src/codegen_new/codegen_ops_mov.c +++ b/src/codegen_new/codegen_ops_mov.c @@ -15,7 +15,7 @@ #include "codegen_ops_mov.h" uint32_t -ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint8_t imm = fastreadb(cs + op_pc); @@ -25,7 +25,7 @@ ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchd return op_pc + 1; } uint32_t -ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm = fastreadw(cs + op_pc); @@ -172,7 +172,7 @@ ropMOV_r_l(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f } uint32_t -ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr; @@ -189,7 +189,7 @@ ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + ((op_32 & 0x200) ? 4 : 2); } uint32_t -ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr; @@ -206,7 +206,7 @@ ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + ((op_32 & 0x200) ? 4 : 2); } uint32_t -ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr = 0; @@ -233,7 +233,7 @@ ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 } uint32_t -ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr; @@ -250,7 +250,7 @@ ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + ((op_32 & 0x200) ? 4 : 2); } uint32_t -ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr; @@ -267,7 +267,7 @@ ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_ return op_pc + ((op_32 & 0x200) ? 4 : 2); } uint32_t -ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uint32_t addr; @@ -614,7 +614,7 @@ ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 } uint32_t -ropXCHG_AX(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropXCHG_AX(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int reg2 = IREG_16(opcode & 7); @@ -625,7 +625,7 @@ ropXCHG_AX(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t f return op_pc; } uint32_t -ropXCHG_EAX(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropXCHG_EAX(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int reg2 = IREG_32(opcode & 7); @@ -716,7 +716,7 @@ ropXCHG_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t f } uint32_t -ropXLAT(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +ropXLAT(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); diff --git a/src/codegen_new/codegen_ops_stack.c b/src/codegen_new/codegen_ops_stack.c index 92ad9509d..057cccb0f 100644 --- a/src/codegen_new/codegen_ops_stack.c +++ b/src/codegen_new/codegen_ops_stack.c @@ -16,7 +16,7 @@ #include "codegen_ops_misc.h" uint32_t -ropPUSH_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -28,7 +28,7 @@ ropPUSH_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t return op_pc; } uint32_t -ropPUSH_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -41,7 +41,7 @@ ropPUSH_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t } uint32_t -ropPOP_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPOP_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -57,7 +57,7 @@ ropPOP_r16(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t f return op_pc; } uint32_t -ropPOP_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPOP_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -74,7 +74,7 @@ ropPOP_r32(UNUSED(codeblock_t *block), ir_data_t *ir, uint8_t opcode, uint32_t f } uint32_t -ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm = fastreadw(cs + op_pc); int sp_reg; @@ -88,7 +88,7 @@ ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 return op_pc + 2; } uint32_t -ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t imm = fastreadl(cs + op_pc); int sp_reg; @@ -103,7 +103,7 @@ ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32 } uint32_t -ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint16_t imm = (int16_t) (int8_t) fastreadb(cs + op_pc); int sp_reg; @@ -117,7 +117,7 @@ ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint return op_pc + 1; } uint32_t -ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uint32_t imm = (int32_t) (int8_t) fastreadb(cs + op_pc); int sp_reg; @@ -197,7 +197,7 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet } #define ROP_PUSH_SEG(seg) \ - uint32_t ropPUSH_##seg##_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropPUSH_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ int sp_reg; \ \ @@ -208,7 +208,7 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet \ return op_pc; \ } \ - uint32_t ropPUSH_##seg##_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropPUSH_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ int sp_reg; \ \ @@ -222,7 +222,7 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet } #define ROP_POP_SEG(seg, rseg) \ - uint32_t ropPOP_##seg##_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropPOP_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ \ @@ -237,7 +237,7 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet \ return op_pc; \ } \ - uint32_t ropPOP_##seg##_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + uint32_t ropPOP_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ { \ uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ \ @@ -253,6 +253,7 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet return op_pc; \ } +// clang-format off ROP_PUSH_SEG(CS) ROP_PUSH_SEG(DS) ROP_PUSH_SEG(ES) @@ -263,9 +264,10 @@ ROP_POP_SEG(DS, cpu_state.seg_ds) ROP_POP_SEG(ES, cpu_state.seg_es) ROP_POP_SEG(FS, cpu_state.seg_fs) ROP_POP_SEG(GS, cpu_state.seg_gs) +// clang-format on uint32_t -ropLEAVE_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropLEAVE_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -281,7 +283,7 @@ ropLEAVE_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), u return op_pc; } uint32_t -ropLEAVE_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropLEAVE_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); @@ -298,7 +300,7 @@ ropLEAVE_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), u } uint32_t -ropPUSHA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSHA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -317,7 +319,7 @@ ropPUSHA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), u return op_pc; } uint32_t -ropPUSHA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSHA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -337,7 +339,7 @@ ropPUSHA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), u } uint32_t -ropPOPA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPOPA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -355,7 +357,7 @@ ropPOPA_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), ui return op_pc; } uint32_t -ropPOPA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPOPA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -374,7 +376,7 @@ ropPOPA_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), ui } uint32_t -ropPUSHF(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSHF(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; @@ -390,7 +392,7 @@ ropPUSHF(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint return op_pc; } uint32_t -ropPUSHFD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, UNUSED(uint32_t op_32), uint32_t op_pc) +ropPUSHFD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) { int sp_reg; diff --git a/src/cpu/386.c b/src/cpu/386.c index 21db155e9..caa5f84a2 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -27,6 +27,7 @@ #include <86box/fdc.h> #include <86box/machine.h> #include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> #include <86box/gdbstub.h> #ifndef OPS_286_386 # define OPS_286_386 diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index a68d866bf..8a2bb4ab8 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1825,7 +1825,7 @@ cpu_386_check_instruction_fault(void) } int -sysenter(uint32_t fetchdat) +sysenter(UNUSED(uint32_t fetchdat)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSENTER called\n"); @@ -1907,7 +1907,7 @@ sysenter(uint32_t fetchdat) } int -sysexit(uint32_t fetchdat) +sysexit(UNUSED(uint32_t fetchdat)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSEXIT called\n"); @@ -1994,7 +1994,7 @@ sysexit(uint32_t fetchdat) } int -syscall_op(uint32_t fetchdat) +syscall_op(UNUSED(uint32_t fetchdat)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSCALL called\n"); @@ -2046,7 +2046,7 @@ syscall_op(uint32_t fetchdat) } int -sysret(uint32_t fetchdat) +sysret(UNUSED(uint32_t fetchdat)) { #ifdef ENABLE_386_COMMON_LOG x386_common_log("SYSRET called\n"); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index c4c095735..5f41c416a 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -30,6 +30,7 @@ #include <86box/fdc.h> #include <86box/machine.h> #include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> #include <86box/gdbstub.h> #ifdef USE_DYNAREC # include "codegen.h" diff --git a/src/cpu/808x.c b/src/cpu/808x.c index f37672a5c..a74cf84ab 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -35,6 +35,7 @@ #include <86box/ppi.h> #include <86box/timer.h> #include <86box/gdbstub.h> +#include <86box/plat_unused.h> /* Is the CPU 8088 or 8086. */ int is8086 = 0; @@ -815,7 +816,7 @@ pop(void) } static void -access(int num, int bits) +access(int num, UNUSED(int bits)) { switch (num) { case 0: @@ -1419,7 +1420,7 @@ set_pzs(int bits) } static void -set_co_mul(int bits, int carry) +set_co_mul(UNUSED(int bits), int carry) { set_cf(carry); set_of(carry); diff --git a/src/cpu/codegen_timing_486.c b/src/cpu/codegen_timing_486.c index 90d682211..d8f05cfd3 100644 --- a/src/cpu/codegen_timing_486.c +++ b/src/cpu/codegen_timing_486.c @@ -328,7 +328,7 @@ codegen_timing_486_start(void) } void -codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_486_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { timing_count += COUNT(opcode_timings_486[prefix], 0); last_prefix = prefix; diff --git a/src/cpu/codegen_timing_k5.c b/src/cpu/codegen_timing_k5.c index 42b1129fe..8ce2f4cea 100644 --- a/src/cpu/codegen_timing_k5.c +++ b/src/cpu/codegen_timing_k5.c @@ -8,6 +8,7 @@ #include <86box/mem.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/plat_unused.h> #include "x86.h" #include "x86_ops.h" @@ -2037,7 +2038,7 @@ codegen_timing_k5_start(void) } void -codegen_timing_k5_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_k5_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { if (prefix != 0x0f) decode_timestamp++; @@ -2047,7 +2048,7 @@ codegen_timing_k5_prefix(uint8_t prefix, uint32_t fetchdat) } void -codegen_timing_k5_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +codegen_timing_k5_opcode(uint8_t opcode, UNUSED(uint32_t fetchdat), int op_32, uint32_t op_pc) { const risc86_instruction_t **ins_table; const uint64_t *deps; diff --git a/src/cpu/codegen_timing_k6.c b/src/cpu/codegen_timing_k6.c index 5566fbbcd..34297211b 100644 --- a/src/cpu/codegen_timing_k6.c +++ b/src/cpu/codegen_timing_k6.c @@ -8,6 +8,7 @@ #include <86box/mem.h> #include "cpu.h" #include <86box/machine.h> +#include <86box/plat_unused.h> #include "x86.h" #include "x86_ops.h" @@ -2037,7 +2038,7 @@ codegen_timing_k6_start(void) } void -codegen_timing_k6_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_k6_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { if (prefix != 0x0f) decode_timestamp++; @@ -2047,7 +2048,7 @@ codegen_timing_k6_prefix(uint8_t prefix, uint32_t fetchdat) } void -codegen_timing_k6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +codegen_timing_k6_opcode(uint8_t opcode, UNUSED(uint32_t fetchdat), int op_32, uint32_t op_pc) { const risc86_instruction_t **ins_table; const uint64_t *deps; diff --git a/src/cpu/codegen_timing_p6.c b/src/cpu/codegen_timing_p6.c index a22813068..42db319c3 100644 --- a/src/cpu/codegen_timing_p6.c +++ b/src/cpu/codegen_timing_p6.c @@ -1845,7 +1845,7 @@ codegen_timing_p6_start(void) } void -codegen_timing_p6_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_p6_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { if (prefix != 0x0f) decode_timestamp++; @@ -1855,7 +1855,7 @@ codegen_timing_p6_prefix(uint8_t prefix, uint32_t fetchdat) } void -codegen_timing_p6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, UNUSED(uint32_t op_pc)) +codegen_timing_p6_opcode(uint8_t opcode, UNUSED(uint32_t fetchdat), int op_32, UNUSED(uint32_t op_pc)) { const macro_op_t **ins_table; const uint64_t *deps; diff --git a/src/cpu/codegen_timing_winchip.c b/src/cpu/codegen_timing_winchip.c index 3597517ce..0d39f4151 100644 --- a/src/cpu/codegen_timing_winchip.c +++ b/src/cpu/codegen_timing_winchip.c @@ -328,7 +328,7 @@ codegen_timing_winchip_start(void) } void -codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_winchip_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { timing_count += COUNT(opcode_timings_winchip[prefix], 0); last_prefix = prefix; diff --git a/src/cpu/codegen_timing_winchip2.c b/src/cpu/codegen_timing_winchip2.c index f37fe3366..696a059cf 100644 --- a/src/cpu/codegen_timing_winchip2.c +++ b/src/cpu/codegen_timing_winchip2.c @@ -589,7 +589,7 @@ codegen_timing_winchip2_start(void) } static void -codegen_timing_winchip2_prefix(uint8_t prefix, uint32_t fetchdat) +codegen_timing_winchip2_prefix(uint8_t prefix, UNUSED(uint32_t fetchdat)) { if (prefix == 0x0f) { /*0fh prefix is 'free'*/ diff --git a/src/cpu/x86_ops_3dnow.h b/src/cpu/x86_ops_3dnow.h index b72cbc06c..2b4ed1a6d 100644 --- a/src/cpu/x86_ops_3dnow.h +++ b/src/cpu/x86_ops_3dnow.h @@ -20,7 +20,7 @@ opPREFETCH_a32(uint32_t fetchdat) } static int -opFEMMS(uint32_t fetchdat) +opFEMMS(UNUSED(uint32_t fetchdat)) { ILLEGAL_ON(!cpu_has_feature(CPU_FEATURE_MMX)); if (cr0 & 0xc) { @@ -33,7 +33,7 @@ opFEMMS(uint32_t fetchdat) } static int -opPAVGUSB(uint32_t fetchdat) +opPAVGUSB(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -54,7 +54,7 @@ opPAVGUSB(uint32_t fetchdat) return 0; } static int -opPF2ID(uint32_t fetchdat) +opPF2ID(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -69,7 +69,7 @@ opPF2ID(uint32_t fetchdat) return 0; } static int -opPF2IW(uint32_t fetchdat) +opPF2IW(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -84,7 +84,7 @@ opPF2IW(uint32_t fetchdat) return 0; } static int -opPFACC(uint32_t fetchdat) +opPFACC(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -101,7 +101,7 @@ opPFACC(uint32_t fetchdat) return 0; } static int -opPFNACC(uint32_t fetchdat) +opPFNACC(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -118,7 +118,7 @@ opPFNACC(uint32_t fetchdat) return 0; } static int -opPFPNACC(uint32_t fetchdat) +opPFPNACC(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -135,7 +135,7 @@ opPFPNACC(uint32_t fetchdat) return 0; } static int -opPSWAPD(uint32_t fetchdat) +opPSWAPD(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -155,7 +155,7 @@ opPSWAPD(uint32_t fetchdat) return 0; } static int -opPFADD(uint32_t fetchdat) +opPFADD(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -170,7 +170,7 @@ opPFADD(uint32_t fetchdat) return 0; } static int -opPFCMPEQ(uint32_t fetchdat) +opPFCMPEQ(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -185,7 +185,7 @@ opPFCMPEQ(uint32_t fetchdat) return 0; } static int -opPFCMPGE(uint32_t fetchdat) +opPFCMPGE(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -200,7 +200,7 @@ opPFCMPGE(uint32_t fetchdat) return 0; } static int -opPFCMPGT(uint32_t fetchdat) +opPFCMPGT(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -215,7 +215,7 @@ opPFCMPGT(uint32_t fetchdat) return 0; } static int -opPFMAX(uint32_t fetchdat) +opPFMAX(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -232,7 +232,7 @@ opPFMAX(uint32_t fetchdat) return 0; } static int -opPFMIN(uint32_t fetchdat) +opPFMIN(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -249,7 +249,7 @@ opPFMIN(uint32_t fetchdat) return 0; } static int -opPFMUL(uint32_t fetchdat) +opPFMUL(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -264,7 +264,7 @@ opPFMUL(uint32_t fetchdat) return 0; } static int -opPFRCP(uint32_t fetchdat) +opPFRCP(UNUSED(uint32_t fetchdat)) { MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -293,7 +293,7 @@ opPFRCP(uint32_t fetchdat) } /*Since opPFRCP() calculates a full precision reciprocal, treat the followup iterations as MOVs*/ static int -opPFRCPIT1(uint32_t fetchdat) +opPFRCPIT1(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -308,7 +308,7 @@ opPFRCPIT1(uint32_t fetchdat) return 0; } static int -opPFRCPIT2(uint32_t fetchdat) +opPFRCPIT2(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -323,7 +323,7 @@ opPFRCPIT2(uint32_t fetchdat) return 0; } static int -opPFRSQRT(uint32_t fetchdat) +opPFRSQRT(UNUSED(uint32_t fetchdat)) { MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -352,7 +352,7 @@ opPFRSQRT(uint32_t fetchdat) } /*Since opPFRSQRT() calculates a full precision inverse square root, treat the followup iteration as a NOP*/ static int -opPFRSQIT1(uint32_t fetchdat) +opPFRSQIT1(UNUSED(uint32_t fetchdat)) { MMX_REG src; @@ -362,7 +362,7 @@ opPFRSQIT1(uint32_t fetchdat) return 0; } static int -opPFSUB(uint32_t fetchdat) +opPFSUB(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -377,7 +377,7 @@ opPFSUB(uint32_t fetchdat) return 0; } static int -opPFSUBR(uint32_t fetchdat) +opPFSUBR(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -392,7 +392,7 @@ opPFSUBR(uint32_t fetchdat) return 0; } static int -opPI2FD(uint32_t fetchdat) +opPI2FD(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -407,7 +407,7 @@ opPI2FD(uint32_t fetchdat) return 0; } static int -opPI2FW(uint32_t fetchdat) +opPI2FW(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); @@ -422,7 +422,7 @@ opPI2FW(uint32_t fetchdat) return 0; } static int -opPMULHRW(uint32_t fetchdat) +opPMULHRW(UNUSED(uint32_t fetchdat)) { MMX_REG src; MMX_REG *dst = MMX_GETREGP(cpu_reg); diff --git a/src/cpu/x86_ops_arith.h b/src/cpu/x86_ops_arith.h index 4e3f74e36..0764877a4 100644 --- a/src/cpu/x86_ops_arith.h +++ b/src/cpu/x86_ops_arith.h @@ -313,7 +313,7 @@ return 0; \ } \ \ - static int op##name##_EAX_imm(uint32_t fetchdat) \ + static int op##name##_EAX_imm(UNUSED(uint32_t fetchdat)) \ { \ uint32_t dst = EAX; \ uint32_t src = getlong(); \ @@ -581,7 +581,7 @@ opCMP_AX_imm(uint32_t fetchdat) } static int -opCMP_EAX_imm(uint32_t fetchdat) +opCMP_EAX_imm(UNUSED(uint32_t fetchdat)) { uint32_t src = getlong(); @@ -747,7 +747,7 @@ opTEST_AX(uint32_t fetchdat) return 0; } static int -opTEST_EAX(uint32_t fetchdat) +opTEST_EAX(UNUSED(uint32_t fetchdat)) { uint32_t temp = getlong(); if (cpu_state.abrt) diff --git a/src/cpu/x86_ops_bcd.h b/src/cpu/x86_ops_bcd.h index a04dea65a..a0d18875d 100644 --- a/src/cpu/x86_ops_bcd.h +++ b/src/cpu/x86_ops_bcd.h @@ -1,5 +1,5 @@ static int -opAAA(uint32_t fetchdat) +opAAA(UNUSED(uint32_t fetchdat)) { flags_rebuild(); if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { @@ -46,7 +46,7 @@ opAAM(uint32_t fetchdat) } static int -opAAS(uint32_t fetchdat) +opAAS(UNUSED(uint32_t fetchdat)) { flags_rebuild(); if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { @@ -63,7 +63,7 @@ opAAS(uint32_t fetchdat) } static int -opDAA(uint32_t fetchdat) +opDAA(UNUSED(uint32_t fetchdat)) { uint16_t tempw; uint16_t old_AL; @@ -100,7 +100,7 @@ opDAA(uint32_t fetchdat) } static int -opDAS(uint32_t fetchdat) +opDAS(UNUSED(uint32_t fetchdat)) { uint16_t tempw; uint16_t old_AL; diff --git a/src/cpu/x86_ops_call.h b/src/cpu/x86_ops_call.h index 9d52a2764..ee54dceff 100644 --- a/src/cpu/x86_ops_call.h +++ b/src/cpu/x86_ops_call.h @@ -209,7 +209,7 @@ opCALL_far_w(uint32_t fetchdat) return 0; } static int -opCALL_far_l(uint32_t fetchdat) +opCALL_far_l(UNUSED(uint32_t fetchdat)) { uint32_t old_cs; uint32_t old_pc; diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index 672ebd08e..8c3d6e155 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -212,7 +212,7 @@ opRSTS_a32(uint32_t fetchdat) } static int -opSMINT(uint32_t fetchdat) +opSMINT(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opSMINT\n"); @@ -223,7 +223,7 @@ opSMINT(uint32_t fetchdat) } static int -opRDSHR_a16(uint32_t fetchdat) +opRDSHR_a16(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opRDSHR_a16\n"); @@ -233,7 +233,7 @@ opRDSHR_a16(uint32_t fetchdat) return 1; } static int -opRDSHR_a32(uint32_t fetchdat) +opRDSHR_a32(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opRDSHR_a32\n"); @@ -244,7 +244,7 @@ opRDSHR_a32(uint32_t fetchdat) } static int -opWRSHR_a16(uint32_t fetchdat) +opWRSHR_a16(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opWRSHR_a16\n"); @@ -254,7 +254,7 @@ opWRSHR_a16(uint32_t fetchdat) return 1; } static int -opWRSHR_a32(uint32_t fetchdat) +opWRSHR_a32(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opWRSHR_a32\n"); diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index 019472aa0..a0fa612a8 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -1,5 +1,5 @@ static int -opCMC(uint32_t fetchdat) +opCMC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags ^= C_FLAG; @@ -9,7 +9,7 @@ opCMC(uint32_t fetchdat) } static int -opCLC(uint32_t fetchdat) +opCLC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags &= ~C_FLAG; @@ -18,7 +18,7 @@ opCLC(uint32_t fetchdat) return 0; } static int -opCLD(uint32_t fetchdat) +opCLD(UNUSED(uint32_t fetchdat)) { cpu_state.flags &= ~D_FLAG; CLOCK_CYCLES(2); @@ -26,7 +26,7 @@ opCLD(uint32_t fetchdat) return 0; } static int -opCLI(uint32_t fetchdat) +opCLI(UNUSED(uint32_t fetchdat)) { if (!IOPLp) { if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { @@ -44,7 +44,7 @@ opCLI(uint32_t fetchdat) } static int -opSTC(uint32_t fetchdat) +opSTC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags |= C_FLAG; @@ -53,7 +53,7 @@ opSTC(uint32_t fetchdat) return 0; } static int -opSTD(uint32_t fetchdat) +opSTD(UNUSED(uint32_t fetchdat)) { cpu_state.flags |= D_FLAG; CLOCK_CYCLES(2); @@ -61,7 +61,7 @@ opSTD(uint32_t fetchdat) return 0; } static int -opSTI(uint32_t fetchdat) +opSTI(UNUSED(uint32_t fetchdat)) { if (!IOPLp) { if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { @@ -87,7 +87,7 @@ opSTI(uint32_t fetchdat) } static int -opSAHF(uint32_t fetchdat) +opSAHF(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; @@ -101,7 +101,7 @@ opSAHF(uint32_t fetchdat) return 0; } static int -opLAHF(uint32_t fetchdat) +opLAHF(UNUSED(uint32_t fetchdat)) { flags_rebuild(); AH = cpu_state.flags & 0xff; @@ -111,7 +111,7 @@ opLAHF(uint32_t fetchdat) } static int -opPUSHF(uint32_t fetchdat) +opPUSHF(UNUSED(uint32_t fetchdat)) { if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) { @@ -135,7 +135,7 @@ opPUSHF(uint32_t fetchdat) return cpu_state.abrt; } static int -opPUSHFD(uint32_t fetchdat) +opPUSHFD(UNUSED(uint32_t fetchdat)) { uint16_t tempw; if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { @@ -156,7 +156,7 @@ opPUSHFD(uint32_t fetchdat) } static int -opPOPF_186(uint32_t fetchdat) +opPOPF_186(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -192,7 +192,7 @@ opPOPF_186(uint32_t fetchdat) return 0; } static int -opPOPF_286(uint32_t fetchdat) +opPOPF_286(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -228,7 +228,7 @@ opPOPF_286(uint32_t fetchdat) return 0; } static int -opPOPF(uint32_t fetchdat) +opPOPF(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -284,7 +284,7 @@ opPOPF(uint32_t fetchdat) return 0; } static int -opPOPFD(uint32_t fetchdat) +opPOPFD(UNUSED(uint32_t fetchdat)) { uint32_t templ; diff --git a/src/cpu/x86_ops_flag_2386.h b/src/cpu/x86_ops_flag_2386.h index ba34ae5e7..c9a2d5ab2 100644 --- a/src/cpu/x86_ops_flag_2386.h +++ b/src/cpu/x86_ops_flag_2386.h @@ -1,5 +1,5 @@ static int -opCMC(uint32_t fetchdat) +opCMC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags ^= C_FLAG; @@ -9,7 +9,7 @@ opCMC(uint32_t fetchdat) } static int -opCLC(uint32_t fetchdat) +opCLC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags &= ~C_FLAG; @@ -18,7 +18,7 @@ opCLC(uint32_t fetchdat) return 0; } static int -opCLD(uint32_t fetchdat) +opCLD(UNUSED(uint32_t fetchdat)) { cpu_state.flags &= ~D_FLAG; CLOCK_CYCLES(2); @@ -26,7 +26,7 @@ opCLD(uint32_t fetchdat) return 0; } static int -opCLI(uint32_t fetchdat) +opCLI(UNUSED(uint32_t fetchdat)) { if (!IOPLp) { if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { @@ -44,7 +44,7 @@ opCLI(uint32_t fetchdat) } static int -opSTC(uint32_t fetchdat) +opSTC(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags |= C_FLAG; @@ -53,7 +53,7 @@ opSTC(uint32_t fetchdat) return 0; } static int -opSTD(uint32_t fetchdat) +opSTD(UNUSED(uint32_t fetchdat)) { cpu_state.flags |= D_FLAG; CLOCK_CYCLES(2); @@ -61,7 +61,7 @@ opSTD(uint32_t fetchdat) return 0; } static int -opSTI(uint32_t fetchdat) +opSTI(UNUSED(uint32_t fetchdat)) { if (!IOPLp) { if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { @@ -87,7 +87,7 @@ opSTI(uint32_t fetchdat) } static int -opSAHF(uint32_t fetchdat) +opSAHF(UNUSED(uint32_t fetchdat)) { flags_rebuild(); cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; @@ -101,7 +101,7 @@ opSAHF(uint32_t fetchdat) return 0; } static int -opLAHF(uint32_t fetchdat) +opLAHF(UNUSED(uint32_t fetchdat)) { flags_rebuild(); AH = cpu_state.flags & 0xff; @@ -111,7 +111,7 @@ opLAHF(uint32_t fetchdat) } static int -opPUSHF(uint32_t fetchdat) +opPUSHF(UNUSED(uint32_t fetchdat)) { if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) { @@ -135,7 +135,7 @@ opPUSHF(uint32_t fetchdat) return cpu_state.abrt; } static int -opPUSHFD(uint32_t fetchdat) +opPUSHFD(UNUSED(uint32_t fetchdat)) { uint16_t tempw; if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { @@ -156,7 +156,7 @@ opPUSHFD(uint32_t fetchdat) } static int -opPOPF_186(uint32_t fetchdat) +opPOPF_186(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -190,7 +190,7 @@ opPOPF_186(uint32_t fetchdat) return 0; } static int -opPOPF_286(uint32_t fetchdat) +opPOPF_286(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -224,7 +224,7 @@ opPOPF_286(uint32_t fetchdat) return 0; } static int -opPOPF(uint32_t fetchdat) +opPOPF(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -278,7 +278,7 @@ opPOPF(uint32_t fetchdat) return 0; } static int -opPOPFD(uint32_t fetchdat) +opPOPFD(UNUSED(uint32_t fetchdat)) { uint32_t templ; diff --git a/src/cpu/x86_ops_fpu.h b/src/cpu/x86_ops_fpu.h index 74c67c2ee..3434c4a73 100644 --- a/src/cpu/x86_ops_fpu.h +++ b/src/cpu/x86_ops_fpu.h @@ -90,7 +90,7 @@ opESCAPE_df_a32(uint32_t fetchdat) } static int -opWAIT(uint32_t fetchdat) +opWAIT(UNUSED(uint32_t fetchdat)) { if ((cr0 & 0xa) == 0xa) { x86_int(7); diff --git a/src/cpu/x86_ops_fpu_2386.h b/src/cpu/x86_ops_fpu_2386.h index cc9c6dcc2..c2252af12 100644 --- a/src/cpu/x86_ops_fpu_2386.h +++ b/src/cpu/x86_ops_fpu_2386.h @@ -90,7 +90,7 @@ opESCAPE_df_a32(uint32_t fetchdat) } static int -opWAIT(uint32_t fetchdat) +opWAIT(UNUSED(uint32_t fetchdat)) { if ((cr0 & 0xa) == 0xa) { x86_int(7); diff --git a/src/cpu/x86_ops_inc_dec.h b/src/cpu/x86_ops_inc_dec.h index 3eb908c57..b33d02f45 100644 --- a/src/cpu/x86_ops_inc_dec.h +++ b/src/cpu/x86_ops_inc_dec.h @@ -1,5 +1,5 @@ #define INC_DEC_OP(name, reg, inc, setflags) \ - static int op##name(uint32_t fetchdat) \ + static int op##name(UNUSED(uint32_t fetchdat)) \ { \ setflags(reg, 1); \ reg += inc; \ diff --git a/src/cpu/x86_ops_int.h b/src/cpu/x86_ops_int.h index a73ed62e0..1ed5e6c2f 100644 --- a/src/cpu/x86_ops_int.h +++ b/src/cpu/x86_ops_int.h @@ -1,5 +1,5 @@ static int -opINT3(uint32_t fetchdat) +opINT3(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -18,7 +18,7 @@ opINT3(uint32_t fetchdat) } static int -opINT1(uint32_t fetchdat) +opINT1(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -75,7 +75,7 @@ opINT(uint32_t fetchdat) } static int -opINTO(uint32_t fetchdat) +opINTO(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); diff --git a/src/cpu/x86_ops_io.h b/src/cpu/x86_ops_io.h index 8a99b8668..36bf05cd3 100644 --- a/src/cpu/x86_ops_io.h +++ b/src/cpu/x86_ops_io.h @@ -75,7 +75,7 @@ opOUT_EAX_imm(uint32_t fetchdat) } static int -opIN_AL_DX(uint32_t fetchdat) +opIN_AL_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 1); AL = inb(DX); @@ -86,7 +86,7 @@ opIN_AL_DX(uint32_t fetchdat) return 0; } static int -opIN_AX_DX(uint32_t fetchdat) +opIN_AX_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 2); AX = inw(DX); @@ -97,7 +97,7 @@ opIN_AX_DX(uint32_t fetchdat) return 0; } static int -opIN_EAX_DX(uint32_t fetchdat) +opIN_EAX_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 4); EAX = inl(DX); @@ -109,7 +109,7 @@ opIN_EAX_DX(uint32_t fetchdat) } static int -opOUT_AL_DX(uint32_t fetchdat) +opOUT_AL_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 1); outb(DX, AL); @@ -120,7 +120,7 @@ opOUT_AL_DX(uint32_t fetchdat) return x86_was_reset; } static int -opOUT_AX_DX(uint32_t fetchdat) +opOUT_AX_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 2); outw(DX, AX); @@ -131,7 +131,7 @@ opOUT_AX_DX(uint32_t fetchdat) return 0; } static int -opOUT_EAX_DX(uint32_t fetchdat) +opOUT_EAX_DX(UNUSED(uint32_t fetchdat)) { check_io_perm(DX, 4); outl(DX, EAX); diff --git a/src/cpu/x86_ops_jump.h b/src/cpu/x86_ops_jump.h index 97ca673d7..fc99fc5fd 100644 --- a/src/cpu/x86_ops_jump.h +++ b/src/cpu/x86_ops_jump.h @@ -51,7 +51,7 @@ return 0; \ } \ \ - static int opJ##condition##_l(uint32_t fetchdat) \ + static int opJ##condition##_l(UNUSED(uint32_t fetchdat)) \ { \ uint32_t offset = getlong(); \ if (cpu_state.abrt) \ @@ -256,7 +256,7 @@ opJMP_r16(uint32_t fetchdat) return 0; } static int -opJMP_r32(uint32_t fetchdat) +opJMP_r32(UNUSED(uint32_t fetchdat)) { int32_t offset = (int32_t) getlong(); if (cpu_state.abrt) @@ -289,7 +289,7 @@ opJMP_far_a16(uint32_t fetchdat) return 0; } static int -opJMP_far_a32(uint32_t fetchdat) +opJMP_far_a32(UNUSED(uint32_t fetchdat)) { uint16_t seg; uint32_t addr; @@ -323,7 +323,7 @@ opCALL_r16(uint32_t fetchdat) return 0; } static int -opCALL_r32(uint32_t fetchdat) +opCALL_r32(UNUSED(uint32_t fetchdat)) { int32_t addr = getlong(); @@ -339,7 +339,7 @@ opCALL_r32(uint32_t fetchdat) } static int -opRET_w(uint32_t fetchdat) +opRET_w(UNUSED(uint32_t fetchdat)) { uint16_t ret; @@ -355,7 +355,7 @@ opRET_w(uint32_t fetchdat) return 0; } static int -opRET_l(uint32_t fetchdat) +opRET_l(UNUSED(uint32_t fetchdat)) { uint32_t ret; diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index c0b9de437..ffc79f0e8 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -1,5 +1,5 @@ static int -opCBW(uint32_t fetchdat) +opCBW(UNUSED(uint32_t fetchdat)) { AH = (AL & 0x80) ? 0xff : 0; CLOCK_CYCLES(3); @@ -7,7 +7,7 @@ opCBW(uint32_t fetchdat) return 0; } static int -opCWDE(uint32_t fetchdat) +opCWDE(UNUSED(uint32_t fetchdat)) { EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; CLOCK_CYCLES(3); @@ -15,7 +15,7 @@ opCWDE(uint32_t fetchdat) return 0; } static int -opCWD(uint32_t fetchdat) +opCWD(UNUSED(uint32_t fetchdat)) { DX = (AX & 0x8000) ? 0xFFFF : 0; CLOCK_CYCLES(2); @@ -23,7 +23,7 @@ opCWD(uint32_t fetchdat) return 0; } static int -opCDQ(uint32_t fetchdat) +opCDQ(UNUSED(uint32_t fetchdat)) { EDX = (EAX & 0x80000000) ? 0xffffffff : 0; CLOCK_CYCLES(2); @@ -32,7 +32,7 @@ opCDQ(uint32_t fetchdat) } static int -opNOP(uint32_t fetchdat) +opNOP(UNUSED(uint32_t fetchdat)) { CLOCK_CYCLES((is486) ? 1 : 3); PREFETCH_RUN(3, 1, -1, 0, 0, 0, 0, 0); @@ -40,7 +40,7 @@ opNOP(uint32_t fetchdat) } static int -opSETALC(uint32_t fetchdat) +opSETALC(UNUSED(uint32_t fetchdat)) { AL = (CF_SET()) ? 0xff : 0; CLOCK_CYCLES(timing_rr); @@ -701,7 +701,7 @@ opF7_l_a32(uint32_t fetchdat) } static int -opHLT(uint32_t fetchdat) +opHLT(UNUSED(uint32_t fetchdat)) { if ((CPL || (cpu_state.eflags & VM_FLAG)) && (cr0 & 1)) { x86gpf(NULL, 0); @@ -856,7 +856,7 @@ opBOUND_l_a32(uint32_t fetchdat) } static int -opCLTS(uint32_t fetchdat) +opCLTS(UNUSED(uint32_t fetchdat)) { if ((CPL || (cpu_state.eflags & VM_FLAG)) && (cr0 & 1)) { x86gpf(NULL, 0); @@ -869,14 +869,14 @@ opCLTS(uint32_t fetchdat) } static int -opINVD(uint32_t fetchdat) +opINVD(UNUSED(uint32_t fetchdat)) { CLOCK_CYCLES(1000); CPU_BLOCK_END(); return 0; } static int -opWBINVD(uint32_t fetchdat) +opWBINVD(UNUSED(uint32_t fetchdat)) { if ((CPL || (cpu_state.eflags & VM_FLAG)) && (cr0 & 1)) { x86gpf(NULL, 0); @@ -888,7 +888,7 @@ opWBINVD(uint32_t fetchdat) } static int -opLOADALL(uint32_t fetchdat) +opLOADALL(UNUSED(uint32_t fetchdat)) { if (CPL && (cr0 & 1)) { x86gpf(NULL, 0); @@ -998,7 +998,7 @@ loadall_load_segment(uint32_t addr, x86seg *s) } static int -opLOADALL386(uint32_t fetchdat) +opLOADALL386(UNUSED(uint32_t fetchdat)) { uint32_t la_addr = es + EDI; @@ -1046,7 +1046,7 @@ opLOADALL386(uint32_t fetchdat) } static int -opCPUID(uint32_t fetchdat) +opCPUID(UNUSED(uint32_t fetchdat)) { if (CPUID) { cpu_CPUID(); @@ -1059,7 +1059,7 @@ opCPUID(uint32_t fetchdat) } static int -opRDMSR(uint32_t fetchdat) +opRDMSR(UNUSED(uint32_t fetchdat)) { if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_RDMSR(); @@ -1072,7 +1072,7 @@ opRDMSR(uint32_t fetchdat) } static int -opWRMSR(uint32_t fetchdat) +opWRMSR(UNUSED(uint32_t fetchdat)) { if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_WRMSR(); @@ -1085,7 +1085,7 @@ opWRMSR(uint32_t fetchdat) } static int -opRSM(uint32_t fetchdat) +opRSM(UNUSED(uint32_t fetchdat)) { if (in_smm) { leave_smm(); diff --git a/src/cpu/x86_ops_mmx.h b/src/cpu/x86_ops_mmx.h index ab5e19762..338948af5 100644 --- a/src/cpu/x86_ops_mmx.h +++ b/src/cpu/x86_ops_mmx.h @@ -34,7 +34,7 @@ x87_set_mmx() static int -opEMMS(uint32_t fetchdat) +opEMMS(UNUSED(uint32_t fetchdat)) { if (!cpu_has_feature(CPU_FEATURE_MMX)) { cpu_state.pc = cpu_state.oldpc; diff --git a/src/cpu/x86_ops_mov.h b/src/cpu/x86_ops_mov.h index e77876d5c..787a727d3 100644 --- a/src/cpu/x86_ops_mov.h +++ b/src/cpu/x86_ops_mov.h @@ -129,7 +129,7 @@ opMOV_SP_imm(uint32_t fetchdat) } static int -opMOV_EAX_imm(uint32_t fetchdat) +opMOV_EAX_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -140,7 +140,7 @@ opMOV_EAX_imm(uint32_t fetchdat) return 0; } static int -opMOV_EBX_imm(uint32_t fetchdat) +opMOV_EBX_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -151,7 +151,7 @@ opMOV_EBX_imm(uint32_t fetchdat) return 0; } static int -opMOV_ECX_imm(uint32_t fetchdat) +opMOV_ECX_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -162,7 +162,7 @@ opMOV_ECX_imm(uint32_t fetchdat) return 0; } static int -opMOV_EDX_imm(uint32_t fetchdat) +opMOV_EDX_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -173,7 +173,7 @@ opMOV_EDX_imm(uint32_t fetchdat) return 0; } static int -opMOV_ESI_imm(uint32_t fetchdat) +opMOV_ESI_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -184,7 +184,7 @@ opMOV_ESI_imm(uint32_t fetchdat) return 0; } static int -opMOV_EDI_imm(uint32_t fetchdat) +opMOV_EDI_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -195,7 +195,7 @@ opMOV_EDI_imm(uint32_t fetchdat) return 0; } static int -opMOV_EBP_imm(uint32_t fetchdat) +opMOV_EBP_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -206,7 +206,7 @@ opMOV_EBP_imm(uint32_t fetchdat) return 0; } static int -opMOV_ESP_imm(uint32_t fetchdat) +opMOV_ESP_imm(UNUSED(uint32_t fetchdat)) { uint32_t templ = getlong(); if (cpu_state.abrt) @@ -326,7 +326,7 @@ opMOV_AL_a16(uint32_t fetchdat) return 0; } static int -opMOV_AL_a32(uint32_t fetchdat) +opMOV_AL_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; uint32_t addr = getlong(); @@ -356,7 +356,7 @@ opMOV_AX_a16(uint32_t fetchdat) return 0; } static int -opMOV_AX_a32(uint32_t fetchdat) +opMOV_AX_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; uint32_t addr = getlong(); @@ -386,7 +386,7 @@ opMOV_EAX_a16(uint32_t fetchdat) return 0; } static int -opMOV_EAX_a32(uint32_t fetchdat) +opMOV_EAX_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; uint32_t addr = getlong(); @@ -413,7 +413,7 @@ opMOV_a16_AL(uint32_t fetchdat) return cpu_state.abrt; } static int -opMOV_a32_AL(uint32_t fetchdat) +opMOV_a32_AL(UNUSED(uint32_t fetchdat)) { uint32_t addr = getlong(); SEG_CHECK_WRITE(cpu_state.ea_seg); @@ -435,7 +435,7 @@ opMOV_a16_AX(uint32_t fetchdat) return cpu_state.abrt; } static int -opMOV_a32_AX(uint32_t fetchdat) +opMOV_a32_AX(UNUSED(uint32_t fetchdat)) { uint32_t addr = getlong(); if (cpu_state.abrt) @@ -459,7 +459,7 @@ opMOV_a16_EAX(uint32_t fetchdat) return cpu_state.abrt; } static int -opMOV_a32_EAX(uint32_t fetchdat) +opMOV_a32_EAX(UNUSED(uint32_t fetchdat)) { uint32_t addr = getlong(); if (cpu_state.abrt) @@ -515,7 +515,7 @@ opLEA_l_a32(uint32_t fetchdat) } static int -opXLAT_a16(uint32_t fetchdat) +opXLAT_a16(UNUSED(uint32_t fetchdat)) { uint32_t addr = (BX + AL) & 0xFFFF; uint8_t temp; @@ -530,7 +530,7 @@ opXLAT_a16(uint32_t fetchdat) return 0; } static int -opXLAT_a32(uint32_t fetchdat) +opXLAT_a32(UNUSED(uint32_t fetchdat)) { uint32_t addr = EBX + AL; uint8_t temp; diff --git a/src/cpu/x86_ops_msr.h b/src/cpu/x86_ops_msr.h index daae01d84..a59cecdd4 100644 --- a/src/cpu/x86_ops_msr.h +++ b/src/cpu/x86_ops_msr.h @@ -1,5 +1,5 @@ static int -opRDTSC(uint32_t fetchdat) +opRDTSC(UNUSED(uint32_t fetchdat)) { if (!cpu_has_feature(CPU_FEATURE_RDTSC)) { cpu_state.pc = cpu_state.oldpc; @@ -21,7 +21,7 @@ opRDTSC(uint32_t fetchdat) } static int -opRDPMC(uint32_t fetchdat) +opRDPMC(UNUSED(uint32_t fetchdat)) { if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) { x86gpf("RDPMC not allowed", 0); diff --git a/src/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index 4f32b0e37..81f194f14 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -172,12 +172,12 @@ opLAR(w_a16, fetch_ea_16, 0, 0) return cpu_state.abrt; \ } - opLSL(w_a16, fetch_ea_16, 0, 0) - opLSL(w_a32, fetch_ea_32, 0, 1) - opLSL(l_a16, fetch_ea_16, 1, 0) - opLSL(l_a32, fetch_ea_32, 1, 1) +opLSL(w_a16, fetch_ea_16, 0, 0) +opLSL(w_a32, fetch_ea_32, 0, 1) +opLSL(l_a16, fetch_ea_16, 1, 0) +opLSL(l_a32, fetch_ea_32, 1, 1) - static int op0F00_common(uint32_t fetchdat, int ea32) +static int op0F00_common(uint32_t fetchdat, UNUSED(int ea32)) { int dpl; int valid; @@ -359,7 +359,7 @@ op0F00_a32(uint32_t fetchdat) } static int -op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) +op0F01_common(UNUSED(uint32_t fetchdat), int is32, int is286, UNUSED(int ea32)) { uint32_t base; uint16_t limit; diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index a49db7e81..c75684d31 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -1,5 +1,5 @@ #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ - static int opREP_INSB_##size(uint32_t fetchdat) \ + static int opREP_INSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -38,7 +38,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSW_##size(uint32_t fetchdat) \ + static int opREP_INSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -77,7 +77,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSL_##size(uint32_t fetchdat) \ + static int opREP_INSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -117,7 +117,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_OUTSB_##size(uint32_t fetchdat) \ + static int opREP_OUTSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -148,7 +148,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSW_##size(uint32_t fetchdat) \ + static int opREP_OUTSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -179,7 +179,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSL_##size(uint32_t fetchdat) \ + static int opREP_OUTSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -211,7 +211,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_MOVSB_##size(uint32_t fetchdat) \ + static int opREP_MOVSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -264,7 +264,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSW_##size(uint32_t fetchdat) \ + static int opREP_MOVSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -318,7 +318,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSL_##size(uint32_t fetchdat) \ + static int opREP_MOVSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -373,7 +373,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_STOSB_##size(uint32_t fetchdat) \ + static int opREP_STOSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -405,7 +405,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSW_##size(uint32_t fetchdat) \ + static int opREP_STOSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -437,7 +437,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSL_##size(uint32_t fetchdat) \ + static int opREP_STOSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -470,7 +470,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_LODSB_##size(uint32_t fetchdat) \ + static int opREP_LODSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -502,7 +502,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSW_##size(uint32_t fetchdat) \ + static int opREP_LODSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -534,7 +534,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSL_##size(uint32_t fetchdat) \ + static int opREP_LODSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -570,7 +570,7 @@ #define CHEK_READ(a, b, c) #define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ - static int opREP_CMPSB_##size(uint32_t fetchdat) \ + static int opREP_CMPSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -623,7 +623,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSW_##size(uint32_t fetchdat) \ + static int opREP_CMPSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -677,7 +677,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSL_##size(uint32_t fetchdat) \ + static int opREP_CMPSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -732,7 +732,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_SCASB_##size(uint32_t fetchdat) \ + static int opREP_SCASB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -767,7 +767,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASW_##size(uint32_t fetchdat) \ + static int opREP_SCASW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -802,7 +802,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASL_##size(uint32_t fetchdat) \ + static int opREP_SCASL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ diff --git a/src/cpu/x86_ops_rep_2386.h b/src/cpu/x86_ops_rep_2386.h index fe5048340..aa1984f81 100644 --- a/src/cpu/x86_ops_rep_2386.h +++ b/src/cpu/x86_ops_rep_2386.h @@ -1,5 +1,5 @@ #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ - static int opREP_INSB_##size(uint32_t fetchdat) \ + static int opREP_INSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -38,7 +38,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSW_##size(uint32_t fetchdat) \ + static int opREP_INSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -77,7 +77,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSL_##size(uint32_t fetchdat) \ + static int opREP_INSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -117,7 +117,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_OUTSB_##size(uint32_t fetchdat) \ + static int opREP_OUTSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -148,7 +148,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSW_##size(uint32_t fetchdat) \ + static int opREP_OUTSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -179,7 +179,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSL_##size(uint32_t fetchdat) \ + static int opREP_OUTSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ \ @@ -211,7 +211,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_MOVSB_##size(uint32_t fetchdat) \ + static int opREP_MOVSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -264,7 +264,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSW_##size(uint32_t fetchdat) \ + static int opREP_MOVSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -318,7 +318,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSL_##size(uint32_t fetchdat) \ + static int opREP_MOVSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -373,7 +373,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_STOSB_##size(uint32_t fetchdat) \ + static int opREP_STOSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -405,7 +405,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSW_##size(uint32_t fetchdat) \ + static int opREP_STOSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -437,7 +437,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSL_##size(uint32_t fetchdat) \ + static int opREP_STOSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int writes = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -470,7 +470,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_LODSB_##size(uint32_t fetchdat) \ + static int opREP_LODSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -502,7 +502,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSW_##size(uint32_t fetchdat) \ + static int opREP_LODSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -534,7 +534,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSL_##size(uint32_t fetchdat) \ + static int opREP_LODSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -570,7 +570,7 @@ #define CHEK_READ(a, b, c) #define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ - static int opREP_CMPSB_##size(uint32_t fetchdat) \ + static int opREP_CMPSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -619,7 +619,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSW_##size(uint32_t fetchdat) \ + static int opREP_CMPSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -669,7 +669,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSL_##size(uint32_t fetchdat) \ + static int opREP_CMPSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ \ @@ -720,7 +720,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_SCASB_##size(uint32_t fetchdat) \ + static int opREP_SCASB_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -755,7 +755,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASW_##size(uint32_t fetchdat) \ + static int opREP_SCASW_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ @@ -790,7 +790,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASL_##size(uint32_t fetchdat) \ + static int opREP_SCASL_##size(UNUSED(uint32_t fetchdat)) \ { \ int reads = 0, total_cycles = 0, tempz; \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h index cf32209cc..bdb721ab0 100644 --- a/src/cpu/x86_ops_rep_dyn.h +++ b/src/cpu/x86_ops_rep_dyn.h @@ -1,5 +1,5 @@ #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ - static int opREP_INSB_##size(uint32_t fetchdat) \ + static int opREP_INSB_##size(UNUSED(uint32_t fetchdat)) \ { \ addr64 = 0x00000000; \ \ @@ -32,7 +32,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSW_##size(uint32_t fetchdat) \ + static int opREP_INSW_##size(UNUSED(uint32_t fetchdat)) \ { \ addr64a[0] = addr64a[1] = 0x00000000; \ \ @@ -65,7 +65,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_INSL_##size(uint32_t fetchdat) \ + static int opREP_INSL_##size(UNUSED(uint32_t fetchdat)) \ { \ addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ \ @@ -99,7 +99,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_OUTSB_##size(uint32_t fetchdat) \ + static int opREP_OUTSB_##size(UNUSED(uint32_t fetchdat)) \ { \ if (CNT_REG > 0) { \ uint8_t temp; \ @@ -124,7 +124,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSW_##size(uint32_t fetchdat) \ + static int opREP_OUTSW_##size(UNUSED(uint32_t fetchdat)) \ { \ if (CNT_REG > 0) { \ uint16_t temp; \ @@ -149,7 +149,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_OUTSL_##size(uint32_t fetchdat) \ + static int opREP_OUTSL_##size(UNUSED(uint32_t fetchdat)) \ { \ if (CNT_REG > 0) { \ uint32_t temp; \ @@ -175,7 +175,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_MOVSB_##size(uint32_t fetchdat) \ + static int opREP_MOVSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ addr64 = addr64_2 = 0x00000000; \ @@ -223,7 +223,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSW_##size(uint32_t fetchdat) \ + static int opREP_MOVSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ addr64a[0] = addr64a[1] = 0x00000000; \ @@ -272,7 +272,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_MOVSL_##size(uint32_t fetchdat) \ + static int opREP_MOVSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ addr64a[0] = addr64a[1] = addr64a[2] = addr64a[3] = 0x00000000; \ @@ -322,7 +322,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_STOSB_##size(uint32_t fetchdat) \ + static int opREP_STOSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -350,7 +350,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSW_##size(uint32_t fetchdat) \ + static int opREP_STOSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -378,7 +378,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_STOSL_##size(uint32_t fetchdat) \ + static int opREP_STOSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -407,7 +407,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_LODSB_##size(uint32_t fetchdat) \ + static int opREP_LODSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -435,7 +435,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSW_##size(uint32_t fetchdat) \ + static int opREP_LODSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -463,7 +463,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_LODSL_##size(uint32_t fetchdat) \ + static int opREP_LODSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ @@ -495,7 +495,7 @@ #define CHEK_READ(a, b, c) #define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ - static int opREP_CMPSB_##size(uint32_t fetchdat) \ + static int opREP_CMPSB_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ \ @@ -545,7 +545,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSW_##size(uint32_t fetchdat) \ + static int opREP_CMPSW_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ \ @@ -596,7 +596,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_CMPSL_##size(uint32_t fetchdat) \ + static int opREP_CMPSL_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ \ @@ -648,7 +648,7 @@ return cpu_state.abrt; \ } \ \ - static int opREP_SCASB_##size(uint32_t fetchdat) \ + static int opREP_SCASB_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ int cycles_end = cycles - 1000; \ @@ -680,7 +680,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASW_##size(uint32_t fetchdat) \ + static int opREP_SCASW_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ int cycles_end = cycles - 1000; \ @@ -712,7 +712,7 @@ } \ return cpu_state.abrt; \ } \ - static int opREP_SCASL_##size(uint32_t fetchdat) \ + static int opREP_SCASL_##size(UNUSED(uint32_t fetchdat)) \ { \ int tempz; \ int cycles_end = cycles - 1000; \ diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index d30d4eb8f..935fb5aa0 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -47,7 +47,7 @@ cycles -= timing_retf_rm; static int -opRETF_a16(uint32_t fetchdat) +opRETF_a16(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -60,7 +60,7 @@ opRETF_a16(uint32_t fetchdat) return 0; } static int -opRETF_a32(uint32_t fetchdat) +opRETF_a32(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -103,7 +103,7 @@ opRETF_a32_imm(uint32_t fetchdat) } static int -opIRET_186(uint32_t fetchdat) +opIRET_186(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -146,7 +146,7 @@ opIRET_186(uint32_t fetchdat) } static int -opIRET_286(uint32_t fetchdat) +opIRET_286(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -189,7 +189,7 @@ opIRET_286(uint32_t fetchdat) } static int -opIRET(uint32_t fetchdat) +opIRET(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -260,7 +260,7 @@ opIRET(uint32_t fetchdat) } static int -opIRETD(uint32_t fetchdat) +opIRETD(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); diff --git a/src/cpu/x86_ops_ret_2386.h b/src/cpu/x86_ops_ret_2386.h index ca85bf2b0..155925dfe 100644 --- a/src/cpu/x86_ops_ret_2386.h +++ b/src/cpu/x86_ops_ret_2386.h @@ -47,7 +47,7 @@ cycles -= timing_retf_rm; static int -opRETF_a16(uint32_t fetchdat) +opRETF_a16(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -60,7 +60,7 @@ opRETF_a16(uint32_t fetchdat) return 0; } static int -opRETF_a32(uint32_t fetchdat) +opRETF_a32(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -103,7 +103,7 @@ opRETF_a32_imm(uint32_t fetchdat) } static int -opIRET_186(uint32_t fetchdat) +opIRET_186(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -144,7 +144,7 @@ opIRET_186(uint32_t fetchdat) } static int -opIRET_286(uint32_t fetchdat) +opIRET_286(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -185,7 +185,7 @@ opIRET_286(uint32_t fetchdat) } static int -opIRET(uint32_t fetchdat) +opIRET(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); @@ -254,7 +254,7 @@ opIRET(uint32_t fetchdat) } static int -opIRETD(uint32_t fetchdat) +opIRETD(UNUSED(uint32_t fetchdat)) { int cycles_old = cycles; UN_USED(cycles_old); diff --git a/src/cpu/x86_ops_stack.h b/src/cpu/x86_ops_stack.h index fbf603ddb..f5d608fbb 100644 --- a/src/cpu/x86_ops_stack.h +++ b/src/cpu/x86_ops_stack.h @@ -1,5 +1,5 @@ #define PUSH_W_OP(reg) \ - static int opPUSH_##reg(uint32_t fetchdat) \ + static int opPUSH_##reg(UNUSED(uint32_t fetchdat)) \ { \ PUSH_W(reg); \ CLOCK_CYCLES((is486) ? 1 : 2); \ @@ -8,7 +8,7 @@ } #define PUSH_L_OP(reg) \ - static int opPUSH_##reg(uint32_t fetchdat) \ + static int opPUSH_##reg(UNUSED(uint32_t fetchdat)) \ { \ PUSH_L(reg); \ CLOCK_CYCLES((is486) ? 1 : 2); \ @@ -17,7 +17,7 @@ } #define POP_W_OP(reg) \ - static int opPOP_##reg(uint32_t fetchdat) \ + static int opPOP_##reg(UNUSED(uint32_t fetchdat)) \ { \ reg = POP_W(); \ CLOCK_CYCLES((is486) ? 1 : 4); \ @@ -26,7 +26,7 @@ } #define POP_L_OP(reg) \ - static int opPOP_##reg(uint32_t fetchdat) \ + static int opPOP_##reg(UNUSED(uint32_t fetchdat)) \ { \ reg = POP_L(); \ CLOCK_CYCLES((is486) ? 1 : 4); \ @@ -71,7 +71,7 @@ POP_L_OP(EBP) POP_L_OP(ESP) static int -opPUSHA_w(uint32_t fetchdat) +opPUSHA_w(UNUSED(uint32_t fetchdat)) { if (stack32) { writememw(ss, ESP - 2, AX); @@ -101,7 +101,7 @@ opPUSHA_w(uint32_t fetchdat) return cpu_state.abrt; } static int -opPUSHA_l(uint32_t fetchdat) +opPUSHA_l(UNUSED(uint32_t fetchdat)) { if (stack32) { writememl(ss, ESP - 4, EAX); @@ -132,7 +132,7 @@ opPUSHA_l(uint32_t fetchdat) } static int -opPOPA_w(uint32_t fetchdat) +opPOPA_w(UNUSED(uint32_t fetchdat)) { if (stack32) { DI = readmemw(ss, ESP); @@ -186,7 +186,7 @@ opPOPA_w(uint32_t fetchdat) return 0; } static int -opPOPA_l(uint32_t fetchdat) +opPOPA_l(UNUSED(uint32_t fetchdat)) { if (stack32) { EDI = readmeml(ss, ESP); @@ -250,7 +250,7 @@ opPUSH_imm_w(uint32_t fetchdat) return cpu_state.abrt; } static int -opPUSH_imm_l(uint32_t fetchdat) +opPUSH_imm_l(UNUSED(uint32_t fetchdat)) { uint32_t val = getlong(); if (cpu_state.abrt) @@ -550,7 +550,7 @@ opENTER_l(uint32_t fetchdat) } static int -opLEAVE_w(uint32_t fetchdat) +opLEAVE_w(UNUSED(uint32_t fetchdat)) { uint32_t tempESP = ESP; uint16_t temp; @@ -568,7 +568,7 @@ opLEAVE_w(uint32_t fetchdat) return 0; } static int -opLEAVE_l(uint32_t fetchdat) +opLEAVE_l(UNUSED(uint32_t fetchdat)) { uint32_t tempESP = ESP; uint32_t temp; @@ -587,14 +587,14 @@ opLEAVE_l(uint32_t fetchdat) } #define PUSH_SEG_OPS(seg) \ - static int opPUSH_##seg##_w(uint32_t fetchdat) \ + static int opPUSH_##seg##_w(UNUSED(uint32_t fetchdat)) \ { \ PUSH_W(seg); \ CLOCK_CYCLES(2); \ PREFETCH_RUN(2, 1, -1, 0, 0, 1, 0, 0); \ return cpu_state.abrt; \ } \ - static int opPUSH_##seg##_l(uint32_t fetchdat) \ + static int opPUSH_##seg##_l(UNUSED(uint32_t fetchdat)) \ { \ PUSH_L(seg); \ CLOCK_CYCLES(2); \ @@ -603,7 +603,7 @@ opLEAVE_l(uint32_t fetchdat) } #define POP_SEG_OPS(seg, realseg) \ - static int opPOP_##seg##_w(uint32_t fetchdat) \ + static int opPOP_##seg##_w(UNUSED(uint32_t fetchdat)) \ { \ uint16_t temp_seg; \ uint32_t temp_esp = ESP; \ @@ -617,7 +617,7 @@ opLEAVE_l(uint32_t fetchdat) PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0, 0, 1, 0, 0); \ return cpu_state.abrt; \ } \ - static int opPOP_##seg##_l(uint32_t fetchdat) \ + static int opPOP_##seg##_l(UNUSED(uint32_t fetchdat)) \ { \ uint32_t temp_seg; \ uint32_t temp_esp = ESP; \ diff --git a/src/cpu/x86_ops_string.h b/src/cpu/x86_ops_string.h index 619386fcb..d3a7d89a9 100644 --- a/src/cpu/x86_ops_string.h +++ b/src/cpu/x86_ops_string.h @@ -1,5 +1,5 @@ static int -opMOVSB_a16(uint32_t fetchdat) +opMOVSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -35,7 +35,7 @@ opMOVSB_a16(uint32_t fetchdat) return 0; } static int -opMOVSB_a32(uint32_t fetchdat) +opMOVSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -71,7 +71,7 @@ opMOVSB_a32(uint32_t fetchdat) } static int -opMOVSW_a16(uint32_t fetchdat) +opMOVSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -107,7 +107,7 @@ opMOVSW_a16(uint32_t fetchdat) return 0; } static int -opMOVSW_a32(uint32_t fetchdat) +opMOVSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -144,7 +144,7 @@ opMOVSW_a32(uint32_t fetchdat) } static int -opMOVSL_a16(uint32_t fetchdat) +opMOVSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -180,7 +180,7 @@ opMOVSL_a16(uint32_t fetchdat) return 0; } static int -opMOVSL_a32(uint32_t fetchdat) +opMOVSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -217,7 +217,7 @@ opMOVSL_a32(uint32_t fetchdat) } static int -opCMPSB_a16(uint32_t fetchdat) +opCMPSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t src; uint8_t dst; @@ -258,7 +258,7 @@ opCMPSB_a16(uint32_t fetchdat) return 0; } static int -opCMPSB_a32(uint32_t fetchdat) +opCMPSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t src; uint8_t dst; @@ -300,7 +300,7 @@ opCMPSB_a32(uint32_t fetchdat) } static int -opCMPSW_a16(uint32_t fetchdat) +opCMPSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t src; uint16_t dst; @@ -342,7 +342,7 @@ opCMPSW_a16(uint32_t fetchdat) return 0; } static int -opCMPSW_a32(uint32_t fetchdat) +opCMPSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t src; uint16_t dst; @@ -385,7 +385,7 @@ opCMPSW_a32(uint32_t fetchdat) } static int -opCMPSL_a16(uint32_t fetchdat) +opCMPSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t src; uint32_t dst; @@ -427,7 +427,7 @@ opCMPSL_a16(uint32_t fetchdat) return 0; } static int -opCMPSL_a32(uint32_t fetchdat) +opCMPSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t src; uint32_t dst; @@ -470,7 +470,7 @@ opCMPSL_a32(uint32_t fetchdat) } static int -opSTOSB_a16(uint32_t fetchdat) +opSTOSB_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI); @@ -486,7 +486,7 @@ opSTOSB_a16(uint32_t fetchdat) return 0; } static int -opSTOSB_a32(uint32_t fetchdat) +opSTOSB_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); @@ -503,7 +503,7 @@ opSTOSB_a32(uint32_t fetchdat) } static int -opSTOSW_a16(uint32_t fetchdat) +opSTOSW_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); @@ -519,7 +519,7 @@ opSTOSW_a16(uint32_t fetchdat) return 0; } static int -opSTOSW_a32(uint32_t fetchdat) +opSTOSW_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); @@ -536,7 +536,7 @@ opSTOSW_a32(uint32_t fetchdat) } static int -opSTOSL_a16(uint32_t fetchdat) +opSTOSL_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); @@ -552,7 +552,7 @@ opSTOSL_a16(uint32_t fetchdat) return 0; } static int -opSTOSL_a32(uint32_t fetchdat) +opSTOSL_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); @@ -569,7 +569,7 @@ opSTOSL_a32(uint32_t fetchdat) } static int -opLODSB_a16(uint32_t fetchdat) +opLODSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -588,7 +588,7 @@ opLODSB_a16(uint32_t fetchdat) return 0; } static int -opLODSB_a32(uint32_t fetchdat) +opLODSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -608,7 +608,7 @@ opLODSB_a32(uint32_t fetchdat) } static int -opLODSW_a16(uint32_t fetchdat) +opLODSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -627,7 +627,7 @@ opLODSW_a16(uint32_t fetchdat) return 0; } static int -opLODSW_a32(uint32_t fetchdat) +opLODSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -647,7 +647,7 @@ opLODSW_a32(uint32_t fetchdat) } static int -opLODSL_a16(uint32_t fetchdat) +opLODSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -666,7 +666,7 @@ opLODSL_a16(uint32_t fetchdat) return 0; } static int -opLODSL_a32(uint32_t fetchdat) +opLODSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -686,7 +686,7 @@ opLODSL_a32(uint32_t fetchdat) } static int -opSCASB_a16(uint32_t fetchdat) +opSCASB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -705,7 +705,7 @@ opSCASB_a16(uint32_t fetchdat) return 0; } static int -opSCASB_a32(uint32_t fetchdat) +opSCASB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -725,7 +725,7 @@ opSCASB_a32(uint32_t fetchdat) } static int -opSCASW_a16(uint32_t fetchdat) +opSCASW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -744,7 +744,7 @@ opSCASW_a16(uint32_t fetchdat) return 0; } static int -opSCASW_a32(uint32_t fetchdat) +opSCASW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -764,7 +764,7 @@ opSCASW_a32(uint32_t fetchdat) } static int -opSCASL_a16(uint32_t fetchdat) +opSCASL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -783,7 +783,7 @@ opSCASL_a16(uint32_t fetchdat) return 0; } static int -opSCASL_a32(uint32_t fetchdat) +opSCASL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -803,7 +803,7 @@ opSCASL_a32(uint32_t fetchdat) } static int -opINSB_a16(uint32_t fetchdat) +opINSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -829,7 +829,7 @@ opINSB_a16(uint32_t fetchdat) return 0; } static int -opINSB_a32(uint32_t fetchdat) +opINSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -856,7 +856,7 @@ opINSB_a32(uint32_t fetchdat) } static int -opINSW_a16(uint32_t fetchdat) +opINSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -882,7 +882,7 @@ opINSW_a16(uint32_t fetchdat) return 0; } static int -opINSW_a32(uint32_t fetchdat) +opINSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -909,7 +909,7 @@ opINSW_a32(uint32_t fetchdat) } static int -opINSL_a16(uint32_t fetchdat) +opINSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -935,7 +935,7 @@ opINSL_a16(uint32_t fetchdat) return 0; } static int -opINSL_a32(uint32_t fetchdat) +opINSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -962,7 +962,7 @@ opINSL_a32(uint32_t fetchdat) } static int -opOUTSB_a16(uint32_t fetchdat) +opOUTSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -982,7 +982,7 @@ opOUTSB_a16(uint32_t fetchdat) return 0; } static int -opOUTSB_a32(uint32_t fetchdat) +opOUTSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -1003,7 +1003,7 @@ opOUTSB_a32(uint32_t fetchdat) } static int -opOUTSW_a16(uint32_t fetchdat) +opOUTSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -1023,7 +1023,7 @@ opOUTSW_a16(uint32_t fetchdat) return 0; } static int -opOUTSW_a32(uint32_t fetchdat) +opOUTSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -1044,7 +1044,7 @@ opOUTSW_a32(uint32_t fetchdat) } static int -opOUTSL_a16(uint32_t fetchdat) +opOUTSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -1064,7 +1064,7 @@ opOUTSL_a16(uint32_t fetchdat) return 0; } static int -opOUTSL_a32(uint32_t fetchdat) +opOUTSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; diff --git a/src/cpu/x86_ops_string_2386.h b/src/cpu/x86_ops_string_2386.h index 98875e54f..32d69d4b2 100644 --- a/src/cpu/x86_ops_string_2386.h +++ b/src/cpu/x86_ops_string_2386.h @@ -1,5 +1,5 @@ static int -opMOVSB_a16(uint32_t fetchdat) +opMOVSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -35,7 +35,7 @@ opMOVSB_a16(uint32_t fetchdat) return 0; } static int -opMOVSB_a32(uint32_t fetchdat) +opMOVSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -71,7 +71,7 @@ opMOVSB_a32(uint32_t fetchdat) } static int -opMOVSW_a16(uint32_t fetchdat) +opMOVSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -107,7 +107,7 @@ opMOVSW_a16(uint32_t fetchdat) return 0; } static int -opMOVSW_a32(uint32_t fetchdat) +opMOVSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -144,7 +144,7 @@ opMOVSW_a32(uint32_t fetchdat) } static int -opMOVSL_a16(uint32_t fetchdat) +opMOVSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -180,7 +180,7 @@ opMOVSL_a16(uint32_t fetchdat) return 0; } static int -opMOVSL_a32(uint32_t fetchdat) +opMOVSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -217,7 +217,7 @@ opMOVSL_a32(uint32_t fetchdat) } static int -opCMPSB_a16(uint32_t fetchdat) +opCMPSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t src; uint8_t dst; @@ -254,7 +254,7 @@ opCMPSB_a16(uint32_t fetchdat) return 0; } static int -opCMPSB_a32(uint32_t fetchdat) +opCMPSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t src; uint8_t dst; @@ -292,7 +292,7 @@ opCMPSB_a32(uint32_t fetchdat) } static int -opCMPSW_a16(uint32_t fetchdat) +opCMPSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t src; uint16_t dst; @@ -330,7 +330,7 @@ opCMPSW_a16(uint32_t fetchdat) return 0; } static int -opCMPSW_a32(uint32_t fetchdat) +opCMPSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t src; uint16_t dst; @@ -369,7 +369,7 @@ opCMPSW_a32(uint32_t fetchdat) } static int -opCMPSL_a16(uint32_t fetchdat) +opCMPSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t src; uint32_t dst; @@ -407,7 +407,7 @@ opCMPSL_a16(uint32_t fetchdat) return 0; } static int -opCMPSL_a32(uint32_t fetchdat) +opCMPSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t src; uint32_t dst; @@ -446,7 +446,7 @@ opCMPSL_a32(uint32_t fetchdat) } static int -opSTOSB_a16(uint32_t fetchdat) +opSTOSB_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI); @@ -462,7 +462,7 @@ opSTOSB_a16(uint32_t fetchdat) return 0; } static int -opSTOSB_a32(uint32_t fetchdat) +opSTOSB_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI); @@ -479,7 +479,7 @@ opSTOSB_a32(uint32_t fetchdat) } static int -opSTOSW_a16(uint32_t fetchdat) +opSTOSW_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 1UL); @@ -495,7 +495,7 @@ opSTOSW_a16(uint32_t fetchdat) return 0; } static int -opSTOSW_a32(uint32_t fetchdat) +opSTOSW_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 1UL); @@ -512,7 +512,7 @@ opSTOSW_a32(uint32_t fetchdat) } static int -opSTOSL_a16(uint32_t fetchdat) +opSTOSL_a16(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, DI, DI + 3UL); @@ -528,7 +528,7 @@ opSTOSL_a16(uint32_t fetchdat) return 0; } static int -opSTOSL_a32(uint32_t fetchdat) +opSTOSL_a32(UNUSED(uint32_t fetchdat)) { SEG_CHECK_WRITE(&cpu_state.seg_es); CHECK_WRITE(&cpu_state.seg_es, EDI, EDI + 3UL); @@ -545,7 +545,7 @@ opSTOSL_a32(uint32_t fetchdat) } static int -opLODSB_a16(uint32_t fetchdat) +opLODSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -564,7 +564,7 @@ opLODSB_a16(uint32_t fetchdat) return 0; } static int -opLODSB_a32(uint32_t fetchdat) +opLODSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -584,7 +584,7 @@ opLODSB_a32(uint32_t fetchdat) } static int -opLODSW_a16(uint32_t fetchdat) +opLODSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -603,7 +603,7 @@ opLODSW_a16(uint32_t fetchdat) return 0; } static int -opLODSW_a32(uint32_t fetchdat) +opLODSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -623,7 +623,7 @@ opLODSW_a32(uint32_t fetchdat) } static int -opLODSL_a16(uint32_t fetchdat) +opLODSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -642,7 +642,7 @@ opLODSL_a16(uint32_t fetchdat) return 0; } static int -opLODSL_a32(uint32_t fetchdat) +opLODSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -662,7 +662,7 @@ opLODSL_a32(uint32_t fetchdat) } static int -opSCASB_a16(uint32_t fetchdat) +opSCASB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -681,7 +681,7 @@ opSCASB_a16(uint32_t fetchdat) return 0; } static int -opSCASB_a32(uint32_t fetchdat) +opSCASB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -701,7 +701,7 @@ opSCASB_a32(uint32_t fetchdat) } static int -opSCASW_a16(uint32_t fetchdat) +opSCASW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -720,7 +720,7 @@ opSCASW_a16(uint32_t fetchdat) return 0; } static int -opSCASW_a32(uint32_t fetchdat) +opSCASW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -740,7 +740,7 @@ opSCASW_a32(uint32_t fetchdat) } static int -opSCASL_a16(uint32_t fetchdat) +opSCASL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -759,7 +759,7 @@ opSCASL_a16(uint32_t fetchdat) return 0; } static int -opSCASL_a32(uint32_t fetchdat) +opSCASL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -779,7 +779,7 @@ opSCASL_a32(uint32_t fetchdat) } static int -opINSB_a16(uint32_t fetchdat) +opINSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -805,7 +805,7 @@ opINSB_a16(uint32_t fetchdat) return 0; } static int -opINSB_a32(uint32_t fetchdat) +opINSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -832,7 +832,7 @@ opINSB_a32(uint32_t fetchdat) } static int -opINSW_a16(uint32_t fetchdat) +opINSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -858,7 +858,7 @@ opINSW_a16(uint32_t fetchdat) return 0; } static int -opINSW_a32(uint32_t fetchdat) +opINSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -885,7 +885,7 @@ opINSW_a32(uint32_t fetchdat) } static int -opINSL_a16(uint32_t fetchdat) +opINSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -911,7 +911,7 @@ opINSL_a16(uint32_t fetchdat) return 0; } static int -opINSL_a32(uint32_t fetchdat) +opINSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -938,7 +938,7 @@ opINSL_a32(uint32_t fetchdat) } static int -opOUTSB_a16(uint32_t fetchdat) +opOUTSB_a16(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -958,7 +958,7 @@ opOUTSB_a16(uint32_t fetchdat) return 0; } static int -opOUTSB_a32(uint32_t fetchdat) +opOUTSB_a32(UNUSED(uint32_t fetchdat)) { uint8_t temp; @@ -979,7 +979,7 @@ opOUTSB_a32(uint32_t fetchdat) } static int -opOUTSW_a16(uint32_t fetchdat) +opOUTSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -999,7 +999,7 @@ opOUTSW_a16(uint32_t fetchdat) return 0; } static int -opOUTSW_a32(uint32_t fetchdat) +opOUTSW_a32(UNUSED(uint32_t fetchdat)) { uint16_t temp; @@ -1020,7 +1020,7 @@ opOUTSW_a32(uint32_t fetchdat) } static int -opOUTSL_a16(uint32_t fetchdat) +opOUTSL_a16(UNUSED(uint32_t fetchdat)) { uint32_t temp; @@ -1040,7 +1040,7 @@ opOUTSL_a16(uint32_t fetchdat) return 0; } static int -opOUTSL_a32(uint32_t fetchdat) +opOUTSL_a32(UNUSED(uint32_t fetchdat)) { uint32_t temp; diff --git a/src/cpu/x86_ops_xchg.h b/src/cpu/x86_ops_xchg.h index 70e7be58c..826181a8e 100644 --- a/src/cpu/x86_ops_xchg.h +++ b/src/cpu/x86_ops_xchg.h @@ -116,7 +116,7 @@ opXCHG_l_a32(uint32_t fetchdat) } static int -opXCHG_AX_BX(uint32_t fetchdat) +opXCHG_AX_BX(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = BX; @@ -126,7 +126,7 @@ opXCHG_AX_BX(uint32_t fetchdat) return 0; } static int -opXCHG_AX_CX(uint32_t fetchdat) +opXCHG_AX_CX(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = CX; @@ -136,7 +136,7 @@ opXCHG_AX_CX(uint32_t fetchdat) return 0; } static int -opXCHG_AX_DX(uint32_t fetchdat) +opXCHG_AX_DX(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = DX; @@ -146,7 +146,7 @@ opXCHG_AX_DX(uint32_t fetchdat) return 0; } static int -opXCHG_AX_SI(uint32_t fetchdat) +opXCHG_AX_SI(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = SI; @@ -156,7 +156,7 @@ opXCHG_AX_SI(uint32_t fetchdat) return 0; } static int -opXCHG_AX_DI(uint32_t fetchdat) +opXCHG_AX_DI(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = DI; @@ -166,7 +166,7 @@ opXCHG_AX_DI(uint32_t fetchdat) return 0; } static int -opXCHG_AX_BP(uint32_t fetchdat) +opXCHG_AX_BP(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = BP; @@ -176,7 +176,7 @@ opXCHG_AX_BP(uint32_t fetchdat) return 0; } static int -opXCHG_AX_SP(uint32_t fetchdat) +opXCHG_AX_SP(UNUSED(uint32_t fetchdat)) { uint16_t temp = AX; AX = SP; @@ -187,7 +187,7 @@ opXCHG_AX_SP(uint32_t fetchdat) } static int -opXCHG_EAX_EBX(uint32_t fetchdat) +opXCHG_EAX_EBX(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = EBX; @@ -197,7 +197,7 @@ opXCHG_EAX_EBX(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_ECX(uint32_t fetchdat) +opXCHG_EAX_ECX(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = ECX; @@ -207,7 +207,7 @@ opXCHG_EAX_ECX(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_EDX(uint32_t fetchdat) +opXCHG_EAX_EDX(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = EDX; @@ -217,7 +217,7 @@ opXCHG_EAX_EDX(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_ESI(uint32_t fetchdat) +opXCHG_EAX_ESI(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = ESI; @@ -227,7 +227,7 @@ opXCHG_EAX_ESI(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_EDI(uint32_t fetchdat) +opXCHG_EAX_EDI(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = EDI; @@ -237,7 +237,7 @@ opXCHG_EAX_EDI(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_EBP(uint32_t fetchdat) +opXCHG_EAX_EBP(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = EBP; @@ -247,7 +247,7 @@ opXCHG_EAX_EBP(uint32_t fetchdat) return 0; } static int -opXCHG_EAX_ESP(uint32_t fetchdat) +opXCHG_EAX_ESP(UNUSED(uint32_t fetchdat)) { uint32_t temp = EAX; EAX = ESP; @@ -258,7 +258,7 @@ opXCHG_EAX_ESP(uint32_t fetchdat) } #define opBSWAP(reg) \ - static int opBSWAP_##reg(uint32_t fetchdat) \ + static int opBSWAP_##reg(UNUSED(uint32_t fetchdat)) \ { \ reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ CLOCK_CYCLES(1); \ @@ -275,4 +275,4 @@ opBSWAP(ESI) opBSWAP(EDI) opBSWAP(EBP) opBSWAP(ESP) - // clang-format on +// clang-format on diff --git a/src/cpu/x87.c b/src/cpu/x87.c index 3b06cab3c..fecca0772 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -20,6 +20,7 @@ #include "softfloat3e/config.h" #include "softfloat3e/fpu_trans.h" #include "softfloat3e/specialize.h" +#include <86box/plat_unused.h> uint32_t x87_pc_off; uint32_t x87_op_off; @@ -312,7 +313,7 @@ FPU_write_eflags_fpu_compare(int float_relation) } uint16_t -FPU_exception(uint32_t fetchdat, uint16_t exceptions, int store) +FPU_exception(UNUSED(uint32_t fetchdat), uint16_t exceptions, int store) { uint16_t status; uint16_t unmasked; diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index d33122b5c..f1362bf76 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -542,7 +542,7 @@ op_nofpu_a32(uint32_t fetchdat) #ifdef FPU_8087 static int -FPU_ILLEGAL_a16(uint32_t fetchdat) +FPU_ILLEGAL_a16(UNUSED(uint32_t fetchdat)) { geteaw(); wait(timing_rr, 0); diff --git a/src/cpu/x87_ops_arith.h b/src/cpu/x87_ops_arith.h index 31c26231b..8d0c02167 100644 --- a/src/cpu/x87_ops_arith.h +++ b/src/cpu/x87_ops_arith.h @@ -1,5 +1,5 @@ #define opFPU(name, optype, a_size, load_var, get, use_var, cycle_postfix) \ - static int opFADD##name##_a##a_size(uint32_t fetchdat) \ + static int opFADD##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -18,7 +18,7 @@ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd##cycle_postfix) : ((x87_concurrency.fadd##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFCOM##name##_a##a_size(uint32_t fetchdat) \ + static int opFCOM##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -27,13 +27,13 @@ load_var = get(); \ if (cpu_state.abrt) \ return 1; \ - cpu_state.npxs &= ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \ + cpu_state.npxs &= ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \ cpu_state.npxs |= x87_compare(ST(0), (double) use_var); \ CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom##cycle_postfix) : ((x87_timings.fcom##cycle_postfix) * cpu_multi)); \ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom##cycle_postfix) : ((x87_concurrency.fcom##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFCOMP##name##_a##a_size(uint32_t fetchdat) \ + static int opFCOMP##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -42,14 +42,14 @@ load_var = get(); \ if (cpu_state.abrt) \ return 1; \ - cpu_state.npxs &= ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \ + cpu_state.npxs &= ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \ cpu_state.npxs |= x87_compare(ST(0), (double) use_var); \ x87_pop(); \ CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom##cycle_postfix) : ((x87_timings.fcom##cycle_postfix) * cpu_multi)); \ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom##cycle_postfix) : ((x87_concurrency.fcom##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFDIV##name##_a##a_size(uint32_t fetchdat) \ + static int opFDIV##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -64,7 +64,7 @@ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd##cycle_postfix) : ((x87_concurrency.fadd##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFDIVR##name##_a##a_size(uint32_t fetchdat) \ + static int opFDIVR##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -79,7 +79,7 @@ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fdiv##cycle_postfix) : ((x87_concurrency.fdiv##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFMUL##name##_a##a_size(uint32_t fetchdat) \ + static int opFMUL##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -94,7 +94,7 @@ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fmul##cycle_postfix) : ((x87_concurrency.fmul##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFSUB##name##_a##a_size(uint32_t fetchdat) \ + static int opFSUB##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -109,7 +109,7 @@ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd##cycle_postfix) : ((x87_concurrency.fadd##cycle_postfix) * cpu_multi)); \ return 0; \ } \ - static int opFSUBR##name##_a##a_size(uint32_t fetchdat) \ + static int opFSUBR##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ optype t; \ FP_ENTER(); \ @@ -208,7 +208,7 @@ opFCOMP(uint32_t fetchdat) } static int -opFCOMPP(uint32_t fetchdat) +opFCOMPP(UNUSED(uint32_t fetchdat)) { uint64_t *p, *q; FP_ENTER(); @@ -229,7 +229,7 @@ opFCOMPP(uint32_t fetchdat) } #ifndef FPU_8087 static int -opFUCOMPP(uint32_t fetchdat) +opFUCOMPP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; diff --git a/src/cpu/x87_ops_loadstore.h b/src/cpu/x87_ops_loadstore.h index 0936f325b..d0b31ac85 100644 --- a/src/cpu/x87_ops_loadstore.h +++ b/src/cpu/x87_ops_loadstore.h @@ -17,7 +17,7 @@ * Copyright 2016-2019 Miran Grca. */ static int -opFILDiw_a16(uint32_t fetchdat) +opFILDiw_a16(UNUSED(uint32_t fetchdat)) { int16_t temp; FP_ENTER(); @@ -50,7 +50,7 @@ opFILDiw_a32(uint32_t fetchdat) #endif static int -opFISTiw_a16(uint32_t fetchdat) +opFISTiw_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -75,7 +75,7 @@ opFISTiw_a32(uint32_t fetchdat) #endif static int -opFISTPiw_a16(uint32_t fetchdat) +opFISTPiw_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -106,7 +106,7 @@ opFISTPiw_a32(uint32_t fetchdat) #endif static int -opFILDiq_a16(uint32_t fetchdat) +opFILDiq_a16(UNUSED(uint32_t fetchdat)) { int64_t temp64; FP_ENTER(); @@ -145,7 +145,7 @@ opFILDiq_a32(uint32_t fetchdat) #endif static int -FBLD_a16(uint32_t fetchdat) +FBLD_a16(UNUSED(uint32_t fetchdat)) { uint16_t load_reg_hi = 0xffff; uint64_t load_reg_lo = BX_CONST64(0xC000000000000000); @@ -228,7 +228,7 @@ FBLD_a32(uint32_t fetchdat) #endif static int -FBSTP_a16(uint32_t fetchdat) +FBSTP_a16(UNUSED(uint32_t fetchdat)) { double dt; double tempd; @@ -296,7 +296,7 @@ FBSTP_a32(uint32_t fetchdat) #endif static int -FISTPiq_a16(uint32_t fetchdat) +FISTPiq_a16(UNUSED(uint32_t fetchdat)) { int64_t temp64; FP_ENTER(); @@ -337,7 +337,7 @@ FISTPiq_a32(uint32_t fetchdat) #endif static int -opFILDil_a16(uint32_t fetchdat) +opFILDil_a16(UNUSED(uint32_t fetchdat)) { int32_t templ; FP_ENTER(); @@ -370,7 +370,7 @@ opFILDil_a32(uint32_t fetchdat) #endif static int -opFISTil_a16(uint32_t fetchdat) +opFISTil_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -395,7 +395,7 @@ opFISTil_a32(uint32_t fetchdat) #endif static int -opFISTPil_a16(uint32_t fetchdat) +opFISTPil_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -426,7 +426,7 @@ opFISTPil_a32(uint32_t fetchdat) #endif static int -opFLDe_a16(uint32_t fetchdat) +opFLDe_a16(UNUSED(uint32_t fetchdat)) { double t; FP_ENTER(); @@ -459,7 +459,7 @@ opFLDe_a32(uint32_t fetchdat) #endif static int -opFSTPe_a16(uint32_t fetchdat) +opFSTPe_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -490,7 +490,7 @@ opFSTPe_a32(uint32_t fetchdat) #endif static int -opFLDd_a16(uint32_t fetchdat) +opFLDd_a16(UNUSED(uint32_t fetchdat)) { x87_td t; FP_ENTER(); @@ -523,7 +523,7 @@ opFLDd_a32(uint32_t fetchdat) #endif static int -opFSTd_a16(uint32_t fetchdat) +opFSTd_a16(UNUSED(uint32_t fetchdat)) { x87_td t; FP_ENTER(); @@ -552,7 +552,7 @@ opFSTd_a32(uint32_t fetchdat) #endif static int -opFSTPd_a16(uint32_t fetchdat) +opFSTPd_a16(UNUSED(uint32_t fetchdat)) { x87_td t; FP_ENTER(); @@ -587,7 +587,7 @@ opFSTPd_a32(uint32_t fetchdat) #endif static int -opFLDs_a16(uint32_t fetchdat) +opFLDs_a16(UNUSED(uint32_t fetchdat)) { x87_ts ts; FP_ENTER(); @@ -620,7 +620,7 @@ opFLDs_a32(uint32_t fetchdat) #endif static int -opFSTs_a16(uint32_t fetchdat) +opFSTs_a16(UNUSED(uint32_t fetchdat)) { x87_ts ts; FP_ENTER(); @@ -649,7 +649,7 @@ opFSTs_a32(uint32_t fetchdat) #endif static int -opFSTPs_a16(uint32_t fetchdat) +opFSTPs_a16(UNUSED(uint32_t fetchdat)) { x87_ts ts; FP_ENTER(); diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 96750468a..c1f09fda9 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -12,7 +12,7 @@ opFI(uint32_t fetchdat) } #else static int -opFSTSW_AX(uint32_t fetchdat) +opFSTSW_AX(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -24,7 +24,7 @@ opFSTSW_AX(uint32_t fetchdat) #endif static int -opFNOP(uint32_t fetchdat) +opFNOP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -34,7 +34,7 @@ opFNOP(uint32_t fetchdat) } static int -opFXTRACT(uint32_t fetchdat) +opFXTRACT(UNUSED(uint32_t fetchdat)) { x87_conv_t test; int64_t exp80; @@ -56,7 +56,7 @@ opFXTRACT(uint32_t fetchdat) } static int -opFCLEX(uint32_t fetchdat) +opFCLEX(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -67,7 +67,7 @@ opFCLEX(uint32_t fetchdat) } static int -opFINIT(uint32_t fetchdat) +opFINIT(UNUSED(uint32_t fetchdat)) { uint64_t *p; FP_ENTER(); @@ -208,7 +208,7 @@ FSTOR(void) return cpu_state.abrt; } static int -opFSTOR_a16(uint32_t fetchdat) +opFSTOR_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -429,7 +429,7 @@ FSAVE(void) return cpu_state.abrt; } static int -opFSAVE_a16(uint32_t fetchdat) +opFSAVE_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -450,7 +450,7 @@ opFSAVE_a32(uint32_t fetchdat) #endif static int -opFSTSW_a16(uint32_t fetchdat) +opFSTSW_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -516,7 +516,7 @@ opFXCH(uint32_t fetchdat) } static int -opFCHS(uint32_t fetchdat) +opFCHS(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -528,7 +528,7 @@ opFCHS(uint32_t fetchdat) } static int -opFABS(uint32_t fetchdat) +opFABS(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -540,7 +540,7 @@ opFABS(uint32_t fetchdat) } static int -opFTST(uint32_t fetchdat) +opFTST(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -555,7 +555,7 @@ opFTST(uint32_t fetchdat) } static int -opFXAM(uint32_t fetchdat) +opFXAM(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -579,7 +579,7 @@ opFXAM(uint32_t fetchdat) } static int -opFLD1(uint32_t fetchdat) +opFLD1(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -590,7 +590,7 @@ opFLD1(uint32_t fetchdat) } static int -opFLDL2T(uint32_t fetchdat) +opFLDL2T(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -601,7 +601,7 @@ opFLDL2T(uint32_t fetchdat) } static int -opFLDL2E(uint32_t fetchdat) +opFLDL2E(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -612,7 +612,7 @@ opFLDL2E(uint32_t fetchdat) } static int -opFLDPI(uint32_t fetchdat) +opFLDPI(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -623,7 +623,7 @@ opFLDPI(uint32_t fetchdat) } static int -opFLDEG2(uint32_t fetchdat) +opFLDEG2(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -634,7 +634,7 @@ opFLDEG2(uint32_t fetchdat) } static int -opFLDLN2(uint32_t fetchdat) +opFLDLN2(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -645,7 +645,7 @@ opFLDLN2(uint32_t fetchdat) } static int -opFLDZ(uint32_t fetchdat) +opFLDZ(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -657,7 +657,7 @@ opFLDZ(uint32_t fetchdat) } static int -opF2XM1(uint32_t fetchdat) +opF2XM1(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -669,7 +669,7 @@ opF2XM1(uint32_t fetchdat) } static int -opFYL2X(uint32_t fetchdat) +opFYL2X(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -682,7 +682,7 @@ opFYL2X(uint32_t fetchdat) } static int -opFYL2XP1(uint32_t fetchdat) +opFYL2XP1(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -695,7 +695,7 @@ opFYL2XP1(uint32_t fetchdat) } static int -opFPTAN(uint32_t fetchdat) +opFPTAN(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -709,7 +709,7 @@ opFPTAN(uint32_t fetchdat) } static int -opFPATAN(uint32_t fetchdat) +opFPATAN(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -722,7 +722,7 @@ opFPATAN(uint32_t fetchdat) } static int -opFDECSTP(uint32_t fetchdat) +opFDECSTP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -737,7 +737,7 @@ opFDECSTP(uint32_t fetchdat) } static int -opFINCSTP(uint32_t fetchdat) +opFINCSTP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -752,7 +752,7 @@ opFINCSTP(uint32_t fetchdat) } static int -opFPREM(uint32_t fetchdat) +opFPREM(UNUSED(uint32_t fetchdat)) { int64_t temp64; FP_ENTER(); @@ -773,7 +773,7 @@ opFPREM(uint32_t fetchdat) } static int -opFPREM1(uint32_t fetchdat) +opFPREM1(UNUSED(uint32_t fetchdat)) { int64_t temp64; FP_ENTER(); @@ -794,7 +794,7 @@ opFPREM1(uint32_t fetchdat) } static int -opFSQRT(uint32_t fetchdat) +opFSQRT(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -807,7 +807,7 @@ opFSQRT(uint32_t fetchdat) #ifndef FPU_8087 static int -opFSINCOS(uint32_t fetchdat) +opFSINCOS(UNUSED(uint32_t fetchdat)) { double td; FP_ENTER(); @@ -824,7 +824,7 @@ opFSINCOS(uint32_t fetchdat) #endif static int -opFRNDINT(uint32_t fetchdat) +opFRNDINT(UNUSED(uint32_t fetchdat)) { double dst0; @@ -839,7 +839,7 @@ opFRNDINT(uint32_t fetchdat) } static int -opFSCALE(uint32_t fetchdat) +opFSCALE(UNUSED(uint32_t fetchdat)) { int64_t temp64; FP_ENTER(); @@ -855,7 +855,7 @@ opFSCALE(uint32_t fetchdat) #ifndef FPU_8087 static int -opFSIN(uint32_t fetchdat) +opFSIN(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -868,7 +868,7 @@ opFSIN(uint32_t fetchdat) } static int -opFCOS(uint32_t fetchdat) +opFCOS(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -909,7 +909,7 @@ FLDENV(void) } static int -opFLDENV_a16(uint32_t fetchdat) +opFLDENV_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -930,7 +930,7 @@ opFLDENV_a32(uint32_t fetchdat) #endif static int -opFLDCW_a16(uint32_t fetchdat) +opFLDCW_a16(UNUSED(uint32_t fetchdat)) { uint16_t tempw; FP_ENTER(); @@ -1011,7 +1011,7 @@ FSTENV(void) } static int -opFSTENV_a16(uint32_t fetchdat) +opFSTENV_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -1032,7 +1032,7 @@ opFSTENV_a32(uint32_t fetchdat) #endif static int -opFSTCW_a16(uint32_t fetchdat) +opFSTCW_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); diff --git a/src/cpu/x87_ops_sf.h b/src/cpu/x87_ops_sf.h index 31416447e..0d4fee81a 100644 --- a/src/cpu/x87_ops_sf.h +++ b/src/cpu/x87_ops_sf.h @@ -235,7 +235,7 @@ fpu_load_environment(void) } static int -sf_FLDCW_a16(uint32_t fetchdat) +sf_FLDCW_a16(UNUSED(uint32_t fetchdat)) { uint16_t tempw; @@ -288,7 +288,7 @@ sf_FLDCW_a32(uint32_t fetchdat) #endif static int -sf_FNSTCW_a16(uint32_t fetchdat) +sf_FNSTCW_a16(UNUSED(uint32_t fetchdat)) { uint16_t cwd = i387_get_control_word(); @@ -317,7 +317,7 @@ sf_FNSTCW_a32(uint32_t fetchdat) #endif static int -sf_FNSTSW_a16(uint32_t fetchdat) +sf_FNSTSW_a16(UNUSED(uint32_t fetchdat)) { uint16_t swd = i387_get_status_word(); @@ -359,7 +359,7 @@ sf_FI(uint32_t fetchdat) } #else static int -sf_FNSTSW_AX(uint32_t fetchdat) +sf_FNSTSW_AX(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -371,7 +371,7 @@ sf_FNSTSW_AX(uint32_t fetchdat) #endif static int -sf_FRSTOR_a16(uint32_t fetchdat) +sf_FRSTOR_a16(UNUSED(uint32_t fetchdat)) { floatx80 tmp; int offset; @@ -414,7 +414,7 @@ sf_FRSTOR_a32(uint32_t fetchdat) #endif static int -sf_FNSAVE_a16(uint32_t fetchdat) +sf_FNSAVE_a16(UNUSED(uint32_t fetchdat)) { floatx80 stn; int offset; @@ -488,7 +488,7 @@ sf_FNSAVE_a32(uint32_t fetchdat) #endif static int -sf_FNCLEX(uint32_t fetchdat) +sf_FNCLEX(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -499,7 +499,7 @@ sf_FNCLEX(uint32_t fetchdat) } static int -sf_FNINIT(uint32_t fetchdat) +sf_FNINIT(UNUSED(uint32_t fetchdat)) { FP_ENTER(); cpu_state.pc++; @@ -525,7 +525,7 @@ sf_FNINIT(uint32_t fetchdat) } static int -sf_FLDENV_a16(uint32_t fetchdat) +sf_FLDENV_a16(UNUSED(uint32_t fetchdat)) { int tag; @@ -572,7 +572,7 @@ sf_FLDENV_a32(uint32_t fetchdat) #endif static int -sf_FNSTENV_a16(uint32_t fetchdat) +sf_FNSTENV_a16(UNUSED(uint32_t fetchdat)) { FP_ENTER(); fetch_ea_16(fetchdat); @@ -605,7 +605,7 @@ sf_FNSTENV_a32(uint32_t fetchdat) #endif static int -sf_FNOP(uint32_t fetchdat) +sf_FNOP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); FPU_check_pending_exceptions(); diff --git a/src/cpu/x87_ops_sf_arith.h b/src/cpu/x87_ops_sf_arith.h index edbd64dcf..c9e25e97c 100644 --- a/src/cpu/x87_ops_sf_arith.h +++ b/src/cpu/x87_ops_sf_arith.h @@ -1,7 +1,7 @@ #define sf_FPU(name, optype, a_size, load_var, rw, use_var, is_nan, cycle_postfix) \ static int sf_FADD##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ @@ -31,7 +31,7 @@ next_ins: } \ static int sf_FDIV##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ @@ -61,7 +61,7 @@ next_ins: } \ static int sf_FDIVR##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ @@ -91,7 +91,7 @@ next_ins: } \ static int sf_FMUL##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ @@ -121,7 +121,7 @@ next_ins: } \ static int sf_FSUB##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ @@ -151,7 +151,7 @@ next_ins: } \ static int sf_FSUBR##name##_a##a_size(uint32_t fetchdat) \ { \ - floatx80 a, result; \ + floatx80 a, result; \ struct softfloat_status_t status; \ optype temp; \ FP_ENTER(); \ diff --git a/src/cpu/x87_ops_sf_compare.h b/src/cpu/x87_ops_sf_compare.h index c4a38b375..945ed99d3 100644 --- a/src/cpu/x87_ops_sf_compare.h +++ b/src/cpu/x87_ops_sf_compare.h @@ -460,7 +460,7 @@ sf_FTST(uint32_t fetchdat) } static int -sf_FXAM(uint32_t fetchdat) +sf_FXAM(UNUSED(uint32_t fetchdat)) { floatx80 reg; int sign; diff --git a/src/cpu/x87_ops_sf_misc.h b/src/cpu/x87_ops_sf_misc.h index 0aab2ec08..746e85c6f 100644 --- a/src/cpu/x87_ops_sf_misc.h +++ b/src/cpu/x87_ops_sf_misc.h @@ -81,7 +81,7 @@ sf_FABS(uint32_t fetchdat) } static int -sf_FDECSTP(uint32_t fetchdat) +sf_FDECSTP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); FPU_check_pending_exceptions(); @@ -94,7 +94,7 @@ sf_FDECSTP(uint32_t fetchdat) } static int -sf_FINCSTP(uint32_t fetchdat) +sf_FINCSTP(UNUSED(uint32_t fetchdat)) { FP_ENTER(); FPU_check_pending_exceptions(); diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index 80e89df1f..24d5de1fb 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -313,7 +313,7 @@ mtouch_process_commands(mouse_microtouch_t *dev) } static void -mtouch_write(serial_t *serial, void *priv, uint8_t data) +mtouch_write(UNUSED(serial_t *serial), void *priv, uint8_t data) { mouse_microtouch_t *dev = (mouse_microtouch_t *) priv; @@ -495,7 +495,7 @@ mtouch_poll_global(void) } void * -mtouch_init(const device_t *info) +mtouch_init(UNUSED(const device_t *info)) { mouse_microtouch_t *dev = calloc(1, sizeof(mouse_microtouch_t)); diff --git a/src/device/nec_mate_unk.c b/src/device/nec_mate_unk.c index 3244733c9..c0393eaa2 100644 --- a/src/device/nec_mate_unk.c +++ b/src/device/nec_mate_unk.c @@ -30,7 +30,7 @@ #include <86box/plat_unused.h> static uint8_t -nec_mate_unk_read(UNUSED(uint16_t addr), void *priv) +nec_mate_unk_read(UNUSED(uint16_t addr), UNUSED(void *priv)) { /* Expected by this NEC machine. @@ -49,7 +49,7 @@ nec_mate_unk_close(void *priv) } static void * -nec_mate_unk_init(const device_t *info) +nec_mate_unk_init(UNUSED(const device_t *info)) { /* We have to return something non-NULL. */ uint8_t *dev = (uint8_t *) calloc(1, sizeof(uint8_t)); diff --git a/src/device/novell_cardkey.c b/src/device/novell_cardkey.c index 737b4104d..34b6390d1 100644 --- a/src/device/novell_cardkey.c +++ b/src/device/novell_cardkey.c @@ -61,7 +61,7 @@ novell_cardkey_read(uint16_t port, void *priv) return val ^ 0xFF; } -void* novell_cardkey_init(const device_t* info) +void* novell_cardkey_init(UNUSED(const device_t* info)) { char sernumstr[13] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 0 }; int i = 0; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 49d23daee..592649c0e 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -386,7 +386,7 @@ ide_atapi_get_period(uint8_t channel) } static void -ide_irq_update(ide_board_t *dev, int log) +ide_irq_update(ide_board_t *dev, UNUSED(int log)) { ide_t *ide; uint8_t set; @@ -1894,7 +1894,7 @@ ide_read_data(ide_t *ide) } static uint8_t -ide_status(ide_t *ide, ide_t *ide_other, int ch) +ide_status(ide_t *ide, UNUSED(ide_t *ide_other), UNUSED(int ch)) { uint8_t ret; @@ -3207,7 +3207,7 @@ mcide_mca_reset(void *priv) } static void -mcide_reset(void *priv) +mcide_reset(UNUSED(void *priv)) { for (uint8_t i = 0; i < 2; i++) { if (ide_boards[i] != NULL) diff --git a/src/disk/lba_enhancer.c b/src/disk/lba_enhancer.c index c7f3fd969..8e8bc480d 100644 --- a/src/disk/lba_enhancer.c +++ b/src/disk/lba_enhancer.c @@ -44,7 +44,7 @@ lba_enhancer_close(void* priv) } void * -lba_enhancer_init(const device_t *info) +lba_enhancer_init(UNUSED(const device_t *info)) { lba_enhancer_t *dev = (lba_enhancer_t *) calloc(1, sizeof(lba_enhancer_t)); diff --git a/src/disk/mo.c b/src/disk/mo.c index 7528806c7..5494fc9a8 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1975,7 +1975,7 @@ mo_global_init(void) } static int -mo_get_max(const ide_t *ide, const int ide_has_dma, const int type) +mo_get_max(UNUSED(const ide_t *ide), const int ide_has_dma, const int type) { int ret; @@ -1999,7 +1999,7 @@ mo_get_max(const ide_t *ide, const int ide_has_dma, const int type) } static int -mo_get_timings(const ide_t *ide, const int ide_has_dma, const int type) +mo_get_timings(UNUSED(const ide_t *ide), const int ide_has_dma, const int type) { int ret; diff --git a/src/disk/zip.c b/src/disk/zip.c index fd261b4dd..72781281a 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -2062,7 +2062,7 @@ zip_global_init(void) } static int -zip_get_max(const ide_t *ide, const int ide_has_dma, const int type) +zip_get_max(UNUSED(const ide_t *ide), const int ide_has_dma, const int type) { int ret; @@ -2086,7 +2086,7 @@ zip_get_max(const ide_t *ide, const int ide_has_dma, const int type) } static int -zip_get_timings(const ide_t *ide, const int ide_has_dma, const int type) +zip_get_timings(UNUSED(const ide_t *ide), const int ide_has_dma, const int type) { int ret; diff --git a/src/floppy/fdc_compaticard.c b/src/floppy/fdc_compaticard.c index a693c9cb2..4abc4abac 100644 --- a/src/floppy/fdc_compaticard.c +++ b/src/floppy/fdc_compaticard.c @@ -30,6 +30,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> +#include <86box/plat_unused.h> #define DEVICE_COMPATICARD_I 0 #define DEVICE_COMPATICARD_II 1 @@ -57,7 +58,7 @@ typedef struct compaticard_s { } compaticard_t; static void -compaticard_out(uint16_t port, uint8_t val, void *priv) +compaticard_out(UNUSED(uint16_t port), uint8_t val, void *priv) { compaticard_t *dev = (compaticard_t *) priv; @@ -65,7 +66,7 @@ compaticard_out(uint16_t port, uint8_t val, void *priv) } static uint8_t -compaticard_in(uint16_t port, void *priv) +compaticard_in(UNUSED(uint16_t port), void *priv) { compaticard_t *dev = (compaticard_t *) priv; uint8_t ret = (dev->cr_2 &CR_2_MASK); diff --git a/src/floppy/fdd_pcjs.c b/src/floppy/fdd_pcjs.c index 41db65a1a..6f69042b0 100644 --- a/src/floppy/fdd_pcjs.c +++ b/src/floppy/fdd_pcjs.c @@ -469,7 +469,7 @@ track_flags(int drive) } static void -set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +set_sector(int drive, int side, uint8_t c, UNUSED(uint8_t h), uint8_t r, UNUSED(uint8_t n)) { pcjs_t *dev = images[drive]; diff --git a/src/game/gameport.c b/src/game/gameport.c index 579f5c235..39193af88 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -646,7 +646,7 @@ static const device_config_t tmacm_config[] = { { "" } } }, - { "", "", -1 } + { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; diff --git a/src/include/86box/bswap.h b/src/include/86box/bswap.h index f7d3a3d0e..37c846d59 100644 --- a/src/include/86box/bswap.h +++ b/src/include/86box/bswap.h @@ -133,12 +133,12 @@ bswap64s(uint64_t *s) return endian##_bswap(v, size); \ } \ \ - static __inline void endian##size##_to_cpus(type *p) \ + static __inline void endian##size##_to_cpus(UNUSED(type *p)) \ { \ endian##_bswaps(p, size) \ } \ \ - static __inline void cpu_to_##endian##size##s(type *p) \ + static __inline void cpu_to_##endian##size##s(UNUSED(type *p)) \ { \ endian##_bswaps(p, size) \ } \ diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index de20facdb..82d211896 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -104,8 +104,7 @@ enum { #define CDV EMU_VERSION_EX -static const struct -{ +static const struct cdrom_drive_types_s { const char vendor[9]; const char model[17]; const char revision[5]; @@ -204,19 +203,19 @@ static const struct Unusual 2.23x according to Google, I'm rounding it upwards to 3x. Assumed caddy based on the DM-3024. */ - { "TEXEL", "CD-ROM DM-3028", "1.06", "texel_3028", BUS_TYPE_SCSI, 2, 3, 36, 1 }, /* Caddy. */ + { "TEXEL", "CD-ROM DM-3028", "1.06", "texel_3028", BUS_TYPE_SCSI, 2, 3, 36, 1, { -1, -1, -1, -1 } }, /* Caddy. */ /* The characteristics are a complete guesswork because I can't find this one on Google. Also, INQUIRY length is always 96 on these Toshiba drives. */ - { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "toshiba_xm", BUS_TYPE_SCSI, 2, 2, 96, 0 }, /* Tray. */ - { "TOSHIBA", "CD-ROM XM-3201B", "3232", "toshiba_3201b", BUS_TYPE_SCSI, 1, 1, 96, 1 }, /* Caddy. */ - { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "toshiba_3301ta", BUS_TYPE_SCSI, 2, 2, 96, 0 }, /* Tray. */ - { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "toshiba_5701a", BUS_TYPE_SCSI, 2, 12, 96, 0 }, /* Tray. */ - { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "toshiba_m1401", BUS_TYPE_SCSI, 2, 40, 96, 0 }, /* Tray. */ - { "", "", "", "", BUS_TYPE_NONE, 0, -1, 0, 0 } + { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "toshiba_xm", BUS_TYPE_SCSI, 2, 2, 96, 0, { -1, -1, -1, -1 } }, /* Tray. */ + { "TOSHIBA", "CD-ROM XM-3201B", "3232", "toshiba_3201b", BUS_TYPE_SCSI, 1, 1, 96, 1, { -1, -1, -1, -1 } }, /* Caddy. */ + { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "toshiba_3301ta", BUS_TYPE_SCSI, 2, 2, 96, 0, { -1, -1, -1, -1 } }, /* Tray. */ + { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "toshiba_5701a", BUS_TYPE_SCSI, 2, 12, 96, 0, { -1, -1, -1, -1 } }, /* Tray. */ + { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "toshiba_m1401", BUS_TYPE_SCSI, 2, 40, 96, 0, { -1, -1, -1, -1 } }, /* Tray. */ + { "", "", "", "", BUS_TYPE_NONE, 0, -1, 0, 0, { -1, -1, -1, -1 } } }; /* To shut up the GCC compilers. */ diff --git a/src/machine/m_at_grid.c b/src/machine/m_at_grid.c index 443607382..03b7288b9 100644 --- a/src/machine/m_at_grid.c +++ b/src/machine/m_at_grid.c @@ -38,6 +38,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/vid_cga.h> +#include <86box/plat_unused.h> #define GRID_APPROM_SELECT 0x440 #define GRID_APPROM_ENABLE 0x405 @@ -263,7 +264,7 @@ static uint8_t grid_io_read(uint16_t port, void *priv) { } static void * -grid_init(const device_t *info) +grid_init(UNUSED(const device_t *info)) { grid_t *dev = calloc(1, sizeof(grid_t)); diff --git a/src/network/net_3c501.c b/src/network/net_3c501.c index 33e9d59bd..73dd5ef62 100644 --- a/src/network/net_3c501.c +++ b/src/network/net_3c501.c @@ -56,7 +56,6 @@ #include <86box/thread.h> #include <86box/timer.h> #include <86box/network.h> -#include <86box/bswap.h> #include <86box/plat_unused.h> /* Maximum number of times we report a link down to the guest (failure to send frame) */ diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index 31156fa9a..cd5016147 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -60,7 +60,6 @@ #include <86box/timer.h> #include <86box/network.h> #include <86box/net_dp8390.h> -#include <86box/bswap.h> #include <86box/plat_unused.h> typedef struct threec503_t { diff --git a/src/network/net_modem.c b/src/network/net_modem.c index 732190254..83dfe04d7 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1133,7 +1133,7 @@ modem_dtr_callback_timer(void *priv) } void -modem_dtr_callback(serial_t *serial, int status, void *priv) +modem_dtr_callback(UNUSED(serial_t *serial), int status, void *priv) { modem_t *dev = (modem_t *) priv; dev->dtrstate = !!status; @@ -1483,7 +1483,7 @@ modem_cmdpause_timer_callback(void *priv) /* Initialize the device for use by the user. */ static void * -modem_init(const device_t *info) +modem_init(UNUSED(const device_t *info)) { modem_t *modem = (modem_t *) calloc(1, sizeof(modem_t)); const char *phonebook_file = NULL; diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index d3de47852..97c2b5de2 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -66,7 +66,6 @@ #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_ne2000.h> -#include <86box/bswap.h> #include <86box/isapnp.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index fea20e3c9..5487486b4 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -46,9 +46,9 @@ #include <86box/thread.h> #include <86box/network.h> #include <86box/net_pcnet.h> -#include <86box/bswap.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#include <86box/bswap.h> /* PCI info. */ #define PCI_VENDID 0x1022 /* AMD */ diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index b9b7fc957..74b041b35 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -44,10 +44,10 @@ #include <86box/thread.h> #include <86box/network.h> #include <86box/net_eeprom_nmc93cxx.h> -#include <86box/bswap.h> #include <86box/nvr.h> #include "cpu.h" #include <86box/plat_unused.h> +#include <86box/bswap.h> #define PCI_PERIOD 30 /* 30 ns period = 33.333333 Mhz frequency */ @@ -1210,7 +1210,7 @@ rtl8139_CpCmd_read(RTL8139State *s) } static void -rtl8139_IntrMitigate_write(UNUSED(RTL8139State *s), uint32_t val) +rtl8139_IntrMitigate_write(UNUSED(RTL8139State *s), UNUSED(uint32_t val)) { rtl8139_log("C+ IntrMitigate register write(w) val=0x%04x\n", val); } @@ -3151,7 +3151,7 @@ rtl8139_pci_read(UNUSED(int func), int addr, void *priv) } static void -rtl8139_pci_write(int func, int addr, uint8_t val, void *priv) +rtl8139_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) { RTL8139State *s = (RTL8139State *) priv; diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index af30c5505..2c3aab379 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -32,9 +32,9 @@ #include <86box/thread.h> #include <86box/network.h> #include <86box/net_eeprom_nmc93cxx.h> -#include <86box/bswap.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#include <86box/bswap.h> #define ROM_PATH_DEC21140 "roms/network/dec21140/BIOS13502.BIN" diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 3d50c8f67..1e5496851 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -63,7 +63,6 @@ #include <86box/network.h> #include <86box/net_dp8390.h> #include <86box/net_wd8003.h> -#include <86box/bswap.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> diff --git a/src/pic.c b/src/pic.c index fa7ff3662..7f6eda40d 100644 --- a/src/pic.c +++ b/src/pic.c @@ -245,7 +245,7 @@ pic_update_pending_at(void) } static void -pic_callback(void *priv) +pic_callback(UNUSED(void *priv)) { update_pending(); } diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index ae4eb1727..9efd67ad6 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -97,7 +97,7 @@ ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) } static int -ioctl_is_track_pre(const void *local, const uint32_t sector) +ioctl_is_track_pre(const void *local, UNUSED(const uint32_t sector)) { ioctl_t *ioctl = (ioctl_t *) local; @@ -111,7 +111,7 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) } static int -ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) +ioctl_read_sector(const void *local, UNUSED(uint8_t *buffer), UNUSED(uint32_t const sector)) { ioctl_t *ioctl = (ioctl_t *) local; diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index f77370574..1c917f517 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -42,15 +42,6 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin) # endif #endif -#ifdef Q_OS_WINDOWS -# include "qt_rendererstack.hpp" -# include "qt_winrawinputfilter.hpp" -# include "qt_winmanagerfilter.hpp" -# include <86box/win.h> -# include -# include -#endif - extern "C" { #include <86box/86box.h> #include <86box/config.h> @@ -64,6 +55,15 @@ extern "C" { #include <86box/version.h> } +#ifdef Q_OS_WINDOWS +# include "qt_rendererstack.hpp" +# include "qt_winrawinputfilter.hpp" +# include "qt_winmanagerfilter.hpp" +# include <86box/win.h> +# include +# include +#endif + #include #include #include diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a0ef86533..dd6c34efc 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -156,6 +156,7 @@ strnicmp(const char *s1, const char *s2, size_t n) void do_start(void) { + // } void @@ -557,7 +558,7 @@ endblit() std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } -} +} /*extern "C" */ #ifdef Q_OS_WINDOWS size_t diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 33858ebbc..ff49aef90 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1524,7 +1524,7 @@ scsi_cdrom_set_speed(scsi_cdrom_t *dev, const uint8_t *cdb) } static uint8_t -scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; uint8_t cmd_stat = 0x00; @@ -1761,7 +1761,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) } static uint8_t -scsi_cdrom_command_matsushita(void *sc, const uint8_t *cdb, int32_t *BufLen) +scsi_cdrom_command_matsushita(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; const uint8_t cmd_stat = 0x00; @@ -3581,7 +3581,7 @@ scsi_cdrom_close(void *priv) } static int -scsi_cdrom_get_max(const ide_t *ide, const int ide_has_dma, const int type) +scsi_cdrom_get_max(const ide_t *ide, UNUSED(const int ide_has_dma), const int type) { const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; int ret; @@ -3600,7 +3600,7 @@ scsi_cdrom_get_max(const ide_t *ide, const int ide_has_dma, const int type) } static int -scsi_cdrom_get_timings(const ide_t *ide, const int ide_has_dma, const int type) +scsi_cdrom_get_timings(const ide_t *ide, UNUSED(const int ide_has_dma), const int type) { const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; int has_dma = cdrom_has_dma(dev->drv->type); @@ -3628,7 +3628,7 @@ scsi_cdrom_get_timings(const ide_t *ide, const int ide_has_dma, const int type) * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command */ static void -scsi_cdrom_identify(const ide_t *ide, const int ide_has_dma) +scsi_cdrom_identify(const ide_t *ide, UNUSED(const int ide_has_dma)) { const scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; char model[2048] = { 0 }; diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index c11f09443..878259094 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -1642,7 +1642,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) } static int -scsi_disk_get_max(const ide_t *ide, int ide_has_dma, const int type) +scsi_disk_get_max(UNUSED(const ide_t *ide), int ide_has_dma, const int type) { int ret; @@ -1668,7 +1668,7 @@ scsi_disk_get_max(const ide_t *ide, int ide_has_dma, const int type) } static int -scsi_disk_get_timings(const ide_t *ide, const int ide_has_dma, const int type) +scsi_disk_get_timings(UNUSED(const ide_t *ide), const int ide_has_dma, const int type) { int ret; diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c index aee1b6a1d..1cde8657e 100644 --- a/src/sio/sio_it86x1f.c +++ b/src/sio/sio_it86x1f.c @@ -602,7 +602,7 @@ it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) } static void -it86x1f_write_addr(uint16_t port, uint8_t val, void *priv) +it86x1f_write_addr(UNUSED(uint16_t port), uint8_t val, void *priv) { it86x1f_t *dev = (it86x1f_t *) priv; @@ -623,7 +623,7 @@ it86x1f_write_addr(uint16_t port, uint8_t val, void *priv) } static void -it86x1f_write_data(uint16_t port, uint8_t val, void *priv) +it86x1f_write_data(UNUSED(uint16_t port), uint8_t val, void *priv) { it86x1f_t *dev = (it86x1f_t *) priv; @@ -659,7 +659,7 @@ it86x1f_write_data(uint16_t port, uint8_t val, void *priv) } static uint8_t -it86x1f_read_addr(uint16_t port, void *priv) +it86x1f_read_addr(UNUSED(uint16_t port), void *priv) { it86x1f_t *dev = (it86x1f_t *) priv; uint8_t ret = dev->locked ? 0xff : dev->cur_reg; @@ -670,7 +670,7 @@ it86x1f_read_addr(uint16_t port, void *priv) } static uint8_t -it86x1f_read_data(uint16_t port, void *priv) +it86x1f_read_data(UNUSED(uint16_t port), void *priv) { it86x1f_t *dev = (it86x1f_t *) priv; uint8_t ret = 0xff; diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index 5da43581f..33cb0d865 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -68,7 +68,7 @@ pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) } uint8_t -pc87306_gpio_read(uint16_t port, void *priv) +pc87306_gpio_read(uint16_t port, UNUSED(void *priv)) { uint32_t ret = machine_handle_gpio(0, 0xffffffff); diff --git a/src/sio/sio_vl82c113.c b/src/sio/sio_vl82c113.c index ecfc7ba09..ee18b1893 100644 --- a/src/sio/sio_vl82c113.c +++ b/src/sio/sio_vl82c113.c @@ -24,6 +24,7 @@ #include <86box/keyboard.h> #include <86box/nvr.h> #include <86box/sio.h> +#include <86box/plat_unused.h> typedef struct vl82c113_t { uint8_t index; @@ -128,7 +129,7 @@ vl82c113_close(void *priv) } static void * -vl82c113_init(const device_t *info) +vl82c113_init(UNUSED(const device_t *info)) { vl82c113_t *dev = (vl82c113_t *) calloc(1, sizeof(vl82c113_t)); diff --git a/src/sound/midi_opl4.c b/src/sound/midi_opl4.c index e1f80b0f5..5ec15cc7c 100644 --- a/src/sound/midi_opl4.c +++ b/src/sound/midi_opl4.c @@ -557,7 +557,7 @@ program_change(uint8_t midi_channel, uint8_t program, opl4_midi_t *opl4_midi) } static void -opl4_midi_thread(void *arg) +opl4_midi_thread(UNUSED(void *arg)) { opl4_midi_t *opl4_midi = opl4_midi_cur; uint32_t i = 0; @@ -648,12 +648,13 @@ opl4_midi_msg(uint8_t *val) } void -opl4_midi_sysex(uint8_t *data, unsigned int len) +opl4_midi_sysex(UNUSED(uint8_t *data), UNUSED(unsigned int len)) { + // } void * -opl4_init(const device_t *info) +opl4_init(UNUSED(const device_t *info)) { midi_device_t *dev; extern void al_set_midi(int freq, int buf_size); diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 8eb5260c0..822abeeaa 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -328,7 +328,7 @@ emu8k_log(const char *fmt, ...) static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) { - const register emu8k_mem_pointers_t addrmem = { { addr } }; + register const emu8k_mem_pointers_t addrmem = { { addr } }; return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address]; } diff --git a/src/sound/snd_opl_esfm.c b/src/sound/snd_opl_esfm.c index 993a0ec6b..bcd2a56e9 100644 --- a/src/sound/snd_opl_esfm.c +++ b/src/sound/snd_opl_esfm.c @@ -34,6 +34,7 @@ #include <86box/device.h> #include <86box/timer.h> #include <86box/snd_opl.h> +#include <86box/plat_unused.h> #define RSM_FRAC 10 @@ -175,7 +176,7 @@ esfm_drv_set_do_cycles(void *priv, int8_t do_cycles) } static void * -esfm_drv_init(const device_t *info) +esfm_drv_init(UNUSED(const device_t *info)) { esfm_drv_t *dev = (esfm_drv_t *) calloc(1, sizeof(esfm_drv_t)); dev->flags = FLAG_CYCLES | FLAG_OPL3; diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 400f176a8..05df32322 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -1671,7 +1671,7 @@ pas16_out(uint16_t port, uint8_t val, void *priv) - A 16-bit sample always takes two ctr_clock() ticks. */ static uint16_t -pas16_dma_channel_read(pas16_t *pas16, int channel) +pas16_dma_channel_read(pas16_t *pas16, UNUSED(int channel)) { int status; uint16_t ret; diff --git a/src/sound/snd_resid.cpp b/src/sound/snd_resid.cpp index b9895cf7e..b0503cac2 100644 --- a/src/sound/snd_resid.cpp +++ b/src/sound/snd_resid.cpp @@ -87,10 +87,10 @@ sid_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) #define CLOCK_DELTA(n) (int) (((14318180.0 * n) / 16.0) / (float) RESID_FREQ) static void -fillbuf2(int &count, int16_t *buf, int len) +fillbuf2(int &count, int16_t *buf, UNUSED(int len)) { - int c; - c = psid->sid->clock(count, buf); + int c = psid->sid->clock(count, buf); + if (!c) *buf = psid->last_sample; psid->last_sample = *buf; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 692a53aa3..ea961a6d3 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1417,7 +1417,7 @@ sb_ct1745_mixer_reset(sb_t *sb) } static void -ess_base_write(uint16_t addr, uint8_t val, void *priv) +ess_base_write(uint16_t addr, UNUSED(uint8_t val), void *priv) { sb_t *ess = (sb_t *) priv; @@ -1463,7 +1463,7 @@ ess_base_read(uint16_t addr, void *priv) } static void -ess_fm_midi_write(uint16_t addr, uint8_t val, void *priv) +ess_fm_midi_write(UNUSED(uint16_t addr), UNUSED(uint8_t val), void *priv) { sb_t *ess = (sb_t *) priv; @@ -1471,7 +1471,7 @@ ess_fm_midi_write(uint16_t addr, uint8_t val, void *priv) } static uint8_t -ess_fm_midi_read(uint16_t addr, void *priv) +ess_fm_midi_read(UNUSED(uint16_t addr), void *priv) { sb_t *ess = (sb_t *) priv; diff --git a/src/sound/snd_ssi2001.c b/src/sound/snd_ssi2001.c index 762b243be..0e1bbd96c 100644 --- a/src/sound/snd_ssi2001.c +++ b/src/sound/snd_ssi2001.c @@ -94,13 +94,13 @@ ssi2001_close(void *priv) } static uint8_t -entertainer_read(uint16_t addr, void *priv) +entertainer_read(UNUSED(uint16_t addr), UNUSED(void *priv)) { return 0xa5; } static void -entertainer_write(uint16_t addr, uint8_t val, void *priv) +entertainer_write(UNUSED(uint16_t addr), uint8_t val, void *priv) { entertainer_t *entertainer = (entertainer_t *) priv; entertainer->regs = val; @@ -163,15 +163,27 @@ static const device_config_t ssi2001_config[] = { { .description = "" } } }, - { "gameport", "Enable Game port", CONFIG_BINARY, "", 1 }, - { "", "", -1 } + { + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } // clang-format off }; static const device_config_t entertainer_config[] = { // clang-format off - { "gameport", "Enable Game port", CONFIG_BINARY, "", 1 }, - { "", "", -1 } + { + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 1 + }, + { .name = "", .description = "", .type = CONFIG_END } // clang-format off }; diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index ae4eb1727..9efd67ad6 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -97,7 +97,7 @@ ioctl_get_raw_track_info(UNUSED(const void *local), int *num, uint8_t *rti) } static int -ioctl_is_track_pre(const void *local, const uint32_t sector) +ioctl_is_track_pre(const void *local, UNUSED(const uint32_t sector)) { ioctl_t *ioctl = (ioctl_t *) local; @@ -111,7 +111,7 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) } static int -ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) +ioctl_read_sector(const void *local, UNUSED(uint8_t *buffer), UNUSED(uint32_t const sector)) { ioctl_t *ioctl = (ioctl_t *) local; diff --git a/src/unix/unix.c b/src/unix/unix.c index 8e070d372..7f653b9b6 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -301,7 +301,7 @@ path_abs(char *path) } void -path_normalize(char *path) +path_normalize(UNUSED(char *path)) { /* No-op. */ } @@ -459,13 +459,13 @@ plat_remove(char *path) } void -ui_sb_update_icon_state(int tag, int state) +ui_sb_update_icon_state(UNUSED(int tag), UNUSED(int state)) { /* No-op. */ } void -ui_sb_update_icon(int tag, int active) +ui_sb_update_icon(UNUSED(int tag), UNUSED(int active)) { /* No-op. */ } @@ -477,7 +477,7 @@ plat_delay_ms(uint32_t count) } void -ui_sb_update_tip(int arg) +ui_sb_update_tip(UNUSED(int arg)) { /* No-op. */ } @@ -514,8 +514,9 @@ path_get_dirname(char *dest, const char *path) *dest = '\0'; } volatile int cpu_thread_run = 1; + void -ui_sb_set_text_w(wchar_t *wstr) +ui_sb_set_text_w(UNUSED(wchar_t *wstr)) { /* No-op. */ } @@ -533,7 +534,7 @@ strnicmp(const char *s1, const char *s2, size_t n) } void -main_thread(void *param) +main_thread(UNUSED(void *param)) { uint32_t old_time; uint32_t new_time; @@ -707,7 +708,7 @@ plat_power_off(void) } void -ui_sb_bugui(char *str) +ui_sb_bugui(UNUSED(char *str)) { /* No-op. */ } @@ -726,7 +727,7 @@ int real_sdl_w; int real_sdl_h; void -ui_sb_set_ready(int ready) +ui_sb_set_ready(UNUSED(int ready)) { /* No-op. */ } @@ -912,14 +913,14 @@ void (*f_rl_callback_handler_remove)(void) = NULL; #endif uint32_t -timer_onesec(uint32_t interval, void *param) +timer_onesec(uint32_t interval, UNUSED(void *param)) { pc_onesec(); return interval; } void -monitor_thread(void *param) +monitor_thread(UNUSED(void *param)) { #ifndef USE_CLI if (isatty(fileno(stdin)) && isatty(fileno(stdout))) { @@ -1369,14 +1370,14 @@ main(int argc, char **argv) return 0; } char * -plat_vidapi_name(int i) +plat_vidapi_name(UNUSED(int i)) { return "default"; } /* Sets up the program language before initialization. */ uint32_t -plat_language_code(char *langcode) +plat_language_code(UNUSED(char *langcode)) { /* or maybe not */ return 0; @@ -1413,7 +1414,7 @@ plat_set_thread_name(void *thread, const char *name) /* Converts back the language code to LCID */ void -plat_language_code_r(uint32_t lcid, char *outbuf, int len) +plat_language_code_r(UNUSED(uint32_t lcid), UNUSED(char *outbuf), UNUSED(int len)) { /* or maybe not */ return; @@ -1451,7 +1452,7 @@ endblit(void) /* API */ void -ui_sb_mt32lcd(char *str) +ui_sb_mt32lcd(UNUSED(char *str)) { /* No-op. */ } diff --git a/src/unix/unix_cdrom.c b/src/unix/unix_cdrom.c index 5223b08ba..b1096b0b4 100644 --- a/src/unix/unix_cdrom.c +++ b/src/unix/unix_cdrom.c @@ -70,7 +70,7 @@ cassette_eject(void) } void -cartridge_mount(uint8_t id, char *fn, uint8_t wp) +cartridge_mount(uint8_t id, char *fn, UNUSED(uint8_t wp)) { cart_close(id); cart_load(id, fn); @@ -121,7 +121,7 @@ floppy_eject(uint8_t id) } void -plat_cdrom_ui_update(uint8_t id, uint8_t reload) +plat_cdrom_ui_update(uint8_t id, UNUSED(uint8_t reload)) { cdrom_t *drv = &cdrom[id]; diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c index 002e33fd6..651822335 100644 --- a/src/unix/unix_sdl.c +++ b/src/unix/unix_sdl.c @@ -533,19 +533,19 @@ ui_window_title(wchar_t *str) } void -ui_init_monitor(int monitor_index) +ui_init_monitor(UNUSED(int monitor_index)) { /* No-op. */ } void -ui_deinit_monitor(int monitor_index) +ui_deinit_monitor(UNUSED(int monitor_index)) { /* No-op. */ } void -plat_resize_request(int w, int h, int monitor_index) +plat_resize_request(UNUSED(int w), UNUSED(int h), int monitor_index) { atomic_store((&doresize_monitors[monitor_index]), 1); } diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 0ef4df6df..a923ea7e2 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -291,7 +291,7 @@ mach_pixel_read(mach_t *mach) } static void -mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint32_t cpu_dat, svga_t *svga, mach_t *mach, ibm8514_t *dev) +mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint32_t cpu_dat, UNUSED(svga_t *svga), mach_t *mach, ibm8514_t *dev) { int compare_mode; uint16_t poly_src = 0; diff --git a/src/video/vid_bt481_ramdac.c b/src/video/vid_bt481_ramdac.c index d1c85dcfe..1b81e2dc7 100644 --- a/src/video/vid_bt481_ramdac.c +++ b/src/video/vid_bt481_ramdac.c @@ -26,6 +26,7 @@ #include <86box/timer.h> #include <86box/video.h> #include <86box/vid_svga.h> +#include <86box/plat_unused.h> typedef struct bt481_ramdac_t { int state; @@ -128,7 +129,7 @@ bt481_ramdac_in(uint16_t addr, int rs2, void *priv, svga_t *svga) } static void * -bt481_ramdac_init(const device_t *info) +bt481_ramdac_init(UNUSED(const device_t *info)) { bt481_ramdac_t *ramdac = (bt481_ramdac_t *) malloc(sizeof(bt481_ramdac_t)); memset(ramdac, 0, sizeof(bt481_ramdac_t)); diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 375830f3c..d324368ab 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -448,7 +448,7 @@ cga_interpolate_linear(uint8_t co1, uint8_t co2, double fraction) } static color_t -cga_interpolate_lookup(cga_t *cga, color_t color1, color_t color2, double fraction) +cga_interpolate_lookup(cga_t *cga, color_t color1, color_t color2, UNUSED(double fraction)) { color_t ret; uint8_t dt = cga->double_type - DOUBLE_INTERPOLATE_SRGB; diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index de66a37aa..012a16348 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -166,12 +166,12 @@ static chips_69000_t *reset_state = NULL; /* TODO: Probe timings on real hardware. */ static video_timings_t timing_chips = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 10, .read_w = 10, .read_l = 10 }; -uint8_t chips_69000_readb_linear(uint32_t addr, void *p); -uint16_t chips_69000_readw_linear(uint32_t addr, void *p); -uint32_t chips_69000_readl_linear(uint32_t addr, void *p); -void chips_69000_writeb_linear(uint32_t addr, uint8_t val, void *p); -void chips_69000_writew_linear(uint32_t addr, uint16_t val, void *p); -void chips_69000_writel_linear(uint32_t addr, uint32_t val, void *p); +uint8_t chips_69000_readb_linear(uint32_t addr, void *priv); +uint16_t chips_69000_readw_linear(uint32_t addr, void *priv); +uint32_t chips_69000_readl_linear(uint32_t addr, void *priv); +void chips_69000_writeb_linear(uint32_t addr, uint8_t val, void *priv); +void chips_69000_writew_linear(uint32_t addr, uint16_t val, void *priv); +void chips_69000_writel_linear(uint32_t addr, uint32_t val, void *priv); /* Multimedia handling. */ uint8_t @@ -1643,9 +1643,9 @@ chips_69000_write_ext_reg(chips_69000_t* chips, uint8_t val) } void -chips_69000_out(uint16_t addr, uint8_t val, void *p) +chips_69000_out(uint16_t addr, uint8_t val, void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; svga_t *svga = &chips->svga; uint8_t old, index; @@ -1750,9 +1750,9 @@ chips_69000_out(uint16_t addr, uint8_t val, void *p) } uint8_t -chips_69000_in(uint16_t addr, void *p) +chips_69000_in(uint16_t addr, void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; svga_t *svga = &chips->svga; uint8_t temp = 0, index; @@ -1828,9 +1828,9 @@ chips_69000_in(uint16_t addr, void *p) } static uint8_t -chips_69000_pci_read(int func, int addr, void *p) +chips_69000_pci_read(UNUSED(int func), int addr, void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; { switch (addr) { @@ -1885,9 +1885,9 @@ chips_69000_pci_read(int func, int addr, void *p) } static void -chips_69000_pci_write(int func, int addr, uint8_t val, void *p) +chips_69000_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; { switch (addr) { @@ -2193,71 +2193,71 @@ chips_69000_writel_mmio(uint32_t addr, uint32_t val, chips_69000_t* chips) } uint8_t -chips_69000_readb_linear(uint32_t addr, void *p) +chips_69000_readb_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x400000) return chips_69000_readb_mmio(addr, chips); - return svga_readb_linear(addr & 0x1FFFFF, p); + return svga_readb_linear(addr & 0x1FFFFF, priv); } uint16_t -chips_69000_readw_linear(uint32_t addr, void *p) +chips_69000_readw_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x800000) { if (addr & 0x400000) return bswap16(chips_69000_readw_mmio(addr, chips)); - return bswap16(svga_readw_linear(addr & 0x1FFFFF, p)); + return bswap16(svga_readw_linear(addr & 0x1FFFFF, priv)); } if (addr & 0x400000) return chips_69000_readw_mmio(addr, chips); - return svga_readw_linear(addr & 0x1FFFFF, p); + return svga_readw_linear(addr & 0x1FFFFF, priv); } uint32_t -chips_69000_readl_linear(uint32_t addr, void *p) +chips_69000_readl_linear(uint32_t addr, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x800000) { if (addr & 0x400000) return bswap32(chips_69000_readl_mmio(addr, chips)); - return bswap32(svga_readl_linear(addr & 0x1FFFFF, p)); + return bswap32(svga_readl_linear(addr & 0x1FFFFF, priv)); } if (addr & 0x400000) return chips_69000_readl_mmio(addr, chips); - return svga_readl_linear(addr & 0x1FFFFF, p); + return svga_readl_linear(addr & 0x1FFFFF, priv); } void -chips_69000_writeb_linear(uint32_t addr, uint8_t val, void *p) +chips_69000_writeb_linear(uint32_t addr, uint8_t val, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x400000) return chips_69000_writeb_mmio(addr, val, chips); - svga_writeb_linear(addr & 0x1FFFFF, val, p); + svga_writeb_linear(addr & 0x1FFFFF, val, priv); } void -chips_69000_writew_linear(uint32_t addr, uint16_t val, void *p) +chips_69000_writew_linear(uint32_t addr, uint16_t val, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x800000) @@ -2266,13 +2266,13 @@ chips_69000_writew_linear(uint32_t addr, uint16_t val, void *p) if (addr & 0x400000) return chips_69000_writew_mmio(addr, val, chips); - svga_writew_linear(addr & 0x1FFFFF, val, p); + svga_writew_linear(addr & 0x1FFFFF, val, priv); } void -chips_69000_writel_linear(uint32_t addr, uint32_t val, void *p) +chips_69000_writel_linear(uint32_t addr, uint32_t val, void *priv) { - svga_t *svga = (svga_t *) p; + svga_t *svga = (svga_t *) priv; chips_69000_t *chips = (chips_69000_t *) svga->priv; if (addr & 0x800000) @@ -2281,7 +2281,7 @@ chips_69000_writel_linear(uint32_t addr, uint32_t val, void *p) if (addr & 0x400000) return chips_69000_writel_mmio(addr, val, chips); - svga_writel_linear(addr & 0x1FFFFF, val, p); + svga_writel_linear(addr & 0x1FFFFF, val, priv); } void @@ -2526,9 +2526,9 @@ chips_69000_available(void) } void -chips_69000_close(void *p) +chips_69000_close(void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; chips->quit = 1; // thread_set_event(chips->fifo_event); @@ -2544,17 +2544,17 @@ chips_69000_close(void *p) } void -chips_69000_speed_changed(void *p) +chips_69000_speed_changed(void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; svga_recalctimings(&chips->svga); } void -chips_69000_force_redraw(void *p) +chips_69000_force_redraw(void *priv) { - chips_69000_t *chips = (chips_69000_t *) p; + chips_69000_t *chips = (chips_69000_t *) priv; chips->svga.fullchange = chips->svga.monitor->mon_changeframecount; } diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index a0d92ef9e..9ee74f512 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -6174,7 +6174,7 @@ mystique_hwcursor_draw(svga_t *svga, int displine) } static uint8_t -mystique_tvp3026_gpio_read(uint8_t cntl, void *priv) +mystique_tvp3026_gpio_read(UNUSED(uint8_t cntl), void *priv) { mystique_t *mystique = (mystique_t *) priv; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 4db2737ca..e68e4c1a0 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1467,7 +1467,7 @@ svga_poll(void *priv) } uint32_t -svga_conv_16to32(struct svga_t *svga, uint16_t color, uint8_t bpp) +svga_conv_16to32(UNUSED(struct svga_t *svga), uint16_t color, uint8_t bpp) { return (bpp == 15) ? video_15to32[color] : video_16to32[color]; } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 859712357..9ff092161 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -50,206 +50,206 @@ static int was_reset = 0; static const VIDEO_CARD video_cards[] = { // clang-format off - { &device_none }, - { &device_internal }, - { &atiega800p_device }, - { &mach8_vga_isa_device, VIDEO_FLAG_TYPE_8514 }, - { &mach32_isa_device, VIDEO_FLAG_TYPE_8514 }, - { &mach64gx_isa_device }, - { &ati28800k_device }, - { &ati18800_vga88_device }, - { &ati28800_device }, - { &compaq_ati28800_device }, - { &ati28800_wonder1024d_xl_plus_device }, + { .device = &device_none, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &device_internal, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &atiega800p_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mach8_vga_isa_device, .flags = VIDEO_FLAG_TYPE_8514 }, + { .device = &mach32_isa_device, .flags = VIDEO_FLAG_TYPE_8514 }, + { .device = &mach64gx_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ati28800k_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ati18800_vga88_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ati28800_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &compaq_ati28800_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ati28800_wonder1024d_xl_plus_device, .flags = VIDEO_FLAG_TYPE_NONE }, #ifdef USE_XL24 - { &ati28800_wonderxl24_device }, + { .device = &ati28800_wonderxl24_device, .flags = VIDEO_FLAG_TYPE_NONE }, #endif /* USE_XL24 */ - { &ati18800_device }, - { &ati18800_wonder_device }, - { &cga_device }, - { &sega_device }, - { &gd5401_isa_device }, - { &gd5402_isa_device }, - { &gd5420_isa_device }, - { &gd5422_isa_device }, - { &gd5426_isa_device }, - { &gd5426_diamond_speedstar_pro_a1_isa_device }, - { &gd5428_boca_isa_device }, - { &gd5428_isa_device }, - { &gd5429_isa_device }, - { &gd5434_isa_device }, - { &gd5434_diamond_speedstar_64_a3_isa_device }, - { &compaq_cga_device }, - { &compaq_cga_2_device }, - { &cpqega_device }, - { &ega_device }, - { &g2_gc205_device }, - { &hercules_device, VIDEO_FLAG_TYPE_MDA }, - { &herculesplus_device, VIDEO_FLAG_TYPE_MDA }, - { &incolor_device }, - { &inmos_isa_device, VIDEO_FLAG_TYPE_XGA }, - { &im1024_device }, - { &iskra_ega_device }, - { &et4000_kasan_isa_device }, - { &mda_device, VIDEO_FLAG_TYPE_MDA }, - { &genius_device }, - { &nga_device }, - { &ogc_device }, - { &oti037c_device }, - { &oti067_device }, - { &oti077_device }, - { ¶dise_pvga1a_device }, - { ¶dise_wd90c11_device }, - { ¶dise_wd90c30_device }, - { &colorplus_device }, - { &pgc_device }, - { &cga_pravetz_device }, - { &radius_svga_multiview_isa_device }, - { &realtek_rtg3105_device }, - { &realtek_rtg3106_device }, - { &s3_diamond_stealth_vram_isa_device }, - { &s3_orchid_86c911_isa_device }, - { &s3_ami_86c924_isa_device }, - { &s3_metheus_86c928_isa_device }, - { &s3_phoenix_86c801_isa_device }, - { &s3_spea_mirage_86c801_isa_device }, - { &sigma_device }, - { &tvga8900b_device }, - { &tvga8900d_device }, - { &tvga8900dr_device }, - { &tvga9000b_device }, - { &nec_sv9000_device }, - { &et4000k_isa_device }, - { &et2000_device }, - { &et3000_isa_device }, - { &et4000_tc6058af_isa_device }, - { &et4000_isa_device }, - { &et4000w32_device }, - { &et4000w32i_isa_device }, - { &vga_device }, - { &v7_vga_1024i_device }, - { &wy700_device }, - { &mach32_mca_device, VIDEO_FLAG_TYPE_8514 }, - { &gd5426_mca_device }, - { &gd5428_mca_device }, - { &et4000_mca_device }, - { &radius_svga_multiview_mca_device }, - { &mach32_pci_device, VIDEO_FLAG_TYPE_8514 }, - { &mach64gx_pci_device }, - { &mach64vt2_device }, - { &bochs_svga_device }, - { &chips_69000_device }, - { &gd5430_pci_device, }, - { &gd5434_pci_device }, - { &gd5436_pci_device, VIDEO_FLAG_TYPE_SPECIAL }, - { &gd5440_pci_device }, - { &gd5446_pci_device, VIDEO_FLAG_TYPE_SPECIAL }, - { &gd5446_stb_pci_device, VIDEO_FLAG_TYPE_SPECIAL }, - { &gd5480_pci_device }, - { &et4000w32p_videomagic_revb_pci_device }, - { &et4000w32p_revc_pci_device }, - { &et4000w32p_cardex_pci_device }, - { &et4000w32p_noncardex_pci_device }, - { &et4000w32p_pci_device }, - { &s3_spea_mercury_lite_86c928_pci_device }, - { &s3_diamond_stealth64_964_pci_device }, - { &s3_elsa_winner2000_pro_x_964_pci_device }, - { &s3_mirocrystal_20sv_964_pci_device }, - { &s3_bahamas64_pci_device }, - { &s3_phoenix_vision864_pci_device }, - { &s3_diamond_stealth_se_pci_device }, - { &s3_phoenix_trio32_pci_device }, - { &s3_diamond_stealth64_pci_device }, - { &s3_9fx_pci_device }, - { &s3_phoenix_trio64_pci_device }, - { &s3_diamond_stealth64_968_pci_device }, - { &s3_elsa_winner2000_pro_x_pci_device }, - { &s3_mirovideo_40sv_ergo_968_pci_device }, - { &s3_9fx_771_pci_device }, - { &s3_phoenix_vision968_pci_device }, - { &s3_spea_mercury_p64v_pci_device }, - { &s3_9fx_531_pci_device }, - { &s3_phoenix_vision868_pci_device }, - { &s3_cardex_trio64vplus_pci_device }, - { &s3_phoenix_trio64vplus_pci_device }, - { &s3_trio64v2_dx_pci_device }, - { &s3_virge_325_pci_device }, - { &s3_diamond_stealth_2000_pci_device }, - { &s3_mirocrystal_3d_pci_device }, - { &s3_diamond_stealth_3000_pci_device }, - { &s3_stb_velocity_3d_pci_device }, - { &s3_virge_375_pci_device }, - { &s3_diamond_stealth_2000pro_pci_device }, - { &s3_virge_385_pci_device }, - { &s3_virge_357_pci_device }, - { &s3_diamond_stealth_4000_pci_device }, - { &s3_trio3d2x_pci_device }, - { &millennium_device }, - { &millennium_ii_device }, - { &mystique_device }, - { &mystique_220_device }, - { &tgui9440_pci_device }, - { &tgui9660_pci_device }, - { &tgui9680_pci_device }, - { &voodoo_banshee_device }, - { &creative_voodoo_banshee_device }, - { &voodoo_3_1000_device }, - { &voodoo_3_2000_device }, - { &voodoo_3_3000_device }, - { &mach32_vlb_device, VIDEO_FLAG_TYPE_8514 }, - { &mach64gx_vlb_device }, - { &et4000w32i_vlb_device }, - { &et4000w32p_videomagic_revb_vlb_device }, - { &et4000w32p_revc_vlb_device }, - { &et4000w32p_cardex_vlb_device }, - { &et4000w32p_vlb_device }, - { &et4000w32p_noncardex_vlb_device }, - { &gd5424_vlb_device }, - { &gd5426_vlb_device }, - { &gd5428_vlb_device }, - { &gd5428_diamond_speedstar_pro_b1_vlb_device }, - { &gd5429_vlb_device }, - { &gd5430_diamond_speedstar_pro_se_a8_vlb_device }, - { &gd5430_vlb_device }, - { &gd5434_vlb_device }, - { &s3_metheus_86c928_vlb_device }, - { &s3_mirocrystal_8s_805_vlb_device }, - { &s3_mirocrystal_10sd_805_vlb_device }, - { &s3_phoenix_86c805_vlb_device }, - { &s3_spea_mirage_86c805_vlb_device }, - { &s3_diamond_stealth64_964_vlb_device }, - { &s3_mirocrystal_20sv_964_vlb_device }, - { &s3_mirocrystal_20sd_864_vlb_device }, - { &s3_bahamas64_vlb_device }, - { &s3_phoenix_vision864_vlb_device }, - { &s3_diamond_stealth_se_vlb_device }, - { &s3_phoenix_trio32_vlb_device }, - { &s3_diamond_stealth64_vlb_device }, - { &s3_9fx_vlb_device }, - { &s3_phoenix_trio64_vlb_device }, - { &s3_spea_mirage_p64_vlb_device }, - { &s3_diamond_stealth64_968_vlb_device }, - { &s3_stb_powergraph_64_video_vlb_device }, - { &ht216_32_standalone_device }, - { &tgui9400cxi_device }, - { &tgui9440_vlb_device }, - { &s3_virge_357_agp_device }, - { &s3_diamond_stealth_4000_agp_device }, - { &s3_trio3d2x_agp_device }, + { .device = &ati18800_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ati18800_wonder_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &cga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &sega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5401_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5402_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5420_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5422_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5426_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5426_diamond_speedstar_pro_a1_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5428_boca_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5428_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5429_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5434_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5434_diamond_speedstar_64_a3_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &compaq_cga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &compaq_cga_2_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &cpqega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &g2_gc205_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &hercules_device, .flags = VIDEO_FLAG_TYPE_MDA }, + { .device = &herculesplus_device, .flags = VIDEO_FLAG_TYPE_MDA }, + { .device = &incolor_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &inmos_isa_device, .flags = VIDEO_FLAG_TYPE_XGA }, + { .device = &im1024_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &iskra_ega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000_kasan_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mda_device, .flags = VIDEO_FLAG_TYPE_MDA }, + { .device = &genius_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ogc_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &oti037c_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &oti067_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &oti077_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = ¶dise_pvga1a_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = ¶dise_wd90c11_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = ¶dise_wd90c30_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &colorplus_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &pgc_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &cga_pravetz_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &radius_svga_multiview_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &realtek_rtg3105_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &realtek_rtg3106_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_vram_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_orchid_86c911_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_ami_86c924_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_metheus_86c928_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_86c801_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_spea_mirage_86c801_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &sigma_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tvga8900b_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tvga8900d_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tvga8900dr_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tvga9000b_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &nec_sv9000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000k_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et2000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et3000_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000_tc6058af_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32i_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &vga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &v7_vga_1024i_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &wy700_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mach32_mca_device, .flags = VIDEO_FLAG_TYPE_8514 }, + { .device = &gd5426_mca_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5428_mca_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000_mca_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &radius_svga_multiview_mca_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mach32_pci_device, .flags = VIDEO_FLAG_TYPE_8514 }, + { .device = &mach64gx_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mach64vt2_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &bochs_svga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &chips_69000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5430_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5434_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5436_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &gd5440_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5446_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &gd5446_stb_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &gd5480_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_videomagic_revb_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_revc_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_noncardex_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_spea_mercury_lite_86c928_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_964_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_elsa_winner2000_pro_x_964_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_20sv_964_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_bahamas64_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_vision864_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_se_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_trio32_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_9fx_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_trio64_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_968_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_elsa_winner2000_pro_x_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirovideo_40sv_ergo_968_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_9fx_771_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_vision968_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_spea_mercury_p64v_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_9fx_531_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_vision868_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_cardex_trio64vplus_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_trio64vplus_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_trio64v2_dx_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_virge_325_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_2000_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_3d_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_3000_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_stb_velocity_3d_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_virge_375_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_2000pro_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_virge_385_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_virge_357_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_4000_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_trio3d2x_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &millennium_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &millennium_ii_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mystique_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mystique_220_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tgui9440_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tgui9660_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tgui9680_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &creative_voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_1000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_2000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mach32_vlb_device, .flags = VIDEO_FLAG_TYPE_8514 }, + { .device = &mach64gx_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32i_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_videomagic_revb_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_revc_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_noncardex_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5424_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5426_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5428_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5428_diamond_speedstar_pro_b1_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5429_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5430_diamond_speedstar_pro_se_a8_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5430_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &gd5434_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_metheus_86c928_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_8s_805_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_10sd_805_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_86c805_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_spea_mirage_86c805_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_964_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_20sv_964_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_mirocrystal_20sd_864_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_bahamas64_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_vision864_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_se_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_trio32_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_9fx_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_phoenix_trio64_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_spea_mirage_p64_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth64_968_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_stb_powergraph_64_video_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ht216_32_standalone_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tgui9400cxi_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &tgui9440_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_virge_357_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_4000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_trio3d2x_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, #ifdef USE_G100 - { &productiva_g100_device, VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &productiva_g100_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, #endif /*USE_G100 */ - { &velocity_100_agp_device }, - { &velocity_200_agp_device }, - { &voodoo_3_1000_agp_device }, - { &voodoo_3_2000_agp_device }, - { &voodoo_3_3000_agp_device }, - { &voodoo_3_3500_agp_ntsc_device }, - { &voodoo_3_3500_agp_pal_device }, - { &compaq_voodoo_3_3500_agp_device }, - { &voodoo_3_3500_se_agp_device }, - { &voodoo_3_3500_si_agp_device }, - { NULL } + { .device = &velocity_100_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &velocity_200_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_1000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_2000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3500_agp_ntsc_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3500_agp_pal_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &compaq_voodoo_3_3500_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3500_se_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3500_si_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = NULL, .flags = VIDEO_FLAG_TYPE_NONE } // clang-format on }; diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index efab288de..e9fbe57f2 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -210,7 +210,7 @@ static void tgui_ext_writel(uint32_t addr, uint32_t val, void *priv); /*Remap address for chain-4/doubleword style layout*/ static __inline uint32_t -dword_remap(svga_t *svga, uint32_t in_addr) +dword_remap(UNUSED(svga_t *svga), uint32_t in_addr) { return ((in_addr << 2) & 0x3fff0) | ((in_addr >> 14) & 0xc) | (in_addr & ~0x3fffc); } diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 93b557fec..ebd92d983 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -480,7 +480,7 @@ banshee_updatemapping(banshee_t *banshee) } uint32_t -banshee_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp) +banshee_conv_16to32(svga_t* svga, uint16_t color, UNUSED(uint8_t bpp)) { banshee_t *banshee = (banshee_t *) svga->priv; uint32_t ret = 0x00000000; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 862dbd1cf..fe72b17c0 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -19,7 +19,7 @@ #include #include #include -#include <86box/bswap.h> +//#include <86box/bswap.h> #include <86box/86box.h> #include <86box/io.h> #include <86box/machine.h> From 47a83d92ea6db0691bb3e74cb8d4e3b858c0f519 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 2 Feb 2025 04:38:06 -0500 Subject: [PATCH 0185/1190] Rename define+device for lotech EMS board --- src/device/isamem.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index 4dc88cc6c..d248e985e 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -102,7 +102,7 @@ #define ISAMEM_BRXT_CARD 13 #define ISAMEM_BRAT_CARD 14 #define ISAMEM_EV165A_CARD 15 -#define ISAMEM_LOTECH_CARD 16 +#define ISAMEM_LOTECH_EMS_CARD 16 #define ISAMEM_DEBUG 0 @@ -578,7 +578,7 @@ isamem_init(const device_t *info) dev->flags |= FLAG_FAST; break; - case ISAMEM_LOTECH_CARD: /* Lotech EMS */ + case ISAMEM_LOTECH_EMS_CARD: /* Lotech EMS */ /* The Lotech EMS cannot have more than 4096KB per board. */ ems_max = EMS_LOTECH_MAXSIZE; fallthrough; @@ -800,7 +800,7 @@ isamem_init(const device_t *info) mem_mapping_disable(&dev->ems[i].mapping); /* Set up an I/O port handler. */ - if (dev->board != ISAMEM_LOTECH_CARD) + if (dev->board != ISAMEM_LOTECH_EMS_CARD) io_sethandler(dev->base_addr[0] + (EMS_PGSIZE * i), 2, ems_in, NULL, NULL, ems_out, NULL, NULL, &(dev->ems[i])); @@ -831,7 +831,7 @@ isamem_init(const device_t *info) } } - if (dev->board == ISAMEM_LOTECH_CARD) + if (dev->board == ISAMEM_LOTECH_EMS_CARD) io_sethandler(dev->base_addr[0], 4, consecutive_ems_in, NULL, NULL, consecutive_ems_out, NULL, NULL, dev); } @@ -1856,11 +1856,11 @@ static const device_config_t lotech_config[] = { // clang-format on }; -static const device_t lotech_device = { +static const device_t lotech_ems_device = { .name = "Lo-tech EMS Board", .internal_name = "lotechems", .flags = DEVICE_ISA, - .local = ISAMEM_LOTECH_CARD, + .local = ISAMEM_LOTECH_EMS_CARD, .init = isamem_init, .close = isamem_close, .reset = NULL, @@ -2071,7 +2071,7 @@ static const struct { #ifdef USE_ISAMEM_IAB { &iab_device }, #endif /* USE_ISAMEM_IAB */ - { &lotech_device }, + { &lotech_ems_device }, { NULL } // clang-format on }; From a3fb32cdc3827ee3d49bcec8ea4ccfe1130a280f Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 2 Feb 2025 04:43:14 -0500 Subject: [PATCH 0186/1190] Rename define+device for Realtek 8019AS PNP --- src/include/86box/net_ne2000.h | 2 +- src/include/86box/network.h | 2 +- src/network/net_ne2000.c | 28 ++++++++++++++-------------- src/network/network.c | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/include/86box/net_ne2000.h b/src/include/86box/net_ne2000.h index cb17ef8b1..ecf2612b5 100644 --- a/src/include/86box/net_ne2000.h +++ b/src/include/86box/net_ne2000.h @@ -44,7 +44,7 @@ enum { NE2K_NE2000_COMPAT = 4, /* 16-bit ISA NE2000-Compatible */ NE2K_NE2000_COMPAT_8BIT = 5, /* 8-bit ISA NE2000-Compatible, like: https://github.com/skiselev/isa8_eth */ NE2K_ETHERNEXT_MC = 6, /* 16-bit MCA EtherNext/MC */ - NE2K_RTL8019AS = 7, /* 16-bit ISA PnP Realtek 8019AS */ + NE2K_RTL8019AS_PNP = 7, /* 16-bit ISA PnP Realtek 8019AS */ NE2K_DE220P = 8, /* 16-bit ISA PnP D-Link DE-220P */ NE2K_RTL8029AS = 9, /* 32-bit PCI Realtek 8029AS */ /* Check nic_init() if adding items after this point. */ diff --git a/src/include/86box/network.h b/src/include/86box/network.h index fa6408790..2140d62dd 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -213,7 +213,7 @@ extern const device_t ne2000_device; extern const device_t ne2000_compat_device; extern const device_t ne2000_compat_8bit_device; extern const device_t ethernext_mc_device; -extern const device_t rtl8019as_device; +extern const device_t rtl8019as_pnp_device; extern const device_t de220p_device; extern const device_t rtl8029as_device; diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 97c2b5de2..2f6c60d51 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -312,7 +312,7 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) static uint32_t page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len)) { - if (dev->board >= NE2K_RTL8019AS) + if (dev->board >= NE2K_RTL8019AS_PNP) switch (off) { case 0x1: /* 9346CR */ return (dev->_9346cr); @@ -327,7 +327,7 @@ page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len)) return (dev->config3 & 0x46); case 0x8: /* CSNSAV */ - return ((dev->board == NE2K_RTL8019AS) ? dev->pnp_csnsav : 0x00); + return ((dev->board == NE2K_RTL8019AS_PNP) ? dev->pnp_csnsav : 0x00); case 0xe: /* 8029ASID0 */ if (dev->board == NE2K_RTL8029AS) @@ -350,7 +350,7 @@ page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len)) static void page3_write(nic_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned len)) { - if (dev->board >= NE2K_RTL8019AS) { + if (dev->board >= NE2K_RTL8019AS_PNP) { nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", dev->name, off, len, val); @@ -919,7 +919,7 @@ nic_init(const device_t *info) dev->name = info->name; dev->board = info->local; - if (dev->board >= NE2K_RTL8019AS) { + if (dev->board >= NE2K_RTL8019AS_PNP) { dev->base_address = 0x340; dev->base_irq = 12; if (dev->board == NE2K_RTL8029AS) { @@ -1042,18 +1042,18 @@ nic_init(const device_t *info) dp8390_mem_alloc(dev->dp8390, 0x4000, 0x8000); break; - case NE2K_RTL8019AS: + case NE2K_RTL8019AS_PNP: case NE2K_RTL8029AS: dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ dev->maclocal[1] = 0xE0; dev->maclocal[2] = 0x4C; - rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; + rom = (dev->board == NE2K_RTL8019AS_PNP) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; if (dev->is_pci) dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC); else dp8390_set_defaults(dev->dp8390, DP8390_FLAG_EVEN_MAC | DP8390_FLAG_CLEAR_IRQ); - dp8390_set_id(dev->dp8390, 0x50, (dev->board == NE2K_RTL8019AS) ? 0x70 : 0x43); + dp8390_set_id(dev->dp8390, 0x50, (dev->board == NE2K_RTL8019AS_PNP) ? 0x70 : 0x43); dp8390_mem_alloc(dev->dp8390, 0x4000, 0x8000); break; @@ -1090,13 +1090,13 @@ nic_init(const device_t *info) * Make this device known to the I/O system. * PnP and PCI devices start with address spaces inactive. */ - if ((dev->board < NE2K_RTL8019AS) && (dev->board != NE2K_ETHERNEXT_MC)) + if ((dev->board < NE2K_RTL8019AS_PNP) && (dev->board != NE2K_ETHERNEXT_MC)) nic_ioset(dev, dev->base_address); /* Set up our BIOS ROM space, if any. */ nic_rom_init(dev, rom); - if (dev->board >= NE2K_RTL8019AS) { + if (dev->board >= NE2K_RTL8019AS_PNP) { if (dev->is_pci) { /* * Configure the PCI space registers. @@ -1144,7 +1144,7 @@ nic_init(const device_t *info) pci_add_card(PCI_ADD_NORMAL, nic_pci_read, nic_pci_write, dev, &dev->pci_slot); } - /* Initialize the RTL8029 EEPROM. */ + /* Initialize the RTL80x9 EEPROM. */ memset(dev->eeprom, 0x00, sizeof(dev->eeprom)); if (dev->board == NE2K_RTL8029AS) { @@ -1158,7 +1158,7 @@ nic_init(const device_t *info) const char *pnp_rom_file = NULL; int pnp_rom_len = 0x4a; switch (dev->board) { - case NE2K_RTL8019AS: + case NE2K_RTL8019AS_PNP: pnp_rom_file = "roms/network/rtl8019as/RTL8019A.BIN"; break; @@ -1182,7 +1182,7 @@ nic_init(const device_t *info) } switch (info->local) { - case NE2K_RTL8019AS: + case NE2K_RTL8019AS_PNP: case NE2K_DE220P: dev->pnp_card = isapnp_add_card(pnp_rom, pnp_rom_len, nic_pnp_config_changed, nic_pnp_csn_changed, @@ -1706,11 +1706,11 @@ const device_t ethernext_mc_device = { .config = mca_mac_config }; -const device_t rtl8019as_device = { +const device_t rtl8019as_pnp_device = { .name = "Realtek RTL8019AS", .internal_name = "ne2kpnp", .flags = DEVICE_ISA | DEVICE_AT, - .local = NE2K_RTL8019AS, + .local = NE2K_RTL8019AS_PNP, .init = nic_init, .close = nic_close, .reset = NULL, diff --git a/src/network/network.c b/src/network/network.c index f4b03ee79..66990e51d 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -96,7 +96,7 @@ static const NETWORK_CARD net_cards[] = { { &ne1000_device }, { &ne2000_device }, { &pcnet_am79c960_eb_device }, - { &rtl8019as_device }, + { &rtl8019as_pnp_device }, { &wd8003e_device }, { &wd8003eb_device }, { &wd8013ebt_device }, From cca1b2b293faaa42b5935db818b71333e1394b7f Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 2 Feb 2025 04:49:32 -0500 Subject: [PATCH 0187/1190] Trivial EMS cleanups and a few comments --- src/device/isamem.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index d248e985e..5cac31c7f 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -27,16 +27,20 @@ * modern boards even have multiple 'copies' of those registers, * which can be switched very fast, to allow for multitasking. * - * TODO: The EV159 is supposed to support 16b EMS transfers, but the + * TODO: The EV-159 is supposed to support 16b EMS transfers, but the * EMM.sys driver for it doesn't seem to want to do that.. * + * EV-125 (It supports backfill) + * https://theretroweb.com/expansioncard/documentation/50250.pdf * + * EV-158 (RAM 10000) + * http://web.archive.org/web/19961104093221/http://www.everex.com/supp/techlib/memmem.html * * Authors: Fred N. van Kempen, * Jasmine Iwanek * * Copyright 2018 Fred N. van Kempen. - * Copyright 2022-2024 Jasmine Iwanek. + * Copyright 2022-2025 Jasmine Iwanek. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -304,16 +308,13 @@ ems_writew(uint32_t addr, uint16_t val, void *priv) static uint8_t ems_in(uint16_t port, void *priv) { - const emsreg_t *dev = (emsreg_t *) priv; - uint8_t ret = 0xff; -#ifdef ENABLE_ISAMEM_LOG - int vpage; -#endif - + const emsreg_t *dev = (emsreg_t *) priv; + uint8_t ret = 0xff; /* Get the viewport page number. */ #ifdef ENABLE_ISAMEM_LOG - vpage = (port / EMS_PGSIZE); + int vpage = (port / EMS_PGSIZE); #endif + port &= (EMS_PGSIZE - 1); switch (port & 0x0001) { @@ -339,13 +340,11 @@ ems_in(uint16_t port, void *priv) static uint8_t consecutive_ems_in(uint16_t port, void *priv) { - const memdev_t *dev = (memdev_t *) priv; - uint8_t ret = 0xff; - int vpage; - + const memdev_t *dev = (memdev_t *) priv; + uint8_t ret = 0xff; /* Get the viewport page number. */ - vpage = (port - dev->base_addr[0]); - + int vpage = (port - dev->base_addr[0]); + ret = dev->ems[vpage].page; if (dev->ems[vpage].enabled) ret |= 0x80; @@ -359,11 +358,10 @@ consecutive_ems_in(uint16_t port, void *priv) static void ems_out(uint16_t port, uint8_t val, void *priv) { - emsreg_t *dev = (emsreg_t *) priv; - int vpage; - + emsreg_t *dev = (emsreg_t *) priv; /* Get the viewport page number. */ - vpage = (port / EMS_PGSIZE); + int vpage = (port / EMS_PGSIZE); + port &= (EMS_PGSIZE - 1); switch (port & 0x0001) { @@ -433,11 +431,9 @@ ems_out(uint16_t port, uint8_t val, void *priv) static void consecutive_ems_out(uint16_t port, uint8_t val, void *priv) { - memdev_t *dev = (memdev_t *) priv; - int vpage; - + memdev_t *dev = (memdev_t *) priv; /* Get the viewport page number. */ - vpage = (port - dev->base_addr[0]); + int vpage = (port - dev->base_addr[0]); isamem_log("ISAMEM: write(%04x, %02x) to page mapping registers! (page=%d)\n", port, val, vpage); @@ -1030,6 +1026,7 @@ static const device_config_t genericxt_config[] = { // clang-format on }; +// This also nicely accounts for the Everex EV-138 static const device_t genericxt_device = { .name = "Generic PC/XT Memory Expansion", .internal_name = "genericxt", @@ -1236,6 +1233,7 @@ static const device_config_t genericat_config[] = { // clang-format on }; +// This also nicely accounts for the Everex EV-135 static const device_t genericat_device = { .name = "Generic PC/AT Memory Expansion", .internal_name = "genericat", From 4b5162feddc25136eabfdadf2ecc58a10f643694 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 2 Feb 2025 05:01:42 -0500 Subject: [PATCH 0188/1190] Fix for building on msys2 clang found by ANightly --- src/qt/win_cdrom_ioctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 271f7226f..38c553852 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include <86box/cdrom.h> #include <86box/log.h> From a540012f9a50a08121fde02b799c6d33d49899b7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 3 Feb 2025 00:46:38 +0100 Subject: [PATCH 0189/1190] XGA: Move a variable initialization to IF blocks, fixes segementation fault when pat_src is 8 (eg. in Windows 95 on the MCA XGA). --- src/video/vid_xga.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index fe72b17c0..fb27b8b2c 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -1504,7 +1504,7 @@ xga_bitblt(svga_t *svga) uint32_t old_dest_dat; uint32_t color_cmp = xga->accel.color_cmp; uint32_t plane_mask = xga->accel.plane_mask; - uint32_t patbase = xga->accel.px_map_base[xga->accel.pat_src]; + uint32_t patbase; uint32_t dstbase = xga->accel.px_map_base[xga->accel.dst_map]; uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; uint32_t patwidth = xga->accel.px_map_width[xga->accel.pat_src]; @@ -1632,6 +1632,8 @@ xga_bitblt(svga_t *svga) } } } else if (xga->accel.pat_src >= 1) { + patbase = xga->accel.px_map_base[xga->accel.pat_src]; + if (patheight == 7) { if (xga->accel.src_map != 1) xga->accel.pattern = 1; @@ -1741,6 +1743,8 @@ xga_bitblt(svga_t *svga) } } } else { + patbase = xga->accel.px_map_base[xga->accel.pat_src]; + while (xga->accel.y >= 0) { mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, patbase, patwidth + 1); From 1ee954ef83f92996408a94c3945594f89947c4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:54:20 +0100 Subject: [PATCH 0190/1190] Update CMakeLists.txt --- src/qt/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index d7ea91f70..a6419ffcb 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -203,7 +203,16 @@ if(WIN32) enable_language(RC) target_sources(86Box PUBLIC 86Box-qt.rc) target_sources(plat PRIVATE win_dynld.c) + if(DINPUT) + target_sources(plat PRIVATE win_joystick.cpp) + target_link_libraries(86Box dinput8) + else() + target_sources(plat PRIVATE win_joystick_rawinput.c) + endif() + target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp) + target_link_libraries(86Box hid d3d9 dwmapi) + # REMOVE THE DINPUT STUFF, IT'S FROM CACO'S DARK MODE BRANCH!!!! # CMake 3.22 messed this up for clang/clang++ # See https://gitlab.kitware.com/cmake/cmake/-/issues/22611 if(MSVC OR (NOT MINGW AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)) From 79e4386daa47fa218441d85850c7082423688982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:55:34 +0100 Subject: [PATCH 0191/1190] Update qt_main.cpp --- src/qt/qt_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 1c917f517..1271b62c1 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -30,6 +30,9 @@ #include #include #include +#include +#include +/* CACO AGAIN */ #include #ifdef QT_STATIC From 0998f03d6f0150abf5bcd56923b97973686cae43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:56:08 +0100 Subject: [PATCH 0192/1190] Update qt_main.cpp --- src/qt/qt_main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 1271b62c1..71bb417fb 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -32,6 +32,7 @@ #include #include #include + /* CACO AGAIN */ #include From 11506e740c095abcfd09bd427ba937f6df43143b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:56:36 +0100 Subject: [PATCH 0193/1190] Update qt_main.cpp --- src/qt/qt_main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 71bb417fb..f7447f953 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -17,6 +17,8 @@ * Copyright 2021-2022 Cacodemon345 * Copyright 2021-2022 Teemu Korhonen */ +/* CACO AGAIN - MOVE TO THE BOTTOM */ +#include #include #include #include @@ -33,9 +35,6 @@ #include #include -/* CACO AGAIN */ -#include - #ifdef QT_STATIC /* Static builds need plugin imports */ # include From 8eee344adbf7f3af3366cabefc41055b0ab67338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:58:00 +0100 Subject: [PATCH 0194/1190] Update qt_main.cpp --- src/qt/qt_main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index b302b9cca..72b0eef53 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -17,8 +17,6 @@ * Copyright 2021-2022 Cacodemon345 * Copyright 2021-2022 Teemu Korhonen */ -/* CACO AGAIN - MOVE TO THE BOTTOM */ -#include #include #include #include @@ -32,6 +30,7 @@ #include #include #include +#include #include #include From af6d8819a519e5501dae2f7cb2e20947139e9db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 3 Feb 2025 02:58:53 +0100 Subject: [PATCH 0195/1190] Update CMakeLists.txt --- src/qt/CMakeLists.txt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 8f1fb39dd..c08a03016 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -204,16 +204,8 @@ if(WIN32) enable_language(RC) target_sources(86Box PUBLIC 86Box-qt.rc) target_sources(plat PRIVATE win_dynld.c) - if(DINPUT) - target_sources(plat PRIVATE win_joystick.cpp) - target_link_libraries(86Box dinput8) - else() - target_sources(plat PRIVATE win_joystick_rawinput.c) - endif() - target_sources(ui PRIVATE qt_d3d9renderer.hpp qt_d3d9renderer.cpp) - target_link_libraries(86Box hid d3d9 dwmapi) + target_link_libraries(86Box dwmapi) - # REMOVE THE DINPUT STUFF, IT'S FROM CACO'S DARK MODE BRANCH!!!! # CMake 3.22 messed this up for clang/clang++ # See https://gitlab.kitware.com/cmake/cmake/-/issues/22611 if(MSVC OR (NOT MINGW AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)) From 2d65663ff67857ffe6138f89a70f1babbf98d7e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 3 Feb 2025 03:08:01 +0100 Subject: [PATCH 0196/1190] Fix a warning. --- src/qt/qt_winrawinputfilter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index a44f203e6..24baa257f 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -172,7 +172,9 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess } return true; - } else if (msg && msg->message == WM_SETTINGCHANGE && msg->lParam != NULL && wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0) { + } else if ((msg != nullptr) && (msg->message == WM_SETTINGCHANGE) && + (((void *) msg->lParam) != nullptr) && + (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); From 35a12e08262835b9a587c2f161961ed8ec1f1b17 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 3 Feb 2025 10:57:19 +0100 Subject: [PATCH 0197/1190] CD-ROM: IOCTL now detects medium changes without having to read the host drive's TOC on every operation, improves performance. --- src/cdrom/cdrom.c | 56 +++++++--- src/cdrom/cdrom_image.c | 3 +- src/include/86box/cdrom.h | 6 +- src/include/86box/scsi_device.h | 2 +- src/qt/dummy_cdrom_ioctl.c | 27 ++++- src/qt/qt_winrawinputfilter.cpp | 187 ++++++++++++++++++++++---------- src/qt/win_cdrom_ioctl.c | 164 ++++++++++++++++------------ src/scsi/scsi_cdrom.c | 60 +++++----- src/unix/dummy_cdrom_ioctl.c | 27 ++++- 9 files changed, 340 insertions(+), 192 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 4ccb81442..2cdcc5a22 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2641,18 +2641,6 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) return ret; } -int -cdrom_ext_medium_changed(const cdrom_t *dev) -{ - int ret = 0; - - if (dev && dev->ops && dev->ops->ext_medium_changed && - (dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED)) - ret = dev->ops->ext_medium_changed(dev->local); - - return ret; -} - int cdrom_is_empty(const uint8_t id) { @@ -2700,6 +2688,44 @@ cdrom_toc_dump(cdrom_t *dev) } #endif +void +cdrom_set_empty(cdrom_t *dev) +{ + dev->cd_status = CD_STATUS_EMPTY; +} + +void +cdrom_update_status(cdrom_t *dev) +{ + const int was_empty = (dev->cd_status == CD_STATUS_EMPTY); + + if (dev->ops->load != NULL) + dev->ops->load(dev->local); + + /* All good, reset state. */ + dev->seek_pos = 0; + dev->cd_buflen = 0; + + if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) + dev->cd_status = CD_STATUS_EMPTY; + else if (dev->ops->is_dvd(dev->local)) + dev->cd_status = CD_STATUS_DVD; + else + dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : + CD_STATUS_DATA_ONLY; + + dev->cdrom_capacity = dev->ops->get_last_block(dev->local); + + if (dev->cd_status != CD_STATUS_EMPTY) { + /* Signal media change to the emulated machine. */ + cdrom_insert(dev->id); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + cdrom_insert(dev->id); + } +} + int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) { @@ -2728,10 +2754,12 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) dev->seek_pos = 0; dev->cd_buflen = 0; + if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) + dev->cd_status = CD_STATUS_EMPTY; if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else - dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : + dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : CD_STATUS_DATA_ONLY; dev->cdrom_capacity = dev->ops->get_last_block(dev->local); @@ -2744,7 +2772,7 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) cdrom_toc_dump(dev); #endif - if (!skip_insert) { + if (!skip_insert && (dev->cd_status != CD_STATUS_EMPTY)) { /* Signal media change to the emulated machine. */ cdrom_insert(dev->id); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index afc70bda7..271a290cb 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -1992,7 +1992,8 @@ static const cdrom_ops_t image_ops = { image_is_dvd, image_has_audio, NULL, - image_close + image_close, + NULL }; /* Public functions. */ diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 82d211896..7c028d7d6 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -271,8 +271,9 @@ typedef struct cdrom_ops_t { uint32_t *info); int (*is_dvd)(const void *local); int (*has_audio)(const void *local); - int (*ext_medium_changed)(void *local); + int (*is_empty)(const void *local); void (*close)(void *local); + void (*load)(const void *local); } cdrom_ops_t; typedef struct cdrom { @@ -423,7 +424,8 @@ extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_ uint8_t *buffer, uint32_t *info); extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); extern int cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); -extern int cdrom_ext_medium_changed(const cdrom_t *dev); +extern void cdrom_set_empty(cdrom_t *dev); +extern void cdrom_update_status(cdrom_t *dev); extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); extern void cdrom_global_init(void); diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 84abee066..ffe042481 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -219,7 +219,7 @@ #define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 #define ASC_WRITE_PROTECTED 0x27 #define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_CAPACITY_DATA_CHANGED 0x2a #define ASC_INCOMPATIBLE_FORMAT 0x30 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_DATA_PHASE_ERROR 0x4b diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index 9efd67ad6..bddfabb5b 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -40,7 +40,6 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; - int toc_valid; void *handle; char path[256]; } ioctl_t; @@ -77,8 +76,6 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; } /* Shared functions. */ @@ -159,6 +156,12 @@ ioctl_has_audio(UNUSED(const void *local)) return 0; } +static int +ioctl_is_empty(const void *local) +{ + return 1; +} + static int ioctl_ext_medium_changed(UNUSED(void *local)) { @@ -186,6 +189,18 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -196,8 +211,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -218,7 +234,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; } diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 24baa257f..13e0ec9a7 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -51,7 +51,10 @@ #include <86box/mouse.h> #include <86box/plat.h> #include <86box/86box.h> +#include <86box/cdrom.h> #include <86box/video.h> +#include +#include extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); @@ -151,72 +154,142 @@ WindowsRawInputFilter::~WindowsRawInputFilter() RegisterRawInputDevices(rid, 2, sizeof(rid[0])); } +static void +notify_drives(ULONG unitmask, int empty) +{ + char p[1024] = { 0 }; + + for (int i = 0; i < 26; ++i) { + if (unitmask & 0x1) { + cdrom_t *dev = NULL; + + sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); + + for (int i = 0; i < CDROM_NUM; i++) + if (!stricmp(cdrom[i].image_path, p)) { + dev = &(cdrom[i]); + if (empty) + cdrom_set_empty(dev); + else + cdrom_update_status(dev); + // pclog("CD-ROM %i : Drive notified of media %s\n", + // dev->id, empty ? "removal" : "change"); + } + } + + unitmask = unitmask >> 1; + } +} + +static void +device_change(WPARAM wParam, LPARAM lParam) +{ + PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lParam; + + switch(wParam) { + case DBT_DEVICEARRIVAL: + case DBT_DEVICEREMOVECOMPLETE: + /* Check whether a CD or DVD was inserted into a drive. */ + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) { + PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lpdb; + + if (lpdbv->dbcv_flags & DBTF_MEDIA) + notify_drives(lpdbv->dbcv_unitmask, + (wParam == DBT_DEVICEREMOVECOMPLETE)); + } + break; + + default: + /* + Process other WM_DEVICECHANGE notifications for other + devices or reasons. + */ + break; + } +} + bool WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *message, result_t *result) { if (eventType == "windows_generic_MSG") { MSG *msg = static_cast(message); - if (msg->message == WM_INPUT) { - - if (window->isActiveWindow() && menus_open == 0) - handle_input((HRAWINPUT) msg->lParam); - else - { - for (auto &w : window->renderers) { - if (w && w->isActiveWindow()) { - handle_input((HRAWINPUT) msg->lParam); - break; + if (msg != nullptr) switch(msg->message) { + case WM_INPUT: + if (window->isActiveWindow() && (menus_open == 0)) + handle_input((HRAWINPUT) msg->lParam); + else { + for (auto &w : window->renderers) { + if (w && w->isActiveWindow()) { + handle_input((HRAWINPUT) msg->lParam); + break; + } } } - } - - return true; - } else if ((msg != nullptr) && (msg->message == WM_SETTINGCHANGE) && - (((void *) msg->lParam) != nullptr) && - (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { - if (!windows_is_light_theme()) { - QFile f(":qdarkstyle/dark/darkstyle.qss"); - - if (!f.exists()) { - printf("Unable to set stylesheet, file not found\n"); - } else { - f.open(QFile::ReadOnly | QFile::Text); - QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); - } - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = TRUE; - DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); - window->ui->stackedWidget->switchRenderer((RendererStack::Renderer) vid_api); - for (int i = 1; i < MONITORS_NUM; i++) { - if (window->renderers[i] && !window->renderers[i]->isHidden()) - window->renderers[i]->switchRenderer((RendererStack::Renderer) vid_api); - } - }); - } else { - qApp->setStyleSheet(""); - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = FALSE; - DwmSetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&DarkMode, sizeof(DarkMode)); - }); - } - - QTimer::singleShot(1000, [this] () { - window->resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); - for (int i = 1; i < MONITORS_NUM; i++) { - if (window->renderers[i] && !window->renderers[i]->isHidden()) { - window->resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); - } - } - }); - } - - /* Stop processing of Alt-F4 */ - if (msg->message == WM_SYSKEYDOWN) { - if (msg->wParam == 0x73) { return true; - } + case WM_SETTINGCHANGE: + if ((((void *) msg->lParam) != nullptr) && + (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { + + if (!windows_is_light_theme()) { + QFile f(":qdarkstyle/dark/darkstyle.qss"); + + if (!f.exists()) + printf("Unable to set stylesheet, file not found\n"); + else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = TRUE; + auto vid_stack = (RendererStack::Renderer) vid_api; + DwmSetWindowAttribute((HWND) window->winId(), + DWMWA_USE_IMMERSIVE_DARK_MODE, + (LPCVOID) &DarkMode, + sizeof(DarkMode)); + window->ui->stackedWidget->switchRenderer(vid_stack); + for (int i = 1; i < MONITORS_NUM; i++) { + if ((window->renderers[i] != nullptr) && + !window->renderers[i]->isHidden()) + window->renderers[i]->switchRenderer(vid_stack); + } + }); + } else { + qApp->setStyleSheet(""); + QTimer::singleShot(1000, [this] () { + BOOL DarkMode = FALSE; + DwmSetWindowAttribute((HWND) window->winId(), + DWMWA_USE_IMMERSIVE_DARK_MODE, + (LPCVOID) &DarkMode, + sizeof(DarkMode)); + }); + } + + QTimer::singleShot(1000, [this] () { + window->resizeContents(monitors[0].mon_scrnsz_x, + monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { + auto mon = &(monitors[i]); + + if ((window->renderers[i] != nullptr) && + !window->renderers[i]->isHidden()) + window->resizeContentsMonitor(mon->mon_scrnsz_x, + mon->mon_scrnsz_y, + i); + } + }); + } + break; + case WM_SYSKEYDOWN: + /* Stop processing of Alt-F4 */ + if (msg->wParam == 0x73) + return true; + break; + case WM_DEVICECHANGE: + if (msg->hwnd == (HWND) window->winId()) + device_change(msg->wParam, msg->lParam); + break; } } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 38c553852..621cf0b76 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -32,9 +32,11 @@ #include #include #include +#include <86box/86box.h> #include <86box/cdrom.h> #include <86box/log.h> #include <86box/plat_cdrom_ioctl.h> +#include <86box/scsi_device.h> typedef struct ioctl_t { cdrom_t *dev; @@ -42,7 +44,6 @@ typedef struct ioctl_t { int is_dvd; int has_audio; int32_t tracks_num; - int toc_valid; uint8_t cur_toc[65536]; CDROM_READ_TOC_EX cur_read_toc_ex; int blocks_num; @@ -51,9 +52,8 @@ typedef struct ioctl_t { WCHAR path[256]; } ioctl_t; -static void ioctl_read_toc(ioctl_t *ioctl); -static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format, - uint8_t *buffer, uint32_t *info); +static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format, + uint8_t *buffer, uint32_t *info); #ifdef ENABLE_IOCTL_LOG int ioctl_do_log = ENABLE_IOCTL_LOG; @@ -94,25 +94,6 @@ ioctl_open_handle(ioctl_t *ioctl) return (ioctl->handle != INVALID_HANDLE_VALUE); } -static int -ioctl_load(ioctl_t *ioctl) -{ - int ret = 0; - - if (ioctl_open_handle(ioctl)) { - long size; - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, - NULL, 0, NULL, 0, - (LPDWORD) &size, NULL); - ret = 1; - ioctl_close_handle(ioctl); - - ioctl_read_toc(ioctl); - } - - return ret; -} - static int ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) { @@ -266,11 +247,8 @@ ioctl_read_raw_toc(ioctl_t *ioctl) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) { - ioctl->toc_valid = 1; - (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); - ioctl_read_raw_toc(ioctl); - } + (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); + ioctl_read_raw_toc(ioctl); } static int @@ -301,8 +279,6 @@ ioctl_is_track_audio(const ioctl_t *ioctl, const uint32_t pos) const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; int ret = 0; - ioctl_read_toc((ioctl_t *) ioctl); - if (ioctl->has_audio && !ioctl->is_dvd) { const int track = ioctl_get_track(ioctl, pos); const int control = rti[track].adr_ctl; @@ -324,8 +300,6 @@ ioctl_get_track_info(const void *local, const uint32_t track, const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; int ret = 1; - ioctl_read_toc((ioctl_t *) ioctl); - if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track); ret = 0; @@ -363,8 +337,6 @@ ioctl_is_track_pre(const void *local, const uint32_t sector) const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; int ret = 0; - ioctl_read_toc((ioctl_t *) ioctl); - if (ioctl->has_audio && !ioctl->is_dvd) { const int track = ioctl_get_track(ioctl, sector); const int control = rti[track].adr_ctl; @@ -572,8 +544,6 @@ ioctl_get_last_block(const void *local) const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; uint32_t lb = 0; - ioctl_read_toc((ioctl_t *) ioctl); - for (int c = 0; c <= toc->LastTrack; c++) { const TRACK_DATA *td = &toc->TrackData[c]; const uint32_t address = MSFtoLBA(td->Address[1], td->Address[2], @@ -688,44 +658,80 @@ ioctl_has_audio(const void *local) } static int -ioctl_ext_medium_changed(void *local) +ioctl_is_empty(const void *local) { - ioctl_t * ioctl = (ioctl_t *) local; - const CDROM_TOC *toc = (CDROM_TOC *) ioctl->cur_toc; - const TRACK_DATA *ltd = &toc->TrackData[toc->LastTrack]; - const uint32_t old_addr = *(uint32_t *) ltd->Address; - const int temp = ioctl_read_normal_toc(ioctl, ioctl->cur_toc); - int ret = 0; + typedef struct SCSI_PASS_THROUGH_DIRECT_BUF { + SCSI_PASS_THROUGH_DIRECT spt; + ULONG Filler; + UCHAR SenseBuf[64]; + } SCSI_PASS_THROUGH_DIRECT_BUF; - if (temp == 1) { - if (ioctl->toc_valid && ((*(uint32_t *) ltd->Address) != old_addr)) { - /* The TOC has changed. */ - ioctl->toc_valid = 0; - ret = 1; - } + const ioctl_t * ioctl = (const ioctl_t *) local; + unsigned long int unused = 0; + SCSI_PASS_THROUGH_DIRECT_BUF req; - if (!ioctl->toc_valid) { - ioctl->toc_valid = 1; - ioctl_read_raw_toc(ioctl); - } - } else { - /* There has been some kind of error - not a medium change, but a not ready - condition. */ - ret = -1; - } + ioctl_open_handle((ioctl_t *) ioctl); - if (ret == 1) { - if (ioctl->is_dvd) - ioctl->dev->cd_status = CD_STATUS_DVD; - else - ioctl->dev->cd_status = ioctl->has_audio ? CD_STATUS_STOPPED : - CD_STATUS_DATA_ONLY; + memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); + req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); + req.spt.PathId = 0; + req.spt.TargetId = 1; + req.spt.Lun = 0; + req.spt.CdbLength = 12; + req.spt.DataIn = SCSI_IOCTL_DATA_IN; + req.spt.SenseInfoLength = sizeof(req.SenseBuf); + req.spt.DataTransferLength = 0; + req.spt.TimeOutValue = 6; + req.spt.DataBuffer = NULL; + req.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_BUF, SenseBuf); - ioctl->dev->cdrom_capacity = ioctl_get_last_block(ioctl); - } else if (ret == -1) - ioctl->dev->cd_status = CD_STATUS_EMPTY; + /* Fill in the CDB. */ + req.spt.Cdb[0] = 0x00; + req.spt.Cdb[1] = 0x00; + req.spt.Cdb[2] = 0x00; + req.spt.Cdb[3] = 0x00; + req.spt.Cdb[4] = 0x00; + req.spt.Cdb[5] = 0x00; + req.spt.Cdb[6] = 0x00; + req.spt.Cdb[7] = 0x00; + req.spt.Cdb[8] = 0x00; + req.spt.Cdb[9] = 0x00; + req.spt.Cdb[10] = 0x00; + req.spt.Cdb[11] = 0x00; - ioctl_log(ioctl->log, "ioctl_ext_medium_changed(): %i\n", ret); + DWORD length = sizeof(SCSI_PASS_THROUGH_DIRECT_BUF); + +#ifdef ENABLE_IOCTL_LOG + uint8_t *cdb = (uint8_t *) req.spt.Cdb; + ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X " + "%02X %02X %02X %02X %02X %02X\n", + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], + cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]); +#endif + + int ret = DeviceIoControl(ioctl->handle, IOCTL_SCSI_PASS_THROUGH_DIRECT, + &req, length, + &req, length, + &unused, NULL); + + ioctl_log(ioctl->log, "ioctl_read_dvd_structure(): ret = %d, " + "req.spt.DataTransferLength = %lu\n", + ret, req.spt.DataTransferLength); + ioctl_log(ioctl->log, "Sense: %08X, %08X\n", req.spt.SenseInfoLength, + req.spt.SenseInfoOffset); + + if (req.spt.SenseInfoLength >= 16) { + uint8_t *sb = (uint8_t *) req.SenseBuf; + /* Return sense to the host as is. */ + ret = ((sb[2] == SENSE_NOT_READY) && (sb[12] == ASC_MEDIUM_NOT_PRESENT)); + ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[0], sb[1], sb[ 2], sb[ 3], sb[ 4], sb[ 5], sb[ 6], sb[ 7]); + ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n", + sb[8], sb[9], sb[10], sb[11], sb[12], sb[13], sb[14], sb[15]); + } else + ret = 0; + + ioctl_close_handle((ioctl_t *) ioctl); return ret; } @@ -744,6 +750,22 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + long size; + DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, + NULL, 0, NULL, 0, + (LPDWORD) &size, NULL); + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -754,8 +776,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -776,7 +799,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index ff49aef90..04c6532df 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -678,8 +678,13 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; scsi_cdrom_set_callback(dev); return; + case 0x43: + dev->drv->seek_diff = dev->drv->seek_pos + 150; + dev->drv->seek_pos = 0; + fallthrough; case 0x08: case 0x28: + case 0x42: case 0x44: case 0xa8: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); @@ -693,7 +698,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; fallthrough; case 0x25: - case 0x42 ... 0x44: + // case 0x42 ... 0x44: case 0x51 ... 0x52: case 0xad: case 0xb8 ... 0xb9: @@ -702,6 +707,11 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += 40.0; /* Account for seek time. */ /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ + /* + TODO: This is a bit of a lie - the actual period is closer to + 75 * 2448 bytes per second, because the subchannel data + has to be read as well. + */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; @@ -730,7 +740,19 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - period = period * (double) (dev->packet_len); + switch (cmd) { + default: + period = period * (double) (dev->packet_len); + break; + case 0x42: case 0x44: + /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ + period = period * 2352.0; + break; + case 0x43: + /* READ TOC - period of 175 entire frames. */ + period = period * 150.0 * 2352.0; + break; + } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); dev->callback += period; @@ -1181,25 +1203,6 @@ scsi_cdrom_insert(void *priv) } } -static void -scsi_cdrom_ext_insert(void *priv, int ext_medium_changed) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; - - if ((dev == NULL) || (dev->drv == NULL)) - return; - - if ((dev->drv->ops == NULL) || (ext_medium_changed == -1)) { - dev->unit_attention = 0; - dev->drv->cd_status = CD_STATUS_EMPTY; - scsi_cdrom_log(dev->log, "External media removal\n"); - } else if (ext_medium_changed == 1) { - dev->unit_attention = 0; - dev->drv->cd_status |= CD_STATUS_TRANSITION; - scsi_cdrom_log(dev->log, "External media transition\n"); - } -} - static int scsi_command_check_ready(const scsi_cdrom_t *dev, const uint8_t *cdb) { @@ -1223,7 +1226,6 @@ static int scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) { int ready; - const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) { @@ -1257,9 +1259,6 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) return 0; } - if (ext_medium_changed != 0) - scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); - if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { ready = 1; @@ -1270,13 +1269,10 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, const uint8_t *cdb) if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) ready = 0; else { - if ((ext_medium_changed != 0) || - !(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - scsi_cdrom_log(dev->log, "(ext_medium_changed != 0): scsi_cdrom_insert()\n"); + if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) scsi_cdrom_insert((void *) dev); - } - ready = (dev->drv->cd_status != CD_STATUS_EMPTY) || (ext_medium_changed == -1); + ready = (dev->drv->cd_status != CD_STATUS_EMPTY); } } else ready = (dev->drv->cd_status != CD_STATUS_EMPTY); @@ -1469,10 +1465,6 @@ void scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - const int ext_medium_changed = cdrom_ext_medium_changed(dev->drv); - - if (ext_medium_changed != 0) - scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { /* diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index 9efd67ad6..bddfabb5b 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -40,7 +40,6 @@ typedef struct ioctl_t { cdrom_t *dev; void *log; - int toc_valid; void *handle; char path[256]; } ioctl_t; @@ -77,8 +76,6 @@ ioctl_open_handle(UNUSED(ioctl_t *ioctl)) static void ioctl_read_toc(ioctl_t *ioctl) { - if (!ioctl->toc_valid) - ioctl->toc_valid = 1; } /* Shared functions. */ @@ -159,6 +156,12 @@ ioctl_has_audio(UNUSED(const void *local)) return 0; } +static int +ioctl_is_empty(const void *local) +{ + return 1; +} + static int ioctl_ext_medium_changed(UNUSED(void *local)) { @@ -186,6 +189,18 @@ ioctl_close(void *local) ioctl->log = NULL; } +static void +ioctl_load(const void *local) +{ + const ioctl_t *ioctl = (const ioctl_t *) local; + + if (ioctl_open_handle((ioctl_t *) ioctl)) { + ioctl_close_handle((ioctl_t *) ioctl); + + ioctl_read_toc((ioctl_t *) ioctl); + } +} + static const cdrom_ops_t ioctl_ops = { ioctl_get_track_info, ioctl_get_raw_track_info, @@ -196,8 +211,9 @@ static const cdrom_ops_t ioctl_ops = { ioctl_read_dvd_structure, ioctl_is_dvd, ioctl_has_audio, - ioctl_ext_medium_changed, - ioctl_close + ioctl_is_empty, + ioctl_close, + ioctl_load }; /* Public functions. */ @@ -218,7 +234,6 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_log(ioctl->log, "Path is %s\n", ioctl->path); ioctl->dev = dev; - ioctl->toc_valid = 0; dev->ops = &ioctl_ops; } From 6614a83b340527263aa9e8312b61d41cb71626d9 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 4 Feb 2025 20:28:24 +0900 Subject: [PATCH 0198/1190] correct font read address in PS/55 video mode 03 --- src/video/vid_ps55da2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index d75d0aa03..f3b7c7834 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1830,7 +1830,7 @@ static void da2_render_textm3(da2_t* da2) else { // the char code is SBCS (ANK) uint32_t fontbase; - fontbase = DA2_FONTROM_BASESBCS; + fontbase = DA2_GAIJIRAM_SBCS; uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font font <<= 8; font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font From 9aad8dbf9c6bffc313a7da8acdec297f1c58f140 Mon Sep 17 00:00:00 2001 From: The Dax Date: Wed, 5 Feb 2025 17:12:40 -0500 Subject: [PATCH 0199/1190] Add basic support for the Quantum3D Raven. AGP was worked on but found to be unstable (freezing on the first frame whenever entering Direct3D fullscreen), so it was removed. --- src/include/86box/video.h | 1 + src/video/vid_table.c | 1 + src/video/vid_voodoo_banshee.c | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 9ee710592..336d656cc 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -575,6 +575,7 @@ extern const device_t ps1vga_mca_device; extern const device_t voodoo_device; extern const device_t voodoo_banshee_device; extern const device_t creative_voodoo_banshee_device; +extern const device_t quantum3d_raven_device; extern const device_t voodoo_3_1000_device; extern const device_t voodoo_3_1000_agp_device; extern const device_t voodoo_3_2000_device; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 9ff092161..756515734 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -193,6 +193,7 @@ video_cards[] = { { .device = &tgui9680_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &creative_voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &quantum3d_raven_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_1000_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_2000_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3000_device, .flags = VIDEO_FLAG_TYPE_NONE }, diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index ebd92d983..36bda6cbe 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -49,6 +49,7 @@ #define ROM_BANSHEE "roms/video/voodoo/Pci_sg.rom" #define ROM_CREATIVE_BANSHEE "roms/video/voodoo/BlasterPCI.rom" +#define ROM_QUANTUM3D_RAVEN "roms/video/voodoo/RVPD0224.rom" #define ROM_VOODOO3_1000 "roms/video/voodoo/1k11sg.rom" #define ROM_VOODOO3_2000 "roms/video/voodoo/2k11sd.rom" #define ROM_VOODOO3_3000 "roms/video/voodoo/3k12sd.rom" @@ -75,6 +76,7 @@ static uint8_t vb_filter_bx_g[256][256]; enum { TYPE_BANSHEE = 0, + TYPE_QUANTUM3D_RAVEN, TYPE_V3_1000, TYPE_V3_2000, TYPE_V3_3000, @@ -3463,6 +3465,16 @@ banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int } break; + case TYPE_QUANTUM3D_RAVEN: + /* This case basically exists only to set the subsystem ID correctly for SF: Rush, a vendor-locked game. */ + /* We set the type back to TYPE_BANSHEE so the card behaves as a regular Banshee (no 3D glasses emulation). */ + banshee->pci_regs[0x2c] = 0x9c; + banshee->pci_regs[0x2d] = 0x13; + banshee->pci_regs[0x2e] = banshee->agp ? 0x16 : 0x17; + banshee->pci_regs[0x2f] = 0x00; + banshee->type = TYPE_BANSHEE; + break; + case TYPE_V3_1000: banshee->pci_regs[0x2c] = 0x1a; banshee->pci_regs[0x2d] = 0x12; @@ -3540,6 +3552,12 @@ creative_banshee_init(const device_t *info) return banshee_init_common(info, ROM_CREATIVE_BANSHEE, 0, TYPE_BANSHEE, VOODOO_BANSHEE, 0); } +static void * +quantum3d_raven_init(const device_t *info) +{ + return banshee_init_common(info, ROM_QUANTUM3D_RAVEN, 0, TYPE_QUANTUM3D_RAVEN, VOODOO_BANSHEE, 0); +} + static void * v3_1000_init(const device_t *info) { @@ -3636,6 +3654,12 @@ creative_banshee_available(void) return rom_present(ROM_CREATIVE_BANSHEE); } +static int +quantum3d_raven_available(void) +{ + return rom_present(ROM_QUANTUM3D_RAVEN); +} + static int v3_1000_available(void) { @@ -3757,6 +3781,20 @@ const device_t creative_voodoo_banshee_device = { .config = banshee_sdram_config }; +const device_t quantum3d_raven_device = { + .name = "Quantum3D Raven", + .internal_name = "q3d_raven_pci", + .flags = DEVICE_PCI, + .local = 0, + .init = quantum3d_raven_init, + .close = banshee_close, + .reset = NULL, + .available = quantum3d_raven_available, + .speed_changed = banshee_speed_changed, + .force_redraw = banshee_force_redraw, + .config = banshee_sdram_config +}; + const device_t voodoo_3_1000_device = { .name = "3dfx Voodoo3 1000", .internal_name = "voodoo3_1k_pci", From f12b975ebacd8e33cf0c5c29f1e0e984abbb028b Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:15:18 +0900 Subject: [PATCH 0200/1190] Added support for PS/55 DA Simplified Chinese font Changed a file path for the PS/55 DA Japanese font ROM. --- src/qt/qt_settingsdisplay.cpp | 13 +++++++ src/qt/qt_settingsdisplay.hpp | 2 + src/qt/qt_settingsdisplay.ui | 9 ++++- src/video/vid_ps55da2.c | 73 ++++++++++++++++++++++++++++------- 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index 42617c4be..f6be74cf2 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -139,6 +139,12 @@ SettingsDisplay::on_pushButtonConfigureXga_clicked() } } +void +SettingsDisplay::on_pushButtonConfigureDa2_clicked() +{ + DeviceConfig::ConfigureDevice(&ps55da2_device, 0, qobject_cast(Settings::settings)); +} + void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) { @@ -176,6 +182,7 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) ui->checkBoxDa2->setChecked(da2_standalone_enabled && machineSupportsDa2); ui->pushButtonConfigureXga->setEnabled(ui->checkBoxXga->isEnabled() && ui->checkBoxXga->isChecked()); + ui->pushButtonConfigureDa2->setEnabled(ui->checkBoxDa2->isEnabled() && ui->checkBoxDa2->isChecked()); int c = 2; @@ -250,6 +257,12 @@ SettingsDisplay::on_checkBoxXga_stateChanged(int state) ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked); } +void +SettingsDisplay::on_checkBoxDa2_stateChanged(int state) +{ + ui->pushButtonConfigureDa2->setEnabled(state == Qt::Checked); +} + void SettingsDisplay::on_comboBoxVideoSecondary_currentIndexChanged(int index) { diff --git a/src/qt/qt_settingsdisplay.hpp b/src/qt/qt_settingsdisplay.hpp index 6297f7eae..f2edb0c8a 100644 --- a/src/qt/qt_settingsdisplay.hpp +++ b/src/qt/qt_settingsdisplay.hpp @@ -30,9 +30,11 @@ private slots: private slots: void on_checkBoxVoodoo_stateChanged(int state); void on_checkBoxXga_stateChanged(int state); + void on_checkBoxDa2_stateChanged(int state); void on_comboBoxVideo_currentIndexChanged(int index); void on_pushButtonConfigureVoodoo_clicked(); void on_pushButtonConfigureXga_clicked(); + void on_pushButtonConfigureDa2_clicked(); void on_pushButtonConfigure_clicked(); private: diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui index e3e081848..8be84a17f 100644 --- a/src/qt/qt_settingsdisplay.ui +++ b/src/qt/qt_settingsdisplay.ui @@ -113,13 +113,20 @@ - + IBM PS/55 Display Adapter Graphics + + + + Configure + + + diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index f3b7c7834..a6d55c76a 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -37,8 +37,9 @@ #include <86box/vid_svga_render.h> #include "cpu.h" -#define DA2_FONTROM_PATH "roms/video/da2/PS55FNTJ.BIN" -#define DA2_FONTROM_SIZE 1024*1024 +#define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" +#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" +#define DA2_FONTROM_SIZE 1536*1024 #define DA2_FONTROM_BASESBCS 0x98000 #define DA2_GAIJIRAM_SBCS 0x34000 #define DA2_GAIJIRAM_SBEX 0x3c000 @@ -54,6 +55,10 @@ #define DA2_DEBUG_BLTLOG_MAX 256*1024 #define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe #define DA2_DEBUG_BLT_USEDRESET 0xfefefe +#define DA2_DCONFIG_FONT_JPAN 0 /* for Code page 932 Japanese */ +//#define DA2_DCONFIG_FONT_HANG 1 /* for Code page 934 Hangul */ +//#define DA2_DCONFIG_FONT_HANS 2 /* for Code page 936 Simplified Chinese */ +#define DA2_DCONFIG_FONT_HANT 3 /* for Code page 938 Traditional Chinese */ #define DA2_BLT_CIDLE 0 #define DA2_BLT_CFILLRECT 1 @@ -100,7 +105,12 @@ #define OldLSI 0x20 /* DA-2 or DA-3,5 */ #define Mon_ID3 0x10 #define FontCard 0x08 /* ? */ -/* IO 3E0/3E1:0Ah Hardware Configuration Value H (imported from OS/2 DDK) */ +/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ +#define Page_One 0x06 /* 80000h 110b */ +#define Page_Two 0x05 /* 100000h 101b */ +#define Page_Four 0x03 /* 200000h 011b */ + +/* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ #define AddPage 0x08 /* ? */ #define Mon_ID2 0x04 #define Mon_ID1 0x02 @@ -110,10 +120,6 @@ //#define StarbuckM 0x09 //1001b x grayscale //#define Lark_B 0x02 //0010b IBM 9517 color 1040x768 //#define Dallas 0x0B //1011b IBM 8515, 9515 color 1040x740 B palette -/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ -#define Page_One 0x06 /* 80000h 110b */ -#define Page_Two 0x05 /* 100000h 101b */ -#define Page_Four 0x03 /* 200000h 011b */ /* DA2 Registers (imported from OS/2 DDK) */ #define AC_REG 0x3EE @@ -1045,6 +1051,8 @@ void da2_out(uint16_t addr, uint16_t val, void *p) case LF_DATA: //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); if (da2->fctladdr > 0x1f) return; + if (da2->fctl[da2->fctladdr & 0x1f] != val) + da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); oldval = da2->fctl[da2->fctladdr]; da2->fctl[da2->fctladdr] = val; if (da2->fctladdr == 0 && oldval != val) @@ -1547,7 +1555,7 @@ Bank 5 (B9580-?;IBMJ 2930-295e?) : Full-width box drawing characters - The signature 80h, 01h must be placed at Bank 0:1AFFEh to run OS/2 J1.3. + Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) [Gaiji RAM Map (DA2)] Bank 0 00000-1FFFFh placed between A0000h-BFFFFh @@ -2271,8 +2279,9 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.ram[addr]; break; case 0x10://Font ROM + //if (addr >= 0x180000) addr -= 0x40000; if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; - da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return da2->mmio.font[addr]; break; default: @@ -2307,7 +2316,7 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) static uint16_t da2_mmio_readw(uint32_t addr, void* p) { da2_t* da2 = (da2_t*)p; - //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); } @@ -2962,7 +2971,7 @@ da2_reset(void* priv) da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ da2->attr_palette_enable = 0; /* disable attribute generator */ - /* Set default color palette (Display driver of Win 3.1 won't reset palette) */ + /* Set default color palette (Windows 3.1 display driver won't reset palette) */ da2_out(0x3c8, 0, da2); for (int i = 0; i < 256; i++) { da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); @@ -2991,7 +3000,17 @@ static void *da2_init() da2->cram = malloc(0x1000); da2->vram_display_mask = DA2_MASK_CRAM; da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h - da2_loadfont(DA2_FONTROM_PATH, da2); + + int fonttype = device_get_config_int("font"); + switch(fonttype) + { + case DA2_DCONFIG_FONT_HANT: + da2_loadfont(DA2_FONTROM_PATH_HANT, da2); + break; + case DA2_DCONFIG_FONT_JPAN: + da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + break; + } mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); @@ -3023,7 +3042,7 @@ static void *da2_init() } static int da2_available() { - return rom_present(DA2_FONTROM_PATH); + return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); } void da2_close(void *p) @@ -3122,6 +3141,32 @@ void da2_force_redraw(void *p) da2->fullchange = changeframecount; } +static const device_config_t da2_configuration[] = { + // clang-format off + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { + .description = "CP932 (Japanese)", + .value = DA2_DCONFIG_FONT_JPAN + }, + { + .description = "CP938 (Traditional Chinese)", + .value = DA2_DCONFIG_FONT_HANT + }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + const device_t ps55da2_device = { .name = "IBM Display Adapter II (MCA)", .internal_name = "ps55da2", @@ -3133,7 +3178,7 @@ const device_t ps55da2_device = { { .available = da2_available }, .speed_changed = da2_speed_changed, .force_redraw = da2_force_redraw, - .config = NULL + .config = da2_configuration }; void From 3bfd2a6b16e19f598ef00dbd2884e5cbc1285fe3 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:20:58 +0900 Subject: [PATCH 0201/1190] Added a configuration to switch monitor types --- src/video/vid_ps55da2.c | 78 +++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index a6d55c76a..6d4f43ca6 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -59,6 +59,8 @@ //#define DA2_DCONFIG_FONT_HANG 1 /* for Code page 934 Hangul */ //#define DA2_DCONFIG_FONT_HANS 2 /* for Code page 936 Simplified Chinese */ #define DA2_DCONFIG_FONT_HANT 3 /* for Code page 938 Traditional Chinese */ +#define DA2_DCONFIG_MONTYPE_COLOR 0x0A +#define DA2_DCONFIG_MONTYPE_MONO 0x09 #define DA2_BLT_CIDLE 0 #define DA2_BLT_CFILLRECT 1 @@ -102,8 +104,10 @@ | EFD8h | Display Adapter /J | | | X | X | X | */ /* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ +//2501 +//2500 mono #define OldLSI 0x20 /* DA-2 or DA-3,5 */ -#define Mon_ID3 0x10 +//#define Mon_ID3 0x10 #define FontCard 0x08 /* ? */ /* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ #define Page_One 0x06 /* 80000h 110b */ @@ -112,14 +116,14 @@ /* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ #define AddPage 0x08 /* ? */ -#define Mon_ID2 0x04 -#define Mon_ID1 0x02 -#define Mon_ID0 0x01 +//#define Mon_ID2 0x04 +//#define Mon_ID1 0x02 +//#define Mon_ID0 0x01 /* Monitor ID (imported from OS/2 DDK 1.2) */ -//#define StarbuckC 0x0A //1010b IBM 8514, 9518 color 1040x768 -//#define StarbuckM 0x09 //1001b x grayscale -//#define Lark_B 0x02 //0010b IBM 9517 color 1040x768 -//#define Dallas 0x0B //1011b IBM 8515, 9515 color 1040x740 B palette +//#define StarbuckC 0x0A //1 010b IBM 8514, 9518 color 1040x768 +//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale +//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4pp +//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 B palette /* DA2 Registers (imported from OS/2 DDK) */ #define AC_REG 0x3EE @@ -400,8 +404,7 @@ typedef struct da2_t uint8_t pos_regs[8]; svga_t *mb_vga; - - //int vidsys_ena; + uint8_t monitorid; int old_pos2; } da2_t; @@ -1256,12 +1259,25 @@ uint16_t da2_in(uint16_t addr, void *p) if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ - if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 0x50 && da2->attrc[LV_COMPATIBILITY] & 0x08) - temp &= 0x7F; /* Inactive when the RGB output voltage is high(or the cable is not connected to the color monitor). */ - else - temp |= 0x80; /* Active when the RGB output voltage is lowand the cable is connected to the color monitor. - If the cable or the monitor is wrong, it becomes inactive. */ - temp &= 0xf6;//idle + if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ + if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { + /* grayscale monitor */ + if ((da2->vgapal[0].r >= 10) || (da2->vgapal[0].g >= 40) || (da2->vgapal[0].b >= 10)) + temp &= 0x7F; /* Inactive when the RGB output voltage is high (or the cable is not connected to a color monitor). */ + else + temp |= 0x80; /* Active when the RGB output voltage is low and the cable is connected to a color monitor. + If the cable or the monitor is wrong, it becomes inactive. */ + } else { + /* color monitor */ + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 80) + temp &= 0x7F; + else + temp |= 0x80; + } + } else { + temp |= 0x80; + } + temp &= 0xf6;//clear busy bits if (da2->bitblt.indata) /* for OS/2 J1.3 */ da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) @@ -2959,8 +2975,9 @@ da2_reset(void* priv) da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ - da2->ioctl[LS_CONFIG1] = OldLSI | Mon_ID3 | Page_Two; /* Configuration(Low) : DA - 2, Monitor ID 3, 1024 KB */ - da2->ioctl[LS_CONFIG2] = Mon_ID1; /* Configuration (High): Monitor ID 0-2 */ + da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA - 2, 1024 KB */ + da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 2); /* Configuration 1 : Monitor ID 3 */ + da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ da2->fctl[0] = 0x2b; /* 3E3h:0 */ da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ @@ -3000,6 +3017,7 @@ static void *da2_init() da2->cram = malloc(0x1000); da2->vram_display_mask = DA2_MASK_CRAM; da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ int fonttype = device_get_config_int("font"); switch(fonttype) @@ -3145,12 +3163,9 @@ static const device_config_t da2_configuration[] = { // clang-format off { .name = "font", - .description = "Font", + .description = "Charset", .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, + .default_int = DA2_DCONFIG_FONT_JPAN, .selection = { { .description = "CP932 (Japanese)", @@ -3163,6 +3178,23 @@ static const device_config_t da2_configuration[] = { { .description = "" } } }, + { + .name = "montype", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_int = DA2_DCONFIG_MONTYPE_COLOR, + .selection = { + { + .description = "Color", + .value = DA2_DCONFIG_MONTYPE_COLOR + }, + { + .description = "Grayscale", + .value = DA2_DCONFIG_MONTYPE_MONO + }, + { .description = "" } + } + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; From ff80b57a8c826669cbfd54dcf386027ee74534d7 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 7 Feb 2025 11:47:55 +0300 Subject: [PATCH 0202/1190] Fix various errors with the machine table for 586-based machines (Part 1) --- src/machine/machine_table.c | 250 ++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bad86a786..26b42bc5b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11121,9 +11121,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { - .min = 8192, - .max = 196608, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -11156,14 +11156,14 @@ const machine_t machines[] = { .min_voltage = 3450, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 2.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { - .min = 8192, + .min = 4096, .max = 524288, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11201,9 +11201,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 524288, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11246,7 +11246,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -11470,7 +11470,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix MultiKey/42 (version 1.38) KBC firmware. */ { - .name = "[i430HX] Acer M3A", + .name = "[i430HX] Acer AcerPower Ultima", .internal_name = "acerm3a", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430HX, @@ -11492,9 +11492,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, /* Machine has internal SCSI */ .ram = { - .min = 8192, - .max = 196608, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -11523,18 +11523,18 @@ const machine_t machines[] = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, .min_bus = 50000000, - .max_bus = 83333333, + .max_bus = 75000000, .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 4.0 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { - .min = 8192, - .max = 262144, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11567,14 +11567,14 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Machine has AMB */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 524288, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11603,7 +11603,7 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 50000000, + .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2800, .max_voltage = 3520, @@ -11613,9 +11613,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { - .min = 8192, - .max = 131072, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -11633,7 +11633,7 @@ const machine_t machines[] = { PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ { - .name = "[i430HX] Intel TC430HX", + .name = "[i430HX] Intel TC430HX (Tucson)", .internal_name = "tc430hx", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430HX, @@ -11650,14 +11650,14 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_VIDEO | MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, /* Has internal sound: Yamaha YMF701-S */ .ram = { .min = 8192, - .max = 131072, - .step = 8192 + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11673,7 +11673,7 @@ const machine_t machines[] = { }, /* OEM version of Intel TC430HX, has AMI MegaKey KBC firmware on the PC87306 Super I/O chip. */ { - .name = "[i430HX] Toshiba Infinia 7200", + .name = "[i430HX] Toshiba Infinia 7201", .internal_name = "infinia7200", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430HX, @@ -11690,14 +11690,14 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_VIDEO | MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, /* Has internal sound: Yamaha YMF701-S */ .ram = { .min = 8192, - .max = 131072, - .step = 8192 + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11713,7 +11713,7 @@ const machine_t machines[] = { }, /* OEM-only Intel CU430HX, has AMI MegaKey KBC firmware on the PC87306 Super I/O chip. */ { - .name = "[i430HX] Intel CU430HX", + .name = "[i430HX] Intel CU430HX (Cumberland)", .internal_name = "cu430hx", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430HX, @@ -11730,14 +11730,14 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 196608, - .step = 8192 + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11770,14 +11770,14 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 196608, - .step = 8192 + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11806,18 +11806,18 @@ const machine_t machines[] = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, .min_bus = 50000000, - .max_bus = 83333333, + .max_bus = 66666667, .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { - .min = 8192, - .max = 262144, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11859,8 +11859,8 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 8192, - .max = 196608, - .step = 8192 + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11899,9 +11899,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, - .max = 786432, - .step = 8192 + .min = 4096, + .max = 524288, + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -11941,9 +11941,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SCSI | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -11976,14 +11976,14 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Machine has AMB */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12017,14 +12017,14 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12062,9 +12062,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12081,7 +12081,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C932QF Super I/O chip with on-chip KBC with AMI MegaKey (revision '5') KBC firmware. */ { - .name = "[i430VX] Compaq Presario 2240", + .name = "[i430VX] Compaq Presario 224x", .internal_name = "presario2240", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -12093,19 +12093,19 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 50000000, + .min_bus = 66666667, .max_bus = 66666667, .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM | MACHINE_ACPI, .ram = { - .min = 8192, - .max = 131072, - .step = 8192 + .min = 16384, + .max = 49152, + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12122,7 +12122,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C931APM Super I/O chip with on-chip KBC with Compaq KBC firmware. */ { - .name = "[i430VX] Compaq Presario 4500", + .name = "[i430VX] Compaq Presario 45xx", .internal_name = "presario4500", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -12134,19 +12134,19 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 50000000, + .min_bus = 66666667, .max_bus = 66666667, .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM | MACHINE_ACPI, .ram = { - .min = 8192, - .max = 131072, - .step = 8192 + .min = 16384, + .max = 49152, + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12163,7 +12163,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C932FR Super I/O chip with on-chip KBC with AMI MegaKey (revision '5') KBC firmware. */ { - .name = "[i430VX] Dell Hannibal+", + .name = "[i430VX] Dell Dimension XPS Pxxxa/Mxxxa", .internal_name = "dellhannibalp", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -12180,14 +12180,14 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12225,9 +12225,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12257,7 +12257,7 @@ const machine_t machines[] = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, .min_bus = 50000000, - .max_bus = 66666667, + .max_bus = 75000000, .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, @@ -12266,9 +12266,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12309,7 +12309,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12343,14 +12343,14 @@ const machine_t machines[] = { .min_voltage = 2200, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { - .min = 16384, + .min = 8192, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12368,7 +12368,7 @@ const machine_t machines[] = { PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ { - .name = "[i430VX] Packard Bell PB680", + .name = "[i430VX] Packard Bell Multimedia C110", .internal_name = "pb680", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -12392,7 +12392,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -12409,7 +12409,7 @@ const machine_t machines[] = { /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix MultiKey/42 (version 1.38) KBC firmware. */ { - .name = "[i430VX] Packard Bell PB810", + .name = "[i430VX] Packard Bell Multimedia M415", .internal_name = "pb810", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430VX, @@ -12426,14 +12426,14 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 4.0 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 511, .kbc_device = NULL, @@ -12467,14 +12467,14 @@ const machine_t machines[] = { .min_voltage = 2600, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12513,9 +12513,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_GAMEPORT | MACHINE_APM | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 131072, - .step = 8192 + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, @@ -12590,7 +12590,7 @@ const machine_t machines[] = { .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, @@ -12613,7 +12613,7 @@ const machine_t machines[] = { }, /* [TEST] Has AMI Megakey '5' KBC firmware on the SM(S)C FDC37C67x Super I/O chip. */ { - .name = "[i430TX] Gateway Tomahawk", + .name = "[i430TX] Gateway E-1000", .internal_name = "tomahawk", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, @@ -12625,12 +12625,12 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 50000000, + .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2100, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 5.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_NIC | MACHINE_USB, @@ -12654,7 +12654,7 @@ const machine_t machines[] = { #ifdef USE_AN430TX /* This has the Phoenix MultiKey KBC firmware. */ { - .name = "[i430TX] Intel AN430TX", + .name = "[i430TX] Intel AN430TX (Anchorage)", .internal_name = "an430tx", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, @@ -12671,7 +12671,7 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, @@ -12695,7 +12695,7 @@ const machine_t machines[] = { #endif /* USE_AN430TX */ /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ { - .name = "[i430TX] Intel YM430TX", + .name = "[i430TX] Intel YM430TX (Yamamoto)", .internal_name = "ym430tx", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, @@ -12712,14 +12712,14 @@ const machine_t machines[] = { .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 262144, - .step = 8192 + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -12733,7 +12733,7 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* PhoenixBIOS 4.0 Rel 6.0 for 430TX, most likely has AMI KBC of some sort. Also has onboard Yamaha YMF701 which can't be emulated yet. */ + /* PhoenixBIOS 4.0 Rel 6.0 for 430TX, has onboard Yamaha YMF701 which is not emulated yet. */ /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix MultiKey/42 (version 1.38) KBC firmware. */ { @@ -12749,12 +12749,12 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK(CPU_WINCHIP, CPU_WINCHIP2), - .min_bus = 50000000, + .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2500, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_GAMEPORT | MACHINE_USB, /* Machine has internal sound: Yamaha YMF701-S */ @@ -12795,13 +12795,13 @@ const machine_t machines[] = { .min_voltage = 2700, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { .min = 8192, - .max = 786432, + .max = 262144, .step = 8192 }, .nvrmask = 255, @@ -12836,14 +12836,14 @@ const machine_t machines[] = { .min_voltage = 2700, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 262144, - .step = 8192 + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -12871,8 +12871,8 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 55000000, - .max_bus = 75000000, + .min_bus = 60000000, + .max_bus = 66666667, .min_voltage = 2800, .max_voltage = 3520, .min_multi = 1.5, @@ -12881,9 +12881,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 262144, - .step = 8192 + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -12912,18 +12912,18 @@ const machine_t machines[] = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, .min_bus = 50000000, - .max_bus = 66666667, + .max_bus = 75000000, .min_voltage = 2100, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 8192, + .min = 4096, .max = 262144, - .step = 8192 + .step = 4096 }, .nvrmask = 255, .kbc_device = NULL, @@ -12939,7 +12939,7 @@ const machine_t machines[] = { }, /* [TEST] Has AMIKey 'H' KBC firmware. */ { - .name = "[i430TX] TriGem Richmond", + .name = "[i430TX] TriGem RD535 (Richmond)", .internal_name = "richmond", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, @@ -12951,12 +12951,12 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 50000000, + .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2100, .max_voltage = 3520, .min_multi = 1.5, - .max_multi = 3.0 + .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, @@ -13108,7 +13108,7 @@ const machine_t machines[] = { /* SiS 5571 */ /* Has the SiS 5571 chipset with on-chip KBC. */ { - .name = "[SiS 5571] Daewoo CB52X-SI", + .name = "[SiS 5571] Daewoo CD520", .internal_name = "cb52xsi", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_SIS_5571, From 34e3f6e8496296975dc8249f6ed2e2ea1835b95a Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 7 Feb 2025 23:34:12 +0100 Subject: [PATCH 0203/1190] No longer list Socket 8 CPU's for Slot 1 machines, closes #5196. --- src/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 0802fa3ac..808f603b5 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -372,7 +372,7 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) if (packages & CPU_PKG_SOCKET3) packages |= CPU_PKG_SOCKET1; else if (packages & CPU_PKG_SLOT1) - packages |= CPU_PKG_SOCKET370 | CPU_PKG_SOCKET8; + packages |= CPU_PKG_SOCKET370; /* Package type. */ if (!(cpu_family->package & packages)) From bc5d2a425e9748a358c3ab7cf45d9a4070c9dc8a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Feb 2025 20:27:49 -0300 Subject: [PATCH 0204/1190] CS423x: Finish implementing the missing chip types --- src/sound/snd_cs423x.c | 95 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index a7aa04718..4e65c3810 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -90,13 +90,13 @@ static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0 0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2, 0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13, 0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A }; -static const uint8_t cs4236b_default[] = { +static const uint8_t cs4236_default[] = { // clang-format off /* Chip configuration */ 0x00, 0x03, /* CD-ROM and modem decode */ 0x80, /* misc. config */ 0x80, /* global config */ - 0x0b, /* chip ID */ + 0x0b, /* [code base byte (CS4236B+)] / reserved (CS4236) */ 0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, /* reserved */ 0x00, /* external decode length */ 0x48, /* reserved */ @@ -104,7 +104,7 @@ static const uint8_t cs4236b_default[] = { 0x10, 0x03, /* DMA routing */ /* Default PnP data */ - 0x0e, 0x63, 0x42, 0x35, 0xff, 0xff, 0xff, 0xff, 0x00 /* hinted by documentation to be just the header */ + 0x0e, 0x63, 0x42, 0x36, 0xff, 0xff, 0xff, 0xff, 0x00 /* hinted by documentation to be just the header */ // clang-format on }; @@ -800,6 +800,47 @@ cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv } } +static void +cs423x_load_defaults(cs423x_t *dev, uint8_t *dest) +{ + switch (dev->type) { + case CRYSTAL_CS4236: + case CRYSTAL_CS4236B: + case CRYSTAL_CS4237B: + case CRYSTAL_CS4238B: + case CRYSTAL_CS4235: + case CRYSTAL_CS4239: + memcpy(dest, cs4236_default, sizeof(cs4236_default)); + dev->pnp_size = 9; /* header-only PnP ROM size */ + + switch (dev->type) { + case CRYSTAL_CS4236: + dest[4] = 0x43; /* code base byte */ + break; + + case CRYSTAL_CS4236B: + dest[22] = 0x35; /* default PnP ID */ + break; + + case CRYSTAL_CS4237B: + dest[22] = 0x37; /* default PnP ID */ + break; + + case CRYSTAL_CS4238B: + dest[22] = 0x38; /* default PnP ID */ + break; + + case CRYSTAL_CS4235: + case CRYSTAL_CS4239: + dest[4] = 0x05; /* code base byte */ + dest[12] = 0x08; /* external decode length */ + dest[22] = 0x36; /* default PnP ID - explicitly stated to be the CS4236 non-B one */ + break; + } + break; + } +} + static void cs423x_reset(void *priv) { @@ -809,8 +850,7 @@ cs423x_reset(void *priv) memset(dev->ram_data, 0, sizeof(dev->ram_data)); /* Load default configuration data to RAM. */ - memcpy(&dev->ram_data[0x4000], cs4236b_default, sizeof(cs4236b_default)); - dev->pnp_size = 9; + cs423x_load_defaults(dev, &dev->ram_data[0x4000]); if (dev->eeprom) { /* Load EEPROM data to RAM if the magic bytes are present. */ @@ -858,21 +898,22 @@ cs423x_init(const device_t *info) dev->type = info->local & 0xff; cs423x_log("CS423x: init(%02X)\n", dev->type); switch (dev->type) { + case CRYSTAL_CS4236: case CRYSTAL_CS4236B: case CRYSTAL_CS4237B: case CRYSTAL_CS4238B: case CRYSTAL_CS4235: case CRYSTAL_CS4239: /* Same WSS codec and EEPROM structure. */ - dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236B; + dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : ((dev->type >= CRYSTAL_CS4236B) ? AD1848_TYPE_CS4236B : AD1848_TYPE_CS4236); dev->pnp_offset = 0x4013; - /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init. */ + /* Different Chip Version and ID registers (N/A on CS4236), which shouldn't be reset by ad1848_init. */ dev->ad1848.xregs[25] = dev->type; if (!(info->local & CRYSTAL_NOEEPROM)) { - /* Copy default configuration data. */ - memcpy(&dev->eeprom_data[4], cs4236b_default, sizeof(cs4236b_default)); + /* Start a new EEPROM with the default configuration data. */ + cs423x_load_defaults(dev, &dev->eeprom_data[4]); /* Load PnP resource data ROM. */ FILE *fp = rom_fopen(PNP_ROM_CS4236B, "rb"); @@ -883,6 +924,8 @@ cs423x_init(const device_t *info) with pretending the whole ROM is PnP data, at least until we can get full EEPROM dumps. */ dev->pnp_size = fread(&dev->eeprom_data[eeprom_pnp_offset], 1, sizeof(dev->eeprom_data) - eeprom_pnp_offset, fp); fclose(fp); + } else { + dev->pnp_size = 0; } /* Populate EEPROM header if the PnP ROM was loaded. */ @@ -895,14 +938,12 @@ cs423x_init(const device_t *info) /* Patch PnP ROM and set EEPROM file name. */ switch (dev->type) { - case CRYSTAL_CS4235: + case CRYSTAL_CS4236: if (dev->pnp_size) { - dev->eeprom_data[8] = 0x05; - dev->eeprom_data[16] = 0x08; - dev->eeprom_data[26] = 0x25; - dev->eeprom_data[44] = '5'; + dev->eeprom_data[26] = 0x36; + dev->eeprom_data[45] = ' '; } - dev->nvr_path = "cs4235.nvr"; + dev->nvr_path = "cs4236.nvr"; break; case CRYSTAL_CS4236B: @@ -914,7 +955,7 @@ cs423x_init(const device_t *info) dev->eeprom_data[26] = 0x37; dev->eeprom_data[44] = '7'; } - dev->nvr_path = "cs4237b.nvr"; + dev->nvr_path = "cs4237b.nvr"; break; case CRYSTAL_CS4238B: @@ -922,7 +963,25 @@ cs423x_init(const device_t *info) dev->eeprom_data[26] = 0x38; dev->eeprom_data[44] = '8'; } - dev->nvr_path = "cs4238b.nvr"; + dev->nvr_path = "cs4238b.nvr"; + break; + + case CRYSTAL_CS4235: + if (dev->pnp_size) { + dev->eeprom_data[26] = 0x25; + dev->eeprom_data[44] = '5'; + dev->eeprom_data[45] = ' '; + } + dev->nvr_path = "cs4235.nvr"; + break; + + case CRYSTAL_CS4239: + if (dev->pnp_size) { + dev->eeprom_data[26] = 0x29; + dev->eeprom_data[44] = '9'; + dev->eeprom_data[45] = ' '; + } + dev->nvr_path = "cs4239.nvr"; break; default: @@ -935,7 +994,7 @@ cs423x_init(const device_t *info) /* Initialize game port. The game port on all B chips only responds to 6 I/O ports; the remaining 2 are reserved. */ - dev->gameport = gameport_add((dev->type == CRYSTAL_CS4235) ? &gameport_pnp_device : &gameport_pnp_6io_device); + dev->gameport = gameport_add((dev->ad1848_type == CRYSTAL_CS4236B) ? &gameport_pnp_6io_device : &gameport_pnp_device); break; From b7f79750549274b5c2c8fe27178911d121937789 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Feb 2025 20:44:21 -0300 Subject: [PATCH 0205/1190] CS423x: Add on-board CS4236 to the VS440FX --- src/include/86box/sound.h | 1 + src/machine/m_at_socket8.c | 6 ++++++ src/machine/machine_table.c | 8 ++++---- src/sound/snd_cs423x.c | 16 +++++++++++++++- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 645d974dd..ba6ac2f83 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -170,6 +170,7 @@ extern const device_t sb_awe64_gold_device; /* Crystal CS423x */ extern const device_t cs4235_device; extern const device_t cs4235_onboard_device; +extern const device_t cs4236_onboard_device; extern const device_t cs4236b_device; extern const device_t cs4237b_device; extern const device_t cs4238b_device; diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index e6f78f6a2..935a26fb2 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -256,6 +256,9 @@ machine_at_vs440fx_init(const machine_t *model) device_add(&intel_flash_bxt_ami_device); + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + return ret; } @@ -290,6 +293,9 @@ machine_at_gw2kvenus_init(const machine_t *model) device_add(&intel_flash_bxt_ami_device); + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 26b42bc5b..82b0082fe 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14072,7 +14072,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14087,7 +14087,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &cs4236_onboard_device, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ @@ -14196,7 +14196,7 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 524288, @@ -14211,7 +14211,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &cs4236_onboard_device, .net_device = NULL }, /* Has the AMIKey-2 (updated 'H') KBC firmware. */ diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 4e65c3810..bef57d992 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -259,7 +259,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) break; case 3: /* Control Indirect Access Register (CS4236B+) */ - if (dev->type < CRYSTAL_CS4236B) + if (dev->type < CRYSTAL_CS4236) /* must be writable on CS4236 for the aforementioned VS440FX BIOS check */ return; val &= 0x0f; break; @@ -1089,6 +1089,20 @@ const device_t cs4235_onboard_device = { .config = NULL }; +const device_t cs4236_onboard_device = { + .name = "Crystal CS4236 (On-Board)", + .internal_name = "cs4236_onboard", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4236 | CRYSTAL_NOEEPROM, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + .available = cs423x_available, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t cs4236b_device = { .name = "Crystal CS4236B", .internal_name = "cs4236b", From 34fbecb377a303c58872b50ac9650d93afa63339 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Feb 2025 00:06:54 -0300 Subject: [PATCH 0206/1190] CS423x: Add proper on-board CS4236B to the Intel AP440FX Default PnP ID patches have been removed as the AP440FX BIOS confirms the CSC4236 ID never changed (as later documented on CS4235/9) --- src/include/86box/sound.h | 1 + src/machine/machine_table.c | 2 +- src/sound/snd_cs423x.c | 33 ++++++++++++++++++--------------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index ba6ac2f83..a30095c66 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -172,6 +172,7 @@ extern const device_t cs4235_device; extern const device_t cs4235_onboard_device; extern const device_t cs4236_onboard_device; extern const device_t cs4236b_device; +extern const device_t cs4236b_onboard_device; extern const device_t cs4237b_device; extern const device_t cs4238b_device; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 82b0082fe..febdc0e0c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14169,7 +14169,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = &s3_virge_325_onboard_pci_device, - .snd_device = &cs4236b_device, + .snd_device = &cs4236b_onboard_device, .net_device = NULL }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index bef57d992..f6ded130a 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -818,23 +818,10 @@ cs423x_load_defaults(cs423x_t *dev, uint8_t *dest) dest[4] = 0x43; /* code base byte */ break; - case CRYSTAL_CS4236B: - dest[22] = 0x35; /* default PnP ID */ - break; - - case CRYSTAL_CS4237B: - dest[22] = 0x37; /* default PnP ID */ - break; - - case CRYSTAL_CS4238B: - dest[22] = 0x38; /* default PnP ID */ - break; - case CRYSTAL_CS4235: case CRYSTAL_CS4239: dest[4] = 0x05; /* code base byte */ dest[12] = 0x08; /* external decode length */ - dest[22] = 0x36; /* default PnP ID - explicitly stated to be the CS4236 non-B one */ break; } break; @@ -904,13 +891,15 @@ cs423x_init(const device_t *info) case CRYSTAL_CS4238B: case CRYSTAL_CS4235: case CRYSTAL_CS4239: - /* Same WSS codec and EEPROM structure. */ + /* Different WSS codec families. */ dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : ((dev->type >= CRYSTAL_CS4236B) ? AD1848_TYPE_CS4236B : AD1848_TYPE_CS4236); - dev->pnp_offset = 0x4013; /* Different Chip Version and ID registers (N/A on CS4236), which shouldn't be reset by ad1848_init. */ dev->ad1848.xregs[25] = dev->type; + /* Same EEPROM structure. */ + dev->pnp_offset = 0x4013; + if (!(info->local & CRYSTAL_NOEEPROM)) { /* Start a new EEPROM with the default configuration data. */ cs423x_load_defaults(dev, &dev->eeprom_data[4]); @@ -1117,6 +1106,20 @@ const device_t cs4236b_device = { .config = NULL }; +const device_t cs4236b_onboard_device = { + .name = "Crystal CS4236B", + .internal_name = "cs4236b", + .flags = DEVICE_ISA | DEVICE_AT, + .local = CRYSTAL_CS4236B | CRYSTAL_NOEEPROM, + .init = cs423x_init, + .close = cs423x_close, + .reset = cs423x_reset, + .available = cs423x_available, + .speed_changed = cs423x_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t cs4237b_device = { .name = "Crystal CS4237B", .internal_name = "cs4237b", From 5b894c32e6f516f62223d9e24a721a830eb41304 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 1 Feb 2025 03:29:03 -0500 Subject: [PATCH 0207/1190] Macro Cleaning --- src/codegen_new/codegen.c | 3 +- src/codegen_new/codegen_accumulate.c | 3 +- src/codegen_new/codegen_ops_3dnow.c | 45 +- src/codegen_new/codegen_ops_branch.c | 85 ++-- src/codegen_new/codegen_ops_fpu_arith.c | 528 ++++++++++----------- src/codegen_new/codegen_ops_misc.c | 92 ++-- src/codegen_new/codegen_ops_mmx_arith.c | 43 +- src/codegen_new/codegen_ops_mmx_cmp.c | 43 +- src/codegen_new/codegen_ops_mmx_pack.c | 43 +- src/codegen_new/codegen_ops_stack.c | 110 ++--- src/video/CMakeLists.txt | 96 +++- src/video/vid_8514a.c | 259 ++++++----- src/video/vid_ati_mach64.c | 66 +-- src/video/vid_ati_mach8.c | 414 +++++++++-------- src/video/vid_cga_comp.c | 32 +- src/video/vid_et4000.c | 4 +- src/video/vid_mga.c | 21 +- src/video/vid_paradise.c | 2 +- src/video/vid_s3.c | 34 +- src/video/vid_s3_virge.c | 586 ++++++++++++------------ src/video/vid_tgui9440.c | 29 +- src/video/vid_voodoo_banshee.c | 40 +- src/video/vid_voodoo_render.c | 16 +- src/video/vid_voodoo_setup.c | 4 +- src/video/vid_voodoo_texture.c | 8 +- src/video/vid_xga.c | 14 +- 26 files changed, 1384 insertions(+), 1236 deletions(-) diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index a3f4ede8f..39ab69b3d 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -21,8 +21,7 @@ #define MAX_INSTRUCTION_COUNT 50 -static struct -{ +static struct { uint32_t pc; int op_ssegs; x86seg *op_ea_seg; diff --git a/src/codegen_new/codegen_accumulate.c b/src/codegen_new/codegen_accumulate.c index 29b05ad77..087d9c797 100644 --- a/src/codegen_new/codegen_accumulate.c +++ b/src/codegen_new/codegen_accumulate.c @@ -8,8 +8,7 @@ #include "codegen_accumulate.h" #include "codegen_ir.h" -static struct -{ +static struct { int count; int dest_reg; } acc_regs[] = { diff --git a/src/codegen_new/codegen_ops_3dnow.c b/src/codegen_new/codegen_ops_3dnow.c index 03af718d1..e827d0d27 100644 --- a/src/codegen_new/codegen_ops_3dnow.c +++ b/src/codegen_new/codegen_ops_3dnow.c @@ -16,28 +16,29 @@ #include "codegen_ops_3dnow.h" #include "codegen_ops_helpers.h" -#define ropParith(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - uop_MMX_ENTER(ir); \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - if ((fetchdat & 0xc0) == 0xc0) { \ - int src_reg = fetchdat & 7; \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ - } else { \ - x86seg *target_seg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ - } \ - \ - codegen_mark_code_present(block, cs + op_pc + 1, 1); \ - return op_pc + 2; \ +#define ropParith(func) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) { \ + int src_reg = fetchdat & 7; \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } else { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + codegen_mark_code_present(block, cs + op_pc + 1, 1); \ + return op_pc + 2; \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_branch.c b/src/codegen_new/codegen_ops_branch.c index 1e2589f8b..2039b6d79 100644 --- a/src/codegen_new/codegen_ops_branch.c +++ b/src/codegen_new/codegen_ops_branch.c @@ -815,41 +815,56 @@ ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t n } } -#define ropJ(cond) \ - uint32_t ropJ##cond##_8(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), uint32_t op_32, uint32_t op_pc) \ - { \ - uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); \ - uint32_t dest_addr = op_pc + 1 + offset; \ - int ret; \ - \ - if (!(op_32 & 0x100)) \ - dest_addr &= 0xffff; \ - ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 1); \ - \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - return ret ? dest_addr : (op_pc + 1); \ - } \ - uint32_t ropJ##cond##_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - uint32_t offset = (int32_t) (int16_t) fastreadw(cs + op_pc); \ - uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \ - int ret; \ - \ - ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 2); \ - \ - codegen_mark_code_present(block, cs + op_pc, 2); \ - return ret ? dest_addr : (op_pc + 2); \ - } \ - uint32_t ropJ##cond##_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - uint32_t offset = fastreadl(cs + op_pc); \ - uint32_t dest_addr = op_pc + 4 + offset; \ - int ret; \ - \ - ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 4); \ - \ - codegen_mark_code_present(block, cs + op_pc, 4); \ - return ret ? dest_addr : (op_pc + 4); \ +#define ropJ(cond) \ + uint32_t ropJ##cond##_8(codeblock_t *block, \ + ir_data_t *ir, \ + UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + uint32_t op_32, \ + uint32_t op_pc) \ + { \ + uint32_t offset = (int32_t) (int8_t) fastreadb(cs + op_pc); \ + uint32_t dest_addr = op_pc + 1 + offset; \ + int ret; \ + \ + if (!(op_32 & 0x100)) \ + dest_addr &= 0xffff; \ + ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 1); \ + \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + return ret ? dest_addr : (op_pc + 1); \ + } \ + uint32_t ropJ##cond##_16(codeblock_t *block, \ + ir_data_t *ir, \ + UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc) \ + { \ + uint32_t offset = (int32_t) (int16_t) fastreadw(cs + op_pc); \ + uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \ + int ret; \ + \ + ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 2); \ + \ + codegen_mark_code_present(block, cs + op_pc, 2); \ + return ret ? dest_addr : (op_pc + 2); \ + } \ + uint32_t ropJ##cond##_32(codeblock_t *block, \ + ir_data_t *ir, \ + UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), \ + UNUSED(uint32_t op_32), \ + uint32_t op_pc) \ + { \ + uint32_t offset = fastreadl(cs + op_pc); \ + uint32_t dest_addr = op_pc + 4 + offset; \ + int ret; \ + \ + ret = ropJ##cond##_common(block, ir, dest_addr, op_pc + 4); \ + \ + codegen_mark_code_present(block, cs + op_pc, 4); \ + return ret ? dest_addr : (op_pc + 4); \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_fpu_arith.c b/src/codegen_new/codegen_ops_fpu_arith.c index 43d243c0f..1568852df 100644 --- a/src/codegen_new/codegen_ops_fpu_arith.c +++ b/src/codegen_new/codegen_ops_fpu_arith.c @@ -300,131 +300,139 @@ ropFUCOMPP(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uin return op_pc; } -#define ropF_arith_mem(name, load_uop) \ - uint32_t ropFADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - if ((cpu_state.npxc >> 10) & 3) \ - return 0; \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFCOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ - uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFCOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ - uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ - fpu_POP(block, ir); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFSUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFSUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ +#define ropF_arith_mem(name, load_uop) \ + uint32_t ropFADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + if ((cpu_state.npxc >> 10) & 3) \ + return 0; \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFCOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFCOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFSUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFSUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ } // clang-format off @@ -432,137 +440,145 @@ ropF_arith_mem(s, uop_MEM_LOAD_SINGLE) ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) // clang-format on -#define ropFI_arith_mem(name, temp_reg) \ - uint32_t ropFIADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFICOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ - uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFICOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ - uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ - uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ - fpu_POP(block, ir); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFIDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFIDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFIMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFISUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ - } \ - uint32_t ropFISUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg; \ - \ - uop_FP_ENTER(ir); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - op_pc--; \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ - uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ - uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ - \ - return op_pc + 1; \ +#define ropFI_arith_mem(name, temp_reg) \ + uint32_t ropFIADD##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFICOM##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFICOMP##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFIDIV##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFIDIVR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFIMUL##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFISUB##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ + } \ + uint32_t ropFISUBR##name(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc + 1; \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_misc.c b/src/codegen_new/codegen_ops_misc.c index c709dffc9..91e0f5d63 100644 --- a/src/codegen_new/codegen_ops_misc.c +++ b/src/codegen_new/codegen_ops_misc.c @@ -519,57 +519,61 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE return op_pc; } -#define ropLxS(name, seg) \ - uint32_t rop##name##_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg = NULL; \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - return 0; \ - \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ - uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ - uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ - \ - if (seg == &cpu_state.seg_ss) \ - CPU_BLOCK_END(); \ - \ - return op_pc + 1; \ - } \ - uint32_t rop##name##_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - x86seg *target_seg = NULL; \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - return 0; \ - \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ - uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ - uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ - \ - if (seg == &cpu_state.seg_ss) \ - CPU_BLOCK_END(); \ - \ - return op_pc + 1; \ +#define ropLxS(name, seg) \ + uint32_t rop##name##_16(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ + } \ + uint32_t rop##name##_32(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ } +// clang-format off ropLxS(LDS, &cpu_state.seg_ds) ropLxS(LES, &cpu_state.seg_es) ropLxS(LFS, &cpu_state.seg_fs) ropLxS(LGS, &cpu_state.seg_gs) ropLxS(LSS, &cpu_state.seg_ss) +// clang-format on uint32_t ropCLC(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) diff --git a/src/codegen_new/codegen_ops_mmx_arith.c b/src/codegen_new/codegen_ops_mmx_arith.c index 8fd1d1651..f01d64273 100644 --- a/src/codegen_new/codegen_ops_mmx_arith.c +++ b/src/codegen_new/codegen_ops_mmx_arith.c @@ -16,27 +16,28 @@ #include "codegen_ops_mmx_arith.h" #include "codegen_ops_helpers.h" -#define ropParith(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - uop_MMX_ENTER(ir); \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - if ((fetchdat & 0xc0) == 0xc0) { \ - int src_reg = fetchdat & 7; \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ - } else { \ - x86seg *target_seg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ - } \ - \ - return op_pc + 1; \ +#define ropParith(func) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) { \ + int src_reg = fetchdat & 7; \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } else { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_mmx_cmp.c b/src/codegen_new/codegen_ops_mmx_cmp.c index e00e56472..cf0cededb 100644 --- a/src/codegen_new/codegen_ops_mmx_cmp.c +++ b/src/codegen_new/codegen_ops_mmx_cmp.c @@ -16,27 +16,28 @@ #include "codegen_ops_mmx_cmp.h" #include "codegen_ops_helpers.h" -#define ropPcmp(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - uop_MMX_ENTER(ir); \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - if ((fetchdat & 0xc0) == 0xc0) { \ - int src_reg = fetchdat & 7; \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ - } else { \ - x86seg *target_seg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ - } \ - \ - return op_pc + 1; \ +#define ropPcmp(func) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) { \ + int src_reg = fetchdat & 7; \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } else { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_mmx_pack.c b/src/codegen_new/codegen_ops_mmx_pack.c index 18377e142..c62aa10d0 100644 --- a/src/codegen_new/codegen_ops_mmx_pack.c +++ b/src/codegen_new/codegen_ops_mmx_pack.c @@ -16,27 +16,28 @@ #include "codegen_ops_mmx_pack.h" #include "codegen_ops_helpers.h" -#define ropPpack(func) \ - uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ - { \ - int dest_reg = (fetchdat >> 3) & 7; \ - \ - uop_MMX_ENTER(ir); \ - codegen_mark_code_present(block, cs + op_pc, 1); \ - if ((fetchdat & 0xc0) == 0xc0) { \ - int src_reg = fetchdat & 7; \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ - } else { \ - x86seg *target_seg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ - codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ - } \ - \ - return op_pc + 1; \ +#define ropPpack(func) \ + uint32_t rop##func(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), \ + uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ + { \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs + op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) { \ + int src_reg = fetchdat & 7; \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } else { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_##func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ } // clang-format off diff --git a/src/codegen_new/codegen_ops_stack.c b/src/codegen_new/codegen_ops_stack.c index 057cccb0f..fca9c9efa 100644 --- a/src/codegen_new/codegen_ops_stack.c +++ b/src/codegen_new/codegen_ops_stack.c @@ -196,61 +196,65 @@ ropPOP_L(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t fet return op_pc + 1; } -#define ROP_PUSH_SEG(seg) \ - uint32_t ropPUSH_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - int sp_reg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); \ - uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_##seg##_seg_W); \ - SUB_SP(ir, 2); \ - \ - return op_pc; \ - } \ - uint32_t ropPUSH_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - int sp_reg; \ - \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); \ - uop_MOVZX(ir, IREG_temp0, IREG_##seg##_seg_W); \ - uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_temp0); \ - SUB_SP(ir, 4); \ - \ - return op_pc; \ +#define ROP_PUSH_SEG(seg) \ + uint32_t ropPUSH_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ + { \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_##seg##_seg_W); \ + SUB_SP(ir, 2); \ + \ + return op_pc; \ + } \ + uint32_t ropPUSH_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ + { \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); \ + uop_MOVZX(ir, IREG_temp0, IREG_##seg##_seg_W); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_temp0); \ + SUB_SP(ir, 4); \ + \ + return op_pc; \ } -#define ROP_POP_SEG(seg, rseg) \ - uint32_t ropPOP_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - \ - if (stack32) \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ - else { \ - uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ - } \ - uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ - ADD_SP(ir, 2); \ - \ - return op_pc; \ - } \ - uint32_t ropPOP_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ - { \ - uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ - \ - if (stack32) \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ - else { \ - uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ - } \ - uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ - ADD_SP(ir, 4); \ - \ - return op_pc; \ +#define ROP_POP_SEG(seg, rseg) \ + uint32_t ropPOP_##seg##_16(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ + { \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 2); \ + \ + return op_pc; \ + } \ + uint32_t ropPOP_##seg##_32(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), \ + UNUSED(uint32_t fetchdat), UNUSED(uint32_t op_32), uint32_t op_pc) \ + { \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 4); \ + \ + return op_pc; \ } // clang-format off diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 3d8e14c5e..41566bf3e 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -13,23 +13,72 @@ # Copyright 2020-2021 David Hrdlička. # -add_library(vid OBJECT agpgart.c video.c vid_table.c vid_cga.c vid_cga_comp.c - vid_compaq_cga.c vid_mda.c vid_hercules.c vid_herculesplus.c - vid_incolor.c vid_colorplus.c vid_genius.c vid_pgc.c vid_im1024.c - vid_sigma.c vid_wy700.c vid_ega.c vid_ega_render.c vid_svga.c vid_8514a.c - vid_svga_render.c vid_ddc.c vid_vga.c vid_ati_eeprom.c vid_ati18800.c - vid_ati28800.c vid_ati_mach8.c vid_ati_mach64.c vid_ati68875_ramdac.c - vid_ati68860_ramdac.c vid_bt481_ramdac.c vid_bt48x_ramdac.c vid_chips_69000.c - vid_av9194.c vid_icd2061.c vid_ics2494.c vid_ics2595.c vid_cl54xx.c - vid_et3000.c vid_et4000.c vid_sc1148x_ramdac.c vid_sc1502x_ramdac.c - vid_et4000w32.c vid_stg_ramdac.c vid_ht216.c vid_oak_oti.c vid_paradise.c - vid_rtg310x.c vid_f82c425.c vid_ti_cf62011.c vid_tvga.c vid_tgui9440.c - vid_tkd8001_ramdac.c vid_att20c49x_ramdac.c vid_s3.c vid_s3_virge.c - vid_ibm_rgb528_ramdac.c vid_sdac_ramdac.c vid_ogc.c vid_mga.c vid_nga.c - vid_tvp3026_ramdac.c vid_att2xc498_ramdac.c vid_xga.c +add_library(vid OBJECT + agpgart.c + video.c + vid_table.c + vid_cga.c + vid_cga_comp.c + vid_compaq_cga.c + vid_mda.c + vid_hercules.c + vid_herculesplus.c + vid_incolor.c + vid_colorplus.c + vid_genius.c + vid_pgc.c + vid_im1024.c + vid_sigma.c + vid_wy700.c + vid_ega.c + vid_ega_render.c + vid_svga.c + vid_8514a.c + vid_svga_render.c + vid_ddc.c + vid_vga.c + vid_ati_eeprom.c + vid_ati18800.c + vid_ati28800.c + vid_ati_mach8.c + vid_ati_mach64.c + vid_ati68875_ramdac.c + vid_ati68860_ramdac.c + vid_bt481_ramdac.c + vid_bt48x_ramdac.c + vid_chips_69000.c + vid_av9194.c + vid_icd2061.c + vid_ics2494.c + vid_ics2595.c + vid_cl54xx.c + vid_et3000.c + vid_et4000.c + vid_sc1148x_ramdac.c + vid_sc1502x_ramdac.c + vid_et4000w32.c + vid_stg_ramdac.c + vid_ht216.c + vid_oak_oti.c + vid_paradise.c + vid_rtg310x.c + vid_f82c425.c + vid_ti_cf62011.c + vid_tvga.c vid_tgui9440.c + vid_tkd8001_ramdac.c + vid_att20c49x_ramdac.c + vid_s3.c vid_s3_virge.c + vid_ibm_rgb528_ramdac.c + vid_sdac_ramdac.c + vid_ogc.c + vid_mga.c + vid_nga.c + vid_tvp3026_ramdac.c + vid_att2xc498_ramdac.c + vid_xga.c vid_bochs_vbe.c nv/nv_rivatimer.c - ) +) if(G100) target_compile_definitions(vid PRIVATE USE_G100) @@ -39,10 +88,19 @@ if(XL24) target_compile_definitions(vid PRIVATE USE_XL24) endif() -add_library(voodoo OBJECT vid_voodoo.c vid_voodoo_banshee.c - vid_voodoo_banshee_blitter.c vid_voodoo_blitter.c vid_voodoo_display.c - vid_voodoo_fb.c vid_voodoo_fifo.c vid_voodoo_reg.c vid_voodoo_render.c - vid_voodoo_setup.c vid_voodoo_texture.c) +add_library(voodoo OBJECT + vid_voodoo.c + vid_voodoo_banshee.c + vid_voodoo_banshee_blitter.c + vid_voodoo_blitter.c + vid_voodoo_display.c + vid_voodoo_fb.c + vid_voodoo_fifo.c + vid_voodoo_reg.c + vid_voodoo_render.c + vid_voodoo_setup.c + vid_voodoo_texture.c +) if(NOT MSVC AND (ARCH STREQUAL "i386" OR ARCH STREQUAL "x86_64")) target_compile_options(voodoo PRIVATE "-msse2") diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 1c81e8166..73abfe1ed 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -47,7 +47,6 @@ # undef CLAMP #endif - #define BIOS_MACH8_ROM_PATH "roms/video/mach8/11301113140_4k.BIN" static void ibm8514_accel_outb(uint16_t port, uint8_t val, void *priv); @@ -84,14 +83,14 @@ CLAMP(int16_t in, int16_t min, int16_t max) return in; } -#define WRITE8(addr, var, val) \ - switch ((addr) & 1) { \ - case 0: \ - var = (var & 0xff00) | (val); \ - break; \ - case 1: \ - var = (var & 0x00ff) | ((val) << 8); \ - break; \ +#define WRITE8(addr, var, val) \ + switch ((addr) & 1) { \ + case 0: \ + var = (var & 0xff00) | (val); \ + break; \ + case 1: \ + var = (var & 0x00ff) | ((val) << 8); \ + break; \ } #define READ8(addr, var) \ @@ -105,139 +104,139 @@ CLAMP(int16_t in, int16_t min, int16_t max) } -#define READ_PIXTRANS_WORD(cx, n) \ - if ((cmd <= 1) || (cmd == 5)) { \ +#define READ_PIXTRANS_WORD(cx, n) \ + if ((cmd <= 1) || (cmd == 5)) { \ temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ - } else { \ - temp = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[(dev->accel.dest + (cx) + (n + 1)) & dev->vram_mask] << 8); \ - } \ + } else { \ + temp = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[(dev->accel.dest + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ -#define READ(addr, dat) \ - if (dev->bpp) \ +#define READ(addr, dat) \ + if (dev->bpp) \ dat = vram_w[(addr) & (dev->vram_mask >> 1)]; \ - else \ + else \ dat = (dev->vram[(addr) & (dev->vram_mask)]); \ -#define READ_HIGH(addr, dat) \ +#define READ_HIGH(addr, dat) \ dat |= (dev->vram[(addr) & (dev->vram_mask)] << 8); -#define MIX(mixmode, dest_dat, src_dat) \ - { \ - switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ - case 0x00: \ - dest_dat = ~dest_dat; \ - break; \ - case 0x01: \ - dest_dat = 0; \ - break; \ - case 0x02: \ - dest_dat = ~0; \ - break; \ - case 0x03: \ - dest_dat = dest_dat; \ - break; \ - case 0x04: \ - dest_dat = ~src_dat; \ - break; \ - case 0x05: \ - dest_dat = src_dat ^ dest_dat; \ - break; \ - case 0x06: \ - dest_dat = ~(src_dat ^ dest_dat); \ - break; \ - case 0x07: \ - dest_dat = src_dat; \ - break; \ - case 0x08: \ - dest_dat = ~(src_dat & dest_dat); \ - break; \ - case 0x09: \ - dest_dat = ~src_dat | dest_dat; \ - break; \ - case 0x0a: \ - dest_dat = src_dat | ~dest_dat; \ - break; \ - case 0x0b: \ - dest_dat = src_dat | dest_dat; \ - break; \ - case 0x0c: \ - dest_dat = src_dat & dest_dat; \ - break; \ - case 0x0d: \ - dest_dat = src_dat & ~dest_dat; \ - break; \ - case 0x0e: \ - dest_dat = ~src_dat & dest_dat; \ - break; \ - case 0x0f: \ - dest_dat = ~(src_dat | dest_dat); \ - break; \ - case 0x10: \ - dest_dat = MIN(src_dat, dest_dat); \ - break; \ - case 0x11: \ - dest_dat = dest_dat - src_dat; \ - break; \ - case 0x12: \ - dest_dat = src_dat - dest_dat; \ - break; \ - case 0x13: \ - dest_dat = src_dat + dest_dat; \ - break; \ - case 0x14: \ - dest_dat = MAX(src_dat, dest_dat); \ - break; \ - case 0x15: \ - dest_dat = (dest_dat - src_dat) >> 1; \ - break; \ - case 0x16: \ - dest_dat = (src_dat - dest_dat) >> 1; \ - break; \ - case 0x17: \ - dest_dat = (dest_dat + src_dat) >> 1; \ - break; \ - case 0x18: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ - case 0x19: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ - case 0x1a: \ - dest_dat = MAX(0, (src_dat - dest_dat)); \ - break; \ - case 0x1b: \ - if (dev->bpp) \ - dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ - else \ - dest_dat = MIN(0xff, (dest_dat + src_dat)); \ - break; \ - case 0x1c: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ - case 0x1d: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ - case 0x1e: \ - dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ - break; \ - case 0x1f: \ - if (dev->bpp) \ +#define MIX(mixmode, dest_dat, src_dat) \ + { \ + switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + case 0x00: \ + dest_dat = ~dest_dat; \ + break; \ + case 0x01: \ + dest_dat = 0; \ + break; \ + case 0x02: \ + dest_dat = ~0; \ + break; \ + case 0x03: \ + dest_dat = dest_dat; \ + break; \ + case 0x04: \ + dest_dat = ~src_dat; \ + break; \ + case 0x05: \ + dest_dat = src_dat ^ dest_dat; \ + break; \ + case 0x06: \ + dest_dat = ~(src_dat ^ dest_dat); \ + break; \ + case 0x07: \ + dest_dat = src_dat; \ + break; \ + case 0x08: \ + dest_dat = ~(src_dat & dest_dat); \ + break; \ + case 0x09: \ + dest_dat = ~src_dat | dest_dat; \ + break; \ + case 0x0a: \ + dest_dat = src_dat | ~dest_dat; \ + break; \ + case 0x0b: \ + dest_dat = src_dat | dest_dat; \ + break; \ + case 0x0c: \ + dest_dat = src_dat & dest_dat; \ + break; \ + case 0x0d: \ + dest_dat = src_dat & ~dest_dat; \ + break; \ + case 0x0e: \ + dest_dat = ~src_dat & dest_dat; \ + break; \ + case 0x0f: \ + dest_dat = ~(src_dat | dest_dat); \ + break; \ + case 0x10: \ + dest_dat = MIN(src_dat, dest_dat); \ + break; \ + case 0x11: \ + dest_dat = dest_dat - src_dat; \ + break; \ + case 0x12: \ + dest_dat = src_dat - dest_dat; \ + break; \ + case 0x13: \ + dest_dat = src_dat + dest_dat; \ + break; \ + case 0x14: \ + dest_dat = MAX(src_dat, dest_dat); \ + break; \ + case 0x15: \ + dest_dat = (dest_dat - src_dat) >> 1; \ + break; \ + case 0x16: \ + dest_dat = (src_dat - dest_dat) >> 1; \ + break; \ + case 0x17: \ + dest_dat = (dest_dat + src_dat) >> 1; \ + break; \ + case 0x18: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x19: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x1a: \ + dest_dat = MAX(0, (src_dat - dest_dat)); \ + break; \ + case 0x1b: \ + if (dev->bpp) \ + dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ + else \ + dest_dat = MIN(0xff, (dest_dat + src_dat)); \ + break; \ + case 0x1c: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1d: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1e: \ + dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ + break; \ + case 0x1f: \ + if (dev->bpp) \ dest_dat = (0xffff < (src_dat + dest_dat)) ? 0xffff : ((src_dat + dest_dat) / 2); \ - else \ - dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ - break; \ - } \ + else \ + dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ + break; \ + } \ } -#define WRITE(addr, dat) \ - if (dev->bpp) { \ - vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ +#define WRITE(addr, dat) \ + if (dev->bpp) { \ + vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = changeframecount; \ - } else { \ - dev->vram[((addr)) & (dev->vram_mask)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + } else { \ + dev->vram[((addr)) & (dev->vram_mask)] = dat; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ } int ibm8514_active = 0; diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index b3a544fc1..1d2326192 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -1508,16 +1508,16 @@ mach64_start_line(mach64_t *mach64) mach64->accel.op = OP_LINE; } -#define READ(addr, dat, width) \ - if (width == 0) \ - dat = svga->vram[((addr)) & mach64->vram_mask]; \ - else if (width == 1) \ - dat = *(uint16_t *) &svga->vram[((addr) << 1) & mach64->vram_mask]; \ - else if (width == 2) \ - dat = *(uint32_t *) &svga->vram[((addr) << 2) & mach64->vram_mask]; \ - else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) &7)) & 1; \ - else \ +#define READ(addr, dat, width) \ + if (width == 0) \ + dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) \ + dat = *(uint16_t *) &svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) \ + dat = *(uint32_t *) &svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) &7)) & 1; \ + else \ dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) &7))) & 1; #define MIX \ @@ -1575,29 +1575,29 @@ mach64_start_line(mach64_t *mach64) break; \ } -#define WRITE(addr, width) \ - if (width == 0) { \ - svga->vram[(addr) &mach64->vram_mask] = dest_dat; \ - svga->changedvram[((addr) &mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ - } else if (width == 1) { \ - *(uint16_t *) &svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ - svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ - } else if (width == 2) { \ - *(uint32_t *) &svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ - svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ - } else { \ - if (dest_dat & 1) { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) &7); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) &7)); \ - } else { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) &7)); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) &7))); \ - } \ - svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ +#define WRITE(addr, width) \ + if (width == 0) { \ + svga->vram[(addr) &mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) &mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ + } else if (width == 1) { \ + *(uint16_t *) &svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ + } else if (width == 2) { \ + *(uint32_t *) &svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ + } else { \ + if (dest_dat & 1) { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) &7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) &7)); \ + } else { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) &7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) &7))); \ + } \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ } void diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index a923ea7e2..5cd29d814 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -49,10 +49,10 @@ #define BIOS_MACH32_MCA_ROM_PATH "roms/video/mach32/MACH32MCA_Olivetti.BIN" #define BIOS_MACH32_PCI_ROM_PATH "roms/video/mach32/intelopt_00000.rom" -static video_timings_t timing_gfxultra_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; -static video_timings_t timing_mach32_vlb = { .type = VIDEO_BUS, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; -static video_timings_t timing_mach32_mca = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 }; -static video_timings_t timing_mach32_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +static video_timings_t timing_gfxultra_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; +static video_timings_t timing_mach32_vlb = { .type = VIDEO_BUS, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; +static video_timings_t timing_mach32_mca = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 }; +static video_timings_t timing_mach32_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 20, .read_w = 20, .read_l = 21 }; static void mach_accel_outb(uint16_t port, uint8_t val, void *priv); static void mach_accel_outw(uint16_t port, uint16_t val, void *priv); @@ -88,14 +88,14 @@ mach_log(const char *fmt, ...) # define mach_log(fmt, ...) #endif -#define WRITE8(addr, var, val) \ - switch ((addr) & 1) { \ - case 0: \ - var = (var & 0xff00) | (val); \ - break; \ - case 1: \ - var = (var & 0x00ff) | ((val) << 8); \ - break; \ +#define WRITE8(addr, var, val) \ + switch ((addr) & 1) { \ + case 0: \ + var = (var & 0xff00) | (val); \ + break; \ + case 1: \ + var = (var & 0x00ff) | ((val) << 8); \ + break; \ } #define READ8(addr, var) \ @@ -110,166 +110,164 @@ mach_log(const char *fmt, ...) #define READ_PIXTRANS_BYTE_IO(cx, n) \ if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ - if (dev->bpp) { \ - if (n == 0)\ + if (dev->bpp) { \ + if (n == 0) \ mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (dev->vram_mask >> 1)] & 0xff; \ - else \ - mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (dev->vram_mask >> 1)] >> 8; \ - \ - } else \ - mach->accel.pix_trans[(n)] = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ - \ + else \ + mach->accel.pix_trans[(n)] = vram_w[(dev->accel.dest + (cx) + (n)) & (dev->vram_mask >> 1)] >> 8; \ + } else \ + mach->accel.pix_trans[(n)] = dev->vram[(dev->accel.dest + (cx) + (n)) & dev->vram_mask]; \ } -#define READ_PIXTRANS_WORD(cx, n) \ - if ((cmd == 0) || (cmd == 1) || (cmd == 5) || (mach->accel.cmd_type == -1)) { \ - if (dev->bpp) \ - temp = vram_w[((dev->accel.cy * dev->pitch) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ - else { \ - temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ - } \ - } else if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ - if (dev->bpp) \ - temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ - else { \ - temp = dev->vram[((dev->accel.dest) + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[((dev->accel.dest) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ - } \ - } else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \ - if (dev->bpp) \ - temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ - else { \ - temp = dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & dev->vram_mask]; \ +#define READ_PIXTRANS_WORD(cx, n) \ + if ((cmd == 0) || (cmd == 1) || (cmd == 5) || (mach->accel.cmd_type == -1)) { \ + if (dev->bpp) \ + temp = vram_w[((dev->accel.cy * dev->pitch) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ + else { \ + temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ + } else if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ + if (dev->bpp) \ + temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ + else { \ + temp = dev->vram[((dev->accel.dest) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[((dev->accel.dest) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + } \ + } else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \ + if (dev->bpp) \ + temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ + else { \ + temp = dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & dev->vram_mask]; \ temp |= (dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ - } \ + } \ } -#define READ(addr, dat) \ - if (dev->bpp) \ +#define READ(addr, dat) \ + if (dev->bpp) \ dat = vram_w[(addr) & (dev->vram_mask >> 1)]; \ - else \ + else \ dat = (dev->vram[(addr) & (dev->vram_mask)]); -#define READ_HIGH(addr, dat) \ +#define READ_HIGH(addr, dat) \ dat |= (dev->vram[(addr) & (dev->vram_mask)] << 8); -#define MIX(mixmode, dest_dat, src_dat) \ - { \ - switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ - case 0x00: \ - dest_dat = ~dest_dat; \ - break; \ - case 0x01: \ - dest_dat = 0; \ - break; \ - case 0x02: \ - dest_dat = ~0; \ - break; \ - case 0x03: \ - dest_dat = dest_dat; \ - break; \ - case 0x04: \ - dest_dat = ~src_dat; \ - break; \ - case 0x05: \ - dest_dat = src_dat ^ dest_dat; \ - break; \ - case 0x06: \ - dest_dat = ~(src_dat ^ dest_dat); \ - break; \ - case 0x07: \ - dest_dat = src_dat; \ - break; \ - case 0x08: \ - dest_dat = ~(src_dat & dest_dat); \ - break; \ - case 0x09: \ - dest_dat = ~src_dat | dest_dat; \ - break; \ - case 0x0a: \ - dest_dat = src_dat | ~dest_dat; \ - break; \ - case 0x0b: \ - dest_dat = src_dat | dest_dat; \ - break; \ - case 0x0c: \ - dest_dat = src_dat & dest_dat; \ - break; \ - case 0x0d: \ - dest_dat = src_dat & ~dest_dat; \ - break; \ - case 0x0e: \ - dest_dat = ~src_dat & dest_dat; \ - break; \ - case 0x0f: \ - dest_dat = ~(src_dat | dest_dat); \ - break; \ - case 0x10: \ - dest_dat = MIN(src_dat, dest_dat); \ - break; \ - case 0x11: \ - dest_dat = dest_dat - src_dat; \ - break; \ - case 0x12: \ - dest_dat = src_dat - dest_dat; \ - break; \ - case 0x13: \ - dest_dat = src_dat + dest_dat; \ - break; \ - case 0x14: \ - dest_dat = MAX(src_dat, dest_dat); \ - break; \ - case 0x15: \ - dest_dat = (dest_dat - src_dat) / 2; \ - break; \ - case 0x16: \ - dest_dat = (src_dat - dest_dat) / 2; \ - break; \ - case 0x17: \ - dest_dat = (dest_dat + src_dat) / 2; \ - break; \ - case 0x18: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ - case 0x19: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ - case 0x1a: \ - dest_dat = MAX(0, (src_dat - dest_dat)); \ - break; \ - case 0x1b: \ - if (dev->bpp) \ - dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ - else \ - dest_dat = MIN(0xff, (dest_dat + src_dat)); \ - break; \ - case 0x1c: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ - case 0x1d: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ - case 0x1e: \ - dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ - break; \ - case 0x1f: \ - if (dev->bpp) \ +#define MIX(mixmode, dest_dat, src_dat) \ + { \ + switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + case 0x00: \ + dest_dat = ~dest_dat; \ + break; \ + case 0x01: \ + dest_dat = 0; \ + break; \ + case 0x02: \ + dest_dat = ~0; \ + break; \ + case 0x03: \ + dest_dat = dest_dat; \ + break; \ + case 0x04: \ + dest_dat = ~src_dat; \ + break; \ + case 0x05: \ + dest_dat = src_dat ^ dest_dat; \ + break; \ + case 0x06: \ + dest_dat = ~(src_dat ^ dest_dat); \ + break; \ + case 0x07: \ + dest_dat = src_dat; \ + break; \ + case 0x08: \ + dest_dat = ~(src_dat & dest_dat); \ + break; \ + case 0x09: \ + dest_dat = ~src_dat | dest_dat; \ + break; \ + case 0x0a: \ + dest_dat = src_dat | ~dest_dat; \ + break; \ + case 0x0b: \ + dest_dat = src_dat | dest_dat; \ + break; \ + case 0x0c: \ + dest_dat = src_dat & dest_dat; \ + break; \ + case 0x0d: \ + dest_dat = src_dat & ~dest_dat; \ + break; \ + case 0x0e: \ + dest_dat = ~src_dat & dest_dat; \ + break; \ + case 0x0f: \ + dest_dat = ~(src_dat | dest_dat); \ + break; \ + case 0x10: \ + dest_dat = MIN(src_dat, dest_dat); \ + break; \ + case 0x11: \ + dest_dat = dest_dat - src_dat; \ + break; \ + case 0x12: \ + dest_dat = src_dat - dest_dat; \ + break; \ + case 0x13: \ + dest_dat = src_dat + dest_dat; \ + break; \ + case 0x14: \ + dest_dat = MAX(src_dat, dest_dat); \ + break; \ + case 0x15: \ + dest_dat = (dest_dat - src_dat) / 2; \ + break; \ + case 0x16: \ + dest_dat = (src_dat - dest_dat) / 2; \ + break; \ + case 0x17: \ + dest_dat = (dest_dat + src_dat) / 2; \ + break; \ + case 0x18: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x19: \ + dest_dat = MAX(0, (dest_dat - src_dat)); \ + break; \ + case 0x1a: \ + dest_dat = MAX(0, (src_dat - dest_dat)); \ + break; \ + case 0x1b: \ + if (dev->bpp) \ + dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ + else \ + dest_dat = MIN(0xff, (dest_dat + src_dat)); \ + break; \ + case 0x1c: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1d: \ + dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + break; \ + case 0x1e: \ + dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ + break; \ + case 0x1f: \ + if (dev->bpp) \ dest_dat = (0xffff < (src_dat + dest_dat)) ? 0xffff : ((src_dat + dest_dat) / 2); \ - else \ - dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ - break; \ - } \ + else \ + dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ + break; \ + } \ } -#define WRITE(addr, dat) \ - if (dev->bpp) { \ - vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ +#define WRITE(addr, dat) \ + if (dev->bpp) { \ + vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = changeframecount; \ - } else { \ - dev->vram[((addr)) & (dev->vram_mask)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + } else { \ + dev->vram[((addr)) & (dev->vram_mask)] = dat; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ } static int @@ -338,7 +336,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if ((dev->accel_bpp == 8) || (dev->accel_bpp == 15) || (dev->accel_bpp == 16) || (dev->accel_bpp == 24)) - mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); + mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", + dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, + mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -366,7 +366,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.stepx = (mach->accel.linedraw_opt & 0x20) ? 1 : -1; mach->accel.stepy = (mach->accel.linedraw_opt & 0x80) ? 1 : -1; - mach_log("Extended bresenham, CUR(%d,%d), DEST(%d,%d), width = %d, options = %04x, dpconfig = %04x, opt_ena = %03x.\n", dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.linedraw_opt, mach->accel.dp_config, mach->accel.max_waitstates & 0x100); + mach_log("Extended bresenham, CUR(%d,%d), DEST(%d,%d), width = %d, options = %04x, dpconfig = %04x, opt_ena = %03x.\n", + dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.linedraw_opt, + mach->accel.dp_config, mach->accel.max_waitstates & 0x100); if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { if (mach_pixel_write(mach)) { @@ -853,11 +855,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.stepx = -1; if (dev->accel.dx > 0) dev->accel.dx--; - mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n", mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx, mach->accel.dp_config); + mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n", + mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx, + mach->accel.dp_config); } else { mach->accel.stepx = 1; mach->accel.width = 0; - mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n", mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start); + mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n", + mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start); } dev->accel.sx = 0; @@ -914,17 +919,23 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.sx_end > mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start); mach->accel.src_stepx = 1; - mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, + mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); } else if (mach->accel.sx_end < mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end); mach->accel.src_stepx = -1; if (dev->accel.cx > 0) dev->accel.cx--; - mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config + mach->accel.src_width & 1); } else { mach->accel.src_stepx = 1; mach->accel.src_width = 0; - mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, + mach->accel.dp_config, mach->accel.src_width & 1); } mach->accel.sx = 0; if (mach->accel.patt_data_idx < 16) @@ -996,7 +1007,8 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (cpu_input) { if (mach->accel.dp_config == 0x3251) { - mach_log("DPCONFIG 3251: monosrc=%d, frgdsel=%d, bkgdsel=%d, pitch=%d.\n", mono_src, frgd_sel, bkgd_sel, dev->pitch); + mach_log("DPCONFIG 3251: monosrc=%d, frgdsel=%d, bkgdsel=%d, pitch=%d.\n", + mono_src, frgd_sel, bkgd_sel, dev->pitch); if (dev->accel.sy == mach->accel.height) { mach_log("No Blit on DPCONFIG=3251.\n"); dev->accel.cmd_back = 1; @@ -1156,7 +1168,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 cpu_dat >>= 8; if (mach->accel.dp_config == 0x2071 || (mach->accel.dp_config == 0x2011)) - mach_log("FontBlit: SX=%d, C(%d,%d), SRCWidth=%d, frgdmix=%d, bkgdmix=%d, rdmask=%04x, D(%d,%d), geoffset=%x, addr=%08x,.\n", mach->accel.sx, dev->accel.cx, dev->accel.cy, mach->accel.src_width, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, rd_mask, dev->accel.dx, dev->accel.dy, dev->accel.ge_offset, (dev->accel.src + dev->accel.cx) & dev->vram_mask); + mach_log("FontBlit: SX=%d, C(%d,%d), SRCWidth=%d, frgdmix=%d, bkgdmix=%d, rdmask=%04x, D(%d,%d), geoffset=%x, addr=%08x,.\n", + mach->accel.sx, dev->accel.cx, dev->accel.cy, mach->accel.src_width, dev->accel.frgd_mix & 0x1f, + dev->accel.bkgd_mix & 0x1f, rd_mask, dev->accel.dx, dev->accel.dy, dev->accel.ge_offset, + (dev->accel.src + dev->accel.cx) & dev->vram_mask); if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) { dev->accel.cx += mach->accel.src_stepx; @@ -1248,7 +1263,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.sx = 0; - mach_log("Linedraw: c(%d,%d), d(%d,%d), cend(%d,%d), bounds: l=%d, r=%d, t=%d, b=%d.\n", dev->accel.cur_x, dev->accel.cur_y, dev->accel.dx, dev->accel.dy, mach->accel.cx_end_line, mach->accel.cy_end_line, mach->accel.bleft, mach->accel.bright, mach->accel.btop, mach->accel.bbottom); + mach_log("Linedraw: c(%d,%d), d(%d,%d), cend(%d,%d), bounds: l=%d, r=%d, t=%d, b=%d.\n", + dev->accel.cur_x, dev->accel.cur_y, dev->accel.dx, dev->accel.dy, mach->accel.cx_end_line, + mach->accel.cy_end_line, mach->accel.bleft, mach->accel.bright, mach->accel.btop, mach->accel.bbottom); if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { if (mach_pixel_write(mach)) { @@ -1944,7 +1961,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); - mach_log("ScanToX=%04x, MonoSRC=%d, FrgdSel=%d, BkgdSel=%d, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), colorpattidx=%d, pattlen=%d.\n", mach->accel.dp_config, mono_src, frgd_sel, bkgd_sel, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, mach->accel.width, mach->accel.height, mach->accel.color_pattern_idx, mach->accel.patt_len); + mach_log("ScanToX=%04x, MonoSRC=%d, FrgdSel=%d, BkgdSel=%d, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), colorpattidx=%d, pattlen=%d.\n", + mach->accel.dp_config, mono_src, frgd_sel, bkgd_sel, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, + mach->accel.width, mach->accel.height, mach->accel.color_pattern_idx, mach->accel.patt_len); if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { if (mach_pixel_write(mach)) { @@ -2197,9 +2216,11 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (((dev->disp_cntl & 0x60) == 0x20) && ((dev->local & 0xff) >= 0x02)) { if ((addr >= 0x3c6) && (addr <= 0x3c9)) { - mach_log("VGA DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); + mach_log("VGA DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", + addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); } else if ((addr >= 0x2ea) && (addr <= 0x2ed)) - mach_log("8514/A DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); + mach_log("8514/A DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", + addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); } switch (addr) { @@ -2609,7 +2630,8 @@ ati8514_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; - mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); + mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", + dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); if (mach->accel.clock_sel & 0x01) { dev->h_disp = dev->hdisp; @@ -2637,7 +2659,9 @@ ati8514_recalctimings(svga_t *svga) if (dev->interlace) dev->dispend >>= 1; - mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); + mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", + dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, + mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); if (dev->vram_512k_8514) { if (dev->h_disp == 640) { dev->ext_pitch = 640; @@ -2713,7 +2737,9 @@ mach_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; - mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x, interlace=%x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0xfe, dev->interlace); + mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x, interlace=%x.\n", + dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, + mach->accel.clock_sel & 0xfe, dev->interlace); if ((dev->local & 0xff) >= 0x02) { if (dev->bpp || ((mach->accel.ext_ge_config & 0x30) == 0x30) || (mach->accel.clock_sel & 0x01)) { dev->h_disp = dev->hdisp; @@ -2788,7 +2814,9 @@ mach_recalctimings(svga_t *svga) } svga->render8514 = ibm8514_render_blank; - mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, dev->accel_bpp, mach->shadow_set & 3, svga->hdisp); + mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", + dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, + dev->accel_bpp, mach->shadow_set & 3, svga->hdisp); switch (dev->accel_bpp) { case 8: svga->render8514 = ibm8514_render_8bpp; @@ -2814,7 +2842,9 @@ mach_recalctimings(svga_t *svga) } } else { svga->render8514 = ibm8514_render_blank; - mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); + mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", + dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, + mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); if (dev->vram_512k_8514) { if (dev->h_disp == 640) { dev->ext_pitch = 640; @@ -2829,7 +2859,8 @@ mach_recalctimings(svga_t *svga) } } else { if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { - mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d.\n", svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on); + mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d.\n", + svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on); if ((svga->gdcreg[6] & 0x01) || (svga->attrregs[0x10] & 0x01)) { if ((svga->gdcreg[5] & 0x40) || (svga->attrregs[0x10] & 0x40) || (mach->regs[0xb0] & 0x20)) { svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); @@ -3405,7 +3436,8 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 } else if (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01)) dev->hdisp2 = (val + 1) << 3; } - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x, shadowcntl=%02x, shadowset=%02x.\n", CS, cpu_state.pc, port, val, mach->shadow_cntl & 0x08, mach->shadow_set & 0x03); + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x, shadowcntl=%02x, shadowset=%02x.\n", + CS, cpu_state.pc, port, val, mach->shadow_cntl & 0x08, mach->shadow_set & 0x03); svga_recalctimings(svga); break; @@ -3475,7 +3507,8 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 dev->interlace = !!(dev->disp_cntl & 0x10); } } - mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n", port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace); + mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n", + port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace); svga_recalctimings(svga); break; @@ -3483,7 +3516,8 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 dev->accel.advfunc_cntl = val; dev->on = dev->accel.advfunc_cntl & 0x01; dev->vendor_mode = 0; - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", + CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); if ((dev->local & 0xff) < 0x02) { dev->ext_crt_pitch = 128; @@ -3630,8 +3664,10 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 WRITE8(port, mach->accel.clock_sel, val); dev->on = mach->accel.clock_sel & 0x01; dev->vendor_mode = 1; - mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d.\n", port, mach->accel.clock_sel & 0x01, val, dev->hdisp, dev->vdisp); - mach_log("Vendor ATI mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); + mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d.\n", + port, mach->accel.clock_sel & 0x01, val, dev->hdisp, dev->vdisp); + mach_log("Vendor ATI mode set %s resolution.\n", + (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); svga_recalctimings(svga); if ((dev->local & 0xff) >= 0x01) mach32_updatemapping(mach, svga); @@ -5160,7 +5196,8 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_accel_outb(0x02e8 + (addr & 1) + (port_dword << 8), val, mach); } } else { - mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_write_common(addr, val, 1, mach, svga); else @@ -5186,7 +5223,8 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8), val, mach); } } else { - mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_writew_linear(addr, val, mach); else @@ -5214,7 +5252,8 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); } } else { - mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_writel_linear(addr, val, mach); else @@ -5354,7 +5393,8 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) } } - mach_log("Linear base = %08x, aperture = %04x, localcntl = %02x svgagdc = %x.\n", mach->linear_base, mach->memory_aperture, mach->local_cntl, svga->gdcreg[6] & 0x0c); + mach_log("Linear base = %08x, aperture = %04x, localcntl = %02x svgagdc = %x.\n", + mach->linear_base, mach->memory_aperture, mach->local_cntl, svga->gdcreg[6] & 0x0c); if (mach->linear_base) { if (((mach->memory_aperture & 3) == 1) && !mach->pci_bus) { /*1 MB aperture*/ @@ -5832,7 +5872,8 @@ mach_mca_write(int port, uint8_t val, void *priv) return; mach->pos_regs[port & 7] = val; - mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", CS, port & 7, mach->pos_regs[port & 7], (((mach->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000); + mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", + CS, port & 7, mach->pos_regs[port & 7], (((mach->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000); mem_mapping_disable(&mach->bios_rom.mapping); mem_mapping_disable(&mach->bios_rom2.mapping); if (mach->pos_regs[2] & 0x01) { @@ -5882,7 +5923,8 @@ ati8514_mca_write(int port, uint8_t val, void *priv) return; dev->pos_regs[port & 7] = val; - mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", CS, port & 7, dev->pos_regs[port & 7], (((dev->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000); + mach_log("[%04X]: MCA write port = %x, val = %02x, biosaddr = %05x.\n", + CS, port & 7, dev->pos_regs[port & 7], (((dev->pos_regs[3] & 0x3e) << 0x0c) >> 1) + 0xc0000); mem_mapping_disable(&dev->bios_rom.mapping); if (dev->pos_regs[2] & 0x01) diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index d580f0c06..6ad6a6b0a 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -44,22 +44,22 @@ static const double tau = 6.28318531; /* == 2*pi */ static unsigned char chroma_multiplexer[256] = { // clang-format off - 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, - 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, - 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, - 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, - 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, - 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, - 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, - 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, - 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, - 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, - 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, - 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, - 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, - 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, - 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, - 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252 + 2, 2, 2, 2, 114, 174, 4, 3, 2, 1, 133, 135, 2, 113, 150, 4, + 133, 2, 1, 99, 151, 152, 2, 1, 3, 2, 96, 136, 151, 152, 151, 152, + 2, 56, 62, 4, 111, 250, 118, 4, 0, 51, 207, 137, 1, 171, 209, 5, + 140, 50, 54, 100, 133, 202, 57, 4, 2, 50, 153, 149, 128, 198, 198, 135, + 32, 1, 36, 81, 147, 158, 1, 42, 33, 1, 210, 254, 34, 109, 169, 77, + 177, 2, 0, 165, 189, 154, 3, 44, 33, 0, 91, 197, 178, 142, 144, 192, + 4, 2, 61, 67, 117, 151, 112, 83, 4, 0, 249, 255, 3, 107, 249, 117, + 147, 1, 50, 162, 143, 141, 52, 54, 3, 0, 145, 206, 124, 123, 192, 193, + 72, 78, 2, 0, 159, 208, 4, 0, 53, 58, 164, 159, 37, 159, 171, 1, + 248, 117, 4, 98, 212, 218, 5, 2, 54, 59, 93, 121, 176, 181, 134, 130, + 1, 61, 31, 0, 160, 255, 34, 1, 1, 58, 197, 166, 0, 177, 194, 2, + 162, 111, 34, 96, 205, 253, 32, 1, 1, 57, 123, 125, 119, 188, 150, 112, + 78, 4, 0, 75, 166, 180, 20, 38, 78, 1, 143, 246, 42, 113, 156, 37, + 252, 4, 1, 188, 175, 129, 1, 37, 118, 4, 88, 249, 202, 150, 145, 200, + 61, 59, 60, 60, 228, 252, 117, 77, 60, 58, 248, 251, 81, 212, 254, 107, + 198, 59, 58, 169, 250, 251, 81, 80, 100, 58, 154, 250, 251, 252, 252, 252 // clang-format on }; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 169dc659b..120505dc5 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -82,8 +82,8 @@ typedef struct { rom_t bios_rom; uint8_t banking; - uint32_t vram_size, - vram_mask; + uint32_t vram_size; + uint32_t vram_mask; uint8_t port_22cb_val; uint8_t port_32cb_val; diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 9ee74f512..b3cbdd999 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -427,8 +427,7 @@ enum { DMA_STATE_SEC }; -typedef struct -{ +typedef struct { uint32_t addr_type; uint32_t val; } fifo_entry_t; @@ -484,13 +483,11 @@ typedef struct mystique_t { event_t *wake_fifo_thread, *fifo_not_full_event; - struct - { + struct { int m, n, p, s; } xpixpll[3]; - struct - { + struct { uint8_t funcnt : 7, stylelen, dmamod; @@ -521,27 +518,23 @@ typedef struct mystique_t { uint64_t extended_dr[4]; - struct - { + struct { int sdydxl, scanleft, sdxl, sdy, sdxr; } sgn; } dwgreg; - struct - { + struct { uint8_t r, g, b; } lut[256]; - struct - { + struct { uint16_t pos_x, pos_y, addr; uint32_t col[3]; } cursor; - struct - { + struct { atomic_int pri_state, sec_state, iload_state, state; atomic_uint primaddress, primend, secaddress, secend, diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 8e3241efd..89d65a1f8 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -68,7 +68,7 @@ typedef struct paradise_t { } paradise_t; static video_timings_t timing_paradise_pvga1a = { .type = VIDEO_ISA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 }; -static video_timings_t timing_paradise_wd90c = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; +static video_timings_t timing_paradise_wd90c = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; void paradise_remap(paradise_t *paradise); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 7e3b7a2ef..52135b066 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -537,15 +537,15 @@ static void s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3); #define READ_PIXTRANS_BYTE_MM \ temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; -#define READ_PIXTRANS_WORD \ - if ((s3->bpp == 0) && !s3->color_16bit) { \ - temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ - temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ - } else \ +#define READ_PIXTRANS_WORD \ + if ((s3->bpp == 0) && !s3->color_16bit) { \ + temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ + temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ + } else \ temp = vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx - s3->accel.minus)) & (s3->vram_mask >> 1)]; #define READ_PIXTRANS_LONG \ - if ((s3->bpp == 0) && !s3->color_16bit) { \ + if ((s3->bpp == 0) && !s3->color_16bit) { \ temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 2)) & s3->vram_mask] << 16); \ @@ -6583,9 +6583,9 @@ polygon_setup(s3_t *s3) #define READ(addr, dat) \ if (((s3->bpp == 0) && !s3->color_16bit) || (s3->bpp == 2)) \ dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ - else if ((s3->bpp == 1) || s3->color_16bit) \ + else if ((s3->bpp == 1) || s3->color_16bit) \ dat = vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)]; \ - else \ + else \ dat = vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)]; #define MIX_READ \ @@ -6642,11 +6642,11 @@ polygon_setup(s3_t *s3) } \ } -#define MIX \ - { \ - old_dest_dat = dest_dat; \ - MIX_READ \ - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); \ +#define MIX \ + { \ + old_dest_dat = dest_dat; \ + MIX_READ \ + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); \ } #define ROPMIX_READ(D, P, S) \ @@ -7431,14 +7431,14 @@ polygon_setup(s3_t *s3) } #define WRITE(addr, dat) \ - if (((s3->bpp == 0) && !s3->color_16bit) || (s3->bpp == 2)) { \ - svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ + if (((s3->bpp == 0) && !s3->color_16bit) || (s3->bpp == 2)) { \ + svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ - } else if ((s3->bpp == 1) || s3->color_16bit) { \ + } else if ((s3->bpp == 1) || s3->color_16bit) { \ vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)] = dat; \ svga->changedvram[(dword_remap_w(svga, addr) & (s3->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ } else { \ - vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)] = dat; \ + vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)] = dat; \ svga->changedvram[(dword_remap_l(svga, addr) & (s3->vram_mask >> 2)) >> 10] = svga->monitor->mon_changeframecount; \ } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 3c61f3a57..86876cd0a 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -2088,127 +2088,127 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } } -#define READ(addr, val) \ - do { \ - switch (bpp) { \ - case 0: /*8 bpp*/ \ +#define READ(addr, val) \ + do { \ + switch (bpp) { \ + case 0: /*8 bpp*/ \ val = vram[addr & virge->vram_mask]; \ - break; \ - case 1: /*16 bpp*/ \ + break; \ + case 1: /*16 bpp*/ \ val = *(uint16_t *)&vram[addr & virge->vram_mask]; \ - break; \ - case 2: /*24 bpp*/ \ + break; \ + case 2: /*24 bpp*/ \ val = (*(uint32_t *)&vram[addr & virge->vram_mask]) & 0xffffff; \ - break; \ - } \ + break; \ + } \ } while (0) #define Z_READ(addr) *(uint16_t *)&vram[addr & virge->vram_mask] -#define Z_WRITE(addr, val) \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ +#define Z_WRITE(addr, val) \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ *(uint16_t *)&vram[addr & virge->vram_mask] = val -#define CLIP(x, y) \ - do { \ - if ((virge->s3d.cmd_set & CMD_SET_HC) && \ - (x < virge->s3d.clip_l || x > virge->s3d.clip_r || \ - y < virge->s3d.clip_t || y > virge->s3d.clip_b)) \ - update = 0; \ +#define CLIP(x, y) \ + do { \ + if ((virge->s3d.cmd_set & CMD_SET_HC) && \ + (x < virge->s3d.clip_l || x > virge->s3d.clip_r || \ + y < virge->s3d.clip_t || y > virge->s3d.clip_b)) \ + update = 0; \ } while (0) -#define CLIP_3D(x, y) \ - do { \ - if ((s3d_tri->cmd_set & CMD_SET_HC) && (x < s3d_tri->clip_l || \ - x > s3d_tri->clip_r || y < s3d_tri->clip_t || \ - y > s3d_tri->clip_b)) \ - update = 0; \ +#define CLIP_3D(x, y) \ + do { \ + if ((s3d_tri->cmd_set & CMD_SET_HC) && (x < s3d_tri->clip_l || \ + x > s3d_tri->clip_r || y < s3d_tri->clip_t || \ + y > s3d_tri->clip_b)) \ + update = 0; \ } while (0) -#define Z_CLIP(Zzb, Zs) \ - do { \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ - switch ((s3d_tri->cmd_set >> 20) & 7) { \ - case 0: \ - update = 0; \ - break; \ - case 1: \ - if (Zs <= Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 2: \ - if (Zs != Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 3: \ - if (Zs < Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 4: \ - if (Zs >= Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 5: \ - if (Zs == Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 6: \ - if (Zs > Zzb) \ - update = 0; \ - else \ - Zzb = Zs; \ - break; \ - case 7: \ - update = 1; \ - Zzb = Zs; \ - break; \ - } \ +#define Z_CLIP(Zzb, Zs) \ + do { \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + switch ((s3d_tri->cmd_set >> 20) & 7) { \ + case 0: \ + update = 0; \ + break; \ + case 1: \ + if (Zs <= Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 2: \ + if (Zs != Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 3: \ + if (Zs < Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 4: \ + if (Zs >= Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 5: \ + if (Zs == Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 6: \ + if (Zs > Zzb) \ + update = 0; \ + else \ + Zzb = Zs; \ + break; \ + case 7: \ + update = 1; \ + Zzb = Zs; \ + break; \ + } \ } while (0) -#define MIX() \ - do { \ - int c; \ - for (c = 0; c < 24; c++) { \ - int d = (dest & (1 << c)) ? 1 : 0; \ - if (source & (1 << c)) \ - d |= 2; \ - if (pattern & (1 << c)) \ - d |= 4; \ - if (virge->s3d.rop & (1 << d)) \ - out |= (1 << c); \ - } \ +#define MIX() \ + do { \ + int c; \ + for (c = 0; c < 24; c++) { \ + int d = (dest & (1 << c)) ? 1 : 0; \ + if (source & (1 << c)) \ + d |= 2; \ + if (pattern & (1 << c)) \ + d |= 4; \ + if (virge->s3d.rop & (1 << d)) \ + out |= (1 << c); \ + } \ } while (0) -#define WRITE(addr, val) \ - do { \ - switch (bpp) { \ - case 0: /*8 bpp*/ \ - vram[addr & virge->vram_mask] = val; \ - virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ - changeframecount; \ - break; \ - case 1: /*16 bpp*/ \ - *(uint16_t *)&vram[addr & virge->vram_mask] = val; \ - virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ - changeframecount; \ - break; \ - case 2: /*24 bpp*/ \ - *(uint32_t *)&vram[addr & virge->vram_mask] = (val & 0xffffff) |\ - (vram[(addr + 3) & virge->vram_mask] << 24); \ - virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ - changeframecount; \ - break; \ - } \ +#define WRITE(addr, val) \ + do { \ + switch (bpp) { \ + case 0: /*8 bpp*/ \ + vram[addr & virge->vram_mask] = val; \ + virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ + changeframecount; \ + break; \ + case 1: /*16 bpp*/ \ + *(uint16_t *)&vram[addr & virge->vram_mask] = val; \ + virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ + changeframecount; \ + break; \ + case 2: /*24 bpp*/ \ + *(uint32_t *)&vram[addr & virge->vram_mask] = (val & 0xffffff) | \ + (vram[(addr + 3) & virge->vram_mask] << 24); \ + virge->svga.changedvram[(addr & virge->vram_mask) >> 12] = \ + changeframecount; \ + break; \ + } \ } while (0) static void @@ -2573,23 +2573,23 @@ skip_line: g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \ r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); -#define RGB24_TO_24(val, r, g, b) \ - b = val & 0xff; \ - g = (val & 0xff00) >> 8; \ +#define RGB24_TO_24(val, r, g, b) \ + b = val & 0xff; \ + g = (val & 0xff00) >> 8; \ r = (val & 0xff0000) >> 16 -#define RGB15(r, g, b, dest) \ - if (virge->dithering_enabled) { \ - int add = dither[_y & 3][_x & 3]; \ - int _r = (r > 248) ? 248 : r + add; \ - int _g = (g > 248) ? 248 : g + add; \ - int _b = (b > 248) ? 248 : b + add; \ - dest = ((_b >> 3) & 0x1f) | \ - (((_g >> 3) & 0x1f) << 5) | \ - (((_r >> 3) & 0x1f) << 10); \ - } else \ - dest = ((b >> 3) & 0x1f) | \ - (((g >> 3) & 0x1f) << 5) | \ +#define RGB15(r, g, b, dest) \ + if (virge->dithering_enabled) { \ + int add = dither[_y & 3][_x & 3]; \ + int _r = (r > 248) ? 248 : r + add; \ + int _g = (g > 248) ? 248 : g + add; \ + int _b = (b > 248) ? 248 : b + add; \ + dest = ((_b >> 3) & 0x1f) | \ + (((_g >> 3) & 0x1f) << 5) | \ + (((_r >> 3) & 0x1f) << 10); \ + } else \ + dest = ((b >> 3) & 0x1f) | \ + (((g >> 3) & 0x1f) << 5) | \ (((r >> 3) & 0x1f) << 10) #define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) @@ -3753,103 +3753,99 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr += 16; } -#define DECODE_YCbCr() \ - do { \ - int c; \ - \ - for (c = 0; c < 2; c++) { \ - uint8_t y1, y2; \ - int8_t Cr; \ - int8_t Cb; \ - int dR; \ - int dG; \ - int dB; \ - \ - y1 = src[0]; \ - Cr = src[1] - 0x80; \ - y2 = src[2]; \ - Cb = src[3] - 0x80; \ - src += 4; \ - \ - dR = (359 * Cr) >> 8; \ - dG = (88 * Cb + 183 * Cr) >> 8; \ - dB = (453 * Cb) >> 8; \ - \ - r[x_write] = y1 + dR; \ - CLAMP(r[x_write]); \ - g[x_write] = y1 - dG; \ - CLAMP(g[x_write]); \ - b[x_write] = y1 + dB; \ - CLAMP(b[x_write]); \ - \ - r[x_write + 1] = y2 + dR; \ - CLAMP(r[x_write + 1]); \ - g[x_write + 1] = y2 - dG; \ - CLAMP(g[x_write + 1]); \ - b[x_write + 1] = y2 + dB; \ - CLAMP(b[x_write + 1]); \ - \ - x_write = (x_write + 2) & 7; \ - } \ +#define DECODE_YCbCr() \ + do { \ + for (uint8_t c = 0; c < 2; c++) { \ + uint8_t y1, y2; \ + int8_t Cr; \ + int8_t Cb; \ + int dR; \ + int dG; \ + int dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359 * Cr) >> 8; \ + dG = (88 * Cb + 183 * Cr) >> 8; \ + dB = (453 * Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write + 1] = y2 + dR; \ + CLAMP(r[x_write + 1]); \ + g[x_write + 1] = y2 - dG; \ + CLAMP(g[x_write + 1]); \ + b[x_write + 1] = y2 + dB; \ + CLAMP(b[x_write + 1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ } while (0) /*Both YUV formats are untested*/ -#define DECODE_YUV211() \ - do { \ - uint8_t y1, y2, y3, y4; \ - int8_t U, V; \ - int dR; \ - int dG; \ - int dB; \ - \ - U = src[0] - 0x80; \ - y1 = (298 * (src[1] - 16)) >> 8; \ - y2 = (298 * (src[2] - 16)) >> 8; \ - V = src[3] - 0x80; \ - y3 = (298 * (src[4] - 16)) >> 8; \ - y4 = (298 * (src[5] - 16)) >> 8; \ - src += 6; \ - \ - dR = (309 * V) >> 8; \ - dG = (100 * U + 208 * V) >> 8; \ - dB = (516 * U) >> 8; \ - \ - r[x_write] = y1 + dR; \ - CLAMP(r[x_write]); \ - g[x_write] = y1 - dG; \ - CLAMP(g[x_write]); \ - b[x_write] = y1 + dB; \ - CLAMP(b[x_write]); \ - \ - r[x_write + 1] = y2 + dR; \ - CLAMP(r[x_write + 1]); \ - g[x_write + 1] = y2 - dG; \ - CLAMP(g[x_write + 1]); \ - b[x_write + 1] = y2 + dB; \ - CLAMP(b[x_write + 1]); \ - \ - r[x_write + 2] = y3 + dR; \ - CLAMP(r[x_write + 2]); \ - g[x_write + 2] = y3 - dG; \ - CLAMP(g[x_write + 2]); \ - b[x_write + 2] = y3 + dB; \ - CLAMP(b[x_write + 2]); \ - \ - r[x_write + 3] = y4 + dR; \ - CLAMP(r[x_write + 3]); \ - g[x_write + 3] = y4 - dG; \ - CLAMP(g[x_write + 3]); \ - b[x_write + 3] = y4 + dB; \ - CLAMP(b[x_write + 3]); \ - \ - x_write = (x_write + 4) & 7; \ +#define DECODE_YUV211() \ + do { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR; \ + int dG; \ + int dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309 * V) >> 8; \ + dG = (100 * U + 208 * V) >> 8; \ + dB = (516 * U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write + 1] = y2 + dR; \ + CLAMP(r[x_write + 1]); \ + g[x_write + 1] = y2 - dG; \ + CLAMP(g[x_write + 1]); \ + b[x_write + 1] = y2 + dB; \ + CLAMP(b[x_write + 1]); \ + \ + r[x_write + 2] = y3 + dR; \ + CLAMP(r[x_write + 2]); \ + g[x_write + 2] = y3 - dG; \ + CLAMP(g[x_write + 2]); \ + b[x_write + 2] = y3 + dB; \ + CLAMP(b[x_write + 2]); \ + \ + r[x_write + 3] = y4 + dR; \ + CLAMP(r[x_write + 3]); \ + g[x_write + 3] = y4 - dG; \ + CLAMP(g[x_write + 3]); \ + b[x_write + 3] = y4 + dB; \ + CLAMP(b[x_write + 3]); \ + \ + x_write = (x_write + 4) & 7; \ } while (0) #define DECODE_YUV422() \ do { \ - int c; \ - \ - for (c = 0; c < 2; c++) { \ + for (uint8_t c = 0; c < 2; c++) { \ uint8_t y1; \ uint8_t y2; \ int8_t U; \ @@ -3886,104 +3882,96 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) } \ } while (0) -#define DECODE_RGB555() \ - do { \ - int c; \ - \ - for (c = 0; c < 4; c++) { \ - uint16_t dat; \ - \ - dat = *(uint16_t *)src; \ - src += 2; \ - \ - r[x_write + c] = \ - ((dat & 0x001f) << 3) | \ - ((dat & 0x001f) >> 2); \ - g[x_write + c] = \ - ((dat & 0x03e0) >> 2) | \ - ((dat & 0x03e0) >> 7); \ - b[x_write + c] = \ - ((dat & 0x7c00) >> 7) | \ - ((dat & 0x7c00) >> 12); \ - } \ - x_write = (x_write + 4) & 7; \ +#define DECODE_RGB555() \ + do { \ + for (uint8_t c = 0; c < 4; c++) { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = \ + ((dat & 0x001f) << 3) | \ + ((dat & 0x001f) >> 2); \ + g[x_write + c] = \ + ((dat & 0x03e0) >> 2) | \ + ((dat & 0x03e0) >> 7); \ + b[x_write + c] = \ + ((dat & 0x7c00) >> 7) | \ + ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ } while (0) -#define DECODE_RGB565() \ - do { \ - int c; \ - \ - for (c = 0; c < 4; c++) { \ - uint16_t dat; \ - \ - dat = *(uint16_t *)src; \ - src += 2; \ - \ - r[x_write + c] = \ - ((dat & 0x001f) << 3) | \ - ((dat & 0x001f) >> 2); \ - g[x_write + c] = \ - ((dat & 0x07e0) >> 3) | \ - ((dat & 0x07e0) >> 9); \ - b[x_write + c] = \ - ((dat & 0xf800) >> 8) | \ - ((dat & 0xf800) >> 13); \ - } \ - x_write = (x_write + 4) & 7; \ +#define DECODE_RGB565() \ + do { \ + for (uint8_t c = 0; c < 4; c++) { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = \ + ((dat & 0x001f) << 3) | \ + ((dat & 0x001f) >> 2); \ + g[x_write + c] = \ + ((dat & 0x07e0) >> 3) | \ + ((dat & 0x07e0) >> 9); \ + b[x_write + c] = \ + ((dat & 0xf800) >> 8) | \ + ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ } while (0) -#define DECODE_RGB888() \ - do { \ - int c; \ - \ - for (c = 0; c < 4; c++) { \ - r[x_write + c] = src[0]; \ - g[x_write + c] = src[1]; \ - b[x_write + c] = src[2]; \ - src += 3; \ - } \ - x_write = (x_write + 4) & 7; \ +#define DECODE_RGB888() \ + do { \ + for (uint8_t c = 0; c < 4; c++) { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ } while (0) -#define DECODE_XRGB8888() \ - do { \ - int c; \ - \ - for (c = 0; c < 4; c++) { \ - r[x_write + c] = src[0]; \ - g[x_write + c] = src[1]; \ - b[x_write + c] = src[2]; \ - src += 4; \ - } \ - x_write = (x_write + 4) & 7; \ +#define DECODE_XRGB8888() \ + do { \ + for (uint8_t c = 0; c < 4; c++) { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ } while (0) -#define OVERLAY_SAMPLE() \ - do { \ - switch (virge->streams.sdif) { \ - case 1: \ - DECODE_YCbCr(); \ - break; \ - case 2: \ - DECODE_YUV422(); \ - break; \ - case 3: \ - DECODE_RGB555(); \ - break; \ - case 4: \ - DECODE_YUV211(); \ - break; \ - case 5: \ - DECODE_RGB565(); \ - break; \ - case 6: \ - DECODE_RGB888(); \ - break; \ - case 7: \ - default: \ - DECODE_XRGB8888(); \ - break; \ - } \ +#define OVERLAY_SAMPLE() \ + do { \ + switch (virge->streams.sdif) { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ } while (0) static void diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index e9fbe57f2..88c26437a 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -112,8 +112,7 @@ typedef struct tgui_t { uint8_t int_line; uint8_t pci_regs[256]; - struct - { + struct { int16_t src_x, src_y; int16_t src_x_clip, src_y_clip; int16_t dst_x, dst_y; @@ -350,7 +349,9 @@ tgui_out(uint16_t addr, uint8_t val, void *priv) if (tgui->ramdac_state == 4) { tgui->ramdac_state = 0; tgui->ramdac_ctrl = val; - //pclog("TGUI ramdac ctrl=%02x.\n", (tgui->ramdac_ctrl >> 4) & 0x0f); +#if 0 + pclog("TGUI ramdac ctrl=%02x.\n", (tgui->ramdac_ctrl >> 4) & 0x0f); +#endif svga_recalctimings(svga); return; } @@ -718,7 +719,9 @@ tgui_recalctimings(svga_t *svga) if (((svga->crtc[0x29] & 0x30) && (svga->bpp >= 15)) || !svga->rowoffset) svga->rowoffset |= 0x100; - //pclog("BPP=%d, DataWidth=%02x, CRTC29 bit 4-5=%02x, pixbusmode=%02x, rowoffset=%02x, doublerowoffset=%x.\n", svga->bpp, svga->crtc[0x2a] & 0x40, svga->crtc[0x29] & 0x30, svga->crtc[0x38], svga->rowoffset, svga->gdcreg[0x2f] & 4); +#if 0 + pclog("BPP=%d, DataWidth=%02x, CRTC29 bit 4-5=%02x, pixbusmode=%02x, rowoffset=%02x, doublerowoffset=%x.\n", svga->bpp, svga->crtc[0x2a] & 0x40, svga->crtc[0x29] & 0x30, svga->crtc[0x38], svga->rowoffset, svga->gdcreg[0x2f] & 4); +#endif if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; @@ -1468,15 +1471,15 @@ enum { } \ } while (0) -#define WRITE(addr, dat) \ - if (tgui->accel.bpp == 0) { \ - svga->vram[(addr) &tgui->vram_mask] = dat; \ +#define WRITE(addr, dat) \ + if (tgui->accel.bpp == 0) { \ + svga->vram[(addr) &tgui->vram_mask] = dat; \ svga->changedvram[((addr) & (tgui->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; \ - } else if (tgui->accel.bpp == 1) { \ - vram_w[(addr) & (tgui->vram_mask >> 1)] = dat; \ + } else if (tgui->accel.bpp == 1) { \ + vram_w[(addr) & (tgui->vram_mask >> 1)] = dat; \ svga->changedvram[((addr) & (tgui->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ - } else { \ - vram_l[(addr) & (tgui->vram_mask >> 2)] = dat; \ + } else { \ + vram_l[(addr) & (tgui->vram_mask >> 2)] = dat; \ svga->changedvram[((addr) & (tgui->vram_mask >> 2)) >> 10] = svga->monitor->mon_changeframecount; \ } @@ -2115,7 +2118,9 @@ tgui_accel_out(uint16_t addr, uint8_t val, void *priv) case 0x2123: tgui->accel.ger22 = (tgui->accel.ger22 & 0xff) | (val << 8); - //pclog("Pitch IO23: val = %02x, rowoffset = %x.\n", tgui->accel.ger22, svga->crtc[0x13]); +#if 0 + pclog("Pitch IO23: val = %02x, rowoffset = %x.\n", tgui->accel.ger22, svga->crtc[0x13]); +#endif switch (svga->bpp) { case 8: case 24: diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index ebd92d983..d2c694a4c 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -441,7 +441,9 @@ banshee_updatemapping(banshee_t *banshee) svga_t *svga = &banshee->svga; if (!(banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { - // banshee_log("Update mapping - PCI disabled\n"); +#if 0 + banshee_log("Update mapping - PCI disabled\n"); +#endif mem_mapping_disable(&svga->mapping); mem_mapping_disable(&banshee->linear_mapping); mem_mapping_disable(&banshee->reg_mapping_low); @@ -1082,7 +1084,9 @@ banshee_ext_in(uint16_t addr, void *priv) break; } - // banshee_log("banshee_ext_in: addr=%04x val=%02x\n", addr, ret); +#if 0 + banshee_log("banshee_ext_in: addr=%04x val=%02x\n", addr, ret); +#endif return ret; } @@ -1273,7 +1277,9 @@ banshee_ext_inl(uint16_t addr, void *priv) break; default: - // fatal("bad banshee_ext_inl: addr=%04x\n", addr); +#if 0 + fatal("bad banshee_ext_inl: addr=%04x\n", addr); +#endif break; } @@ -1334,17 +1340,23 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) case cmdBaseAddr0: ret = voodoo->cmdfifo_base >> 12; - // banshee_log("Read cmdfifo_base %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_base %08x\n", ret); +#endif break; case cmdRdPtrL0: ret = voodoo->cmdfifo_rp; - // banshee_log("Read cmdfifo_rp %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_rp %08x\n", ret); +#endif break; case cmdFifoDepth0: ret = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; - // banshee_log("Read cmdfifo_depth %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_depth %08x\n", ret); +#endif break; case cmdStatus0: @@ -1357,17 +1369,23 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) case cmdBaseAddr1: ret = voodoo->cmdfifo_base_2 >> 12; - // banshee_log("Read cmdfifo_base %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_base %08x\n", ret); +#endif break; case cmdRdPtrL1: ret = voodoo->cmdfifo_rp_2; - // banshee_log("Read cmdfifo_rp %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_rp %08x\n", ret); +#endif break; case cmdFifoDepth1: ret = voodoo->cmdfifo_depth_wr_2 - voodoo->cmdfifo_depth_rd_2; - // banshee_log("Read cmdfifo_depth %08x\n", ret); +#if 0 + banshee_log("Read cmdfifo_depth %08x\n", ret); +#endif break; case cmdStatus1: @@ -2833,7 +2851,9 @@ banshee_pci_read(int func, int addr, void *priv) if (func) return 0xff; - // banshee_log("Banshee PCI read %08X ", addr); +#if 0 + banshee_log("Banshee PCI read %08X ", addr); +#endif switch (addr) { case 0x00: ret = 0x1a; diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c index d8f812f7f..cc52fc61a 100644 --- a/src/video/vid_voodoo_render.c +++ b/src/video/vid_voodoo_render.c @@ -43,8 +43,7 @@ typedef struct voodoo_state_t { int xstart, xend, xdir; uint32_t base_r, base_g, base_b, base_a, base_z; - struct - { + struct { int64_t base_s, base_t, base_w; int lod; } tmu[2]; @@ -1424,11 +1423,14 @@ voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) if ((params->vertexAy & 0xf) > 8) dy += 16; - /* voodoo_render_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, - (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, - (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, - (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, - (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ +#if 0 +voodoo_render_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", + odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode); +#endif state.base_r = params->startR; state.base_g = params->startG; diff --git a/src/video/vid_voodoo_setup.c b/src/video/vid_voodoo_setup.c index e1d13ba35..11f4ff861 100644 --- a/src/video/vid_voodoo_setup.c +++ b/src/video/vid_voodoo_setup.c @@ -191,8 +191,8 @@ voodoo_triangle_setup(voodoo_t *voodoo) voodoo->params.dWdX = (int64_t) (((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f); voodoo->params.dWdY = (int64_t) (((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f); voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; - voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; - voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; + voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; + voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; } if (voodoo->sSetupMode & SETUPMODE_W0) { voodoo->params.tmu[0].startW = (int64_t) (verts[va].sW0 * 4294967296.0f); diff --git a/src/video/vid_voodoo_texture.c b/src/video/vid_voodoo_texture.c index 3939db3cd..f6894ec0f 100644 --- a/src/video/vid_voodoo_texture.c +++ b/src/video/vid_voodoo_texture.c @@ -61,10 +61,10 @@ voodoo_texture_log(const char *fmt, ...) void voodoo_recalc_tex12(voodoo_t *voodoo, int tmu) { - int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; - int width = 256; - int height = 256; - int shift = 8; + int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; + int width = 256; + int height = 256; + int shift = 8; uint32_t base = voodoo->params.texBaseAddr[tmu]; uint32_t offset = 0; int tex_lod = 0; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index fb27b8b2c..f5d46f937 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -856,18 +856,18 @@ xga_ext_inb(uint16_t addr, void *priv) return ret; } -#define READ(addr, dat) \ +#define READ(addr, dat) \ dat = xga->vram[(addr) & (xga->vram_mask)]; -#define WRITE(addr, dat) \ - xga->vram[((addr)) & (xga->vram_mask)] = dat; \ +#define WRITE(addr, dat) \ + xga->vram[((addr)) & (xga->vram_mask)] = dat; \ xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; -#define READW(addr, dat) \ +#define READW(addr, dat) \ dat = *(uint16_t *) &xga->vram[(addr) & (xga->vram_mask)]; -#define WRITEW(addr, dat) \ - *(uint16_t *) &xga->vram[((addr)) & (xga->vram_mask)] = dat; \ +#define WRITEW(addr, dat) \ + *(uint16_t *) &xga->vram[((addr)) & (xga->vram_mask)] = dat; \ xga->changedvram[(((addr)) & (xga->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; #define ROP(mix, d, s) \ @@ -928,7 +928,7 @@ xga_ext_inb(uint16_t addr, void *priv) d = MIN(s, d); \ break; \ case 0x12: \ - d = MIN(~0, s + d); \ + d = MIN(~0, s + d); \ break; \ case 0x13: \ d = MAX(0, d - s); \ From d5d1d5c449e013256941cbbe8576b34e85eed426 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 3 Feb 2025 20:00:58 -0500 Subject: [PATCH 0208/1190] More cleanups to device structs --- src/cdrom/cdrom_mitsumi.c | 4 +- src/device.c | 2 +- src/device/isamem.c | 1159 ++++++----- src/device/isartc.c | 70 +- src/device/keyboard_at.c | 21 +- src/device/mouse_bus.c | 133 +- src/device/mouse_microtouch_touchscreen.c | 61 +- src/device/mouse_ps2.c | 19 +- src/device/mouse_serial.c | 161 +- src/device/mouse_wacom_tablet.c | 17 +- src/device/novell_cardkey.c | 18 +- src/device/serial_passthrough.c | 191 +- src/device/unittester.c | 30 +- src/disk/hdc_ide.c | 39 +- src/disk/hdc_st506_xt.c | 399 ++-- src/disk/hdc_xta.c | 87 +- src/disk/hdc_xtide.c | 74 +- src/disk/lba_enhancer.c | 31 +- src/floppy/fdc_compaticard.c | 64 +- src/floppy/fdc_magitronic.c | 19 +- src/floppy/fdc_monster.c | 153 +- src/floppy/fdc_pii15xb.c | 19 +- src/game/gameport.c | 64 +- src/network/net_3c501.c | 61 +- src/network/net_3c503.c | 87 +- src/network/net_modem.c | 83 +- src/network/net_ne2000.c | 383 ++-- src/network/net_pcnet.c | 147 +- src/network/net_rtl8139.c | 14 +- src/network/net_tulip.c | 42 +- src/network/net_wd8003.c | 274 +-- src/scsi/scsi_aha154x.c | 290 +-- src/scsi/scsi_buslogic.c | 82 +- src/scsi/scsi_ncr53c400.c | 203 +- src/scsi/scsi_ncr53c8xx.c | 17 +- src/scsi/scsi_pcscsi.c | 14 +- src/scsi/scsi_spock.c | 17 +- src/scsi/scsi_t128.c | 49 +- src/sound/midi_fluidsynth.c | 235 ++- src/sound/midi_mt32.c | 76 +- src/sound/midi_rtmidi.cpp | 70 +- src/sound/snd_adlibgold.c | 114 +- src/sound/snd_audiopci.c | 155 +- src/sound/snd_azt2316a.c | 415 ++-- src/sound/snd_cmi8x38.c | 42 +- src/sound/snd_cms.c | 53 +- src/sound/snd_gus.c | 127 +- src/sound/snd_mpu401.c | 209 +- src/sound/snd_opl2board.c | 14 +- src/sound/snd_optimc.c | 28 +- src/sound/snd_pas16.c | 42 +- src/sound/snd_pssj.c | 51 +- src/sound/snd_sb.c | 2246 +++++++++------------ src/sound/snd_sn76489.c | 51 +- src/sound/snd_ssi2001.c | 69 +- src/sound/snd_wss.c | 55 +- src/video/vid_8514a.c | 172 +- src/video/vid_ati18800.c | 28 +- src/video/vid_ati28800.c | 70 +- src/video/vid_ati_mach64.c | 65 +- src/video/vid_ati_mach8.c | 140 +- src/video/vid_bochs_vbe.c | 63 +- src/video/vid_cga.c | 163 +- src/video/vid_cl54xx.c | 244 +-- src/video/vid_colorplus.c | 73 +- src/video/vid_ega.c | 93 +- src/video/vid_et3000.c | 22 +- src/video/vid_et4000.c | 183 +- src/video/vid_et4000w32.c | 30 +- src/video/vid_hercules.c | 53 +- src/video/vid_herculesplus.c | 53 +- src/video/vid_ht216.c | 40 +- src/video/vid_mda.c | 40 +- src/video/vid_mga.c | 62 +- src/video/vid_nga.c | 128 +- src/video/vid_oak_oti.c | 130 +- src/video/vid_ogc.c | 53 +- src/video/vid_paradise.c | 65 +- src/video/vid_rtg310x.c | 65 +- src/video/vid_s3.c | 98 +- src/video/vid_s3_virge.c | 191 +- src/video/vid_sigma.c | 139 +- src/video/vid_tgui9440.c | 61 +- src/video/vid_tvga.c | 35 +- src/video/vid_voodoo.c | 184 +- src/video/vid_voodoo_banshee.c | 395 ++-- src/video/vid_xga.c | 183 +- 87 files changed, 5883 insertions(+), 6088 deletions(-) diff --git a/src/cdrom/cdrom_mitsumi.c b/src/cdrom/cdrom_mitsumi.c index 19fa06e23..7ef8a04b2 100644 --- a/src/cdrom/cdrom_mitsumi.c +++ b/src/cdrom/cdrom_mitsumi.c @@ -460,11 +460,11 @@ const device_t mitsumi_cdrom_device = { .name = "Mitsumi CD-ROM interface", .internal_name = "mcd", .flags = DEVICE_ISA | DEVICE_AT, - .local = 1, + .local = 0, .init = mitsumi_cdrom_init, .close = mitsumi_cdrom_close, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device.c b/src/device.c index 55552ead4..1228eedd2 100644 --- a/src/device.c +++ b/src/device.c @@ -883,7 +883,7 @@ machine_get_config_string(char *str) return NULL; } -const device_t* +const device_t * device_context_get_device(void) { return device_current.dev; diff --git a/src/device/isamem.c b/src/device/isamem.c index 5cac31c7f..45a0413be 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -851,32 +851,34 @@ isamem_close(void *priv) static const device_config_t ibmxt_32k_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 32, - .file_filter = "", - .spinner = { - .min = 32, - .max = 576, - .step = 32 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 32, + .file_filter = NULL, + .spinner = { + .min = 32, + .max = 576, + .step = 32 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 0, - .max = 608, - .step = 32 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 608, + .step = 32 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -899,32 +901,34 @@ static const device_t ibmxt_32k_device = { static const device_config_t ibmxt_64k_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 64, - .max = 576, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 64, + .max = 576, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 0, - .max = 576, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 576, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -947,32 +951,34 @@ static const device_t ibmxt_64k_device = { static const device_config_t ibmxt_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 128, - .file_filter = "", - .spinner = { - .min = 64, - .max = 576, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 128, + .file_filter = NULL, + .spinner = { + .min = 64, + .max = 576, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 256, - .file_filter = "", - .spinner = { - .min = 0, - .max = 576, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 576, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -995,32 +1001,34 @@ static const device_t ibmxt_device = { static const device_config_t genericxt_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 16, - .file_filter = "", - .spinner = { - .min = 0, - .max = 640, - .step = 16 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 16, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 640, + .step = 16 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 624, - .step = 16 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 624, + .step = 16 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1044,32 +1052,34 @@ static const device_t genericxt_device = { static const device_config_t msramcard_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 0, - .max = 256, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 256, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 624, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 624, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1092,32 +1102,34 @@ static const device_t msramcard_device = { static const device_config_t mssystemcard_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 0, - .max = 256, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 256, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 624, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 624, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1154,32 +1166,34 @@ static const device_t ibmat_128k_device = { static const device_config_t ibmat_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 0, - .max = 12288, - .step = 512 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 12288, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 1024, - .file_filter = "", - .spinner = { - .min = 0, - .max = 15872, - .step = 512 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 15872, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1202,32 +1216,34 @@ static const device_t ibmat_device = { static const device_config_t genericat_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 0, - .max = 16384, - .step = 128 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 16384, + .step = 128 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 1024, - .file_filter = "", - .spinner = { - .min = 0, - .max = 15872, - .step = 128 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 15872, + .step = 128 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1251,32 +1267,34 @@ static const device_t genericat_device = { static const device_config_t p5pak_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 128, - .file_filter = "", - .spinner = { - .min = 0, - .max = 384, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 128, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 384, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 64, - .max = 576, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 64, + .max = 576, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1299,32 +1317,34 @@ static const device_t p5pak_device = { static const device_config_t a6pak_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 0, - .max = 384, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 384, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 256, - .file_filter = "", - .spinner = { - .min = 64, - .max = 512, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { + .min = 64, + .max = 512, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1347,28 +1367,29 @@ static const device_t a6pak_device = { static const device_config_t ems5150_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 256, - .file_filter = "", - .spinner = { - .min = 0, - .max = 2048, - .step = 64 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 2048, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x0000 }, { .description = "Board 1", .value = 0x0208 }, { .description = "Board 2", .value = 0x020a }, @@ -1376,6 +1397,7 @@ static const device_config_t ems5150_config[] = { { .description = "Board 4", .value = 0x020e }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1398,98 +1420,104 @@ static const device_t ems5150_device = { static const device_config_t ev159_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 0, - .max = 3072, - .step = 512 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 3072, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 16128, - .step = 128 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 16128, + .step = 128 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "length", - .description = "Contiguous Size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 16384, - .step = 128 + .name = "length", + .description = "Contiguous Size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 16384, + .step = 128 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "width", - .description = "I/O Width", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8-bit", .value = 0 }, { .description = "16-bit", .value = 1 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "speed", - .description = "Transfer Speed", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Standard (150ns)", .value = 0 }, { .description = "High-Speed (120ns)", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "ems", - .description = "EMS mode", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ems", + .description = "EMS mode", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "Enabled", .value = 1 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0258, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0258, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, @@ -1499,16 +1527,17 @@ static const device_config_t ev159_config[] = { { .description = "2E8H", .value = 0x02E8 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "base2", - .description = "Address for > 2 MB", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0268, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base2", + .description = "Address for > 2 MB", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0268, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, @@ -1518,6 +1547,7 @@ static const device_config_t ev159_config[] = { { .description = "2E8H", .value = 0x02E8 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1540,70 +1570,74 @@ static const device_t ev159_device = { static const device_config_t ev165a_config[] = { // clang-format off { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 256, - .file_filter = "", - .spinner = { - .min = 0, - .max = 2048, - .step = 256 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 2048, + .step = 256 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 64, - .file_filter = "", - .spinner = { - .min = 64, - .max = 640, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { + .min = 64, + .max = 640, + .step = 64 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "length", .description = "Contiguous Size", .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 2048, - .step = 256 + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 2048, + .step = 256 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "ems", - .description = "EMS mode", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ems", + .description = "EMS mode", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "Enabled", .value = 1 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0258, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0258, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, @@ -1613,6 +1647,7 @@ static const device_config_t ev165a_config[] = { { .description = "2E8H", .value = 0x02E8 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1635,48 +1670,51 @@ static const device_t ev165a_device = { static const device_config_t brxt_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0268, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0268, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, { .description = "268H", .value = 0x0268 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "frame", - .description = "Frame Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "D000H", .value = 0xD0000 }, - { .description = "E000H", .value = 0xE0000 }, - { .description = "" } + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "D000H", .value = 0xD0000 }, + { .description = "E000H", .value = 0xE0000 }, + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 0, - .max = 2048, - .step = 512 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 2048, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1700,89 +1738,96 @@ static const device_t brxt_device = { static const device_config_t brat_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0268, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0268, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, { .description = "268H", .value = 0x0268 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "frame", - .description = "Frame Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "D000H", .value = 0xD0000 }, { .description = "E000H", .value = 0xE0000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "width", - .description = "I/O Width", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 8, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8-bit", .value = 8 }, { .description = "16-bit", .value = 16 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "speed", - .description = "Transfer Speed", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Standard", .value = 0 }, { .description = "High-Speed", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { - .min = 0, - .max = 4096, - .step = 512 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 4096, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { - .min = 0, - .max = 14336, - .step = 512 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 14336, + .step = 512 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1806,66 +1851,69 @@ static const device_t brat_device = { static const device_config_t lotech_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0260, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0260, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "260H", .value = 0x0260 }, { .description = "264H", .value = 0x0264 }, { .description = "268H", .value = 0x0268 }, { .description = "26CH", .value = 0x026C }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "frame", - .description = "Frame Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xe0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xe0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C000H", .value = 0xC0000 }, { .description = "D000H", .value = 0xD0000 }, { .description = "E000H", .value = 0xE0000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 2048, - .file_filter = "", - .spinner = { - .min = 512, - .max = 4096, - .step = 512 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 2048, + .file_filter = NULL, + .spinner = { + .min = 512, + .max = 4096, + .step = 512 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; static const device_t lotech_ems_device = { - .name = "Lo-tech EMS Board", + .name = "Lo-tech EMS Board", .internal_name = "lotechems", - .flags = DEVICE_ISA, - .local = ISAMEM_LOTECH_EMS_CARD, - .init = isamem_init, - .close = isamem_close, - .reset = NULL, + .flags = DEVICE_ISA, + .local = ISAMEM_LOTECH_EMS_CARD, + .init = isamem_init, + .close = isamem_close, + .reset = NULL, .available = NULL, .speed_changed = NULL, - .force_redraw = NULL, - .config = lotech_config + .force_redraw = NULL, + .config = lotech_config }; #ifdef USE_ISAMEM_RAMPAGE @@ -1874,14 +1922,14 @@ static const device_t lotech_ems_device = { static const device_config_t rampage_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0218, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0218, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, @@ -1891,33 +1939,37 @@ static const device_config_t rampage_config[] = { { .description = "2E8H", .value = 0x02E8 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 256, /* Technically 128k, but banks 2-7 must be 256, headaches elsewise */ - .file_filter = "", - .spinner = { - .min = 256, - .max = 2048, - .step = 256 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 256, /* Technically 128k, but banks 2-7 must be 256, headaches elsewise */ + .file_filter = NULL, + .spinner = { + .min = 256, + .max = 2048, + .step = 256 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "start", - .description = "Start Address", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 640, - .file_filter = "", - .spinner = { - .min = 0, - .max = 640, - .step = 64 + .name = "start", + .description = "Start Address", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 640, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 640, + .step = 64 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1942,14 +1994,14 @@ static const device_t rampage_device = { static const device_config_t iab_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0258, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0258, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "208H", .value = 0x0208 }, { .description = "218H", .value = 0x0218 }, { .description = "258H", .value = 0x0258 }, @@ -1959,64 +2011,69 @@ static const device_config_t iab_config[] = { { .description = "2E8H", .value = 0x02E8 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "frame", - .description = "Frame Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "frame", + .description = "Frame Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C000H", .value = 0xC0000 }, { .description = "D000H", .value = 0xD0000 }, { .description = "E000H", .value = 0xE0000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "width", - .description = "I/O Width", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 8, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "width", + .description = "I/O Width", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8-bit", .value = 8 }, { .description = "16-bit", .value = 16 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "speed", - .description = "Transfer Speed", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "speed", + .description = "Transfer Speed", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Standard", .value = 0 }, { .description = "High-Speed", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "size", - .description = "Memory size", - .type = CONFIG_SPINNER, - .default_string = "", - .default_int = 128, - .file_filter = "", - .spinner = { - .min = 0, - .max = 8192, - .step = 128 + .name = "size", + .description = "Memory size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 128, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 8192, + .step = 128 }, - .selection = { { 0 } } + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/isartc.c b/src/device/isartc.c index f24ffb72b..63ce0b065 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -631,23 +631,24 @@ static const device_config_t ev170_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x02C0, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "240H", .value = 0x0240 }, { .description = "2C0H", .value = 0x02c0 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = -1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "Disabled", .value = -1 }, @@ -656,6 +657,7 @@ static const device_config_t ev170_config[] = { { .description = "IRQ7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -681,15 +683,16 @@ static const device_config_t pii147_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x0240, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "Clock 1", .value = 0x0240 }, { .description = "Clock 2", .value = 0x0340 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -715,9 +718,9 @@ static const device_config_t p5pak_config[] = { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = -1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "Disabled", -1 }, @@ -726,6 +729,7 @@ static const device_config_t p5pak_config[] = { { .description = "IRQ5", 5 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -751,9 +755,9 @@ static const device_config_t a6pak_config[] = { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = -1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "Disabled", .value = -1 }, @@ -762,6 +766,7 @@ static const device_config_t a6pak_config[] = { { .description = "IRQ5", .value = 5 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -787,42 +792,44 @@ static const device_config_t mm58167_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x02C0, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { "240H", 0x0240 }, - { "2C0H", 0x02c0 }, - { "340H", 0x0340 }, - { "" } + { .description = "240H", .value = 0x0240 }, + { .description = "2C0H", .value = 0x02c0 }, + { .description = "340H", .value = 0x0340 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = -1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { "Disabled", -1 }, - { "IRQ2", 2 }, - { "IRQ5", 5 }, - { "IRQ7", 7 }, - { "" } + { .description = "Disabled", .value = -1 }, + { .description = "IRQ2", .value = 2 }, + { .description = "IRQ5", .value = 5 }, + { .description = "IRQ7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xcc000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xcc000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = -1 }, { .description = "C800H", .value = 0xc8000 }, { .description = "CA00H", .value = 0xca000 }, @@ -846,6 +853,7 @@ static const device_config_t mm58167_config[] = { { .description = "EE00H", .value = 0xee000 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index af3d5d5fc..9b3f06098 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2187,14 +2187,14 @@ keyboard_at_close(void *priv) static const device_config_t keyboard_at_config[] = { // clang-format off { - .name = "type", - .description = "Type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "type", + .description = "Type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "AT 84-key", .value = FLAG_AT | KBD_84_KEY }, { .description = "AT 101/102/106-key", .value = FLAG_AT | KBD_101_KEY }, { .description = "AT Korean", .value = FLAG_AT | KBD_KOREAN }, @@ -2203,7 +2203,8 @@ static const device_config_t keyboard_at_config[] = { { .description = "PS/2 106-key JIS", .value = FLAG_PS2 | KBD_JIS }, { .description = "PS/2 Korean", .value = FLAG_PS2 | KBD_KOREAN }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END @@ -2220,7 +2221,7 @@ const device_t keyboard_at_generic_device = { .init = keyboard_at_init, .close = keyboard_at_close, .reset = NULL, - { .poll = NULL }, + .poll = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = keyboard_at_config diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index b56a3cc18..c0f161dbd 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -686,66 +686,70 @@ bm_init(const device_t *info) static const device_config_t lt_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x23c, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x23c, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x230", .value = 0x230 }, { .description = "0x234", .value = 0x234 }, { .description = "0x238", .value = 0x238 }, { .description = "0x23C", .value = 0x23c }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "hz", - .description = "Hz", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 45, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "hz", + .description = "Hz", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 45, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Non-timed (original)", .value = 0 }, { .description = "30 Hz (JMP2 = 1)", .value = 30 }, { .description = "45 Hz (JMP2 not populated)", .value = 45 }, { .description = "60 Hz (JMP2 = 2)", .value = 60 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -754,50 +758,53 @@ static const device_config_t lt_config[] = { static const device_config_t ms_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x23c, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x23c, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x230", .value = 0x230 }, { .description = "0x234", .value = 0x234 }, { .description = "0x238", .value = 0x238 }, { .description = "0x23C", .value = 0x23c }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index 24d5de1fb..15b42bfdd 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -549,42 +549,49 @@ mtouch_close(void *priv) static const device_config_t mtouch_config[] = { // clang-format off { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "identity", - .description = "Controller", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { - { .description = "A3 - SMT2 Serial / SMT3(R)V", .value = 0 }, - { .description = "A4 - SMT2 PCBus", .value = 1 }, - { .description = "P5 - TouchPen 4(+)", .value = 2 }, - { .description = "Q1 - SMT3(R) Serial", .value = 3 } - } + .name = "identity", + .description = "Controller", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "A3 - SMT2 Serial / SMT3(R)V", .value = 0 }, + { .description = "A4 - SMT2 PCBus", .value = 1 }, + { .description = "P5 - TouchPen 4(+)", .value = 2 }, + { .description = "Q1 - SMT3(R) Serial", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "crosshair", - .description = "Show Crosshair", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "crosshair", + .description = "Show Crosshair", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 53af97b78..9afc75410 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -367,20 +367,21 @@ ps2_close(void *priv) static const device_config_t ps2_config[] = { // clang-format off { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "Wheel", .value = 4 }, { .description = "Five + Wheel", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index c64be5a6d..be9bc62e1 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -916,41 +916,47 @@ sermouse_init(const device_t *info) static const device_config_t msssermouse_config[] = { // clang-format off { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "rts_toggle", - .description = "RTS toggle", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "rts_toggle", + .description = "RTS toggle", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -959,35 +965,37 @@ static const device_config_t msssermouse_config[] = { static const device_config_t mssermouse_config[] = { // clang-format off { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "Wheel", .value = 4 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -996,57 +1004,64 @@ static const device_config_t mssermouse_config[] = { static const device_config_t ltsermouse_config[] = { // clang-format off { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "buttons", - .description = "Buttons", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Two", .value = 2 }, { .description = "Three", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "revision", - .description = "Revision", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "LOGIMOUSE R7 1.0", .value = 1 }, { .description = "LOGIMOUSE R7 2.0", .value = 2 }, { .description = "LOGIMOUSE C7 3.0", .value = 3 }, { .description = "Logitech MouseMan", .value = 4 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "rts_toggle", - .description = "RTS toggle", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "rts_toggle", + .description = "RTS toggle", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/mouse_wacom_tablet.c b/src/device/mouse_wacom_tablet.c index d74e58411..79b674e07 100644 --- a/src/device/mouse_wacom_tablet.c +++ b/src/device/mouse_wacom_tablet.c @@ -693,20 +693,21 @@ wacom_close(void *priv) static const device_config_t wacom_config[] = { // clang-format off { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/novell_cardkey.c b/src/device/novell_cardkey.c index 34b6390d1..8820addde 100644 --- a/src/device/novell_cardkey.c +++ b/src/device/novell_cardkey.c @@ -27,8 +27,7 @@ #include <86box/plat.h> #include <86box/novell_cardkey.h> -typedef struct novell_cardkey_t -{ +typedef struct novell_cardkey_t { char serial_number_str[13]; } novell_cardkey_t; @@ -95,14 +94,15 @@ void novell_cardkey_close(void* priv) static const device_config_t keycard_config[] = { // clang-format off { - .name = "serial_number", - .description = "Serial Number", - .type = CONFIG_STRING, + .name = "serial_number", + .description = "Serial Number", + .type = CONFIG_STRING, .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { { 0 } } + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index bb2378a22..256f9eaa9 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -231,138 +231,129 @@ const char *serpt_mode_names[SERPT_MODES_MAX] = { // clang-format off static const device_config_t serial_passthrough_config[] = { { - .name = "mode", - .description = "Passthrough Mode", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "mode", + .description = "Passthrough Mode", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { #ifdef _WIN32 - { - .description = "Named Pipe (Server)", - .value = SERPT_MODE_VCON - }, + { .description = "Named Pipe (Server)", .value = SERPT_MODE_VCON }, #if 0 /* TODO */ - { - .description = "Named Pipe (Client)", - .value = SERPT_MODE_VCON - }, -#endif -#else - { - .description = "Pseudo Terminal/Virtual Console", - .value = SERPT_MODE_VCON - }, + { .description = "Named Pipe (Client)", .value = SERPT_MODE_VCON }, #endif +#else /* _WIN32 */ + { .description = "Pseudo Terminal/Virtual Console", .value = SERPT_MODE_VCON }, +#endif /* _WIN32 */ #if 0 /* TODO */ - { - .description = "TCP Server", - .value = SERPT_MODE_TCPSRV - }, - { - .description = "TCP Client", - .value = SERPT_MODE_TCPCLNT - }, + { .description = "TCP Server", .value = SERPT_MODE_TCPSRV }, + { .description = "TCP Client", .value = SERPT_MODE_TCPCLNT }, #endif - { - .description = "Host Serial Passthrough", - .value = SERPT_MODE_HOSTSER - }, - { - .description = "" - } - } + { .description = "Host Serial Passthrough", .value = SERPT_MODE_HOSTSER }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "host_serial_path", - .description = "Host Serial Device", - .type = CONFIG_SERPORT, - .default_string = "", - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } } + .name = "host_serial_path", + .description = "Host Serial Device", + .type = CONFIG_SERPORT, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, #ifdef _WIN32 { - .name = "named_pipe", - .description = "Name of pipe", - .type = CONFIG_STRING, + .name = "named_pipe", + .description = "Name of pipe", + .type = CONFIG_STRING, .default_string = "\\\\.\\pipe\\86Box\\test", - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } } + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, -#endif +#endif /* _WIN32 */ { - .name = "data_bits", - .description = "Data bits", - .type = CONFIG_SELECTION, - .default_string = "8", - .default_int = 8, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { + .name = "data_bits", + .description = "Data bits", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { #if 0 /* Mentioned by WFW 3.1x, not supported, atleast on Linux */ { .description = "4", .value = 4 }, #endif { .description = "5", .value = 5 }, { .description = "6", .value = 6 }, { .description = "7", .value = 7 }, - { .description = "8", .value = 8 } - } + { .description = "8", .value = 8 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "stop_bits", - .description = "Stop bits", - .type = CONFIG_SELECTION, - .default_string = "1", - .default_int = 1, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { + .name = "stop_bits", + .description = "Stop bits", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "1", .value = 1 }, #if 0 { .description = "1.5", .value = 1.5 }, #endif - { .description = "2", .value = 2 } - } + { .description = "2", .value = 2 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "baudrate", - .description = "Baud Rate of Passthrough", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 115200, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { + .name = "baudrate", + .description = "Baud Rate of Passthrough", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 115200, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { #if 0 - { .description = "256000", .value = 256000 }, - { .description = "128000", .value = 128000 }, + { .description = "256000", .value = 256000 }, + { .description = "128000", .value = 128000 }, #endif - { .description = "115200", .value = 115200 }, - { .description = "57600", .value = 57600 }, - { .description = "56000", .value = 56000 }, - { .description = "38400", .value = 38400 }, - { .description = "19200", .value = 19200 }, - { .description = "14400", .value = 14400 }, - { .description = "9600", .value = 9600 }, - { .description = "7200", .value = 7200 }, - { .description = "4800", .value = 4800 }, - { .description = "2400", .value = 2400 }, - { .description = "1800", .value = 1800 }, - { .description = "1200", .value = 1200 }, - { .description = "600", .value = 600 }, - { .description = "300", .value = 300 }, - { .description = "150", .value = 150 }, + { .description = "115200", .value = 115200 }, + { .description = "57600", .value = 57600 }, + { .description = "56000", .value = 56000 }, + { .description = "38400", .value = 38400 }, + { .description = "19200", .value = 19200 }, + { .description = "14400", .value = 14400 }, + { .description = "9600", .value = 9600 }, + { .description = "7200", .value = 7200 }, + { .description = "4800", .value = 4800 }, + { .description = "2400", .value = 2400 }, + { .description = "1800", .value = 1800 }, + { .description = "1200", .value = 1200 }, + { .description = "600", .value = 600 }, + { .description = "300", .value = 300 }, + { .description = "150", .value = 150 }, #if 0 { .description = "134.5", .value = 134.5 }, #endif - { .description = "110", .value = 110 }, - { .description = "75", .value = 75 } - } + { .description = "110", .value = 110 }, + { .description = "75", .value = 75 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/device/unittester.c b/src/device/unittester.c index 5f0fa5712..0e864aa0b 100644 --- a/src/device/unittester.c +++ b/src/device/unittester.c @@ -114,19 +114,6 @@ static struct unittester_state unittester_defaults = { .cmd_id = UT_CMD_NOOP, }; -static const device_config_t unittester_config[] = { -// clang-format off - { - .name = "exit_enabled", - .description = "Enable 0x04 \"Exit 86Box\" command", - .type = CONFIG_BINARY, - .default_int = 1, - .default_string = "" - }, - { .name = "", .description = "", .type = CONFIG_END } -// clang-format on -}; - /* Kept separate, as we will be reusing this object */ static bitmap_t *unittester_screen_buffer = NULL; @@ -624,6 +611,23 @@ unittester_close(UNUSED(void *priv)) unittester_log("[UT] 86Box Unit Tester closed\n"); } +static const device_config_t unittester_config[] = { + // clang-format off + { + .name = "exit_enabled", + .description = "Enable 0x04 \"Exit 86Box\" command", + .type = CONFIG_BINARY, + .default_int = 1, + .default_string = NULL, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + const device_t unittester_device = { .name = "86Box Unit Tester", .internal_name = "unittester", diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 592649c0e..1583d6b9c 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3359,18 +3359,17 @@ const device_t mcide_device = { .config = NULL }; - // clang-format off static const device_config_t ide_ter_config[] = { { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = HDC_TERTIARY_IRQ, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = HDC_TERTIARY_IRQ, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Plug and Play", .value = -1 }, { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -3382,21 +3381,22 @@ static const device_config_t ide_ter_config[] = { { .description = "IRQ 11", .value = 11 }, { .description = "IRQ 12", .value = 12 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ide_qua_config[] = { { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = HDC_QUATERNARY_IRQ, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = HDC_QUATERNARY_IRQ, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Plug and Play", .value = -1 }, { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -3408,7 +3408,8 @@ static const device_config_t ide_qua_config[] = { { .description = "IRQ 11", .value = 11 }, { .description = "IRQ 12", .value = 12 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index 789e7e6c4..536fd76c0 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -1914,335 +1914,356 @@ victor_v86p_available(void) // clang-format off static const device_config_t dtc_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "CA00H", .value = 0xca000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "F400H", .value = 0xf4000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t st11_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "328H", .value = 0x0328 }, { .description = "32CH", .value = 0x032c }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "D000H", .value = 0xd0000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "E000H", .value = 0xe0000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "revision", - .description = "BIOS Revision", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 19, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "revision", + .description = "BIOS Revision", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 19, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "v1.7", .value = 5 }, { .description = "v2.0", .value = 19 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd_nobios_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd_rll_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "translate", - .description = "Translate 26 -> 17", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "translate", + .description = "Translate 26 -> 17", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Off", .value = 0 }, { .description = "On", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd1004a_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd1004_rll_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "CA00H", .value = 0xca000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "CE00H", .value = 0xce000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "328H", .value = 0x0328 }, { .description = "32CH", .value = 0x032c }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 5", .value = 5 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "translate", - .description = "Translate 26 -> 17", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "translate", + .description = "Translate 26 -> 17", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Off", .value = 0 }, { .description = "On", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 553e53b48..b01d80c61 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1107,60 +1107,77 @@ xta_close(void *priv) static const device_config_t wdxt150_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "320H", .value = 0x0320 }, { .description = "324H", .value = 0x0324 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 4", .value = 4 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800H", .value = 0xc8000 }, { .description = "CA00H", .value = 0xca000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_rev", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios_rev", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "rev_1", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Revision 1.0", .internal_name = "rev_1", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { WD_REV_1_BIOS_FILE, "" } }, - { .name = "Revision 2.0", .internal_name = "rev_2", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { WD_REV_2_BIOS_FILE, "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .bios = { + { + .name = "Revision 1.0", + .internal_name = "rev_1", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { WD_REV_1_BIOS_FILE, "" } + }, + { + .name = "Revision 2.0", + .internal_name = "rev_2", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { WD_REV_2_BIOS_FILE, "" } + }, { .files_no = 0 } }, }, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 7ec7695b3..4c071e596 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -224,18 +224,33 @@ xtide_at_close(void *priv) static const device_config_t xtide_config[] = { // clang-format off { - .name = "bios", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "xt", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Regular XT", .internal_name = "xt", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_XT, "" } }, - { .name = "XT+ (V20/V30/8018x)", .internal_name = "xt_plus", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_XTP, "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Regular XT", + .internal_name = "xt", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_XT, "" } + }, + { + .name = "XT+ (V20/V30/8018x)", + .internal_name = "xt_plus", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_XTP, "" } + }, { .files_no = 0 } }, }, @@ -246,18 +261,33 @@ static const device_config_t xtide_config[] = { static const device_config_t xtide_at_config[] = { // clang-format off { - .name = "bios", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "at", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Regular AT", .internal_name = "at", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_AT, "" } }, - { .name = "386", .internal_name = "at_386", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { ROM_PATH_AT_386, "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Regular AT", + .internal_name = "at", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_AT, "" } + }, + { + .name = "386", + .internal_name = "at_386", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_AT_386, "" } + }, { .files_no = 0 } }, }, diff --git a/src/disk/lba_enhancer.c b/src/disk/lba_enhancer.c index 8e8bc480d..429611b2d 100644 --- a/src/disk/lba_enhancer.c +++ b/src/disk/lba_enhancer.c @@ -63,22 +63,23 @@ lba_enhancer_available(void) // clang-format off static const device_config_t lba_enhancer_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "C800H", .value = 0xc8000 }, - { .description = "CC00H", .value = 0xcc000 }, - { .description = "D000H", .value = 0xd0000 }, - { .description = "D400H", .value = 0xd4000 }, - { .description = "D800H", .value = 0xd8000 }, - { .description = "DC00H", .value = 0xdc000 }, - { .description = "" } + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "C800H", .value = 0xc8000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/floppy/fdc_compaticard.c b/src/floppy/fdc_compaticard.c index 4abc4abac..741105927 100644 --- a/src/floppy/fdc_compaticard.c +++ b/src/floppy/fdc_compaticard.c @@ -157,9 +157,9 @@ static const device_config_t compaticard_i_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x3f0, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "0x3f0", .value = 0x3f0 }, @@ -167,7 +167,8 @@ static const device_config_t compaticard_i_config[] = { { .description = "0x360", .value = 0x360 }, { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -179,9 +180,9 @@ static const device_config_t compaticard_ii_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x3f0, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "0x3f0", .value = 0x3f0 }, @@ -189,15 +190,16 @@ static const device_config_t compaticard_ii_config[] = { { .description = "0x360", .value = 0x360 }, { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 6, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "IRQ 2", .value = 2 }, @@ -207,22 +209,24 @@ static const device_config_t compaticard_ii_config[] = { { .description = "IRQ 6", .value = 6 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "dma", .description = "DMA channel", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 2, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "DMA 1", .value = 1 }, { .description = "DMA 2", .value = 2 }, { .description = "DMA 3", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -234,9 +238,9 @@ static const device_config_t compaticard_iv_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x3f0, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "0x3f0", .value = 0x3f0 }, @@ -244,15 +248,16 @@ static const device_config_t compaticard_iv_config[] = { { .description = "0x360", .value = 0x360 }, { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 6, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "IRQ 2", .value = 2 }, @@ -262,30 +267,32 @@ static const device_config_t compaticard_iv_config[] = { { .description = "IRQ 6", .value = 6 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "dma", .description = "DMA channel", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 2, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "DMA 1", .value = 1 }, { .description = "DMA 2", .value = 2 }, { .description = "DMA 3", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "bios_addr", .description = "BIOS Address:", .type = CONFIG_HEX20, - .default_string = "", + .default_string = NULL, .default_int = 0xce000, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { { .description = "Disabled", .value = 0 }, @@ -298,15 +305,20 @@ static const device_config_t compaticard_iv_config[] = { { .description = "E800H", .value = 0xe8000 }, { .description = "EE00H", .value = 0xee000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, #if 0 { .name = "autoboot_enabled", .description = "Enable Autoboot", .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, #endif { .name = "", .description = "", .type = CONFIG_END } diff --git a/src/floppy/fdc_magitronic.c b/src/floppy/fdc_magitronic.c index 2b708a121..17e556e0f 100644 --- a/src/floppy/fdc_magitronic.c +++ b/src/floppy/fdc_magitronic.c @@ -109,18 +109,19 @@ b215_available(void) static const device_config_t b215_config[] = { // clang-format off { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xca000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xca000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "CA00H", .value = 0xca000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 51fb108d6..1b0e2fbac 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -165,82 +165,61 @@ static const device_config_t monster_fdc_config[] = { // clang-format off #if 0 { - .name = "sec_enabled", - .description = "Enable Secondary Controller", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "sec_enabled", + .description = "Enable Secondary Controller", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "sec_irq", - .description = "Secondary Controller IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 4", - .value = 4 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 6", - .value = 6 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "sec_irq", + .description = "Secondary Controller IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 6", .value = 6 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "sec_dma", - .description = "Secondary Controller DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 2", - .value = 2 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "sec_dma", + .description = "Secondary Controller DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 2", .value = 2 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, #endif { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C000H", .value = 0xc0000 }, { .description = "C800H", .value = 0xc8000 }, @@ -249,30 +228,36 @@ static const device_config_t monster_fdc_config[] = { { .description = "E000H", .value = 0xe0000 }, { .description = "E800H", .value = 0xe8000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, #if 0 { - .name = "bios_size", - .description = "BIOS Size:", - .type = CONFIG_HEX20, - .default_string = "32", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_size", + .description = "BIOS Size:", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 32, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8K", .value = 8 }, { .description = "32K", .value = 32 }, { .description = "" } - } + }, + .bios = { { 0 } } }, #endif { - .name = "rom_writes_enabled", - .description = "Enable BIOS extension ROM Writes", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "rom_writes_enabled", + .description = "Enable BIOS extension ROM Writes", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/floppy/fdc_pii15xb.c b/src/floppy/fdc_pii15xb.c index 587eb64fa..4e6a8367c 100644 --- a/src/floppy/fdc_pii15xb.c +++ b/src/floppy/fdc_pii15xb.c @@ -122,20 +122,21 @@ pii_158_available(void) static const device_config_t pii_config[] = { // clang-format off { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xce000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xce000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "CA00H", .value = 0xca000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "CE00H", .value = 0xce000 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/game/gameport.c b/src/game/gameport.c index 39193af88..90986a655 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -88,18 +88,18 @@ static const joystick_if_t joystick_none = { static const struct { const joystick_if_t *joystick; } joysticks[] = { - { &joystick_none }, - { &joystick_2axis_2button }, - { &joystick_2axis_4button }, - { &joystick_2axis_6button }, - { &joystick_2axis_8button }, - { &joystick_3axis_2button }, - { &joystick_3axis_4button }, - { &joystick_4axis_4button }, + { &joystick_none }, + { &joystick_2axis_2button }, + { &joystick_2axis_4button }, + { &joystick_2axis_6button }, + { &joystick_2axis_8button }, + { &joystick_3axis_2button }, + { &joystick_3axis_4button }, + { &joystick_4axis_4button }, { &joystick_ch_flightstick_pro }, - { &joystick_sw_pad }, - { &joystick_tm_fcs }, - { NULL } + { &joystick_sw_pad }, + { &joystick_tm_fcs }, + { NULL } }; static joystick_instance_t *joystick_instance[GAMEPORT_MAX] = { NULL, NULL }; @@ -613,38 +613,40 @@ const device_t gameport_20f_device = { static const device_config_t tmacm_config[] = { // clang-format off { - .name = "port1_addr", - .description = "Port 1 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0201, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port1_addr", + .description = "Port 1 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0201, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "201h", .value = 0x0201 }, { .description = "203h", .value = 0x0203 }, { .description = "205h", .value = 0x0205 }, { .description = "207h", .value = 0x0207 }, { .description = "Disabled", .value = 0x0000 }, - { "" } - } + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "port2_addr", - .description = "Port 2 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0209, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port2_addr", + .description = "Port 2 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0209, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "209h", .value = 0x0209 }, { .description = "20Bh", .value = 0x020B }, { .description = "20Dh", .value = 0x020D }, { .description = "20Fh", .value = 0x020F }, { .description = "Disabled", .value = 0x0000 }, - { "" } - } + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/network/net_3c501.c b/src/network/net_3c501.c index 73dd5ef62..f5809afb1 100644 --- a/src/network/net_3c501.c +++ b/src/network/net_3c501.c @@ -1154,30 +1154,31 @@ threec501_nic_close(void *priv) static const device_config_t threec501_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x280", .value = 0x280 }, { .description = "0x300", .value = 0x300 }, { .description = "0x310", .value = 0x310 }, { .description = "0x320", .value = 0x320 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2/9", .value = 9 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, @@ -1186,28 +1187,34 @@ static const device_config_t threec501_config[] = { { .description = "IRQ 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "dma", .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 1", .value = 1 }, { .description = "DMA 2", .value = 2 }, { .description = "DMA 3", .value = 3 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index cd5016147..b35e0d453 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -654,14 +654,14 @@ threec503_nic_close(void *priv) static const device_config_t threec503_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x250", .value = 0x250 }, { .description = "0x280", .value = 0x280 }, { .description = "0x2a0", .value = 0x2a0 }, @@ -672,65 +672,68 @@ static const device_config_t threec503_config[] = { { .description = "0x350", .value = 0x350 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, { .description = "IRQ 5", .value = 5 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .default_int = 3, + .file_filter = "", + .spinner = { 0 }, + .selection = { { .description = "DMA 1", .value = 1 }, { .description = "DMA 2", .value = 2 }, { .description = "DMA 3", .value = 3 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "", .value = 0 } - }, + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xCC000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xCC000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DC00", .value = 0xDC000 }, { .description = "D800", .value = 0xD8000 }, { .description = "C800", .value = 0xC8000 }, { .description = "CC00", .value = 0xCC000 }, - { .description = "", .value = 0 } + { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off diff --git a/src/network/net_modem.c b/src/network/net_modem.c index 83dfe04d7..62621391c 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1531,30 +1531,31 @@ modem_close(void *priv) // clang-format off static const device_config_t modem_config[] = { { - .name = "port", - .description = "Serial Port", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "port", + .description = "Serial Port", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "COM1", .value = 0 }, { .description = "COM2", .value = 1 }, { .description = "COM3", .value = 2 }, { .description = "COM4", .value = 3 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { - .name = "baudrate", - .description = "Baud Rate", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 115200, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { + .name = "baudrate", + .description = "Baud Rate", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 115200, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "115200", .value = 115200 }, { .description = "57600", .value = 57600 }, { .description = "56000", .value = 56000 }, @@ -1569,32 +1570,44 @@ static const device_config_t modem_config[] = { { .description = "1200", .value = 1200 }, { .description = "600", .value = 600 }, { .description = "300", .value = 300 }, - } + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "listen_port", - .description = "TCP/IP listening port", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, + .name = "listen_port", + .description = "TCP/IP listening port", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, .max = 32767 }, - .default_int = 0 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "phonebook_file", - .description = "Phonebook File", - .type = CONFIG_FNAME, - .default_string = "", - .file_filter = "Text files (*.txt)|*.txt" + .name = "phonebook_file", + .description = "Phonebook File", + .type = CONFIG_FNAME, + .default_string = NULL, + .file_filter = "Text files (*.txt)|*.txt", + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "telnet_mode", - .description = "Telnet emulation", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "telnet_mode", + .description = "Telnet emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 2f6c60d51..dd3a12047 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1234,14 +1234,14 @@ de220p_available(void) // clang-format off static const device_config_t ne1000_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "0x300", .value = 0x300 }, { .description = "0x320", .value = 0x320 }, @@ -1249,16 +1249,17 @@ static const device_config_t ne1000_config[] = { { .description = "0x360", .value = 0x360 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -1267,27 +1268,32 @@ static const device_config_t ne1000_config[] = { { .description = "IRQ 9", .value = 9 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ne1000_compat_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "0x200", .value = 0x200 }, { .description = "0x220", .value = 0x220 }, @@ -1307,16 +1313,17 @@ static const device_config_t ne1000_compat_config[] = { { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -1326,34 +1333,43 @@ static const device_config_t ne1000_compat_config[] = { { .description = "IRQ 9", .value = 9 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "mac_oui", - .description = "MAC Address OUI", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac_oui", + .description = "MAC Address OUI", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ne2000_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "0x300", .value = 0x300 }, { .description = "0x320", .value = 0x320 }, @@ -1361,16 +1377,17 @@ static const device_config_t ne2000_config[] = { { .description = "0x360", .value = 0x360 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -1379,43 +1396,49 @@ static const device_config_t ne2000_config[] = { { .description = "IRQ 9", .value = 9 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "bios_addr", .description = "BIOS Address", .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "D000", .value = 0xD0000 }, { .description = "D800", .value = 0xD8000 }, { .description = "C800", .value = 0xC8000 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ne2000_compat_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file. */ { .description = "0x200", .value = 0x200 }, { .description = "0x220", .value = 0x220 }, @@ -1435,16 +1458,17 @@ static const device_config_t ne2000_compat_config[] = { { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 10, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 10, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: Windows 95 .INF file - not giving impossible IRQ's such as 6, 8, or 13. */ { .description = "IRQ 3", .value = 3 }, @@ -1459,50 +1483,60 @@ static const device_config_t ne2000_compat_config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "mac_oui", - .description = "MAC Address OUI", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac_oui", + .description = "MAC Address OUI", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0x00000 }, { .description = "D000", .value = 0xD0000 }, { .description = "D800", .value = 0xD8000 }, { .description = "C800", .value = 0xC8000 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ne2000_compat_8bit_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x320, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x320, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: board docs, https://github.com/skiselev/isa8_eth */ { .description = "0x200", .value = 0x200 }, { .description = "0x220", .value = 0x220 }, @@ -1522,16 +1556,17 @@ static const device_config_t ne2000_compat_8bit_config[] = { { .description = "0x3e0", .value = 0x3e0 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: board docs, https://github.com/skiselev/isa8_eth */ { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, @@ -1540,30 +1575,39 @@ static const device_config_t ne2000_compat_8bit_config[] = { { .description = "IRQ 9", .value = 9 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "mac_oui", - .description = "MAC Address OUI", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac_oui", + .description = "MAC Address OUI", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { /* Source: board docs, https://github.com/skiselev/isa8_eth */ { .description = "Disabled", .value = 0x00000 }, { .description = "C000", .value = 0xC0000 }, @@ -1576,6 +1620,7 @@ static const device_config_t ne2000_compat_8bit_config[] = { { .description = "DC00", .value = 0xDC000 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -1583,40 +1628,56 @@ static const device_config_t ne2000_compat_8bit_config[] = { static const device_config_t rtl8019as_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t rtl8029as_config[] = { { - .name = "bios", - .description = "Enable BIOS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mca_mac_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 5487486b4..3272033cf 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -3088,62 +3088,68 @@ pcnet_close(void *priv) // clang-format off static const device_config_t pcnet_pci_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t pcnet_isa_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x300", .value = 0x300 }, { .description = "0x320", .value = 0x320 }, { .description = "0x340", .value = 0x340 }, { .description = "0x360", .value = 0x360 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 4", .value = 4 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "IRQ 9", .value = 9 }, + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, { .description = "IRQ 12", .value = 12 }, { .description = "IRQ 15", .value = 15 }, - { .description = "" } + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 0", .value = 0 }, { .description = "DMA 3", .value = 3 }, { .description = "DMA 5", .value = 5 }, @@ -3151,61 +3157,72 @@ static const device_config_t pcnet_isa_config[] = { { .description = "DMA 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t pcnet_vlb_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x300", .value = 0x300 }, { .description = "0x320", .value = 0x320 }, { .description = "0x340", .value = 0x340 }, { .description = "0x360", .value = 0x360 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, .selection = { - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 4", .value = 4 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "IRQ 9", .value = 9 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, { .description = "IRQ 12", .value = 12 }, { .description = "IRQ 15", .value = 15 }, - { .description = "" } + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, .default_string = "", - .default_int = -1 + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index 74b041b35..5138b5168 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -3315,11 +3315,15 @@ nic_close(void *priv) // clang-format off static const device_config_t rtl8139c_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index 2c3aab379..7d988368c 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -1664,29 +1664,41 @@ nic_close(void *priv) // clang-format off static const device_config_t dec_tulip_21143_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t dec_tulip_21140_config[] = { { - .name = "bios", - .description = "Enable BIOS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 1e5496851..1ca8d8697 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -806,46 +806,48 @@ wd_close(void *priv) // clang-format off static const device_config_t wd8003_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x300, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x240", .value = 0x240 }, { .description = "0x280", .value = 0x280 }, { .description = "0x300", .value = 0x300 }, { .description = "0x380", .value = 0x380 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ram_addr", - .description = "RAM Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_addr", + .description = "RAM Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800", .value = 0xC8000 }, { .description = "CC00", .value = 0xCC000 }, { .description = "D000", .value = 0xD0000 }, @@ -854,27 +856,32 @@ static const device_config_t wd8003_config[] = { { .description = "DC00", .value = 0xDC000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd8003eb_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x280, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x280, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x200", .value = 0x200 }, { .description = "0x220", .value = 0x220 }, { .description = "0x240", .value = 0x240 }, @@ -887,32 +894,34 @@ static const device_config_t wd8003eb_config[] = { { .description = "0x380", .value = 0x380 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2/9", .value = 9 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ram_addr", - .description = "RAM Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_addr", + .description = "RAM Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C000", .value = 0xC0000 }, { .description = "C400", .value = 0xC4000 }, { .description = "C800", .value = 0xC8000 }, @@ -923,27 +932,33 @@ static const device_config_t wd8003eb_config[] = { { .description = "DC00", .value = 0xDC000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ram_size", - .description = "RAM size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 8192, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_size", + .description = "RAM size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8192, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8 KB", .value = 8192 }, { .description = "32 KB", .value = 32768 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -952,14 +967,14 @@ static const device_config_t wd8003eb_config[] = { http://www.stack.nl/~marcolz/network/wd80x3.html#WD8013EBT */ static const device_config_t wd8013_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x280, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x280, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x200", .value = 0x200 }, { .description = "0x220", .value = 0x220 }, { .description = "0x240", .value = 0x240 }, @@ -972,16 +987,17 @@ static const device_config_t wd8013_config[] = { { .description = "0x380", .value = 0x380 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 3, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 2/9", .value = 9 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, @@ -992,16 +1008,17 @@ static const device_config_t wd8013_config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ram_addr", - .description = "RAM Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD0000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_addr", + .description = "RAM Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C000", .value = 0xC0000 }, { .description = "C400", .value = 0xC4000 }, { .description = "C800", .value = 0xC8000 }, @@ -1012,63 +1029,78 @@ static const device_config_t wd8013_config[] = { { .description = "DC00", .value = 0xDC000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ram_size", - .description = "RAM size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 16384, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_size", + .description = "RAM size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 16384, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "16 KB", .value = 16384 }, { .description = "64 KB", .value = 65536 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t wd8013epa_config[] = { { - .name = "ram_size", - .description = "Initial RAM size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 16384, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ram_size", + .description = "Initial RAM size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 16384, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "8 KB", .value = 8192 }, { .description = "16 KB", .value = 16384 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mca_mac_config[] = { { - .name = "mac", - .description = "MAC Address", - .type = CONFIG_MAC, - .default_string = "", - .default_int = -1 + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = NULL, + .default_int = -1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index b6a1698c5..4f3d1d1e7 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -1158,14 +1158,14 @@ aha_init(const device_t *info) // clang-format off static const device_config_t aha_154xb_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x334, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x334, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = 0 }, { .description = "0x330", .value = 0x330 }, { .description = "0x334", .value = 0x334 }, @@ -1175,16 +1175,17 @@ static const device_config_t aha_154xb_config[] = { { .description = "0x134", .value = 0x134 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 11, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 11, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, @@ -1193,31 +1194,33 @@ static const device_config_t aha_154xb_config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 5", .value = 5 }, { .description = "DMA 6", .value = 6 }, { .description = "DMA 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "hostid", - .description = "Host ID", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "hostid", + .description = "Host ID", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0", .value = 0 }, { .description = "1", .value = 1 }, { .description = "2", .value = 2 }, @@ -1228,16 +1231,17 @@ static const device_config_t aha_154xb_config[] = { { .description = "7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C800H", .value = 0xc8000 }, { .description = "D000H", .value = 0xd0000 }, @@ -1245,20 +1249,21 @@ static const device_config_t aha_154xb_config[] = { { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t aha_154x_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x334, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x334, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = 0 }, { .description = "0x330", .value = 0x330 }, { .description = "0x334", .value = 0x334 }, @@ -1268,16 +1273,17 @@ static const device_config_t aha_154x_config[] = { { .description = "0x134", .value = 0x134 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 11, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 11, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, @@ -1286,52 +1292,55 @@ static const device_config_t aha_154x_config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 5", .value = 5 }, { .description = "DMA 6", .value = 6 }, { .description = "DMA 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C800H", .value = 0xc8000 }, { .description = "D000H", .value = 0xd0000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "DC00H", .value = 0xdc000 }, { .description = "" } - }, }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t aha_154xcf_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x334, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x334, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = 0 }, { .description = "0x330", .value = 0x330 }, { .description = "0x334", .value = 0x334 }, @@ -1341,16 +1350,17 @@ static const device_config_t aha_154xcf_config[] = { { .description = "0x134", .value = 0x134 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 11, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 11, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, @@ -1359,31 +1369,33 @@ static const device_config_t aha_154xcf_config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 5", .value = 5 }, { .description = "DMA 6", .value = 6 }, { .description = "DMA 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C800H", .value = 0xc8000 }, { .description = "CC00H", .value = 0xcc000 }, @@ -1393,44 +1405,64 @@ static const device_config_t aha_154xcf_config[] = { { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "fdc_addr", - .description = "FDC Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "fdc_addr", + .description = "FDC Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = 0 }, { .description = "0x3f0", .value = FDC_PRIMARY_ADDR }, { .description = "0x370", .value = FDC_SECONDARY_ADDR }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t aha_154xcp_config[] = { { - .name = "bios_rev", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios_rev", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "v1_02_en", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Version 1.02 (English)", .internal_name = "v1_02_en", .bios_type = BIOS_NORMAL, - .files_no = 2, .local = 0, .size = 32768, .files = { "roms/scsi/adaptec/aha1542cp102.bin", - "roms/scsi/adaptec/908301-00_f_mcode_17c9.u12", "" } }, - { .name = "Version 1.02 (German)", .internal_name = "v1_02_de", .bios_type = BIOS_NORMAL, - .files_no = 2, .local = 0, .size = 32768, .files = { "roms/scsi/adaptec/buff_1-0_bios.bin", - "roms/scsi/adaptec/buff_1-0_mcode.bin", "" } }, - { .name = "Version 1.03 (English)", .internal_name = "v1_03_en", .bios_type = BIOS_NORMAL, - .files_no = 2, .local = 0, .size = 32768, .files = { "roms/scsi/adaptec/aha1542cp103.bin", - "roms/scsi/adaptec/908301-00_g_mcode_144c.u12.bin", "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .bios = { + { + .name = "Version 1.02 (English)", + .internal_name = "v1_02_en", + .bios_type = BIOS_NORMAL, + .files_no = 2, + .local = 0, + .size = 32768, + .files = { "roms/scsi/adaptec/aha1542cp102.bin", "roms/scsi/adaptec/908301-00_f_mcode_17c9.u12", "" } + }, + { + .name = "Version 1.02 (German)", + .internal_name = "v1_02_de", + .bios_type = BIOS_NORMAL, + .files_no = 2, + .local = 0, + .size = 32768, + .files = { "roms/scsi/adaptec/buff_1-0_bios.bin", "roms/scsi/adaptec/buff_1-0_mcode.bin", "" } + }, + { + .name = "Version 1.03 (English)", + .internal_name = "v1_03_en", + .bios_type = BIOS_NORMAL, + .files_no = 2, + .local = 0, + .size = 32768, + .files = { "roms/scsi/adaptec/aha1542cp103.bin", "roms/scsi/adaptec/908301-00_g_mcode_144c.u12.bin", "" } + }, { .files_no = 0 } }, }, diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index b235f2c3c..c4745e2df 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1780,14 +1780,14 @@ buslogic_init(const device_t *info) // clang-format off static const device_config_t BT_ISA_Config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x334, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x334, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0x330", .value = 0x330 }, { .description = "0x334", .value = 0x334 }, { .description = "0x230", .value = 0x230 }, @@ -1796,16 +1796,17 @@ static const device_config_t BT_ISA_Config[] = { { .description = "0x134", .value = 0x134 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 11, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 11, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "IRQ 9", .value = 9 }, { .description = "IRQ 10", .value = 10 }, { .description = "IRQ 11", .value = 11 }, @@ -1814,48 +1815,55 @@ static const device_config_t BT_ISA_Config[] = { { .description = "IRQ 15", .value = 15 }, { .description = "", 0 } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "DMA 5", .value = 5 }, { .description = "DMA 6", .value = 6 }, { .description = "DMA 7", .value = 7 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C800H", .value = 0xc8000 }, { .description = "D000H", .value = 0xd0000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "", .value = 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t BT958D_Config[] = { { - .name = "bios", - .description = "Enable BIOS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index d8008cf02..10934880f 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -778,14 +778,14 @@ corel_ls2000_available(void) // clang-format off static const device_config_t ncr53c400_mmio_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800H", .value = 0xc8000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "D000H", .value = 0xd0000 }, @@ -794,36 +794,38 @@ static const device_config_t ncr53c400_mmio_config[] = { { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = -1 }, - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "" } + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t rt1000b_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800H", .value = 0xc8000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "D000H", .value = 0xd0000 }, @@ -832,36 +834,53 @@ static const device_config_t rt1000b_config[] = { { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = -1 }, - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "" } + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "bios_ver", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios_ver", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "v8_10r", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, .bios = { - { .name = "Version 8.10R", .internal_name = "v8_10r", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { RT1000B_810R_ROM, "" } }, - { .name = "Version 8.20R", .internal_name = "v8_20r", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 8192, .files = { RT1000B_820R_ROM, "" } }, + { + .name = "Version 8.10R", + .internal_name = "v8_10r", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { RT1000B_810R_ROM, "" } + }, + { + .name = "Version 8.20R", + .internal_name = "v8_20r", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { RT1000B_820R_ROM, "" } + }, { .files_no = 0 } }, }, @@ -870,34 +889,35 @@ static const device_config_t rt1000b_config[] = { static const device_config_t rt1000b_mc_config[] = { { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = -1 }, - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "" } + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t t130b_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, { .description = "C800H", .value = 0xc8000 }, { .description = "CC00H", .value = 0xcc000 }, @@ -905,38 +925,41 @@ static const device_config_t t130b_config[] = { { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0350, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0350, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "240H", .value = 0x0240 }, { .description = "250H", .value = 0x0250 }, { .description = "340H", .value = 0x0340 }, { .description = "350H", .value = 0x0350 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = -1 }, - { .description = "IRQ 3", .value = 3 }, - { .description = "IRQ 5", .value = 5 }, - { .description = "IRQ 7", .value = 7 }, - { .description = "" } + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index d26da3bb3..f87f22452 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -2663,19 +2663,20 @@ ncr53c8xx_close(void *priv) static const device_config_t ncr53c8xx_pci_config[] = { // clang-format off { - .name = "bios", - .description = "BIOS Revision", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios", + .description = "BIOS Revision", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "SDMS 4.x BIOS", .value = 2 }, { .description = "SDMS 3.x BIOS", .value = 1 }, { .description = "Disable BIOS", .value = 0 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c index 012d5524b..7c991bdb1 100644 --- a/src/scsi/scsi_pcscsi.c +++ b/src/scsi/scsi_pcscsi.c @@ -2458,11 +2458,15 @@ esp_close(void *priv) static const device_config_t bios_enable_config[] = { // clang-format off { - .name = "bios", - .description = "Enable BIOS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index cbf6ff205..d6a26b7d0 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1231,18 +1231,19 @@ spock_available(void) static const device_config_t spock_rom_config[] = { // clang-format off { - .name = "bios_ver", - .description = "BIOS Revision", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_ver", + .description = "BIOS Revision", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "1991 BIOS (>1GB)", .value = 1 }, { .description = "1990 BIOS", .value = 0 }, { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index ff5f584f1..77c2302cc 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -554,43 +554,49 @@ t128_available(void) // clang-format off static const device_config_t t128_config[] = { { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xD8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xD8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800H", .value = 0xc8000 }, { .description = "CC00H", .value = 0xcc000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "DC00H", .value = 0xdc000 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "None", .value = -1 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } }, + .bios = { { 0 } } }, { - .name = "boot", - .description = "Enable BIOS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "boot", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -618,6 +624,7 @@ const device_t scsi_t228_device = { .local = 0, .init = t128_init, .close = t128_close, + .close = t128_close, .reset = NULL, .available = t128_available, .speed_changed = NULL, diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 6ba017cd1..027c85b79 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -319,153 +319,195 @@ fluidsynth_close(void *priv) static const device_config_t fluidsynth_config[] = { // clang-format off { - .name = "sound_font", - .description = "SoundFont", - .type = CONFIG_FNAME, - .default_string = "", - .file_filter = "SF2 Sound Fonts (*.sf2)|*.sf2" + .name = "sound_font", + .description = "SoundFont", + .type = CONFIG_FNAME, + .default_string = NULL, + .default_int = 0, + .file_filter = "SF2 Sound Fonts (*.sf2)|*.sf2", + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "output_gain", - .description = "Output Gain", - .type = CONFIG_SPINNER, - .spinner = { - .min = 0, + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 100, + .file_filter = NULL, + .spinner = { + .min = 0, .max = 100 }, - .default_int = 100 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus", - .description = "Chorus", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "chorus", + .description = "Chorus", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus_voices", - .description = "Chorus Voices", - .type = CONFIG_SPINNER, + .name = "chorus_voices", + .description = "Chorus Voices", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 3, + .file_filter = NULL, .spinner = { - .min = 0, + .min = 0, .max = 99 }, - .default_int = 3 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus_level", - .description = "Chorus Level", - .type = CONFIG_SPINNER, - .spinner = { - .min = 0, + .name = "chorus_level", + .description = "Chorus Level", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 20, + .file_filter = NULL, + .spinner = { + .min = 0, .max = 100 }, - .default_int = 20 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus_speed", - .description = "Chorus Speed", - .type = CONFIG_SPINNER, + .name = "chorus_speed", + .description = "Chorus Speed", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 30, + .file_filter = NULL, .spinner = { - .min = 10, + .min = 10, .max = 500 }, - .default_int = 30 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus_depth", - .description = "Chorus Depth", - .type = CONFIG_SPINNER, + .name = "chorus_depth", + .description = "Chorus Depth", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 80, + .file_filter = NULL, .spinner = { - .min = 0, + .min = 0, .max = 2560 }, - .default_int = 80 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "chorus_waveform", - .description = "Chorus Waveform", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "Sine", - .value = 0 - }, - { - .description = "Triangle", - .value = 1 - } + .name = "chorus_waveform", + .description = "Chorus Waveform", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Sine", .value = 0 }, + { .description = "Triangle", .value = 1 }, + { .description = "" } }, - .default_int = 0 + .bios = { { 0 } } }, { - .name = "reverb", - .description = "Reverb", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "reverb_room_size", - .description = "Reverb Room Size", - .type = CONFIG_SPINNER, + .name = "reverb_room_size", + .description = "Reverb Room Size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 20, + .file_filter = NULL, .spinner = { - .min = 0, + .min = 0, .max = 100 }, - .default_int = 20 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "reverb_damping", - .description = "Reverb Damping", - .type = CONFIG_SPINNER, + .name = "reverb_damping", + .description = "Reverb Damping", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, .spinner = { - .min = 0, + .min = 0, .max = 100 }, - .default_int = 0 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "reverb_width", - .description = "Reverb Width", - .type = CONFIG_SPINNER, - .spinner = { - .min = 0, + .name = "reverb_width", + .description = "Reverb Width", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { + .min = 0, .max = 1000 }, - .default_int = 5 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "reverb_level", - .description = "Reverb Level", - .type = CONFIG_SPINNER, - .spinner = { - .min = 0, + .name = "reverb_level", + .description = "Reverb Level", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 90, + .file_filter = NULL, + .spinner = { + .min = 0, .max = 100 }, - .default_int = 90 + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "interpolation", - .description = "Interpolation Method", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "None", - .value = 0 - }, - { - .description = "Linear", - .value = 1 - }, - { - .description = "4th Order", - .value = 2 - }, - { - .description = "7th Order", - .value = 3 - } + .name = "interpolation", + .description = "Interpolation Method", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "Linear", .value = 1 }, + { .description = "4th Order", .value = 2 }, + { .description = "7th Order", .value = 3 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -484,4 +526,3 @@ const device_t fluidsynth_device = { .force_redraw = NULL, .config = fluidsynth_config }; - diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index ab2165c52..67f1d26c8 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -377,42 +377,60 @@ mt32_close(void *priv) static const device_config_t mt32_config[] = { // clang-format off { - .name = "output_gain", - .description = "Output Gain", - .type = CONFIG_SPINNER, - .spinner = { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 100, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 100 + }, + .selection = { { 0 } } + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } } + }, + { + .name = "reverb_output_gain", + .description = "Reverb Output Gain", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 100, + .file_filter = NULL, + .spinner = { .min = 0, .max = 100 }, - .default_int = 100 + .selection = { { 0 } } }, { - .name = "reverb", - .description = "Reverb", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "reversed_stereo", + .description = "Reversed stereo", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } } }, { - .name = "reverb_output_gain", - .description = "Reverb Output Gain", - .type = CONFIG_SPINNER, - .spinner = { - .min = 0, - .max = 100 - }, - .default_int = 100 - }, - { - .name = "reversed_stereo", - .description = "Reversed stereo", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "nice_ramp", - .description = "Nice ramp", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "nice_ramp", + .description = "Nice ramp", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/midi_rtmidi.cpp b/src/sound/midi_rtmidi.cpp index 9da3fdb91..11203c3f2 100644 --- a/src/sound/midi_rtmidi.cpp +++ b/src/sound/midi_rtmidi.cpp @@ -231,11 +231,15 @@ rtmidi_in_get_dev_name(int num, char *s) static const device_config_t system_midi_config[] = { // clang-format off { - .name = "midi", - .description = "MIDI Output Device", - .type = CONFIG_MIDI_OUT, - .default_string = "", - .default_int = 0 + .name = "midi", + .description = "MIDI Output Device", + .type = CONFIG_MIDI_OUT, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -244,32 +248,48 @@ static const device_config_t system_midi_config[] = { static const device_config_t midi_input_config[] = { // clang-format off { - .name = "midi_input", - .description = "MIDI Input Device", - .type = CONFIG_MIDI_IN, - .default_string = "", - .default_int = 0 + .name = "midi_input", + .description = "MIDI Input Device", + .type = CONFIG_MIDI_IN, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "realtime", - .description = "MIDI Real time", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "realtime", + .description = "MIDI Real time", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "thruchan", - .description = "MIDI Thru", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "thruchan", + .description = "MIDI Thru", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "clockout", - .description = "MIDI Clockout", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "clockout", + .description = "MIDI Clockout", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 8a809803d..360da3fec 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -1192,73 +1192,69 @@ adgold_close(void *priv) static const device_config_t adgold_config[] = { // clang-format off { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 4", - .value = 4 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "Low DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "Low DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "gameport", - .description = "Enable Game port", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "surround", - .description = "Surround module", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "surround", + .description = "Surround module", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 9e520bcf5..f8a6e4153 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -2737,11 +2737,15 @@ es137x_speed_changed(void *priv) static const device_config_t es1370_config[] = { // clang-format off { - .name = "receive_input", - .description = "Receive input (MIDI)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive input (MIDI)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -2750,28 +2754,30 @@ static const device_config_t es1370_config[] = { static const device_config_t es1371_config[] = { // clang-format off { - .name = "codec", - .description = "Codec", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "Asahi Kasei AK4540", - .value = AC97_CODEC_AK4540 - }, - { - .description = "TriTech TR28023 / Creative CT1297", - .value = AC97_CODEC_TR28023 - }, - { .description = "" } + .name = "codec", + .description = "Codec", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = AC97_CODEC_TR28023, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Asahi Kasei AK4540", .value = AC97_CODEC_AK4540 }, + { .description = "TriTech TR28023 / Creative CT1297", .value = AC97_CODEC_TR28023 }, + { .description = "" } }, - .default_int = AC97_CODEC_TR28023 + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -2780,32 +2786,31 @@ static const device_config_t es1371_config[] = { static const device_config_t es1373_config[] = { // clang-format off { - .name = "codec", - .description = "Codec", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "Crystal CS4297A", - .value = AC97_CODEC_CS4297A - }, - { - .description = "SigmaTel STAC9721T", - .value = AC97_CODEC_STAC9721 - }, - { - .description = "TriTech TR28023 / Creative CT1297", - .value = AC97_CODEC_TR28023 - }, + .name = "codec", + .description = "Codec", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = AC97_CODEC_CS4297A, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Crystal CS4297A", .value = AC97_CODEC_CS4297A }, + { .description = "SigmaTel STAC9721T", .value = AC97_CODEC_STAC9721 }, + { .description = "TriTech TR28023 / Creative CT1297", .value = AC97_CODEC_TR28023 }, { .description = "" } }, - .default_int = AC97_CODEC_CS4297A + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -2814,32 +2819,31 @@ static const device_config_t es1373_config[] = { static const device_config_t ct5880_config[] = { // clang-format off { - .name = "codec", - .description = "Codec", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "SigmaTel STAC9708T", - .value = AC97_CODEC_STAC9708 - }, - { - .description = "SigmaTel STAC9721T (stereo)", - .value = AC97_CODEC_STAC9721 - }, - { - .description = "TriTech TR28023 / Creative CT1297", - .value = AC97_CODEC_TR28023 - }, - { .description = "" } + .name = "codec", + .description = "Codec", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = AC97_CODEC_STAC9708, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "SigmaTel STAC9708T", .value = AC97_CODEC_STAC9708 }, + { .description = "SigmaTel STAC9721T (stereo)", .value = AC97_CODEC_STAC9721 }, + { .description = "TriTech TR28023 / Creative CT1297", .value = AC97_CODEC_TR28023 }, + { .description = "" } }, - .default_int = AC97_CODEC_STAC9708 + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -2848,11 +2852,14 @@ static const device_config_t ct5880_config[] = { static const device_config_t es1371_onboard_config[] = { // clang-format off { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index dfbab2bd3..ea682a82c 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1315,142 +1315,127 @@ azt_speed_changed(void *priv) static const device_config_t azt1605_config[] = { // clang-format off { - .name = "codec", - .description = "CODEC", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "CS4248", - .value = AD1848_TYPE_CS4248 - }, - { - .description = "CS4231", - .value = AD1848_TYPE_CS4231 - }, + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = AD1848_TYPE_CS4248, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "CS4248", .value = AD1848_TYPE_CS4248 }, + { .description = "CS4231", .value = AD1848_TYPE_CS4231 }, + { .description = "" } }, - .default_int = AD1848_TYPE_CS4248 + .bios = { { 0 } } }, { - .name = "wss_interrupt_after_config", - .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", - .type = CONFIG_BINARY, - .default_int = 0 + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "addr", - .description = "SB Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "Use EEPROM setting", - .value = 0 - }, - { - .description = "" - } - } - }, - { - .name = "sb_dma8", - .description = "SB low DMA", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } + .name = "addr", + .description = "SB Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "Use EEPROM setting", .value = 0 }, + { .description = "" } }, - .default_int = 1 + .bios = { { 0 } } }, { - .name = "wss_irq", - .description = "WSS IRQ", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "" - } + .name = "sb_dma8", + .description = "SB low DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } }, - .default_int = 10 + .bios = { { 0 } } }, - { - .name = "wss_dma", - .description = "WSS DMA", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } - }, - .default_int = 0 + { + .name = "wss_irq", + .description = "WSS IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 10, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, - { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "wss_dma", + .description = "WSS DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1459,119 +1444,111 @@ static const device_config_t azt1605_config[] = { static const device_config_t azt2316a_config[] = { // clang-format off { - .name = "codec", - .description = "CODEC", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "CS4248", - .value = AD1848_TYPE_CS4248 - }, - { - .description = "CS4231", - .value = AD1848_TYPE_CS4231 - }, + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = AD1848_TYPE_CS4248, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "CS4248", .value = AD1848_TYPE_CS4248 }, + { .description = "CS4231", .value = AD1848_TYPE_CS4231 }, + { .description = "" } }, - .default_int = AD1848_TYPE_CS4248 + .bios = { { 0 } } }, { - .name = "wss_interrupt_after_config", - .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", - .type = CONFIG_BINARY, - .default_int = 0 + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "addr", - .description = "SB Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "Use EEPROM setting", - .value = 0 - }, - { - .description = "" - } - } - }, - { - .name = "wss_irq", - .description = "WSS IRQ", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "IRQ 11", - .value = 11 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "" - } + .name = "addr", + .description = "SB Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "Use EEPROM setting", .value = 0 }, + { .description = "" } }, - .default_int = 10 + .bios = { { 0 } } }, { - .name = "wss_dma", - .description = "WSS DMA", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { - .description = "" - } + .name = "wss_irq", + .description = "WSS IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 10, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } }, - .default_int = 0 + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "wss_dma", + .description = "WSS DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_cmi8x38.c b/src/sound/snd_cmi8x38.c index 5f75d0dc3..a41f53865 100644 --- a/src/sound/snd_cmi8x38.c +++ b/src/sound/snd_cmi8x38.c @@ -1508,11 +1508,15 @@ cmi8x38_close(void *priv) static const device_config_t cmi8x38_config[] = { // clang-format off { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1521,18 +1525,26 @@ static const device_config_t cmi8x38_config[] = { static const device_config_t cmi8738_config[] = { // clang-format off { - .name = "six_channel", - .description = "6CH variant (6-channel)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "six_channel", + .description = "6CH variant (6-channel)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index f8db04fed..66dff80f3 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -200,42 +200,23 @@ cms_close(void *priv) static const device_config_t cms_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x210", - .value = 0x210 - }, - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { - .description = "0x260", - .value = 0x260 - }, - { - .description = "" - } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x210", .value = 0x210 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x260", .value = 0x260 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 9dcf0f00b..f2651c72f 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -1431,92 +1431,67 @@ gus_speed_changed(void *priv) static const device_config_t gus_config[] = { // clang-format off { - .name = "type", - .description = "GUS type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "Classic", - .value = GUS_CLASSIC - }, + .name = "type", + .description = "GUS type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Classic", .value = GUS_CLASSIC }, #ifdef USE_GUSMAX - { - .description = "MAX", - .value = GUS_MAX - }, + { .description = "MAX", .value = GUS_MAX }, #endif /*USE_GUSMAX */ - { NULL } + { NULL } }, + .bios = { { 0 } } }, { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "210H", - .value = 0x210 - }, - { - .description = "220H", - .value = 0x220 - }, - { - .description = "230H", - .value = 0x230 - }, - { - .description = "240H", - .value = 0x240 - }, - { - .description = "250H", - .value = 0x250 - }, - { - .description = "260H", - .value = 0x260 - }, + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "210H", .value = 0x210 }, + { .description = "220H", .value = 0x220 }, + { .description = "230H", .value = 0x230 }, + { .description = "240H", .value = 0x240 }, + { .description = "250H", .value = 0x250 }, + { .description = "260H", .value = 0x260 }, + { NULL } }, + .bios = { { 0 } } }, { - .name = "gus_ram", - "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "256 KB", - .value = 0 - }, - { - .description = "512 KB", - .value = 1 - }, - { - .description = "1 MB", - .value = 2 - }, - { NULL } - } + .name = "gus_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 0 }, + { .description = "512 KB", .value = 1 }, + { .description = "1 MB", .value = 2 }, + { NULL } + }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 09d1757eb..bec2ed39c 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1804,106 +1804,59 @@ mpu401_standalone_close(void *priv) static const device_config_t mpu401_standalone_config[] = { // clang-format off { - .name = "base", - .description = "MPU-401 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x330, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { - .description = "0x300", - .value = 0x300 - }, - { - .description = "0x320", - .value = 0x320 - }, - { - .description = "0x330", - .value = 0x330 - }, - { - .description = "0x332", - .value = 0x332 - }, - { - .description = "0x334", - .value = 0x334 - }, - { - .description = "0x336", - .value = 0x336 - }, - { - .description = "0x340", - .value = 0x340 - }, - { - .description = "0x350", - .value = 0x350 - }, - { .description = "" } - } + .name = "base", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x330, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x320", .value = 0x320 }, + { .description = "0x330", .value = 0x330 }, + { .description = "0x332", .value = 0x332 }, + { .description = "0x334", .value = 0x334 }, + { .description = "0x336", .value = 0x336 }, + { .description = "0x340", .value = 0x340 }, + { .description = "0x350", .value = 0x350 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "MPU-401 IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 2, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 4", - .value = 4 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 6", - .value = 6 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "irq", + .description = "MPU-401 IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 6", .value = 6 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1912,46 +1865,34 @@ static const device_config_t mpu401_standalone_config[] = { static const device_config_t mpu401_standalone_mca_config[] = { // clang-format off { - .name = "irq", - .description = "MPU-401 IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 9, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 4", - .value = 4 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 6", - .value = 6 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 9", - .value = 9 - }, - { .description = "" } - } + .name = "irq", + .description = "MPU-401 IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 9, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 6", .value = 6 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 9", .value = 9 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_opl2board.c b/src/sound/snd_opl2board.c index a76b6bf4d..632ad85f1 100644 --- a/src/sound/snd_opl2board.c +++ b/src/sound/snd_opl2board.c @@ -167,13 +167,15 @@ opl2board_device_close(void *priv) static const device_config_t opl2board_config[] = { { - .name = "host_serial_path", - .description = "Host Serial Device", - .type = CONFIG_SERPORT, + .name = "host_serial_path", + .description = "Host Serial Device", + .type = CONFIG_SERPORT, .default_string = "", - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } } + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index 7058d918c..d5c01dbaf 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -456,18 +456,26 @@ mirosound_pcm10_available(void) static const device_config_t optimc_config[] = { // clang-format off { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 05df32322..ddb135357 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -2401,25 +2401,37 @@ pas16_close(void *priv) static const device_config_t pas16_config[] = { { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 0b09a7b2e..7de8ec824 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -245,40 +245,23 @@ pssj_close(void *priv) static const device_config_t pssj_isa_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x2C0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x0C0", - .value = 0x0C0 - }, - { - .description = "0x0E0", - .value = 0x0E0 - }, - { - .description = "0x1C0", - .value = 0x1C0 - }, - { - .description = "0x1E0", - .value = 0x1E0 - }, - { - .description = "0x2C0", - .value = 0x2C0 - }, - { - .description = "0x2E0", - .value = 0x2E0 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x2C0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x0C0", .value = 0x0C0 }, + { .description = "0x0E0", .value = 0x0E0 }, + { .description = "0x1C0", .value = 0x1C0 }, + { .description = "0x1E0", .value = 0x1E0 }, + { .description = "0x2C0", .value = 0x2C0 }, + { .description = "0x2E0", .value = 0x2E0 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index ea961a6d3..ca233b252 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -4081,211 +4081,165 @@ sb_speed_changed(void *priv) // clang-format off static const device_config_t sb_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x210", - .value = 0x210 - }, - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { - .description = "0x260", - .value = 0x260 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x210", .value = 0x210 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x260", .value = 0x260 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 - }, + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb15_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x210", - .value = 0x210 - }, - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { - .description = "0x260", - .value = 0x260 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x210", .value = 0x210 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x260", .value = 0x260 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "cms", - .description = "Enable CMS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "cms", + .description = "Enable CMS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -4294,1064 +4248,888 @@ static const device_config_t sb2_config[] = { { .name = "base", .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { .description = "" } - } + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "mixaddr", - .description = "Mixer", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "Disabled", - .value = 0 - }, - { - .description = "0x250", - .value = 0x250 - }, - { - .description = "0x260", - .value = 0x260 - }, - { .description = "" } - } + .name = "mixaddr", + .description = "Mixer", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x260", .value = 0x260 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "cms", - .description = "Enable CMS", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "cms", + .description = "Enable CMS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_mcv_config[] = { { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 3", - .value = 3 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_pro_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_pro_mcv_config[] = { { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_16_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x260", - .value = 0x260 - }, - { - .description = "0x280", - .value = 0x280 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x260", .value = 0x260 }, + { .description = "0x280", .value = 0x280 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "base401", - .description = "MPU-401 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x330, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "Disabled", - .value = 0 - }, - { - .description = "0x300", - .value = 0x300 - }, - { - .description = "0x330", - .value = 0x330 - }, - { .description = "" } - } + .name = "base401", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x330, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x330", .value = 0x330 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "Low DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "Low DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma16", - .description = "High DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 5", - .value = 5 - }, - { - .description = "DMA 6", - .value = 6 - }, - { - .description = "DMA 7", - .value = 7 - }, - { .description = "" } - } + .name = "dma16", + .description = "High DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_16_pnp_config[] = { { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_goldfinch_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "None", - .value = 0 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "16 MB", - .value = 16384 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "4 MB", .value = 4096 }, + { .description = "8 MB", .value = 8192 }, + { .description = "16 MB", .value = 16384 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_32_pnp_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "None", - .value = 0 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "512 KB", .value = 512 }, + { .description = "2 MB", .value = 2048 }, + { .description = "8 MB", .value = 8192 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_awe32_config[] = { { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x220, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x260", - .value = 0x260 - }, - { - .description = "0x280", - .value = 0x280 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x220", .value = 0x220 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x260", .value = 0x260 }, + { .description = "0x280", .value = 0x280 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "emu_base", - .description = "EMU8000 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x620, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x620", - .value = 0x620 - }, - { - .description = "0x640", - .value = 0x640 - }, - { - .description = "0x660", - .value = 0x660 - }, - { - .description = "0x680", - .value = 0x680 - }, - { .description = ""} - } + .name = "emu_base", + .description = "EMU8000 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x620, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x620", .value = 0x620 }, + { .description = "0x640", .value = 0x640 }, + { .description = "0x660", .value = 0x660 }, + { .description = "0x680", .value = 0x680 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "base401", - .description = "MPU-401 Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x330, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "Disabled", - .value = 0 - }, - { - .description = "0x300", - .value = 0x300 - }, - { - .description = "0x330", - .value = 0x330 - }, - { .description = "" } - } + .name = "base401", + .description = "MPU-401 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x330, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x300", .value = 0x300 }, + { .description = "0x330", .value = 0x330 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "irq", - .description = "IRQ", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { .description = "" } - } + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "Low DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + .name = "dma", + .description = "Low DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "dma16", - .description = "High DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 5, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "DMA 5", - .value = 5 - }, - { - .description = "DMA 6", - .value = 6 - }, - { - .description = "DMA 7", - .value = 7 - }, - { .description = "" } - } + .name = "dma16", + .description = "High DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "DMA 5", .value = 5 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "None", - .value = 0 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "28 MB", - .value = 28672 - }, - { "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "512 KB", .value = 512 }, + { .description = "2 MB", .value = 2048 }, + { .description = "8 MB", .value = 8192 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_awe32_pnp_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "None", - .value = 0 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = 0 }, + { .description = "512 KB", .value = 512 }, + { .description = "2 MB", .value = 2048 }, + { .description = "8 MB", .value = 8192 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_awe64_value_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 512, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "12 MB", - .value = 12288 - }, - { - .description = "16 MB", - .value = 16384 - }, - { - .description = "20 MB", - .value = 20480 - }, - { - .description = "24 MB", - .value = 24576 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "4 MB", .value = 4096 }, + { .description = "8 MB", .value = 8192 }, + { .description = "12 MB", .value = 12288 }, + { .description = "16 MB", .value = 16384 }, + { .description = "20 MB", .value = 20480 }, + { .description = "24 MB", .value = 24576 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_awe64_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 1024, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "12 MB", - .value = 12288 - }, - { - .description = "16 MB", - .value = 16384 - }, - { - .description = "20 MB", - .value = 20480 - }, - { - .description = "24 MB", - .value = 24576 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "4 MB", .value = 4096 }, + { .description = "8 MB", .value = 8192 }, + { .description = "12 MB", .value = 12288 }, + { .description = "16 MB", .value = 16384 }, + { .description = "20 MB", .value = 20480 }, + { .description = "24 MB", .value = 24576 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t sb_awe64_gold_config[] = { { - .name = "onboard_ram", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 4096, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "8 MB", - .value = 8192 - }, - { - .description = "12 MB", - .value = 12288 - }, - { - .description = "16 MB", - .value = 16384 - }, - { - .description = "20 MB", - .value = 20480 - }, - { - .description = "24 MB", - .value = 24576 - }, - { - .description = "28 MB", - .value = 28672 - }, - { .description = "" } - } + .name = "onboard_ram", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4096, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "4 MB", .value = 4096 }, + { .description = "8 MB", .value = 8192 }, + { .description = "12 MB", .value = 12288 }, + { .description = "16 MB", .value = 16384 }, + { .description = "20 MB", .value = 20480 }, + { .description = "24 MB", .value = 24576 }, + { .description = "28 MB", .value = 28672 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -5361,120 +5139,80 @@ static const device_config_t ess_688_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x220, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { .description = "" } - } + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 5, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { .description = "" } - } + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "dma", .description = "DMA", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "ide_ctrl", .description = "IDE Controller", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x0000, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "Disabled", - .value = 0x0000 - }, - { - .description = "0x170, IRQ 15", - .value = 0xf170 - }, - { - .description = "0x1E8, IRQ 11", - .value = 0xb1e8 - }, - { - .description = "0x168, IRQ 9", - .value = 0x9168 - }, - { - .description = "0x168, IRQ 10", - .value = 0xa168 - }, - { .description = "" } - } + { .description = "Disabled", .value = 0x0000 }, + { .description = "0x170, IRQ 15", .value = 0xf170 }, + { .description = "0x1E8, IRQ 11", .value = 0xb1e8 }, + { .description = "0x168, IRQ 9", .value = 0x9168 }, + { .description = "0x168, IRQ 10", .value = 0xa168 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "receive_input", .description = "Receive MIDI input", .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -5484,170 +5222,154 @@ static const device_config_t ess_1688_config[] = { .name = "base", .description = "Address", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x220, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "0x220", - .value = 0x220 - }, - { - .description = "0x230", - .value = 0x230 - }, - { - .description = "0x240", - .value = 0x240 - }, - { - .description = "0x250", - .value = 0x250 - }, - { .description = "" } - } + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "irq", .description = "IRQ", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 5, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "IRQ 2", - .value = 2 - }, - { - .description = "IRQ 5", - .value = 5 - }, - { - .description = "IRQ 7", - .value = 7 - }, - { - .description = "IRQ 10", - .value = 10 - }, - { .description = "" } - } + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "dma", .description = "DMA", .type = CONFIG_SELECTION, - .default_string = "", + .default_string = NULL, .default_int = 1, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "DMA 0", - .value = 0 - }, - { - .description = "DMA 1", - .value = 1 - }, - { - .description = "DMA 3", - .value = 3 - }, - { .description = "" } - } + { .description = "DMA 0", .value = 0 }, + { .description = "DMA 1", .value = 1 }, + { .description = "DMA 3", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "ide_ctrl", .description = "IDE Controller", .type = CONFIG_HEX16, - .default_string = "", + .default_string = NULL, .default_int = 0x0000, - .file_filter = "", + .file_filter = NULL, .spinner = { 0 }, .selection = { - { - .description = "Disabled", - .value = 0x0000 - }, - { - .description = "0x170, IRQ 15", - .value = 0xf170 - }, - { - .description = "0x1E8, IRQ 11", - .value = 0xb1e8 - }, - { - .description = "0x168, IRQ 9", - .value = 0x9168 - }, - { - .description = "0x168, IRQ 10", - .value = 0xa168 - }, - { .description = "" } - } + { .description = "Disabled", .value = 0x0000 }, + { .description = "0x170, IRQ 15", .value = 0xf170 }, + { .description = "0x1E8, IRQ 11", .value = 0xb1e8 }, + { .description = "0x168, IRQ 9", .value = 0x9168 }, + { .description = "0x168, IRQ 10", .value = 0xa168 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 0 + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ess_688_pnp_config[] = { { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ess_1688_pnp_config[] = { { - .name = "control_pc_speaker", - .description = "Control PC speaker", - .type = CONFIG_BINARY, + .name = "control_pc_speaker", + .description = "Control PC speaker", + .type = CONFIG_BINARY, .default_string = "", - .default_int = 0 + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input", - .description = "Receive MIDI input", - .type = CONFIG_BINARY, + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, .default_string = "", - .default_int = 1 + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "receive_input401", - .description = "Receive MIDI input (MPU-401)", - .type = CONFIG_BINARY, + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, .default_string = "", - .default_int = 0 + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/sound/snd_sn76489.c b/src/sound/snd_sn76489.c index 89064bea4..569d698d5 100644 --- a/src/sound/snd_sn76489.c +++ b/src/sound/snd_sn76489.c @@ -268,40 +268,23 @@ sn76489_device_close(void *priv) static const device_config_t tndy_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x0C0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x0C0", - .value = 0x0C0 - }, - { - .description = "0x0E0", - .value = 0x0E0 - }, - { - .description = "0x1C0", - .value = 0x1C0 - }, - { - .description = "0x1E0", - .value = 0x1E0 - }, - { - .description = "0x2C0", - .value = 0x2C0 - }, - { - .description = "0x2E0", - .value = 0x2E0 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x0C0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x0C0", .value = 0x0C0 }, + { .description = "0x0E0", .value = 0x0E0 }, + { .description = "0x1C0", .value = 0x1C0 }, + { .description = "0x1E0", .value = 0x1E0 }, + { .description = "0x2C0", .value = 0x2C0 }, + { .description = "0x2E0", .value = 0x2E0 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/sound/snd_ssi2001.c b/src/sound/snd_ssi2001.c index 0e1bbd96c..f1620b817 100644 --- a/src/sound/snd_ssi2001.c +++ b/src/sound/snd_ssi2001.c @@ -136,39 +136,32 @@ entertainer_close(void *priv) static const device_config_t ssi2001_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x280, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x280", - .value = 0x280 - }, - { - .description = "0x2A0", - .value = 0x2A0 - }, - { - .description = "0x2C0", - .value = 0x2C0 - }, - { - .description = "0x2E0", - .value = 0x2E0 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x280, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x280", .value = 0x280 }, + { .description = "0x2A0", .value = 0x2A0 }, + { .description = "0x2C0", .value = 0x2C0 }, + { .description = "0x2E0", .value = 0x2E0 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "gameport", - .description = "Enable Game port", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off @@ -177,11 +170,15 @@ static const device_config_t ssi2001_config[] = { static const device_config_t entertainer_config[] = { // clang-format off { - .name = "gameport", - .description = "Enable Game port", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "gameport", + .description = "Enable Game port", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 0f37cbf27..c55e5f57b 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -245,39 +245,32 @@ wss_speed_changed(void *priv) static const device_config_t wss_config[] = { // clang-format off { - .name = "base", - .description = "Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x530, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "0x530", - .value = 0x530 - }, - { - .description = "0x604", - .value = 0x604 - }, - { - .description = "0xe80", - .value = 0xe80 - }, - { - .description = "0xf40", - .value = 0xf40 - }, - { .description = "" } - } + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x530, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x530", .value = 0x530 }, + { .description = "0x604", .value = 0x604 }, + { .description = "0xe80", .value = 0xe80 }, + { .description = "0xf40", .value = 0xf40 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "opl", - .description = "Enable OPL", - .type = CONFIG_BINARY, - .default_string = "", - .default_int = 1 + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 73abfe1ed..09b054895 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -3976,52 +3976,44 @@ ibm8514_force_redraw(void *priv) // clang-format off static const device_config_t isa_ext8514_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "extensions", - .description = "Vendor", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "IBM", - .value = 0 - }, - { - .description = "ATI", - .value = 1 - }, - { - .description = "" - } - } + .name = "extensions", + .description = "Vendor", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IBM", .value = 0 }, + { .description = "ATI", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_string = "", - .default_int = 0xc8000, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc8000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800h", .value = 0xc8000 }, { .description = "CA00h", .value = 0xca000 }, { .description = "CC00h", .value = 0xcc000 }, @@ -4034,8 +4026,9 @@ static const device_config_t isa_ext8514_config[] = { { .description = "DA00h", .value = 0xda000 }, { .description = "DC00h", .value = 0xdc000 }, { .description = "DE00h", .value = 0xde000 }, - { .description = "" } + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -4043,76 +4036,67 @@ static const device_config_t isa_ext8514_config[] = { // clang-format off static const device_config_t mca_ext8514_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "extensions", - .description = "Vendor", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "IBM", - .value = 0 - }, - { - .description = "ATI", - .value = 1 - }, - { - .description = "" - } - } + .name = "extensions", + .description = "Vendor", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IBM", .value = 0 }, + { .description = "ATI", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; // clang-format off const device_t gen8514_isa_device = { - .name = "IBM 8514/A clone (ISA)", + .name = "IBM 8514/A clone (ISA)", .internal_name = "8514_isa", - .flags = DEVICE_AT | DEVICE_ISA, - .local = 0, - .init = ibm8514_init, - .close = ibm8514_close, - .reset = NULL, + .flags = DEVICE_AT | DEVICE_ISA, + .local = 0, + .init = ibm8514_init, + .close = ibm8514_close, + .reset = NULL, .available = NULL, .speed_changed = ibm8514_speed_changed, - .force_redraw = ibm8514_force_redraw, - .config = isa_ext8514_config + .force_redraw = ibm8514_force_redraw, + .config = isa_ext8514_config }; const device_t ibm8514_mca_device = { - .name = "IBM 8514/A (MCA)", + .name = "IBM 8514/A (MCA)", .internal_name = "8514_mca", - .flags = DEVICE_MCA, - .local = 0, - .init = ibm8514_init, - .close = ibm8514_close, - .reset = NULL, + .flags = DEVICE_MCA, + .local = 0, + .init = ibm8514_init, + .close = ibm8514_close, + .reset = NULL, .available = NULL, .speed_changed = ibm8514_speed_changed, - .force_redraw = ibm8514_force_redraw, - .config = mca_ext8514_config + .force_redraw = ibm8514_force_redraw, + .config = mca_ext8514_config }; - void ibm8514_device_add(void) { diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 59688087f..9a9be6ff6 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -329,23 +329,19 @@ ati18800_force_redraw(void *priv) static const device_config_t ati18800_wonder_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "" - } - } + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 4c039d9e6..156e95425 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -744,27 +744,20 @@ ati28800_force_redraw(void *priv) // clang-format off static const device_config_t ati28800_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; @@ -772,27 +765,20 @@ static const device_config_t ati28800_config[] = { #ifdef USE_XL24 static const device_config_t ati28800_wonderxl_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 1d2326192..9b7a67f31 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -4711,50 +4711,39 @@ mach64_force_redraw(void *priv) // clang-format off static const device_config_t mach64gx_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mach64vt2_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 5cd29d814..06a60449f 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -6353,104 +6353,76 @@ mach_force_redraw(void *priv) // clang-format off static const device_config_t mach8_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mach32_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2048, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2048, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "4 MB", .value = 4096 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t mach32_pci_config[] = { { - .name = "ramdac", - .description = "RAMDAC type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "ATI 68860", - .value = 0 - }, - { - .description = "ATI 68875", - .value = 1 - }, - { - .description = "" - } - } + .name = "ramdac", + .description = "RAMDAC type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "ATI 68860", .value = 0 }, + { .description = "ATI 68875", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2048, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "4 MB", - .value = 4096 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2048, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "4 MB", .value = 4096 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index 473b10983..84fb110c6 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -921,46 +921,35 @@ bochs_vbe_force_redraw(void *priv) static const device_config_t bochs_vbe_config[] = { // clang-format off { - .name = "revision", - .description = "Revision", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "VirtualBox", - .value = VBE_DISPI_ID4 - }, - { - .description = "Bochs latest", - .value = VBE_DISPI_ID5 - }, - { - .description = "" - } + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = VBE_DISPI_ID5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "VirtualBox", .value = VBE_DISPI_ID4 }, + { .description = "Bochs latest", .value = VBE_DISPI_ID5 }, + { .description = "" } }, - .default_int = VBE_DISPI_ID5 + .bios = { { 0 } } }, { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "16 MB", - .value = 16 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 16, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "16 MB", .value = 16 }, + { .description = "" } }, - .default_int = 16 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -974,7 +963,7 @@ const device_t bochs_svga_device = { .init = bochs_vbe_init, .close = bochs_vbe_close, .reset = bochs_vbe_reset, - .available = bochs_vbe_available, + .available = bochs_vbe_available, .speed_changed = bochs_vbe_speed_changed, .force_redraw = bochs_vbe_force_redraw, .config = bochs_vbe_config diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index d324368ab..f439cb1d8 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -809,110 +809,81 @@ cga_speed_changed(void *priv) // clang-format off const device_config_t cga_config[] = { { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_int = CGA_RGB, - .selection = { - { - .description = "RGB", - .value = CGA_RGB - }, - { - .description = "Composite", - .value = CGA_COMPOSITE - }, - { - .description = "" - } - } + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = CGA_RGB, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = CGA_RGB }, + { .description = "Composite", .value = CGA_COMPOSITE }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "composite_type", - .description = "Composite type", - .type = CONFIG_SELECTION, - .default_int = COMPOSITE_OLD, - .selection = { - { - .description = "Old", - .value = COMPOSITE_OLD - }, - { - .description = "New", - .value = COMPOSITE_NEW - }, - { - .description = "" - } - } + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = COMPOSITE_OLD, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Old", .value = COMPOSITE_OLD }, + { .description = "New", .value = COMPOSITE_NEW }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_int = 5, - .selection = { - { - .description = "Color (generic)", - .value = 0 - }, - { - .description = "Green Monochrome", - .value = 1 - }, - { - .description = "Amber Monochrome", - .value = 2 - }, - { - .description = "Gray Monochrome", - .value = 3 - }, - { - .description = "Color (no brown)", - .value = 4 - }, - { - .description = "Color (IBM 5153)", - .value = 5 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Color (generic)", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "Color (no brown)", .value = 4 }, + { .description = "Color (IBM 5153)", .value = 5 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "double_type", - .description = "Line doubling type", - .type = CONFIG_SELECTION, - .default_int = DOUBLE_NONE, - .selection = { - { - .description = "None", - .value = DOUBLE_NONE - }, - { - .description = "Simple doubling", - .value = DOUBLE_SIMPLE - }, - { - .description = "sRGB interpolation", - .value = DOUBLE_INTERPOLATE_SRGB - }, - { - .description = "Linear interpolation", - .value = DOUBLE_INTERPOLATE_LINEAR - }, - { - .description = "" - } - } + .name = "double_type", + .description = "Line doubling type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = DOUBLE_NONE, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = DOUBLE_NONE }, + { .description = "Simple doubling", .value = DOUBLE_SIMPLE }, + { .description = "sRGB interpolation", .value = DOUBLE_INTERPOLATE_SRGB }, + { .description = "Linear interpolation", .value = DOUBLE_INTERPOLATE_LINEAR }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 51e4ba335..19f51bd9d 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4701,200 +4701,156 @@ gd54xx_force_redraw(void *priv) // clang-format off static const device_config_t gd542x_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } }, - .default_int = 512 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5426_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2048, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "" } }, - .default_int = 2048 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5428_onboard_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "2 MB", - .value = 2048 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2048, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "2 MB", .value = 2048 }, + { .description = "" } }, - .default_int = 2048 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5429_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5440_onboard_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5434_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 4 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5434_onboard_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 4 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t gd5480_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 4 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index 98d6adea7..958375f4e 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -382,48 +382,45 @@ colorplus_speed_changed(void *priv) static const device_config_t colorplus_config[] = { // clang-format off { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_int = CGA_RGB, - .selection = { - { - .description = "RGB", - .value = CGA_RGB - }, - { - .description = "Composite", - .value = CGA_COMPOSITE - }, - { - .description = "" - } - } + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = CGA_RGB, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = CGA_RGB }, + { .description = "Composite", .value = CGA_COMPOSITE }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "composite_type", - .description = "Composite type", - .type = CONFIG_SELECTION, - .default_int = COMPOSITE_OLD, - .selection = { - { - .description = "Old", - .value = COMPOSITE_OLD - }, - { - .description = "New", - .value = COMPOSITE_NEW - }, - { - .description = "" - } - } + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = COMPOSITE_OLD, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Old", .value = COMPOSITE_OLD }, + { .description = "New", .value = COMPOSITE_NEW }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index faf4b9066..10df85c79 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1590,70 +1590,41 @@ ega_speed_changed(void *priv) static const device_config_t ega_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 256, - .selection = { - { - .description = "32 KB", - .value = 32 - }, - { - .description = "64 KB", - .value = 64 - }, - { - .description = "128 KB", - .value = 128 - }, - { - .description = "256 KB", - .value = 256 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "32 KB", .value = 32 }, + { .description = "64 KB", .value = 64 }, + { .description = "128 KB", .value = 128 }, + { .description = "256 KB", .value = 256 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "monitor_type", - .description = "Monitor type", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "Monochrome (5151/MDA) (white)", - .value = 0x0B | (DISPLAY_WHITE << 4) - }, - { - .description = "Monochrome (5151/MDA) (green)", - .value = 0x0B | (DISPLAY_GREEN << 4) - }, - { - .description = "Monochrome (5151/MDA) (amber)", - .value = 0x0B | (DISPLAY_AMBER << 4) - }, - { - .description = "Color 40x25 (5153/CGA)", - .value = 0x06 - }, - { - .description = "Color 80x25 (5153/CGA)", - .value = 0x07 - }, - { - .description = "Enhanced Color - Normal Mode (5154/ECD)", - .value = 0x08 - }, - { - .description = "Enhanced Color - Enhanced Mode (5154/ECD)", - .value = 0x09 - }, - { - .description = "" - } + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 9, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Monochrome (5151/MDA) (white)", .value = 0x0B | (DISPLAY_WHITE << 4) }, + { .description = "Monochrome (5151/MDA) (green)", .value = 0x0B | (DISPLAY_GREEN << 4) }, + { .description = "Monochrome (5151/MDA) (amber)", .value = 0x0B | (DISPLAY_AMBER << 4) }, + { .description = "Color 40x25 (5153/CGA)", .value = 0x06 }, + { .description = "Color 80x25 (5153/CGA)", .value = 0x07 }, + { .description = "Enhanced Color - Normal Mode (5154/ECD)", .value = 0x08 }, + { .description = "Enhanced Color - Enhanced Mode (5154/ECD)", .value = 0x09 }, + { .description = "" } }, - .default_int = 9 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index 8585fedff..193fed3c7 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -550,15 +550,19 @@ et3000_available(void) static const device_config_t et3000_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { .description = "256 KB", .value = 256 }, - { .description = "512 KB", .value = 512 }, - { .description = "" } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 120505dc5..064d79230 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -943,43 +943,51 @@ et4000_kasan_available(void) static const device_config_t et4000_tc6058af_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bios_ver", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios_ver", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "v1_10", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Version 1.10", .internal_name = "v1_10", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 32768, .files = { TC6058AF_BIOS_ROM_PATH, "" } }, - { .name = "Version 1.21", .internal_name = "v1_21", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 32768, .files = { V1_21_BIOS_ROM_PATH, "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Version 1.10", + .internal_name = "v1_10", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 32768, + .files = { TC6058AF_BIOS_ROM_PATH, "" } + }, + { + .name = "Version 1.21", + .internal_name = "v1_21", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 32768, + .files = { V1_21_BIOS_ROM_PATH, "" } + }, { .files_no = 0 } - }, + } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -988,43 +996,51 @@ static const device_config_t et4000_tc6058af_config[] = { static const device_config_t et4000_bios_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bios_ver", - .description = "BIOS Revision", - .type = CONFIG_BIOS, + .name = "bios_ver", + .description = "BIOS Revision", + .type = CONFIG_BIOS, .default_string = "v8_01", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .bios = { - { .name = "Version 8.01", .internal_name = "v8_01", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 32768, .files = { BIOS_ROM_PATH, "" } }, - { .name = "Version 8.06", .internal_name = "v8_06", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 32768, .files = { V8_06_BIOS_ROM_PATH, "" } }, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Version 8.01", + .internal_name = "v8_01", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 32768, + .files = { BIOS_ROM_PATH, "" } + }, + { + .name = "Version 8.06", + .internal_name = "v8_06", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 32768, + .files = { V8_06_BIOS_ROM_PATH, "" } + }, { .files_no = 0 } - }, + } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -1033,27 +1049,20 @@ static const device_config_t et4000_bios_config[] = { static const device_config_t et4000_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 351dfba5d..6ff34cbb1 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -2943,23 +2943,19 @@ et4000w32p_force_redraw(void *priv) static const device_config_t et4000w32p_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 8d99e9c7b..d50e8ba37 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -615,37 +615,32 @@ speed_changed(void *priv) static const device_config_t hercules_config[] = { // clang-format off { - .name = "rgb_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "Default", - .value = 0 - }, - { - .description = "Green", - .value = 1 - }, - { - .description = "Amber", - .value = 2 - }, - { - .description = "Gray", - .value = 3 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Default", .value = 0 }, + { .description = "Green", .value = 1 }, + { .description = "Amber", .value = 2 }, + { .description = "Gray", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "blend", - .description = "Blend", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "blend", + .description = "Blend", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index 1b6b74033..99c614259 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -700,37 +700,32 @@ speed_changed(void *priv) static const device_config_t herculesplus_config[] = { // clang-format off { - .name = "rgb_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "Default", - .value = 0 - }, - { - .description = "Green", - .value = 1 - }, - { - .description = "Amber", - .value = 2 - }, - { - .description = "Gray", - .value = 3 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Default", .value = 0 }, + { .description = "Green", .value = 1 }, + { .description = "Amber", .value = 2 }, + { .description = "Gray", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "blend", - .description = "Blend", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "blend", + .description = "Blend", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 3ed9e2bce..ce756f7d8 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1721,32 +1721,40 @@ ht216_force_redraw(void *priv) // clang-format off static const device_config_t v7_vga_1024i_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { .description = "256 KB", .value = 256 }, - { .description = "512 KB", .value = 512 }, - { .description = "" } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t ht216_32_standalone_config[] = { { - .name = "monitor_type", - .description = "Monitor type", - .type = CONFIG_SELECTION, - .default_int = 0x18, - .selection = { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0x18, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Mono Interlaced", .value = 0x00 }, { .description = "Mono Non-Interlaced", .value = 0x08 }, { .description = "Color Interlaced", .value = 0x10 }, { .description = "Color Non-Interlaced", .value = 0x18 }, - { .description = "" } - } + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index edadb4e46..975b9ead1 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -353,31 +353,21 @@ mda_speed_changed(void *priv) static const device_config_t mda_config[] = { // clang-format off { - .name = "rgb_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "Default", - .value = 0 - }, - { - .description = "Green", - .value = 1 - }, - { - .description = "Amber", - .value = 2 - }, - { - .description = "Gray", - .value = 3 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Default", .value = 0 }, + { .description = "Green", .value = 1 }, + { .description = "Amber", .value = 2 }, + { .description = "Gray", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index b3cbdd999..3937c2a7d 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -6845,25 +6845,20 @@ mystique_force_redraw(void *priv) static const device_config_t mystique_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { .description = "" } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "" } }, - .default_int = 8 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -6872,25 +6867,20 @@ static const device_config_t mystique_config[] = { static const device_config_t millennium_ii_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "16 MB", - .value = 16 - }, - { .description = "" } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 8, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "16 MB", .value = 16 }, + { .description = "" } }, - .default_int = 8 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_nga.c b/src/video/vid_nga.c index 3cb7426b8..3640e5106 100644 --- a/src/video/vid_nga.c +++ b/src/video/vid_nga.c @@ -600,87 +600,65 @@ nga_init(UNUSED(const device_t *info)) const device_config_t nga_config[] = { // clang-format off { - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "Color", - .value = 0 - }, - { - .description = "Green Monochrome", - .value = 1 - }, - { - .description = "Amber Monochrome", - .value = 2 - }, - { - .description = "Gray Monochrome", - .value = 3 - }, - { - .description = "Color (no brown)", - .value = 4 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "Color (no brown)", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 64, - .selection = { - { - .description = "32 KB", - .value = 32 - }, - { - .description = "64 KB", - .value = 64 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 64, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "32 KB", .value = 32 }, + { .description = "64 KB", .value = 64 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "charset", - .description = "Character set", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "U.S. English", - .value = 0 - }, - { - .description = "Scandinavian", - .value = 1 - }, - { - .description = "Other languages", - .value = 2 - }, - { - .description = "E.F. Hutton", - .value = 3 - }, - { - .description = "" - } - } + .name = "charset", + .description = "Character set", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "U.S. English", .value = 0 }, + { .description = "Scandinavian", .value = 1 }, + { .description = "Other languages", .value = 2 }, + { .description = "E.F. Hutton", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index c7d42275d..ce44ef890 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -571,100 +571,78 @@ oti067_m300_available(void) // clang-format off static const device_config_t oti067_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti067_ama932j_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 256, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 256, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti077_acer100t_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t oti077_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_ogc.c b/src/video/vid_ogc.c index d430d2e14..7fe5fbbeb 100644 --- a/src/video/vid_ogc.c +++ b/src/video/vid_ogc.c @@ -634,37 +634,32 @@ const device_config_t ogc_m24_config[] = { // clang-format off { /* Olivetti / ATT compatible displays */ - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_int = CGA_RGB, - .selection = { - { - .description = "Color", - .value = 0 - }, - { - .description = "Green Monochrome", - .value = 1 - }, - { - .description = "Amber Monochrome", - .value = 2 - }, - { - .description = "Gray Monochrome", - .value = 3 - }, - { - .description = "" - } - } + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = CGA_RGB, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "snow_enabled", - .description = "Snow emulation", - .type = CONFIG_BINARY, - .default_int = 1, + .name = "snow_enabled", + .description = "Snow emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 89d65a1f8..d0acaf276 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -735,23 +735,19 @@ const device_t paradise_pvga1a_pc3086_device = { static const device_config_t paradise_pvga1a_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -816,27 +812,20 @@ const device_t paradise_wd90c11_device = { static const device_config_t paradise_wd90c30_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c index b6e0085f8..ae9475d96 100644 --- a/src/video/vid_rtg310x.c +++ b/src/video/vid_rtg310x.c @@ -387,23 +387,19 @@ rtg3106_available(void) static const device_config_t rtg3105_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 512, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 512, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -412,27 +408,20 @@ static const device_config_t rtg3105_config[] = { static const device_config_t rtg3106_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 52135b066..aecc898c4 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10543,100 +10543,126 @@ s3_force_redraw(void *priv) s3->svga.fullchange = s3->svga.monitor->mon_changeframecount; } +// clang-format off static const device_config_t s3_orchid_86c911_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "512 KB", .value = 0 }, { .description = "1 MB", .value = 1 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_9fx_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "1 MB", .value = 1 }, { .description = "2 MB", .value = 2 }, /* Trio64 also supports 4 MB, however the Number Nine BIOS does not */ { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_phoenix_trio32_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "512 KB", .value = 0 }, { .description = "1 MB", .value = 1 }, { .description = "2 MB", .value = 2 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_standard_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "1 MB", .value = 1 }, { .description = "2 MB", .value = 2 }, { .description = "4 MB", .value = 4 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_968_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "1 MB", .value = 1 }, { .description = "2 MB", .value = 2 }, { .description = "4 MB", .value = 4 }, { .description = "8 MB", .value = 8 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t s3_standard_config2[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "2 MB", .value = 2 }, { .description = "4 MB", .value = 4 }, { .description = "" } - } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; +// clang-format on const device_t s3_orchid_86c911_isa_device = { .name = "S3 86c911 ISA (Orchid Fahrenheit 1280)", diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 86876cd0a..91b186240 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -4692,35 +4692,38 @@ s3_virge_force_redraw(void *priv) static const device_config_t s3_virge_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dithering", - .description = "Dithering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -4729,39 +4732,39 @@ static const device_config_t s3_virge_config[] = { static const device_config_t s3_virge_stb_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dithering", - .description = "Dithering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -4770,16 +4773,24 @@ static const device_config_t s3_virge_stb_config[] = { static const device_config_t s3_virge_357_config[] = { // clang-format off { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dithering", - .description = "Dithering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -4788,35 +4799,41 @@ static const device_config_t s3_virge_357_config[] = { static const device_config_t s3_trio3d2x_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 4, - .selection = { - { - .description = "4 MB", - .value = 4 - }, - { - .description = "8 MB", - .value = 8 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "4 MB", .value = 4 }, + { .description = "8 MB", .value = 8 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dithering", - .description = "Dithering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 161331918..d771260ed 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -860,96 +860,57 @@ sigma_speed_changed(void *priv) device_config_t sigma_config[] = { // clang-format off { - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_int = 0, - .selection = { - { - .description = "Color", - .value = 0 - }, - { - .description = "Green Monochrome", - .value = 1 - }, - { - .description = "Amber Monochrome", - .value = 2 - }, - { - .description = "Gray Monochrome", - .value = 3 - }, - { - .description = "Color (no brown)", - .value = 4 - }, - { - .description = "" - } - } - }, - { - .name = "enable_nmi", - .description = "Enable NMI for CGA emulation", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "bios_addr", - .description = "BIOS Address", - .type = CONFIG_HEX20, - .default_int = 0xc0000, - .selection = { - { - .description = "C000H", - .value = 0xc0000 - }, - { - .description = "C800H", - .value = 0xc8000 - }, - { - .description = "CC00H", - .value = 0xcc000 - }, - { - .description = "D000H", - .value = 0xd0000 - }, - { - .description = "D400H", - .value = 0xd4000 - }, - { - .description = "D800H", - .value = 0xd8000 - }, - { - .description = "DC00H", - .value = 0xdc000 - }, - { - .description = "E000H", - .value = 0xe0000 - }, - { - .description = "E400H", - .value = 0xe4000 - }, - { - .description = "E800H", - .value = 0xe8000 - }, - { - .description = "EC00H", - .value = 0xec000 - }, - { - .description = "" - } + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "Color (no brown)", .value = 4 }, + { .description = "" } }, + .bios = { { 0 } } + }, + { + .name = "enable_nmi", + .description = "Enable NMI for CGA emulation", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xc0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "C000H", .value = 0xc0000 }, + { .description = "C800H", .value = 0xc8000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "E000H", .value = 0xe0000 }, + { .description = "E400H", .value = 0xe4000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EC00H", .value = 0xec000 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 88c26437a..d1391f1d1 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -3369,50 +3369,39 @@ tgui_force_redraw(void *priv) // clang-format off static const device_config_t tgui9440_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; static const device_config_t tgui96xx_config[] = { { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 4 + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 9f329a604..9dd7e424d 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -521,28 +521,21 @@ tvga_force_redraw(void *priv) static const device_config_t tvga_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 1024, - .selection = { - { - .description = "256 KB", - .value = 256 - }, - { - .description = "512 KB", - .value = 512 - }, - { - .description = "1 MB", - .value = 1024 - }, + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, /*Chip supports 2mb, but drivers are buggy*/ - { - .description = "" - } - } + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index bf3b63736..e45f112ed 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -1308,119 +1308,121 @@ voodoo_close(void *priv) static const device_config_t voodoo_config[] = { // clang-format off { - .name = "type", - .description = "Voodoo type", - .type = CONFIG_SELECTION, + .name = "type", + .description = "Voodoo type", + .type = CONFIG_SELECTION, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, .selection = { - { - .description = "3Dfx Voodoo Graphics", - .value = VOODOO_1 - }, - { - .description = "Obsidian SB50 + Amethyst (2 TMUs)", - .value = VOODOO_SB50 - }, - { - .description = "3Dfx Voodoo 2", - .value = VOODOO_2 - }, - { - .description = "" - } + { .description = "3Dfx Voodoo Graphics", .value = VOODOO_1 }, + { .description = "Obsidian SB50 + Amethyst (2 TMUs)", .value = VOODOO_SB50 }, + { .description = "3Dfx Voodoo 2", .value = VOODOO_2 }, + { .description = "" } }, - .default_int = 0 + .bios = { { 0 } } }, { - .name = "framebuffer_memory", - .description = "Framebuffer memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { - .name = "texture_memory", - .description = "Texture memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "2 MB", - .value = 2 - }, - { - .description = "4 MB", - .value = 4 - }, - { - .description = "" - } + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dithersub", - .description = "Dither subtraction", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "dacfilter", - .description = "Screen Filter", - .type = CONFIG_BINARY, - .default_int = 0 + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, { - .name = "render_threads", - .description = "Render threads", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "4", - .value = 4 - }, - { - .description = "" - } + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "4", .value = 4 }, + { .description = "" } }, - .default_int = 2 + .bios = { { 0 } } }, { - .name = "sli", - .description = "SLI", - .type = CONFIG_BINARY, - .default_int = 0 + .name = "sli", + .description = "SLI", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, #ifndef NO_CODEGEN { - .name = "recompiler", - .description = "Dynamic Recompiler", - .type = CONFIG_BINARY, - .default_int = 1 + .name = "recompiler", + .description = "Dynamic Recompiler", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } }, #endif { .name = "", .description = "", .type = CONFIG_END } diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index d2c694a4c..fadd782a5 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -3178,186 +3178,6 @@ banshee_pci_write(int func, int addr, uint8_t val, void *priv) } } -// clang-format off -static const device_config_t banshee_sgram_config[] = { - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "8 MB", - .value = 8 - }, - { - .description = "16 MB", - .value = 16 - }, - { - .description = "" - } - }, - .default_int = 16 - }, - { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dithersub", - .description = "Dither subtraction", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dacfilter", - .description = "Screen Filter", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "render_threads", - .description = "Render threads", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "4", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 - }, -#ifndef NO_CODEGEN - { - .name = "recompiler", - .description = "Dynamic Recompiler", - .type = CONFIG_BINARY, - .default_int = 1 - }, -#endif - { .name = "", .description = "", .type = CONFIG_END } -}; - -static const device_config_t banshee_sgram_16mbonly_config[] = { - { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dithersub", - .description = "Dither subtraction", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dacfilter", - .description = "Screen Filter", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "render_threads", - .description = "Render threads", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "4", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 - }, -#ifndef NO_CODEGEN - { - .name = "recompiler", - .description = "Dynamic Recompiler", - .type = CONFIG_BINARY, - .default_int = 1 - }, -#endif - { .name = "", .description = "", .type = CONFIG_END } -}; - -static const device_config_t banshee_sdram_config[] = { - { - .name = "bilinear", - .description = "Bilinear filtering", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dithersub", - .description = "Dither subtraction", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "dacfilter", - .description = "Screen Filter", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "render_threads", - .description = "Render threads", - .type = CONFIG_SELECTION, - .selection = { - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "4", - .value = 4 - }, - { - .description = "" - } - }, - .default_int = 2 - }, -#ifndef NO_CODEGEN - { - .name = "recompiler", - .description = "Dynamic Recompiler", - .type = CONFIG_BINARY, - .default_int = 1 - }, -#endif - { .name = "", .description = "", .type = CONFIG_END } -}; -// clang-format on - static void * banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int voodoo_type, int agp) { @@ -3749,6 +3569,221 @@ banshee_force_redraw(void *priv) banshee->svga.fullchange = changeframecount; } +// clang-format off +static const device_config_t banshee_sgram_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 16, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "8 MB", .value = 8 }, + { .description = "16 MB", .value = 16 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "4", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Dynamic Recompiler", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, +#endif + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t banshee_sgram_16mbonly_config[] = { + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "4", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Dynamic Recompiler", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, +#endif + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t banshee_sdram_config[] = { + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "4", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Dynamic Recompiler", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, +#endif + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on + const device_t voodoo_banshee_device = { .name = "3Dfx Voodoo Banshee", .internal_name = "voodoo_banshee_pci", diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index f5d46f937..a469330af 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -41,7 +41,7 @@ #define XGA2_BIOS_PATH "roms/video/xga/xga2_v300.bin" #define INMOS_XGA_BIOS_PATH "roms/video/xga/InMOS XGA - Fairchild NM27C256Q-150.BIN" -static video_timings_t timing_xga_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; +static video_timings_t timing_xga_isa = { .type = VIDEO_ISA, .write_b = 3, .write_w = 3, .write_l = 6, .read_b = 5, .read_w = 5, .read_l = 10 }; static video_timings_t timing_xga_mca = { .type = VIDEO_MCA, .write_b = 4, .write_w = 5, .write_l = 10, .read_b = 5, .read_w = 5, .read_l = 10 }; static void xga_ext_outb(uint16_t addr, uint8_t val, void *priv); @@ -3660,24 +3660,19 @@ xga_force_redraw(void *priv) static const device_config_t xga_mca_configuration[] = { // clang-format off { - .name = "type", - .description = "XGA type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "XGA-1", - .value = 0 - }, - { - .description = "XGA-2", - .value = 1 - }, - { .description = "" } - } + .name = "type", + .description = "XGA type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "XGA-1", .value = 0 }, + { .description = "XGA-2", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -3686,34 +3681,29 @@ static const device_config_t xga_mca_configuration[] = { static const device_config_t xga_isa_configuration[] = { // clang-format off { - .name = "type", - .description = "XGA type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "XGA-1", - .value = 0 - }, - { - .description = "XGA-2", - .value = 1 - }, - { .description = "" } - } + .name = "type", + .description = "XGA type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "XGA-1", .value = 0 }, + { .description = "XGA-2", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } }, { - .name = "instance", - .description = "Instance", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 6, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "instance", + .description = "Instance", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 6, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "0 (2100h-210Fh)", .value = 0 }, { .description = "1 (2110h-211Fh)", .value = 1 }, { .description = "2 (2120h-212Fh)", .value = 2 }, @@ -3722,18 +3712,19 @@ static const device_config_t xga_isa_configuration[] = { { .description = "5 (2150h-215Fh)", .value = 5 }, { .description = "6 (2160h-216Fh)", .value = 6 }, { .description = "7 (2170h-217Fh)", .value = 7 }, - { .description = "" } + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "ext_mem_addr", - .description = "MMIO Address", - .type = CONFIG_HEX16, - .default_string = "", - .default_int = 0x00f0, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "ext_mem_addr", + .description = "MMIO Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x00f0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "C800h", .value = 0x0040 }, { .description = "CA00h", .value = 0x0050 }, { .description = "CC00h", .value = 0x0060 }, @@ -3746,23 +3737,25 @@ static const device_config_t xga_isa_configuration[] = { { .description = "DA00h", .value = 0x00d0 }, { .description = "DC00h", .value = 0x00e0 }, { .description = "DE00h", .value = 0x00f0 }, - { .description = "" } + { .description = "" } }, + .bios = { { 0 } } }, { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { .description = "Disabled", .value = 0 }, - { .description = "DMA 6", .value = 6 }, - { .description = "DMA 7", .value = 7 }, - { .description = "" } + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -3771,39 +3764,35 @@ static const device_config_t xga_isa_configuration[] = { static const device_config_t xga_inmos_isa_configuration[] = { // clang-format off { - .name = "type", - .description = "XGA type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { - .description = "XGA-1", - .value = 0 - }, - { - .description = "XGA-2", - .value = 1 - }, - { .description = "" } - } - }, - { - .name = "dma", - .description = "DMA", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 7, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "Disabled", .value = 0 }, - { .description = "DMA 6", .value = 6 }, - { .description = "DMA 7", .value = 7 }, + .name = "type", + .description = "XGA type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "XGA-1", .value = 0 }, + { .description = "XGA-2", .value = 1 }, { .description = "" } }, + .bios = { { 0 } } + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "DMA 6", .value = 6 }, + { .description = "DMA 7", .value = 7 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on From 03c74f8bb6cce2b92aa85be7cbadc43e5a61168c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Feb 2025 16:10:26 +0100 Subject: [PATCH 0209/1190] Fix the AC flag on 8-bit and 16-bit ADC and SBB instructions. --- src/cpu/x86_flags.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cpu/x86_flags.h b/src/cpu/x86_flags.h index e82041783..7d5c41ca8 100644 --- a/src/cpu/x86_flags.h +++ b/src/cpu/x86_flags.h @@ -741,7 +741,7 @@ setadc8(uint8_t a, uint8_t b) cpu_state.flags |= C_FLAG; if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) cpu_state.flags |= V_FLAG; - if (((a & 0xF) + (b & 0xF)) & 0x10) + if (((a & 0xF) + (b & 0xF) + tempc) & 0x10) cpu_state.flags |= A_FLAG; } static __inline void @@ -755,7 +755,7 @@ setadc16(uint16_t a, uint16_t b) cpu_state.flags |= C_FLAG; if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) cpu_state.flags |= V_FLAG; - if (((a & 0xF) + (b & 0xF)) & 0x10) + if (((a & 0xF) + (b & 0xF) + tempc) & 0x10) cpu_state.flags |= A_FLAG; } static __inline void @@ -785,7 +785,7 @@ setsbc8(uint8_t a, uint8_t b) cpu_state.flags |= C_FLAG; if ((a ^ b) & (a ^ c) & 0x80) cpu_state.flags |= V_FLAG; - if (((a & 0xF) - (b & 0xF)) & 0x10) + if (((a & 0xF) - ((b & 0xF) + tempc)) & 0x10) cpu_state.flags |= A_FLAG; } static __inline void @@ -800,7 +800,7 @@ setsbc16(uint16_t a, uint16_t b) cpu_state.flags |= C_FLAG; if ((a ^ b) & (a ^ c) & 0x8000) cpu_state.flags |= V_FLAG; - if (((a & 0xF) - (b & 0xF)) & 0x10) + if (((a & 0xF) - ((b & 0xF) + tempc)) & 0x10) cpu_state.flags |= A_FLAG; } From b86e459e78a388c9698ab05019dcaeda1695d220 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 19:23:57 -0500 Subject: [PATCH 0210/1190] A couple of cleanups in hdc_ide.c --- src/disk/hdc_ide.c | 11 +++++------ src/include/86box/hdc.h | 1 - src/include/86box/hdc_ide.h | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 1583d6b9c..c5f776b3e 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2920,9 +2920,8 @@ ide_ter_init(const device_t *info) if (irq == -1) isapnp_add_card(ide_ter_pnp_rom, sizeof(ide_ter_pnp_rom), ide_pnp_config_changed, NULL, NULL, NULL, (void *) 2); - } else { + } else ide_board_init(2, irq, HDC_TERTIARY_BASE, HDC_TERTIARY_SIDE, 0, 0); - } return (ide_boards[2]); } @@ -3004,10 +3003,10 @@ ide_init(const device_t *info) switch (info->local) { case 0 ... 5: - ide_board_init(0, 14, 0x1f0, 0x3f6, info->local, info->flags); + ide_board_init(0, HDC_PRIMARY_IRQ, HDC_PRIMARY_BASE, HDC_PRIMARY_SIDE, info->local, info->flags); if (info->local & 1) - ide_board_init(1, 15, 0x170, 0x376, info->local, info->flags); + ide_board_init(1, HDC_SECONDARY_IRQ, HDC_SECONDARY_BASE, HDC_SECONDARY_SIDE, info->local, info->flags); break; default: @@ -3122,8 +3121,8 @@ static void mcide_mca_write(const int port, const uint8_t val, void *priv) { mcide_t *dev = (mcide_t *) priv; - uint16_t bases[4] = { 0x01f0, 0x0170, 0x01e8, 0x0168 }; - int irqs[4] = { 10, 11, 14, 15 }; + uint16_t bases[4] = { HDC_PRIMARY_BASE, HDC_SECONDARY_BASE, HDC_TERTIARY_BASE, HDC_QUATERNARY_BASE }; + int irqs[4] = { HDC_QUATERNARY_IRQ, HDC_TERTIARY_IRQ, HDC_PRIMARY_IRQ, HDC_SECONDARY_IRQ }; if ((port >= 0x102) && (dev->pos_regs[port & 7] != val)) { ide_log("IDE: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n", diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 110804244..5e09c2242 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -51,7 +51,6 @@ extern const device_t esdi_ps2_device; /* esdi_mca */ extern const device_t ide_isa_device; /* isa_ide */ extern const device_t ide_isa_2ch_device; /* isa_ide_2ch */ -extern const device_t ide_isa_2ch_opt_device; /* isa_ide_2ch_opt */ extern const device_t ide_vlb_device; /* vlb_ide */ extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */ extern const device_t ide_pci_device; /* pci_ide */ diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 0280cf301..6af4d92e6 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -25,17 +25,17 @@ #define IDE_BUS_MAX 4 #define IDE_CHAN_MAX 2 -#define HDC_PRIMARY_BASE 0x01F0 -#define HDC_PRIMARY_SIDE 0x03F6 +#define HDC_PRIMARY_BASE 0x01f0 +#define HDC_PRIMARY_SIDE 0x03f6 #define HDC_PRIMARY_IRQ 14 #define HDC_SECONDARY_BASE 0x0170 #define HDC_SECONDARY_SIDE 0x0376 #define HDC_SECONDARY_IRQ 15 -#define HDC_TERTIARY_BASE 0x01E8 -#define HDC_TERTIARY_SIDE 0x03EE +#define HDC_TERTIARY_BASE 0x01e8 +#define HDC_TERTIARY_SIDE 0x03ee #define HDC_TERTIARY_IRQ 11 #define HDC_QUATERNARY_BASE 0x0168 -#define HDC_QUATERNARY_SIDE 0x036E +#define HDC_QUATERNARY_SIDE 0x036e #define HDC_QUATERNARY_IRQ 10 enum { From 0c997cc4eb922a09a3f3dbacf7b472d26b681085 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 19:28:37 -0500 Subject: [PATCH 0211/1190] Add ISA, VLB & PCI second channel IDE devs --- src/disk/hdc_ide.c | 61 +++++++++++++++++++++++++++++++++++++++++ src/include/86box/hdc.h | 3 ++ 2 files changed, 64 insertions(+) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index c5f776b3e..3e1ce39f8 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2902,6 +2902,25 @@ ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) } } +static void * +ide_sec_init(const device_t *info) +{ + /* Don't claim this channel again if it was already claimed. */ + if (ide_boards[1]) + return (NULL); + + ide_board_init(1, HDC_SECONDARY_IRQ, HDC_SECONDARY_BASE, HDC_SECONDARY_SIDE, info->local, info->flags); + + return (ide_boards[1]); +} + +/* Close a standalone IDE unit. */ +static void +ide_sec_close(UNUSED(void *priv)) +{ + ide_board_close(1); +} + static void * ide_ter_init(const device_t *info) { @@ -3274,6 +3293,20 @@ const device_t ide_isa_device = { .config = NULL }; +const device_t ide_isa_sec_device = { + .name = "ISA PC/AT IDE Controller (Secondary)", + .internal_name = "ide_isa_sec", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t ide_isa_2ch_device = { .name = "ISA PC/AT IDE Controller (Dual-Channel)", .internal_name = "ide_isa_2ch", @@ -3302,6 +3335,20 @@ const device_t ide_vlb_device = { .config = NULL }; +const device_t ide_vlb_sec_device = { + .name = "VLB IDE Controller (Secondary)", + .internal_name = "ide_vlb_sec", + .flags = DEVICE_VLB | DEVICE_AT, + .local = 2, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t ide_vlb_2ch_device = { .name = "VLB IDE Controller (Dual-Channel)", .internal_name = "ide_vlb_2ch", @@ -3330,6 +3377,20 @@ const device_t ide_pci_device = { .config = NULL }; +const device_t ide_pci_sec_device = { + .name = "PCI IDE Controller (Secondary)", + .internal_name = "ide_pci_sec", + .flags = DEVICE_PCI | DEVICE_AT, + .local = 4, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t ide_pci_2ch_device = { .name = "PCI IDE Controller (Dual-Channel)", .internal_name = "ide_pci_2ch", diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 5e09c2242..7731d60d4 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -50,10 +50,13 @@ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ extern const device_t ide_isa_device; /* isa_ide */ +extern const device_t ide_isa_sec_device; /* isa_ide sec*/ extern const device_t ide_isa_2ch_device; /* isa_ide_2ch */ extern const device_t ide_vlb_device; /* vlb_ide */ +extern const device_t ide_vlb_sec_device; /* vlb_ide sec */ extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */ extern const device_t ide_pci_device; /* pci_ide */ +extern const device_t ide_pci_sec_device; /* pci_ide sec */ extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */ extern const device_t ide_ali1489_device; /* ALi M1489 */ From 61d583425501f9e3b0d9ce2700a2c2c2058f0526 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Feb 2025 23:23:47 -0300 Subject: [PATCH 0212/1190] CS423x: Add some more missing CS4235 features and locks --- src/sound/snd_ad1848.c | 58 ++++++++++++++++++++++++------------------ src/sound/snd_cs423x.c | 4 +++ 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index d870b4588..f78bc841b 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -303,30 +303,35 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) case 18: case 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { - if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ - ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */ - temp = 1; + if (ad1848->type >= AD1848_TYPE_CS4235) { + if (ad1848->xregs[18] & 0x20) /* AUX1 remapping */ + ad1848->regs[ad1848->index & 3] = val; /* also controls AUX1 on registers 2 and 3 */ + } else { + if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ + ad1848->xregs[6 | (ad1848->index & 1)] = val; /* real FM volume on extended registers 6 and 7 */ + temp = 1; - if (ad1848->index == 18) { - if (val & 0x80) - ad1848->fm_vol_l = 0; - else - ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; - } else { - if (val & 0x80) - ad1848->fm_vol_r = 0; - else - ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + if (ad1848->index == 18) { + if (val & 0x80) + ad1848->fm_vol_l = 0; + else + ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f]; + } else { + if (val & 0x80) + ad1848->fm_vol_r = 0; + else + ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f]; + } + } + if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */ + ad1848->xregs[16 | (ad1848->index & 1)] = val; /* real wavetable volume on extended registers 16 and 17 */ + temp = 1; } - } - if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */ - ad1848->xregs[ad1848->index - 2] = val; /* real wavetable volume on extended registers 16 and 17 */ - temp = 1; - } - /* Stop here if any remapping is enabled. */ - if (temp) - return; + /* Stop here if any remapping is enabled. */ + if (temp) + return; + } /* HACK: the Windows 9x driver's "Synth" control writes to this register with no remapping, even if internal FM is enabled. */ @@ -366,9 +371,11 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) switch (ad1848->xindex) { case 0 ... 1: - /* Remapped line volume. */ - ad1848->regs[18 + ad1848->xindex] = val; - return; + if (ad1848->type < AD1848_TYPE_CS4235) { + /* Remapped line volume. */ + ad1848->regs[18 | ad1848->xindex] = val; + } + break; case 6: if (val & 0x80) @@ -747,7 +754,8 @@ ad1848_init(ad1848_t *ad1848, uint8_t type) ad1848->regs[30] = ad1848->regs[31] = 0; if (type >= AD1848_TYPE_CS4236B) { - ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; + if (type < AD1848_TYPE_CS4235) + ad1848->xregs[0] = ad1848->xregs[1] = 0xe8; ad1848->xregs[2] = ad1848->xregs[3] = 0xcf; ad1848->xregs[4] = 0x84; ad1848->xregs[5] = 0; diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index f6ded130a..4f9050924 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -692,6 +692,10 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) dev->regs[4] &= ~0x40; } + /* Update X18 bits. */ + if (dev->type >= CRYSTAL_CS4235) + dev->ad1848.xregs[18] = (dev->ad1848.xregs[18] & ~0x3e) | (dev->ram_data[0x400b] & 0x3e); + /* Inform WSS codec of the changes. */ ad1848_updatevolmask(&dev->ad1848); } From 8d2150777cf885197ec0d4de15592b0aa04e5b60 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Feb 2025 23:28:50 -0300 Subject: [PATCH 0213/1190] CS423x: Add one more missing CS4235 hardware config byte --- src/sound/snd_cs423x.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 4f9050924..cf38ccb4b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -654,9 +654,10 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) Disable the PnP key disabling mechanism until someone figures something out. */ #if 0 isapnp_enable_card(dev->pnp_card, ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) ? ISAPNP_CARD_NO_KEY : ISAPNP_CARD_ENABLE); -#endif +#else if ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) pclog("CS423x: Attempted to disable PnP key\n"); +#endif } /* Update some register bits based on the config data in RAM if requested. */ @@ -684,17 +685,19 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) else dev->ad1848.xregs[4] &= ~0x10; - /* Update VCEN. */ if (dev->type == CRYSTAL_CS4236) { + /* Update VCEN. */ if (dev->ram_data[0x4002] & 0x04) dev->regs[4] |= 0x40; else dev->regs[4] &= ~0x40; } - /* Update X18 bits. */ - if (dev->type >= CRYSTAL_CS4235) + if (dev->type >= CRYSTAL_CS4235) { + /* Update X18 and X19 values. */ dev->ad1848.xregs[18] = (dev->ad1848.xregs[18] & ~0x3e) | (dev->ram_data[0x400b] & 0x3e); + dev->ad1848.xregs[19] = dev->ram_data[0x4005]; + } /* Inform WSS codec of the changes. */ ad1848_updatevolmask(&dev->ad1848); @@ -898,7 +901,7 @@ cs423x_init(const device_t *info) /* Different WSS codec families. */ dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : ((dev->type >= CRYSTAL_CS4236B) ? AD1848_TYPE_CS4236B : AD1848_TYPE_CS4236); - /* Different Chip Version and ID registers (N/A on CS4236), which shouldn't be reset by ad1848_init. */ + /* Different Chip Version and ID values (N/A on CS4236), which shouldn't be reset by ad1848_init. */ dev->ad1848.xregs[25] = dev->type; /* Same EEPROM structure. */ From 83b3b322ac8a549bc40b3501e498ba46164d56b8 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Feb 2025 23:46:26 -0300 Subject: [PATCH 0214/1190] CS423x: Playback powerdown check fixes --- src/sound/snd_cs423x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index cf38ccb4b..f5458eaf0 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -606,8 +606,8 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv) /* Output audio from the WSS codec, and also the OPL if we're in charge of it. */ ad1848_update(&dev->ad1848); - /* Don't output anything if the analog section is powered down. */ - if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x04)) { + /* Don't output anything if the analog section or DAC is powered down. */ + if (!(dev->regs[2] & 0xb4) && !(dev->indirect_regs[9] & 0x04)) { for (int c = 0; c < len * 2; c += 2) { buffer[c] += dev->ad1848.buffer[c] / 2; buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2; @@ -626,8 +626,9 @@ cs423x_get_music_buffer(int32_t *buffer, int len, void *priv) if (dev->opl_wss) { const int32_t *opl_buf = dev->sb->opl.update(dev->sb->opl.priv); - /* Don't output anything if the analog section or DAC2 (CS4235+) is powered down. */ - if (!(dev->indirect_regs[2] & 0xa4) && !(dev->indirect_regs[9] & 0x06)) { + /* Don't output anything if the analog section, DAC (DAC2 instead on CS4235+) or FM synth is powered down. */ + uint8_t bpd_mask = (dev->type >= CRYSTAL_CS4235) ? 0xb1 : 0xb5; + if (!(dev->regs[2] & bpd_mask) && !(dev->indirect_regs[9] & 0x06)) { for (int c = 0; c < len * 2; c += 2) { buffer[c] += (opl_buf[c] * dev->ad1848.fm_vol_l) >> 16; buffer[c + 1] += (opl_buf[c + 1] * dev->ad1848.fm_vol_r) >> 16; From bb51c324e2ebc955f7711063d83926f053a2760f Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Feb 2025 00:03:25 -0300 Subject: [PATCH 0215/1190] CS423x: Add remaining CS4235 extended->control register access paths --- src/sound/snd_ad1848.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index f78bc841b..87755a96c 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -167,6 +167,7 @@ ad1848_read(uint16_t addr, void *priv) { ad1848_t *ad1848 = (ad1848_t *) priv; uint8_t ret = 0xff; + uint8_t temp = 0; switch (addr & 3) { case 0: /* Index */ @@ -207,10 +208,22 @@ ad1848_read(uint16_t addr, void *priv) ret = ad1848->regs[18 + ad1848->xindex]; break; - case 26: - /* Backdoor to the Joystick Control register on CS4235+. */ + case 23 ... 24: + case 29: + /* Backdoor to control indirect registers on CS4235+. */ + if (ad1848->type >= AD1848_TYPE_CS4235) { + temp = ad1848->cram_read(3, ad1848->cram_priv); + ad1848->cram_write(3, (ad1848->xindex == 23) ? 2 : ((ad1848->xindex == 24) ? 8 : 9), ad1848->cram_priv); + ret = ad1848->cram_read(4, ad1848->cram_priv); + ad1848->cram_write(3, temp, ad1848->cram_priv); + } + break; + + case 26 ... 28: + case 30: + /* Backdoor to control registers on CS4235+. */ if (ad1848->type >= AD1848_TYPE_CS4235) - ret = ad1848->cram_read(0, ad1848->cram_priv); + ret = ad1848->cram_read((ad1848->xindex == 30) ? 7 : (ad1848->xindex - 26), ad1848->cram_priv); break; default: @@ -396,13 +409,25 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) updatefreq = 1; break; + case 23 ... 24: + case 29: + /* Backdoor to control indirect registers on CS4235+. */ + if (ad1848->type >= AD1848_TYPE_CS4235) { + temp = ad1848->cram_read(3, ad1848->cram_priv); + ad1848->cram_write(3, (ad1848->xindex == 23) ? 2 : ((ad1848->xindex == 24) ? 8 : 9), ad1848->cram_priv); + ad1848->cram_write(4, val, ad1848->cram_priv); + ad1848->cram_write(3, temp, ad1848->cram_priv); + } + break; + case 25: return; - case 26: - /* Backdoor to the Joystick Control register on CS4235+. */ + case 26 ... 28: + case 30: + /* Backdoor to control registers on CS4235+. */ if (ad1848->type >= AD1848_TYPE_CS4235) - ad1848->cram_write(0, val, ad1848->cram_priv); + ad1848->cram_write((ad1848->xindex == 30) ? 7 : (ad1848->xindex - 26), val, ad1848->cram_priv); break; default: From 1936c05c8829f9e6e052861e89309a1339b4c65d Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Feb 2025 00:58:57 -0500 Subject: [PATCH 0216/1190] Fix warnings in ide_sec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- src/disk/hdc_ide.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3e1ce39f8..3683c8671 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3298,8 +3298,8 @@ const device_t ide_isa_sec_device = { .internal_name = "ide_isa_sec", .flags = DEVICE_ISA | DEVICE_AT, .local = 0, - .init = ide_init, - .close = ide_close, + .init = ide_sec_init, + .close = ide_sec_close, .reset = ide_reset, .available = NULL, .speed_changed = NULL, @@ -3340,8 +3340,8 @@ const device_t ide_vlb_sec_device = { .internal_name = "ide_vlb_sec", .flags = DEVICE_VLB | DEVICE_AT, .local = 2, - .init = ide_init, - .close = ide_close, + .init = ide_sec_init, + .close = ide_sec_close, .reset = ide_reset, .available = NULL, .speed_changed = NULL, @@ -3382,8 +3382,8 @@ const device_t ide_pci_sec_device = { .internal_name = "ide_pci_sec", .flags = DEVICE_PCI | DEVICE_AT, .local = 4, - .init = ide_init, - .close = ide_close, + .init = ide_sec_init, + .close = ide_sec_close, .reset = ide_reset, .available = NULL, .speed_changed = NULL, From d00f80d3ce85546c170187cc1ef9ae1402a6bdf6 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 9 Sep 2024 00:43:14 -0400 Subject: [PATCH 0217/1190] General changes from the obattler_202406 branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- CMakeLists.txt | 2 +- CMakePresets.json | 8 + cmake/flags-gcc.cmake | 4 +- src/acpi.c | 3 +- src/chipset/stpc.c | 33 +-- src/chipset/umc_8886.c | 2 + src/chipset/wd76c10.c | 12 +- src/device.c | 7 + src/device/CMakeLists.txt | 44 +-- src/disk/hdc_ide_w83769f.c | 2 +- src/include/86box/hdc.h | 2 +- src/include/86box/keyboard.h | 22 +- src/include/86box/lpt.h | 14 +- src/include/86box/sio.h | 62 +++- src/io.c | 4 +- src/lpt.c | 4 +- src/machine/m_at_286_386sx.c | 8 +- src/machine/m_at_386dx_486.c | 5 +- src/machine/m_at_commodore.c | 6 +- src/machine/m_ps1.c | 8 +- src/machine/m_ps2_isa.c | 8 +- src/machine/m_ps2_mca.c | 26 +- src/machine/m_xt_compaq.c | 4 +- src/machine/m_xt_zenith.c | 4 +- src/network/net_plip.c | 2 +- src/printer/prt_ps.c | 2 +- src/sio/sio_82091aa.c | 2 +- src/sio/sio_acc3221.c | 4 +- src/sio/sio_ali5123.c | 8 +- src/sio/sio_f82c710.c | 4 +- src/sio/sio_fdc37c669.c | 2 +- src/sio/sio_fdc37c67x.c | 2 +- src/sio/sio_fdc37c6xx.c | 14 +- src/sio/sio_fdc37c93x.c | 533 +++++++++++++++++------------------ src/sio/sio_fdc37m60x.c | 2 +- src/sio/sio_it86x1f.c | 2 +- src/sio/sio_pc87306.c | 26 +- src/sio/sio_pc87307.c | 2 +- src/sio/sio_pc87309.c | 2 +- src/sio/sio_pc87310.c | 2 +- src/sio/sio_pc87311.c | 2 +- src/sio/sio_pc87332.c | 2 +- src/sio/sio_prime3b.c | 2 +- src/sio/sio_prime3c.c | 2 +- src/sio/sio_um8663f.c | 10 +- src/sio/sio_um8669f.c | 2 +- src/sio/sio_vt82c686.c | 2 +- src/sio/sio_w83787f.c | 4 +- src/sio/sio_w83877f.c | 2 +- src/sio/sio_w83977f.c | 4 +- src/sound/snd_lpt_dac.c | 2 +- src/sound/snd_lpt_dss.c | 2 +- src/video/vid_colorplus.c | 4 +- src/video/vid_hercules.c | 4 +- src/video/vid_herculesplus.c | 6 +- src/video/vid_incolor.c | 4 +- src/video/vid_mda.c | 4 +- 57 files changed, 493 insertions(+), 468 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d7b3f6f0..aa687222a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ # Authors: David Hrdlička, # # Copyright 2020-2021 David Hrdlička. -# Copyright 2021-2024 Jasmine Iwanek. +# Copyright 2021-2025 Jasmine Iwanek. # cmake_minimum_required(VERSION 3.16) diff --git a/CMakePresets.json b/CMakePresets.json index d4af8e6cb..be6615088 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -55,6 +55,14 @@ }, "inherits": "base" }, + { + "name": "ultra_debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "UltraDebug", + "DEV_BRANCH": "ON" + }, + "inherits": "base" + }, { "name": "llvm-macos-aarch64.cmake", "displayName": "MacOS clang regular", diff --git a/cmake/flags-gcc.cmake b/cmake/flags-gcc.cmake index 885353b87..90eb52cd1 100644 --- a/cmake/flags-gcc.cmake +++ b/cmake/flags-gcc.cmake @@ -20,6 +20,8 @@ string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -g0 -O3") string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -g0 -O3") string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -ggdb -Og") string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -ggdb -Og") +string(APPEND CMAKE_C_FLAGS_ULTRADEBUG_INIT " -O0 -ggdb -g3") +string(APPEND CMAKE_CXX_FLAGS_ULTRADEBUG_INIT " -O0 -ggdb -g3") string(APPEND CMAKE_C_FLAGS_OPTIMIZED_INIT " -march=native -mtune=native -O3 -ffp-contract=fast -flto") string(APPEND CMAKE_CXX_FLAGS_OPTIMIZED_INIT " -march=native -mtune=native -O3 -ffp-contract=fast -flto") @@ -28,7 +30,7 @@ foreach(LANG C;CXX) set(CMAKE_${LANG}_FLAGS "$ENV{${LANG}FLAGS} ${CMAKE_${LANG}_FLAGS_INIT}" CACHE STRING "Flags used by the ${LANG} compiler during all build types.") mark_as_advanced(CMAKE_${LANG}_FLAGS) - foreach(CONFIG RELEASE;DEBUG;OPTIMIZED) + foreach(CONFIG RELEASE;DEBUG;ULTRADEBUG;OPTIMIZED) set(CMAKE_${LANG}_FLAGS_${CONFIG} "${CMAKE_${LANG}_FLAGS_${CONFIG}_INIT}" CACHE STRING "Flags used by the ${LANG} compiler during ${CONFIG} builds.") mark_as_advanced(CMAKE_${LANG}_FLAGS_${CONFIG}) endforeach() diff --git a/src/acpi.c b/src/acpi.c index 2850a340d..b33653663 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -2473,10 +2473,9 @@ acpi_init(const device_t *info) { acpi_t *dev; - dev = (acpi_t *) malloc(sizeof(acpi_t)); + dev = (acpi_t *) calloc(1, sizeof(acpi_t)); if (dev == NULL) return NULL; - memset(dev, 0x00, sizeof(acpi_t)); cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock; dev->vendor = info->local; diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 23cc56bd3..13dbd97e9 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -975,39 +975,24 @@ stpc_serial_init(UNUSED(const device_t *info)) static void stpc_lpt_handlers(stpc_lpt_t *dev, uint8_t val) { - uint8_t old_addr = (dev->reg1 & 0x03); - uint8_t new_addr = (val & 0x03); + const uint8_t new_addr = (val & 0x03); - switch (old_addr) { - case 0x1: - lpt3_remove(); - break; - - case 0x2: - lpt1_remove(); - break; - - case 0x3: - lpt2_remove(); - break; - default: - break; - } + lpt1_remove(); switch (new_addr) { case 0x1: stpc_log("STPC: Remapping parallel port to LPT3\n"); - lpt3_init(0x3bc); + lpt1_setup(LPT_MDA_ADDR); break; case 0x2: stpc_log("STPC: Remapping parallel port to LPT1\n"); - lpt1_init(0x378); + lpt1_setup(LPT1_ADDR); break; case 0x3: stpc_log("STPC: Remapping parallel port to LPT2\n"); - lpt2_init(0x278); + lpt1_setup(LPT2_ADDR); break; default: @@ -1015,9 +1000,11 @@ stpc_lpt_handlers(stpc_lpt_t *dev, uint8_t val) break; } - dev->reg1 = (val & 0x08); - dev->reg1 |= new_addr; - dev->reg1 |= 0x84; /* reserved bits that default to 1; hardwired? */ + if (dev != NULL) { + dev->reg1 = (val & 0x08); + dev->reg1 |= new_addr; + dev->reg1 |= 0x84; /* reserved bits that default to 1; hardwired? */ + } } static void diff --git a/src/chipset/umc_8886.c b/src/chipset/umc_8886.c index f96480c2c..0ed062450 100644 --- a/src/chipset/umc_8886.c +++ b/src/chipset/umc_8886.c @@ -82,6 +82,8 @@ #include <86box/hdd.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> +#include <86box/keyboard.h> +#include <86box/machine.h> #include <86box/pic.h> #include <86box/pci.h> #include <86box/port_92.h> diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index d7d8b0fe2..a375c8eb6 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -542,16 +542,16 @@ wd76c10_ser_par_cs_recalc(wd76c10_t *dev) lpt1_remove(); switch ((dev->ser_par_cs >> 9) & 0x03) { case 1: - lpt1_init(0x3bc); - lpt1_irq(7); + lpt1_setup(LPT_MDA_ADDR); + lpt1_irq(LPT1_IRQ); break; case 2: - lpt1_init(0x378); - lpt1_irq(7); + lpt1_setup(LPT1_ADDR); + lpt1_irq(LPT1_IRQ); break; case 3: - lpt1_init(0x278); - lpt1_irq(7); + lpt1_setup(LPT2_ADDR); + lpt1_irq(LPT1_IRQ); break; } } diff --git a/src/device.c b/src/device.c index 1228eedd2..d7c80be7a 100644 --- a/src/device.c +++ b/src/device.c @@ -158,6 +158,13 @@ device_add_common(const device_t *dev, void *p, void *params, int inst) void *priv = NULL; int16_t c; + /* + IMPORTANT: This is needed to gracefully handle machine + device addition if the relevant device is NULL. + */ + if (dev == NULL) + return NULL; + if (!device_available(dev)) { wchar_t temp[512] = { 0 }; swprintf(temp, sizeof_w(temp), diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index c9da627ef..678c700a5 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -13,48 +13,48 @@ # # Copyright 2020-2021 David Hrdlička. # Copyright 2021 Andreas J. Reichel. -# Copyright 2021-2024 Jasmine Iwanek. +# Copyright 2021-2025 Jasmine Iwanek. # add_library(dev OBJECT bugger.c - cassette.c cartridge.c + cassette.c + clock_ics9xxx.c hasp.c hwm.c + hwm_gl518sm.c hwm_lm75.c hwm_lm78.c - hwm_gl518sm.c hwm_vt82c686.c + i2c.c + i2c_gpio.c ibm_5161.c isamem.c isartc.c - ../lpt.c - pci_bridge.c - postcard.c - serial.c - unittester.c - clock_ics9xxx.c isapnp.c - i2c.c - i2c_gpio.c - smbus_piix4.c - smbus_ali7101.c - smbus_sis5595.c - keyboard.c - keyboard_xt.c kbc_at.c kbc_at_dev.c + keyboard.c keyboard_at.c + keyboard_xt.c + ../lpt.c mouse.c mouse_bus.c - mouse_serial.c - mouse_ps2.c - nec_mate_unk.c - phoenix_486_jumper.c - serial_passthrough.c - novell_cardkey.c mouse_microtouch_touchscreen.c + mouse_ps2.c + mouse_serial.c + nec_mate_unk.c + novell_cardkey.c + pci_bridge.c + phoenix_486_jumper.c + postcard.c + serial.c + serial_passthrough.c + smbus_ali7101.c + smbus_piix4.c + smbus_sis5595.c + unittester.c ) if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT MSVC) diff --git a/src/disk/hdc_ide_w83769f.c b/src/disk/hdc_ide_w83769f.c index 9c0f744b2..7829c5b92 100644 --- a/src/disk/hdc_ide_w83769f.c +++ b/src/disk/hdc_ide_w83769f.c @@ -10,7 +10,7 @@ * * Authors: Miran Grca, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Miran Grca. */ #include #include diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 7731d60d4..e798f2464 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -13,7 +13,7 @@ * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2025 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. */ #ifndef EMU_HDC_H diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 225ab3936..ec5c05775 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -15,7 +15,7 @@ * Fred N. van Kempen, * * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2025 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. */ @@ -194,8 +194,8 @@ typedef struct scancode { extern "C" { #endif -extern uint8_t keyboard_mode; -extern int keyboard_scan; +extern uint8_t keyboard_mode; +extern int keyboard_scan; extern uint16_t scancode_map[768]; @@ -232,26 +232,26 @@ extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_xt_hyundai_device; extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; -extern const device_t keyboard_at_siemens_device; extern const device_t keyboard_at_ami_device; +extern const device_t keyboard_at_compaq_device; +extern const device_t keyboard_at_ncr_device; +extern const device_t keyboard_at_olivetti_device; +extern const device_t keyboard_at_siemens_device; extern const device_t keyboard_at_tg_ami_device; extern const device_t keyboard_at_toshiba_device; -extern const device_t keyboard_at_olivetti_device; -extern const device_t keyboard_at_ncr_device; -extern const device_t keyboard_at_compaq_device; extern const device_t keyboard_ps2_device; extern const device_t keyboard_ps2_ps1_device; extern const device_t keyboard_ps2_ps1_pci_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_holtek_device; -extern const device_t keyboard_ps2_tg_ami_device; -extern const device_t keyboard_ps2_tg_ami_green_device; -extern const device_t keyboard_ps2_olivetti_device; -extern const device_t keyboard_ps2_phoenix_device; extern const device_t keyboard_ps2_mca_1_device; extern const device_t keyboard_ps2_mca_2_device; +extern const device_t keyboard_ps2_olivetti_device; +extern const device_t keyboard_ps2_phoenix_device; extern const device_t keyboard_ps2_quadtel_device; +extern const device_t keyboard_ps2_tg_ami_device; +extern const device_t keyboard_ps2_tg_ami_green_device; extern const device_t keyboard_ps2_pci_device; extern const device_t keyboard_ps2_ami_pci_device; extern const device_t keyboard_ps2_intel_ami_pci_device; diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 4e95b64c3..674d6340f 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -31,33 +31,33 @@ typedef struct lpt_device_t { } lpt_device_t; extern void lpt_init(void); -extern void lpt_port_init(int i, uint16_t port); +extern void lpt_port_setup(int i, uint16_t port); extern void lpt_port_irq(int i, uint8_t irq); extern void lpt_port_remove(int i); extern void lpt1_remove_ams(void); -#define lpt1_init(a) lpt_port_init(0, a) +#define lpt1_setup(a) lpt_port_setup(0, a) #define lpt1_irq(a) lpt_port_irq(0, a) #define lpt1_remove() lpt_port_remove(0) -#define lpt2_init(a) lpt_port_init(1, a) +#define lpt2_setup(a) lpt_port_setup(1, a) #define lpt2_irq(a) lpt_port_irq(1, a) #define lpt2_remove() lpt_port_remove(1) -#define lpt3_init(a) lpt_port_init(2, a) +#define lpt3_setup(a) lpt_port_setup(2, a) #define lpt3_irq(a) lpt_port_irq(2, a) #define lpt3_remove() lpt_port_remove(2) -#define lpt4_init(a) lpt_port_init(3, a) +#define lpt4_setup(a) lpt_port_setup(3, a) #define lpt4_irq(a) lpt_port_irq(3, a) #define lpt4_remove() lpt_port_remove(3) #if 0 -#define lpt5_init(a) lpt_port_init(4, a) +#define lpt5_setup(a) lpt_port_setup(4, a) #define lpt5_irq(a) lpt_port_irq(4, a) #define lpt5_remove() lpt_port_remove(4) -#define lpt6_init(a) lpt_port_init(5, a) +#define lpt6_setup(a) lpt_port_setup(5, a) #define lpt6_irq(a) lpt_port_irq(5, a) #define lpt6_remove() lpt_port_remove(5) #endif diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 2dbe97ab0..7fcb376b9 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -16,13 +16,20 @@ #ifndef EMU_SIO_H #define EMU_SIO_H -extern void vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv); - +/* ACC Micro */ extern const device_t acc3221_device; + +/* Acer / ALi */ extern const device_t ali5105_device; + extern const device_t ali5123_device; -extern const device_t f82c710_device; + +/* Chips & Technologies */ extern const device_t f82c606_device; + +extern const device_t f82c710_device; + +/* SM(S)C */ extern const device_t fdc37c651_device; extern const device_t fdc37c651_ide_device; extern const device_t fdc37c661_device; @@ -35,9 +42,12 @@ extern const device_t fdc37c665_ide_device; extern const device_t fdc37c665_ide_pri_device; extern const device_t fdc37c665_ide_sec_device; extern const device_t fdc37c666_device; -extern const device_t fdc37c67x_device; + extern const device_t fdc37c669_device; extern const device_t fdc37c669_370_device; + +extern const device_t fdc37c67x_device; + extern const device_t fdc37c931apm_device; extern const device_t fdc37c931apm_compaq_device; extern const device_t fdc37c932fr_device; @@ -46,22 +56,23 @@ extern const device_t fdc37c932_device; extern const device_t fdc37c935_device; extern const device_t fdc37c935_370_device; extern const device_t fdc37c935_no_nvr_device; + extern const device_t fdc37m60x_device; extern const device_t fdc37m60x_370_device; + +/* ITE */ extern const device_t it8661f_device; extern const device_t it8671f_device; extern const device_t i82091aa_device; extern const device_t i82091aa_398_device; extern const device_t i82091aa_ide_pri_device; extern const device_t i82091aa_ide_device; -extern const device_t pc87306_device; -extern const device_t pc87307_device; -extern const device_t pc87307_15c_device; -extern const device_t pc87307_both_device; -extern const device_t pc87309_device; -extern const device_t pc87309_15c_device; + +/* National Semiconductors */ extern const device_t pc87310_device; extern const device_t pc87310_ide_device; + +extern const device_t pc87306_device; extern const device_t pc87311_device; extern const device_t pc87311_ide_device; extern const device_t pc87332_device; @@ -69,35 +80,66 @@ extern const device_t pc87332_398_device; extern const device_t pc87332_398_ide_device; extern const device_t pc87332_398_ide_sec_device; extern const device_t pc87332_398_ide_fdcon_device; + +extern const device_t pc87307_device; +extern const device_t pc87307_15c_device; +extern const device_t pc87307_both_device; extern const device_t pc97307_device; + +extern const device_t pc87309_device; +extern const device_t pc87309_15c_device; + +/* LG Prime */ extern const device_t prime3b_device; extern const device_t prime3b_ide_device; extern const device_t prime3c_device; extern const device_t prime3c_ide_device; + +/* IBM PS/1 */ extern const device_t ps1_m2133_sio; + +/* Super I/O Detect */ #ifdef USE_SIO_DETECT extern const device_t sio_detect_device; #endif /* USE_SIO_DETECT */ + +/* UMC */ extern const device_t um8663af_device; extern const device_t um8663af_ide_device; extern const device_t um8663af_sec_device; extern const device_t um8663bf_device; extern const device_t um8663bf_ide_device; extern const device_t um8663bf_sec_device; + extern const device_t um8669f_device; extern const device_t um8669f_ide_device; extern const device_t um8669f_ide_sec_device; + +/* VIA */ +extern void vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv); + extern const device_t via_vt82c686_sio_device; + +/* VLSI */ extern const device_t vl82c113_device; + +/* Winbond */ extern const device_t w83787f_88h_device; extern const device_t w83787f_device; extern const device_t w83787f_ide_device; extern const device_t w83787f_ide_en_device; extern const device_t w83787f_ide_sec_device; + extern const device_t w83877f_device; extern const device_t w83877f_president_device; extern const device_t w83877tf_device; extern const device_t w83877tf_acorp_device; + +#define TYPE_W83977EF 0x52F0 +#define TYPE_W83977F 0x9771 +#define TYPE_W83977TF 0x9773 +#define TYPE_W83977ATF 0x9774 + extern const device_t w83977f_device; extern const device_t w83977f_370_device; extern const device_t w83977tf_device; diff --git a/src/io.c b/src/io.c index fd87089d0..27f8503b0 100644 --- a/src/io.c +++ b/src/io.c @@ -15,7 +15,7 @@ * Fred N. van Kempen, * * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -145,6 +145,8 @@ io_sethandler_common(uint16_t base, int size, q->next = NULL; io_last[base + c] = q; + + q = NULL; } } diff --git a/src/lpt.c b/src/lpt.c index 3f1c5eb7b..26174d96b 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -219,14 +219,14 @@ lpt_init(void) lpt_ports[i].enable_irq = 0x10; if (lpt_ports[i].enabled) { - lpt_port_init(i, default_ports[i]); + lpt_port_setup(i, default_ports[i]); lpt_port_irq(i, default_irqs[i]); } } } void -lpt_port_init(int i, uint16_t port) +lpt_port_setup(int i, uint16_t port) { if (lpt_ports[i].enabled) { if (lpt_ports[i].addr != 0xffff) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index c3dc5c772..cb2a04d07 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -66,7 +66,7 @@ machine_at_mr286_init(const machine_t *model) } static void -machine_at_headland_common_init(int type) +machine_at_headland_common_init(const machine_t *model, int type) { device_add(&keyboard_at_ami_device); @@ -94,7 +94,7 @@ machine_at_tg286m_init(const machine_t *model) machine_at_common_ide_init(model); - machine_at_headland_common_init(1); + machine_at_headland_common_init(model, 1); return ret; } @@ -115,7 +115,7 @@ machine_at_ama932j_init(const machine_t *model) if (gfxcard[0] == VID_INTERNAL) device_add(&oti067_ama932j_device); - machine_at_headland_common_init(2); + machine_at_headland_common_init(model, 2); device_add(&ali5105_device); @@ -755,7 +755,7 @@ machine_at_acer100t_init(const machine_t *model) device_add(&ali1409_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&oti077_acer100t_device); + device_add(&oti077_acer100t_device); device_add(&ali5105_device); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 656db503b..3d152065b 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -50,6 +50,7 @@ #include <86box/plat_unused.h> #include <86box/sound.h> +/* 386DX */ int machine_at_acc386_init(const machine_t *model) { @@ -252,7 +253,7 @@ machine_at_ecs386v_init(const machine_t *model) int ret; ret = bios_load_linear("roms/machines/ecs386v/PANDA_386V.BIN", - 0x000f0000, 65536, 0); + 0x000f0000, 65536, 0); if (bios_only || !ret) return ret; @@ -1412,7 +1413,7 @@ machine_at_amis76_init(const machine_t *model) { int ret; - ret = bios_load_linear_inverted("roms/machines/s76p/S76P.ROM", + ret = bios_load_linear_inverted("roms/machines/s76p/S76P.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 0b45fe60c..b9615c064 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -64,13 +64,13 @@ cbm_io_write(UNUSED(uint16_t port), uint8_t val, UNUSED(void *priv)) switch (val & 3) { case 1: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 2: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 3: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 92846c401..130481394 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -146,13 +146,13 @@ ps1_write(uint16_t port, uint8_t val, void *priv) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -316,7 +316,7 @@ ps1_setup(int model) ps->uart = device_add_inst(&ns16450_device, 1); lpt1_remove(); - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); mem_remap_top(384); diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 7d024c335..8a2760f15 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -64,13 +64,13 @@ ps2_write(uint16_t port, uint8_t val, void *priv) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -167,7 +167,7 @@ ps2_isa_setup(int model, int cpu_type) ps2->uart = device_add_inst(&ns16450_device, 1); lpt1_remove(); - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); device_add(&port_92_device); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 632381ca1..35f3ed125 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -374,13 +374,13 @@ model_50_write(uint16_t port, uint8_t val) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -506,13 +506,13 @@ model_55sx_write(uint16_t port, uint8_t val) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -565,13 +565,13 @@ model_70_type3_write(uint16_t port, uint8_t val) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -619,13 +619,13 @@ model_80_write(uint16_t port, uint8_t val) if (val & 0x10) { switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: @@ -846,7 +846,7 @@ ps2_mca_board_common_init(void) ps2.setup = 0xff; - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); } static uint8_t diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index ed1b3e26c..f8c0b6a19 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -59,7 +59,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model) standalone_gameport_type = &gameport_device; lpt1_remove(); - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); return ret; } @@ -87,7 +87,7 @@ machine_xt_compaq_portable_init(const machine_t *model) device_add(&gameport_device); lpt1_remove(); - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); return ret; } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index 833529ffb..6c5d556f2 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -144,7 +144,7 @@ machine_xt_z184_init(const machine_t *model) lpt1_remove(); /* only one parallel port */ lpt2_remove(); - lpt1_init(0x278); + lpt1_setup(LPT2_ADDR); device_add(&ns8250_device); serial_set_next_inst(SERIAL_MAX); /* So that serial_standalone_init() won't do anything. */ @@ -198,7 +198,7 @@ machine_xt_z159_init(const machine_t *model) /* parallel port is on the memory board */ lpt1_remove(); /* only one parallel port */ lpt2_remove(); - lpt1_init(0x278); + lpt1_setup(LPT2_ADDR); return ret; } diff --git a/src/network/net_plip.c b/src/network/net_plip.c index f80effeec..8c46213c6 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -26,12 +26,12 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/timer.h> #include <86box/lpt.h> #include <86box/timer.h> #include <86box/pit.h> #include <86box/device.h> #include <86box/thread.h> -#include <86box/timer.h> #include <86box/network.h> #include <86box/plat_unused.h> diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 1a9d5c0e8..1298018ee 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -26,8 +26,8 @@ #include #include #include <86box/86box.h> -#include <86box/lpt.h> #include <86box/timer.h> +#include <86box/lpt.h> #include <86box/pit.h> #include <86box/path.h> #include <86box/plat.h> diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c index 76c7ba3f5..d3cd5017a 100644 --- a/src/sio/sio_82091aa.c +++ b/src/sio/sio_82091aa.c @@ -78,7 +78,7 @@ lpt1_handler(i82091aa_t *dev) } if ((dev->regs[0x20] & 0x01) && lpt_port) - lpt1_init(lpt_port); + lpt1_setup(lpt_port); lpt1_irq((dev->regs[0x20] & 0x08) ? LPT1_IRQ : LPT2_IRQ); } diff --git a/src/sio/sio_acc3221.c b/src/sio/sio_acc3221.c index d52949d46..203b1c1f1 100644 --- a/src/sio/sio_acc3221.c +++ b/src/sio/sio_acc3221.c @@ -305,7 +305,7 @@ acc3221_lpt_handle(acc3221_t *dev) lpt1_remove(); if (!(dev->regs[0xbe] & REG_BE_LPT1_DISABLE)) - lpt1_init(dev->regs[0xbf] << 2); + lpt1_setup(dev->regs[0xbf] << 2); } static void @@ -437,7 +437,7 @@ acc3221_reset(acc3221_t *dev) serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); lpt1_remove(); - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); lpt1_irq(LPT1_IRQ); fdc_reset(dev->fdc); diff --git a/src/sio/sio_ali5123.c b/src/sio/sio_ali5123.c index 5380e065a..398d00839 100644 --- a/src/sio/sio_ali5123.c +++ b/src/sio/sio_ali5123.c @@ -93,7 +93,7 @@ ali5123_lpt_handler(ali5123_t *dev) if (global_enable && local_enable) { ld_port = make_port(dev, 3) & 0xFFFC; if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - lpt1_init(ld_port); + lpt1_setup(ld_port); } lpt1_irq(lpt_irq); } @@ -133,8 +133,10 @@ ali5123_serial_handler(ali5123_t *dev, int uart) } static void -ali5123_reset(ali5123_t *dev) +ali5123_reset(void *priv) { + ali5123_t *dev = (ali5123_t *) priv; + memset(dev->regs, 0, 48); dev->regs[0x20] = 0x43; @@ -490,7 +492,7 @@ const device_t ali5123_device = { .local = 0x40, .init = ali5123_init, .close = ali5123_close, - .reset = NULL, + .reset = ali5123_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, diff --git a/src/sio/sio_f82c710.c b/src/sio/sio_f82c710.c index 8882f16e0..a7aa101c6 100644 --- a/src/sio/sio_f82c710.c +++ b/src/sio/sio_f82c710.c @@ -104,7 +104,7 @@ f82c710_update_ports(upc_t *dev, int set) if (dev->regs[0] & 8) { lpt_addr = dev->regs[6] * 4; - lpt1_init(lpt_addr); + lpt1_setup(lpt_addr); if ((lpt_addr == LPT1_ADDR) || (lpt_addr == LPT_MDA_ADDR)) lpt1_irq(LPT1_IRQ); else if (lpt_addr == LPT2_ADDR) @@ -215,7 +215,7 @@ f82c606_update_ports(upc_t *dev, int set) } if (dev->regs[0] & 8) { - lpt1_init(((uint16_t) dev->regs[6]) << 2); + lpt1_setup(((uint16_t) dev->regs[6]) << 2); lpt1_irq(lpt1_int); f82c710_log("LPT1 at %04X, IRQ %i\n", ((uint16_t) dev->regs[6]) << 2, lpt1_int); } diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index 7f97e79b0..3be28c6ba 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -107,7 +107,7 @@ fdc37c669_lpt_handler(fdc37c669_t *dev) lpt_port_remove(dev->id); if ((dev->regs[0x01] & 0x04) && (dev->regs[0x23] >= 0x40)) - lpt_port_init(dev->id, ((uint16_t) (dev->regs[0x23] & mask)) << 2); + lpt_port_setup(dev->id, ((uint16_t) (dev->regs[0x23] & mask)) << 2); } static void diff --git a/src/sio/sio_fdc37c67x.c b/src/sio/sio_fdc37c67x.c index f0fb8cd64..931734048 100644 --- a/src/sio/sio_fdc37c67x.c +++ b/src/sio/sio_fdc37c67x.c @@ -134,7 +134,7 @@ fdc37c67x_lpt_handler(fdc37c67x_t *dev) if (global_enable && local_enable) { ld_port = make_port(dev, 3) & 0xFFFC; if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - lpt1_init(ld_port); + lpt1_setup(ld_port); } lpt1_irq(lpt_irq); } diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index 530fff216..0f3460565 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -111,16 +111,16 @@ lpt1_handler(fdc37c6xx_t *dev) lpt1_remove(); switch (dev->regs[1] & 3) { case 1: - lpt1_init(LPT_MDA_ADDR); - lpt1_irq(7); + lpt1_setup(LPT_MDA_ADDR); + lpt1_irq(LPT_MDA_IRQ); break; case 2: - lpt1_init(LPT1_ADDR); - lpt1_irq(7 /*5*/); + lpt1_setup(LPT1_ADDR); + lpt1_irq(LPT1_IRQ /*LPT2_IRQ*/); break; case 3: - lpt1_init(LPT2_ADDR); - lpt1_irq(7 /*5*/); + lpt1_setup(LPT2_ADDR); + lpt1_irq(LPT1_IRQ /*LPT2_IRQ*/); break; default: @@ -252,7 +252,7 @@ fdc37c6xx_reset(fdc37c6xx_t *dev) serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); lpt1_remove(); - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); fdc_reset(dev->fdc); fdc_remove(dev->fdc); diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 42908ecaf..8d8f76cb6 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -35,24 +35,15 @@ #include <86box/machine.h> #include <86box/nvr.h> #include <86box/apm.h> +#include <86box/access_bus.h> #include <86box/acpi.h> #include <86box/sio.h> #include <86box/plat_unused.h> -#define AB_RST 0x80 - -typedef struct access_bus_t { - uint8_t control; - uint8_t status; - uint8_t own_addr; - uint8_t data; - uint8_t clock; - uint16_t base; -} access_bus_t; - typedef struct fdc37c93x_t { uint8_t chip_id; uint8_t is_apm; + uint8_t is_compaq; uint8_t has_nvr; uint8_t tries; uint8_t port_370; @@ -61,51 +52,56 @@ typedef struct fdc37c93x_t { uint8_t regs[48]; uint8_t ld_regs[11][256]; uint16_t superio_base; + uint16_t fdc_base; + uint16_t lpt_base; + uint16_t nvr_pri_base; + uint16_t nvr_sec_base; + uint16_t kbc_base; uint16_t gpio_base; /* Set to EA */ uint16_t auxio_base; - uint16_t nvr_sec_base; + uint16_t uart_base[2]; int locked; int cur_reg; fdc_t *fdc; - serial_t *uart[2]; access_bus_t *access_bus; nvr_t *nvr; acpi_t *acpi; void *kbc; + serial_t *uart[2]; } fdc37c93x_t; static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv); static uint8_t fdc37c93x_read(uint16_t port, void *priv); static uint16_t -make_port_superio(fdc37c93x_t *dev) +make_port_superio(const fdc37c93x_t *dev) { - uint16_t r0 = dev->regs[0x26]; - uint16_t r1 = dev->regs[0x27]; + const uint16_t r0 = dev->regs[0x26]; + const uint16_t r1 = dev->regs[0x27]; - uint16_t p = (r1 << 8) + r0; + const uint16_t p = (r1 << 8) + r0; return p; } static uint16_t -make_port(fdc37c93x_t *dev, uint8_t ld) +make_port(const fdc37c93x_t *dev, const uint8_t ld) { - uint16_t r0 = dev->ld_regs[ld][0x60]; - uint16_t r1 = dev->ld_regs[ld][0x61]; + const uint16_t r0 = dev->ld_regs[ld][0x60]; + const uint16_t r1 = dev->ld_regs[ld][0x61]; - uint16_t p = (r0 << 8) + r1; + const uint16_t p = (r0 << 8) + r1; return p; } static uint16_t -make_port_sec(fdc37c93x_t *dev, uint8_t ld) +make_port_sec(const fdc37c93x_t *dev, const uint8_t ld) { - uint16_t r0 = dev->ld_regs[ld][0x62]; - uint16_t r1 = dev->ld_regs[ld][0x63]; + const uint16_t r0 = dev->ld_regs[ld][0x62]; + const uint16_t r1 = dev->ld_regs[ld][0x63]; - uint16_t p = (r0 << 8) + r1; + const uint16_t p = (r0 << 8) + r1; return p; } @@ -150,66 +146,91 @@ fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) static void fdc37c93x_superio_handler(fdc37c93x_t *dev) { - io_removehandler(dev->superio_base, 0x0002, - fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); - dev->superio_base = make_port_superio(dev); - io_sethandler(dev->superio_base, 0x0002, - fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + if (!dev->is_compaq) { + if (dev->superio_base != 0x0000) + io_removehandler(dev->superio_base, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + dev->superio_base = make_port_superio(dev); + if (dev->superio_base != 0x0000) + io_sethandler(dev->superio_base, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + } } static void fdc37c93x_fdc_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); - uint8_t local_enable = !!dev->ld_regs[0][0x30]; + const uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + const uint8_t local_enable = !!dev->ld_regs[0][0x30]; + const uint16_t old_base = dev->fdc_base; - fdc_remove(dev->fdc); - if (global_enable && local_enable) { - ld_port = make_port(dev, 0) & 0xFFF8; - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) - fdc_set_base(dev->fdc, ld_port); + dev->fdc_base = 0x0000; + + if (global_enable && local_enable) + dev->fdc_base = make_port(dev, 0) & 0xfff8; + + if (dev->fdc_base != old_base) { + if ((old_base >= 0x0100) && (old_base <= 0x0ff8)) + fdc_remove(dev->fdc); + + if ((dev->fdc_base >= 0x0100) && (dev->fdc_base <= 0x0ff8)) + fdc_set_base(dev->fdc, dev->fdc_base); } } static void fdc37c93x_lpt_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); - uint8_t local_enable = !!dev->ld_regs[3][0x30]; - uint8_t lpt_irq = dev->ld_regs[3][0x70]; + const uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + const uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + const uint16_t old_base = dev->lpt_base; if (lpt_irq > 15) lpt_irq = 0xff; - lpt1_remove(); - if (global_enable && local_enable) { - ld_port = make_port(dev, 3) & 0xFFFC; - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - lpt1_init(ld_port); + dev->lpt_base = 0x0000; + + if (global_enable && local_enable) + dev->lpt_base = make_port(dev, 3) & 0xfffc; + + if (dev->lpt_base != old_base) { + if ((old_base >= 0x0100) && (old_base <= 0x0ffc)) + lpt1_remove(); + + if ((dev->lpt_base >= 0x0100) && (dev->lpt_base <= 0x0ffc)) + lpt1_setup(dev->lpt_base); } + lpt1_irq(lpt_irq); } static void -fdc37c93x_serial_handler(fdc37c93x_t *dev, int uart) +fdc37c93x_serial_handler(fdc37c93x_t *dev, const int uart) { - uint16_t ld_port = 0; - uint8_t uart_no = 4 + uart; - uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); - uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + const uint8_t uart_no = 4 + uart; + const uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + const uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + const uint16_t old_base = dev->uart_base[uart]; - serial_remove(dev->uart[uart]); - if (global_enable && local_enable) { - ld_port = make_port(dev, uart_no) & 0xFFF8; - if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) - serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + dev->uart_base[uart] = 0x0000; + + if (global_enable && local_enable) + dev->uart_base[uart] = make_port(dev, uart_no) & 0xfff8; + + if (dev->uart_base[uart] != old_base) { + if ((old_base >= 0x0100) && (old_base <= 0x0ff8)) + serial_remove(dev->uart[uart]); + + if ((dev->uart_base[uart] >= 0x0100) && (dev->uart_base[uart] <= 0x0ff8)) + serial_setup(dev->uart[uart], dev->uart_base[uart], dev->ld_regs[uart_no][0x70]); } + + serial_irq(dev->uart[uart], dev->ld_regs[uart_no][0x70]); } static void -fdc37c93x_nvr_pri_handler(fdc37c93x_t *dev) +fdc37c93x_nvr_pri_handler(const fdc37c93x_t *dev) { uint8_t local_enable = !!dev->ld_regs[6][0x30]; @@ -224,18 +245,24 @@ fdc37c93x_nvr_pri_handler(fdc37c93x_t *dev) static void fdc37c93x_nvr_sec_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t local_enable = !!dev->ld_regs[6][0x30]; + uint8_t local_enable = !!dev->ld_regs[6][0x30]; + const uint16_t old_base = dev->nvr_sec_base; local_enable &= (((dev->ld_regs[6][0xf0] & 0xe0) == 0x80) || ((dev->ld_regs[6][0xf0] & 0xe0) == 0xe0)); - nvr_at_sec_handler(0, dev->nvr_sec_base, dev->nvr); - if (local_enable) { - dev->nvr_sec_base = ld_port = make_port_sec(dev, 6) & 0xFFFE; + dev->nvr_sec_base = 0x0000; + + if (local_enable) + dev->nvr_sec_base = make_port_sec(dev, 6) & 0xfffe; + + if (dev->nvr_sec_base != old_base) { + if ((old_base > 0x0000) && (old_base <= 0x0ffe)) + nvr_at_sec_handler(0, dev->nvr_sec_base, dev->nvr); + /* Datasheet erratum: First it says minimum address is 0x0100, but later implies that it's 0x0000 and that default is 0x0070, same as (unrelocatable) primary NVR. */ - if (ld_port <= 0x0FFE) + if ((dev->nvr_sec_base > 0x0000) && (dev->nvr_sec_base <= 0x0ffe)) nvr_at_sec_handler(1, dev->nvr_sec_base, dev->nvr); } } @@ -243,22 +270,32 @@ fdc37c93x_nvr_sec_handler(fdc37c93x_t *dev) static void fdc37c93x_kbc_handler(fdc37c93x_t *dev) { - uint8_t local_enable = !!dev->ld_regs[7][0x30]; + const uint8_t local_enable = !!dev->ld_regs[7][0x30]; + const uint16_t old_base = dev->kbc_base; - kbc_at_handler(local_enable, dev->kbc); + dev->kbc_base = local_enable ? 0x0060 : 0x0000; + + if (dev->kbc_base != old_base) + kbc_at_handler(local_enable, dev->kbc); } static void fdc37c93x_auxio_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t local_enable = !!dev->ld_regs[8][0x30]; + const uint8_t local_enable = !!dev->ld_regs[8][0x30]; + const uint16_t old_base = dev->auxio_base; - io_removehandler(dev->auxio_base, 0x0001, - fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); - if (local_enable) { - dev->auxio_base = ld_port = make_port(dev, 8); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + if (local_enable) + dev->auxio_base = make_port(dev, 8); + else + dev->auxio_base = 0x0000; + + if (dev->auxio_base != old_base) { + if ((old_base >= 0x0100) && (old_base <= 0x0fff)) + io_removehandler(old_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + + if ((dev->auxio_base >= 0x0100) && (dev->auxio_base <= 0x0fff)) io_sethandler(dev->auxio_base, 0x0001, fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); } @@ -267,113 +304,55 @@ fdc37c93x_auxio_handler(fdc37c93x_t *dev) static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t local_enable; + const uint8_t local_enable = !dev->locked && !!(dev->regs[0x03] & 0x80); + const uint16_t old_base = dev->gpio_base; - local_enable = !!(dev->regs[0x03] & 0x80); + dev->gpio_base = 0x0000; - io_removehandler(dev->gpio_base, 0x0002, - fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); - if (local_enable) { - switch (dev->regs[0x03] & 0x03) { - case 0: - ld_port = 0xe0; - break; - case 1: - ld_port = 0xe2; - break; - case 2: - ld_port = 0xe4; - break; - case 3: - ld_port = 0xea; /* Default */ - break; + if (local_enable) switch (dev->regs[0x03] & 0x03) { + default: + break; + case 0: + dev->gpio_base = 0x00e0; + break; + case 1: + dev->gpio_base = 0x00e2; + break; + case 2: + dev->gpio_base = 0x00e4; + break; + case 3: + dev->gpio_base = 0x00ea; /* Default */ + break; + } - default: - break; - } - dev->gpio_base = ld_port; - if (ld_port > 0x0000) + if (dev->gpio_base != old_base) { + if (old_base != 0x0000) + io_removehandler(old_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + + if (dev->gpio_base > 0x0000) io_sethandler(dev->gpio_base, 0x0002, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); } } -static uint8_t -fdc37c93x_access_bus_read(uint16_t port, void *priv) -{ - const access_bus_t *dev = (access_bus_t *) priv; - uint8_t ret = 0xff; - - switch (port & 3) { - case 0: - ret = (dev->status & 0xBF); - break; - case 1: - ret = (dev->own_addr & 0x7F); - break; - case 2: - ret = dev->data; - break; - case 3: - ret = (dev->clock & 0x87); - break; - - default: - break; - } - - return ret; -} - -static void -fdc37c93x_access_bus_write(uint16_t port, uint8_t val, void *priv) -{ - access_bus_t *dev = (access_bus_t *) priv; - - switch (port & 3) { - case 0: - dev->control = (val & 0xCF); - break; - case 1: - dev->own_addr = (val & 0x7F); - break; - case 2: - dev->data = val; - break; - case 3: - dev->clock &= 0x80; - dev->clock |= (val & 0x07); - break; - - default: - break; - } -} - static void fdc37c93x_access_bus_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); - uint8_t local_enable = !!dev->ld_regs[9][0x30]; + const uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); + const uint8_t local_enable = !!dev->ld_regs[9][0x30]; + const uint16_t ld_port = dev->access_bus->base = make_port(dev, 9); - io_removehandler(dev->access_bus->base, 0x0004, - fdc37c93x_access_bus_read, NULL, NULL, fdc37c93x_access_bus_write, NULL, NULL, dev->access_bus); - if (global_enable && local_enable) { - dev->access_bus->base = ld_port = make_port(dev, 9); - if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) - io_sethandler(dev->access_bus->base, 0x0004, - fdc37c93x_access_bus_read, NULL, NULL, fdc37c93x_access_bus_write, NULL, NULL, dev->access_bus); - } + access_bus_handler(dev->access_bus, global_enable && local_enable, ld_port); } static void fdc37c93x_acpi_handler(fdc37c93x_t *dev) { - uint16_t ld_port = 0; - uint8_t local_enable = !!dev->ld_regs[0x0a][0x30]; - uint8_t sci_irq = dev->ld_regs[0x0a][0x70]; + uint16_t ld_port; + const uint8_t local_enable = !!dev->ld_regs[0x0a][0x30]; + const uint8_t sci_irq = dev->ld_regs[0x0a][0x70]; acpi_update_io_mapping(dev->acpi, 0x0000, local_enable); if (local_enable) { @@ -392,41 +371,49 @@ fdc37c93x_acpi_handler(fdc37c93x_t *dev) acpi_set_irq_line(dev->acpi, sci_irq); } +static void +fdc37c93x_state_change(fdc37c93x_t *dev, const uint8_t locked) +{ + dev->locked = locked; + fdc_3f1_enable(dev->fdc, !locked); + fdc37c93x_gpio_handler(dev); +} + static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor = 0x00; - uint8_t keep = 0x00; + uint8_t valxor; /* Compaq Presario 4500: Unlock at FB, Register at EA, Data at EB, Lock at F9. */ - if ((port == 0xea) || (port == 0xf9) || (port == 0xfb)) + if (port == 0xea) index = 1; else if (port == 0xeb) index = 0; - if (index) { - if ((val == 0x55) && !dev->locked) { + if (port == 0xfb) { + fdc37c93x_state_change(dev, 1); + dev->tries = 0; + return; + } else if (port == 0xf9) { + fdc37c93x_state_change(dev, 0); + return; + } else if (index) { + if ((!dev->is_compaq) && (val == 0x55) && !dev->locked) { if (dev->tries) { - dev->locked = 1; - fdc_3f1_enable(dev->fdc, 0); + fdc37c93x_state_change(dev, 1); dev->tries = 0; } else dev->tries++; - } else { - if (dev->locked) { - if (val == 0xaa) { - dev->locked = 0; - fdc_3f1_enable(dev->fdc, 1); - return; - } - dev->cur_reg = val; - } else { - if (dev->tries) - dev->tries = 0; + } else if (dev->locked) { + if ((!dev->is_compaq) && (val == 0xaa)) { + fdc37c93x_state_change(dev, 0); + return; } - } + dev->cur_reg = val; + } else if ((!dev->is_compaq) && dev->tries) + dev->tries = 0; return; } else { if (dev->locked) { @@ -436,6 +423,8 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) return; dev->regs[dev->cur_reg] = val; } else { + uint8_t keep = 0x00; + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) return; @@ -479,9 +468,11 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) if (dev->cur_reg < 48) { switch (dev->cur_reg) { + case 0x02: + if (val == 0x02) + fdc37c93x_state_change(dev, 0); + break; case 0x03: - if (valxor & 0x83) - fdc37c93x_gpio_handler(dev); dev->regs[0x03] &= 0x83; break; case 0x22: @@ -788,91 +779,95 @@ fdc37c93x_read(uint16_t port, void *priv) static void fdc37c93x_reset(fdc37c93x_t *dev) { - memset(dev->regs, 0, 48); + memset(dev->regs, 0x00, sizeof(dev->regs)); dev->regs[0x03] = 0x03; dev->regs[0x20] = dev->chip_id; dev->regs[0x21] = 0x01; dev->regs[0x22] = 0x39; dev->regs[0x24] = 0x04; - if (dev->chip_id != 0x02) { - dev->regs[0x26] = dev->port_370 ? 0x70 : 0xF0; - dev->regs[0x27] = 0x03; - } + dev->regs[0x26] = dev->port_370 ? 0x70 : 0xf0; + dev->regs[0x27] = 0x03; - for (uint8_t i = 0; i < 11; i++) - memset(dev->ld_regs[i], 0, 256); + memset(dev->ld_regs, 0x00, sizeof(dev->ld_regs)); /* Logical device 0: FDD */ - dev->ld_regs[0][0x30] = 0; - dev->ld_regs[0][0x60] = 3; - dev->ld_regs[0][0x61] = 0xF0; - dev->ld_regs[0][0x70] = 6; - dev->ld_regs[0][0x74] = 2; - dev->ld_regs[0][0xF0] = 0xE; - dev->ld_regs[0][0xF2] = 0xFF; + dev->ld_regs[0x00][0x30] = 0x00; + dev->ld_regs[0x00][0x60] = 0x03; + dev->ld_regs[0x00][0x61] = 0xf0; + dev->ld_regs[0x00][0x70] = 0x06; + dev->ld_regs[0x00][0x74] = 0x02; + dev->ld_regs[0x00][0xf0] = 0x0e; + dev->ld_regs[0x00][0xf2] = 0xff; /* Logical device 1: IDE1 */ - dev->ld_regs[1][0x30] = 0; - dev->ld_regs[1][0x60] = 1; - dev->ld_regs[1][0x61] = 0xF0; - dev->ld_regs[1][0x62] = 3; - dev->ld_regs[1][0x63] = 0xF6; - dev->ld_regs[1][0x70] = 0xE; - dev->ld_regs[1][0xF0] = 0xC; + dev->ld_regs[0x01][0x30] = 0x00; + dev->ld_regs[0x01][0x60] = 0x01; + dev->ld_regs[0x01][0x61] = 0xf0; + dev->ld_regs[0x01][0x62] = 0x03; + dev->ld_regs[0x01][0x63] = 0xf6; + dev->ld_regs[0x01][0x70] = 0x0e; + dev->ld_regs[0x01][0xf0] = 0x0c; /* Logical device 2: IDE2 */ - dev->ld_regs[2][0x30] = 0; - dev->ld_regs[2][0x60] = 1; - dev->ld_regs[2][0x61] = 0x70; - dev->ld_regs[2][0x62] = 3; - dev->ld_regs[2][0x63] = 0x76; - dev->ld_regs[2][0x70] = 0xF; + dev->ld_regs[0x02][0x30] = 0x00; + dev->ld_regs[0x02][0x60] = 0x01; + dev->ld_regs[0x02][0x61] = 0x70; + dev->ld_regs[0x02][0x62] = 0x03; + dev->ld_regs[0x02][0x63] = 0x76; + dev->ld_regs[0x02][0x70] = 0x0f; /* Logical device 3: Parallel Port */ - dev->ld_regs[3][0x30] = 0; - dev->ld_regs[3][0x60] = 3; - dev->ld_regs[3][0x61] = 0x78; - dev->ld_regs[3][0x70] = 7; - dev->ld_regs[3][0x74] = 4; - dev->ld_regs[3][0xF0] = 0x3C; + dev->ld_regs[0x03][0x30] = 0x00; + dev->ld_regs[0x03][0x60] = 0x03; + dev->ld_regs[0x03][0x61] = 0x78; + dev->ld_regs[0x03][0x70] = 0x07; + dev->ld_regs[0x03][0x74] = 0x04; + dev->ld_regs[0x03][0xf0] = 0x3c; /* Logical device 4: Serial Port 1 */ - dev->ld_regs[4][0x30] = 0; - dev->ld_regs[4][0x60] = 3; - dev->ld_regs[4][0x61] = 0xf8; - dev->ld_regs[4][0x70] = 4; - dev->ld_regs[4][0xF0] = 3; - serial_setup(dev->uart[0], COM1_ADDR, dev->ld_regs[4][0x70]); + dev->ld_regs[0x04][0x30] = 0x00; + dev->ld_regs[0x04][0x60] = 0x03; + dev->ld_regs[0x04][0x61] = 0xf8; + dev->ld_regs[0x04][0x70] = 0x04; + dev->ld_regs[0x04][0xf0] = 0x03; + serial_irq(dev->uart[0], dev->ld_regs[4][0x70]); /* Logical device 5: Serial Port 2 */ - dev->ld_regs[5][0x30] = 0; - dev->ld_regs[5][0x60] = 2; - dev->ld_regs[5][0x61] = 0xf8; - dev->ld_regs[5][0x70] = 3; - dev->ld_regs[5][0x74] = 4; - dev->ld_regs[5][0xF1] = 2; - dev->ld_regs[5][0xF2] = 3; - serial_setup(dev->uart[1], COM2_ADDR, dev->ld_regs[5][0x70]); + dev->ld_regs[0x05][0x30] = 0x00; + dev->ld_regs[0x05][0x60] = 0x02; + dev->ld_regs[0x05][0x61] = 0xf8; + dev->ld_regs[0x05][0x70] = 0x03; + dev->ld_regs[0x05][0x74] = 0x04; + dev->ld_regs[0x05][0xf1] = 0x02; + dev->ld_regs[0x05][0xf2] = 0x03; + serial_irq(dev->uart[1], dev->ld_regs[5][0x70]); /* Logical device 6: RTC */ - dev->ld_regs[6][0x30] = 0; - dev->ld_regs[6][0x60] = 0x70; - if (dev->chip_id != 0x02) - dev->ld_regs[6][0x63] = (dev->has_nvr) ? 0x70 : 0x00; - dev->ld_regs[6][0xF0] = 0; - dev->ld_regs[6][0xF4] = 3; + dev->ld_regs[0x06][0x30] = 0x00; + dev->ld_regs[0x06][0x63] = (dev->has_nvr) ? 0x70 : 0x00; + dev->ld_regs[0x06][0xf0] = 0x00; + dev->ld_regs[0x06][0xf4] = 0x03; /* Logical device 7: Keyboard */ - dev->ld_regs[7][0x30] = 0; - dev->ld_regs[7][0x61] = 0x60; - dev->ld_regs[7][0x70] = 1; + dev->ld_regs[0x07][0x30] = 0x00; + dev->ld_regs[0x07][0x61] = 0x60; + dev->ld_regs[0x07][0x70] = 0x01; /* Logical device 8: Auxiliary I/O */ + dev->ld_regs[0x08][0x30] = 0x00; + dev->ld_regs[0x08][0x60] = 0x00; + dev->ld_regs[0x08][0x61] = 0x00; /* Logical device 9: ACCESS.bus */ + dev->ld_regs[0x09][0x30] = 0x00; + dev->ld_regs[0x09][0x60] = 0x00; + dev->ld_regs[0x09][0x61] = 0x00; /* Logical device A: ACPI */ + dev->ld_regs[0x0a][0x30] = 0x00; + dev->ld_regs[0x0a][0x60] = 0x00; + dev->ld_regs[0x0a][0x61] = 0x00; fdc37c93x_gpio_handler(dev); fdc37c93x_lpt_handler(dev); @@ -907,36 +902,6 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->locked = 0; } -static void -access_bus_close(void *priv) -{ - access_bus_t *dev = (access_bus_t *) priv; - - free(dev); -} - -static void * -access_bus_init(UNUSED(const device_t *info)) -{ - access_bus_t *dev = (access_bus_t *) calloc(1, sizeof(access_bus_t)); - - return dev; -} - -static const device_t access_bus_device = { - .name = "SMC FDC37C932FR ACCESS.bus", - .internal_name = "access_bus", - .flags = 0, - .local = 0x03, - .init = access_bus_init, - .close = access_bus_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - static void fdc37c93x_close(void *priv) { @@ -948,19 +913,18 @@ fdc37c93x_close(void *priv) static void * fdc37c93x_init(const device_t *info) { - int is_compaq; fdc37c93x_t *dev = (fdc37c93x_t *) calloc(1, sizeof(fdc37c93x_t)); dev->fdc = device_add(&fdc_at_smc_device); - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->chip_id = info->local & 0xff; - dev->is_apm = (info->local >> 8) & 0x01; - is_compaq = (info->local >> 8) & 0x02; - dev->has_nvr = !((info->local >> 8) & 0x04); - dev->port_370 = ((info->local >> 8) & 0x08); + dev->chip_id = info->local & 0xff; + dev->is_apm = (info->local >> 8) & 0x01; + dev->is_compaq = (info->local >> 8) & 0x02; + dev->has_nvr = !((info->local >> 8) & 0x04); + dev->port_370 = ((info->local >> 8) & 0x08); dev->gpio_regs[0] = 0xff; #if 0 @@ -981,7 +945,7 @@ fdc37c93x_init(const device_t *info) if (dev->is_apm) dev->acpi = device_add(&acpi_smc_device); - if (is_compaq) { + if (dev->is_compaq) { io_sethandler(0x0ea, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); io_sethandler(0x0f9, 0x0001, @@ -992,6 +956,16 @@ fdc37c93x_init(const device_t *info) dev->kbc = device_add(&keyboard_ps2_ami_pci_device); + /* Set the defaults here so the ports can be removed by fdc37c93x_reset(). */ + dev->fdc_base = 0x03f0; + dev->lpt_base = 0x0378; + dev->uart_base[0] = 0x03f8; + dev->uart_base[1] = 0x02f8; + dev->nvr_pri_base = 0x0070; + dev->nvr_sec_base = 0x0070; + dev->kbc_base = 0x0060; + dev->gpio_base = 0x00ea; + fdc37c93x_reset(dev); if (dev->chip_id == 0x02) { @@ -1115,4 +1089,3 @@ const device_t fdc37c935_no_nvr_device = { .force_redraw = NULL, .config = NULL }; - diff --git a/src/sio/sio_fdc37m60x.c b/src/sio/sio_fdc37m60x.c index 671b3581b..11d2f3349 100644 --- a/src/sio/sio_fdc37m60x.c +++ b/src/sio/sio_fdc37m60x.c @@ -216,7 +216,7 @@ fdc37m60x_lpt_handler(fdc37m60x_t *dev) lpt1_remove(); if (ENABLED(3) || (POWER_CONTROL & 0x08)) { - lpt1_init(BASE_ADDRESS(3)); + lpt1_setup(BASE_ADDRESS(3)); lpt1_irq(IRQ(3) & 0xf); fdc37m60x_log("SMC60x-LPT: BASE %04x IRQ %d\n", BASE_ADDRESS(3), IRQ(3) & 0xf); } diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c index 1cde8657e..b3553bf54 100644 --- a/src/sio/sio_it86x1f.c +++ b/src/sio/sio_it86x1f.c @@ -294,7 +294,7 @@ it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { it86x1f_log("IT86x1F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq); - lpt1_init(config->io[0].base); + lpt1_setup(config->io[0].base); } else { it86x1f_log("IT86x1F: LPT disabled\n"); } diff --git a/src/sio/sio_pc87306.c b/src/sio/sio_pc87306.c index 33cb0d865..41d69b0cc 100644 --- a/src/sio/sio_pc87306.c +++ b/src/sio/sio_pc87306.c @@ -154,7 +154,7 @@ lpt1_handler(pc87306_t *dev) lpt_irq = (dev->regs[0x1b] & 0x20) ? 7 : 5; if (lpt_port) - lpt1_init(lpt_port); + lpt1_setup(lpt_port); lpt1_irq(lpt_irq); } @@ -303,26 +303,26 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) } break; case 0x02: - if (valxor & 1) { + if (valxor & 0x01) { lpt1_remove(); - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); + serial_remove(dev->uart[0x00]); + serial_remove(dev->uart[0x01]); fdc_remove(dev->fdc); if (!(val & 1)) { - if (dev->regs[0] & 1) + if (dev->regs[0x00] & 0x01) lpt1_handler(dev); - if (dev->regs[0] & 2) + if (dev->regs[0x00] & 0x02) serial_handler(dev, 0); - if (dev->regs[0] & 4) + if (dev->regs[0x00] & 0x04) serial_handler(dev, 1); - if (dev->regs[0] & 8) - fdc_set_base(dev->fdc, (dev->regs[0] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); + if (dev->regs[0x00] & 0x08) + fdc_set_base(dev->fdc, (dev->regs[0x00] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR); } } - if (valxor & 8) { + if (valxor & 0x08) { lpt1_remove(); - if ((dev->regs[0] & 1) && !(dev->regs[2] & 1)) + if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1)) lpt1_handler(dev); } break; @@ -359,7 +359,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) lpt1_handler(dev); } break; - case 0x1B: + case 0x1b: if (valxor & 0x70) { lpt1_remove(); if (!(val & 0x40)) @@ -368,7 +368,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv) lpt1_handler(dev); } break; - case 0x1C: + case 0x1c: if (valxor) { serial_remove(dev->uart[0]); serial_remove(dev->uart[1]); diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index eba0748c9..ae21d34af 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -200,7 +200,7 @@ lpt1_handler(pc87307_t *dev) irq = (dev->ld_regs[0x04][0x40] & 0x0f); if (active && (addr <= 0xfffc)) { - lpt1_init(addr); + lpt1_setup(addr); lpt1_irq(irq); } } diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 1b790bc6b..da53802c1 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -137,7 +137,7 @@ lpt1_handler(pc87309_t *dev) irq = (dev->ld_regs[0x01][0x40] & 0x0f); if (active) { - lpt1_init(addr); + lpt1_setup(addr); lpt1_irq(irq); } } diff --git a/src/sio/sio_pc87310.c b/src/sio/sio_pc87310.c index 674db6364..5bd595f05 100644 --- a/src/sio/sio_pc87310.c +++ b/src/sio/sio_pc87310.c @@ -106,7 +106,7 @@ lpt1_handler(pc87310_t *dev) } if (lpt_port) - lpt1_init(lpt_port); + lpt1_setup(lpt_port); lpt1_irq(lpt_irq); } diff --git a/src/sio/sio_pc87311.c b/src/sio/sio_pc87311.c index 1f38e6aa8..b560ef425 100644 --- a/src/sio/sio_pc87311.c +++ b/src/sio/sio_pc87311.c @@ -220,7 +220,7 @@ pc87311_lpt_handler(pc87311_t *dev) default: break; } - lpt1_init(dev->base); + lpt1_setup(dev->base); lpt1_irq(dev->irq); pc87311_log("PC87311-LPT: BASE %04x IRQ %01x\n", dev->base, dev->irq); } diff --git a/src/sio/sio_pc87332.c b/src/sio/sio_pc87332.c index f746306bd..d9fb0b211 100644 --- a/src/sio/sio_pc87332.c +++ b/src/sio/sio_pc87332.c @@ -77,7 +77,7 @@ lpt1_handler(pc87332_t *dev) } if (lpt_port) - lpt1_init(lpt_port); + lpt1_setup(lpt_port); lpt1_irq(lpt_irq); } diff --git a/src/sio/sio_prime3b.c b/src/sio/sio_prime3b.c index 2cadda2ab..1cc0be3aa 100644 --- a/src/sio/sio_prime3b.c +++ b/src/sio/sio_prime3b.c @@ -176,7 +176,7 @@ prime3b_lpt_handler(prime3b_t *dev) { uint16_t lpt_base = (ASR & 2) ? LPT_MDA_ADDR : (!(ASR & 1) ? LPT1_ADDR : LPT2_ADDR); lpt1_remove(); - lpt1_init(lpt_base); + lpt1_setup(lpt_base); lpt1_irq(LPT1_IRQ); prime3b_log("Prime3B-LPT: Enabled with base %03x\n", lpt_base); } diff --git a/src/sio/sio_prime3c.c b/src/sio/sio_prime3c.c index e646a3653..f70f9f372 100644 --- a/src/sio/sio_prime3c.c +++ b/src/sio/sio_prime3c.c @@ -241,7 +241,7 @@ prime3c_lpt_handler(prime3c_t *dev) lpt1_remove(); if (!(FUNCTION_SELECT & 0x03)) { - lpt1_init(LPT_BASE_ADDRESS << 2); + lpt1_setup(LPT_BASE_ADDRESS << 2); lpt1_irq(FDC_LPT_IRQ & 0xf); prime3c_log("Prime3C-LPT: BASE %04x IRQ %02x\n", LPT_BASE_ADDRESS << 2, FDC_LPT_IRQ & 0xf); } diff --git a/src/sio/sio_um8663f.c b/src/sio/sio_um8663f.c index 79cb37da4..54f12dda6 100644 --- a/src/sio/sio_um8663f.c +++ b/src/sio/sio_um8663f.c @@ -106,12 +106,12 @@ um8663f_lpt_handler(um8663f_t *dev) if (dev->regs[0] & 0x08) { switch ((dev->regs[1] >> 3) & 0x01) { case 0x01: - lpt1_init(LPT1_ADDR); - lpt1_irq(7); + lpt1_setup(LPT1_ADDR); + lpt1_irq(LPT1_IRQ); break; case 0x00: - lpt1_init(LPT2_ADDR); - lpt1_irq(5); + lpt1_setup(LPT2_ADDR); + lpt1_irq(LPT2_IRQ); break; default: @@ -231,7 +231,7 @@ um8663f_reset(void *priv) serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ); lpt1_remove(); - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); fdc_reset(dev->fdc); fdc_remove(dev->fdc); diff --git a/src/sio/sio_um8669f.c b/src/sio/sio_um8669f.c index b3d5259a2..6da9ef6e9 100644 --- a/src/sio/sio_um8669f.c +++ b/src/sio/sio_um8669f.c @@ -207,7 +207,7 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { um8669f_log("UM8669F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq); - lpt1_init(config->io[0].base); + lpt1_setup(config->io[0].base); } else { um8669f_log("UM8669F: LPT disabled\n"); } diff --git a/src/sio/sio_vt82c686.c b/src/sio/sio_vt82c686.c index fa0bf3c63..0e874210d 100644 --- a/src/sio/sio_vt82c686.c +++ b/src/sio/sio_vt82c686.c @@ -86,7 +86,7 @@ vt82c686_lpt_handler(vt82c686_t *dev) lpt1_remove(); if (((dev->regs[0x02] & 0x03) != 0x03) && !(dev->regs[0x0f] & 0x11) && (io_base >= 0x100) && (io_base <= io_mask)) - lpt1_init(io_base); + lpt1_setup(io_base); if (dev->lpt_irq) { lpt1_irq(dev->lpt_irq); diff --git a/src/sio/sio_w83787f.c b/src/sio/sio_w83787f.c index ea5169afc..f4971ddce 100644 --- a/src/sio/sio_w83787f.c +++ b/src/sio/sio_w83787f.c @@ -197,7 +197,7 @@ w83787f_lpt_handler(w83787f_t *dev) lpt1_remove(); if (enable) { - lpt1_init(addr); + lpt1_setup(addr); lpt1_irq(irq); } } @@ -378,7 +378,7 @@ w83787f_reset(w83787f_t *dev) uint16_t hefere = dev->reg_init & 0x0100; lpt1_remove(); - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); lpt1_irq(LPT1_IRQ); memset(dev->regs, 0, 0x2A); diff --git a/src/sio/sio_w83877f.c b/src/sio/sio_w83877f.c index 90a3dba1b..7c92d6e71 100644 --- a/src/sio/sio_w83877f.c +++ b/src/sio/sio_w83877f.c @@ -168,7 +168,7 @@ w83877f_lpt_handler(w83877f_t *dev) lpt1_remove(); if (!(dev->regs[4] & 0x80) && (dev->regs[0x23] & 0xc0)) - lpt1_init(make_port(dev, 0x23)); + lpt1_setup(make_port(dev, 0x23)); lpt_irq = 0xff; diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index 1d743cc64..fd177bc19 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -112,14 +112,14 @@ w83977f_lpt_handler(w83977f_t *dev) lpt2_remove(); if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask)) - lpt2_init(io_base); + lpt2_setup(io_base); lpt2_irq(dev->dev_regs[1][0x40] & 0x0f); } else { lpt1_remove(); if ((dev->dev_regs[1][0x00] & 0x01) && (dev->regs[0x22] & 0x08) && (io_base >= 0x100) && (io_base <= io_mask)) - lpt1_init(io_base); + lpt1_setup(io_base); lpt1_irq(dev->dev_regs[1][0x40] & 0x0f); } diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index 812a649a8..0462818a0 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -7,10 +7,10 @@ #include "cpu.h" #include <86box/86box.h> #include <86box/filters.h> +#include <86box/timer.h> #include <86box/lpt.h> #include <86box/machine.h> #include <86box/sound.h> -#include <86box/timer.h> #include <86box/plat_unused.h> typedef struct lpt_dac_t { diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index 06160ce4c..875230518 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -7,10 +7,10 @@ #include "cpu.h" #include <86box/86box.h> #include <86box/filters.h> +#include <86box/timer.h> #include <86box/lpt.h> #include <86box/machine.h> #include <86box/sound.h> -#include <86box/timer.h> #include <86box/plat_unused.h> typedef struct dss_t { diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index 958375f4e..6c66175c1 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -14,7 +14,7 @@ * Miran Grca, * * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -357,7 +357,7 @@ colorplus_standalone_init(UNUSED(const device_t *info)) mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); - lpt3_init(0x3BC); + lpt3_setup(LPT_MDA_ADDR); return colorplus; } diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index d50e8ba37..00374d08f 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -14,7 +14,7 @@ * Miran Grca, * * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -585,7 +585,7 @@ hercules_init(UNUSED(const device_t *info)) video_inform(VIDEO_FLAG_TYPE_MDA, &timing_hercules); /* Force the LPT3 port to be enabled. */ - lpt3_init(0x3BC); + lpt3_setup(LPT_MDA_ADDR); return dev; } diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index 99c614259..fb42c3022 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -14,7 +14,7 @@ * Miran Grca, * * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -23,8 +23,8 @@ #include #include <86box/86box.h> #include <86box/io.h> -#include <86box/lpt.h> #include <86box/timer.h> +#include <86box/lpt.h> #include <86box/pit.h> #include <86box/mem.h> #include <86box/rom.h> @@ -670,7 +670,7 @@ herculesplus_init(UNUSED(const device_t *info)) video_inform(VIDEO_FLAG_TYPE_MDA, &timing_herculesplus); /* Force the LPT3 port to be enabled. */ - lpt3_init(0x3BC); + lpt3_setup(LPT_MDA_ADDR); return dev; } diff --git a/src/video/vid_incolor.c b/src/video/vid_incolor.c index 0abb4a6c2..d9b48f43a 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_incolor.c @@ -14,7 +14,7 @@ * Miran Grca, * * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -1018,7 +1018,7 @@ incolor_init(UNUSED(const device_t *info)) video_inform(VIDEO_FLAG_TYPE_MDA, &timing_incolor); /* Force the LPT3 port to be enabled. */ - lpt3_init(0x3BC); + lpt3_setup(LPT_MDA_ADDR); return dev; } diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 975b9ead1..66a0fbb71 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -14,7 +14,7 @@ * Miran Grca, * * Copyright 2008-2019 Sarah Walker. - * Copyright 2016-2019 Miran Grca. + * Copyright 2016-2025 Miran Grca. */ #include #include @@ -322,7 +322,7 @@ mda_standalone_init(UNUSED(const device_t *info)) mda_init(mda); - lpt3_init(0x3BC); + lpt3_setup(LPT_MDA_ADDR); return mda; } From dd24d0329c91fc7415829bb6b642932e5057f6b5 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 21:48:57 -0500 Subject: [PATCH 0218/1190] FIFO tagged functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- src/fifo.c | 137 ++++++++++++++++++++++++++++++++++++++- src/include/86box/fifo.h | 13 ++-- 2 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/fifo.c b/src/fifo.c index f51809fd8..8afb5640f 100644 --- a/src/fifo.c +++ b/src/fifo.c @@ -10,7 +10,7 @@ * * Authors: Miran Grca, * - * Copyright 2023 Miran Grca. + * Copyright 2023-2025 Miran Grca. */ #include #include @@ -84,6 +84,31 @@ fifo_write(uint8_t val, void *priv) } } +void +fifo_write_tagged(uint8_t tag, uint8_t val, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = fifo->d_overrun = 0; + + if (fifo->full) + fifo->overrun = 1; + else { + fifo->buf[fifo->end] = val; + fifo->tag[fifo->end] = tag; + fifo->end = (fifo->end + 1) % fifo->len; + + if (fifo->end == fifo->start) + fifo->full = 1; + + fifo->empty = 0; + + if (fifo_get_count(fifo) >= fifo->trigger_len) + fifo->ready = 1; + } +} + void fifo_write_evt(uint8_t val, void *priv) { @@ -122,6 +147,45 @@ fifo_write_evt(uint8_t val, void *priv) } } +void +fifo_write_evt_tagged(uint8_t tag, uint8_t val, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = fifo->d_overrun = 0; + + if (fifo->full) { + fifo->d_overrun = (fifo->overrun != 1); + fifo->overrun = 1; + if (fifo->d_overrun && (fifo->d_overrun_evt != NULL)) + fifo->d_overrun_evt(fifo->priv); + } else { + fifo->buf[fifo->end] = val; + fifo->tag[fifo->end] = tag; + fifo->end = (fifo->end + 1) % fifo->len; + + if (fifo->end == fifo->start) { + fifo->d_full = (fifo->full != 1); + fifo->full = 1; + if (fifo->d_full && (fifo->d_full_evt != NULL)) + fifo->d_full_evt(fifo->priv); + } + + fifo->d_empty = (fifo->empty != 0); + fifo->empty = 0; + if (fifo->d_empty && (fifo->d_empty_evt != NULL)) + fifo->d_empty_evt(fifo->priv); + + if (fifo_get_count(fifo) >= fifo->trigger_len) { + fifo->d_ready = (fifo->ready != 1); + fifo->ready = 1; + if (fifo->d_ready && (fifo->d_ready_evt != NULL)) + fifo->d_ready_evt(fifo->priv); + } + } +} + uint8_t fifo_read(void *priv) { @@ -148,6 +212,35 @@ fifo_read(void *priv) return ret; } +uint8_t +fifo_read_tagged(uint8_t *tag, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + uint8_t ret = 0x00; + int count; + + if (!fifo->empty) { + ret = fifo->buf[fifo->start]; + *tag = fifo->tag[fifo->start]; + + fifo->start = (fifo->start + 1) % fifo->len; + + fifo->full = 0; + + count = fifo_get_count(fifo); + + if (count < fifo->trigger_len) { + fifo->ready = 0; + + if (count == 0) + fifo->empty = 1; + } + } else + *tag = 0x00; + + return ret; +} + uint8_t fifo_read_evt(void *priv) { @@ -187,6 +280,48 @@ fifo_read_evt(void *priv) return ret; } +uint8_t +fifo_read_evt_tagged(uint8_t *tag, void *priv) +{ + fifo_t *fifo = (fifo_t *) priv; + uint8_t ret = 0x00; + int count; + + fifo->d_full = fifo->d_empty = 0; + fifo->d_ready = 0; + + if (!fifo->empty) { + ret = fifo->buf[fifo->start]; + *tag = fifo->tag[fifo->start]; + + fifo->start = (fifo->start + 1) % fifo->len; + + fifo->d_full = (fifo->full != 0); + fifo->full = 0; + if (fifo->d_full && (fifo->d_full_evt != NULL)) + fifo->d_full_evt(fifo->priv); + + count = fifo_get_count(fifo); + + if (count < fifo->trigger_len) { + fifo->d_ready = (fifo->ready != 0); + fifo->ready = 0; + if (fifo->d_ready && (fifo->d_ready_evt != NULL)) + fifo->d_ready_evt(fifo->priv); + + if (count == 0) { + fifo->d_empty = (fifo->empty != 1); + fifo->empty = 1; + if (fifo->d_empty && (fifo->d_empty_evt != NULL)) + fifo->d_empty_evt(fifo->priv); + } + } + } else + *tag = 0x00; + + return ret; +} + void fifo_clear_overrun(void *priv) { diff --git a/src/include/86box/fifo.h b/src/include/86box/fifo.h index f87f932e0..f8f07d9b5 100644 --- a/src/include/86box/fifo.h +++ b/src/include/86box/fifo.h @@ -1,6 +1,3 @@ -#ifndef FIFO_H -#define FIFO_H - /* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM @@ -13,8 +10,11 @@ * * Authors: Miran Grca, * - * Copyright 2023 Miran Grca. + * Copyright 2023-2025 Miran Grca. */ +#ifndef FIFO_H +#define FIFO_H + #define FIFO(size) \ typedef struct { \ int start; \ @@ -37,6 +37,7 @@ void (*d_full_evt)(void *); \ void (*d_ready_evt)(void *); \ \ + uint8_t tag[64]; \ uint8_t buf[size]; \ } fifo## size ##_t; @@ -50,9 +51,13 @@ FIFO(64) extern int fifo_get_count(void *priv); extern void fifo_write(uint8_t val, void *priv); +extern void fifo_write_tagged(uint8_t tag, uint8_t val, void *priv); extern void fifo_write_evt(uint8_t val, void *priv); +extern void fifo_write_evt_tagged(uint8_t tag, uint8_t val, void *priv); extern uint8_t fifo_read(void *priv); +extern uint8_t fifo_read_tagged(uint8_t *tag, void *priv); extern uint8_t fifo_read_evt(void *priv); +extern uint8_t fifo_read_evt_tagged(uint8_t *tag, void *priv); extern void fifo_clear_overrun(void *priv); extern int fifo_get_full(void *priv); extern int fifo_get_d_full(void *priv); From 370481ceed0920bc7993a1334c1e51068ee283a0 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 22:29:56 -0500 Subject: [PATCH 0219/1190] Serial IRQ function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- src/device/serial.c | 16 +++++++++++++++- src/include/86box/serial.h | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/device/serial.c b/src/device/serial.c index 0ba60551c..823d07c1f 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -15,7 +15,7 @@ * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2025 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. */ #include @@ -782,6 +782,20 @@ serial_setup(serial_t *dev, uint16_t addr, uint8_t irq) dev->irq = irq; } +void +serial_irq(serial_t *dev, const uint8_t irq) +{ + if (dev == NULL) + return; + + if (com_ports[dev->inst].enabled) + dev->irq = irq; + else + dev->irq = 0xff; + + serial_log("Port %i IRQ = %02X\n", dev->inst, irq); +} + static void serial_rcvr_d_empty_evt(void *priv) { diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index a205c7cec..31c77ce5a 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -16,7 +16,7 @@ * Fred N. van Kempen, * * Copyright 2008-2020 Sarah Walker. - * Copyright 2016-2020 Miran Grca. + * Copyright 2016-2025 Miran Grca. * Copyright 2017-2020 Fred N. van Kempen. */ @@ -137,6 +137,7 @@ extern serial_t *serial_attach_ex_2(int port, extern void serial_remove(serial_t *dev); extern void serial_set_type(serial_t *dev, int type); extern void serial_setup(serial_t *dev, uint16_t addr, uint8_t irq); +extern void serial_irq(serial_t *dev, uint8_t irq); extern void serial_clear_fifo(serial_t *dev); extern void serial_write_fifo(serial_t *dev, uint8_t dat); extern void serial_set_next_inst(int ni); From e592ab5505766311cb4165df45dbd60ba238f002 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 22:32:50 -0500 Subject: [PATCH 0220/1190] ACCESS.bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- src/device/CMakeLists.txt | 1 + src/device/access_bus.c | 122 +++++++++++++++++++++++++++++++++ src/include/86box/access_bus.h | 37 ++++++++++ 3 files changed, 160 insertions(+) create mode 100644 src/device/access_bus.c create mode 100644 src/include/86box/access_bus.h diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 678c700a5..bbbab22fd 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -17,6 +17,7 @@ # add_library(dev OBJECT + access_bus.c bugger.c cartridge.c cassette.c diff --git a/src/device/access_bus.c b/src/device/access_bus.c new file mode 100644 index 000000000..951454e19 --- /dev/null +++ b/src/device/access_bus.c @@ -0,0 +1,122 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ACCESS.bus. + * + * Authors: Miran Grca, + * + * Copyright 2024-2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/access_bus.h> +#include <86box/plat_unused.h> + +static uint8_t +access_bus_in(uint16_t port, void *priv) +{ + const access_bus_t *dev = (access_bus_t *) priv; + uint8_t ret = 0xff; + + switch (port & 3) { + case 0: + ret = (dev->status & 0xbf); + break; + case 1: + ret = (dev->own_addr & 0x7f); + break; + case 2: + ret = dev->data; + break; + case 3: + ret = (dev->clock & 0x87); + break; + + default: + break; + } + + return ret; +} + +static void +access_bus_out(uint16_t port, uint8_t val, void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + switch (port & 3) { + case 0: + dev->control = (val & 0xcf); + break; + case 1: + dev->own_addr = (val & 0x7f); + break; + case 2: + dev->data = val; + break; + case 3: + dev->clock &= 0x80; + dev->clock |= (val & 0x07); + break; + + default: + break; + } +} + +void +access_bus_handler(access_bus_t *dev, uint8_t enable, uint16_t base) +{ + if (dev->enable && (dev->base >= 0x0100) && (dev->base <= 0x0ffc)) + io_removehandler(dev->base, 0x0004, + access_bus_in, NULL, NULL, access_bus_out, NULL, NULL, dev); + + dev->enable = enable; + dev->base = base; + + if (dev->enable && (dev->base >= 0x0100) && (dev->base <= 0x0ffc)) + io_sethandler(dev->base, 0x0004, + access_bus_in, NULL, NULL, access_bus_out, NULL, NULL, dev); +} + + +static void +access_bus_close(void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + free(dev); +} + +static void * +access_bus_init(UNUSED(const device_t *info)) +{ + access_bus_t *dev = (access_bus_t *) calloc(1, sizeof(access_bus_t)); + + return dev; +} + +const device_t access_bus_device = { + .name = "ACCESS.bus", + .internal_name = "access_bus", + .flags = 0, + .local = 0, + .init = access_bus_init, + .close = access_bus_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/access_bus.h b/src/include/86box/access_bus.h new file mode 100644 index 000000000..333a1d4a5 --- /dev/null +++ b/src/include/86box/access_bus.h @@ -0,0 +1,37 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the ACPI emulation. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2020-2025 Miran Grca. + */ +#ifndef ACCESS_BUS_H +#define ACCESS_BUS_H + +#define AB_RST 0x80 + +typedef struct access_bus_t { + uint8_t control; + uint8_t status; + uint8_t own_addr; + uint8_t data; + uint8_t clock; + uint8_t enable; + uint16_t base; +} access_bus_t; + +extern const device_t access_bus_device; + +/* Functions */ +extern void access_bus_handler(access_bus_t *dev, uint8_t enable, uint16_t base); + +#endif /*ACCESS_BUS_H*/ From a4fd6a0895acf6938eb9f1e9067544193d94cab5 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Feb 2025 23:47:24 -0500 Subject: [PATCH 0221/1190] Seperate Socket 3 and Socket 3 PCI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Miran Grča --- src/include/86box/machine.h | 65 ++++++++++++++++--------------- src/machine/machine_table.c | 77 +++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index f4f3f8834..f39187dd9 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -173,20 +173,21 @@ enum { MACHINE_TYPE_486 = 8, MACHINE_TYPE_486_S2 = 9, MACHINE_TYPE_486_S3 = 10, - MACHINE_TYPE_486_MISC = 11, - MACHINE_TYPE_SOCKET4 = 12, - MACHINE_TYPE_SOCKET5 = 13, - MACHINE_TYPE_SOCKET7_3V = 14, - MACHINE_TYPE_SOCKET7 = 15, - MACHINE_TYPE_SOCKETS7 = 16, - MACHINE_TYPE_SOCKET8 = 17, - MACHINE_TYPE_SLOT1 = 18, - MACHINE_TYPE_SLOT1_2 = 19, - MACHINE_TYPE_SLOT1_370 = 20, - MACHINE_TYPE_SLOT2 = 21, - MACHINE_TYPE_SOCKET370 = 22, - MACHINE_TYPE_MISC = 23, - MACHINE_TYPE_MAX = 24 + MACHINE_TYPE_486_S3_PCI = 11, + MACHINE_TYPE_486_MISC = 12, + MACHINE_TYPE_SOCKET4 = 13, + MACHINE_TYPE_SOCKET5 = 14, + MACHINE_TYPE_SOCKET7_3V = 15, + MACHINE_TYPE_SOCKET7 = 16, + MACHINE_TYPE_SOCKETS7 = 17, + MACHINE_TYPE_SOCKET8 = 18, + MACHINE_TYPE_SLOT1 = 19, + MACHINE_TYPE_SLOT1_2 = 20, + MACHINE_TYPE_SLOT1_370 = 21, + MACHINE_TYPE_SLOT2 = 22, + MACHINE_TYPE_SOCKET370 = 23, + MACHINE_TYPE_MISC = 24, + MACHINE_TYPE_MAX = 25 }; enum { @@ -320,27 +321,29 @@ typedef struct _machine_ { int ram_granularity; int nvrmask; #ifdef EMU_DEVICE_H - const device_t *kbc_device; + const device_t *kbc_device; #else - void *kbc_device; + void *kbc_device; #endif /* EMU_DEVICE_H */ - uint8_t kbc_p1; - uint32_t gpio; - uint32_t gpio_acpi; + uintptr_t kbc_params; + /* Bits 23-16: XOR mask, bits 15-8: OR mask, bits 7-0: AND mask. */ + uint32_t kbc_p1; + uint32_t gpio; + uint32_t gpio_acpi; #ifdef EMU_DEVICE_H - const device_t *device; - const device_t *fdc_device; - const device_t *sio_device; - const device_t *vid_device; - const device_t *snd_device; - const device_t *net_device; + const device_t *device; + const device_t *fdc_device; + const device_t *sio_device; + const device_t *vid_device; + const device_t *snd_device; + const device_t *net_device; #else - void *device; - void *fdc_device; - void *sio_device; - void *vid_device; - void *snd_device; - void *net_device; + void *device; + void *fdc_device; + void *sio_device; + void *vid_device; + void *snd_device; + void *net_device; #endif } machine_t; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index febdc0e0c..f5cc30782 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -31,12 +31,14 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/machine.h> +#include <86box/timer.h> +#include <86box/fdd.h> +#include <86box/fdc.h> #include <86box/keyboard.h> #include <86box/sound.h> #include <86box/video.h> #include <86box/plat_unused.h> #include <86box/thread.h> -#include <86box/timer.h> #include <86box/network.h> // Temporarily here till we move everything out into the right files @@ -79,6 +81,7 @@ const machine_filter_t machine_types[] = { { "[1992] i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, { "[1992] i486 (Socket 2)", MACHINE_TYPE_486_S2 }, { "[1994] i486 (Socket 3)", MACHINE_TYPE_486_S3 }, + { "[1994] i486 (Socket 3 PCI)", MACHINE_TYPE_486_S3_PCI }, { "[1992] i486 (Miscellaneous)", MACHINE_TYPE_486_MISC }, { "[1993] Socket 4", MACHINE_TYPE_SOCKET4 }, { "[1994] Socket 5", MACHINE_TYPE_SOCKET5 }, @@ -7427,7 +7430,7 @@ const machine_t machines[] = { { .name = "[ALi M1429G] TriGem 486GP", .internal_name = "tg486gp", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1429G, .init = machine_at_tg486gp_init, .p1_handler = NULL, @@ -7467,7 +7470,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] AAEON SBC-490", .internal_name = "sbc490", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_sbc490_init, .p1_handler = NULL, @@ -7508,7 +7511,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] ABIT AB-PB4", .internal_name = "abpb4", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_abpb4_init, .p1_handler = NULL, @@ -7596,7 +7599,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] MSI MS-4145", .internal_name = "ms4145", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_ms4145_init, .p1_handler = NULL, @@ -7636,7 +7639,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] ESA TF-486", .internal_name = "tf486", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_tf486_init, .p1_handler = NULL, @@ -7676,7 +7679,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] Acrosser AR-B1476", .internal_name = "arb1476", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_arb1476_init, .p1_handler = NULL, @@ -7716,7 +7719,7 @@ const machine_t machines[] = { { .name = "[OPTi 802G] IBM Aptiva 510/710/Vision", .internal_name = "aptiva510", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_OPTI_895_802G, .init = machine_at_aptiva510_init, .p1_handler = NULL, @@ -7756,7 +7759,7 @@ const machine_t machines[] = { { .name = "[OPTi 802G] IBM PC 330 (type 6573)", .internal_name = "pc330_6573", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_OPTI_895_802G, .init = machine_at_pc330_6573_init, .p1_handler = NULL, @@ -7796,7 +7799,7 @@ const machine_t machines[] = { { .name = "[i420EX] ASUS PVI-486AP4", .internal_name = "486ap4", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420EX, .init = machine_at_486ap4_init, .p1_handler = NULL, @@ -7836,7 +7839,7 @@ const machine_t machines[] = { { .name = "[i420EX] Intel Classic/PCI ED", .internal_name = "ninja", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420EX, .init = machine_at_ninja_init, .p1_handler = NULL, @@ -7876,7 +7879,7 @@ const machine_t machines[] = { { .name = "[i420EX] Anigma BAT4IP3e", .internal_name = "bat4ip3e", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420EX, .init = machine_at_bat4ip3e_init, .p1_handler = NULL, @@ -7916,7 +7919,7 @@ const machine_t machines[] = { { .name = "[i420EX] Advanced Integration Research 486PI", .internal_name = "486pi", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420EX, .init = machine_at_486pi_init, .p1_handler = NULL, @@ -7956,7 +7959,7 @@ const machine_t machines[] = { { .name = "[i420EX] ICS SB486P", .internal_name = "sb486p", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420EX, .init = machine_at_sb486p_init, .p1_handler = NULL, @@ -7996,7 +7999,7 @@ const machine_t machines[] = { { .name = "[i420TX] ASUS PCI/I-486SP3", .internal_name = "486sp3", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420TX, .init = machine_at_486sp3_init, .p1_handler = NULL, @@ -8036,7 +8039,7 @@ const machine_t machines[] = { { .name = "[i420TX] Intel Classic/PCI", .internal_name = "alfredo", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420TX, .init = machine_at_alfredo_init, .p1_handler = NULL, @@ -8076,7 +8079,7 @@ const machine_t machines[] = { { .name = "[i420TX] AMI Super Voyager PCI", .internal_name = "amis76", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420TX, .init = machine_at_amis76_init, .p1_handler = NULL, @@ -8117,7 +8120,7 @@ const machine_t machines[] = { { .name = "[i420ZX] ASUS PCI/I-486SP3G", .internal_name = "486sp3g", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_INTEL_420ZX, .init = machine_at_486sp3g_init, .p1_handler = NULL, @@ -8157,7 +8160,7 @@ const machine_t machines[] = { { .name = "[IMS 8848] J-Bond PCI400C-B", .internal_name = "pci400cb", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_IMS_8848, .init = machine_at_pci400cb_init, .p1_handler = NULL, @@ -8197,7 +8200,7 @@ const machine_t machines[] = { { .name = "[SiS 496] ASUS PVI-486SP3C", .internal_name = "486sp3c", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_486sp3c_init, .p1_handler = NULL, @@ -8237,7 +8240,7 @@ const machine_t machines[] = { { .name = "[SiS 496] Lucky Star LS-486E", .internal_name = "ls486e", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_ls486e_init, .p1_handler = NULL, @@ -8277,7 +8280,7 @@ const machine_t machines[] = { { .name = "[SiS 496] Micronics M4Li", .internal_name = "m4li", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_m4li_init, .p1_handler = NULL, @@ -8317,7 +8320,7 @@ const machine_t machines[] = { { .name = "[SiS 496] Rise Computer R418", .internal_name = "r418", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_r418_init, .p1_handler = NULL, @@ -8358,7 +8361,7 @@ const machine_t machines[] = { { .name = "[SiS 496] Soyo 4SAW2", .internal_name = "4saw2", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_4saw2_init, .p1_handler = NULL, @@ -8399,7 +8402,7 @@ const machine_t machines[] = { { .name = "[SiS 496] Zida Tomato 4DP", .internal_name = "4dps", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_4dps_init, .p1_handler = NULL, @@ -8439,7 +8442,7 @@ const machine_t machines[] = { { .name = "[SiS 496] MSI MS-4144", .internal_name = "ms4144", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_SIS_496, .init = machine_at_ms4144_init, .p1_handler = NULL, @@ -8479,7 +8482,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] A-Trend ATC-1415", .internal_name = "atc1415", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_atc1415_init, .p1_handler = NULL, @@ -8519,7 +8522,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] ECS Elite UM8810P-AIO", .internal_name = "ecs486", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_ecs486_init, .p1_handler = NULL, @@ -8559,7 +8562,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] Epson ActionPC 2600", .internal_name = "actionpc2600", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_actionpc2600_init, .p1_handler = NULL, @@ -8600,7 +8603,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] Epson ActionTower 8400", .internal_name = "actiontower8400", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_actiontower8400_init, .p1_handler = NULL, @@ -8641,7 +8644,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] PC Chips M919", .internal_name = "m919", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_m919_init, .p1_handler = NULL, @@ -8681,7 +8684,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] Samsung SPC7700P-LW", .internal_name = "spc7700plw", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_spc7700plw_init, .p1_handler = NULL, @@ -8721,7 +8724,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] Shuttle HOT-433A", .internal_name = "hot433a", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_hot433a_init, .p1_handler = NULL, @@ -8802,7 +8805,7 @@ const machine_t machines[] = { { .name = "[VIA VT82C496G] DFI G486VPA", .internal_name = "g486vpa", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_VIA_VT82C496G, .init = machine_at_g486vpa_init, .p1_handler = NULL, @@ -8842,7 +8845,7 @@ const machine_t machines[] = { { .name = "[VIA VT82C496G] FIC VIP-IO2", .internal_name = "486vipio2", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_VIA_VT82C496G, .init = machine_at_486vipio2_init, .p1_handler = NULL, @@ -16222,8 +16225,8 @@ const machine_t machines[] = { /* Saved copies - jumpers get applied to these. We use also machine_gpio to store IBM PC/XT jumpers as they need more than one byte. */ -static uint8_t machine_p1_default; -static uint8_t machine_p1; +static uint32_t machine_p1_default; +static uint32_t machine_p1; static uint32_t machine_gpio_default; static uint32_t machine_gpio; From 729e8080b6b886effa4068d64c35f2ee049e302d Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Feb 2025 12:59:08 -0500 Subject: [PATCH 0222/1190] More Socket 3 PCI --- src/machine/machine_table.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f5cc30782..458b54013 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6865,7 +6865,7 @@ const machine_t machines[] = { { .name = "[OPTi 895] Packard Bell PB450", .internal_name = "pb450", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_OPTI_895_802G, .init = machine_at_pb450_init, .p1_handler = NULL, @@ -7390,7 +7390,7 @@ const machine_t machines[] = { { .name = "[ALi M1429G] MSI MS-4134", .internal_name = "ms4134", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1429G, .init = machine_at_ms4134_init, .p1_handler = NULL, @@ -7555,7 +7555,7 @@ const machine_t machines[] = { { .name = "[ALi M1489] AMI WinBIOS 486 PCI", .internal_name = "win486pci", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_ALI_M1489, .init = machine_at_win486pci_init, .p1_handler = NULL, @@ -8765,7 +8765,7 @@ const machine_t machines[] = { { .name = "[UMC 8881] Compaq Presario 7100/7200 Series 486", .internal_name = "pl4600c", - .type = MACHINE_TYPE_486_S3, + .type = MACHINE_TYPE_486_S3_PCI, .chipset = MACHINE_CHIPSET_UMC_UM8881, .init = machine_at_pl4600c_init, .p1_handler = NULL, From 74e04082017b35e284be40de36be45878baa8430 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Feb 2025 20:06:15 +0100 Subject: [PATCH 0223/1190] Current WIP CD-ROM changes. --- src/cdrom/cdrom.c | 692 +++++++++++++++++++------------- src/cdrom/cdrom_image.c | 2 +- src/disk/hdc_ide.c | 196 ++++++--- src/disk/hdc_ide_sff8038i.c | 2 +- src/include/86box/cdrom.h | 62 +-- src/include/86box/device.h | 29 +- src/include/86box/hdc_ide.h | 2 + src/include/86box/hdd.h | 86 ++-- src/include/86box/mo.h | 9 +- src/include/86box/scsi_cdrom.h | 16 +- src/include/86box/scsi_device.h | 28 +- src/include/86box/scsi_disk.h | 1 + src/include/86box/zip.h | 1 + src/qt/qt_winrawinputfilter.cpp | 1 + src/qt/win_cdrom_ioctl.c | 14 + src/scsi/scsi_cdrom.c | 646 ++++++++++++++++++----------- src/sound/sound.c | 150 +++---- 17 files changed, 1201 insertions(+), 736 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 2cdcc5a22..9e6c57e70 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -89,8 +89,10 @@ static char * cdrom_modes[4] = { "Mode 1", "Mode 2", "CD-I/ static uint8_t cdrom_mode_masks[14] = { 0x0f, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x05, 0x05, 0x04, 0x04, 0x0c, 0x0c }; -static uint8_t status_codes[2][8] = { { 0x13, 0x15, 0x15, 0x15, 0x12, 0x11, 0x13, 0x13 }, - { 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00 } }; +static uint8_t status_codes[2][16] = { { 0x13, 0x15, 0x15, 0x15, 0x12, 0x11, 0x13, 0x13, + 0x12, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15 }, + { 0x00, 0x00, 0x00, 0x00, 0x15, 0x11, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; static int mult = 1; static int part = 0; static int ecc_diff = 288; @@ -122,7 +124,7 @@ static const struct { static void cdrom_generate_name(const int type, char *name, const int internal) { - char elements[3][2048] = { 0 }; + char elements[3][512] = { 0 }; memcpy(elements[0], cdrom_drive_types[type].vendor, strlen(cdrom_drive_types[type].vendor) + 1); @@ -286,32 +288,39 @@ msf_to_bcd(int *m, int *s, int *f) static int read_data(cdrom_t *dev, const uint32_t lba) { - return dev->ops->read_sector(dev->local, dev->raw_buffer, lba); + int ret = 1; + + if (dev->cached_sector != lba) { + dev->cached_sector = lba; + + ret = dev->ops->read_sector(dev->local, + dev->raw_buffer[dev->cur_buf ^ 1], lba); + + if (ret <= 0) { + memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2448); + dev->cached_sector = -1; + } + + dev->cur_buf ^= 1; + } + + return ret; } static void cdrom_get_subchannel(cdrom_t *dev, const uint32_t lba, subchannel_t *subc, const int cooked) { - const uint8_t *scb; - uint32_t scb_offs = 0; uint8_t q[16] = { 0 }; + if (lba != dev->cached_sector) + dev->cached_sector = -1; - if ((lba == dev->seek_pos) && - ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))) - scb = dev->subch_buffer; - else { - scb = (const uint8_t *) dev->raw_buffer; - scb_offs = 2352; - - memset(dev->raw_buffer, 0, 2448); - - (void) read_data(dev, lba); - } + (void) read_data(dev, lba); for (int i = 0; i < 12; i++) for (int j = 0; j < 8; j++) - q[i] |= ((scb[scb_offs + (i << 3) + j] >> 6) & 0x01) << (7 - j); + q[i] |= ((dev->raw_buffer[dev->cur_buf][RAW_SECTOR_SIZE + + (i << 3) + j] >> 6) & 0x01) << (7 - j); if (cooked) { uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); @@ -406,7 +415,7 @@ find_specific_track(const raw_track_info_t *trti, const int num, const int track static int read_toc_normal(const cdrom_t *dev, unsigned char *b, - const unsigned char start_track, const int msf, + unsigned char start_track, const int msf, const int sony) { uint8_t rti[65536] = { 0 }; @@ -417,8 +426,13 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, int len = 4; int t = -1; - cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i)\n", + if ((dev->is_bcd || dev->is_chinon) && (start_track < 0xa0)) + start_track = bcd2bin(start_track); + + cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); + pclog("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", + (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); dev->ops->get_raw_track_info(dev->local, &num, rti); @@ -458,7 +472,11 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, if (!sony) b[len++] = 0; /* Reserved */ b[len++] = tprti[i].adr_ctl; /* ADR/CTL */ - b[len++] = tprti[i].point; /* Track number */ + if ((dev->is_bcd || dev->is_chinon) && (tprti[i].point >= 1) && + (tprti[i].point <= 99)) + b[len++] = bin2bcd(tprti[i].point); /* Track number */ + else + b[len++] = tprti[i].point; /* Track number */ if (!sony) b[len++] = 0; /* Reserved */ @@ -466,7 +484,7 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, b[len++] = 0; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { int m = tprti[i].pm; int s = tprti[i].ps; int f = tprti[i].pf; @@ -527,14 +545,18 @@ read_toc_session(const cdrom_t *dev, unsigned char *b, const int msf) if (first != NULL) { b[len++] = 0x00; b[len++] = first->adr_ctl; - b[len++] = first->point; + if ((dev->is_bcd || dev->is_chinon) && (first->point >= 1) && + (first->point <= 99)) + b[len++] = bin2bcd(first->point); + else + b[len++] = first->point; b[len++] = 0x00; if (msf) { b[len++] = 0x00; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { int m = first->pm; int s = first->ps; int f = first->pf; @@ -586,6 +608,16 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra if (num != 0) for (int i = 0; i < num; i++) if (t[i].session >= start_track) { memcpy(&(b[len]), &(t[i]), 11); + + if ((dev->is_bcd || dev->is_chinon) && (b[3] >= 1) && (b[3] <= 99)) + b[3] = bin2bcd(b[3]); + + for (int j = 0; j < 3; j++) + if (dev->is_bcd) { + b[4 + j] = bin2bcd(b[4 + j]); + b[8 + j] = bin2bcd(b[8 + j]); + } + len += 11; } @@ -642,9 +674,9 @@ track_type_is_valid(UNUSED(const cdrom_t *dev), const int type, const int flags, static int read_audio(cdrom_t *dev, const uint32_t lba, uint8_t *b) { - const int ret = dev->ops->read_sector(dev->local, dev->raw_buffer, lba); + const int ret = read_data(dev, lba); - memcpy(b, dev->raw_buffer, 2352); + memcpy(b, dev->raw_buffer[dev->cur_buf], 2352); dev->cdrom_sector_size = 2352; @@ -660,7 +692,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 1] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -668,7 +700,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 1] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -678,7 +710,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (!(cdrom_sector_flags & 0x10)) { /* No user data */ cdrom_log(dev->log, "[Mode 1] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -688,12 +720,12 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) /* User data */ cdrom_log(dev->log, "[Mode 1] User data\n"); if (mult > 1) { - memcpy(b, dev->raw_buffer + 16 + (part * dev->sector_size), - dev->sector_size); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16 + + (part * dev->sector_size), dev->sector_size); dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, dev->raw_buffer + 16, 2048); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 2048); dev->cdrom_sector_size += 2048; b += 2048; } @@ -702,7 +734,7 @@ process_mode1(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[Mode 1] EDC/ECC\n"); - memcpy(b, dev->raw_buffer + 2064, (288 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 2064, (288 - ecc_diff)); dev->cdrom_sector_size += (288 - ecc_diff); } } @@ -716,7 +748,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[Mode 2 Formless] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -724,7 +756,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[Mode 2 Formless] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -733,7 +765,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[Mode 2 Formless] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -741,7 +773,7 @@ process_mode2_non_xa(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[Mode 2 Formless] User data\n"); - memcpy(b, dev->raw_buffer + 24, (2336 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, (2336 - ecc_diff)); dev->cdrom_sector_size += (2336 - ecc_diff); } } @@ -755,7 +787,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -763,7 +795,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -771,7 +803,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 1] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -780,12 +812,12 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 1] User data\n"); if (mult > 1) { - memcpy(b, dev->raw_buffer + 24 + (part * dev->sector_size), - dev->sector_size); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24 + + (part * dev->sector_size), dev->sector_size); dev->cdrom_sector_size += dev->sector_size; b += dev->sector_size; } else { - memcpy(b, dev->raw_buffer + 24, 2048); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, 2048); dev->cdrom_sector_size += 2048; b += 2048; } @@ -794,7 +826,7 @@ process_mode2_xa_form1(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ cdrom_log(dev->log, "[XA Mode 2 Form 1] EDC/ECC\n"); - memcpy(b, dev->raw_buffer + 2072, (280 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 2072, (280 - ecc_diff)); dev->cdrom_sector_size += (280 - ecc_diff); } } @@ -808,7 +840,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x80) { /* Sync */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sync\n"); - memcpy(b, dev->raw_buffer, 12); + memcpy(b, dev->raw_buffer[dev->cur_buf], 12); dev->cdrom_sector_size += 12; b += 12; } @@ -816,7 +848,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x20) { /* Header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Header\n"); - memcpy(b, dev->raw_buffer + 12, 4); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 12, 4); dev->cdrom_sector_size += 4; b += 4; } @@ -824,7 +856,7 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x40) { /* Sub-header */ cdrom_log(dev->log, "[XA Mode 2 Form 2] Sub-header\n"); - memcpy(b, dev->raw_buffer + 16, 8); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 16, 8); dev->cdrom_sector_size += 8; b += 8; } @@ -832,14 +864,14 @@ process_mode2_xa_form2(cdrom_t *dev, const int cdrom_sector_flags, if (cdrom_sector_flags & 0x10) { /* User data */ cdrom_log(dev->log, "[XA Mode 2 Form 2] User data\n"); - memcpy(b, dev->raw_buffer + 24, (2328 - ecc_diff)); + memcpy(b, dev->raw_buffer[dev->cur_buf] + 24, + (2328 - ecc_diff)); dev->cdrom_sector_size += (2328 - ecc_diff); } } static void -process_ecc_and_subch(cdrom_t *dev, const int cdrom_sector_flags, - uint8_t *b) +process_c2(cdrom_t *dev, const int cdrom_sector_flags, uint8_t *b) { if ((cdrom_sector_flags & 0x06) == 0x02) { /* Add error flags. */ @@ -851,31 +883,65 @@ process_ecc_and_subch(cdrom_t *dev, const int cdrom_sector_flags, cdrom_log(dev->log, "Full error flags\n"); memcpy(b + dev->cdrom_sector_size, dev->extra_buffer, 296); dev->cdrom_sector_size += 296; - } + } +} + +static void +cdrom_deinterleave_subch(uint8_t *d, const uint8_t *s) +{ + for (int i = 0; i < 8 * 12; i++) { + int dmask = 0x80; + int smask = 1 << (7 - (i / 12)); + + (*d) = 0; + + for (int j = 0; j < 8; j++) { + (*d) |= (s[(i % 12) * 8 + j] & smask) ? dmask : 0; + dmask >>= 1; + } + + d++; + } +} + +static void +process_c2_and_subch(cdrom_t *dev, const int cdrom_sector_flags, + uint8_t *b) +{ + if (dev->c2_first) + process_c2(dev, cdrom_sector_flags, b); if ((cdrom_sector_flags & 0x700) == 0x100) { cdrom_log(dev->log, "Raw subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer[dev->cur_buf] + + 2352, 96); dev->cdrom_sector_size += 96; } else if ((cdrom_sector_flags & 0x700) == 0x200) { cdrom_log(dev->log, "Q subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 16); + memcpy(b + dev->cdrom_sector_size, dev->raw_buffer[dev->cur_buf] + + 2352, 16); dev->cdrom_sector_size += 16; } else if ((cdrom_sector_flags & 0x700) == 0x400) { cdrom_log(dev->log, "R/W subchannel data\n"); - memcpy(b + dev->cdrom_sector_size, dev->raw_buffer + 2352, 96); + cdrom_deinterleave_subch(b + dev->cdrom_sector_size, + dev->raw_buffer[dev->cur_buf] + 2352); dev->cdrom_sector_size += 96; } + + if (!dev->c2_first) + process_c2(dev, cdrom_sector_flags, b); } static void cdrom_drive_reset(cdrom_t *dev) { - dev->priv = NULL; - dev->insert = NULL; - dev->close = NULL; - dev->get_volume = NULL; - dev->get_channel = NULL; + dev->priv = NULL; + dev->insert = NULL; + dev->close = NULL; + dev->get_volume = NULL; + dev->get_channel = NULL; + + dev->cached_sector = -1; if (cdrom_drive_types[dev->type].speed == -1) dev->real_speed = dev->speed; @@ -890,7 +956,8 @@ cdrom_unload(cdrom_t *dev) cdrom_log(dev->log, "CDROM: cdrom_unload(%s)\n", dev->image_path); } - dev->cd_status = CD_STATUS_EMPTY; + dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; if (dev->local != NULL) { dev->ops->close(dev->local); @@ -900,6 +967,39 @@ cdrom_unload(cdrom_t *dev) dev->ops = NULL; } +#ifdef ENABLE_CDROM_LOG +static void +cdrom_toc_dump(cdrom_t *dev) +{ + uint8_t b[65536] = { 0 }; + int len = cdrom_read_toc(dev, b, CD_TOC_RAW, 0, 0, 65536); + const char *fn2 = "d:\\86boxnew\\toc_cue.dmp"; + FILE * f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_session.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2); +} +#endif + /* Reset the CD-ROM Interface, whichever one that is. */ void cdrom_interface_reset(void) @@ -1001,24 +1101,6 @@ cdrom_is_generic(const int type) return (cdrom_drive_types[type].speed == -1); } -int -cdrom_has_date(const int type) -{ - /* This will do for now. */ - return !strcmp(cdrom_drive_types[type].vendor, "PIONEER"); -} - -int -cdrom_is_sony(const int type) -{ - /* This will do for now. */ - return (cdrom_drive_types[type].bus_type == BUS_TYPE_SCSI) && - (!strcmp(cdrom_drive_types[type].vendor, "DEC") || - !strcmp(cdrom_drive_types[type].vendor, "ShinaKen") || - !strcmp(cdrom_drive_types[type].vendor, "SONY") || - !strcmp(cdrom_drive_types[type].vendor, "TEXEL")); -} - int cdrom_is_caddy(const int type) { @@ -1067,7 +1149,7 @@ cdrom_get_type_count(void) void cdrom_get_identify_model(const int type, char *name, const int id) { - char elements[2][2048] = { 0 }; + char elements[2][512] = { 0 }; memcpy(elements[0], cdrom_drive_types[type].vendor, strlen(cdrom_drive_types[type].vendor) + 1); @@ -1197,6 +1279,24 @@ cdrom_lba_to_msf_accurate(const int lba) return ((m << 16) | (s << 8) | f); } +void +cdrom_interleave_subch(uint8_t *d, const uint8_t *s) +{ + memset(d, 0x00, 96); + + for (int i = 0; i < 8 * 12; i++) { + int smask = 0x80; + int dmask = 1 << (7 - (i / 12)); + + for (int j = 0; j < 8; j++) { + d[(i % 12) * 8 + j] |= ((*s) & smask) ? dmask : 0; + smask >>= 1; + } + + s++; + } +} + double cdrom_seek_time(const cdrom_t *dev) { @@ -1261,40 +1361,58 @@ cdrom_is_pre(const cdrom_t *dev, const uint32_t lba) return 0; } +#include <86box/filters.h> + +static void +cdrom_audio_deemphasize(int16_t *buffer) +{ + for (int i = 0; i < 588; i++) + for (int j = 0; j < 2; j++) + buffer[(i * 2) + j] = deemph_iir(j, buffer[(i * 2) + j]); +} + int cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len) { int ret = 1; - if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING) || dev->audio_muted_soft) { - // cdrom_log(dev->log, "Audio callback while not playing\n"); - if (dev->cd_status == CD_STATUS_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; - } - while (dev->cd_buflen < len) { if (dev->seek_pos < dev->cd_end) { - if (dev->ops->read_sector(dev->local, - (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), dev->seek_pos)) { + ret = dev->ops->read_sector(dev->local, + dev->raw_buffer[dev->cur_buf ^ 1], + dev->seek_pos); + if (!dev->sound_on) + memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2352); + dev->cur_buf ^= 1; + if (ret) { cdrom_log(dev->log, "Read LBA %08X successful\n", dev->seek_pos); - memcpy(dev->subch_buffer, - ((uint8_t *) &(dev->cd_buffer[dev->cd_buflen])) + 2352, 96); + dev->cached_sector = dev->seek_pos; + /* Q subchannel data in bit 6: 4-5-6-7-0-1-2-3. */ + if ((dev->raw_buffer[dev->cur_buf][2353] >> 6) & 0x01) + /* Data sector, copy silence into buffer. */ + memset((uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + 0x00, RAW_SECTOR_SIZE); + else { + memcpy((uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), + dev->raw_buffer[dev->cur_buf], RAW_SECTOR_SIZE); + if ((dev->raw_buffer[dev->cur_buf][2355] >> 6) & 0x01) + /* De-emphasize pre-emphasized audio. */ + cdrom_audio_deemphasize(&(dev->cd_buffer[dev->cd_buflen])); + } dev->seek_pos++; dev->cd_buflen += (RAW_SECTOR_SIZE / 2); ret = 1; } else { cdrom_log(dev->log, "Read LBA %08X failed\n", dev->seek_pos); memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, - (BUF_SIZE - dev->cd_buflen) * 2); + (CD_BUF_SIZE - dev->cd_buflen) * 2); dev->cd_status = CD_STATUS_STOPPED; dev->cd_buflen = len; ret = 0; } } else { cdrom_log(dev->log, "Playing completed\n"); - memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); + memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (CD_BUF_SIZE - dev->cd_buflen) * 2); dev->cd_status = CD_STATUS_PLAYING_COMPLETED; dev->cd_buflen = len; ret = 0; @@ -1302,9 +1420,12 @@ cdrom_audio_callback(cdrom_t *dev, int16_t *output, const int len) } memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (CD_BUF_SIZE - len) * 2); dev->cd_buflen -= len; + if (!dev->sound_on) + ret = 0; + cdrom_log(dev->log, "Audio callback returning %i\n", ret); return ret; } @@ -1313,15 +1434,18 @@ uint8_t cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ismsf) { track_info_t ti; - uint32_t pos2 = pos; - uint32_t len2 = len; - int ret = 0; + uint32_t pos2 = pos; + uint32_t len2 = len; + int ret = 0; if (dev->cd_status & CD_STATUS_HAS_AUDIO) { cdrom_log(dev->log, "Play audio - %08X %08X %i\n", pos2, len, ismsf); if (ismsf & 0x100) { /* Track-relative audio play. */ + pos2 = ismsf & 0xff; + if ((dev->is_bcd || dev->is_chinon) && (pos2 < 0xa0)) + pos2 = bcd2bin(pos2); ret = dev->ops->get_track_info(dev->local, ismsf & 0xff, 0, &ti); if (ret) pos2 += MSFtoLBA(ti.m, ti.s, ti.f) - 150; @@ -1331,13 +1455,17 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int cdrom_stop(dev); } } else if ((ismsf == 2) || (ismsf == 3)) { + if ((dev->is_bcd || dev->is_chinon) && (pos2 < 0xa0)) + pos2 = bcd2bin(pos2); ret = dev->ops->get_track_info(dev->local, pos2, 0, &ti); if (ret) { pos2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; if (ismsf == 2) { /* We have to end at the *end* of the specified track, not at the beginning. */ - ret = dev->ops->get_track_info(dev->local, len, 1, &ti); + if ((dev->is_bcd || dev->is_chinon) && (len2 < 0xa0)) + len2 = bcd2bin(len2); + ret = dev->ops->get_track_info(dev->local, len2, 1, &ti); if (ret) len2 = MSFtoLBA(ti.m, ti.s, ti.f) - 150; else { @@ -1357,7 +1485,7 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int int f = pos & 0xff; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) + if (dev->is_bcd) msf_from_bcd(&m, &s, &f); if (pos == 0xffffff) { @@ -1371,7 +1499,7 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int f = len & 0xff; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) + if (dev->is_bcd) msf_from_bcd(&m, &s, &f); len2 = MSFtoLBA(m, s, f) - 150; @@ -1391,8 +1519,6 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int } if (ret) { - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. @@ -1400,10 +1526,11 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int ret = (dev->ops->get_track_type(dev->local, pos2) == CD_TRACK_AUDIO); if (ret) { - dev->seek_pos = pos2; - dev->cd_end = len2; - dev->cd_status = CD_STATUS_PLAYING; - dev->cd_buflen = 0; + dev->seek_diff = ABS(dev->seek_pos - pos2); + dev->seek_pos = pos2; + dev->cd_end = len2; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; } else { cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); cdrom_stop(dev); @@ -1424,6 +1551,8 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, cdrom_log(dev->log, "Audio Track Search: MSF = %06x, type = %02x, " "playbit = %02x\n", pos, type, playbit); + ret = 1; + switch (type) { case 0x00: if (pos == 0xffffffff) { @@ -1445,39 +1574,37 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, dev->seek_pos = pos2; break; } case 0x80: - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 2) Search from current position\n"); - pos2 = dev->seek_pos; + track_info_t ti; + + pos2 = (pos2 >> 24) & 0xff; + if (pos2 < 0xa0) + pos2 = bcd2bin(pos2); + ret = dev->ops->get_track_info(dev->local, pos2, 1, &ti); + if (ret) + dev->seek_pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", ismsf & 0xff); + cdrom_stop(dev); } - dev->seek_pos = (pos2 >> 24) & 0xff; break; default: break; } - if (pos2 != 0x00000000) - pos2--; + if (ret) { + if (pos2 != 0x00000000) + pos2--; - /* - Do this at this point, since it's at this point that we know the - actual LBA position to start playing from. - */ - if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; - else { - cdrom_log(dev->log, "Track Search: LBA %08X not on an audio track\n", pos); - dev->audio_muted_soft = 1; - if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; + cdrom_log(dev->log, "Track Search Toshiba: LBA=%08X.\n", pos); + + dev->cd_end = dev->cdrom_capacity; + dev->cd_buflen = 0; + + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_HOLD; + + ret = 1; } - - cdrom_log(dev->log, "Track Search Toshiba: Muted?=%d, LBA=%08X.\n", - dev->audio_muted_soft, pos); - dev->cd_buflen = 0; - - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; - - ret = 1; } return ret; @@ -1501,15 +1628,15 @@ cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t dev->seek_pos = pos2; - dev->audio_muted_soft = 0; - /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (dev->ops->get_track_type(dev->local, pos2) & CD_TRACK_AUDIO) { + dev->cd_end = dev->cdrom_capacity; dev->cd_buflen = 0; - dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; + + dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_HOLD; ret = 1; } else { @@ -1533,7 +1660,6 @@ cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos) uint32_t pos2 = MSFtoLBA(m, s, f) - 150; dev->cd_end = pos2; - dev->audio_muted_soft = 0; dev->cd_buflen = 0; dev->cd_status = CD_STATUS_PLAYING; @@ -1552,6 +1678,8 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) if (dev->cd_status & CD_STATUS_HAS_AUDIO) { /* Preliminary support, revert if too incomplete. */ + ret = 1; + switch (type) { case 0x00: dev->cd_end = pos2; @@ -1564,7 +1692,19 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) dev->cd_end = pos2; break; } case 0x80: - dev->cd_end = (pos2 >> 24) & 0xff; + track_info_t ti; + + pos2 = (pos2 >> 24) & 0xff; + if (pos2 < 0xa0) + pos2 = bcd2bin(pos2); + ret = dev->ops->get_track_info(dev->local, pos2, 1, &ti); + if (ret) + dev->cd_end = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + else { + cdrom_log(dev->log, "Unable to get the starting position for " + "track %08X\n", ismsf & 0xff); + cdrom_stop(dev); + } break; case 0xc0: if (pos == 0xffffffff) { @@ -1577,55 +1717,32 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) break; } - cdrom_log(dev->log, "Toshiba Play Audio: Muted?=%d, LBA=%08X.\n", - dev->audio_muted_soft, pos2); - dev->cd_buflen = 0; + if (ret) { + cdrom_log(dev->log, "Toshiba Play Audio: LBA=%08X.\n", pos2); - dev->cd_status = CD_STATUS_PLAYING; - - ret = 1; + dev->cd_status = CD_STATUS_PLAYING; + dev->cd_buflen = 0; + } } return ret; } uint8_t -cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type) +cdrom_audio_scan(cdrom_t *dev, const uint32_t pos) { - uint32_t pos2 = pos; - uint8_t ret = 0; + uint32_t pos2 = pos; + uint8_t ret = 0; if (dev->cd_status & CD_STATUS_HAS_AUDIO) { cdrom_log(dev->log, "Audio Scan: MSF = %06x, type = %02x\n", pos, type); - switch (type) { - case 0x00: - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 0) Search from current position\n"); - pos2 = dev->seek_pos; - } - dev->seek_pos = pos2; - break; - case 0x40: { - const int m = bcd2bin((pos >> 24) & 0xff); - const int s = bcd2bin((pos >> 16) & 0xff); - const int f = bcd2bin((pos >> 8) & 0xff); - if (pos == 0xffffffff) { - cdrom_log(dev->log, "(Type 1) Search from current position\n"); - pos2 = dev->seek_pos; - } else - pos2 = MSFtoLBA(m, s, f) - 150; - - dev->seek_pos = pos2; - break; - } case 0x80: - dev->seek_pos = (pos >> 24) & 0xff; - break; - default: - break; + if (pos == 0xffffffff) { + cdrom_log(dev->log, "(Type 0) Search from current position\n"); + pos2 = dev->seek_pos; } + dev->seek_pos = pos2; - dev->audio_muted_soft = 0; /* Do this at this point, since it's at this point that we know the actual LBA position to start playing from. */ if (dev->ops->get_track_type(dev->local, pos) & CD_TRACK_AUDIO) { @@ -1650,8 +1767,8 @@ cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume) uint8_t cdrom_get_current_status(const cdrom_t *dev) { - const uint8_t is_chinon = !strcmp(cdrom_drive_types[dev->type].vendor, "CHINON"); - const uint8_t ret = status_codes[is_chinon][dev->cd_status & CD_STATUS_MASK]; + const uint8_t ret = status_codes[dev->is_chinon] + [dev->cd_status & CD_STATUS_MASK]; return ret; } @@ -1659,9 +1776,14 @@ cdrom_get_current_status(const cdrom_t *dev) void cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) { - subchannel_t subc; + subchannel_t subc; + int base = 0; + int diff = 4; - cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); + if (dev->cached_sector == -1) + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); + else + cdrom_get_subchannel(dev, dev->cached_sector, &subc, 1); cdrom_log(dev->log, "Returned subchannel absolute at %02i:%02i.%02i, " "relative at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x.\n", @@ -1674,17 +1796,29 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), the rest are stuff like ISRC etc., which can be all zeroes. */ + case 0x00: + if (dev->bus_type == CDROM_BUS_ATAPI) { + // pclog("Format 0 on ATAPI\n"); + break; + } + // pclog("Format 0 on SCSI\n"); + diff = 0; + fallthrough; case 0x01: /* Current position. */ b[1] = subc.attr; - b[2] = subc.track; + if ((dev->is_bcd || dev->is_chinon) && + (subc.track >= 1) && (subc.track <= 99)) + b[2] = bin2bcd(subc.track); + else + b[2] = subc.track; b[3] = subc.index; if (msf) { b[4] = b[8] = 0x00; /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) { + if (dev->is_bcd) { b[5] = bin2bcd(subc.abs_m); b[6] = bin2bcd(subc.abs_s); b[7] = bin2bcd(subc.abs_f); @@ -1714,26 +1848,37 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - break; + pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], + b[ 8], b[ 9], b[10], b[11]); + if (b[0] != 0x00) + break; + base += 12; + fallthrough; case 0x02: /* UPC - TODO: Finding and reporting the actual UPC data. */ - memset(&(b[1]), 0x00, 19); - memset(&(b[5]), 0x30, 13); + memset(&(b[base]), 0x00, 20 - diff); + base += diff; + memset(&(b[base + 1]), 0x30, 13); /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) - b[19] = bin2bcd(subc.abs_f); + if (dev->is_bcd) + b[base + 15] = bin2bcd(subc.abs_f); else - b[19] = subc.abs_f; - break; + b[base + 15] = subc.abs_f; + if (b[0] != 0x00) + break; + base += 16; + fallthrough; case 0x03: /* ISRC - TODO: Finding and reporting the actual ISRC data. */ - memset(&(b[1]), 0x00, 19); - memset(&(b[5]), 0x30, 12); + memset(&(b[base]), 0x00, 20 - diff); + base += diff; + memset(&(b[base]), 0x30, 12); /* NEC CDR-260 speaks BCD. */ - if (dev->is_early) - b[18] = bin2bcd(subc.abs_f); + if (dev->is_bcd) + b[base + 14] = bin2bcd(subc.abs_f); else - b[18] = subc.abs_f; + b[base + 14] = subc.abs_f; break; default: cdrom_log(dev->log, "b[0] = %02X\n", b[0]); @@ -1842,7 +1987,7 @@ cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) cdrom_get_subchannel(dev, dev->seek_pos, &subc, 0); - b[0] = subc.attr; + b[0] = (subc.attr >> 4) | ((subc.attr & 0xf) << 4); b[1] = subc.track; b[2] = subc.index; b[3] = subc.rel_m; @@ -1851,6 +1996,10 @@ cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) b[6] = subc.abs_m; b[7] = subc.abs_s; b[8] = subc.abs_f; + + cdrom_log(dev->log, "SubCodeQ: %02X %02X %02X %02X %02X %02X %02X %02X " + "%02X\n", + b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8]); } uint8_t @@ -1860,20 +2009,25 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) cdrom_get_current_subcodeq(dev, b); - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || - (dev->cd_status == CD_STATUS_DVD) || - (dev->cd_status == CD_STATUS_PLAYING_COMPLETED) || - (dev->cd_status == CD_STATUS_STOPPED)) - ret = 0x03; - else - ret = (dev->cd_status == CD_STATUS_PLAYING) ? 0x00 : dev->audio_op; + switch (dev->cd_status) { + default: case CD_STATUS_EMPTY: + case CD_STATUS_DATA_ONLY: case CD_STATUS_DVD: + case CD_STATUS_STOPPED: case CD_STATUS_PLAYING_COMPLETED: + ret = 0x03; + break; + case CD_STATUS_HOLD: + ret = 0x02; + break; + case CD_STATUS_PAUSED: + ret = 0x01; + break; + case CD_STATUS_PLAYING: + ret = 0x00; + break; + } - /*If a valid audio track is detected with audio on, unmute it.*/ - if (dev->ops->get_track_type(dev->local, dev->seek_pos) & CD_TRACK_AUDIO) - dev->audio_muted_soft = 0; - - cdrom_log(dev->log, "SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", - dev->seek_pos, dev->cd_end, dev->audio_muted_soft); + cdrom_log(dev->log, "SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x.\n", + dev->seek_pos, dev->cd_end); return ret; } @@ -2041,14 +2195,11 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, switch (type) { case 0: if (num > 0) { - first = find_track(trti, num, 1); - const int last = find_track(trti, num, 0); - - if ((first == -1) || (last == -1)) + if (num < 4) ret = 0; else { - b[0] = bin2bcd(first); - b[1] = bin2bcd(last); + b[0] = bin2bcd(trti[0].pm); + b[1] = bin2bcd(trti[1].pm); b[2] = 0x00; b[3] = 0x00; @@ -2108,7 +2259,7 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, b[0x12] = temp; } } else { - b[0] = 0x00; /* Audio or CDROM disc. */ + b[0] = trti[0].ps; /* Disc type. */ if (num > 0) first = find_track(trti, num, 1); @@ -2195,7 +2346,6 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int if (dm != CD_TRACK_NORMAL) mode2 = 1; - memset(dev->raw_buffer, 0, 2448); memset(dev->extra_buffer, 0, 296); if ((cdrom_sector_flags & 0xf8) == 0x08) { @@ -2228,28 +2378,29 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int if (ret > 0) { int form = 0; - if ((dev->raw_buffer[0x000f] == 0x00) || - (dev->raw_buffer[0x000f] > 0x02)) { + if ((dev->raw_buffer[dev->cur_buf][0x000f] == 0x00) || + (dev->raw_buffer[dev->cur_buf][0x000f] > 0x02)) { cdrom_log(dev->log, "[%s] Unknown mode: %02X\n", cdrom_req_modes[cdrom_sector_type], - dev->raw_buffer[0x000f]); + dev->raw_buffer[dev->cur_buf][0x000f]); ret = 0; } else if (mode2) { - if (dev->raw_buffer[0x000f] == 0x01) + if (dev->raw_buffer[dev->cur_buf][0x000f] == 0x01) /* Use Mode 1, since evidently specification-violating discs exist. */ mode2 = 0; - else if (dev->raw_buffer[0x0012] != - dev->raw_buffer[0x0016]) { + else if (dev->raw_buffer[dev->cur_buf][0x0012] != + dev->raw_buffer[dev->cur_buf][0x0016]) { cdrom_log(dev->log, "[%s] XA Mode 2 sector with " "malformed sub-header\n", cdrom_req_modes[cdrom_sector_type]); ret = 0; } else - form = ((dev->raw_buffer[0x0012] & 0x20) >> 5) + 1; - } else if (dev->raw_buffer[0x000f] == 0x02) + form = ((dev->raw_buffer[dev->cur_buf][0x0012] & + 0x20) >> 5) + 1; + } else if (dev->raw_buffer[dev->cur_buf][0x000f] == 0x02) mode2 = 1; if (ret > 0) { @@ -2281,7 +2432,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int } if (ret > 0) { - process_ecc_and_subch(dev, cdrom_sector_flags, b); + process_c2_and_subch(dev, cdrom_sector_flags, b); *len = dev->cdrom_sector_size; } } @@ -2617,7 +2768,7 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) if (track->adr_ctl & 0x04) { ret = read_data(dev, start); - mode = dev->raw_buffer[3]; + mode = dev->raw_buffer[dev->cur_buf][3]; } } else if (track->point != 0xa2) start = 0x00000000; @@ -2641,57 +2792,22 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer) return ret; } -int -cdrom_is_empty(const uint8_t id) +uint8_t +cdrom_get_current_mode(cdrom_t *dev) { - const cdrom_t *dev = &cdrom[id]; - int ret = 0; + if (dev->cached_sector == -1) + (void) read_data(dev, dev->seek_pos); + else + (void) read_data(dev, dev->cached_sector); - /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) - /* Switch from empty to empty. Do nothing. */ - ret = 1; - - return ret; + return dev->raw_buffer[dev->cur_buf][3]; } -#ifdef ENABLE_CDROM_LOG -static void -cdrom_toc_dump(cdrom_t *dev) -{ - uint8_t b[65536] = { 0 }; - int len = cdrom_read_toc(dev, b, CD_TOC_RAW, 0, 0, 65536); - const char *fn2 = "d:\\86boxnew\\toc_cue.dmp"; - FILE * f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2); - - memset(b, 0x00, 65536); - len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); - fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp"; - f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2); - - memset(b, 0x00, 65536); - len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); - fn2 = "d:\\86boxnew\\toc_cue_session.dmp"; - f = fopen(fn2, "wb"); - fwrite(b, 1, len, f); - fflush(f); - fclose(f); - cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2); -} -#endif - void cdrom_set_empty(cdrom_t *dev) { dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; } void @@ -2714,6 +2830,7 @@ cdrom_update_status(cdrom_t *dev) dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : CD_STATUS_DATA_ONLY; + dev->cached_sector = -1; dev->cdrom_capacity = dev->ops->get_last_block(dev->local); if (dev->cd_status != CD_STATUS_EMPTY) { @@ -2744,6 +2861,8 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) else dev->local = image_open(dev, dev->image_path); + dev->cached_sector = -1; + if (dev->local == NULL) { dev->ops = NULL; dev->image_path[0] = 0; @@ -2790,6 +2909,9 @@ cdrom_global_init(void) { /* Clear the global data. */ memset(cdrom, 0x00, sizeof(cdrom)); + + for (uint8_t i = 0; i < CDROM_NUM; i++) + cdrom[i].cached_sector = -1; } void @@ -2799,11 +2921,26 @@ cdrom_hard_reset(void) cdrom_t *dev = &cdrom[i]; if (dev->bus_type) { - dev->id = i; + dev->id = i; - dev->is_early = cdrom_is_early(dev->type); - dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && - !strcmp(cdrom_drive_types[dev->type].vendor, "NEC"); + const char *vendor = cdrom_drive_types[dev->type].vendor; + + dev->is_early = cdrom_is_early(dev->type); + dev->is_bcd = !strcmp(vendor, "NEC"); + dev->is_nec = (dev->bus_type == CDROM_BUS_SCSI) && + !strcmp(vendor, "NEC"); + dev->is_chinon = !strcmp(vendor, "CHINON"); + dev->is_pioneer = !strcmp(vendor, "PIONEER"); + dev->is_plextor = !strcmp(vendor, "PLEXTOR"); + dev->is_sony = (dev->bus_type == CDROM_BUS_SCSI) && + (!strcmp(vendor, "DEC") || + !strcmp(vendor, "ShinaKen") || + !strcmp(vendor, "SONY") || + !strcmp(vendor, "TEXEL")); + dev->is_toshiba = !strcmp(vendor, "TOSHIBA"); + + dev->c2_first = !strcmp(vendor, "NEC") || + !strcmp(vendor, "PLEXTOR"); cdrom_drive_reset(dev); @@ -2824,7 +2961,8 @@ cdrom_hard_reset(void) break; } - dev->cd_status = CD_STATUS_EMPTY; + dev->cd_status = CD_STATUS_EMPTY; + dev->cached_sector = -1; if (strlen(dev->image_path) > 0) { #ifdef _WIN32 @@ -2889,6 +3027,8 @@ cdrom_exit(const uint8_t id) strcpy(dev->prev_image_path, dev->image_path); + dev->cached_sector = -1; + if (dev->ops) { cdrom_unload(dev); @@ -2901,6 +3041,20 @@ cdrom_exit(const uint8_t id) cdrom_insert(id); } +int +cdrom_is_empty(const uint8_t id) +{ + const cdrom_t *dev = &cdrom[id]; + int ret = 0; + + /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ + if (strlen(dev->image_path) == 0) + /* Switch from empty to empty. Do nothing. */ + ret = 1; + + return ret; +} + /* The mechanics of ejecting a CD-ROM from a drive. */ void cdrom_eject(const uint8_t id) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 271a290cb..519afaa4c 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -409,7 +409,7 @@ image_get_track_and_index(const cd_image_t *img, const uint32_t sector, for (int i = 0; i < img->tracks_num; i++) { track_t *ct = &(img->tracks[i]); - for (int j = 0; j < 3; j++) { + if ((ct->point >= 1) && (ct->point <= 99)) for (int j = 0; j < 3; j++) { track_index_t *ci = &(ct->idx[j]); if ((ci->type >= INDEX_ZERO) && (ci->length != 0ULL) && ((sector + 150) >= ci->start) && ((sector + 150) <= (ci->start + ci->length - 1))) { diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3683c8671..e367f73b0 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,6 +241,7 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); +#define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1028,9 +1029,8 @@ ide_atapi_command_bus(ide_t *ide) static void ide_atapi_callback(ide_t *ide) { - int out; - int ret = 0; - ide_bm_t *bm = ide_boards[ide->board]->bm; + static int ret = 0; + ide_bm_t *bm = ide_boards[ide->board]->bm; #ifdef ENABLE_IDE_LOG char *phases[7] = { "Idle", "Command", "Data in", "Data out", "Data in DMA", "Data out DMA", "Complete" }; @@ -1056,14 +1056,17 @@ ide_atapi_callback(ide_t *ide) switch (ide->sc->packet_status) { default: + ret = 0; break; case PHASE_IDLE: + ret = 0; ide->tf->pos = 0; ide->tf->phase = 1; ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); break; case PHASE_COMMAND: + ret = 1; ide->tf->atastat = BUSY_STAT | (ide->tf->atastat & ERR_STAT); if (ide->packet_command) { ide->packet_command(ide->sc, ide->sc->atapi_cdb); @@ -1073,6 +1076,7 @@ ide_atapi_callback(ide_t *ide) break; case PHASE_COMPLETE: case PHASE_ERROR: + ret = 0; ide->tf->atastat = READY_STAT; if (ide->sc->packet_status == PHASE_ERROR) ide->tf->atastat |= ERR_STAT; @@ -1082,19 +1086,30 @@ ide_atapi_callback(ide_t *ide) break; case PHASE_DATA_IN: case PHASE_DATA_OUT: + ret = 0; ide->tf->atastat = READY_STAT | DRQ_STAT | (ide->tf->atastat & ERR_STAT); ide->tf->phase = !(ide->sc->packet_status & 0x01) << 1; ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - case PHASE_DATA_OUT_DMA: - out = (ide->sc->packet_status & 0x01); - if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, out, bm->priv); - } - /* Else, DMA command without a bus master, ret = 0 (default). */ + if (ide->sc->block_len == 0) + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); + else { + ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - + ide->sc->block_len, ide->sc->block_len, + 0, bm->priv); + + if (ret == 1) { + if (ide->sc->sector_len == 0) + ret = 3; + else if (ide->read != NULL) + ide->read(ide->sc); + } + } + } else + ret = 0; switch (ret) { default: @@ -1103,18 +1118,69 @@ ide_atapi_callback(ide_t *ide) if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; - case 1: - if (out && ide->phase_data_out) - (void) ide->phase_data_out(ide->sc); - else if (!out && ide->command_stop) - ide->command_stop(ide->sc); + case 2: + ide_atapi_command_bus(ide); + break; + case 3: + /* Reached EOT - terminate the command as there's nothing + more to transfer. */ + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + if (ide->command_stop != NULL) + ide->command_stop(ide->sc); + fallthrough; + case 1: + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) ide_atapi_callback(ide); break; + } + break; + case PHASE_DATA_OUT_DMA: + if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && + (bm != NULL) && bm->dma) { + if (ide->sc->block_len == 0) + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); + else { + ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, + ide->sc->block_len, 1, bm->priv); + + if (ret & 1) { + if (ide->write != NULL) + ide->write(ide->sc); + + if ((ret == 1) && (ide->sc->sector_len == 0)) + ret = 3; + } + } + } else + ret = 0; + + switch (ret) { + default: + break; + case 0: + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + break; case 2: ide_atapi_command_bus(ide); break; + case 3: + /* Reached EOT - terminate the command as there's nothing + more to transfer. */ + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(ide->sc); + fallthrough; + case 1: + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + break; } break; } @@ -1134,22 +1200,37 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); ide->tf->pos = dev->request_pos = 0; - if (out && ide->phase_data_out) - ide->phase_data_out(dev); - else if (!out && ide->command_stop) - ide->command_stop(dev); - if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) - ide_atapi_callback(ide); + if (dev->block_len != 0) { + if (out && (ide->write != NULL)) + ide->write(dev); + else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) + ide->read(dev); + } + + if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (out && (ide->phase_data_out != NULL)) + ide->phase_data_out(dev); + else if (!out && (ide->command_stop != NULL)) + ide->command_stop(dev); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); + } } else { ide_log("%i bytes %s, %i bytes are still left\n", ide->tf->pos, out ? "written" : "read", dev->packet_len - ide->tf->pos); - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ + /* + If less than (packet length) bytes are remaining, update packet length + accordingly. + */ if ((dev->packet_len - ide->tf->pos) < (dev->max_transfer_len)) { dev->max_transfer_len = dev->packet_len - ide->tf->pos; - /* Also update the request length so the host knows how many bytes to transfer. */ + /* + Also update the request length so the host knows how many bytes to + transfer. + */ ide->tf->request_length = dev->max_transfer_len; } ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, @@ -1157,10 +1238,20 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->packet_status = PHASE_DATA_IN | out; + if (dev->block_len != 0) { + if (out && (ide->write != NULL)) + ide->write(dev); + else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) + ide->read(dev); + } + ide->tf->atastat = BSY_STAT; ide->tf->phase = 1; - ide_atapi_callback(ide); - ide_set_callback(ide, 0.0); + + if ((dev->block_len == 0) || (dev->sector_len == 0)) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } dev->request_pos = 0; } @@ -1179,19 +1270,26 @@ ide_atapi_packet_read(ide_t *ide) bufferw = (uint16_t *) dev->temp_buffer; - /* Make sure we return a 0 and don't attempt to read from the buffer if + /* + Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ + (which is 1 sector = 2048 bytes). + */ ret = (ide->tf->pos < dev->packet_len) ? bufferw[ide->tf->pos >> 1] : 0; ide->tf->pos += 2; dev->request_pos += 2; - if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { + if ((dev->request_pos >= dev->max_transfer_len) || + (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); - } + } else if ((dev->block_len != 0) && + (dev->sector_len != 0) && + ((dev->request_pos % dev->block_len) == 0) && + (ide->read != NULL)) + ide->read(dev); } return ret; @@ -1221,10 +1319,14 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) dev->request_pos += 2; if (dev->packet_status == PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (ide->tf->pos >= dev->packet_len)) { + if ((dev->request_pos >= dev->max_transfer_len) || + (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); - } + } else if ((dev->block_len != 0) && + ((dev->request_pos % dev->block_len) == 0) && + (ide->write != NULL)) + ide->write(dev); } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; @@ -1287,7 +1389,7 @@ ide_writew(uint16_t addr, uint16_t val, void *priv) ide = ide_drives[ch]; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_writew(%04X, %04X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writew(%04X, %04X, %08X)\n", CS, cpu_state.pc, addr, val, priv); #endif addr &= 0x7; @@ -1321,7 +1423,7 @@ ide_writel(uint16_t addr, uint32_t val, void *priv) ide = ide_drives[ch]; #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_writel(%04X, %08X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writel(%04X, %08X, %08X)\n", CS, cpu_state.pc, addr, val, priv); #endif addr &= 0x7; @@ -1371,9 +1473,9 @@ ide_write_devctl(UNUSED(uint16_t addr), uint8_t val, void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_write_devctl(%04X, %02X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_write_devctl(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); - if ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE)) + if ((addr & 0x0001) || ((ide->type == IDE_NONE) && (ide_other->type == IDE_NONE))) return; dev->diag = 0; @@ -1481,7 +1583,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_log("ide_writeb(%04X, %02X, %08X)\n", addr, val, priv); + ide_log("[%04X:%08X] ide_writeb(%04X, %02X, %08X)\n", CS, cpu_state.pc, addr, val, priv); addr &= 0x7; @@ -1831,7 +1933,7 @@ ide_read_data(ide_t *ide) const uint16_t *idebufferw = ide->buffer; uint16_t ret = 0x0000; -#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) +#if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 3) ide_log("ide_read_data(): ch = %i, board = %i, type = %i\n", ide->channel, ide->board, ide->type); #endif @@ -2010,7 +2112,7 @@ ide_readb(uint16_t addr, void *priv) break; } - ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readb(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); return ret; } @@ -2022,12 +2124,14 @@ ide_read_alt_status(UNUSED(const uint16_t addr), void *priv) const int ch = dev->cur_dev; ide_t * ide = ide_drives[ch]; + uint8_t ret = 0xff; /* Per the Seagate ATA-3 specification: Reading the alternate status does *NOT* clear the IRQ. */ - const uint8_t ret = ide_status(ide, ide_drives[ch ^ 1], ch); + if (!(addr & 0x0001)) + ret = ide_status(ide, ide_drives[ch ^ 1], ch); - ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_read_alt_status(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); return ret; } @@ -2053,7 +2157,7 @@ ide_readw(uint16_t addr, void *priv) } #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readw(%04X, %08X) = %04X\n", CS, cpu_state.pc, addr, priv, ret); #endif return ret; } @@ -2084,7 +2188,7 @@ ide_readl(uint16_t addr, void *priv) } #if defined(ENABLE_IDE_LOG) && (ENABLE_IDE_LOG == 2) - ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, ret); + ide_log("[%04X:%08X] ide_readl(%04X, %08X) = %04X\n", CS, cpu_state.pc, addr, priv, ret); #endif return ret; } @@ -2270,7 +2374,7 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_set_callback(ide, 6.0 * IDE_TIME); return; - } else if (ret == 1) { + } else if (ret & 1) { /* DMA successful */ ide_log("IDE %i: DMA read successful\n", ide->channel); @@ -2379,7 +2483,7 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_set_callback(ide, 6.0 * IDE_TIME); return; - } else if (ret == 1) { + } else if (ret & 1) { /* DMA successful */ ret = hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); @@ -2637,7 +2741,7 @@ ide_handlers(uint8_t board, int set) } if (ide_boards[board]->base[1]) { - io_handler(set, ide_boards[board]->base[1], 1, + io_handler(set, ide_boards[board]->base[1], 2, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 73dc5f36b..2cc1fe72e 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -375,7 +375,7 @@ sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) } else if (dev->eot) { sff_log("Regular EOT\n"); dev->status &= ~3; - return 1; /* We have regularly reached EOT - clear status and break. */ + return 3; /* We have regularly reached EOT - clear status and break. */ } else { /* We have more to transfer and there are blocks left, get next block. */ sff_bus_master_next_addr(dev); diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7c028d7d6..c6347fc3e 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -28,8 +28,9 @@ #define CD_STATUS_PLAYING 5 #define CD_STATUS_STOPPED 6 #define CD_STATUS_PLAYING_COMPLETED 7 -#define CD_STATUS_HAS_AUDIO 4 -#define CD_STATUS_MASK 7 +#define CD_STATUS_HOLD 8 +#define CD_STATUS_HAS_AUDIO 0xc +#define CD_STATUS_MASK 0xf /* Medium changed flag. */ #define CD_STATUS_TRANSITION 0x40 @@ -50,8 +51,6 @@ #define CD_IMAGE_HISTORY 10 -#define BUF_SIZE 32768 - #define CDROM_IMAGE 200 /* This is so that if/when this is changed to something else, @@ -63,6 +62,8 @@ #define RAW_SECTOR_SIZE 2352 #define COOKED_SECTOR_SIZE 2048 +#define CD_BUF_SIZE (16 * RAW_SECTOR_SIZE) + #define DATA_TRACK 0x14 #define AUDIO_TRACK 0x10 @@ -105,9 +106,9 @@ enum { #define CDV EMU_VERSION_EX static const struct cdrom_drive_types_s { - const char vendor[9]; - const char model[17]; - const char revision[5]; + const char * vendor; + const char * model; + const char * revision; const char * internal_name; const int bus_type; /* SCSI standard for SCSI (or both) devices, early for IDE. */ @@ -298,9 +299,7 @@ typedef struct cdrom { void * priv; char image_path[1024]; - char prev_image_path[1024]; - - char * image_history[CD_IMAGE_HISTORY]; + char prev_image_path[1280]; uint32_t sound_on; uint32_t cdrom_capacity; @@ -310,18 +309,21 @@ typedef struct cdrom { uint32_t type; uint32_t sector_size; - int cd_buflen; - int audio_op; - int audio_muted_soft; - int sony_msf; - int real_speed; - int is_early; - int is_nec; - uint32_t inv_field; + int32_t cached_sector; + int32_t cd_buflen; + int32_t sony_msf; + int32_t real_speed; + int32_t is_early; + int32_t is_nec; + int32_t is_bcd; + + int32_t cdrom_sector_size; const cdrom_ops_t *ops; + char * image_history[CD_IMAGE_HISTORY]; + void * local; void * log; @@ -330,22 +332,26 @@ typedef struct cdrom { uint32_t (*get_volume)(void *p, int channel); uint32_t (*get_channel)(void *p, int channel); - int16_t cd_buffer[BUF_SIZE]; + int16_t cd_buffer[CD_BUF_SIZE]; uint8_t subch_buffer[96]; - int cdrom_sector_size; - /* Needs some extra breathing space in case of overflows. */ - uint8_t raw_buffer[4096]; + uint8_t raw_buffer[2][4096]; uint8_t extra_buffer[296]; + + int32_t is_chinon; + int32_t is_pioneer; + int32_t is_plextor; + int32_t is_sony; + int32_t is_toshiba; + + int32_t c2_first; + int32_t cur_buf; } cdrom_t; extern cdrom_t cdrom[CDROM_NUM]; -/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: - there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start - of the audio while audio still plays. With an absolute conversion, the counter is fine. */ #define MSFtoLBA(m, s, f) ((((m * 60) + s) * 75) + f) static __inline int @@ -366,8 +372,6 @@ extern char *cdrom_get_revision(const int type); extern int cdrom_get_scsi_std(const int type); extern int cdrom_is_early(const int type); extern int cdrom_is_generic(const int type); -extern int cdrom_has_date(const int type); -extern int cdrom_is_sony(const int type); extern int cdrom_is_caddy(const int type); extern int cdrom_get_speed(const int type); extern int cdrom_get_inquiry_len(const int type); @@ -384,6 +388,7 @@ extern void cdrom_set_type(const int model, const int type); extern int cdrom_get_type(const int model); extern int cdrom_lba_to_msf_accurate(const int lba); +extern void cdrom_interleave_subch(uint8_t *d, const uint8_t *s); extern double cdrom_seek_time(const cdrom_t *dev); extern void cdrom_stop(cdrom_t *dev); extern void cdrom_seek(cdrom_t *dev, const uint32_t pos, const uint8_t vendor_type); @@ -396,7 +401,7 @@ extern uint8_t cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos extern uint8_t cdrom_audio_track_search_pioneer(cdrom_t *dev, const uint32_t pos, const uint8_t playbit); extern uint8_t cdrom_audio_play_pioneer(cdrom_t *dev, const uint32_t pos); extern uint8_t cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type); -extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos, const int type); +extern uint8_t cdrom_audio_scan(cdrom_t *dev, const uint32_t pos); extern void cdrom_audio_pause_resume(cdrom_t *dev, const uint8_t resume); extern uint8_t cdrom_get_current_status(const cdrom_t *dev); @@ -424,6 +429,7 @@ extern int cdrom_read_dvd_structure(const cdrom_t *dev, const uint8_ uint8_t *buffer, uint32_t *info); extern void cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer); extern int cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer); +extern uint8_t cdrom_get_current_mode(cdrom_t *dev); extern void cdrom_set_empty(cdrom_t *dev); extern void cdrom_update_status(cdrom_t *dev); extern int cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert); diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 1c2ec5203..6902ffdfd 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -118,16 +118,6 @@ enum { #define BIOS_INTERLEAVED_INVERT 8 #define BIOS_HIGH_BIT_INVERT 16 -#define device_common_config_t \ - const char *name; \ - const char *description; \ - int type; \ - const char *default_string; \ - int default_int; \ - const char *file_filter; \ - const device_config_spinner_t spinner; \ - const device_config_selection_t selection[32] - typedef struct device_config_selection_t { const char *description; int value; @@ -139,10 +129,6 @@ typedef struct device_config_spinner_t { int16_t step; } device_config_spinner_t; -typedef struct _device_dep_config_ { - device_common_config_t; -} device_dep_config_t; - typedef struct device_config_bios_t { const char *name; const char *internal_name; @@ -153,15 +139,18 @@ typedef struct device_config_bios_t { void *dev1; void *dev2; const char *files[9]; - /* Configuration options that depend on the device variant. - To prevent excessive nesting, there is no CONFIG_BIOS - option a dep_config struct */ - const device_dep_config_t *dep_config; } device_config_bios_t; typedef struct _device_config_ { - device_common_config_t; - const device_config_bios_t bios[32]; + const char *name; + const char *description; + int type; + const char *default_string; + int default_int; + const char *file_filter; + const device_config_spinner_t spinner; + const device_config_selection_t selection[32]; + const device_config_bios_t bios[32]; } device_config_t; typedef struct _device_ { diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 6af4d92e6..4e4ea4e5b 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -133,6 +133,8 @@ typedef struct ide_s { uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); void (*bus_master_error)(scsi_common_t *sc); + void (*read)(scsi_common_t *sc); + void (*write)(scsi_common_t *sc); #else void * get_max; void * get_timings; diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index b80c21c13..eda4396ef 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -138,55 +138,63 @@ typedef struct hdd_zone_t { /* Define the virtual Hard Disk. */ typedef struct hard_disk_t { - uint8_t id; + uint8_t id; + union { - uint8_t channel; /* Needed for Settings to reduce the number of if's */ + /* Needed for Settings to reduce the number of if's */ + uint8_t channel; - uint8_t mfm_channel; /* Should rename and/or unionize */ - uint8_t esdi_channel; - uint8_t xta_channel; - uint8_t ide_channel; - uint8_t scsi_id; + uint8_t mfm_channel; + uint8_t esdi_channel; + uint8_t xta_channel; + uint8_t ide_channel; + uint8_t scsi_id; }; - uint8_t bus_type; - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - uint8_t wp; /* Disk has been mounted READ-ONLY */ - uint8_t pad; - uint8_t pad0; - void *priv; + uint8_t bus_type; + uint8_t bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + uint8_t wp; /* Disk has been mounted + READ-ONLY */ + uint8_t pad; + uint8_t pad0; - char fn[1024]; /* Name of current image file */ - char vhd_parent[1041]; /* Differential VHD parent file */ + void * priv; - uint32_t seek_pos; - uint32_t seek_len; - uint32_t base; - uint32_t spt; - uint32_t hpc; /* Physical geometry parameters */ - uint32_t tracks; - const char *model; + char fn[1024]; /* Name of current image file */ + /* Differential VHD parent file */ + char vhd_parent[1280]; - hdd_zone_t zones[HDD_MAX_ZONES]; - uint32_t num_zones; - hdd_cache_t cache; - uint32_t phy_cyl; - uint32_t phy_heads; - uint32_t rpm; - uint8_t max_multiple_block; + uint32_t seek_pos; + uint32_t seek_len; + uint32_t base; + uint32_t spt; /* Physical geometry parameters */ + uint32_t hpc; + uint32_t tracks; + uint32_t speed_preset; - uint32_t cur_cylinder; - uint32_t cur_track; - uint32_t cur_addr; + uint32_t num_zones; + uint32_t phy_cyl; + uint32_t phy_heads; + uint32_t rpm; + uint32_t cur_cylinder; + uint32_t cur_track; + uint32_t cur_addr; + uint32_t vhd_blocksize; - uint32_t speed_preset; - uint32_t vhd_blocksize; + uint8_t max_multiple_block; + uint8_t pad1[3]; - double avg_rotation_lat_usec; - double full_stroke_usec; - double head_switch_usec; - double cyl_switch_usec; + const char * model; + + hdd_zone_t zones[HDD_MAX_ZONES]; + + hdd_cache_t cache; + + double avg_rotation_lat_usec; + double full_stroke_usec; + double head_switch_usec; + double cyl_switch_usec; } hard_disk_t; extern hard_disk_t hdd[HDD_NUM]; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 1df16c3fe..e09515b10 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -51,10 +51,10 @@ static const mo_type_t mo_types[KNOWN_MO_TYPES] = { }; typedef struct mo_drive_type_t { - const char vendor[9]; - const char model[16]; - const char revision[5]; - int8_t supported_media[KNOWN_MO_TYPES]; + const char *vendor; + const char *model; + const char *revision; + int8_t supported_media[KNOWN_MO_TYPES]; } mo_drive_type_t; #define KNOWN_MO_DRIVE_TYPES 22 @@ -161,6 +161,7 @@ typedef struct mo_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index bc2d4c8bd..7bb39d9db 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -54,18 +54,24 @@ typedef struct scsi_cdrom_t { int do_page_save; int unit_attention; int request_pos; - int old_len; - int media_status; + int wait; + int buffer_pos; uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; - int is_sony; - int use_cdb_9; + uint8_t (*ven_cmd)(void *sc, const uint8_t *cdb, int32_t *BufLen); + int use_cdb_9; + int was_cached; + int toc_cached; + int media_access; + + uint8_t vendor_type; uint8_t ven_cmd_is_data[256]; mode_sense_pages_t ms_drive_status_pages_saved; @@ -74,8 +80,6 @@ typedef struct scsi_cdrom_t { mode_sense_pages_t ms_pages_default; mode_sense_pages_t ms_pages_changeable; - - uint8_t (*ven_cmd)(void *sc, const uint8_t *cdb, int32_t *BufLen); } scsi_cdrom_t; #endif diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index ffe042481..62da8b7dc 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -110,39 +110,40 @@ #define GPCMD_MECHANISM_STATUS 0xbd #define GPCMD_READ_CD 0xbe #define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to 86Box. */ -#define GPCMD_EJECT_CHINON 0xc0 /* Chinon Vendor Unique command */ #define GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA 0xc0 /* Toshiba Vendor Unique command */ -#define GPCMD_SET_ADDRESS_FORMAT_SONY 0xc0 /* Sony Vendor Unique command */ +#define GPCMD_EJECT_CHINON 0xc0 /* Chinon Vendor Unique command */ #define GPCMD_MAGAZINE_EJECT_PIONEER 0xc0 /* Pioneer Vendor Unique command */ +#define GPCMD_SET_ADDRESS_FORMAT_SONY 0xc0 /* Sony Vendor Unique command */ #define GPCMD_PLAY_AUDIO_TOSHIBA 0xc1 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_TOC_SONY 0xc1 /* Sony Vendor Unique command */ #define GPCMD_READ_TOC_PIONEER 0xc1 /* Pioneer Vendor Unique command */ +#define GPCMD_READ_TOC_SONY 0xc1 /* Sony Vendor Unique command */ #define GPCMD_PAUSE_RESUME_ALT 0xc2 #define GPCMD_READ_SUBCHANNEL_MATSUSHITA 0xc2 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_SUBCODEQ_PIONEER 0xc2 /* Pioneer Vendor Unique command */ #define GPCMD_READ_SUBCHANNEL_SONY 0xc2 /* Sony Vendor Unique command */ #define GPCMD_STILL_TOSHIBA 0xc2 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_SUBCODEQ_PIONEER 0xc2 /* Pioneer Vendor Unique command */ #define GPCMD_READ_TOC_MATSUSHITA 0xc3 /* Matsushita Vendor Unique command */ #define GPCMD_READ_HEADER_SONY 0xc3 /* Sony Vendor Unique command */ #define GPCMD_SET_STOP_TIME_TOSHIBA 0xc3 /* Toshiba Vendor Unique command */ -#define GPCMD_READ_HEADER_MATSUSHITA 0xc4 /* Matsushita Vendor Unique command */ -#define GPCMD_PLAYBACK_STATUS_SONY 0xc4 /* Sony Vendor Unique command */ #define GPCMD_CADDY_EJECT_TOSHIBA 0xc4 /* Toshiba Vendor Unique command */ +#define GPCMD_PLAYBACK_STATUS_SONY 0xc4 /* Sony Vendor Unique command */ +#define GPCMD_READ_HEADER_MATSUSHITA 0xc4 /* Matsushita Vendor Unique command */ #define GPCMD_PAUSE_SONY 0xc5 /* Sony Vendor Unique command */ #define GPCMD_PLAY_AUDIO_MATSUSHITA 0xc5 /* Matsushita Vendor Unique command */ #define GPCMD_UNKNOWN_SCSI2_NEC 0xc5 /* NEC Vendor Unique Command */ -#define GPCMD_STOP_CHINON 0xc6 /* Chinon Vendor Unique command */ #define GPCMD_PLAY_TRACK_SONY 0xc6 /* Sony Vendor Unique command */ #define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA 0xc6 /* Toshiba Vendor Unique command */ +#define GPCMD_STOP_CHINON 0xc6 /* Chinon Vendor Unique command */ #define GPCMD_PLAY_AUDIO_MSF_MATSUSHITA 0xc7 /* Matsushita Vendor Unique command*/ #define GPCMD_PLAY_MSF_SONY 0xc7 /* Sony Vendor Unique command*/ #define GPCMD_READ_DISC_INFORMATION_TOSHIBA 0xc7 /* Toshiba Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA 0xc8 /* Matsushita Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_SONY 0xc8 /* Sony Vendor Unique command */ #define GPCMD_AUDIO_TRACK_SEARCH_PIONEER 0xc8 /* Pioneer Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_SONY 0xc8 /* Sony Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA 0xc8 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_CDROM_MODE_TOSHIBA 0xc8 /* Toshiba Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_PIONEER 0xc9 /* Pioneer Vendor Unique command */ #define GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA 0xc9 /* Matsushita Vendor Unique command */ #define GPCMD_PLAYBACK_CONTROL_SONY 0xc9 /* Sony Vendor Unique command */ -#define GPCMD_PLAY_AUDIO_PIONEER 0xc9 /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_PIONEER 0xca /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_RESUME_MATSUSHITA 0xcb /* Matsushita Vendor Unique command */ #define GPCMD_STOP_PIONEER 0xcb /* Pioneer Vendor Unique command */ @@ -151,8 +152,8 @@ #define GPCMD_READ_CD_MSF_OLD 0xd5 /* Should be equivalent to 0xb9 */ #define GPCMD_AUDIO_TRACK_SEARCH_NEC 0xd8 /* NEC Vendor Unique command */ #define GPCMD_PLAY_AUDIO_NEC 0xd9 /* NEC Vendor Unique command */ -#define GPCMD_STILL_NEC 0xda /* NEC Vendor Unique command */ #define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ +#define GPCMD_STILL_NEC 0xda /* NEC Vendor Unique command */ #define GPCMD_SET_STOP_TIME_NEC 0xdb /* NEC Vendor Unique command */ #define GPCMD_CADDY_EJECT_NEC 0xdc /* NEC Vendor Unique command */ #define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC 0xdd /* NEC Vendor Unique command */ @@ -409,12 +410,13 @@ typedef struct scsi_common_s { int do_page_save; int unit_attention; int request_pos; - int old_len; - int media_status; + int wait; + int buffer_pos; uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index 7099b836a..293cc35e6 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -53,6 +53,7 @@ typedef struct scsi_disk_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index 06c6e8485..443ab1327 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -108,6 +108,7 @@ typedef struct zip_t { uint32_t sector_pos; uint32_t sector_len; uint32_t packet_len; + uint32_t block_len; double callback; diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 13e0ec9a7..272b389c5 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -65,6 +65,7 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); #include "ui_qt_mainwindow.h" bool windows_is_light_theme() { + return 0; // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 621cf0b76..3d9ecefd5 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -91,6 +91,20 @@ ioctl_open_handle(ioctl_t *ioctl) ioctl_log(ioctl->log, "handle=%p, error=%x\n", ioctl->handle, (unsigned int) GetLastError()); + if (ioctl->handle != INVALID_HANDLE_VALUE) { + CDROM_SET_SPEED set_speed = { 0 }; + + set_speed.RequestType = CdromSetSpeed; + set_speed.ReadSpeed = 0xffff; + set_speed.WriteSpeed = 0xffff; + set_speed.RotationControl = CdromDefaultRotation; + + (void) DeviceIoControl(ioctl->handle, IOCTL_CDROM_SET_SPEED, + &set_speed, sizeof(set_speed), + NULL, 0, + 0, NULL); + } + return (ioctl->handle != INVALID_HANDLE_VALUE); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 04c6532df..07590d5ae 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,6 +15,7 @@ */ #include #include +#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -110,6 +111,7 @@ uint8_t scsi_cdrom_command_flags[0x100] = { [0xbd] = IMPLEMENTED, [0xbe ... 0xbf] = IMPLEMENTED | CHECK_READY, [0xc0 ... 0xcd] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0xd5] = IMPLEMENTED | CHECK_READY, [0xd8 ... 0xde] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, [0xe0 ... 0xe1] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, [0xe3 ... 0xe9] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, @@ -303,15 +305,14 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->tf->status = 0; dev->tf->pos = 0; dev->packet_status = PHASE_NONE; - scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_sense_key = scsi_cdrom_asc = + scsi_cdrom_ascq = dev->unit_attention = 0; scsi_cdrom_info = 0x00000000; dev->drv->cd_status &= ~CD_STATUS_TRANSITION; dev->drv->cur_speed = dev->drv->real_speed; scsi_cdrom_mode_sense_load(dev); - const char *vendor = cdrom_get_vendor(dev->drv->type); - - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && !strcmp(vendor, "PIONEER")) + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && dev->drv->is_pioneer) scsi_cdrom_drive_status_load(dev); } } @@ -339,7 +340,7 @@ scsi_cdrom_get_channel(void *priv, const int channel) uint32_t ret = channel + 1; if (dev != NULL) - ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; + ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8] & 0x0f; return ret; } @@ -530,7 +531,8 @@ scsi_cdrom_mode_sense(const scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); else buf[pos++] = ((dev->drv->cur_speed * 176) >> 8); - } else if (dev->is_sony && (i == GPMODE_CDROM_AUDIO_PAGE_SONY) && + } else if (dev->drv->is_sony && + (i == GPMODE_CDROM_AUDIO_PAGE_SONY) && (j >= 6) && (j <= 13)) buf[pos++] = scsi_cdrom_mode_sense_read(dev, pgctl, GPMODE_CDROM_AUDIO_PAGE, 2 + j); @@ -559,13 +561,21 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len matches the block length. */ switch (dev->current_cdb[0]) { + case 0xbc: + if (!dev->drv->is_early) { + dev->packet_len = len; + break; + } + fallthrough; case 0x08: case 0x28: case 0xa8: + case 0xb8: case 0xb9: case 0xbe: + case 0xd5: /* Round it to the nearest (block length) bytes. */ - if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { + if (dev->current_cdb[0] >= 0xb8) { /* READ CD MSF and READ CD: Round the request length to the sector size - the device must ensure that a media access comand does not DRQ in the middle @@ -601,10 +611,11 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len break; } } + dev->requested_blocks = 1; fallthrough; default: - dev->packet_len = len; + dev->packet_len = len; break; } /* @@ -649,16 +660,10 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) } static void -scsi_cdrom_command_common(scsi_cdrom_t *dev) +scsi_cdrom_set_period(scsi_cdrom_t *dev) { const uint8_t cmd = dev->current_cdb[0]; - /* MAP: BUSY_STAT, no DRQ, phase 1. */ - dev->tf->status = BUSY_STAT; - dev->tf->phase = 1; - dev->tf->pos = 0; - dev->callback = 0; - scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); if (dev->packet_status == PHASE_COMPLETE) @@ -667,91 +672,38 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) double bytes_per_second; double period; - switch (cmd) { - case GPCMD_REZERO_UNIT: - case 0x0b: - case 0x2b: - /* Seek time is in us. */ - period = cdrom_seek_time(dev->drv); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", - (uint64_t) period); - dev->callback += period; + if (dev->was_cached != -1) { + if (dev->was_cached) { + dev->callback += 512.0; scsi_cdrom_set_callback(dev); return; - case 0x43: - dev->drv->seek_diff = dev->drv->seek_pos + 150; - dev->drv->seek_pos = 0; - fallthrough; - case 0x08: - case 0x28: - case 0x42: case 0x44: - case 0xa8: - /* Seek time is in us. */ - period = cdrom_seek_time(dev->drv); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", - (uint64_t) period); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us, speed: %" - PRIu64 " bytes per second, should be: %" - PRIu64 " bytes per second\n", - (uint64_t) period, (uint64_t) (1000000.0 / period), - (uint64_t) (176400.0 * (double) dev->drv->cur_speed)); - dev->callback += period; - fallthrough; - case 0x25: - // case 0x42 ... 0x44: - case 0x51 ... 0x52: - case 0xad: - case 0xb8 ... 0xb9: - case 0xbe: - if (dev->current_cdb[0] == 0x42) - dev->callback += 40.0; - /* Account for seek time. */ - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - /* - TODO: This is a bit of a lie - the actual period is closer to - 75 * 2448 bytes per second, because the subchannel data - has to be read as well. - */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - case 0xc0 ... 0xc3: - case 0xc6 ... 0xc7: - case 0xdd ... 0xde: - if (dev->ven_cmd_is_data[cmd]) { - if (dev->current_cdb[0] == 0xc2) - dev->callback += 40.0; - /* Account for seek time. */ - /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - bytes_per_second = 176400.0; - bytes_per_second *= (double) dev->drv->cur_speed; - break; - } - fallthrough; - default: - bytes_per_second = scsi_cdrom_bus_speed(dev); - if (bytes_per_second == 0.0) { - dev->callback = -1; /* Speed depends on SCSI controller */ - return; - } - break; + } + + /* Seek time is in us. */ + period = cdrom_seek_time(dev->drv); + scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", + (uint64_t) period); + dev->callback += period; + + /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ + bytes_per_second = 176400.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } else { + bytes_per_second = scsi_cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1; /* Speed depends on SCSI controller */ + return; + } } period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - switch (cmd) { - default: - period = period * (double) (dev->packet_len); - break; - case 0x42: case 0x44: - /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ - period = period * 2352.0; - break; - case 0x43: - /* READ TOC - period of 175 entire frames. */ - period = period * 150.0 * 2352.0; - break; + if (dev->was_cached == -1) + period *= (double) dev->packet_len; + else { + period *= ((double) dev->requested_blocks) * 2352.0; + pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, dev->requested_blocks); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -760,6 +712,18 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) scsi_cdrom_set_callback(dev); } +static void +scsi_cdrom_command_common(scsi_cdrom_t *dev) +{ + /* MAP: BUSY_STAT, no DRQ, phase 1. */ + dev->tf->status = BUSY_STAT; + dev->tf->phase = 1; + dev->tf->pos = 0; + dev->callback = 0; + + scsi_cdrom_set_period(dev); +} + static void scsi_cdrom_command_complete(scsi_cdrom_t *dev) { @@ -977,7 +941,7 @@ scsi_cdrom_invalid_lun(scsi_cdrom_t *dev, const uint8_t lun) static void scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev, const uint8_t opcode) { - scsi_cdrom_log(dev->log, "Illegal opcode\n"); + scsi_cdrom_log(dev->log, "Illegal opcode: %02X\n", opcode); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; scsi_cdrom_ascq = 0; @@ -988,7 +952,7 @@ scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev, const uint8_t opcode) static void scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) { - scsi_cdrom_log(dev->log, "LBA out of range\n"); + scsi_cdrom_log(dev->log, "LBA out of range: %08X\n", dev->sector_pos); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; scsi_cdrom_ascq = 0; @@ -1073,7 +1037,7 @@ scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) static int scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int flags, - int32_t *len, const int vendor_type) + const int vendor_type) { int temp_len = 0; int ret = 0; @@ -1081,69 +1045,60 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); else { - const uint32_t cdsize = dev->drv->cdrom_capacity; - - if (dev->sector_pos >= cdsize) { - scsi_cdrom_log(dev->log, "Trying to read from beyond the end of " - "disc (%i >= %i)\n", dev->sector_pos, cdsize); + if (dev->sector_pos > dev->drv->cdrom_capacity) { scsi_cdrom_lba_out_of_range(dev); ret = -1; } else { - int data_pos = 0; + ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, + dev->sector_pos, msf, type, + flags, &temp_len, vendor_type); - dev->old_len = 0; - *len = 0; + if (ret < 0) + scsi_cdrom_circ_error(dev); + else if (ret == 0) + scsi_cdrom_illegal_mode(dev); + else { + if (dev->block_len == 0xffffffff) + dev->block_len = temp_len; - ret = 1; + dev->sector_pos++; + dev->drv->seek_pos = dev->sector_pos; - for (int i = 0; i < dev->requested_blocks; i++) { - ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, - dev->sector_pos + i, msf, type, - flags, &temp_len, vendor_type); + dev->sector_len--; - data_pos += temp_len; - dev->old_len += temp_len; - - *len += temp_len; - - if (ret == 0) { - scsi_cdrom_illegal_mode(dev); - break; - } - - if (ret < 0) { - scsi_cdrom_circ_error(dev); - break; - } + pclog("Sector read to buffer position %08X\n", dev->buffer_pos); + dev->buffer_pos += temp_len; } } } + if ((ret < 1) || (dev->sector_len == 0)) + dev->wait = 0; + return ret; } static int -scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) +scsi_cdrom_read_blocks(scsi_cdrom_t *dev) { int ret = 1; int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; - /* Any of these commands stop the audio playing. */ - cdrom_stop(dev->drv); - switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD_MSF: msf = 1; fallthrough; + case GPCMD_PLAY_CD: case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: type = (dev->current_cdb[1] >> 2) & 7; flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); break; case GPCMD_READ_HEADER: + case GPCMD_READ_HEADER_SONY: type = 0x00; flags = 0x20; break; @@ -1164,16 +1119,10 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, const int vendor_type) scsi_cdrom_log(dev->log, "Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - ret = scsi_cdrom_read_data(dev, msf, type, flags, len, vendor_type); + ret = scsi_cdrom_read_data(dev, msf, type, flags, dev->vendor_type); - scsi_cdrom_log(dev->log, "Read %i bytes of blocks (ret = %i)...\n", *len, ret); - } - - if ((ret > 0) && (dev->current_cdb[0] != GPCMD_READ_HEADER)) { - dev->sector_pos += dev->requested_blocks; - dev->drv->seek_pos = dev->sector_pos; - - dev->sector_len -= dev->requested_blocks; + scsi_cdrom_log(dev->log, "Read %i bytes of blocks (ret = %i)...\n", + dev->block_len, ret); } return ret; @@ -1214,7 +1163,7 @@ scsi_command_check_ready(const scsi_cdrom_t *dev, const uint8_t *cdb) check for ready status but they do on Y vendor. Quite confusing I know. */ - if (!dev->is_sony || (cdb[0] != 0xc0)) + if (!dev->drv->is_sony || (cdb[0] != 0xc0)) ret = 1; } else if ((cdb[0] == GPCMD_READ_DVD_STRUCTURE) && (cdb[7] < 0xc0)) ret = 1; @@ -1317,12 +1266,6 @@ skip_ready_check: if (cdb[0] != GPCMD_REQUEST_SENSE) scsi_cdrom_sense_clear(dev, cdb[0]); - /* Next it's time for NOT READY. */ - if (ready) - dev->media_status = dev->unit_attention ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - else - dev->media_status = MEC_MEDIA_REMOVAL; - if (!ready && scsi_command_check_ready(dev, cdb)) { scsi_cdrom_log(dev->log, "Not ready (%02X)\n", cdb[0]); scsi_cdrom_not_ready(dev); @@ -1336,6 +1279,7 @@ skip_ready_check: static void scsi_cdrom_rezero(scsi_cdrom_t *dev) { + dev->drv->seek_diff = ABS(dev->sector_pos); dev->sector_pos = dev->sector_len = 0; cdrom_seek(dev->drv, 0, 0); } @@ -1388,6 +1332,10 @@ scsi_cdrom_update_sector_flags(scsi_cdrom_t *dev) dev->sector_type = 0x00; dev->sector_flags = 0x02f8; break; + case 2646: + dev->sector_type = 0x00; + dev->sector_flags = 0x00fa; + break; } return ret; @@ -1412,9 +1360,11 @@ scsi_cdrom_reset(scsi_common_t *sc) dev->drv->sector_size = 2048; (void) scsi_cdrom_update_sector_flags(dev); - scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; - scsi_cdrom_info = 0x00000000; - dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; + scsi_cdrom_info = 0x00000000; + dev->drv->cd_status &= ~CD_STATUS_TRANSITION; + dev->drv->cached_sector = -1; + dev->toc_cached = 0; } } @@ -1498,6 +1448,8 @@ scsi_cdrom_stop(const scsi_common_t *sc) const scsi_cdrom_t *dev = (const scsi_cdrom_t *) sc; cdrom_stop(dev->drv); + + ui_sb_update_icon(SB_CDROM | dev->id, 0); } static void @@ -1536,6 +1488,7 @@ scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -1551,16 +1504,66 @@ scsi_cdrom_command_chinon(void *sc, const uint8_t *cdb, UNUSED(int32_t *BufLen)) return cmd_stat; } +static void +scsi_cdrom_cache_toc(scsi_cdrom_t *dev) +{ + if (!dev->toc_cached) { + dev->toc_cached = 1; + dev->drv->seek_diff = dev->drv->seek_pos + 150; + dev->sector_pos = -150; + dev->drv->seek_pos = -150; + dev->requested_blocks = 150; + dev->drv->cached_sector = -1; + } +} + +static void +scsi_cdrom_one_sector_seek(scsi_cdrom_t *dev) +{ + if (!dev->was_cached) { + dev->drv->seek_diff = 0; + dev->requested_blocks = 1; + } +} + +static void +scsi_cdrom_media_access_complete(scsi_cdrom_t *dev, const int ret) +{ + ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); +} + +static void +scsi_cdrom_read(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const int ret = scsi_cdrom_read_blocks(dev); + + dev->drv->seek_diff = 0; + + if (ret > 0) { + if (dev->packet_status != PHASE_COMPLETE) { + ui_sb_update_icon(SB_CDROM | dev->id, 1); + + scsi_cdrom_set_period(dev); + } else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else + scsi_cdrom_media_access_complete(dev, ret); +} + static uint8_t scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int msf; + int ret = 1; uint8_t cmd_stat = 0x00; + int msf; int len; int max_len; - int alloc_length; - int real_pos; switch (cdb[0]) { default: @@ -1575,7 +1578,9 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_TOC_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - msf = dev->drv->sony_msf; + dev->was_cached = dev->toc_cached; + + msf = dev->drv->sony_msf; max_len = cdb[7]; max_len <<= 8; @@ -1592,6 +1597,8 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) /* If the returned length is -1, this means cdrom_read_toc_sony() has encountered an error. */ scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } @@ -1601,6 +1608,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_SUBCHANNEL_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); max_len = cdb[7]; max_len <<= 8; @@ -1615,6 +1623,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, 9); len = 9; cdrom_get_current_subchannel_sony(dev->drv, dev->buffer, msf); + scsi_cdrom_one_sector_seek(dev); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -1631,23 +1640,54 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_HEADER_SONY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = ((cdb[7] << 8) | cdb[8]); - scsi_cdrom_buf_alloc(dev, 4); + len = (cdb[7] << 8) | cdb[8]; + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + dev->was_cached = (dev->drv->cached_sector == dev->sector_pos); + scsi_cdrom_log(dev->log, "READ HEADER SONY: Length: %i, LBA: %i\n", + dev->sector_len, dev->sector_pos); - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - dev->buffer[0] = ((real_pos >> 16) & 0xff); - dev->buffer[1] = ((real_pos >> 8) & 0xff); - dev->buffer[2] = real_pos & 0xff; - dev->buffer[3] = 1; /*2048 bytes user data*/ + if (len > 0) { + max_len = 1; + dev->requested_blocks = 1; - len = 4; - len = MIN(len, alloc_length); + dev->packet_len = len; + scsi_cdrom_buf_alloc(dev, 2352); - scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_one_sector_seek(dev); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + dev->vendor_type = 0x00; + + dev->buffer_pos = 0x00000000; + + ret = scsi_cdrom_read_blocks(dev); + + if (ret > 0) { + len = MIN(4, len); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, + len, 0); + + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log(dev->log, "All done - callback set\n"); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } cmd_stat = 0x01; break; @@ -1702,7 +1742,11 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_illegal_mode(dev); else { /* In this case, len is unused so just pass a fixed value of 1 intead. */ - const int ret = cdrom_audio_play(dev->drv, pos, 1, msf); + const int ret = cdrom_audio_play(dev->drv, pos, 1, msf); + dev->requested_blocks = 0; + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -1746,6 +1790,7 @@ scsi_cdrom_command_dec_sony_texel(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 1); } + cmd_stat = 0x01; break; } @@ -1874,12 +1919,16 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) scsi_cdrom_illegal_mode(dev); else { - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -1909,7 +1958,6 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_STILL_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, 0x00); - dev->drv->audio_op = 0x01; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -1924,12 +1972,14 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector == -1); alloc_length = cdb[1] & 0x1f; len = 10; @@ -1958,6 +2008,8 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_DISC_INFORMATION_NEC: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + /* NEC manual claims 4 bytes but the Linux kernel (namely sr_vendor.c) actually states otherwise. @@ -1967,6 +2019,8 @@ scsi_cdrom_command_nec(void *sc, const uint8_t *cdb, int32_t *BufLen) ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); len = 22; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -1998,12 +2052,15 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_TOC_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + scsi_cdrom_buf_alloc(dev, 4); if (dev->drv->ops == NULL) @@ -2013,6 +2070,8 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) len = 4; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -2023,6 +2082,7 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_SUBCODEQ_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); alloc_length = cdb[1] & 0x1f; len = 9; @@ -2041,6 +2101,7 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); cdrom_get_current_subcodeq(dev->drv, &dev->buffer[1]); + scsi_cdrom_one_sector_seek(dev); scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); @@ -2051,15 +2112,18 @@ scsi_cdrom_command_pioneer(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_PIONEER: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) ret = 0; else { pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; ret = cdrom_audio_track_search_pioneer(dev->drv, pos, cdb[1] & 1); - - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; } + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; + if (ret) scsi_cdrom_command_complete(dev); else @@ -2178,13 +2242,17 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) { scsi_cdrom_illegal_mode(dev); break; } - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -2213,7 +2281,6 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_STILL_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, 0x00); - dev->drv->audio_op = 0x01; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; @@ -2228,12 +2295,14 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; scsi_cdrom_command_complete(dev); cmd_stat = 0x01; break; case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); alloc_length = cdb[1] & 0x1f; len = 10; @@ -2252,6 +2321,7 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) memset(dev->buffer, 0, len); dev->buffer[0] = cdrom_get_current_subcodeq_playstatus(dev->drv, &dev->buffer[1]); + scsi_cdrom_one_sector_seek(dev); scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[0]); scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); @@ -2262,6 +2332,8 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) case GPCMD_READ_DISC_INFORMATION_TOSHIBA: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; + scsi_cdrom_buf_alloc(dev, 4); if (dev->drv->ops == NULL) @@ -2270,6 +2342,8 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); len = 4; if (ret) { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } else @@ -2277,6 +2351,25 @@ scsi_cdrom_command_toshiba(void *sc, const uint8_t *cdb, int32_t *BufLen) } cmd_stat = 0x01; break; + + case GPCMD_READ_CDROM_MODE_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); + + scsi_cdrom_buf_alloc(dev, 1); + + alloc_length = 1; + + len = alloc_length; + dev->buffer[0] = cdrom_get_current_mode(dev->drv); + + scsi_cdrom_one_sector_seek(dev); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + + cmd_stat = 0x01; + break; } return cmd_stat; @@ -2306,6 +2399,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) int toc_format; int32_t *BufLen; + dev->was_cached = -1; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; dev->tf->status &= ~ERR_STAT; @@ -2317,6 +2412,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; + dev->block_len = 0; + memcpy(dev->current_cdb, cdb, 12); #if ENABLE_SCSI_CDROM_LOG == 2 @@ -2331,8 +2428,9 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) cdb[8], cdb[9], cdb[10], cdb[11]); #endif - msf = cdb[1] & 2; - dev->sector_len = 0; + msf = cdb[1] & 2; + dev->sector_len = 0; + dev->requested_blocks = 0; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -2348,17 +2446,22 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_sense_clear(dev, cdb[0]); } - if ((dev->ven_cmd == NULL) || (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (dev->current_cdb[0]) { + if ((dev->ven_cmd == NULL) || + (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (dev->current_cdb[0]) { case GPCMD_TEST_UNIT_READY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); break; case GPCMD_REZERO_UNIT: + pclog("Rezero unit\n"); + dev->was_cached = 0; scsi_cdrom_stop(sc); - dev->sector_pos = dev->sector_len = 0; + dev->requested_blocks = 0; dev->drv->seek_diff = dev->drv->seek_pos; cdrom_seek(dev->drv, 0, 0); + dev->sector_pos = dev->drv->seek_pos; + dev->drv->cached_sector = -1; scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); break; @@ -2386,7 +2489,9 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: + pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DVD)) { @@ -2395,7 +2500,10 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) } pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_audio_scan(dev->drv, pos, 0); + ret = cdrom_audio_scan(dev->drv, pos); + + dev->drv->seek_diff = ABS(dev->sector_pos - dev->drv->seek_pos); + dev->sector_pos = dev->drv->seek_pos; if (ret) scsi_cdrom_command_complete(dev); @@ -2419,6 +2527,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_TOC_PMA_ATIP: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2427,6 +2536,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; + pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -2439,6 +2549,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) if (len == -1) scsi_cdrom_invalid_field(dev, dev->drv->inv_field); else { + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); } @@ -2446,6 +2558,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_invalid_field(dev, toc_format); break; + case GPCMD_PLAY_CD: + /* + According to the ATAPI specification, this was actually READ CD + on early drives. + */ + if (!dev->drv->is_early) { + scsi_cdrom_illegal_opcode(dev, dev->current_cdb[0]); + break; + } + fallthrough; case GPCMD_READ_6: case GPCMD_READ_10: case GPCMD_READ_12: @@ -2454,9 +2576,11 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_CD: case GPCMD_READ_CD_MSF: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = dev->drv->sector_size; + dev->was_cached = 0; - switch (cdb[0]) { + alloc_length = dev->drv->sector_size; + + switch (dev->current_cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; /* @@ -2491,6 +2615,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_CD_MSF: msf = 1; fallthrough; + case GPCMD_PLAY_CD: case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: alloc_length = 2856; @@ -2535,22 +2660,30 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); dev->drv->seek_pos = dev->sector_pos; - if (dev->use_cdb_9 && ((cdb[0] == GPCMD_READ_10) || - (cdb[0] == GPCMD_READ_12))) - ret = scsi_cdrom_read_blocks(dev, &alloc_length, - cdb[9] & 0xc0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + if (dev->use_cdb_9 && + ((dev->current_cdb[0] == GPCMD_READ_10) || + (dev->current_cdb[0] == GPCMD_READ_12))) + dev->vendor_type = cdb[9] & 0xc0; else - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); + dev->vendor_type = 0x00; + + dev->block_len = 0xffffffff; + dev->buffer_pos = 0x00000000; + + ret = scsi_cdrom_read_blocks(dev); + alloc_length = dev->requested_blocks * dev->block_len; if (ret > 0) { - dev->requested_blocks = max_len; dev->packet_len = alloc_length; scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); scsi_cdrom_data_command_finish(dev, alloc_length, - alloc_length / dev->requested_blocks, + dev->block_len, alloc_length, 0); if (dev->packet_status != PHASE_COMPLETE) @@ -2575,11 +2708,14 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_HEADER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - alloc_length = 2352; - len = (cdb[7] << 8) | cdb[8]; - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + alloc_length = 2352; + + len = (cdb[7] << 8) | cdb[8]; + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | + (cdb[4] << 8) | cdb[5]; + dev->was_cached = (dev->drv->cached_sector == dev->sector_pos); scsi_cdrom_log(dev->log, "READ HEADER: Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); @@ -2590,10 +2726,15 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = len; scsi_cdrom_buf_alloc(dev, 2352); - dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); - dev->drv->seek_pos = dev->sector_pos; + scsi_cdrom_one_sector_seek(dev); - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 0); + /* Any of these commands stop the audio playing. */ + cdrom_stop(dev->drv); + + dev->vendor_type = 0x00; + + dev->buffer_pos = 0x00000000; + ret = scsi_cdrom_read_blocks(dev); if (ret > 0) { uint8_t header[4] = { 0 }; @@ -2650,7 +2791,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) else block_desc = !((cdb[1] >> 3) & 1); - if (cdb[0] == GPCMD_MODE_SENSE_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; scsi_cdrom_buf_alloc(dev, 256); } else { @@ -2681,7 +2822,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) else max_len = 3; /* Audio or mixed-mode CD. */ - if (cdb[0] == GPCMD_MODE_SENSE_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SENSE_6) { len = scsi_cdrom_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); len = MIN(len, alloc_length); dev->buffer[0] = len - 1; @@ -2714,7 +2855,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_MODE_SELECT_10: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (cdb[0] == GPCMD_MODE_SELECT_6) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { len = cdb[4]; scsi_cdrom_buf_alloc(dev, 256); } else { @@ -2919,7 +3060,10 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) gesn_event_header->notification_class |= GESN_MEDIA; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status. */ - dev->buffer[4] = dev->media_status; + if (dev->drv->cd_status == CD_STATUS_EMPTY) + dev->buffer[4] = MEC_MEDIA_REMOVAL; + else + dev->buffer[4] = dev->unit_attention ? MEC_NEW_MEDIA : MEC_NO_CHANGE; /* Power Status (1 = Active). */ dev->buffer[5] = 1; dev->buffer[6] = 0; @@ -2947,6 +3091,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_DISC_INFORMATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2958,6 +3103,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = MIN(34, max_len); + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -2965,6 +3112,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_TRACK_INFORMATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; max_len = cdb[7]; max_len <<= 8; @@ -2983,6 +3131,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->buffer[1] = (max_len - 2) & 0xff; } + scsi_cdrom_cache_toc(dev); + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); } else @@ -2999,21 +3149,25 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = 0; - switch (cdb[0]) { + switch (dev->current_cdb[0]) { case GPCMD_PLAY_AUDIO_10: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; + pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", + cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3022,16 +3176,19 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; + pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; + pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + pclog("Play audio track relative (12)\n"); break; default: @@ -3039,9 +3196,11 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) } if (ret && (dev->drv->image_path[0] != 0x00) && - (dev->drv->cd_status > CD_STATUS_DVD)) - ret = cdrom_audio_play(dev->drv, pos, len, msf); - else + (dev->drv->cd_status > CD_STATUS_DVD)) { + ret = cdrom_audio_play(dev->drv, pos, len, msf); + + dev->sector_pos = dev->drv->seek_pos; + } else ret = 0; if (ret) @@ -3052,13 +3211,14 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_READ_SUBCHANNEL: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = (dev->drv->cached_sector != -1); max_len = cdb[7]; max_len <<= 8; max_len |= cdb[8]; msf = (cdb[1] >> 1) & 1; - scsi_cdrom_buf_alloc(dev, 32); + scsi_cdrom_buf_alloc(dev, 128); scsi_cdrom_log(dev->log, "Getting page %i (%s)\n", cdb[3], msf ? "MSF" : "LBA"); @@ -3090,23 +3250,23 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = alloc_length; - memset(dev->buffer, 0, 24); - pos = 0x00; - dev->buffer[pos++] = 0x00; - dev->buffer[pos++] = 0x00; /* Audio status */ - dev->buffer[pos++] = 0x00; - dev->buffer[pos++] = 0x00; /* Subchannel length */ - dev->buffer[pos++] = cdb[3]; /* Format code */ + memset(dev->buffer, 0x00, 128); - if (alloc_length != 4) { + if (alloc_length > 4) { + dev->buffer[4] = cdb[3]; /* Format code */ cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); - dev->buffer[2] = alloc_length - 4; + alloc_length = MIN(max_len, alloc_length); + + dev->buffer[3] = (alloc_length - 4) & 0xff; + dev->buffer[4] = cdb[3]; /* Format code */ } dev->buffer[1] = cdrom_get_current_status(dev->drv); - scsi_cdrom_log(dev->log, "Audio Status = %02x\n", dev->buffer[1]); + scsi_cdrom_log(dev->log, "Audio status: %02X\n", dev->buffer[1]); + + scsi_cdrom_one_sector_seek(dev); len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -3119,7 +3279,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - scsi_cdrom_buf_alloc(dev, alloc_length); if ((cdb[7] < 0xc0) && (dev->drv->cd_status != CD_STATUS_DVD)) @@ -3168,10 +3327,13 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) This makes no sense under emulation as this would do absolutely nothing, so just break. */ + dev->toc_cached = 0; + scsi_cdrom_cache_toc(dev); break; case 2: /* Eject the disc if possible. */ scsi_cdrom_stop(sc); cdrom_eject(dev->id); + dev->toc_cached = 0; break; case 3: /* Load the disc (close tray). */ cdrom_reload(dev->id); @@ -3267,7 +3429,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) if (dev->drv->bus_type == CDROM_BUS_SCSI) { dev->buffer[3] = cdrom_get_scsi_std(dev->drv->type); - if (!strcmp(cdrom_get_vendor(dev->drv->type), "TOSHIBA")) + if (dev->drv->is_toshiba) /* Linked Command and Relative Addressing supported */ dev->buffer[7] = 0x88; } else { @@ -3287,7 +3449,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) ide_padstr8(dev->buffer + 32, 4, cdrom_get_revision(dev->drv->type)); /* Revision */ - if (cdrom_has_date(dev->drv->type)) { + if (dev->drv->is_pioneer) { dev->buffer[36] = 0x20; ide_padstr8(dev->buffer + 37, 10, "1991/01/01"); /* Date */ } @@ -3321,15 +3483,16 @@ atapi_out: case GPCMD_PAUSE_RESUME: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, cdb[8] & 0x01); - dev->drv->audio_op = (cdb[8] & 0x01) ? 0x03 : 0x01; scsi_cdrom_command_complete(dev); break; case GPCMD_SEEK_6: case GPCMD_SEEK_10: + pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->was_cached = 0; - switch (cdb[0]) { + switch (dev->current_cdb[0]) { case GPCMD_SEEK_6: pos = (cdb[2] << 8) | cdb[3]; break; @@ -3346,16 +3509,20 @@ atapi_out: /* Stop the audio playing. */ cdrom_stop(dev->drv); - if (dev->use_cdb_9 && (cdb[0] == GPCMD_SEEK_10)) + if (dev->use_cdb_9 && (dev->current_cdb[0] == GPCMD_SEEK_10)) cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); else cdrom_seek(dev->drv, pos, 0); + dev->sector_pos = dev->drv->seek_pos; + dev->drv->cached_sector = -1; + scsi_cdrom_command_complete(dev); break; case GPCMD_READ_CDROM_CAPACITY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->was_cached = dev->toc_cached; scsi_cdrom_buf_alloc(dev, 8); @@ -3370,6 +3537,8 @@ atapi_out: scsi_cdrom_log(dev->log, "CD-ROM Capacity: %08X\n", dev->drv->cdrom_capacity - 1); + + scsi_cdrom_cache_toc(dev); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -3388,7 +3557,7 @@ atapi_out: break; default: - scsi_cdrom_illegal_opcode(dev, cdb[0]); + scsi_cdrom_illegal_opcode(dev, dev->current_cdb[0]); break; } @@ -3486,7 +3655,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; - if (dev->is_sony && (page == 0x08) && (page_len == 0x02)) + if (dev->drv->is_sony && (page == 0x08) && (page_len == 0x02)) dev->drv->sony_msf = dev->buffer[pos] & 0x01; if (!(dev->ms_page_flags & (1LL << ((uint64_t) page)))) { @@ -3496,7 +3665,9 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) for (i = 0; i < page_len; i++) { uint8_t pg = page; - if (dev->is_sony && (page == GPMODE_CDROM_AUDIO_PAGE_SONY) && (i >= 6) && (i <= 13)) + if (dev->drv->is_sony && + (page == GPMODE_CDROM_AUDIO_PAGE_SONY) && + (i >= 6) && (i <= 13)) pg = GPMODE_CDROM_AUDIO_PAGE; ch = dev->ms_pages_changeable.pages[pg][i + 2]; @@ -3532,7 +3703,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) } break; case 0xc9: - if (dev->is_sony) { + if (dev->drv->is_sony) { for (i = 0; i < 18; i++) { if ((i >= 8) && (i <= 15)) dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][i] = @@ -3687,12 +3858,15 @@ scsi_cdrom_drive_reset(const int c) dev->id = c; dev->drv = drv; - dev->cur_lun = SCSI_LUN_USE_CDB; + dev->cur_lun = SCSI_LUN_USE_CDB; - drv->insert = scsi_cdrom_insert; - drv->get_volume = scsi_cdrom_get_volume; - drv->get_channel = scsi_cdrom_get_channel; - drv->close = scsi_cdrom_close; + dev->toc_cached = 0; + drv->cached_sector = -1; + + drv->insert = scsi_cdrom_insert; + drv->get_volume = scsi_cdrom_get_volume; + drv->get_channel = scsi_cdrom_get_channel; + drv->close = scsi_cdrom_close; drv->sector_size = 2048; (void) scsi_cdrom_update_sector_flags(dev); @@ -3702,22 +3876,19 @@ scsi_cdrom_drive_reset(const int c) dev->ven_cmd = NULL; memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); - dev->is_sony = 0; dev->use_cdb_9 = 0; dev->ms_page_flags = scsi_cdrom_ms_page_flags_scsi; dev->ms_pages_default = scsi_cdrom_ms_pages_default_scsi; dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_scsi; - if (!strcmp(vendor, "CHINON")) + if (dev->drv->is_chinon) dev->ven_cmd = scsi_cdrom_command_chinon; - else if (!strcmp(vendor, "DEC") || !strcmp(vendor, "ShinaKen") || - !strcmp(vendor, "SONY") || !strcmp(vendor, "TEXEL")) { + else if (dev->drv->is_sony) { dev->ven_cmd = scsi_cdrom_command_dec_sony_texel; dev->ven_cmd_is_data[0xc0] = 1; dev->ven_cmd_is_data[0xc1] = 1; dev->ven_cmd_is_data[0xc2] = 1; dev->ven_cmd_is_data[0xc3] = 1; - dev->is_sony = 1; dev->ms_page_flags = scsi_cdrom_ms_page_flags_sony_scsi; dev->ms_pages_default = scsi_cdrom_ms_pages_default_sony_scsi; dev->ms_pages_changeable = scsi_cdrom_ms_pages_changeable_sony_scsi; @@ -3727,12 +3898,12 @@ scsi_cdrom_drive_reset(const int c) dev->ven_cmd = scsi_cdrom_command_nec; dev->ven_cmd_is_data[0xdd] = 1; dev->ven_cmd_is_data[0xde] = 1; - } else if (!strcmp(vendor, "PIONEER")) { + } else if (dev->drv->is_pioneer) { dev->ven_cmd = scsi_cdrom_command_pioneer; dev->ven_cmd_is_data[0xc1] = 1; dev->ven_cmd_is_data[0xc2] = 1; dev->ven_cmd_is_data[0xc3] = 1; - } else if (!strcmp(vendor, "TOSHIBA")) { + } else if (dev->drv->is_toshiba) { dev->ven_cmd = scsi_cdrom_command_toshiba; dev->ven_cmd_is_data[0xc6] = 1; dev->ven_cmd_is_data[0xc7] = 1; @@ -3768,7 +3939,6 @@ scsi_cdrom_drive_reset(const int c) if (id) { dev->ven_cmd = NULL; memset(dev->ven_cmd_is_data, 0x00, sizeof(dev->ven_cmd_is_data)); - dev->is_sony = 0; dev->use_cdb_9 = 0; dev->ms_page_flags = scsi_cdrom_ms_page_flags; dev->ms_pages_default = scsi_cdrom_ms_pages_default; @@ -3786,6 +3956,8 @@ scsi_cdrom_drive_reset(const int c) id->phase_data_out = scsi_cdrom_phase_data_out; id->command_stop = scsi_cdrom_command_stop; id->bus_master_error = scsi_cdrom_bus_master_error; + id->read = scsi_cdrom_read; + id->write = NULL; id->interrupt_drq = dev->drv->is_early; valid = 1; diff --git a/src/sound/sound.c b/src/sound/sound.c index 28cb96629..0c8dffe12 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -274,83 +274,89 @@ sound_cd_thread(UNUSED(void *param)) temp_buffer[0] = temp_buffer[1] = 0; for (uint8_t i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || (cdrom[i].cd_status == CD_STATUS_EMPTY)) + /* Just in case the thread is in a loop when it gets terminated. */ + if (!cdaudioon) + break; + + if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || + (cdrom[i].cd_status != CD_STATUS_PLAYING)) continue; - const uint32_t lba = cdrom[i].seek_pos; - const int r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); - if (!cdrom[i].sound_on || !r) - continue; - const int pre = cdrom_is_pre(&(cdrom[i]), lba); + const int ret = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], + CD_BUFLEN * 2); - - if (cdrom[i].get_volume) { - audio_vol_l = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 0)]; - audio_vol_r = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 1)]; - } else { - audio_vol_l = cd_audio_volume_lut[255]; - audio_vol_r = cd_audio_volume_lut[255]; - } - - if (cdrom[i].get_channel) { - channel_select[0] = (int) cdrom[i].get_channel(cdrom[i].priv, 0); - channel_select[1] = (int) cdrom[i].get_channel(cdrom[i].priv, 1); - } else { - channel_select[0] = 1; - channel_select[1] = 2; - } - - for (int c = 0; c < CD_BUFLEN * 2; c += 2) { - /*Apply ATAPI channel select*/ - cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; - - if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { - if (channel_select[0] & 1) - cd_buffer_temp[0] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 0 */ - if (channel_select[0] & 2) - cd_buffer_temp[0] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ - - cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ - - if (pre) - cd_buffer_temp[0] = deemph_iir(0, cd_buffer_temp[0]); /* De-emphasize if necessary */ - } - - if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { - if (channel_select[1] & 1) - cd_buffer_temp[1] += ((double) cd_buffer[i][c]); /* Channel 0 => Port 1 */ - if (channel_select[1] & 2) - cd_buffer_temp[1] += ((double) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ - - cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ - - if (pre) - cd_buffer_temp[1] = deemph_iir(1, cd_buffer_temp[1]); /* De-emphasize if necessary */ - } - - /* Apply sound card CD volume and filters */ - if (filter_cd_audio != NULL) { - filter_cd_audio(0, &(cd_buffer_temp[0]), filter_cd_audio_p); - filter_cd_audio(1, &(cd_buffer_temp[1]), filter_cd_audio_p); - } - - if (sound_is_float) { - cd_out_buffer[c] += (float) (cd_buffer_temp[0] / 32768.0); - cd_out_buffer[c + 1] += (float) (cd_buffer_temp[1] / 32768.0); + if (ret) { + if (cdrom[i].get_volume) { + audio_vol_l = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 0)]; + audio_vol_r = cd_audio_volume_lut[cdrom[i].get_volume(cdrom[i].priv, 1)]; } else { - temp_buffer[0] += (int) trunc(cd_buffer_temp[0]); - temp_buffer[1] += (int) trunc(cd_buffer_temp[1]); + audio_vol_l = cd_audio_volume_lut[255]; + audio_vol_r = cd_audio_volume_lut[255]; + } - if (temp_buffer[0] > 32767) - temp_buffer[0] = 32767; - if (temp_buffer[0] < -32768) - temp_buffer[0] = -32768; - if (temp_buffer[1] > 32767) - temp_buffer[1] = 32767; - if (temp_buffer[1] < -32768) - temp_buffer[1] = -32768; + if (cdrom[i].get_channel) { + channel_select[0] = (int) cdrom[i].get_channel(cdrom[i].priv, 0); + channel_select[1] = (int) cdrom[i].get_channel(cdrom[i].priv, 1); + } else { + channel_select[0] = 1; + channel_select[1] = 2; + } - cd_out_buffer_int16[c] = (int16_t) temp_buffer[0]; - cd_out_buffer_int16[c + 1] = (int16_t) temp_buffer[1]; + // uint16_t *cddab = (uint16_t *) cdrom[i].raw_buffer; + for (int c = 0; c < CD_BUFLEN * 2; c += 2) { + /* Apply ATAPI channel select */ + cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; + + if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { + if (channel_select[0] & 1) + /* Channel 0 => Port 0 */ + cd_buffer_temp[0] += ((double) cd_buffer[i][c]); + if (channel_select[0] & 2) + /* Channel 1 => Port 0 */ + cd_buffer_temp[0] += ((double) cd_buffer[i][c + 1]); + + /* Multiply Port 0 by Port 0 volume */ + cd_buffer_temp[0] *= audio_vol_l; + } + + if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { + if (channel_select[1] & 1) + /* Channel 0 => Port 1 */ + cd_buffer_temp[1] += ((double) cd_buffer[i][c]); + if (channel_select[1] & 2) + /* Channel 1 => Port 1 */ + cd_buffer_temp[1] += ((double) cd_buffer[i][c + 1]); + + /* Multiply Port 1 by Port 1 volume */ + cd_buffer_temp[1] *= audio_vol_r; + } + + /* Apply sound card CD volume and filters */ + if (filter_cd_audio != NULL) { + filter_cd_audio(0, &(cd_buffer_temp[0]), + filter_cd_audio_p); + filter_cd_audio(1, &(cd_buffer_temp[1]), + filter_cd_audio_p); + } + + if (sound_is_float) { + cd_out_buffer[c] += (float) (cd_buffer_temp[0] / 32768.0); + cd_out_buffer[c + 1] += (float) (cd_buffer_temp[1] / 32768.0); + } else { + temp_buffer[0] = (int) trunc(cd_buffer_temp[0]); + temp_buffer[1] = (int) trunc(cd_buffer_temp[1]); + + if (temp_buffer[0] > 32767) + temp_buffer[0] = 32767; + if (temp_buffer[0] < -32768) + temp_buffer[0] = -32768; + if (temp_buffer[1] > 32767) + temp_buffer[1] = 32767; + if (temp_buffer[1] < -32768) + temp_buffer[1] = -32768; + + cd_out_buffer_int16[c] += (int16_t) temp_buffer[0]; + cd_out_buffer_int16[c + 1] += (int16_t) temp_buffer[1]; + } } } } From ae597c2e46c3097d5f13631d408c4761022e0f90 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Feb 2025 05:31:29 +0100 Subject: [PATCH 0224/1190] Reverted the dark mode forcing and reveted CD-ROM to old behavior if bus is SCSI, because it turns out the changes are not even needed on SCSI. --- src/qt/qt_winrawinputfilter.cpp | 1 - src/scsi/scsi_cdrom.c | 15 +++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 272b389c5..13e0ec9a7 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -65,7 +65,6 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); #include "ui_qt_mainwindow.h" bool windows_is_light_theme() { - return 0; // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 07590d5ae..8a39edb39 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -611,7 +611,9 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len break; } } - dev->requested_blocks = 1; + + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->requested_blocks = 1; fallthrough; default: @@ -1044,11 +1046,12 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); - else { - if (dev->sector_pos > dev->drv->cdrom_capacity) { - scsi_cdrom_lba_out_of_range(dev); - ret = -1; - } else { + else if (dev->sector_pos > dev->drv->cdrom_capacity) { + scsi_cdrom_lba_out_of_range(dev); + ret = -1; + } else { + ret = 1; + for (int i = 0; (i < dev->requested_blocks) && (ret > 0); i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, dev->sector_pos, msf, type, flags, &temp_len, vendor_type); From ab3d849c76c5e6a29a5615ddd02833c39deaa937 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 10 Feb 2025 13:58:22 -0300 Subject: [PATCH 0225/1190] Jenkins: Revise MacPorts OpenAL hack for 1.24.2 and hopefully later updates, fixes #5218 --- .ci/build.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.ci/build.sh b/.ci/build.sh index 326952186..0af94132a 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -542,11 +542,12 @@ then sudo sed -i -e 's/configure.env-append MAKE=/configure.env-append VULKAN_SDK=${prefix} MAKE=/g' "$qt5_portfile" fi - # Patch openal-soft to use 1.23.1 on all targets instead of 1.24.1 on >=10.15 only, + # Patch openal-soft to use 1.23.1 on all targets instead of 1.24.2 on >=10.13 only, # to prevent a symlink mismatch from having different versions on x86_64 and arm64. # See: https://github.com/macports/macports-ports/commit/9b4903fc9c76769d476079e404c9a3b8a225f8aa + # https://github.com/macports/macports-ports/commit/788deb64dc0695e8d04afb32ed904947f2a7591b openal_portfile="$macports/var/macports/sources/rsync.macports.org/macports/release/tarballs/ports/audio/openal-soft/Portfile" - sudo sed -i -e 's/if {${os.platform} ne "darwin" || ${os.major} >= 19}/if {0}/g' "$openal_portfile" + sudo sed -i -e 's/if {${os.platform} ne "darwin" ||/if {0 \&\&/g' "$openal_portfile" # Patch wget to remove libproxy support, as it depends on shared-mime-info which # fails to build for a 10.13 target, which we have to do despite wget only being From cdc381b6192dca8c1e3a0be3607d72b28eba743e Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 11 Feb 2025 11:27:41 +0900 Subject: [PATCH 0226/1190] Added a new machine: IBM PS/55 model 5551-V0,V1 --- src/machine/m_ps2_mca.c | 174 +++++++++++++++++++++++++++++++++++- src/machine/machine_table.c | 40 +++++++++ src/video/vid_ps55da2.c | 44 ++++----- 3 files changed, 231 insertions(+), 27 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 72776b22d..103badf61 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -418,6 +418,50 @@ ps55_model_50t_read(uint16_t port) return 0xff; } +static uint8_t +ps55_model_50v_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return ps2.planar_id & 0xff; + case 0x101: + return ps2.planar_id >> 8; + case 0x102: + return ps2.option[0]; + case 0x103: + uint8_t val = 0xff; + /* + I/O 103h - Bit 7-4: Reserved + Bit 3-0: Memory Card ID (Connector 3 or 1) + + Memory Card ID: 8h = 4 MB Memory Card IV Installed + Fh = No Card Installed + */ + switch (mem_size / 1024) + { + case 4: + if (ps2.option[1] & 0x04) val = 0xff; + else val = 0xf8; + break; + case 8: + default: + if (ps2.option[1] & 0x04) val = 0xf8; + else val = 0xf8; + break; + } + return val; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} static void model_50_write(uint16_t port, uint8_t val) { @@ -716,7 +760,7 @@ model_80_write(uint16_t port, uint8_t val) } static void -ps55_model_50t_write(uint16_t port, uint8_t val)//pcem55 +ps55_model_50tv_write(uint16_t port, uint8_t val) { ps2_mca_log(" Write SysBrd %04X %02X %04X:%04X\n", port, val, cs >> 4, cpu_state.pc); switch (port) @@ -1382,6 +1426,62 @@ mem_encoding_write_cached(uint16_t addr, uint8_t val, UNUSED(void *priv)) } } +static void +mem_encoding_write_cached_ps55(uint16_t addr, uint8_t val, UNUSED(void *priv)) +{ + uint8_t old; + + switch (addr) { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + case 0xe2: + old = ps2.mem_regs[2]; + ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88); + if (val & 2) { + ps2_mca_log("Clear latch - %i\n", ps2.pending_cache_miss); + if (ps2.pending_cache_miss) + ps2.mem_regs[2] |= 0x80; + else + ps2.mem_regs[2] &= ~0x80; + ps2.pending_cache_miss = 0; + } + + if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20) + ps2.pending_cache_miss = 1; + if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01) + ps2_cache_clean(); +#if 1 + // FIXME: Look into this!!! + if (val & 0x01) + ram_mid_mapping.flags |= MEM_MAPPING_ROM_WS; + else + ram_mid_mapping.flags &= ~MEM_MAPPING_ROM_WS; +#endif + break; + + default: + break; + } + ps2_mca_log("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS, cpu_state.pc, ps2.mem_regs[1], ps2.mem_regs[2]); + mem_encoding_update(); + if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20) { + mem_mapping_disable(&ram_low_mapping); + mem_mapping_enable(&ps2.cache_mapping); + flushmmucache(); + } else { + mem_mapping_disable(&ps2.cache_mapping); + mem_mapping_enable(&ram_low_mapping); + flushmmucache(); + } + if (ps2.option[2] & 1) /* reset memstate for E0000 - E0FFFh hole */ + { + mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } +} static void ps2_mca_board_model_70_type34_init(int is_type4, int slots) { @@ -1750,7 +1850,7 @@ ps55_mca_board_model_50t_init() device_add(&keyboard_ps2_mca_1_device); ps2.planar_read = ps55_model_50t_read; - ps2.planar_write = ps55_model_50t_write; + ps2.planar_write = ps55_model_50tv_write; device_add(&ps2_nvr_device); @@ -1790,6 +1890,51 @@ ps55_mca_board_model_50t_init() ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device); } +void +ps55_mca_board_model_50v_init() +{ + ps2_mca_board_common_init(); + + //mem_remap_top(256); + ps2.split_addr = mem_size * 1024; + /* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */ + mca_init(5); + device_add(&keyboard_ps2_mca_1_device); + + ps2.planar_read = ps55_model_50v_read; + ps2.planar_write = ps55_model_50tv_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0002, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached_ps55, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + ps2.option[2] &= 0xf2; /* Bit 3-2: -Cache IDs, Bit 1: Reserved + Bit 0: Disable E0000-E0FFFh (4 KB) */ + + mem_mapping_add(&ps2.split_mapping, + (mem_size + 256) * 1024, + 256 * 1024, + ps2_read_split_ram, + ps2_read_split_ramw, + ps2_read_split_raml, + ps2_write_split_ram, + ps2_write_split_ramw, + ps2_write_split_raml, + &ram[0xa0000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.split_mapping); + + if (mem_size > 8192) { + /* Only 8 MB supported on planar, create a memory expansion card for the rest */ + ps2_mca_mem_fffc_init(8); + } + + if (gfxcard[0] == VID_INTERNAL) + ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device); +} + int machine_ps55_model_50t_init(const machine_t* model) { @@ -1814,3 +1959,28 @@ machine_ps55_model_50t_init(const machine_t* model) return ret; } + +int +machine_ps55_model_50v_init(const machine_t* model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/ibmps55_m50v/56F7416.BIN", + "roms/machines/ibmps55_m50v/56F7417.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_ps2_common_init(model); + + /* + * Planar ID + * F1FFh - PS/55 model 5551-V0x, V1x + * POST (P/N 38F6933) determination: FBxx -> 5 slots (ok), F1xx -> 5 slots (ok), others -> 8 (error) + */ + ps2.planar_id = 0xf1ff; + ps55_mca_board_model_50v_init(); + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c005c9282..bb0f0cd80 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5508,6 +5508,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has IBM PS/55 5551-V0x, V1x firmware. */ + { + .name = "[MCA] IBM PS/55 model 5550-V0", + .internal_name = "ibmps55_m50v", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_ps55_model_50v_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_486BL, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_MCA, + .flags = MACHINE_VIDEO | MACHINE_APM, + .ram = { + .min = 4096, + .max = 16384, + .step = 4096 + }, + .nvrmask = 63, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 386DX/486 machines */ /* Has AMIKey F KBC firmware. */ diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 6d4f43ca6..610e272fb 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -60,6 +60,7 @@ //#define DA2_DCONFIG_FONT_HANS 2 /* for Code page 936 Simplified Chinese */ #define DA2_DCONFIG_FONT_HANT 3 /* for Code page 938 Traditional Chinese */ #define DA2_DCONFIG_MONTYPE_COLOR 0x0A +#define DA2_DCONFIG_MONTYPE_8515 0x0B #define DA2_DCONFIG_MONTYPE_MONO 0x09 #define DA2_BLT_CIDLE 0 @@ -104,9 +105,7 @@ | EFD8h | Display Adapter /J | | | X | X | X | */ /* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ -//2501 -//2500 mono -#define OldLSI 0x20 /* DA-2 or DA-3,5 */ +#define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ //#define Mon_ID3 0x10 #define FontCard 0x08 /* ? */ /* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ @@ -122,8 +121,8 @@ /* Monitor ID (imported from OS/2 DDK 1.2) */ //#define StarbuckC 0x0A //1 010b IBM 8514, 9518 color 1040x768 //#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale -//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4pp -//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 B palette +//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp +//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B /* DA2 Registers (imported from OS/2 DDK) */ #define AC_REG 0x3EE @@ -277,8 +276,6 @@ typedef struct da2_t int fctladdr; int crtcaddr; - uint8_t miscout; - uint32_t decode_mask; uint32_t vram_max; uint32_t vram_mask; @@ -319,8 +316,6 @@ typedef struct da2_t pc_timer_t timer; uint64_t da2const; - //uint8_t scrblank; - int dispon; int hdisp_on; @@ -346,7 +341,6 @@ typedef struct da2_t uint8_t *changedvram; /* (vram size - 1) >> 3 = 0x1FFFF */ uint32_t vram_display_mask; - uint32_t banked_mask; //uint32_t write_bank, read_bank; @@ -364,16 +358,9 @@ typedef struct da2_t int enable; mem_mapping_t mapping; uint8_t ram[256 * 1024]; - uint8_t font[DA2_FONTROM_SIZE]; + uint8_t *font; } mmio; - //mem_mapping_t linear_mapping; - - //uint32_t bank[2]; - //uint32_t mask; - - //int type; - struct { int bitshift_destr; int raster_op; @@ -2295,7 +2282,8 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.ram[addr]; break; case 0x10://Font ROM - //if (addr >= 0x180000) addr -= 0x40000; + if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; + if (addr >= 0x180000) addr -= 0x40000; if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return da2->mmio.font[addr]; @@ -2975,8 +2963,8 @@ da2_reset(void* priv) da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ - da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA - 2, 1024 KB */ - da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 2); /* Configuration 1 : Monitor ID 3 */ + da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ + da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ da2->fctl[0] = 0x2b; /* 3E3h:0 */ da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ @@ -3019,7 +3007,8 @@ static void *da2_init() da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ - int fonttype = device_get_config_int("font"); + int fonttype = device_get_config_int("charset"); + da2->mmio.font= malloc(DA2_FONTROM_SIZE); switch(fonttype) { case DA2_DCONFIG_FONT_HANT: @@ -3142,6 +3131,7 @@ void da2_close(void *p) free(da2->cram); free(da2->vram); free(da2->changedvram); + free(da2->mmio.font); free(da2); } @@ -3162,17 +3152,17 @@ void da2_force_redraw(void *p) static const device_config_t da2_configuration[] = { // clang-format off { - .name = "font", + .name = "charset", .description = "Charset", .type = CONFIG_SELECTION, .default_int = DA2_DCONFIG_FONT_JPAN, .selection = { { - .description = "CP932 (Japanese)", + .description = "932 (Japanese)", .value = DA2_DCONFIG_FONT_JPAN }, { - .description = "CP938 (Traditional Chinese)", + .description = "938 (Traditional Chinese)", .value = DA2_DCONFIG_FONT_HANT }, { .description = "" } @@ -3188,6 +3178,10 @@ static const device_config_t da2_configuration[] = { .description = "Color", .value = DA2_DCONFIG_MONTYPE_COLOR }, + { + .description = "IBM 8515", + .value = DA2_DCONFIG_MONTYPE_8515 + }, { .description = "Grayscale", .value = DA2_DCONFIG_MONTYPE_MONO From eeb10651da407af167026ac7f47235a5c7af7684 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:08:45 +0900 Subject: [PATCH 0227/1190] the prev change must be restricted in CN fontset --- src/video/vid_ps55da2.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 610e272fb..011a9633f 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -55,10 +55,10 @@ #define DA2_DEBUG_BLTLOG_MAX 256*1024 #define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe #define DA2_DEBUG_BLT_USEDRESET 0xfefefe -#define DA2_DCONFIG_FONT_JPAN 0 /* for Code page 932 Japanese */ -//#define DA2_DCONFIG_FONT_HANG 1 /* for Code page 934 Hangul */ -//#define DA2_DCONFIG_FONT_HANS 2 /* for Code page 936 Simplified Chinese */ -#define DA2_DCONFIG_FONT_HANT 3 /* for Code page 938 Traditional Chinese */ +#define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ +//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ +//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ +#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ #define DA2_DCONFIG_MONTYPE_COLOR 0x0A #define DA2_DCONFIG_MONTYPE_8515 0x0B #define DA2_DCONFIG_MONTYPE_MONO 0x09 @@ -359,6 +359,7 @@ typedef struct da2_t mem_mapping_t mapping; uint8_t ram[256 * 1024]; uint8_t *font; + int charset; } mmio; struct { @@ -2282,8 +2283,11 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.ram[addr]; break; case 0x10://Font ROM - if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; - if (addr >= 0x180000) addr -= 0x40000; + if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { + if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; + if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, + but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ + } if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return da2->mmio.font[addr]; @@ -3007,14 +3011,14 @@ static void *da2_init() da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ - int fonttype = device_get_config_int("charset"); + da2->mmio.charset = device_get_config_int("charset"); da2->mmio.font= malloc(DA2_FONTROM_SIZE); - switch(fonttype) + switch(da2->mmio.charset) { - case DA2_DCONFIG_FONT_HANT: + case DA2_DCONFIG_CHARSET_HANT: da2_loadfont(DA2_FONTROM_PATH_HANT, da2); break; - case DA2_DCONFIG_FONT_JPAN: + case DA2_DCONFIG_CHARSET_JPAN: da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); break; } @@ -3155,15 +3159,15 @@ static const device_config_t da2_configuration[] = { .name = "charset", .description = "Charset", .type = CONFIG_SELECTION, - .default_int = DA2_DCONFIG_FONT_JPAN, + .default_int = DA2_DCONFIG_CHARSET_JPAN, .selection = { { .description = "932 (Japanese)", - .value = DA2_DCONFIG_FONT_JPAN + .value = DA2_DCONFIG_CHARSET_JPAN }, { .description = "938 (Traditional Chinese)", - .value = DA2_DCONFIG_FONT_HANT + .value = DA2_DCONFIG_CHARSET_HANT }, { .description = "" } } From 109a913bf58cedae4c4010b0dca4953fed4ea430 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Tue, 11 Feb 2025 12:02:47 -0500 Subject: [PATCH 0228/1190] Remove duplicate .close in scsi_t228_device --- src/scsi/scsi_t128.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 77c2302cc..a40d803f1 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -616,7 +616,6 @@ const device_t scsi_t128_device = { .config = t128_config }; - const device_t scsi_t228_device = { .name = "Trantor T228", .internal_name = "t228", @@ -624,7 +623,6 @@ const device_t scsi_t228_device = { .local = 0, .init = t128_init, .close = t128_close, - .close = t128_close, .reset = NULL, .available = t128_available, .speed_changed = NULL, From d075d0d3c9c9976798c5ed9b6eee6daf9fa23773 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Feb 2025 03:20:12 +0100 Subject: [PATCH 0229/1190] Default host_serial_path to empty string instead of NULL, fixes segmentation fault on initilization of serial passthrough with non-initialized string. --- src/device/serial_passthrough.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 256f9eaa9..3da2e09ff 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -260,7 +260,7 @@ static const device_config_t serial_passthrough_config[] = { .name = "host_serial_path", .description = "Host Serial Device", .type = CONFIG_SERPORT, - .default_string = NULL, + .default_string = "", .default_int = 0, .file_filter = NULL, .spinner = { 0 }, From 90ba9eda084b942c28a7ffe631819dafd1a09f55 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Feb 2025 05:18:12 +0100 Subject: [PATCH 0230/1190] Fixes to the device and machine configuration string getters and accordingly reverted the serial passthrough fix as well as it's no longer needed. --- src/device.c | 47 +++++++++++++++++++++------------ src/device/serial_passthrough.c | 2 +- src/include/86box/device.h | 33 ++++++++--------------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/device.c b/src/device.c index d7c80be7a..fa7378c1a 100644 --- a/src/device.c +++ b/src/device.c @@ -637,16 +637,24 @@ device_get_instance(void) const char * device_get_config_string(const char *str) { - const device_config_t *cfg = device_current.dev->config; + const char *ret = ""; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_string((char *) device_current.name, (char *) str, (char *) cfg->default_string)); + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - cfg++; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + const char *s = (config_get_string((char *) device_current.name, + (char *) str, (char *) cfg->default_string)); + ret = (s == NULL) ? "" : s; + break; + } + + cfg++; + } } - return (NULL); + return ret; } int @@ -870,24 +878,29 @@ machine_get_config_int(char *str) return 0; } -char * +const char * machine_get_config_string(char *str) { - const device_t *dev = machine_get_device(machine); - const device_config_t *cfg; + const device_t *dev = machine_get_device(machine); + const char *ret = ""; - if (dev == NULL) - return 0; + if (dev != NULL) { + const device_config_t *cfg; - cfg = dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_string((char *) dev->name, str, (char *) cfg->default_string)); + cfg = dev->config; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + const char *s = config_get_string((char *) dev->name, str, + (char *) cfg->default_string); + ret = (s == NULL) ? "" : s; + break; + } - cfg++; + cfg++; + } } - return NULL; + return ret; } const device_t * diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 3da2e09ff..256f9eaa9 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -260,7 +260,7 @@ static const device_config_t serial_passthrough_config[] = { .name = "host_serial_path", .description = "Host Serial Device", .type = CONFIG_SERPORT, - .default_string = "", + .default_string = NULL, .default_int = 0, .file_filter = NULL, .spinner = { 0 }, diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 1c2ec5203..b5a4c1925 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -118,16 +118,6 @@ enum { #define BIOS_INTERLEAVED_INVERT 8 #define BIOS_HIGH_BIT_INVERT 16 -#define device_common_config_t \ - const char *name; \ - const char *description; \ - int type; \ - const char *default_string; \ - int default_int; \ - const char *file_filter; \ - const device_config_spinner_t spinner; \ - const device_config_selection_t selection[32] - typedef struct device_config_selection_t { const char *description; int value; @@ -139,10 +129,6 @@ typedef struct device_config_spinner_t { int16_t step; } device_config_spinner_t; -typedef struct _device_dep_config_ { - device_common_config_t; -} device_dep_config_t; - typedef struct device_config_bios_t { const char *name; const char *internal_name; @@ -153,15 +139,18 @@ typedef struct device_config_bios_t { void *dev1; void *dev2; const char *files[9]; - /* Configuration options that depend on the device variant. - To prevent excessive nesting, there is no CONFIG_BIOS - option a dep_config struct */ - const device_dep_config_t *dep_config; } device_config_bios_t; typedef struct _device_config_ { - device_common_config_t; - const device_config_bios_t bios[32]; + const char *name; + const char *description; + int type; + const char *default_string; + int default_int; + const char *file_filter; + const device_config_spinner_t spinner; + const device_config_selection_t selection[32]; + const device_config_bios_t bios[32]; } device_config_t; typedef struct _device_ { @@ -242,8 +231,8 @@ extern int device_get_instance(void); extern const char *device_get_internal_name(const device_t *dev); -extern int machine_get_config_int(char *str); -extern char *machine_get_config_string(char *str); +extern int machine_get_config_int(char *str); +extern const char *machine_get_config_string(char *str); extern const device_t device_none; extern const device_t device_internal; From af476f957c4c109927eaff390c83fb31598e1ff7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 00:09:03 +0100 Subject: [PATCH 0231/1190] Some const changes in the FDD code. --- src/floppy/fdd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index a381f67f1..f0a32df75 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -100,10 +100,10 @@ d86f_handler_t d86f_handler[FDD_NUM]; static const struct { - char *ext; - void (*load)(int drive, char *fn); - void (*close)(int drive); - int size; + const char *ext; + void (*load)(int drive, char *fn); + void (*close)(int drive); + int size; } loaders[] = { { "001", img_load, img_close, -1}, { "002", img_load, img_close, -1}, From 48065193884b075f68edecd3dfc7e05c11556f6e Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 00:23:35 +0100 Subject: [PATCH 0232/1190] The device_t available/poll union is now gone, mouse poll is now set using mouse_set_poll(), and mouse_curr is now also gone. --- src/cdrom/cdrom.c | 2 +- src/device/mouse.c | 32 +++++------------------ src/device/mouse_bus.c | 8 +++--- src/device/mouse_microtouch_touchscreen.c | 3 ++- src/device/mouse_ps2.c | 4 ++- src/device/mouse_serial.c | 8 +++--- src/device/mouse_wacom_tablet.c | 10 ++++--- src/device/serial_passthrough.c | 2 +- src/include/86box/device.h | 6 ++--- src/network/net_modem.c | 2 +- 10 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 2cdcc5a22..8ebcfea1f 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -103,7 +103,7 @@ static const device_t cdrom_interface_none_device = { .init = NULL, .close = NULL, .reset = NULL, - { .available = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL diff --git a/src/device/mouse.c b/src/device/mouse.c index 604109668..f0446d781 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -61,7 +61,7 @@ static const device_t mouse_none_device = { .init = NULL, .close = NULL, .reset = NULL, - { .poll = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -75,7 +75,7 @@ static const device_t mouse_internal_device = { .init = NULL, .close = NULL, .reset = NULL, - { .poll = NULL }, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -111,7 +111,6 @@ static atomic_int mouse_buttons; static int mouse_delta_b; static int mouse_old_b; -static const device_t *mouse_curr; static void *mouse_priv; static int mouse_nbut; static int mouse_raw; @@ -537,17 +536,10 @@ mouse_get_abs_coords(double *x_abs, double *y_abs) void mouse_process(void) { - if (mouse_curr == NULL) - return; - if ((mouse_input_mode >= 1) && mouse_poll_ex) mouse_poll_ex(); - else if ((mouse_input_mode == 0) && ((mouse_dev_poll != NULL) || (mouse_curr->poll != NULL))) { - if (mouse_curr->poll != NULL) - mouse_curr->poll(mouse_priv); - else - mouse_dev_poll(mouse_priv); - } + else if ((mouse_input_mode == 0) && (mouse_dev_poll != NULL)) + mouse_dev_poll(mouse_priv); } void @@ -559,9 +551,6 @@ mouse_set_poll_ex(void (*poll_ex)(void)) void mouse_set_poll(int (*func)(void *), void *arg) { - if (mouse_type != MOUSE_TYPE_INTERNAL) - return; - mouse_dev_poll = func; mouse_priv = arg; } @@ -629,7 +618,7 @@ mouse_set_raw(int raw) void mouse_reset(void) { - if (mouse_curr != NULL) + if (mouse_priv != NULL) return; /* Mouse already initialized. */ mouse_log("MOUSE: reset(type=%d, '%s')\n", @@ -651,19 +640,13 @@ mouse_reset(void) sample_rate = 100.0; timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); - mouse_curr = mouse_devices[mouse_type].device; - - if ((mouse_type > 1) && (mouse_curr != NULL)) - mouse_priv = device_add(mouse_curr); + if ((mouse_type > 1) && (mouse_devices[mouse_type].device != NULL)) + mouse_priv = device_add(mouse_devices[mouse_type].device); } void mouse_close(void) { - if (mouse_curr == NULL) - return; - - mouse_curr = NULL; mouse_priv = NULL; mouse_nbut = 0; mouse_dev_poll = NULL; @@ -680,7 +663,6 @@ mouse_init(void) mouse_clear_buttons(); mouse_type = MOUSE_TYPE_NONE; - mouse_curr = NULL; mouse_priv = NULL; mouse_nbut = 0; mouse_dev_poll = NULL; diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index c0f161dbd..7074a71ac 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -680,6 +680,8 @@ bm_init(const device_t *info) mouse_set_sample_rate(0.0); + mouse_set_poll(bm_poll, dev); + return dev; } @@ -818,7 +820,7 @@ const device_t mouse_logibus_device = { .init = bm_init, .close = bm_close, .reset = NULL, - .poll = bm_poll, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = lt_config @@ -832,7 +834,7 @@ const device_t mouse_logibus_onboard_device = { .init = bm_init, .close = bm_close, .reset = NULL, - .poll = bm_poll, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = NULL @@ -846,7 +848,7 @@ const device_t mouse_msinport_device = { .init = bm_init, .close = bm_close, .reset = NULL, - .poll = bm_poll, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ms_config diff --git a/src/device/mouse_microtouch_touchscreen.c b/src/device/mouse_microtouch_touchscreen.c index 15b42bfdd..512fcc0df 100644 --- a/src/device/mouse_microtouch_touchscreen.c +++ b/src/device/mouse_microtouch_touchscreen.c @@ -525,6 +525,7 @@ mtouch_init(UNUSED(const device_t *info)) mouse_input_mode = device_get_config_int("crosshair") + 1; mouse_set_buttons(2); + mouse_set_poll(mtouch_poll, dev); mouse_set_poll_ex(mtouch_poll_global); mtouch_inst = dev; @@ -605,7 +606,7 @@ const device_t mouse_mtouch_device = { .init = mtouch_init, .close = mtouch_close, .reset = NULL, - .poll = mtouch_poll, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = mtouch_config diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 9afc75410..8d98b07ce 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -352,6 +352,8 @@ mouse_ps2_init(const device_t *info) if (dev->port != NULL) kbc_at_dev_reset(dev, 0); + mouse_set_poll(ps2_poll, dev); + /* Return our private data to the I/O layer. */ return dev; } @@ -397,7 +399,7 @@ const device_t mouse_ps2_device = { .init = mouse_ps2_init, .close = ps2_close, .reset = NULL, - .poll = ps2_poll, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ps2_config diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index be9bc62e1..96d3a867c 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -909,6 +909,8 @@ sermouse_init(const device_t *info) /* Tell them how many buttons we have. */ mouse_set_buttons(dev->but); + mouse_set_poll(sermouse_poll, dev); + /* Return our private data to the I/O layer. */ return dev; } @@ -1075,7 +1077,7 @@ const device_t mouse_mssystems_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - .poll = sermouse_poll, + .available = NULL, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = msssermouse_config @@ -1089,7 +1091,7 @@ const device_t mouse_msserial_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - .poll = sermouse_poll, + .available = NULL, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = mssermouse_config @@ -1103,7 +1105,7 @@ const device_t mouse_ltserial_device = { .init = sermouse_init, .close = sermouse_close, .reset = NULL, - .poll = sermouse_poll, + .available = NULL, .speed_changed = sermouse_speed_changed, .force_redraw = NULL, .config = ltsermouse_config diff --git a/src/device/mouse_wacom_tablet.c b/src/device/mouse_wacom_tablet.c index 79b674e07..3b50882ab 100644 --- a/src/device/mouse_wacom_tablet.c +++ b/src/device/mouse_wacom_tablet.c @@ -662,8 +662,10 @@ wacom_init(const device_t *info) if (dev->tablet_type->type == WACOM_TYPE_IV) { wacom_reset_artpad(dev); wacom_process_settings_dword(dev, 0xE2018000); - } - else wacom_reset(dev); + } else + wacom_reset(dev); + + mouse_set_poll(wacom_poll, dev); return dev; } @@ -721,7 +723,7 @@ const device_t mouse_wacom_device = { .init = wacom_init, .close = wacom_close, .reset = NULL, - .poll = wacom_poll, + .available = NULL, .speed_changed = wacom_speed_changed, .force_redraw = NULL, .config = wacom_config @@ -735,7 +737,7 @@ const device_t mouse_wacom_artpad_device = { .init = wacom_init, .close = wacom_close, .reset = NULL, - .poll = wacom_poll, + .available = NULL, .speed_changed = wacom_speed_changed, .force_redraw = NULL, .config = wacom_config diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 256f9eaa9..3ad969006 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -366,7 +366,7 @@ const device_t serial_passthrough_device = { .init = serial_passthrough_dev_init, .close = serial_passthrough_dev_close, .reset = NULL, - .poll = NULL, + .available = NULL, .speed_changed = serial_passthrough_speed_changed, .force_redraw = NULL, .config = serial_passthrough_config diff --git a/src/include/86box/device.h b/src/include/86box/device.h index b5a4c1925..479e4cbb6 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -165,10 +165,8 @@ typedef struct _device_ { }; void (*close)(void *priv); void (*reset)(void *priv); - union { - int (*available)(void); - int (*poll)(void *priv); - }; + int (*available)(void); + int (*poll)(void *priv); void (*speed_changed)(void *priv); void (*force_redraw)(void *priv); diff --git a/src/network/net_modem.c b/src/network/net_modem.c index 62621391c..a8eab4290 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1621,7 +1621,7 @@ const device_t modem_device = { .init = modem_init, .close = modem_close, .reset = NULL, - .poll = NULL, + .available = NULL, .speed_changed = modem_speed_changed, .force_redraw = NULL, .config = modem_config From 187a1ca416eb49673cc7a56442d70cb9c992ac68 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 00:45:10 +0100 Subject: [PATCH 0233/1190] The NVR name is now obtained from the selected machine BIOS type if applicable. --- src/86box.c | 6 +++--- src/chipset/sis_5513_p2i.c | 4 ++-- src/device/hwm_lm78.c | 4 ++-- src/include/86box/machine.h | 2 ++ src/machine/m_at_386dx_486.c | 2 +- src/machine/machine_table.c | 23 +++++++++++++++++++++++ src/mem/catalyst_flash.c | 2 +- src/mem/intel_flash.c | 2 +- src/mem/sst_flash.c | 2 +- src/nvr.c | 4 ++-- src/nvr_ps2.c | 4 ++-- 11 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/86box.c b/src/86box.c index 246d06b16..3ade3c4e2 100644 --- a/src/86box.c +++ b/src/86box.c @@ -457,7 +457,7 @@ delete_nvr_file(uint8_t flash) int c; /* Set up the NVR file's name. */ - c = strlen(machine_get_internal_name()) + 5; + c = strlen(machine_get_nvr_name()) + 5; fn = (char *) malloc(c + 1); if (fn == NULL) @@ -465,9 +465,9 @@ delete_nvr_file(uint8_t flash) flash ? "BIOS flash" : "CMOS"); if (flash) - sprintf(fn, "%s.bin", machine_get_internal_name()); + sprintf(fn, "%s.bin", machine_get_nvr_name()); else - sprintf(fn, "%s.nvr", machine_get_internal_name()); + sprintf(fn, "%s.nvr", machine_get_nvr_name()); remove(nvr_path(fn)); diff --git a/src/chipset/sis_5513_p2i.c b/src/chipset/sis_5513_p2i.c index 3655ccc3f..95a890fcf 100644 --- a/src/chipset/sis_5513_p2i.c +++ b/src/chipset/sis_5513_p2i.c @@ -1287,9 +1287,9 @@ sis_5513_pci_to_isa_init(UNUSED(const device_t *info)) acpi_set_nvr(dev->sis->acpi, dev->nvr); /* Set up the NVR file's name. */ - c = strlen(machine_get_internal_name()) + 9; + c = strlen(machine_get_nvr_name()) + 9; dev->fn = (char *) malloc(c + 1); - sprintf(dev->fn, "%s_apc.nvr", machine_get_internal_name()); + sprintf(dev->fn, "%s_apc.nvr", machine_get_nvr_name()); fp = nvr_fopen(dev->fn, "rb"); diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 1e61168ac..909713833 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -102,9 +102,9 @@ lm78_log(const char *fmt, ...) void lm78_nvram(lm78_t *dev, uint8_t save) { - size_t l = strlen(machine_get_internal_name_ex(machine)) + 14; + size_t l = strlen(machine_get_nvr_name_ex(machine)) + 14; char *nvr_path = (char *) malloc(l); - sprintf(nvr_path, "%s_as99127f.nvr", machine_get_internal_name_ex(machine)); + sprintf(nvr_path, "%s_as99127f.nvr", machine_get_nvr_name_ex(machine)); FILE *fp = nvr_fopen(nvr_path, save ? "wb" : "rb"); if (fp) { diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index f39187dd9..1ce46de9b 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -361,6 +361,7 @@ extern int machine_available(int m); extern const char *machine_getname(void); extern const char *machine_getname_ex(int m); extern const char *machine_get_internal_name(void); +extern const char *machine_get_nvr_name(void); extern int machine_get_machine_from_internal_name(const char *s); extern void machine_init(void); #ifdef EMU_DEVICE_H @@ -373,6 +374,7 @@ extern const device_t *machine_get_snd_device(int m); extern const device_t *machine_get_net_device(int m); #endif extern const char *machine_get_internal_name_ex(int m); +extern const char *machine_get_nvr_name_ex(int m); extern int machine_get_nvrmask(int m); extern int machine_has_flags(int m, int flags); extern int machine_has_bus(int m, int bus_flags); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 3d152065b..19c4b535e 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -696,7 +696,7 @@ static const device_config_t pb450_config[] = { .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "PCI 1.0A", .internal_name = "pci10a", .bios_type = BIOS_NORMAL, + { .name = "PCI 1.0A", .internal_name = "pb450" /*"pci10a"*/, .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/OPTI802.bin", "" } }, { .name = "PNP 1.1A", .internal_name = "pnp11a", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/PNP11A.bin", "" } }, diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 458b54013..e6198541e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16565,3 +16565,26 @@ machine_is_sony(void) { return (!strcmp(machines[machine].internal_name, "pcv90")); } + +const char * +machine_get_nvr_name_ex(int m) +{ + const char *ret = machines[m].internal_name; + const device_t *dev = machine_get_device(m); + + if (dev != NULL) { + device_context(dev); + const char *bios = device_get_config_string("bios"); + if ((bios != NULL) && (strcmp(bios, "") != 0)) + ret = bios; + device_context_restore(); + } + + return ret; +} + +const char * +machine_get_nvr_name(void) +{ + return machine_get_nvr_name_ex(machine); +} diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c index fd2bb739f..00e2422a3 100644 --- a/src/mem/catalyst_flash.c +++ b/src/mem/catalyst_flash.c @@ -194,7 +194,7 @@ catalyst_flash_init(UNUSED(const device_t *info)) dev = calloc(1, sizeof(flash_t)); - sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); + sprintf(flash_path, "%s.bin", machine_get_nvr_name_ex(machine)); mem_mapping_disable(&bios_mapping); mem_mapping_disable(&bios_high_mapping); diff --git a/src/mem/intel_flash.c b/src/mem/intel_flash.c index 7375b1f42..e193f3545 100644 --- a/src/mem/intel_flash.c +++ b/src/mem/intel_flash.c @@ -353,7 +353,7 @@ intel_flash_init(const device_t *info) dev = calloc(1, sizeof(flash_t)); - sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); + sprintf(flash_path, "%s.bin", machine_get_nvr_name_ex(machine)); dev->flags = info->local & 0xff; diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index 5a9c9c877..b41e0f2e2 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -507,7 +507,7 @@ sst_init(const device_t *info) FILE *fp; sst_t *dev = calloc(1, sizeof(sst_t)); - sprintf(flash_path, "%s.bin", machine_get_internal_name_ex(machine)); + sprintf(flash_path, "%s.bin", machine_get_nvr_name_ex(machine)); mem_mapping_disable(&bios_mapping); mem_mapping_disable(&bios_high_mapping); diff --git a/src/nvr.c b/src/nvr.c index d0b05b93a..7f43a76c1 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -161,9 +161,9 @@ nvr_init(nvr_t *nvr) int c; /* Set up the NVR file's name. */ - c = strlen(machine_get_internal_name()) + 5; + c = strlen(machine_get_nvr_name()) + 5; nvr->fn = (char *) malloc(c + 1); - sprintf(nvr->fn, "%s.nvr", machine_get_internal_name()); + sprintf(nvr->fn, "%s.nvr", machine_get_nvr_name()); /* Initialize the internal clock as needed. */ memset(&intclk, 0x00, sizeof(intclk)); diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 3ca0b0ba5..febf6c165 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -122,9 +122,9 @@ ps2_nvr_init(const device_t *info) nvr->size = 8192; /* Set up the NVR file's name. */ - c = strlen(machine_get_internal_name()) + 9; + c = strlen(machine_get_nvr_name()) + 9; nvr->fn = (char *) malloc(c + 1); - sprintf(nvr->fn, "%s_sec.nvr", machine_get_internal_name()); + sprintf(nvr->fn, "%s_sec.nvr", machine_get_nvr_name()); io_sethandler(0x0074, 3, ps2_nvr_read, NULL, NULL, ps2_nvr_write, NULL, NULL, nvr); From 8ffdff2bd4825f2a09c53d23d9e1778b80eb7812 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 00:52:34 +0100 Subject: [PATCH 0234/1190] Generic Xt memory expansion: Allow starting at 640k. --- src/device/isamem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/isamem.c b/src/device/isamem.c index 45a0413be..62fb96f5d 100644 --- a/src/device/isamem.c +++ b/src/device/isamem.c @@ -1024,7 +1024,7 @@ static const device_config_t genericxt_config[] = { .file_filter = NULL, .spinner = { .min = 0, - .max = 624, + .max = 640, .step = 16 }, .selection = { { 0 } }, From 30ca057519af1995cfc07c81d28cf5676f7d2ad8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 01:06:40 +0100 Subject: [PATCH 0235/1190] Removed the last remnants of device_t.poll(). --- src/device.c | 15 --------------- src/device/keyboard_at.c | 2 +- src/include/86box/device.h | 2 -- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/device.c b/src/device.c index fa7378c1a..dad583cdc 100644 --- a/src/device.c +++ b/src/device.c @@ -484,21 +484,6 @@ device_has_config(const device_t *dev) return (c > 0) ? 1 : 0; } -int -device_poll(const device_t *dev) -{ - for (uint16_t c = 0; c < DEVICE_MAX; c++) { - if (devices[c] != NULL) { - if (devices[c] == dev) { - if (devices[c]->poll) - return (devices[c]->poll(device_priv[c])); - } - } - } - - return 0; -} - void device_get_name(const device_t *dev, int bus, char *name) { diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 9b3f06098..589ec7ded 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2221,7 +2221,7 @@ const device_t keyboard_at_generic_device = { .init = keyboard_at_init, .close = keyboard_at_close, .reset = NULL, - .poll = NULL, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = keyboard_at_config diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 479e4cbb6..d92a387e9 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -166,7 +166,6 @@ typedef struct _device_ { void (*close)(void *priv); void (*reset)(void *priv); int (*available)(void); - int (*poll)(void *priv); void (*speed_changed)(void *priv); void (*force_redraw)(void *priv); @@ -203,7 +202,6 @@ extern void device_reset_all(uint32_t match_flags); extern void *device_find_first_priv(uint32_t match_flags); extern void *device_get_priv(const device_t *dev); extern int device_available(const device_t *dev); -extern int device_poll(const device_t *dev); extern void device_speed_changed(void); extern void device_force_redraw(void); extern void device_get_name(const device_t *dev, int bus, char *name); From 9a1ae5997fe3d63941aed2ecbb9cc771fc95604c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 01:44:10 +0100 Subject: [PATCH 0236/1190] Fixed ATAPI transfer split by sectors and improved the performance of IOCTL by making it no longer constantly open and close the handle. --- src/cdrom/cdrom.c | 6 ++---- src/disk/hdc_ide.c | 1 - src/qt/win_cdrom_ioctl.c | 17 ----------------- src/scsi/scsi_cdrom.c | 16 ++++++++++------ 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 9f3b6e079..aab6cf67c 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2822,9 +2822,7 @@ cdrom_update_status(cdrom_t *dev) dev->seek_pos = 0; dev->cd_buflen = 0; - if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) - dev->cd_status = CD_STATUS_EMPTY; - else if (dev->ops->is_dvd(dev->local)) + if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : @@ -3048,7 +3046,7 @@ cdrom_is_empty(const uint8_t id) int ret = 0; /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) + if ((strlen(dev->image_path) == 0) || (dev->cd_status == CD_STATUS_EMPTY)) /* Switch from empty to empty. Do nothing. */ ret = 1; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index e367f73b0..d42a595df 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,7 +241,6 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -#define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 3d9ecefd5..8da62a49d 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -124,12 +124,10 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) ioctl->cur_read_toc_ex.Msf = 1; ioctl->cur_read_toc_ex.SessionTrack = 1; - ioctl_open_handle(ioctl); const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, cur_full_toc, 65535, (LPDWORD) &size, NULL); - ioctl_close_handle(ioctl); ioctl_log(ioctl->log, "temp = %i\n", temp); if (temp != 0) { @@ -178,12 +176,10 @@ ioctl_read_raw_toc(ioctl_t *ioctl) ioctl->cur_read_toc_ex.Msf = 1; ioctl->cur_read_toc_ex.SessionTrack = 1; - ioctl_open_handle(ioctl); const int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, &ioctl->cur_read_toc_ex, 65535, cur_full_toc, 65535, (LPDWORD) &size, NULL); - ioctl_close_handle(ioctl); ioctl_log(ioctl->log, "status = %i\n", status); if ((status == 0) && (ioctl->tracks_num >= 1)) { @@ -384,8 +380,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) int ret; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - if (ioctl->is_dvd) { int track; @@ -517,8 +511,6 @@ ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector) for (int j = 7; j >= 0; j--) buffer[2352 + (i * 8) + j] = ((buffer[sc_offs + i] >> (7 - j)) & 0x01) << 6; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -587,8 +579,6 @@ ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t f const int len = 2052; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); req.spt.PathId = 0; @@ -650,8 +640,6 @@ ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t f } else ret = ret ? (req.spt.DataTransferLength >= len) : 0; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -684,8 +672,6 @@ ioctl_is_empty(const void *local) unsigned long int unused = 0; SCSI_PASS_THROUGH_DIRECT_BUF req; - ioctl_open_handle((ioctl_t *) ioctl); - memset(&req, 0x00, sizeof(SCSI_PASS_THROUGH_DIRECT_BUF)); req.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); req.spt.PathId = 0; @@ -745,8 +731,6 @@ ioctl_is_empty(const void *local) } else ret = 0; - ioctl_close_handle((ioctl_t *) ioctl); - return ret; } @@ -774,7 +758,6 @@ ioctl_load(const void *local) DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, (LPDWORD) &size, NULL); - ioctl_close_handle((ioctl_t *) ioctl); ioctl_read_toc((ioctl_t *) ioctl); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8a39edb39..53a079d6a 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,7 +15,6 @@ */ #include #include -#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -704,8 +703,11 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) if (dev->was_cached == -1) period *= (double) dev->packet_len; else { - period *= ((double) dev->requested_blocks) * 2352.0; - pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, dev->requested_blocks); + const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; + + period *= ((double) num) * 2352.0; + pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -1041,8 +1043,10 @@ static int scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int flags, const int vendor_type) { - int temp_len = 0; - int ret = 0; + int temp_len = 0; + int ret = 0; + const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); @@ -1051,7 +1055,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int ret = -1; } else { ret = 1; - for (int i = 0; (i < dev->requested_blocks) && (ret > 0); i++) { + for (int i = 0; (i < num) && (ret > 0); i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, dev->sector_pos, msf, type, flags, &temp_len, vendor_type); From 8a66dbef372b1f06f107f8514fc41105380f52cb Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:28:05 +0100 Subject: [PATCH 0237/1190] Fixed ATAPI PIO operation and ATAPI DMA timings. --- src/disk/hdc_ide.c | 116 ++++++++++++++++++++++++++++++++---------- src/scsi/scsi_cdrom.c | 62 ++++++++++++---------- 2 files changed, 125 insertions(+), 53 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index d42a595df..8559d7a63 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,6 +241,7 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); +// #define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1091,6 +1092,7 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: + pclog("Reading block %i... ", ide->sc->sector_len + 1); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) @@ -1114,13 +1116,16 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: + pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: + pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: + pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1130,6 +1135,7 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: + pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); @@ -1193,21 +1199,15 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_irq_lower(ide); - ide->tf->atastat = BSY_STAT; + ide->tf->atastat = BSY_STAT; if (ide->tf->pos >= dev->packet_len) { ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); ide->tf->pos = dev->request_pos = 0; - if (dev->block_len != 0) { - if (out && (ide->write != NULL)) - ide->write(dev); - else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) - ide->read(dev); - } - - if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (dev->block_len == 0) { + // pclog("ide_atapi_pio_request(): Processing instant command...\n"); if (out && (ide->phase_data_out != NULL)) ide->phase_data_out(dev); else if (!out && (ide->command_stop != NULL)) @@ -1237,22 +1237,62 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->packet_status = PHASE_DATA_IN | out; - if (dev->block_len != 0) { - if (out && (ide->write != NULL)) - ide->write(dev); - else if (!out && (dev->sector_len != 0) && (ide->read != NULL)) - ide->read(dev); - } - - ide->tf->atastat = BSY_STAT; - ide->tf->phase = 1; - - if ((dev->block_len == 0) || (dev->sector_len == 0)) { + if (dev->block_len == 0) { ide_atapi_callback(ide); ide_set_callback(ide, 0.0); } - dev->request_pos = 0; + dev->request_pos = 0; + } + + if (dev->block_len != 0) { + if (out) { + if (ide->write != NULL) { +#if 0 + pclog("ide_atapi_pio_request(): Continuing write command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->write(dev); + } + + if (dev->sector_len == 0) { +#if 0 + pclog("ide_atapi_pio_request(): Ending write command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(dev); + + ide_atapi_callback(ide); + } + } else { + if (dev->sector_len == 0) { +#if 0 + pclog("ide_atapi_pio_request(): Ending read command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + if (ide->command_stop != NULL) + ide->command_stop(dev); + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + ide_atapi_callback(ide); + } else if (ide->read != NULL) { +#if 0 + pclog("ide_atapi_pio_request(): Continuing read command " + "(dev->sector_len = %i)...\n", dev->sector_len); +#endif + + ide->read(dev); + } + } } } @@ -1284,11 +1324,27 @@ ide_atapi_packet_read(ide_t *ide) (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); - } else if ((dev->block_len != 0) && + } +#if 0 + else if ((dev->block_len != 0) && (dev->sector_len != 0) && - ((dev->request_pos % dev->block_len) == 0) && - (ide->read != NULL)) - ide->read(dev); + ((dev->request_pos % dev->block_len) == 0)) { + if (dev->sector_len == 0) { + // pclog("ide_atapi_packet_read(): Ending read command (dev->sector_len = %i)...\n", dev->sector_len); + + if (ide->command_stop != NULL) + ide->command_stop(ide->sc); + + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; + + ide_atapi_callback(ide); + } else if (ide->read != NULL) { + // pclog("ide_atapi_packet_read(): Continuing read command (dev->sector_len = %i)...\n", dev->sector_len); + ide->read(dev); + } + } +#endif } return ret; @@ -1322,10 +1378,16 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) (ide->tf->pos >= dev->packet_len)) { /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); - } else if ((dev->block_len != 0) && + } +#if 0 + else if ((dev->block_len != 0) && ((dev->request_pos % dev->block_len) == 0) && - (ide->write != NULL)) + (ide->write != NULL)) { + // pclog("ide_atapi_packet_write(): Continuing write command (dev->sector_len = %i)...\n", dev->sector_len); + ide->write(dev); + } +#endif } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 53a079d6a..21ea9ce16 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,6 +15,7 @@ */ #include #include +// #define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -611,8 +612,8 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, const int block_len } } - if (dev->drv->bus_type != CDROM_BUS_SCSI) - dev->requested_blocks = 1; + if ((dev->drv->bus_type != CDROM_BUS_SCSI) && (dev->block_len != 0)) + dev->requested_blocks = (dev->packet_len / dev->block_len); fallthrough; default: @@ -667,9 +668,9 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); - if (dev->packet_status == PHASE_COMPLETE) - dev->callback = 0; - else { + dev->callback = 0; + + if (dev->packet_status != PHASE_COMPLETE) { double bytes_per_second; double period; @@ -689,6 +690,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; + // pclog("Current speed: %ix\n", dev->drv->cur_speed); } else { bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { @@ -703,8 +705,11 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) if (dev->was_cached == -1) period *= (double) dev->packet_len; else { - const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? - dev->requested_blocks : 1; + const int num = ((dev->drv->bus_type == CDROM_BUS_SCSI) || + (dev->block_len == 0)) ? + dev->requested_blocks : + ((scsi_cdrom_current_mode(dev) == 2) ? 1 : + (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); @@ -1045,7 +1050,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int { int temp_len = 0; int ret = 0; - const int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? dev->requested_blocks : 1; if (dev->drv->cd_status == CD_STATUS_EMPTY) @@ -1065,15 +1070,20 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int else if (ret == 0) scsi_cdrom_illegal_mode(dev); else { - if (dev->block_len == 0xffffffff) + if (dev->block_len == 0xffffffff) { dev->block_len = temp_len; + if ((dev->drv->bus_type != CDROM_BUS_SCSI) && + (scsi_cdrom_current_mode(dev) != 2)) + num = (dev->packet_len / dev->block_len); + } + dev->sector_pos++; dev->drv->seek_pos = dev->sector_pos; dev->sector_len--; - pclog("Sector read to buffer position %08X\n", dev->buffer_pos); + // pclog("Sector read to buffer position %08X\n", dev->buffer_pos); dev->buffer_pos += temp_len; } } @@ -1547,17 +1557,17 @@ static void scsi_cdrom_read(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + const int osl = dev->sector_len; const int ret = scsi_cdrom_read_blocks(dev); dev->drv->seek_diff = 0; if (ret > 0) { - if (dev->packet_status != PHASE_COMPLETE) { - ui_sb_update_icon(SB_CDROM | dev->id, 1); - + if (osl > 0) scsi_cdrom_set_period(dev); - } else - ui_sb_update_icon(SB_CDROM | dev->id, 0); + + ui_sb_update_icon(SB_CDROM | dev->id, + (dev->packet_status != PHASE_COMPLETE)); } else scsi_cdrom_media_access_complete(dev, ret); } @@ -2461,7 +2471,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_REZERO_UNIT: - pclog("Rezero unit\n"); + // pclog("Rezero unit\n"); dev->was_cached = 0; scsi_cdrom_stop(sc); dev->requested_blocks = 0; @@ -2496,7 +2506,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: - pclog("Audio scan\n"); + // pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; @@ -2543,7 +2553,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; - pclog("READ TOC format %1X\n", toc_format); + // pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -3161,20 +3171,20 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - pclog("Play audio (10)\n"); + // pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - pclog("Play audio (12)\n"); + // pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", - cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); + // pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", + // cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3183,19 +3193,19 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; - pclog("Play audio track index\n"); + // pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - pclog("Play audio track relative (10)\n"); + // pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - pclog("Play audio track relative (12)\n"); + // pclog("Play audio track relative (12)\n"); break; default: @@ -3495,7 +3505,7 @@ atapi_out: case GPCMD_SEEK_6: case GPCMD_SEEK_10: - pclog("Seek\n"); + // pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; From 4221b7205997d1dab8c1f3513036a9f25443c009 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:28:52 +0100 Subject: [PATCH 0238/1190] Commented out some logging stuff. --- src/scsi/scsi_cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 21ea9ce16..8c24c4623 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -712,7 +712,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; - pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); + // pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); From 1a87aea37aa05742402825ee11618628431edfe5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:32:59 +0100 Subject: [PATCH 0239/1190] And some more. --- src/disk/hdc_ide.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 8559d7a63..d4dcea625 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1092,7 +1092,7 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - pclog("Reading block %i... ", ide->sc->sector_len + 1); + // pclog("Reading block %i... ", ide->sc->sector_len + 1); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) @@ -1116,16 +1116,16 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: - pclog("ERROR\n"); + // pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: - pclog("WAIT\n"); + // pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: - pclog("DONE\n"); + // pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1135,7 +1135,7 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: - pclog("NEXT\n"); + // pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); From 5262693624f540eaba572ee05c63665998501bed Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 04:53:51 +0100 Subject: [PATCH 0240/1190] IOCTL: The host non-raw TOC is no longer always read and is also only used to reconstruct the raw toc for DVD's, should reduce the slowness on host drive mounting. --- src/qt/win_cdrom_ioctl.c | 104 +++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 8da62a49d..96b75db38 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -44,8 +44,6 @@ typedef struct ioctl_t { int is_dvd; int has_audio; int32_t tracks_num; - uint8_t cur_toc[65536]; - CDROM_READ_TOC_EX cur_read_toc_ex; int blocks_num; uint8_t cur_rti[65536]; HANDLE handle; @@ -111,22 +109,23 @@ ioctl_open_handle(ioctl_t *ioctl) static int ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) { - long size = 0; - PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + long size = 0; + PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; ioctl->tracks_num = 0; memset(toc_buf, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_TOC; - ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); - ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 1; + cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_TOC; + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", cur_read_toc_ex.Format); + cur_read_toc_ex.Msf = 1; + cur_read_toc_ex.SessionTrack = 1; const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, + &cur_read_toc_ex, 65535, + cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "temp = %i\n", temp); @@ -157,10 +156,12 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) static void ioctl_read_raw_toc(ioctl_t *ioctl) { - PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; - long size = 0; - raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; - uint8_t *buffer = (uint8_t *) calloc (1, 2052); + PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; + long size = 0; + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; + uint8_t *buffer = (uint8_t *) calloc (1, 2052); + int status = 0; + CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; ioctl->is_dvd = (ioctl_read_dvd_structure(ioctl, 0, 0, buffer, NULL) > 0); free(buffer); @@ -171,16 +172,18 @@ ioctl_read_raw_toc(ioctl_t *ioctl) cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); - ioctl->cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; - ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", ioctl->cur_read_toc_ex.Format); - ioctl->cur_read_toc_ex.Msf = 1; - ioctl->cur_read_toc_ex.SessionTrack = 1; + cur_read_toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; + ioctl_log(ioctl->log, "cur_read_toc_ex.Format = %i\n", cur_read_toc_ex.Format); + cur_read_toc_ex.Msf = 1; + cur_read_toc_ex.SessionTrack = 1; - const int status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &ioctl->cur_read_toc_ex, 65535, - cur_full_toc, 65535, - (LPDWORD) &size, NULL); - ioctl_log(ioctl->log, "status = %i\n", status); + if (!ioctl->is_dvd) { + status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, + &cur_read_toc_ex, 65535, + cur_full_toc, 65535, + (LPDWORD) &size, NULL); + ioctl_log(ioctl->log, "status = %i\n", status); + } if ((status == 0) && (ioctl->tracks_num >= 1)) { /* @@ -189,8 +192,12 @@ ioctl_read_raw_toc(ioctl_t *ioctl) reading the cooked TOC does not, so we have to construct the raw TOC from the cooked TOC. */ - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; - const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); + uint8_t cur_toc[65536] = { 0 }; + + const CDROM_TOC * toc = (const CDROM_TOC *) cur_toc; + const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); + + ioctl_read_normal_toc(ioctl, cur_toc); rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); rti[0].point = 0xa0; @@ -257,7 +264,6 @@ ioctl_read_raw_toc(ioctl_t *ioctl) static void ioctl_read_toc(ioctl_t *ioctl) { - (void) ioctl_read_normal_toc(ioctl, ioctl->cur_toc); ioctl_read_raw_toc(ioctl); } @@ -306,23 +312,28 @@ static int ioctl_get_track_info(const void *local, const uint32_t track, int end, track_info_t *ti) { - const ioctl_t * ioctl = (const ioctl_t *) local; - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; - int ret = 1; + const ioctl_t * ioctl = (const ioctl_t *) local; + const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti; + int ret = 1; + int trk = -1; - if ((track < 1) || (track == 0xaa) || (track > (toc->LastTrack + 1))) { + if ((track >= 1) && (track < 99)) + for (int i = 0; i < ioctl->blocks_num; i++) + if (rti[i].point == track) { + trk = i; + break; + } + + if ((track == 0xaa) || (trk == -1)) { ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track); ret = 0; } else { - const TRACK_DATA * td = &toc->TrackData[track - 1]; + ti->m = rti[trk].pm; + ti->s = rti[trk].ps; + ti->f = rti[trk].pf; - ti->m = td->Address[1]; - ti->s = td->Address[2]; - ti->f = td->Address[3]; - - ti->number = td->TrackNumber; - ti->attr = td->Control; - ti->attr |= ((td->Adr << 4) & 0xf0); + ti->number = rti[trk].point; + ti->attr = rti[trk].adr_ctl; ioctl_log(ioctl->log, "ioctl_get_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n", track, ti->m, ti->s, ti->f, ti->number, ti->attr); @@ -546,18 +557,15 @@ ioctl_get_track_type(const void *local, const uint32_t sector) static uint32_t ioctl_get_last_block(const void *local) { - const ioctl_t *ioctl = (const ioctl_t *) local; - const CDROM_TOC *toc = (const CDROM_TOC *) ioctl->cur_toc; + const ioctl_t * ioctl = (const ioctl_t *) local; + raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; uint32_t lb = 0; - for (int c = 0; c <= toc->LastTrack; c++) { - const TRACK_DATA *td = &toc->TrackData[c]; - const uint32_t address = MSFtoLBA(td->Address[1], td->Address[2], - td->Address[3]) - 150; - - if (address > lb) - lb = address; - } + for (int i = (ioctl->blocks_num - 1); i >= 0; i--) + if (rti[i].point == 0xa2) { + lb = MSFtoLBA(rti[i].pm, rti[i].ps, rti[i].pf) - 151; + break; + } ioctl_log(ioctl->log, "LBCapacity=%d\n", lb); From 91ba20fbd08355de79e601040646d5f70d09d501 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 05:10:55 +0100 Subject: [PATCH 0241/1190] Added the test mode entry point requested by gloriouscow. --- src/86box.c | 24 ++++++++++++++++++++++++ src/cpu/808x.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cpu/cpu.h | 8 ++++++++ 3 files changed, 74 insertions(+) diff --git a/src/86box.c b/src/86box.c index 3ade3c4e2..e1cf61b64 100644 --- a/src/86box.c +++ b/src/86box.c @@ -210,6 +210,7 @@ int video_fullscreen_scale_maximized = 0; /* (C) Whether int do_auto_pause = 0; /* (C) Auto-pause the emulator on focus loss */ int hook_enabled = 1; /* (C) Keyboard hook is enabled */ +int test_mode = 0; /* (C) Test mode */ char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are @@ -585,6 +586,7 @@ usage: #ifndef USE_SDL_UI printf("-S or --settings - show only the settings dialog\n"); #endif + printf("-T or --testmode - test mode: execute the test mode entry point on init/hard reset\n"); printf("-V or --vmname name - overrides the name of the running VM\n"); printf("-W or --nohook - disables keyboard hook (compatibility-only outside Windows)\n"); printf("-X or --clear what - clears the 'what' (cmos/flash/both)\n"); @@ -656,6 +658,8 @@ usage: } else if (!strcasecmp(argv[c], "--settings") || !strcasecmp(argv[c], "-S")) { settings_only = 1; #endif + } else if (!strcasecmp(argv[c], "--testmode") || !strcasecmp(argv[c], "-T")) { + test_mode = 1; } else if (!strcasecmp(argv[c], "--noconfirm") || !strcasecmp(argv[c], "-N")) { confirm_exit_cmdl = 0; } else if (!strcasecmp(argv[c], "--missing") || !strcasecmp(argv[c], "-M")) { @@ -1112,6 +1116,23 @@ pc_send_cae(void) pc_send_ca(1); } +/* + Currently available API: + + extern void prefetch_queue_set_pos(int pos); + extern void prefetch_queue_set_ip(uint16_t ip); + extern void prefetch_queue_set_prefetching(int p); + extern int prefetch_queue_get_pos(void); + extern uint16_t prefetch_queue_get_ip(void); + extern int prefetch_queue_get_prefetching(void); + extern int prefetch_queue_get_size(void); + */ +static void +pc_test_mode_entry_point(void) +{ + pclog("Test mode entry point\n=====================\n"); +} + void pc_reset_hard_close(void) { @@ -1313,6 +1334,9 @@ pc_reset_hard_init(void) update_mouse_msg(); + if (test_mode) + pc_test_mode_entry_point(); + ui_hard_reset_completed(); } diff --git a/src/cpu/808x.c b/src/cpu/808x.c index a74cf84ab..e3a326503 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -154,6 +154,48 @@ x808x_log(const char *fmt, ...) static void pfq_add(int c, int add); static void set_pzs(int bits); +void +prefetch_queue_set_pos(int pos) +{ + pfq_pos = pos; +} + +void +prefetch_queue_set_ip(uint16_t ip) +{ + pfq_ip = ip; +} + +void +prefetch_queue_set_prefetching(int p) +{ + prefetching = p; +} + +int +prefetch_queue_get_pos(void) +{ + return pfq_pos; +} + +uint16_t +prefetch_queue_get_ip(void) +{ + return pfq_ip; +} + +int +prefetch_queue_get_prefetching(void) +{ + return prefetching; +} + +int +prefetch_queue_get_size(void) +{ + return pfq_size; +} + uint16_t get_last_addr(void) { diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index bd841ccc6..ab4bad8b0 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -821,4 +821,12 @@ extern int cpu_override_interpreter; extern int is_lock_legal(uint32_t fetchdat); +extern void prefetch_queue_set_pos(int pos); +extern void prefetch_queue_set_ip(uint16_t ip); +extern void prefetch_queue_set_prefetching(int p); +extern int prefetch_queue_get_pos(void); +extern uint16_t prefetch_queue_get_ip(void); +extern int prefetch_queue_get_prefetching(void); +extern int prefetch_queue_get_size(void); + #endif /*EMU_CPU_H*/ From 63fbe6ab4faab499a1bdb04d92f41f3d1a14b8d8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 05:27:10 +0100 Subject: [PATCH 0242/1190] Documented three more functions. --- src/86box.c | 4 ++++ src/cpu/cpu.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/86box.c b/src/86box.c index e1cf61b64..f8d632e11 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1119,6 +1119,10 @@ pc_send_cae(void) /* Currently available API: + extern void resetx86(void); + extern void softresetx86(void); + extern void hardresetx86(void); + extern void prefetch_queue_set_pos(int pos); extern void prefetch_queue_set_ip(uint16_t ip); extern void prefetch_queue_set_prefetching(int p); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index ab4bad8b0..1d003ddc9 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -829,4 +829,7 @@ extern uint16_t prefetch_queue_get_ip(void); extern int prefetch_queue_get_prefetching(void); extern int prefetch_queue_get_size(void); +#define prefetch_queue_set_suspended(s) prefetch_queue_set_prefetching(!s) +#define prefetch_queue_get_suspended !prefetch_queue_get_prefetching + #endif /*EMU_CPU_H*/ From 44c6daad1c3e8189222d4aa1a1a06a3656228acf Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 08:36:36 +0100 Subject: [PATCH 0243/1190] Fixed IOCTL failing to read raw TOC after hard reset. --- src/cdrom/cdrom.c | 2 +- src/qt/win_cdrom_ioctl.c | 22 ++++++++-------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index aab6cf67c..b34b01fff 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2873,7 +2873,7 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert) if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local)) dev->cd_status = CD_STATUS_EMPTY; - if (dev->ops->is_dvd(dev->local)) + else if (dev->ops->is_dvd(dev->local)) dev->cd_status = CD_STATUS_DVD; else dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED : diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 96b75db38..40addd591 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -124,7 +124,7 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) cur_read_toc_ex.SessionTrack = 1; const int temp = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &cur_read_toc_ex, 65535, + &cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX), cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "temp = %i\n", temp); @@ -179,7 +179,7 @@ ioctl_read_raw_toc(ioctl_t *ioctl) if (!ioctl->is_dvd) { status = DeviceIoControl(ioctl->handle, IOCTL_CDROM_READ_TOC_EX, - &cur_read_toc_ex, 65535, + &cur_read_toc_ex, sizeof(CDROM_READ_TOC_EX), cur_full_toc, 65535, (LPDWORD) &size, NULL); ioctl_log(ioctl->log, "status = %i\n", status); @@ -261,12 +261,6 @@ ioctl_read_raw_toc(ioctl_t *ioctl) free(cur_full_toc); } -static void -ioctl_read_toc(ioctl_t *ioctl) -{ - ioctl_read_raw_toc(ioctl); -} - static int ioctl_get_track(const ioctl_t *ioctl, const uint32_t sector) { raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti; @@ -761,13 +755,13 @@ ioctl_load(const void *local) { const ioctl_t *ioctl = (const ioctl_t *) local; - if (ioctl_open_handle((ioctl_t *) ioctl)) { - long size; - DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, - NULL, 0, NULL, 0, - (LPDWORD) &size, NULL); + if ((ioctl->handle != NULL) || ioctl_open_handle((ioctl_t *) ioctl)) { + long size = 0; + (void) DeviceIoControl(ioctl->handle, IOCTL_STORAGE_LOAD_MEDIA, + NULL, 0, NULL, 0, + (LPDWORD) &size, NULL); - ioctl_read_toc((ioctl_t *) ioctl); + ioctl_read_raw_toc((ioctl_t *) ioctl); } } From 7c422a4d507222b00c8f1edc1ce1cdff77dd9a88 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Thu, 13 Feb 2025 12:07:13 +0300 Subject: [PATCH 0244/1190] Block AMD and Cyrix CPUs from Intel Socket 5/7 motherboards with stock BIOS --- src/machine/machine_table.c | 48 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e6198541e..e55d9b494 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -9762,7 +9762,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3520, @@ -9802,7 +9802,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3520, @@ -9843,7 +9843,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -10087,7 +10087,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -10741,7 +10741,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -10824,7 +10824,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -10908,7 +10908,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -10989,7 +10989,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -11236,7 +11236,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_Cx6x86), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 3380, @@ -11647,7 +11647,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -11687,7 +11688,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -11727,7 +11729,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -11767,7 +11770,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -11850,7 +11854,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -12177,7 +12182,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2500, @@ -12299,7 +12305,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2200, @@ -12382,7 +12389,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -12668,7 +12676,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2800, @@ -12709,7 +12718,8 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 2800, From 48f42af74575144d19a1cb7d005dad25a6cfe332 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 10:31:12 +0100 Subject: [PATCH 0245/1190] Moved some files to the utils folder, that's where the CRC code is soon going to reside as well. --- src/CMakeLists.txt | 10 +++------- src/utils/CMakeLists.txt | 25 +++++++++++++++++++++++++ src/{ => utils}/cJSON.c | 0 src/{ => utils}/fifo.c | 0 src/{ => utils}/fifo8.c | 0 src/{ => utils}/ini.c | 0 src/{ => utils}/log.c | 0 src/{ => utils}/random.c | 0 8 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 src/utils/CMakeLists.txt rename src/{ => utils}/cJSON.c (100%) rename src/{ => utils}/fifo.c (100%) rename src/{ => utils}/fifo8.c (100%) rename src/{ => utils}/ini.c (100%) rename src/{ => utils}/log.c (100%) rename src/{ => utils}/random.c (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d6daff9c..3ae7c297e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,8 +23,6 @@ endif() add_executable(86Box 86box.c config.c - log.c - random.c timer.c io.c acpi.c @@ -41,15 +39,11 @@ add_executable(86Box pci.c mca.c usb.c - fifo.c - fifo8.c device.c nvr.c nvr_at.c nvr_ps2.c machine_status.c - ini.c - cJSON.c ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -106,7 +100,7 @@ if(INSTRUMENT) endif() target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd - net print scsi sio snd vid voodoo plat ui) + net print scsi sio snd utils vid voodoo plat ui) if(WIN32 AND ARCH STREQUAL "i386") if(MINGW) @@ -253,7 +247,9 @@ add_subdirectory(printer) add_subdirectory(sio) add_subdirectory(scsi) add_subdirectory(sound) +add_subdirectory(utils) add_subdirectory(video) + if (APPLE) add_subdirectory(mac) endif() diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt new file mode 100644 index 000000000..1d4b1f73e --- /dev/null +++ b/src/utils/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# CMake build script. +# +# Authors: David Hrdlička, +# Jasmine Iwanek, +# +# Copyright 2020-2021 David Hrdlička. +# Copyright 2024 Jasmine Iwanek. +# + +add_library(utils OBJECT + cJSON.c + fifo.c + fifo8.c + ini.c + log.c + random.c +) diff --git a/src/cJSON.c b/src/utils/cJSON.c similarity index 100% rename from src/cJSON.c rename to src/utils/cJSON.c diff --git a/src/fifo.c b/src/utils/fifo.c similarity index 100% rename from src/fifo.c rename to src/utils/fifo.c diff --git a/src/fifo8.c b/src/utils/fifo8.c similarity index 100% rename from src/fifo8.c rename to src/utils/fifo8.c diff --git a/src/ini.c b/src/utils/ini.c similarity index 100% rename from src/ini.c rename to src/utils/ini.c diff --git a/src/log.c b/src/utils/log.c similarity index 100% rename from src/log.c rename to src/utils/log.c diff --git a/src/random.c b/src/utils/random.c similarity index 100% rename from src/random.c rename to src/utils/random.c From 9ab1e35b16679c4d5870e4fb250d4b9df888e5f5 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 13 Feb 2025 20:10:23 +0900 Subject: [PATCH 0246/1190] added a Traditional Chinese font ROM info --- src/video/vid_ps55da2.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 011a9633f..a19965f6f 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1533,34 +1533,32 @@ The IBM 5550 character mode addresses video memory between E0000h and E0FFFh. DOS Bunsho Program transfers 1/2 and 1/4 fonts fron the font ROM to the Extended SBCS. This bit is not used for DBCS, but some apps set it as that column is right half of DBCS. -[Font ROM Map (DA2)] -The Font ROM is accessed via 128 KB memory window located on A0000-BFFFFh. -I don't know how much data the actual Font ROM has. -Here information, I researched it by disassembling J-DOS. +[Font ROM Map (DA2, Japanese)] +The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. -Bank 0 + Bank 0 4800- * -Bank 1, 2, 3 - * - * -Bank 4 - * -0DB6Fh ( 4800-8DB6Fh;IBMJ 100-1F7Dh) : JIS X 0208 DBCS (24 x 24) -10000-16D1Fh (90000-96D1Fh;IBMJ 2000-2183h) : IBM Extended Characters -18000-1BFCFh (98000-9BFCFh;around IBMJ 21C7-22AAh) : JIS X 0201 SBCS (13 x 30) -1C000-1FFFFh (9C000-9FFFFh;around IBMJ 22AA-238Eh) : Codepage 437 characters (13 x 30) -Bank 5 -00000-0C68Fh (A0000-AC68Fh;around IBMJ 238E-2650h) : Gaiji (24 x 24) - - * -0D09Fh (9FD20-AD09Fh;IBMJ 2384-2673h) : Gaiji 752 chs (maybe blank) -10000-13FFFh (B0000-B3FFFh;around IBMJ 271C-27FFh) : Extended SBCS (13 x 30) - -14000-147FFh (B4000-B46FFh;IBMJ 2800-2818h) : Half-width box drawing characters (7 lines * 4 parts * 64 bytes) used by DOS Bunsho -16000-17FFFh (B6000-B7FFFh;around IBMJ h) : Codepage 850 characters (13 x 30) -18000-1A3FFh (B8000-BA3FFh;around IBMJ h) : Shape Icons? (32 x 32) - - (B9580-?;IBMJ 2930-295e?) : Full-width box drawing characters + Bank 1, 2, 3 + * - * + Bank 4 + * -0DB6Fh ( 4800-8DB6Fh) : JIS X 0208 DBCS (24 x 24) (IBMJ code: 100-1F7Dh) + 10000-16D1Fh (90000-96D1Fh) : IBM Extended Characters (IBMJ code: 2ADC-2C5Fh) + 18000-1BFCFh (98000-9BFCFh) : JIS X 0201 SBCS (13 x 30) + 1C000-1FFFFh (9C000-9FFFFh) : Codepage 437 characters (13 x 30) + Bank 5 + 00000-0C68Fh (A0000-AC68Fh) : Gaiji used by DOS Bunsho + 10000-13FFFh (B0000-B3FFFh) : Extended SBCS (13 x 30) + 14000-1477Fh (B4000-B477Fh) : Half-width box drawing characters used by DOS Bunsho + 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) + 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) +[Font ROM Map (DA3, Traditional Chinese)] + Bank 0 - 11 : Valid Font ROM data + Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) + Bank 13 : All addresses return 0xFF + [Gaiji RAM Map (DA2)] Bank 0 00000-1FFFFh placed between A0000h-BFFFFh 00000-1F7FFh(A0000-BF7FFh): Gaiji Non-resident (Kuten 103-114 ku,IBM: 2674-2ADBh) 1008 chs 128 bytes From 6362351987b3170a7a5f84de81211b38dd6c9f09 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:14:36 +0100 Subject: [PATCH 0247/1190] bring back the Slot 1 to Socket 8 adapter --- src/cpu/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 808f603b5..0802fa3ac 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -372,7 +372,7 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) if (packages & CPU_PKG_SOCKET3) packages |= CPU_PKG_SOCKET1; else if (packages & CPU_PKG_SLOT1) - packages |= CPU_PKG_SOCKET370; + packages |= CPU_PKG_SOCKET370 | CPU_PKG_SOCKET8; /* Package type. */ if (!(cpu_family->package & packages)) From f5d65f2e66da32e335b3032b58ce164ccb882e63 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:21:19 +0100 Subject: [PATCH 0248/1190] Just block Pentium Pro on incompatibile machines, instead of removing the Slot 1-to-Socket 8 adapter altogether (part 2) --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e55d9b494..72271ee7e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15278,7 +15278,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SLOT1, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_PENTIUMPRO), .min_bus = 66666667, .max_bus = 150000000, .min_voltage = 1300, @@ -16163,7 +16163,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SLOT1, - .block = CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), + .block = CPU_BLOCK(CPU_PENTIUMPRO, CPU_PENTIUM2, CPU_CYRIX3S), .min_bus = 0, .max_bus = 66666667, .min_voltage = 0, From 1a33a2bd099763d577d0178d25240374184494c1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 19:47:21 +0100 Subject: [PATCH 0249/1190] CD-ROM: Ignore zero-length pages on MODE SELECT, and also stop properly on error. TODO: Apply to SCSI Disk, ZIP, and MO as well. --- src/scsi/scsi_cdrom.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8c24c4623..5d9a6e2f2 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -3672,12 +3672,17 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; + /* Ignore any page codes with zero length. */ + if (page_len == 0) + continue; + if (dev->drv->is_sony && (page == 0x08) && (page_len == 0x02)) dev->drv->sony_msf = dev->buffer[pos] & 0x01; if (!(dev->ms_page_flags & (1LL << ((uint64_t) page)))) { scsi_cdrom_log(dev->log, "Unimplemented page %02X\n", page); error |= 1; + break; } else { for (i = 0; i < page_len; i++) { uint8_t pg = page; @@ -3698,9 +3703,13 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) "%02X on page %02X\n", i + 2, page); scsi_cdrom_invalid_field_pl(dev, val); error |= 1; + break; } } } + + if (error) + break; } pos += page_len; @@ -3716,6 +3725,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) if (error) { scsi_cdrom_buf_free(dev); + scsi_cdrom_command_stop((scsi_common_t *) dev); return 0; } break; From da360ab9da6a5ca4e8a38f912e564529efa5dc6c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Feb 2025 23:37:27 +0100 Subject: [PATCH 0250/1190] IOCTL: Fix detection of whether or not the disc has audio, fixes audio playing. --- src/cdrom/cdrom.c | 12 +++---- src/qt/win_cdrom_ioctl.c | 69 +++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index b34b01fff..8d6326f8b 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -431,8 +431,6 @@ read_toc_normal(const cdrom_t *dev, unsigned char *b, cdrom_log(dev->log, "read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); - pclog("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i, %i)\n", - (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); dev->ops->get_raw_track_info(dev->local, &num, rti); @@ -1848,9 +1846,9 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], - b[ 8], b[ 9], b[10], b[11]); + // pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + // b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], + // b[ 8], b[ 9], b[10], b[11]); if (b[0] != 0x00) break; base += 12; @@ -3074,7 +3072,9 @@ cdrom_reload(const uint8_t id) { cdrom_t *dev = &cdrom[id]; - if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || (strlen(dev->prev_image_path) == 0) || (strlen(dev->image_path) > 0)) { + if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || + (strlen(dev->prev_image_path) == 0) || + (strlen(dev->image_path) > 0)) { /* Switch from empty to empty. Do nothing. */ return; } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 40addd591..9af59190b 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -43,7 +43,6 @@ typedef struct ioctl_t { void *log; int is_dvd; int has_audio; - int32_t tracks_num; int blocks_num; uint8_t cur_rti[65536]; HANDLE handle; @@ -107,13 +106,13 @@ ioctl_open_handle(ioctl_t *ioctl) } static int -ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) +ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf, int32_t *tracks_num) { long size = 0; PCDROM_TOC_FULL_TOC_DATA cur_full_toc = NULL; CDROM_READ_TOC_EX cur_read_toc_ex = { 0 }; - ioctl->tracks_num = 0; + *tracks_num = 0; memset(toc_buf, 0x00, 65536); cur_full_toc = (PCDROM_TOC_FULL_TOC_DATA) calloc(1, 65536); @@ -132,7 +131,7 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) if (temp != 0) { const int length = ((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) + 2; memcpy(toc_buf, cur_full_toc, length); - ioctl->tracks_num = (length - 4) / 8; + *tracks_num = (length - 4) / 8; } free(cur_full_toc); @@ -141,9 +140,9 @@ ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf) PCDROM_TOC toc = (PCDROM_TOC) toc_buf; ioctl_log(ioctl->log, "%i tracks: %02X %02X %02X %02X\n", - ioctl->tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); + *tracks_num, toc_buf[0], toc_buf[1], toc_buf[2], toc_buf[3]); - for (int i = 0; i < ioctl->tracks_num; i++) { + for (int i = 0; i < *tracks_num; i++) { const uint8_t *t = (const uint8_t *) &toc->TrackData[i]; ioctl_log(ioctl->log, "Track %03i: %02X %02X %02X %02X %02X %02X %02X %02X\n", i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]); @@ -185,7 +184,7 @@ ioctl_read_raw_toc(ioctl_t *ioctl) ioctl_log(ioctl->log, "status = %i\n", status); } - if ((status == 0) && (ioctl->tracks_num >= 1)) { + if (status == 0) { /* This is needed because in some circumstances (eg. a DVD .MDS mounted in Daemon Tools), reading the raw TOC fails but @@ -193,48 +192,54 @@ ioctl_read_raw_toc(ioctl_t *ioctl) raw TOC from the cooked TOC. */ uint8_t cur_toc[65536] = { 0 }; + int32_t tracks_num = 0; const CDROM_TOC * toc = (const CDROM_TOC *) cur_toc; - const TRACK_DATA *ct = &(toc->TrackData[ioctl->tracks_num - 1]); - ioctl_read_normal_toc(ioctl, cur_toc); + status = ioctl_read_normal_toc(ioctl, cur_toc, &tracks_num); - rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); - rti[0].point = 0xa0; - rti[0].pm = toc->FirstTrack; + const TRACK_DATA *ct = &(toc->TrackData[tracks_num - 1]); - rti[1].adr_ctl = rti[0].adr_ctl; - rti[1].point = 0xa1; - rti[1].pm = toc->LastTrack; + if ((status > 0) && (tracks_num >= 1)) { + rti[0].adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + rti[0].point = 0xa0; + rti[0].pm = toc->FirstTrack; - rti[2].adr_ctl = rti[0].adr_ctl; - rti[2].point = 0xa2; - rti[2].pm = ct->Address[1]; - rti[2].ps = ct->Address[2]; - rti[2].pf = ct->Address[3]; + rti[1].adr_ctl = rti[0].adr_ctl; + rti[1].point = 0xa1; + rti[1].pm = toc->LastTrack; - ioctl->blocks_num = 3; + rti[2].adr_ctl = rti[0].adr_ctl; + rti[2].point = 0xa2; + rti[2].pm = ct->Address[1]; + rti[2].ps = ct->Address[2]; + rti[2].pf = ct->Address[3]; - for (int i = 0; i < (ioctl->tracks_num - 1); i++) { - raw_track_info_t *crt = &(rti[ioctl->blocks_num]); + ioctl->blocks_num = 3; - ct = &(toc->TrackData[i]); + for (int i = 0; i < (tracks_num - 1); i++) { + raw_track_info_t *crt = &(rti[ioctl->blocks_num]); - crt->adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); - crt->point = ct->TrackNumber; - crt->pm = ct->Address[1]; - crt->ps = ct->Address[2]; - crt->pf = ct->Address[3]; + ct = &(toc->TrackData[i]); - ioctl->blocks_num++; - } + crt->adr_ctl = ((ct->Adr & 0xf) << 4) | (ct->Control & 0xf); + crt->point = ct->TrackNumber; + crt->pm = ct->Address[1]; + crt->ps = ct->Address[2]; + crt->pf = ct->Address[3]; + + ioctl->blocks_num++; + } + } else if (status > 0) + /* Announce that we've had a failure. */ + status = 0; } else if (status != 0) { ioctl->blocks_num = (((cur_full_toc->Length[0] << 8) | cur_full_toc->Length[1]) - 2) / 11; memcpy(ioctl->cur_rti, cur_full_toc->Descriptors, ioctl->blocks_num * 11); } - if (ioctl->blocks_num) for (int i = 0; i < ioctl->tracks_num; i++) { + if (ioctl->blocks_num) for (int i = 0; i < ioctl->blocks_num; i++) { const raw_track_info_t *crt = &(rti[i]); if ((crt->point >= 1) && (crt->point <= 99) && !(crt->adr_ctl & 0x04)) { From ee2b523653afd6c0f4237d231004c58cead4c433 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 01:02:13 +0100 Subject: [PATCH 0251/1190] Fixed two warnings. --- src/scsi/scsi_cdrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 5d9a6e2f2..840bec6a0 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -91,7 +91,7 @@ uint8_t scsi_cdrom_command_flags[0x100] = { eventually becomes ready, make the condition go away. */ [0x43 ... 0x45] = IMPLEMENTED | CHECK_READY, - [0x46] IMPLEMENTED | ALLOW_UA, + [0x46] = IMPLEMENTED | ALLOW_UA, [0x47 ... 0x49] = IMPLEMENTED | CHECK_READY, [0x4a] = IMPLEMENTED | ALLOW_UA, [0x4b] = IMPLEMENTED | CHECK_READY, @@ -664,7 +664,7 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) static void scsi_cdrom_set_period(scsi_cdrom_t *dev) { - const uint8_t cmd = dev->current_cdb[0]; + // const uint8_t cmd = dev->current_cdb[0]; scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); From 1a0cefc3b395c0f0122cfb5626b7001cb1fb6185 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 03:29:35 +0100 Subject: [PATCH 0252/1190] And some more. --- src/cdrom/cdrom.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 8d6326f8b..9349223db 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1239,7 +1239,7 @@ cdrom_get_from_name(const char *s) wchar_t tempmsg[2048]; sprintf(n, "WARNING: CD-ROM \"%s\" not found - contact 86Box support\n", s); swprintf(tempmsg, sizeof_w(tempmsg), L"%hs", n); - pclog(n); + pclog("%s", n); ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), tempmsg); @@ -1571,7 +1571,7 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, dev->seek_pos = pos2; break; - } case 0x80: + } case 0x80: { track_info_t ti; pos2 = (pos2 >> 24) & 0xff; @@ -1586,7 +1586,7 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos, cdrom_stop(dev); } break; - default: + } default: break; } @@ -1689,7 +1689,7 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) pos2 = MSFtoLBA(m, s, f) - 150; dev->cd_end = pos2; break; - } case 0x80: + } case 0x80: { track_info_t ti; pos2 = (pos2 >> 24) & 0xff; @@ -1704,7 +1704,7 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type) cdrom_stop(dev); } break; - case 0xc0: + } case 0xc0: if (pos == 0xffffffff) { cdrom_log(dev->log, "Playing from current position\n"); pos2 = dev->cd_end; From 5b6a965900fe49f1cfb96104d983a279d15680e3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 07:10:55 +0100 Subject: [PATCH 0253/1190] Bring machine flags on par with device flag and clean up device_is_valid() accordingly. --- src/device.c | 84 ++++++++++--------------------------- src/device/kbc_at.c | 31 +++++--------- src/include/86box/device.h | 26 ++++++++---- src/include/86box/machine.h | 64 ++++++++++++++-------------- src/machine/machine_table.c | 42 ++++++++++++++----- src/pic.c | 2 +- 6 files changed, 112 insertions(+), 137 deletions(-) diff --git a/src/device.c b/src/device.c index dad583cdc..7cfa1d70e 100644 --- a/src/device.c +++ b/src/device.c @@ -490,7 +490,7 @@ device_get_name(const device_t *dev, int bus, char *name) const char *sbus = NULL; const char *fbus; char *tname; - char pbus[8] = { 0 }; + char pbus[11] = { 0 }; if (dev == NULL) return; @@ -498,8 +498,21 @@ device_get_name(const device_t *dev, int bus, char *name) name[0] = 0x00; if (bus) { - if (dev->flags & DEVICE_ISA) - sbus = (dev->flags & DEVICE_AT) ? "ISA16" : "ISA"; + if ((dev->flags & (DEVICE_PCJR | DEVICE_ISA)) == + (DEVICE_PCJR | DEVICE_ISA)) + sbus = "ISA/PCJR"; + else if (dev->flags & DEVICE_SIDECAR) + sbus = "Sidecar"; + else if (dev->flags & DEVICE_XT_KBC) + sbus = "XT KBC"; + else if (dev->flags & DEVICE_ISA16) + sbus = "ISA16"; + else if (dev->flags & DEVICE_AT_KBC) + sbus = "AT KBC"; + else if (dev->flags & DEVICE_PS2_KBC) + sbus = "PS/2 KBC"; + else if (dev->flags & DEVICE_ISA) + sbus = "ISA"; else if (dev->flags & DEVICE_CBUS) sbus = "C-BUS"; else if (dev->flags & DEVICE_PCMCIA) @@ -519,7 +532,7 @@ device_get_name(const device_t *dev, int bus, char *name) else if (dev->flags & DEVICE_PCI) sbus = "PCI"; else if (dev->flags & DEVICE_CARDBUS) - sbus = "CARDBUS"; + sbus = "CardBus"; else if (dev->flags & DEVICE_USB) sbus = "USB"; else if (dev->flags & DEVICE_AGP) @@ -780,67 +793,12 @@ device_set_config_mac(const char *str, int val) int device_is_valid(const device_t *device, int mch) { - if (device == NULL) - return 1; + int ret = 1; - if ((device->flags & DEVICE_PCJR) && !machine_has_bus(mch, MACHINE_BUS_PCJR)) - return 0; + if (device != NULL) + ret = machine_has_bus(mch, device->flags & DEVICE_BUS); - if ((device->flags & DEVICE_XTKBC) && machine_has_bus(mch, MACHINE_BUS_ISA16) && !machine_has_bus(mch, MACHINE_BUS_DM_KBC)) - return 0; - - if ((device->flags & DEVICE_AT) && !machine_has_bus(mch, MACHINE_BUS_ISA16)) - return 0; - - if ((device->flags & DEVICE_ATKBC) && !machine_has_bus(mch, MACHINE_BUS_ISA16) && !machine_has_bus(mch, MACHINE_BUS_DM_KBC)) - return 0; - - if ((device->flags & DEVICE_PS2) && !machine_has_bus(mch, MACHINE_BUS_PS2_PORTS)) - return 0; - - if ((device->flags & DEVICE_ISA) && !machine_has_bus(mch, MACHINE_BUS_ISA)) - return 0; - - if ((device->flags & DEVICE_CBUS) && !machine_has_bus(mch, MACHINE_BUS_CBUS)) - return 0; - - if ((device->flags & DEVICE_PCMCIA) && !machine_has_bus(mch, MACHINE_BUS_PCMCIA) && !machine_has_bus(mch, MACHINE_BUS_ISA)) - return 0; - - if ((device->flags & DEVICE_MCA) && !machine_has_bus(mch, MACHINE_BUS_MCA)) - return 0; - - if ((device->flags & DEVICE_HIL) && !machine_has_bus(mch, MACHINE_BUS_HIL)) - return 0; - - if ((device->flags & DEVICE_EISA) && !machine_has_bus(mch, MACHINE_BUS_EISA)) - return 0; - - if ((device->flags & DEVICE_AT32) && !machine_has_bus(mch, MACHINE_BUS_AT32)) - return 0; - - if ((device->flags & DEVICE_OLB) && !machine_has_bus(mch, MACHINE_BUS_OLB)) - return 0; - - if ((device->flags & DEVICE_VLB) && !machine_has_bus(mch, MACHINE_BUS_VLB)) - return 0; - - if ((device->flags & DEVICE_PCI) && !machine_has_bus(mch, MACHINE_BUS_PCI)) - return 0; - - if ((device->flags & DEVICE_CARDBUS) && !machine_has_bus(mch, MACHINE_BUS_CARDBUS) && !machine_has_bus(mch, MACHINE_BUS_PCI)) - return 0; - - if ((device->flags & DEVICE_USB) && !machine_has_bus(mch, MACHINE_BUS_USB)) - return 0; - - if ((device->flags & DEVICE_AGP) && !machine_has_bus(mch, MACHINE_BUS_AGP)) - return 0; - - if ((device->flags & DEVICE_AC97) && !machine_has_bus(mch, MACHINE_BUS_AC97)) - return 0; - - return 1; + return ret; } int diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index ad1625873..09855a387 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -810,27 +810,18 @@ write_p2(atkbc_t *dev, uint8_t val) if (!(val & 0x01)) { /* Pin 0 selected. */ /* Pin 0 selected. */ kbc_at_log("write_p2(): Pulse reset!\n"); - if (machines[machine].flags & MACHINE_COREBOOT) { - /* The SeaBIOS hard reset code attempts a KBC reset if ACPI RESET_REG - is not available. However, the KBC reset is normally a soft reset, so - SeaBIOS gets caught in a soft reset loop as it tries to hard reset the - machine. Hack around this by making the KBC reset a hard reset only on - coreboot machines. */ - pc_reset_hard(); - } else { - softresetx86(); /* Pulse reset! */ - cpu_set_edx(); - flushmmucache(); - if ((kbc_ven == KBC_VEN_ALI) || !strcmp(machine_get_internal_name(), "spc7700plw")) - smbase = 0x00030000; + softresetx86(); /* Pulse reset! */ + cpu_set_edx(); + flushmmucache(); + if ((kbc_ven == KBC_VEN_ALI) || !strcmp(machine_get_internal_name(), "spc7700plw")) + smbase = 0x00030000; - /* Yes, this is a hack, but until someone gets ahold of the real PCD-2L - and can find out what they actually did to make it boot from FFFFF0 - correctly despite A20 being gated when the CPU is reset, this will - have to do. */ - if ((kbc_ven == KBC_VEN_SIEMENS) || !strcmp(machine_get_internal_name(), "acera1g")) - is486 ? loadcs(0xf000) : loadcs_2386(0xf000); - } + /* Yes, this is a hack, but until someone gets ahold of the real PCD-2L + and can find out what they actually did to make it boot from FFFFF0 + correctly despite A20 being gated when the CPU is reset, this will + have to do. */ + if ((kbc_ven == KBC_VEN_SIEMENS) || !strcmp(machine_get_internal_name(), "acera1g")) + is486 ? loadcs(0xf000) : loadcs_2386(0xf000); } } diff --git a/src/include/86box/device.h b/src/include/86box/device.h index d92a387e9..d074cc2fc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -79,15 +79,15 @@ // #define CONFIG_STANDALONE 257 /* not available on the on-board variant */ enum { - DEVICE_PCJR = 2, /* requires an IBM PCjr */ - DEVICE_XTKBC = 4, /* requires an XT-compatible keyboard controller */ - DEVICE_AT = 8, /* requires an AT-compatible system */ - DEVICE_ATKBC = 0x10, /* requires an AT-compatible keyboard controller */ - DEVICE_PS2 = 0x20, /* requires a PS/1 or PS/2 system */ - DEVICE_ISA = 0x40, /* requires the ISA bus */ - DEVICE_CBUS = 0x80, /* requires the C-BUS bus */ - DEVICE_PCMCIA = 0x100, /* requires the PCMCIA bus */ - DEVICE_MCA = 0x200, /* requires the MCA bus */ + DEVICE_SIDECAR = 2, /* requires an IBM PCjr */ + DEVICE_ISA = 4, /* requires the ISA bus */ + DEVICE_XT_KBC = 8, /* requires an XT-compatible keyboard controller */ + DEVICE_CBUS = 0x10, /* requires the C-BUS bus */ + DEVICE_ISA16 = 0x20, /* requires an AT-compatible system */ + DEVICE_AT_KBC = 0x40, /* requires an AT-compatible keyboard controller */ + DEVICE_MCA = 0x80, /* requires the MCA bus */ + DEVICE_PS2_KBC = 0x100, /* requires a PS/1 or PS/2 system */ + DEVICE_PCMCIA = 0x200, /* requires the PCMCIA bus */ DEVICE_HIL = 0x400, /* requires the HP HIL bus */ DEVICE_EISA = 0x800, /* requires the EISA bus */ DEVICE_AT32 = 0x1000, /* requires the Mylex AT/32 local bus */ @@ -98,8 +98,11 @@ enum { DEVICE_USB = 0x20000, /* requires the USB bus */ DEVICE_AGP = 0x40000, /* requires the AGP bus */ DEVICE_AC97 = 0x80000, /* requires the AC'97 bus */ + DEVICE_BUS = 0xfffff, /* requires a machine bus */ + DEVICE_COM = 0x100000, /* requires a serial port */ DEVICE_LPT = 0x200000, /* requires a parallel port */ + DEVICE_KBC = 0x400000, /* is a keyboard controller */ DEVICE_SOFTRESET = 0x800000, /* requires to be reset on soft reset */ @@ -109,6 +112,11 @@ enum { DEVICE_ALL = 0xffffffff /* match all devices */ }; +/* TODO: Remove this once all the devices' flags have been updated. */ +#define DEVICE_AT DEVICE_ISA16 +#define DEVICE_PCJR DEVICE_SIDECAR +#define DEVICE_PS2 DEVICE_PS2_KBC + #define BIOS_NORMAL 0 #define BIOS_INTERLEAVED 1 #define BIOS_INTERLEAVED_SINGLEFILE 2 diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 1ce46de9b..2c5440438 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -23,34 +23,31 @@ #define EMU_MACHINE_H /* Machine feature flags. */ -#define MACHINE_BUS_NONE 0x00000000 /* sys has no bus */ +#define MACHINE_BUS_NONE 0x00000000 /* sys has no bus */ /* Feature flags for BUS'es. */ -#define MACHINE_BUS_ISA 0x00000001 /* sys has ISA bus */ -#define MACHINE_BUS_CASSETTE 0x00000002 /* sys has cassette port */ -#define MACHINE_BUS_CARTRIDGE 0x00000004 /* sys has two cartridge bays */ -#define MACHINE_BUS_PCJR 0x00000008 /* sys has PCjr sidecar bus */ -#define MACHINE_BUS_DM_KBC 0x00000010 /* system has keyboard controller that supports - both XT and AT keyboards */ +#define MACHINE_BUS_CASSETTE 0x00000001 /* sys has cassette port */ +#define MACHINE_BUS_ISA 0x00000002 /* sys has ISA bus */ +#define MACHINE_BUS_SIDECAR 0x00000004 /* sys has PCjr sidecar bus */ +#define MACHINE_BUS_XT_KBD 0x00000008 /* sys has an XT keyboard port */ +#define MACHINE_BUS_CBUS 0x00000010 /* sys has C-BUS bus */ #define MACHINE_BUS_ISA16 0x00000020 /* sys has ISA16 bus - PC/AT architecture */ -#define MACHINE_BUS_CBUS 0x00000040 /* sys has C-BUS bus */ -#define MACHINE_BUS_PCMCIA 0x00000080 /* sys has PCMCIA bus */ -#define MACHINE_BUS_PS2_LATCH 0x00000100 /* system has PS/2 keyboard controller IRQ latch */ -#define MACHINE_BUS_PS2_PORTS 0x00000200 /* system has PS/2 keyboard and mouse ports */ -#define MACHINE_BUS_PS2 (MACHINE_BUS_PS2_LATCH | MACHINE_BUS_PS2_PORTS) +#define MACHINE_BUS_AT_KBD 0x00000040 /* sys has an AT keyboard port */ +#define MACHINE_BUS_MCA 0x00000080 /* sys has MCA bus */ +#define MACHINE_BUS_PS2_PORTS 0x00000100 /* system has PS/2 keyboard and mouse ports */ +#define MACHINE_BUS_PS2 MACHINE_BUS_PS2_PORTS +#define MACHINE_BUS_PCMCIA 0x00000200 /* sys has PCMCIA bus */ #define MACHINE_BUS_HIL 0x00000400 /* system has HP HIL keyboard and mouse ports */ #define MACHINE_BUS_EISA 0x00000800 /* sys has EISA bus */ #define MACHINE_BUS_AT32 0x00001000 /* sys has Mylex AT/32 local bus */ #define MACHINE_BUS_OLB 0x00002000 /* sys has OPTi local bus */ #define MACHINE_BUS_VLB 0x00004000 /* sys has VL bus */ -#define MACHINE_BUS_MCA 0x00008000 /* sys has MCA bus */ -#define MACHINE_BUS_PCI 0x00010000 /* sys has PCI bus */ -#define MACHINE_BUS_CARDBUS 0x00020000 /* sys has CardBus bus */ -#define MACHINE_BUS_USB 0x00040000 /* sys has USB bus */ -#define MACHINE_BUS_AGP 0x00080000 /* sys has AGP bus */ -#define MACHINE_BUS_AC97 0x00100000 /* sys has AC97 bus (ACR/AMR/CNR slot) */ +#define MACHINE_BUS_PCI 0x00008000 /* sys has PCI bus */ +#define MACHINE_BUS_CARDBUS 0x00010000 /* sys has CardBus bus */ +#define MACHINE_BUS_USB 0x00020000 /* sys has USB bus */ +#define MACHINE_BUS_AGP 0x00040000 /* sys has AGP bus */ +#define MACHINE_BUS_AC97 0x00080000 /* sys has AC97 bus (ACR/AMR/CNR slot) */ /* Aliases. */ #define MACHINE_CASSETTE (MACHINE_BUS_CASSETTE) /* sys has cassette port */ -#define MACHINE_CARTRIDGE (MACHINE_BUS_CARTRIDGE) /* sys has two cartridge bays */ /* Combined flags. */ #define MACHINE_PC (MACHINE_BUS_ISA) /* sys is PC/XT-compatible (ISA) */ #define MACHINE_AT (MACHINE_BUS_ISA | MACHINE_BUS_ISA16) /* sys is AT-compatible (ISA + ISA16) */ @@ -69,18 +66,18 @@ #define MACHINE_AGP (MACHINE_BUS_AGP | MACHINE_PCI) /* sys is AT-compatible with AGP */ #define MACHINE_AGP98 (MACHINE_BUS_AGP | MACHINE_PCI98) /* sys is NEC PC-98x1 series with AGP (did that even exist?) */ -#define MACHINE_PC5150 (MACHINE_PC | MACHINE_CASSETTE) /* sys is IBM PC 5150 */ -#define MACHINE_PCJR (MACHINE_PC | MACHINE_CASSETTE | MACHINE_CARTRIDGE) /* sys is PCjr */ -#define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ -#define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ -#define MACHINE_PS2_VLB (MACHINE_VLB | MACHINE_BUS_PS2) /* sys is VLB PS/2 */ -#define MACHINE_PS2_PCI (MACHINE_PCI | MACHINE_BUS_PS2) /* sys is PCI PS/2 */ -#define MACHINE_PS2_PCIV (MACHINE_PCIV | MACHINE_BUS_PS2) /* sys is VLB/PCI PS/2 */ -#define MACHINE_PS2_AGP (MACHINE_AGP | MACHINE_BUS_PS2) /* sys is AGP PS/2 */ -#define MACHINE_PS2_A97 (MACHINE_PS2_AGP | MACHINE_BUS_AC97) /* sys is AGP/AC97 PS/2 */ -#define MACHINE_PS2_NOISA (MACHINE_PS2_AGP & ~MACHINE_AT) /* sys is AGP PS/2 without ISA */ -#define MACHINE_PS2_PCIONLY (MACHINE_PS2_NOISA & ~MACHINE_BUS_AGP) /* sys is PCI PS/2 without ISA */ -#define MACHINE_PS2_NOI97 (MACHINE_PS2_A97 & ~MACHINE_AT) /* sys is AGP/AC97 PS/2 without ISA */ +#define MACHINE_PC5150 (MACHINE_PC | MACHINE_CASSETTE) /* sys is IBM PC 5150 */ +#define MACHINE_PCJR (MACHINE_PC | MACHINE_CASSETTE | MACHINE_BUS_SIDECAR) /* sys is PCjr */ +#define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ +#define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ +#define MACHINE_PS2_VLB (MACHINE_VLB | MACHINE_BUS_PS2) /* sys is VLB PS/2 */ +#define MACHINE_PS2_PCI (MACHINE_PCI | MACHINE_BUS_PS2) /* sys is PCI PS/2 */ +#define MACHINE_PS2_PCIV (MACHINE_PCIV | MACHINE_BUS_PS2) /* sys is VLB/PCI PS/2 */ +#define MACHINE_PS2_AGP (MACHINE_AGP | MACHINE_BUS_PS2) /* sys is AGP PS/2 */ +#define MACHINE_PS2_A97 (MACHINE_PS2_AGP | MACHINE_BUS_AC97) /* sys is AGP/AC97 PS/2 */ +#define MACHINE_PS2_NOISA (MACHINE_PS2_AGP & ~MACHINE_AT) /* sys is AGP PS/2 without ISA */ +#define MACHINE_PS2_PCIONLY (MACHINE_PS2_NOISA & ~MACHINE_BUS_AGP) /* sys is PCI PS/2 without ISA */ +#define MACHINE_PS2_NOI97 (MACHINE_PS2_A97 & ~MACHINE_AT) /* sys is AGP/AC97 PS/2 without ISA */ /* Feature flags for miscellaneous internal devices. */ #define MACHINE_FLAGS_NONE 0x00000000 /* sys has no int devices */ #define MACHINE_SOFTFLOAT_ONLY 0x00000001 /* sys requires SoftFloat FPU */ @@ -93,7 +90,8 @@ #define MACHINE_LPT_PRI 0x00000080 /* sys has int pri LPT */ #define MACHINE_LPT_SEC 0x00000100 /* sys has int sec LPT */ #define MACHINE_LPT_TER 0x00000200 /* sys has int ter LPT */ -#define MACHINE_LPT_QUA 0x00000400 /* sys has int qua LPT */ +#define MACHINE_PS2_KBC 0x00000400 /* sys has a PS/2 keyboard controller */ + /* this is separate from having PS/2 ports */ #define MACHINE_UART_PRI 0x00000800 /* sys has int pri UART */ #define MACHINE_UART_SEC 0x00001000 /* sys has int sec UART */ #define MACHINE_UART_TER 0x00002000 /* sys has int ter UART */ @@ -106,7 +104,7 @@ #define MACHINE_APM 0x00080000 /* sys has APM */ #define MACHINE_ACPI 0x00100000 /* sys has ACPI */ #define MACHINE_HWM 0x00200000 /* sys has hw monitor */ -#define MACHINE_COREBOOT 0x00400000 /* sys has coreboot BIOS */ +#define MACHINE_CARTRIDGE 0x00400000 /* sys has cartridge bays */ /* Feature flags for internal storage controllers. */ #define MACHINE_MFM 0x00800000 /* sys has int MFM/RLL */ #define MACHINE_XTA 0x01000000 /* sys has int XTA */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e6198541e..765943fba 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8257,8 +8257,8 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_BUS_PS2_LATCH | MACHINE_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_PS2_KBC | MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 1024, .max = 131072, @@ -8337,8 +8337,8 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_BUS_PS2_LATCH | MACHINE_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_PS2_KBC | MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 1024, .max = 261120, @@ -8539,8 +8539,8 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI | MACHINE_BUS_PS2_LATCH, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_PS2_KBC | MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 1024, .max = 131072, @@ -9198,8 +9198,8 @@ const machine_t machines[] = { .min_multi = MACHINE_MULTIPLIER_FIXED, .max_multi = MACHINE_MULTIPLIER_FIXED }, - .bus_flags = MACHINE_BUS_PS2_LATCH | MACHINE_PCI, - .flags = MACHINE_APM, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_PS2_KBC | MACHINE_APM, .ram = { .min = 2048, .max = 196608, @@ -16497,19 +16497,39 @@ machine_get_nvrmask(int m) int machine_has_flags(int m, int flags) { - return (machines[m].flags & flags); + int ret = machines[m].flags & flags; + + /* Can't have PS/2 ports with an AT KBC. */ + if ((flags & MACHINE_PS2_KBC) && + (machines[m].bus_flags & MACHINE_BUS_PS2_PORTS)) + ret |= MACHINE_PS2_KBC; + + return ret; } int machine_has_bus(int m, int bus_flags) { - return (machines[m].bus_flags & bus_flags); + int ret = machines[m].bus_flags & bus_flags; + + /* TODO: Move the KBD flags to the machine table! */ + if ((bus_flags & MACHINE_BUS_XT_KBD) && + !(machines[m].bus_flags & MACHINE_BUS_ISA16) && + !(machines[m].bus_flags & MACHINE_BUS_PS2_PORTS)) + ret |= MACHINE_BUS_XT_KBD; + + if ((bus_flags & MACHINE_BUS_AT_KBD) && + (IS_AT(m)) && + !(machines[m].bus_flags & MACHINE_BUS_PS2_PORTS)) + ret |= MACHINE_BUS_AT_KBD; + + return ret; } int machine_has_cartridge(int m) { - return (machine_has_bus(m, MACHINE_CARTRIDGE) ? 1 : 0); + return (machine_has_flags(m, MACHINE_CARTRIDGE) ? 1 : 0); } int diff --git a/src/pic.c b/src/pic.c index 7f6eda40d..cf17e8205 100644 --- a/src/pic.c +++ b/src/pic.c @@ -629,7 +629,7 @@ pic_reset_hard(void) /* The situation is as follows: There is a giant mess when it comes to these latches on real hardware, to the point that there's even boards with board-level latched that get used in place of the latches on the chipset, therefore, I'm just doing this here for the sake of simplicity. */ - if (machine_has_bus(machine, MACHINE_BUS_PS2_LATCH)) { + if (machine_has_flags(machine, MACHINE_PS2_KBC)) { pic_kbd_latch(0x01); pic_mouse_latch(0x01); } else { From a72b3884b578bcb8d304ceac3da77c7fc30420a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 07:26:22 +0100 Subject: [PATCH 0254/1190] Fixed (S)VGA memory access bitness stuff. --- src/video/vid_svga.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index e68e4c1a0..7c674e00a 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1528,7 +1528,11 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->translate_address = NULL; svga->ksc5601_english_font_type = 0; - if ((info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + /* TODO: Move DEVICE_MCA to 16-bit once the device flags have been appropriately corrected. */ + if ((info->flags & DEVICE_MCA) || (info->flags & DEVICE_MCA32) || + (info->flags & DEVICE_EISA) || (info->flags & DEVICE_AT32) || + (info->flags & DEVICE_OLB) || (info->flags & DEVICE_VLB) || + (info->flags & DEVICE_PCI) || (info->flags & DEVICE_AGP)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = svga_readl; @@ -1539,7 +1543,8 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_AT)) { + /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ + } else if ((info->flags & DEVICE_CBUS) || (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = NULL; From 2c197000ea78f0f6a20043febf89ea93e5ee34c4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 07:39:21 +0100 Subject: [PATCH 0255/1190] Removed the legacy #defines in device.h. --- src/cdrom/cdrom_mitsumi.c | 2 +- src/chipset/ali6117.c | 4 ++-- src/device.c | 10 +++++---- src/device/bugger.c | 2 +- src/device/keyboard_at.c | 2 +- src/device/mouse_ps2.c | 2 +- src/device/serial.c | 4 ++-- src/device/smbus_ali7101.c | 2 +- src/device/smbus_piix4.c | 4 ++-- src/device/smbus_sis5595.c | 2 +- src/disk/hdc_esdi_at.c | 2 +- src/disk/hdc_ide.c | 26 +++++++++++----------- src/disk/hdc_st506_at.c | 2 +- src/disk/hdc_xtide.c | 4 ++-- src/disk/lba_enhancer.c | 2 +- src/include/86box/device.h | 32 ++++++++++++--------------- src/include/86box/machine.h | 25 +++++++++++---------- src/ioapic.c | 2 +- src/machine/m_ps1_hdc.c | 2 +- src/mem/row.c | 2 +- src/network/net_ne2000.c | 8 +++---- src/network/net_pcnet.c | 8 +++---- src/nvr_at.c | 30 ++++++++++++------------- src/scsi/scsi_aha154x.c | 10 ++++----- src/scsi/scsi_buslogic.c | 8 +++---- src/sound/snd_azt2316a.c | 4 ++-- src/sound/snd_cs423x.c | 14 ++++++------ src/sound/snd_gus.c | 2 +- src/sound/snd_optimc.c | 4 ++-- src/sound/snd_pas16.c | 4 ++-- src/sound/snd_sb.c | 44 ++++++++++++++++++------------------- src/sound/snd_wss.c | 2 +- src/video/vid_8514a.c | 2 +- src/video/vid_ati_mach64.c | 2 +- src/video/vid_cl54xx.c | 22 +++++++++---------- src/video/vid_et4000w32.c | 6 ++--- src/video/vid_ht216.c | 2 +- src/video/vid_s3.c | 12 +++++----- src/video/vid_xga.c | 4 ++-- 39 files changed, 160 insertions(+), 161 deletions(-) diff --git a/src/cdrom/cdrom_mitsumi.c b/src/cdrom/cdrom_mitsumi.c index 7ef8a04b2..e27faab94 100644 --- a/src/cdrom/cdrom_mitsumi.c +++ b/src/cdrom/cdrom_mitsumi.c @@ -459,7 +459,7 @@ mitsumi_cdrom_close(void *priv) const device_t mitsumi_cdrom_device = { .name = "Mitsumi CD-ROM interface", .internal_name = "mcd", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = mitsumi_cdrom_init, .close = mitsumi_cdrom_close, diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index c351a0cfa..707b528b2 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -493,7 +493,7 @@ ali6117_init(const device_t *info) const device_t ali1217_device = { .name = "ALi M1217", .internal_name = "ali1217", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x8, .init = ali6117_init, .close = ali6117_close, @@ -507,7 +507,7 @@ const device_t ali1217_device = { const device_t ali6117d_device = { .name = "ALi M6117D", .internal_name = "ali6117d", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x2, .init = ali6117_init, .close = ali6117_close, diff --git a/src/device.c b/src/device.c index 7cfa1d70e..ff81fe5e5 100644 --- a/src/device.c +++ b/src/device.c @@ -490,7 +490,7 @@ device_get_name(const device_t *dev, int bus, char *name) const char *sbus = NULL; const char *fbus; char *tname; - char pbus[11] = { 0 }; + char pbus[12] = { 0 }; if (dev == NULL) return; @@ -498,9 +498,9 @@ device_get_name(const device_t *dev, int bus, char *name) name[0] = 0x00; if (bus) { - if ((dev->flags & (DEVICE_PCJR | DEVICE_ISA)) == - (DEVICE_PCJR | DEVICE_ISA)) - sbus = "ISA/PCJR"; + if ((dev->flags & (DEVICE_SIDECAR | DEVICE_ISA)) == + (DEVICE_SIDECAR | DEVICE_ISA)) + sbus = "ISA/Sidecar"; else if (dev->flags & DEVICE_SIDECAR) sbus = "Sidecar"; else if (dev->flags & DEVICE_XT_KBC) @@ -519,6 +519,8 @@ device_get_name(const device_t *dev, int bus, char *name) sbus = "PCMCIA"; else if (dev->flags & DEVICE_MCA) sbus = "MCA"; + else if (dev->flags & DEVICE_MCA32) + sbus = "MCA32"; else if (dev->flags & DEVICE_HIL) sbus = "HP HIL"; else if (dev->flags & DEVICE_EISA) diff --git a/src/device/bugger.c b/src/device/bugger.c index 56cac91bc..b56937a43 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -346,7 +346,7 @@ bug_close(UNUSED(void *priv)) const device_t bugger_device = { .name = "ISA/PCI Bus Bugger", .internal_name = "bugger", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = bug_init, .close = bug_close, diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 589ec7ded..c3cc29b78 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2216,7 +2216,7 @@ static const device_config_t keyboard_at_config[] = { const device_t keyboard_at_generic_device = { .name = "Standard AT or PS/2 Keyboard", .internal_name = "ps2", - .flags = DEVICE_PS2, + .flags = DEVICE_PS2_KBC, .local = 0, .init = keyboard_at_init, .close = keyboard_at_close, diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 8d98b07ce..79d7afc96 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -394,7 +394,7 @@ static const device_config_t ps2_config[] = { const device_t mouse_ps2_device = { .name = "PS/2 Mouse", .internal_name = "ps2", - .flags = DEVICE_PS2, + .flags = DEVICE_PS2_KBC, .local = MOUSE_TYPE_PS2, .init = mouse_ps2_init, .close = ps2_close, diff --git a/src/device/serial.c b/src/device/serial.c index 823d07c1f..c25da0070 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -948,7 +948,7 @@ serial_init(const device_t *info) serial_setup(dev, COM4_ADDR, COM4_IRQ); else if (next_inst == 2) serial_setup(dev, COM3_ADDR, COM3_IRQ); - else if ((next_inst == 1) || (info->flags & DEVICE_PCJR)) + else if ((next_inst == 1) || (info->local == SERIAL_8250_PCJR)) serial_setup(dev, COM2_ADDR, COM2_IRQ); else if (next_inst == 0) serial_setup(dev, COM1_ADDR, COM1_IRQ); @@ -1018,7 +1018,7 @@ const device_t ns8250_device = { const device_t ns8250_pcjr_device = { .name = "National Semiconductor 8250(-compatible) UART for PCjr", .internal_name = "ns8250_pcjr", - .flags = DEVICE_PCJR, + .flags = 0, .local = SERIAL_8250_PCJR, .init = serial_init, .close = serial_close, diff --git a/src/device/smbus_ali7101.c b/src/device/smbus_ali7101.c index 3907a065e..49eb44bc6 100644 --- a/src/device/smbus_ali7101.c +++ b/src/device/smbus_ali7101.c @@ -302,7 +302,7 @@ smbus_ali7101_close(void *priv) const device_t ali7101_smbus_device = { .name = "ALi M7101-compatible SMBus Host Controller", .internal_name = "ali7101_smbus", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = smbus_ali7101_init, .close = smbus_ali7101_close, diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index a9ffcd847..ae37c72c4 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -386,7 +386,7 @@ smbus_piix4_close(void *priv) const device_t piix4_smbus_device = { .name = "PIIX4-compatible SMBus Host Controller", .internal_name = "piix4_smbus", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = SMBUS_PIIX4, .init = smbus_piix4_init, .close = smbus_piix4_close, @@ -400,7 +400,7 @@ const device_t piix4_smbus_device = { const device_t via_smbus_device = { .name = "VIA VT82C686B SMBus Host Controller", .internal_name = "via_smbus", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = SMBUS_VIA, .init = smbus_piix4_init, .close = smbus_piix4_close, diff --git a/src/device/smbus_sis5595.c b/src/device/smbus_sis5595.c index 0a24d2355..42d1452ad 100644 --- a/src/device/smbus_sis5595.c +++ b/src/device/smbus_sis5595.c @@ -373,7 +373,7 @@ smbus_sis5595_close(void *priv) const device_t sis5595_smbus_device = { .name = "SiS 5595-compatible SMBus Host Controller", .internal_name = "sis5595_smbus", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = smbus_sis5595_init, .close = smbus_sis5595_close, diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index adc39d509..ab24aa6fa 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -984,7 +984,7 @@ wd1007vse1_available(void) const device_t esdi_at_wd1007vse1_device = { .name = "Western Digital WD1007V-SE1 (ESDI)", .internal_name = "esdi_at", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = wd1007vse1_init, .close = wd1007vse1_close, diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3683c8671..b69ddf128 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3282,7 +3282,7 @@ mcide_close(void *priv) const device_t ide_isa_device = { .name = "ISA PC/AT IDE Controller", .internal_name = "ide_isa", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = ide_init, .close = ide_close, @@ -3296,7 +3296,7 @@ const device_t ide_isa_device = { const device_t ide_isa_sec_device = { .name = "ISA PC/AT IDE Controller (Secondary)", .internal_name = "ide_isa_sec", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = ide_sec_init, .close = ide_sec_close, @@ -3310,7 +3310,7 @@ const device_t ide_isa_sec_device = { const device_t ide_isa_2ch_device = { .name = "ISA PC/AT IDE Controller (Dual-Channel)", .internal_name = "ide_isa_2ch", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 1, .init = ide_init, .close = ide_close, @@ -3324,7 +3324,7 @@ const device_t ide_isa_2ch_device = { const device_t ide_vlb_device = { .name = "VLB IDE Controller", .internal_name = "ide_vlb", - .flags = DEVICE_VLB | DEVICE_AT, + .flags = DEVICE_VLB | DEVICE_ISA16, .local = 2, .init = ide_init, .close = ide_close, @@ -3338,7 +3338,7 @@ const device_t ide_vlb_device = { const device_t ide_vlb_sec_device = { .name = "VLB IDE Controller (Secondary)", .internal_name = "ide_vlb_sec", - .flags = DEVICE_VLB | DEVICE_AT, + .flags = DEVICE_VLB | DEVICE_ISA16, .local = 2, .init = ide_sec_init, .close = ide_sec_close, @@ -3352,7 +3352,7 @@ const device_t ide_vlb_sec_device = { const device_t ide_vlb_2ch_device = { .name = "VLB IDE Controller (Dual-Channel)", .internal_name = "ide_vlb_2ch", - .flags = DEVICE_VLB | DEVICE_AT, + .flags = DEVICE_VLB | DEVICE_ISA16, .local = 3, .init = ide_init, .close = ide_close, @@ -3366,7 +3366,7 @@ const device_t ide_vlb_2ch_device = { const device_t ide_pci_device = { .name = "PCI IDE Controller", .internal_name = "ide_pci", - .flags = DEVICE_PCI | DEVICE_AT, + .flags = DEVICE_PCI | DEVICE_ISA16, .local = 4, .init = ide_init, .close = ide_close, @@ -3380,7 +3380,7 @@ const device_t ide_pci_device = { const device_t ide_pci_sec_device = { .name = "PCI IDE Controller (Secondary)", .internal_name = "ide_pci_sec", - .flags = DEVICE_PCI | DEVICE_AT, + .flags = DEVICE_PCI | DEVICE_ISA16, .local = 4, .init = ide_sec_init, .close = ide_sec_close, @@ -3394,7 +3394,7 @@ const device_t ide_pci_sec_device = { const device_t ide_pci_2ch_device = { .name = "PCI IDE Controller (Dual-Channel)", .internal_name = "ide_pci_2ch", - .flags = DEVICE_PCI | DEVICE_AT, + .flags = DEVICE_PCI | DEVICE_ISA16, .local = 5, .init = ide_init, .close = ide_close, @@ -3478,7 +3478,7 @@ static const device_config_t ide_qua_config[] = { const device_t ide_ter_device = { .name = "Tertiary IDE Controller", .internal_name = "ide_ter", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = ide_ter_init, .close = ide_ter_close, @@ -3492,7 +3492,7 @@ const device_t ide_ter_device = { const device_t ide_ter_pnp_device = { .name = "Tertiary IDE Controller (Plug and Play only)", .internal_name = "ide_ter_pnp", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 1, .init = ide_ter_init, .close = ide_ter_close, @@ -3506,7 +3506,7 @@ const device_t ide_ter_pnp_device = { const device_t ide_qua_device = { .name = "Quaternary IDE Controller", .internal_name = "ide_qua", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = ide_qua_init, .close = ide_qua_close, @@ -3520,7 +3520,7 @@ const device_t ide_qua_device = { const device_t ide_qua_pnp_device = { .name = "Quaternary IDE Controller (Plug and Play only)", .internal_name = "ide_qua_pnp", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 1, .init = ide_qua_init, .close = ide_qua_close, diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index eeb242a94..07c57b2ca 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -795,7 +795,7 @@ mfm_close(void *priv) const device_t st506_at_wd1003_device = { .name = "WD1003 AT MFM/RLL Controller", .internal_name = "st506_at", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = mfm_init, .close = mfm_close, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 4c071e596..c18a24c4e 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -312,7 +312,7 @@ const device_t xtide_device = { const device_t xtide_at_device = { .name = "PC/AT XTIDE", .internal_name = "xtide_at", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = xtide_at_init, .close = xtide_at_close, @@ -340,7 +340,7 @@ const device_t xtide_acculogic_device = { const device_t xtide_at_ps2_device = { .name = "PS/2 AT XTIDE (1.1.5)", .internal_name = "xtide_at_ps2", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = xtide_at_ps2_init, .close = xtide_at_close, diff --git a/src/disk/lba_enhancer.c b/src/disk/lba_enhancer.c index 429611b2d..ef9e167d3 100644 --- a/src/disk/lba_enhancer.c +++ b/src/disk/lba_enhancer.c @@ -88,7 +88,7 @@ static const device_config_t lba_enhancer_config[] = { const device_t lba_enhancer_device = { .name = "Vision Systems LBA Enhancer", .internal_name = "lba_enhancer", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = lba_enhancer_init, .close = lba_enhancer_close, diff --git a/src/include/86box/device.h b/src/include/86box/device.h index d074cc2fc..584f0f069 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -86,19 +86,20 @@ enum { DEVICE_ISA16 = 0x20, /* requires an AT-compatible system */ DEVICE_AT_KBC = 0x40, /* requires an AT-compatible keyboard controller */ DEVICE_MCA = 0x80, /* requires the MCA bus */ - DEVICE_PS2_KBC = 0x100, /* requires a PS/1 or PS/2 system */ - DEVICE_PCMCIA = 0x200, /* requires the PCMCIA bus */ - DEVICE_HIL = 0x400, /* requires the HP HIL bus */ - DEVICE_EISA = 0x800, /* requires the EISA bus */ - DEVICE_AT32 = 0x1000, /* requires the Mylex AT/32 local bus */ - DEVICE_OLB = 0x2000, /* requires the OPTi local bus */ - DEVICE_VLB = 0x4000, /* requires the VLB bus */ - DEVICE_PCI = 0x8000, /* requires the PCI bus */ - DEVICE_CARDBUS = 0x10000, /* requires the CardBus bus */ - DEVICE_USB = 0x20000, /* requires the USB bus */ - DEVICE_AGP = 0x40000, /* requires the AGP bus */ - DEVICE_AC97 = 0x80000, /* requires the AC'97 bus */ - DEVICE_BUS = 0xfffff, /* requires a machine bus */ + DEVICE_MCA32 = 0x100, /* requires the MCA bus */ + DEVICE_PS2_KBC = 0x200, /* requires a PS/1 or PS/2 system */ + DEVICE_PCMCIA = 0x400, /* requires the PCMCIA bus */ + DEVICE_HIL = 0x800, /* requires the HP HIL bus */ + DEVICE_EISA = 0x1000, /* requires the EISA bus */ + DEVICE_AT32 = 0x2000, /* requires the Mylex AT/32 local bus */ + DEVICE_OLB = 0x4000, /* requires the OPTi local bus */ + DEVICE_VLB = 0x8000, /* requires the VLB bus */ + DEVICE_PCI = 0x10000, /* requires the PCI bus */ + DEVICE_CARDBUS = 0x20000, /* requires the CardBus bus */ + DEVICE_USB = 0x40000, /* requires the USB bus */ + DEVICE_AGP = 0x80000, /* requires the AGP bus */ + DEVICE_AC97 = 0x100000, /* requires the AC'97 bus */ + DEVICE_BUS = 0xffffff, /* requires a machine bus */ DEVICE_COM = 0x100000, /* requires a serial port */ DEVICE_LPT = 0x200000, /* requires a parallel port */ @@ -112,11 +113,6 @@ enum { DEVICE_ALL = 0xffffffff /* match all devices */ }; -/* TODO: Remove this once all the devices' flags have been updated. */ -#define DEVICE_AT DEVICE_ISA16 -#define DEVICE_PCJR DEVICE_SIDECAR -#define DEVICE_PS2 DEVICE_PS2_KBC - #define BIOS_NORMAL 0 #define BIOS_INTERLEAVED 1 #define BIOS_INTERLEAVED_SINGLEFILE 2 diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 2c5440438..bf4954ae9 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -33,19 +33,20 @@ #define MACHINE_BUS_ISA16 0x00000020 /* sys has ISA16 bus - PC/AT architecture */ #define MACHINE_BUS_AT_KBD 0x00000040 /* sys has an AT keyboard port */ #define MACHINE_BUS_MCA 0x00000080 /* sys has MCA bus */ -#define MACHINE_BUS_PS2_PORTS 0x00000100 /* system has PS/2 keyboard and mouse ports */ +#define MACHINE_BUS_MCA32 0x00000100 /* sys has MCA32 bus */ +#define MACHINE_BUS_PS2_PORTS 0x00000200 /* system has PS/2 keyboard and mouse ports */ #define MACHINE_BUS_PS2 MACHINE_BUS_PS2_PORTS -#define MACHINE_BUS_PCMCIA 0x00000200 /* sys has PCMCIA bus */ -#define MACHINE_BUS_HIL 0x00000400 /* system has HP HIL keyboard and mouse ports */ -#define MACHINE_BUS_EISA 0x00000800 /* sys has EISA bus */ -#define MACHINE_BUS_AT32 0x00001000 /* sys has Mylex AT/32 local bus */ -#define MACHINE_BUS_OLB 0x00002000 /* sys has OPTi local bus */ -#define MACHINE_BUS_VLB 0x00004000 /* sys has VL bus */ -#define MACHINE_BUS_PCI 0x00008000 /* sys has PCI bus */ -#define MACHINE_BUS_CARDBUS 0x00010000 /* sys has CardBus bus */ -#define MACHINE_BUS_USB 0x00020000 /* sys has USB bus */ -#define MACHINE_BUS_AGP 0x00040000 /* sys has AGP bus */ -#define MACHINE_BUS_AC97 0x00080000 /* sys has AC97 bus (ACR/AMR/CNR slot) */ +#define MACHINE_BUS_PCMCIA 0x00000400 /* sys has PCMCIA bus */ +#define MACHINE_BUS_HIL 0x00000800 /* system has HP HIL keyboard and mouse ports */ +#define MACHINE_BUS_EISA 0x00001000 /* sys has EISA bus */ +#define MACHINE_BUS_AT32 0x00002000 /* sys has Mylex AT/32 local bus */ +#define MACHINE_BUS_OLB 0x00004000 /* sys has OPTi local bus */ +#define MACHINE_BUS_VLB 0x00008000 /* sys has VL bus */ +#define MACHINE_BUS_PCI 0x00010000 /* sys has PCI bus */ +#define MACHINE_BUS_CARDBUS 0x00020000 /* sys has CardBus bus */ +#define MACHINE_BUS_USB 0x00040000 /* sys has USB bus */ +#define MACHINE_BUS_AGP 0x00080000 /* sys has AGP bus */ +#define MACHINE_BUS_AC97 0x00100000 /* sys has AC97 bus (ACR/AMR/CNR slot) */ /* Aliases. */ #define MACHINE_CASSETTE (MACHINE_BUS_CASSETTE) /* sys has cassette port */ /* Combined flags. */ diff --git a/src/ioapic.c b/src/ioapic.c index b5ca4c7a7..ea0811f91 100644 --- a/src/ioapic.c +++ b/src/ioapic.c @@ -117,7 +117,7 @@ ioapic_init(UNUSED(const device_t *info)) const device_t ioapic_device = { .name = "I/O Advanced Programmable Interrupt Controller", .internal_name = "ioapic", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = ioapic_init, .close = ioapic_close, diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index d407953b4..18792ded7 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -1380,7 +1380,7 @@ ps1_hdc_close(void *priv) const device_t ps1_hdc_device = { .name = "PS/1 2011 Fixed Disk Controller", .internal_name = "ps1_hdc", - .flags = DEVICE_ISA | DEVICE_PS2, + .flags = DEVICE_ISA, .local = 0, .init = ps1_hdc_init, .close = ps1_hdc_close, diff --git a/src/mem/row.c b/src/mem/row.c index 633d0e31a..c3e10841f 100644 --- a/src/mem/row.c +++ b/src/mem/row.c @@ -336,7 +336,7 @@ row_init(const device_t *info) device_t row_device = { .name = "DRAM Rows", .internal_name = "dram_rows", - .flags = DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x0000, .init = row_init, .close = row_close, diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index dd3a12047..71e5c2ca7 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1714,7 +1714,7 @@ const device_t ne1000_compat_device = { const device_t ne2000_device = { .name = "Novell NE2000", .internal_name = "novell_ne2k", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = NE2K_NE2000, .init = nic_init, .close = nic_close, @@ -1728,7 +1728,7 @@ const device_t ne2000_device = { const device_t ne2000_compat_device = { .name = "NE2000 Compatible", .internal_name = "ne2k", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = NE2K_NE2000_COMPAT, .init = nic_init, .close = nic_close, @@ -1770,7 +1770,7 @@ const device_t ethernext_mc_device = { const device_t rtl8019as_pnp_device = { .name = "Realtek RTL8019AS", .internal_name = "ne2kpnp", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = NE2K_RTL8019AS_PNP, .init = nic_init, .close = nic_close, @@ -1784,7 +1784,7 @@ const device_t rtl8019as_pnp_device = { const device_t de220p_device = { .name = "D-Link DE-220P", .internal_name = "de220p", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = NE2K_DE220P, .init = nic_init, .close = nic_close, diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 3272033cf..b13fd8438 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -2922,7 +2922,7 @@ pcnet_init(const device_t *info) dev->is_pci = !!(info->flags & DEVICE_PCI); dev->is_vlb = !!(info->flags & DEVICE_VLB); - dev->is_isa = !!(info->flags & (DEVICE_ISA | DEVICE_AT)); + dev->is_isa = !!(info->flags & (DEVICE_ISA16)); if (dev->is_pci || dev->is_vlb) dev->transfer_size = 4; @@ -3231,7 +3231,7 @@ static const device_config_t pcnet_vlb_config[] = { const device_t pcnet_am79c960_device = { .name = "AMD PCnet-ISA", .internal_name = "pcnetisa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = DEV_AM79C960, .init = pcnet_init, .close = pcnet_close, @@ -3245,7 +3245,7 @@ const device_t pcnet_am79c960_device = { const device_t pcnet_am79c960_eb_device = { .name = "Racal Interlan EtherBlaster", .internal_name = "pcnetracal", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = DEV_AM79C960_EB, .init = pcnet_init, .close = pcnet_close, @@ -3273,7 +3273,7 @@ const device_t pcnet_am79c960_vlb_device = { const device_t pcnet_am79c961_device = { .name = "AMD PCnet-ISA+", .internal_name = "pcnetisaplus", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = DEV_AM79C961, .init = pcnet_init, .close = pcnet_close, diff --git a/src/nvr_at.c b/src/nvr_at.c index 147795f8e..bde80b434 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1219,7 +1219,7 @@ nvr_at_close(void *priv) const device_t at_nvr_old_device = { .name = "PC/AT NVRAM (No century)", .internal_name = "at_nvr_old", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = nvr_at_init, .close = nvr_at_close, @@ -1233,7 +1233,7 @@ const device_t at_nvr_old_device = { const device_t at_nvr_device = { .name = "PC/AT NVRAM", .internal_name = "at_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 1, .init = nvr_at_init, .close = nvr_at_close, @@ -1247,7 +1247,7 @@ const device_t at_nvr_device = { const device_t at_mb_nvr_device = { .name = "PC/AT NVRAM", .internal_name = "at_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x40 | 0x20 | 1, .init = nvr_at_init, .close = nvr_at_close, @@ -1261,7 +1261,7 @@ const device_t at_mb_nvr_device = { const device_t ps_nvr_device = { .name = "PS/1 or PS/2 NVRAM", .internal_name = "ps_nvr", - .flags = DEVICE_PS2, + .flags = DEVICE_ISA16, .local = 2, .init = nvr_at_init, .close = nvr_at_close, @@ -1275,7 +1275,7 @@ const device_t ps_nvr_device = { const device_t amstrad_nvr_device = { .name = "Amstrad NVRAM", .internal_name = "amstrad_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 3, .init = nvr_at_init, .close = nvr_at_close, @@ -1289,7 +1289,7 @@ const device_t amstrad_nvr_device = { const device_t ibmat_nvr_device = { .name = "IBM AT NVRAM", .internal_name = "ibmat_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 4, .init = nvr_at_init, .close = nvr_at_close, @@ -1303,7 +1303,7 @@ const device_t ibmat_nvr_device = { const device_t piix4_nvr_device = { .name = "Intel PIIX4 PC/AT NVRAM", .internal_name = "piix4_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 1, .init = nvr_at_init, .close = nvr_at_close, @@ -1317,7 +1317,7 @@ const device_t piix4_nvr_device = { const device_t ps_no_nmi_nvr_device = { .name = "PS/1 or PS/2 NVRAM (No NMI)", .internal_name = "ps1_nvr", - .flags = DEVICE_PS2, + .flags = DEVICE_ISA16, .local = 0x10 | 2, .init = nvr_at_init, .close = nvr_at_close, @@ -1331,7 +1331,7 @@ const device_t ps_no_nmi_nvr_device = { const device_t amstrad_no_nmi_nvr_device = { .name = "Amstrad NVRAM (No NMI)", .internal_name = "amstrad_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 3, .init = nvr_at_init, .close = nvr_at_close, @@ -1345,7 +1345,7 @@ const device_t amstrad_no_nmi_nvr_device = { const device_t ami_1992_nvr_device = { .name = "AMI Color 1992 PC/AT NVRAM", .internal_name = "ami_1992_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 4, .init = nvr_at_init, .close = nvr_at_close, @@ -1359,7 +1359,7 @@ const device_t ami_1992_nvr_device = { const device_t ami_1994_nvr_device = { .name = "AMI WinBIOS 1994 PC/AT NVRAM", .internal_name = "ami_1994_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 5, .init = nvr_at_init, .close = nvr_at_close, @@ -1373,7 +1373,7 @@ const device_t ami_1994_nvr_device = { const device_t ami_1995_nvr_device = { .name = "AMI WinBIOS 1995 PC/AT NVRAM", .internal_name = "ami_1995_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 6, .init = nvr_at_init, .close = nvr_at_close, @@ -1387,7 +1387,7 @@ const device_t ami_1995_nvr_device = { const device_t via_nvr_device = { .name = "VIA PC/AT NVRAM", .internal_name = "via_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x10 | 7, .init = nvr_at_init, .close = nvr_at_close, @@ -1401,7 +1401,7 @@ const device_t via_nvr_device = { const device_t p6rp4_nvr_device = { .name = "ASUS P/I-P6RP4 PC/AT NVRAM", .internal_name = "p6rp4_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 32, .init = nvr_at_init, .close = nvr_at_close, @@ -1415,7 +1415,7 @@ const device_t p6rp4_nvr_device = { const device_t amstrad_megapc_nvr_device = { .name = "Amstrad MegaPC NVRAM", .internal_name = "amstrad_megapc_nvr", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 36, .init = nvr_at_init, .close = nvr_at_close, diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 4f3d1d1e7..7c887e28b 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -1473,7 +1473,7 @@ static const device_config_t aha_154xcp_config[] = { const device_t aha154xa_device = { .name = "Adaptec AHA-154xA", .internal_name = "aha154xa", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = AHA_154xA, .init = aha_init, .close = x54x_close, @@ -1487,7 +1487,7 @@ const device_t aha154xa_device = { const device_t aha154xb_device = { .name = "Adaptec AHA-154xB", .internal_name = "aha154xb", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = AHA_154xB, .init = aha_init, .close = x54x_close, @@ -1501,7 +1501,7 @@ const device_t aha154xb_device = { const device_t aha154xc_device = { .name = "Adaptec AHA-154xC", .internal_name = "aha154xc", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = AHA_154xC, .init = aha_init, .close = x54x_close, @@ -1515,7 +1515,7 @@ const device_t aha154xc_device = { const device_t aha154xcf_device = { .name = "Adaptec AHA-154xCF", .internal_name = "aha154xcf", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = AHA_154xCF, .init = aha_init, .close = x54x_close, @@ -1529,7 +1529,7 @@ const device_t aha154xcf_device = { const device_t aha154xcp_device = { .name = "Adaptec AHA-154xCP", .internal_name = "aha154xcp", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = AHA_154xCP, .init = aha_init, .close = aha1542cp_close, diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index c4745e2df..9fe34380b 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1872,7 +1872,7 @@ static const device_config_t BT958D_Config[] = { const device_t buslogic_542b_device = { .name = "BusLogic BT-542B ISA", .internal_name = "bt542b", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CHIP_BUSLOGIC_ISA_542B_1991_12_14, .init = buslogic_init, .close = x54x_close, @@ -1886,7 +1886,7 @@ const device_t buslogic_542b_device = { const device_t buslogic_545s_device = { .name = "BusLogic BT-545S ISA", .internal_name = "bt545s", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CHIP_BUSLOGIC_ISA_545S_1992_10_05, .init = buslogic_init, .close = x54x_close, @@ -1900,7 +1900,7 @@ const device_t buslogic_545s_device = { const device_t buslogic_542bh_device = { .name = "BusLogic BT-542BH ISA", .internal_name = "bt542bh", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CHIP_BUSLOGIC_ISA_542BH_1993_05_23, .init = buslogic_init, .close = x54x_close, @@ -1914,7 +1914,7 @@ const device_t buslogic_542bh_device = { const device_t buslogic_545c_device = { .name = "BusLogic BT-545C ISA", .internal_name = "bt545c", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CHIP_BUSLOGIC_ISA_545C_1994_12_01, .init = buslogic_init, .close = x54x_close, diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index ea682a82c..76bf1b24f 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1557,7 +1557,7 @@ static const device_config_t azt2316a_config[] = { const device_t azt2316a_device = { .name = "Aztech Sound Galaxy Pro 16 AB (Washington)", .internal_name = "azt2316a", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_SUBTYPE_CLONE_AZT2316A_0X11, .init = azt_init, .close = azt_close, @@ -1571,7 +1571,7 @@ const device_t azt2316a_device = { const device_t azt1605_device = { .name = "Aztech Sound Galaxy Nova 16 Extra (Clinton)", .internal_name = "azt1605", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_SUBTYPE_CLONE_AZT1605_0X0C, .init = azt_init, .close = azt_close, diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index f5458eaf0..17ea48dd3 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -1061,7 +1061,7 @@ cs423x_speed_changed(void *priv) const device_t cs4235_device = { .name = "Crystal CS4235", .internal_name = "cs4235", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4235, .init = cs423x_init, .close = cs423x_close, @@ -1075,7 +1075,7 @@ const device_t cs4235_device = { const device_t cs4235_onboard_device = { .name = "Crystal CS4235 (On-Board)", .internal_name = "cs4235_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4235 | CRYSTAL_NOEEPROM, .init = cs423x_init, .close = cs423x_close, @@ -1089,7 +1089,7 @@ const device_t cs4235_onboard_device = { const device_t cs4236_onboard_device = { .name = "Crystal CS4236 (On-Board)", .internal_name = "cs4236_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4236 | CRYSTAL_NOEEPROM, .init = cs423x_init, .close = cs423x_close, @@ -1103,7 +1103,7 @@ const device_t cs4236_onboard_device = { const device_t cs4236b_device = { .name = "Crystal CS4236B", .internal_name = "cs4236b", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4236B, .init = cs423x_init, .close = cs423x_close, @@ -1117,7 +1117,7 @@ const device_t cs4236b_device = { const device_t cs4236b_onboard_device = { .name = "Crystal CS4236B", .internal_name = "cs4236b", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4236B | CRYSTAL_NOEEPROM, .init = cs423x_init, .close = cs423x_close, @@ -1131,7 +1131,7 @@ const device_t cs4236b_onboard_device = { const device_t cs4237b_device = { .name = "Crystal CS4237B", .internal_name = "cs4237b", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4237B, .init = cs423x_init, .close = cs423x_close, @@ -1145,7 +1145,7 @@ const device_t cs4237b_device = { const device_t cs4238b_device = { .name = "Crystal CS4238B", .internal_name = "cs4238b", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = CRYSTAL_CS4238B, .init = cs423x_init, .close = cs423x_close, diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index f2651c72f..43638473c 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -1500,7 +1500,7 @@ static const device_config_t gus_config[] = { const device_t gus_device = { .name = "Gravis UltraSound", .internal_name = "gus", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = gus_init, .close = gus_close, diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index d5c01dbaf..d0b05741a 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -484,7 +484,7 @@ static const device_config_t optimc_config[] = { const device_t acermagic_s20_device = { .name = "AcerMagic S20", .internal_name = "acermagic_s20", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0xE3 | OPTIMC_CS4231, .init = optimc_init, .close = optimc_close, @@ -498,7 +498,7 @@ const device_t acermagic_s20_device = { const device_t mirosound_pcm10_device = { .name = "miroSOUND PCM10", .internal_name = "mirosound_pcm10", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0xE3 | OPTIMC_OPL4, .init = optimc_init, .close = optimc_close, diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index ddb135357..353f9a3d5 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -2453,7 +2453,7 @@ const device_t pasplus_device = { const device_t pas16_device = { .name = "Pro Audio Spectrum 16", .internal_name = "pas16", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x0f, .init = pas16_init, .close = pas16_close, @@ -2467,7 +2467,7 @@ const device_t pas16_device = { const device_t pas16d_device = { .name = "Pro Audio Spectrum 16D", .internal_name = "pas16d", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x0c, .init = pas16_init, .close = pas16_close, diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index ca233b252..4f8b8a0bd 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -5476,7 +5476,7 @@ const device_t sb_pro_mcv_device = { const device_t sb_pro_compat_device = { .name = "Sound Blaster Pro (Compatibility)", .internal_name = "sbpro_compat", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = sb_pro_compat_init, .close = sb_close, @@ -5490,7 +5490,7 @@ const device_t sb_pro_compat_device = { const device_t sb_16_device = { .name = "Sound Blaster 16", .internal_name = "sb16", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = FM_YMF262, .init = sb_16_init, .close = sb_close, @@ -5504,7 +5504,7 @@ const device_t sb_16_device = { const device_t sb_vibra16c_onboard_device = { .name = "Sound Blaster ViBRA 16C (On-Board)", .internal_name = "sb_vibra16c_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16C, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5518,7 +5518,7 @@ const device_t sb_vibra16c_onboard_device = { const device_t sb_vibra16c_device = { .name = "Sound Blaster ViBRA 16C", .internal_name = "sb_vibra16c", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16C, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5532,7 +5532,7 @@ const device_t sb_vibra16c_device = { const device_t sb_vibra16cl_onboard_device = { .name = "Sound Blaster ViBRA 16CL (On-Board)", .internal_name = "sb_vibra16cl_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16CL, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5546,7 +5546,7 @@ const device_t sb_vibra16cl_onboard_device = { const device_t sb_vibra16cl_device = { .name = "Sound Blaster ViBRA 16CL", .internal_name = "sb_vibra16cl", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16CL, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5560,7 +5560,7 @@ const device_t sb_vibra16cl_device = { const device_t sb_vibra16s_onboard_device = { .name = "Sound Blaster ViBRA 16S (On-Board)", .internal_name = "sb_vibra16s_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = FM_YMF289B, .init = sb_16_init, .close = sb_close, @@ -5574,7 +5574,7 @@ const device_t sb_vibra16s_onboard_device = { const device_t sb_vibra16s_device = { .name = "Sound Blaster ViBRA 16S", .internal_name = "sb_vibra16s", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = FM_YMF289B, .init = sb_16_init, .close = sb_close, @@ -5588,7 +5588,7 @@ const device_t sb_vibra16s_device = { const device_t sb_vibra16xv_onboard_device = { .name = "Sound Blaster ViBRA 16XV (On-Board)", .internal_name = "sb_vibra16xv_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16XV, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5602,7 +5602,7 @@ const device_t sb_vibra16xv_onboard_device = { const device_t sb_vibra16xv_device = { .name = "Sound Blaster ViBRA 16XV", .internal_name = "sb_vibra16xv", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_VIBRA16XV, .init = sb_vibra16_pnp_init, .close = sb_close, @@ -5630,7 +5630,7 @@ const device_t sb_16_reply_mca_device = { const device_t sb_16_pnp_device = { .name = "Sound Blaster 16 PnP", .internal_name = "sb16_pnp", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_16_PNP_NOIDE, .init = sb_16_pnp_init, .close = sb_close, @@ -5644,7 +5644,7 @@ const device_t sb_16_pnp_device = { const device_t sb_16_pnp_ide_device = { .name = "Sound Blaster 16 PnP (IDE)", .internal_name = "sb16_pnp_ide", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_16_PNP_IDE, .init = sb_16_pnp_init, .close = sb_close, @@ -5658,7 +5658,7 @@ const device_t sb_16_pnp_ide_device = { const device_t sb_16_compat_device = { .name = "Sound Blaster 16 (Compatibility)", .internal_name = "sb16_compat", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 1, .init = sb_16_compat_init, .close = sb_close, @@ -5672,7 +5672,7 @@ const device_t sb_16_compat_device = { const device_t sb_16_compat_nompu_device = { .name = "Sound Blaster 16 (Compatibility - MPU-401 Off)", .internal_name = "sb16_compat", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = sb_16_compat_init, .close = sb_close, @@ -5686,7 +5686,7 @@ const device_t sb_16_compat_nompu_device = { const device_t sb_goldfinch_device = { .name = "Creative EMU8000 PnP (Goldfinch)", .internal_name = "sb_goldfinch", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = sb_goldfinch_init, .close = sb_goldfinch_close, @@ -5700,7 +5700,7 @@ const device_t sb_goldfinch_device = { const device_t sb_32_pnp_device = { .name = "Sound Blaster 32 PnP", .internal_name = "sb32_pnp", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_32_PNP, .init = sb_awe32_pnp_init, .close = sb_awe32_close, @@ -5714,7 +5714,7 @@ const device_t sb_32_pnp_device = { const device_t sb_awe32_device = { .name = "Sound Blaster AWE32", .internal_name = "sbawe32", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = sb_awe32_init, .close = sb_awe32_close, @@ -5728,7 +5728,7 @@ const device_t sb_awe32_device = { const device_t sb_awe32_pnp_device = { .name = "Sound Blaster AWE32 PnP", .internal_name = "sbawe32_pnp", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_AWE32_PNP, .init = sb_awe32_pnp_init, .close = sb_awe32_close, @@ -5742,7 +5742,7 @@ const device_t sb_awe32_pnp_device = { const device_t sb_awe64_value_device = { .name = "Sound Blaster AWE64 Value", .internal_name = "sbawe64_value", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_AWE64_VALUE, .init = sb_awe32_pnp_init, .close = sb_awe32_close, @@ -5756,7 +5756,7 @@ const device_t sb_awe64_value_device = { const device_t sb_awe64_device = { .name = "Sound Blaster AWE64", .internal_name = "sbawe64", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_AWE64_NOIDE, .init = sb_awe32_pnp_init, .close = sb_awe32_close, @@ -5770,7 +5770,7 @@ const device_t sb_awe64_device = { const device_t sb_awe64_ide_device = { .name = "Sound Blaster AWE64 (IDE)", .internal_name = "sbawe64_ide", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_AWE64_IDE, .init = sb_awe32_pnp_init, .close = sb_awe32_close, @@ -5784,7 +5784,7 @@ const device_t sb_awe64_ide_device = { const device_t sb_awe64_gold_device = { .name = "Sound Blaster AWE64 Gold", .internal_name = "sbawe64_gold", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = SB_AWE64_GOLD, .init = sb_awe32_pnp_init, .close = sb_awe32_close, diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index c55e5f57b..874638a80 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -279,7 +279,7 @@ static const device_config_t wss_config[] = { const device_t wss_device = { .name = "Windows Sound System", .internal_name = "wss", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = wss_init, .close = wss_close, diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 09b054895..379772820 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -4072,7 +4072,7 @@ static const device_config_t mca_ext8514_config[] = { const device_t gen8514_isa_device = { .name = "IBM 8514/A clone (ISA)", .internal_name = "8514_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = 0, .init = ibm8514_init, .close = ibm8514_close, diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 9b7a67f31..9499f4ecc 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -4752,7 +4752,7 @@ static const device_config_t mach64vt2_config[] = { const device_t mach64gx_isa_device = { .name = "ATI Mach64GX ISA", .internal_name = "mach64gx_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = 0, .init = mach64gx_init, .close = mach64_close, diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 19f51bd9d..73be7cd76 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4887,7 +4887,7 @@ const device_t gd5402_isa_device = { const device_t gd5402_onboard_device = { .name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2) (On-Board)", .internal_name = "cl_gd5402_onboard", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5402 | 0x200, .init = gd54xx_init, .close = gd54xx_close, @@ -4901,7 +4901,7 @@ const device_t gd5402_onboard_device = { const device_t gd5420_isa_device = { .name = "Cirrus Logic GD5420 (ISA)", .internal_name = "cl_gd5420_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5420, .init = gd54xx_init, .close = gd54xx_close, @@ -4915,7 +4915,7 @@ const device_t gd5420_isa_device = { const device_t gd5422_isa_device = { .name = "Cirrus Logic GD5422 (ISA)", .internal_name = "cl_gd5422_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5422, .init = gd54xx_init, .close = gd54xx_close, @@ -4943,7 +4943,7 @@ const device_t gd5424_vlb_device = { const device_t gd5426_isa_device = { .name = "Cirrus Logic GD5426 (ISA)", .internal_name = "cl_gd5426_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5426, .init = gd54xx_init, .close = gd54xx_close, @@ -4958,7 +4958,7 @@ const device_t gd5426_isa_device = { const device_t gd5426_diamond_speedstar_pro_a1_isa_device = { .name = "Cirrus Logic GD5426 (ISA) (Diamond SpeedStar Pro Rev. A1)", .internal_name = "cl_gd5426_diamond_a1_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5426 | 0x100, .init = gd54xx_init, .close = gd54xx_close, @@ -5000,7 +5000,7 @@ const device_t gd5426_onboard_device = { const device_t gd5428_isa_device = { .name = "Cirrus Logic GD5428 (ISA)", .internal_name = "cl_gd5428_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5428, .init = gd54xx_init, .close = gd54xx_close, @@ -5043,7 +5043,7 @@ const device_t gd5428_diamond_speedstar_pro_b1_vlb_device = { const device_t gd5428_boca_isa_device = { .name = "Cirrus Logic GD5428 (ISA) (BOCA Research 4610)", .internal_name = "cl_gd5428_boca_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5428 | 0x100, .init = gd54xx_init, .close = gd54xx_close, @@ -5085,7 +5085,7 @@ const device_t gd5426_mca_device = { const device_t gd5428_onboard_device = { .name = "Cirrus Logic GD5428 (ISA) (On-Board)", .internal_name = "cl_gd5428_onboard", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5428, .init = gd54xx_init, .close = gd54xx_close, @@ -5113,7 +5113,7 @@ const device_t gd5428_vlb_onboard_device = { const device_t gd5429_isa_device = { .name = "Cirrus Logic GD5429 (ISA)", .internal_name = "cl_gd5429_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5429, .init = gd54xx_init, .close = gd54xx_close, @@ -5212,7 +5212,7 @@ const device_t gd5430_onboard_pci_device = { const device_t gd5434_isa_device = { .name = "Cirrus Logic GD5434 (ISA)", .internal_name = "cl_gd5434_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5434, .init = gd54xx_init, .close = gd54xx_close, @@ -5227,7 +5227,7 @@ const device_t gd5434_isa_device = { const device_t gd5434_diamond_speedstar_64_a3_isa_device = { .name = "Cirrus Logic GD5434 (ISA) (Diamond SpeedStar 64 Rev. A3)", .internal_name = "cl_gd5434_diamond_a3_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = CIRRUS_ID_CLGD5434 | 0x100, .init = gd54xx_init, .close = gd54xx_close, diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 6ff34cbb1..246decb9c 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -2964,7 +2964,7 @@ static const device_config_t et4000w32p_config[] = { const device_t et4000w32_device = { .name = "Tseng Labs ET4000/w32 ISA", .internal_name = "et4000w32", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = ET4000W32, .init = et4000w32p_init, .close = et4000w32p_close, @@ -2978,7 +2978,7 @@ const device_t et4000w32_device = { const device_t et4000w32_onboard_device = { .name = "Tseng Labs ET4000/w32 (ISA) (On-Board)", .internal_name = "et4000w32_onboard", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = ET4000W32, .init = et4000w32p_init, .close = et4000w32p_close, @@ -2992,7 +2992,7 @@ const device_t et4000w32_onboard_device = { const device_t et4000w32i_isa_device = { .name = "Tseng Labs ET4000/w32i Rev. B ISA", .internal_name = "et4000w32i", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = ET4000W32I, .init = et4000w32p_init, .close = et4000w32p_close, diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index ce756f7d8..57b0f303c 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1819,7 +1819,7 @@ const device_t ht216_32_standalone_device = { const device_t radius_svga_multiview_isa_device = { .name = "Radius SVGA Multiview ISA (HT209)", .internal_name = "radius_isa", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0x7152, /*HT209*/ .init = radius_svga_multiview_init, .close = ht216_close, diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index aecc898c4..769cd0001 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10667,7 +10667,7 @@ static const device_config_t s3_standard_config2[] = { const device_t s3_orchid_86c911_isa_device = { .name = "S3 86c911 ISA (Orchid Fahrenheit 1280)", .internal_name = "orchid_s3_911", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_ORCHID_86C911, .init = s3_init, .close = s3_close, @@ -10681,7 +10681,7 @@ const device_t s3_orchid_86c911_isa_device = { const device_t s3_diamond_stealth_vram_isa_device = { .name = "S3 86c911 ISA (Diamond Stealth VRAM)", .internal_name = "stealthvram_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_DIAMOND_STEALTH_VRAM, .init = s3_init, .close = s3_close, @@ -10695,7 +10695,7 @@ const device_t s3_diamond_stealth_vram_isa_device = { const device_t s3_ami_86c924_isa_device = { .name = "S3 86c924 ISA (AMI)", .internal_name = "ami_s3_924", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_AMI_86C924, .init = s3_init, .close = s3_close, @@ -10709,7 +10709,7 @@ const device_t s3_ami_86c924_isa_device = { const device_t s3_spea_mirage_86c801_isa_device = { .name = "S3 86c801 ISA (SPEA Mirage ISA)", .internal_name = "px_s3_v7_801_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_SPEA_MIRAGE_86C801, .init = s3_init, .close = s3_close, @@ -10779,7 +10779,7 @@ const device_t s3_mirocrystal_10sd_805_vlb_device = { const device_t s3_phoenix_86c801_isa_device = { .name = "S3 86c801 ISA (Phoenix)", .internal_name = "px_86c801_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_PHOENIX_86C801, .init = s3_init, .close = s3_close, @@ -10807,7 +10807,7 @@ const device_t s3_phoenix_86c805_vlb_device = { const device_t s3_metheus_86c928_isa_device = { .name = "S3 86c928 ISA (Metheus Premier 928)", .internal_name = "metheus928_isa", - .flags = DEVICE_AT | DEVICE_ISA, + .flags = DEVICE_ISA16, .local = S3_METHEUS_86C928, .init = s3_init, .close = s3_close, diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index a469330af..2cc20044a 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -3815,7 +3815,7 @@ const device_t xga_device = { const device_t xga_isa_device = { .name = "XGA (ISA)", .internal_name = "xga_isa", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = xga_init, .close = xga_close, @@ -3829,7 +3829,7 @@ const device_t xga_isa_device = { const device_t inmos_isa_device = { .name = "INMOS XGA (ISA)", .internal_name = "inmos_xga_isa", - .flags = DEVICE_ISA | DEVICE_AT, + .flags = DEVICE_ISA16, .local = 0, .init = svga_xga_init, .close = xga_close, From a8cbb4deef63495159f28045ad95125353721011 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 08:03:15 +0100 Subject: [PATCH 0256/1190] Corrected the ISA and Sidecar flags. --- src/include/86box/machine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index bf4954ae9..8676fa5f1 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -26,8 +26,8 @@ #define MACHINE_BUS_NONE 0x00000000 /* sys has no bus */ /* Feature flags for BUS'es. */ #define MACHINE_BUS_CASSETTE 0x00000001 /* sys has cassette port */ -#define MACHINE_BUS_ISA 0x00000002 /* sys has ISA bus */ -#define MACHINE_BUS_SIDECAR 0x00000004 /* sys has PCjr sidecar bus */ +#define MACHINE_BUS_SIDECAR 0x00000002 /* sys has PCjr sidecar bus */ +#define MACHINE_BUS_ISA 0x00000004 /* sys has ISA bus */ #define MACHINE_BUS_XT_KBD 0x00000008 /* sys has an XT keyboard port */ #define MACHINE_BUS_CBUS 0x00000010 /* sys has C-BUS bus */ #define MACHINE_BUS_ISA16 0x00000020 /* sys has ISA16 bus - PC/AT architecture */ From 32f2153f56dada8531df0eb20a771cae95edc15d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 08:57:30 +0100 Subject: [PATCH 0257/1190] Assume device valid if it has no bus flags set. --- src/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index ff81fe5e5..8b2ddf35e 100644 --- a/src/device.c +++ b/src/device.c @@ -797,7 +797,7 @@ device_is_valid(const device_t *device, int mch) { int ret = 1; - if (device != NULL) + if ((device != NULL) && ((device->flags & DEVICE_BUS) != 0)) ret = machine_has_bus(mch, device->flags & DEVICE_BUS); return ret; From 58089997a4a2e845052cbdeb3109f9cd8cb537a0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:03:57 +0100 Subject: [PATCH 0258/1190] Machine status: initialize it for the two cartridge bays as well. --- src/machine_status.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/machine_status.c b/src/machine_status.c index 16976fa83..3eb2762bc 100644 --- a/src/machine_status.c +++ b/src/machine_status.c @@ -45,11 +45,13 @@ machine_status_init(void) machine_status.mo[i].active = false; } + for (size_t i = 0; i < 2; i++) + machine_status.cartridge[i].empty = (strlen(cart_fns[i]) == 0); + machine_status.cassette.empty = (strlen(cassette_fname) == 0); - for (size_t i = 0; i < HDD_BUS_USB; i++) { + for (size_t i = 0; i < HDD_BUS_USB; i++) machine_status.hdd[i].active = false; - } for (size_t i = 0; i < NET_CARD_MAX; i++) { machine_status.net[i].active = false; From 51185745648813c1e07feaf178b325ce691af9b0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:06:20 +0100 Subject: [PATCH 0259/1190] Attempt to resolve again. --- src/video/vid_svga.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 7c674e00a..86173adef 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1543,8 +1543,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ - } else if ((info->flags & DEVICE_CBUS) || (info->flags & DEVICE_ISA16)) { + } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = NULL; From 7b1326236c0f967049664d8cc4bfa6b420d15bc4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:06:58 +0100 Subject: [PATCH 0260/1190] Tabs. --- src/video/vid_svga.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 86173adef..ffca0037f 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1543,6 +1543,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); + /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; From 549df9af7f841f99285ba9ccd882e3f2daf757fd Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:09:51 +0100 Subject: [PATCH 0261/1190] Updated a header. --- src/include/86box/fdd_86f.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/include/86box/fdd_86f.h b/src/include/86box/fdd_86f.h index cc8035965..de7bb7dcb 100644 --- a/src/include/86box/fdd_86f.h +++ b/src/include/86box/fdd_86f.h @@ -8,13 +8,11 @@ * * Definitions for the 86F floppy image format. * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2019 Miran Grca. - * Copyright 2018-2019 Fred N. van Kempen. + * Copyright 2016-2025 Miran Grca. + * Copyright 2018-2025 Fred N. van Kempen. */ #ifndef EMU_FLOPPY_86F_H #define EMU_FLOPPY_86F_H From 4e1926f954fb5a6dd033dffa209405b181de1d58 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 09:11:49 +0100 Subject: [PATCH 0262/1190] The last time. --- src/video/vid_svga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index ffca0037f..7c674e00a 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1544,7 +1544,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); /* The chances of ever seeing a C-BUS (S)VGA card are approximately zero, but you never know. */ - } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_ISA16)) { + } else if ((info->flags & DEVICE_CBUS) || (info->flags & DEVICE_ISA16)) { svga->read = svga_read; svga->readw = svga_readw; svga->readl = NULL; From 9236856ad5131ee9c70fdc66af6d0606c1ff68c7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 16:39:42 +0100 Subject: [PATCH 0263/1190] Fixed the DEVICE_COM flags onwards, should fix serial mice. --- src/include/86box/device.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 584f0f069..af546c64d 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -101,11 +101,11 @@ enum { DEVICE_AC97 = 0x100000, /* requires the AC'97 bus */ DEVICE_BUS = 0xffffff, /* requires a machine bus */ - DEVICE_COM = 0x100000, /* requires a serial port */ - DEVICE_LPT = 0x200000, /* requires a parallel port */ + DEVICE_COM = 0x200000, /* requires a serial port */ + DEVICE_LPT = 0x400000, /* requires a parallel port */ - DEVICE_KBC = 0x400000, /* is a keyboard controller */ - DEVICE_SOFTRESET = 0x800000, /* requires to be reset on soft reset */ + DEVICE_KBC = 0x800000, /* is a keyboard controller */ + DEVICE_SOFTRESET = 0x1000000, /* requires to be reset on soft reset */ DEVICE_ONBOARD = 0x40000000, /* is on-board */ DEVICE_PIT = 0x80000000, /* device is a PIT */ From 1d87a200e1f685e307c913f1ba5bc619ecab7132 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Feb 2025 16:42:53 +0100 Subject: [PATCH 0264/1190] Fixed DEVICE_BUS as well. --- src/include/86box/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index af546c64d..1c3ef1ef3 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -99,7 +99,7 @@ enum { DEVICE_USB = 0x40000, /* requires the USB bus */ DEVICE_AGP = 0x80000, /* requires the AGP bus */ DEVICE_AC97 = 0x100000, /* requires the AC'97 bus */ - DEVICE_BUS = 0xffffff, /* requires a machine bus */ + DEVICE_BUS = 0x1fffff, /* requires a machine bus */ DEVICE_COM = 0x200000, /* requires a serial port */ DEVICE_LPT = 0x400000, /* requires a parallel port */ From 466bcc68b40328e13d236f4973f0592c7894115a Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 08:09:43 +0900 Subject: [PATCH 0265/1190] update header files I forgot updating header files --- src/include/86box/fdc.h | 4 ++-- src/include/86box/machine.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 0d71dd374..0c2e5ce06 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -52,7 +52,7 @@ #define FDC_FLAG_ALI 0x800 /* ALi M512x / M1543C */ #define FDC_FLAG_NO_DSR_RESET 0x1000 /* Has no DSR reset */ #define FDC_FLAG_NEC 0x2000 /* Is NEC upd765-compatible */ -#define FDC_FLAG_PS55 0x4000 /* PS/55 */ +#define FDC_FLAG_PS2 0x4000 /* PS/2, PS/55 */ #define FDC_FLAG_SEC 0x10000 /* Is Secondary */ #define FDC_FLAG_TER 0x20000 /* Is Tertiary */ #define FDC_FLAG_QUA 0x40000 /* Is Quaternary */ @@ -253,7 +253,7 @@ extern const device_t fdc_at_qua_device; extern const device_t fdc_at_actlow_device; extern const device_t fdc_at_ps1_device; extern const device_t fdc_at_ps1_2121_device; -extern const device_t fdc_at_ps55_device; +extern const device_t fdc_at_ps2_device; extern const device_t fdc_at_smc_device; extern const device_t fdc_at_ali_device; extern const device_t fdc_at_winbond_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index fe867a4dc..3efb5a8e8 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -887,7 +887,8 @@ extern int machine_ps2_model_70_type3_init(const machine_t *); extern int machine_ps2_model_80_init(const machine_t *); extern int machine_ps2_model_80_axx_init(const machine_t *); extern int machine_ps2_model_70_type4_init(const machine_t *); -extern int machine_ps55_model_50t_init(const machine_t*); +extern int machine_ps55_model_50t_init(const machine_t*);; +extern int machine_ps55_model_50v_init(const machine_t*); /* m_tandy.c */ extern int tandy1k_eeprom_read(void); From cb67a389b17ec1aa03be9a0fa51e631b2160e659 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 08:14:31 +0900 Subject: [PATCH 0266/1190] modified ps/55 configuration, added a mca func I forgot updating some files --- src/86box.c | 2 +- src/config.c | 6 ++++++ src/mca.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index 82eedbd78..9b77263a2 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1062,7 +1062,7 @@ pc_init_modules(void) void pc_send_ca(uint16_t sc) { - /* Use R-Alt because 5576-002 keyboard assigns L-Alt as */ + /* Use R-Alt because PS/55 DOS assigns L-Alt as Kanji */ keyboard_input(1, 0x1D); /* Ctrl key pressed */ keyboard_input(1, 0x138); /* R-Alt key pressed */ keyboard_input(1, sc); diff --git a/src/config.c b/src/config.c index 2c0781028..7a5d76465 100644 --- a/src/config.c +++ b/src/config.c @@ -456,6 +456,7 @@ load_video(void) ibm8514_active = ibm8514_standalone_enabled; xga_standalone_enabled = !!ini_section_get_int(cat, "xga", 0); xga_active = xga_standalone_enabled; + da2_standalone_enabled = !!ini_section_get_int(cat, "da2", 0); show_second_monitors = !!ini_section_get_int(cat, "show_second_monitors", 1); video_fullscreen_scale_maximized = !!ini_section_get_int(cat, "video_fullscreen_scale_maximized", 0); @@ -2013,6 +2014,11 @@ save_video(void) else ini_section_set_int(cat, "xga", xga_standalone_enabled); + if (da2_standalone_enabled == 0) + ini_section_delete_var(cat, "da2"); + else + ini_section_set_int(cat, "da2", da2_standalone_enabled); + // TODO for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if (gfxcard[i] == 0) diff --git a/src/mca.c b/src/mca.c index 871060bb4..a14fea6fa 100644 --- a/src/mca.c +++ b/src/mca.c @@ -101,3 +101,19 @@ mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t v } } } + +void +mca_add_to_slot(uint8_t (*read)(int addr, void* priv), void (*write)(int addr, uint8_t val, void* priv), uint8_t(*feedb)(void* priv), void (*reset)(void* priv), void* priv, int c) +{ + if (mca_card_read[c] || mca_card_write[c]) + { + //pclog("cannot add the device to slot %d\n", num); + return; + } + mca_card_read[c] = read; + mca_card_write[c] = write; + mca_card_feedb[c] = feedb; + mca_card_reset[c] = reset; + mca_priv[c] = priv; + return; +} From bfac770b4e19cb1bc23396a98263e6f1fd097208 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 08:27:17 +0900 Subject: [PATCH 0267/1190] reupload without code modification --- src/include/86box/vid_ps55da2.h | 48 +- src/video/vid_ps55da2.c | 6444 +++++++++++++++---------------- 2 files changed, 3246 insertions(+), 3246 deletions(-) diff --git a/src/include/86box/vid_ps55da2.h b/src/include/86box/vid_ps55da2.h index 70007be19..f029b5751 100644 --- a/src/include/86box/vid_ps55da2.h +++ b/src/include/86box/vid_ps55da2.h @@ -1,24 +1,24 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * IBM PS/55 Display Adapter II emulation. - * - * - * - * Authors: Akamaki. - * - * Copyright 2024 Akamaki. - */ - -#ifndef VIDEO_DA2_DEVICE_H -#define VIDEO_DA2_DEVICE_H - -#ifdef EMU_DEVICE_H -extern const device_t ps55da2_device; -#endif -#endif /*VIDEO_DA2_DEVICE_H*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PS/55 Display Adapter II emulation. + * + * + * + * Authors: Akamaki. + * + * Copyright 2024 Akamaki. + */ + +#ifndef VIDEO_DA2_DEVICE_H +#define VIDEO_DA2_DEVICE_H + +#ifdef EMU_DEVICE_H +extern const device_t ps55da2_device; +#endif +#endif /*VIDEO_DA2_DEVICE_H*/ diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index a19965f6f..0ac136630 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1,3222 +1,3222 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * IBM PS/55 Display Adapter II emulation. - * - * Authors: Akamaki. - * - * Copyright 2024 Akamaki. - */ - -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/device.h> -#include <86box/io.h> -#include <86box/machine.h> -#include <86box/mem.h> -#include <86box/timer.h> -#include <86box/mca.h> -#include <86box/rom.h> -#include <86box/plat.h> -#include <86box/thread.h> -#include <86box/video.h> -#include <86box/vid_ps55da2.h> -#include <86box/vid_svga.h> -#include <86box/vid_svga_render.h> -#include "cpu.h" - -#define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" -#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" -#define DA2_FONTROM_SIZE 1536*1024 -#define DA2_FONTROM_BASESBCS 0x98000 -#define DA2_GAIJIRAM_SBCS 0x34000 -#define DA2_GAIJIRAM_SBEX 0x3c000 -#define DA2_INVALIDACCESS8 0xff -#define DA2_MASK_MMIO 0x1ffff -#define DA2_MASK_GRAM 0x1ffff -#define DA2_MASK_CRAM 0xfff -#define DA2_MASK_GAIJIRAM 0x3ffff -#define DA2_PIXELCLOCK 58000000.0 -#define DA2_BLT_MEMSIZE 0x100 -#define DA2_BLT_REGSIZE 0x40 -#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) -#define DA2_DEBUG_BLTLOG_MAX 256*1024 -#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe -#define DA2_DEBUG_BLT_USEDRESET 0xfefefe -#define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ -//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ -//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ -#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ -#define DA2_DCONFIG_MONTYPE_COLOR 0x0A -#define DA2_DCONFIG_MONTYPE_8515 0x0B -#define DA2_DCONFIG_MONTYPE_MONO 0x09 - -#define DA2_BLT_CIDLE 0 -#define DA2_BLT_CFILLRECT 1 -#define DA2_BLT_CFILLTILE 2 -#define DA2_BLT_CCOPYF 3 -#define DA2_BLT_CCOPYR 4 -#define DA2_BLT_CPUTCHAR 5 -#define DA2_BLT_CDONE 6 -#define DA2_BLT_CLOAD 7 -/* POS ID = 0xeffe : Display Adapter II, III, V */ -#define DA2_POSID_H 0xef -#define DA2_POSID_L 0xfe -/* - [Identification] - POS ID SYS ID - EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] - E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] - EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] - |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) - |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) - |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) - ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] - |- * Display Adapter IV - ECCEh * Display Adapter IV - 901Fh * Display Adapter A2 - 901Dh * Display Adapter A1 [Atlas II] - 901Eh * Plasma Display Adapter - EFD8h * Display Adapter/J [Atlas-SP2] - - [Japanese DOS and Display Adapter compatibility] - | POS ID | Adapter Name | K3.31 | J4.04 | J5.02 | OS2 J1.3 | Win3 | - |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| - | EFFFh | Display Adapter | X | | | ? | | - | FFEDh | ? [Atlas EVT] | X | | | ? | | - | FFFDh | ? [LDT EVT] | X | | | ? | | - | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | - | E013h | ? [LDT] | X | X | X | X | | - | ECCEh | Display Adapter IV | | X | X | X | | - | ECECh | Display Adapter IV,B1 | | X | X | X | X | - | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | - | EFD8h | Display Adapter /J | | | X | X | X | -*/ -/* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ -#define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ -//#define Mon_ID3 0x10 -#define FontCard 0x08 /* ? */ -/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ -#define Page_One 0x06 /* 80000h 110b */ -#define Page_Two 0x05 /* 100000h 101b */ -#define Page_Four 0x03 /* 200000h 011b */ - -/* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ -#define AddPage 0x08 /* ? */ -//#define Mon_ID2 0x04 -//#define Mon_ID1 0x02 -//#define Mon_ID0 0x01 -/* Monitor ID (imported from OS/2 DDK 1.2) */ -//#define StarbuckC 0x0A //1 010b IBM 8514, 9518 color 1040x768 -//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale -//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp -//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B - -/* DA2 Registers (imported from OS/2 DDK) */ -#define AC_REG 0x3EE -#define AC_DMAE 0x80 -#define AC_FONT_SEL 0x40 -#define FONT_BANK 0x3EF -#define LS_INDEX 0x3E0 -#define LS_DATA 0x3E1 -#define LS_RESET 0x00 -#define LS_MODE 0x02 -#define LS_STATUS 0x03 /* added */ -#define LS_MMIO 0x08 /* added */ -#define LS_CONFIG1 0x0a -#define LS_CONFIG2 0x0b /* added */ -#define LF_INDEX 0x3e2 -#define LF_DATA 0x3e3 -#define LF_MMIO_SEL 0x08 /* added */ -#define LF_MMIO_ADDR 0x0A /* added */ -#define LF_MMIO_MODE 0x0B /* added */ -#define LC_INDEX 0x3E4 -#define LC_DATA 0x3E5 -#define LC_HORIZONTAL_TOTAL 0x00 -#define LC_H_DISPLAY_ENABLE_END 0x01 -#define LC_START_H_BLANKING 0x02 -#define LC_END_H_BLANKING 0x03 -#define LC_START_HSYNC_PULSE 0x04 -#define LC_END_HSYNC_PULSE 0x05 -#define LC_VERTICAL_TOTALJ 0x06 -#define LC_CRTC_OVERFLOW 0x07 -#define LC_PRESET_ROW_SCANJ 0x08 -#define LC_MAXIMUM_SCAN_LINE 0x09 -#define LC_CURSOR_ROW_START 0x0A -#define LC_CURSOR_ROW_END 0x0B -#define LC_START_ADDRESS_HIGH 0x0C -#define LC_START_ADDRESS_LOW 0x0D -#define LC_CURSOR_LOC_HIGH 0x0E -#define LC_ROW_CURSOR_LOC 0x0E -#define LC_CURSOR_LOC_LOWJ 0x0F -#define LC_COLUMN_CURSOR_LOC 0x0F -#define LC_VERTICAL_SYNC_START 0x10 -#define LC_LIGHT_PEN_HIGH 0x10 -#define LC_VERTICAL_SYNC_END 0x11 -#define LC_LIGHT_PEN_LOW 0x11 -#define LC_V_DISPLAY_ENABLE_END 0x12 -#define LC_OFFSET 0x13 -#define LC_UNDERLINE_LOCATION 0x14 -#define LC_START_VERTICAL_BLANK 0x15 -#define LC_END_VERTICAL_BLANK 0x16 -#define LC_LC_MODE_CONTROL 0x17 -#define LC_LINE_COMPAREJ 0x18 -#define LC_START_H_DISPLAY_ENAB 0x19 -#define LC_START_V_DISPLAY_ENAB 0x1A -#define LC_VIEWPORT_COMMAND 0x1B -#define LC_VIEWPORT_SELECT 0x1C -#define LC_VIEWPORT_PRIORITY 0x1D -#define LC_COMMAND 0x1E -#define LC_COMPATIBILITY 0x1F -#define LC_VIEWPORT_NUMBER 0x1F -#define LV_PORT 0x3E8 -#define LV_PALETTE_0 0x00 -#define LV_MODE_CONTROL 0x10 -#define LV_OVERSCAN_COLOR 0x11 -#define LV_COLOR_PLANE_ENAB 0x12 -#define LV_PANNING 0x13 -#define LV_VIEWPORT1_BG 0x14 -#define LV_VIEWPORT2_BG 0x15 -#define LV_VIEWPORT3_BG 0x16 -#define LV_BLINK_COLOR 0x17 -#define LV_BLINK_CODE 0x18 -#define LV_GR_CURSOR_ROTATION 0x19 -#define LV_GR_CURSOR_COLOR 0x1A -#define LV_GR_CURSOR_CONTROL 0x1B -#define LV_COMMAND 0x1C -#define LV_VP_BORDER_LINE 0x1D -#define LV_SYNC_POLARITY 0x1F -#define LV_CURSOR_CODE_0 0x20 -#define LV_GRID_COLOR_0 0x34 -#define LV_GRID_COLOR_1 0x35 -#define LV_GRID_COLOR_2 0x36 -#define LV_GRID_COLOR_3 0x37 -#define LV_ATTRIBUTE_CNTL 0x38 -#define LV_CURSOR_COLOR 0x3A -#define LV_CURSOR_CONTROL 0x3B -#define LV_RAS_STATUS_VIDEO 0x3C -#define LV_PAS_STATUS_CNTRL 0x3D -#define LV_IDENTIFICATION 0x3E -#define LV_OUTPUT 0x3E -#define LV_COMPATIBILITY 0x3F -#define LG_INDEX 0x3EA -#define LG_DATA 0x3EB -#define LG_SET_RESETJ 0x00 -#define LG_ENABLE_SRJ 0x01 -#define LG_COLOR_COMPAREJ 0x02 -#define LG_DATA_ROTATION 0x03 -#define LG_READ_MAP_SELECT 0x04 -#define LG_MODE 0x05 -#define LG_COMPLEMENT 0x06 -#define LG_COLOR_DONT_CARE 0x07 -#define LG_BIT_MASK_LOW 0x08 -#define LG_BIT_MASK_HIGH 0x09 -#define LG_MAP_MASKJ 0x0A -#define LG_COMMAND 0x0B -#define LG_SET_RESET_2 0x10 - -#ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 -#endif - -#ifdef ENABLE_DA2_LOG -int da2_do_log = ENABLE_DA2_LOG; - -static void -da2_log(const char* fmt, ...) -{ - va_list ap; - - if (da2_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -# define da2_log(fmt, ...) -#endif -#ifndef RELEASE_BUILD -# define ENABLE_DA2_DEBUGBLT 1 -#endif - -typedef struct da2_t -{ - //mem_mapping_t vmapping; - mem_mapping_t cmapping; - - //uint8_t crtcreg; - uint8_t ioctl[16]; - uint8_t fctl[32]; - uint16_t crtc[128]; - uint8_t gdcreg[64]; - uint8_t reg3ee[16]; - int gdcaddr; - uint8_t attrc[0x40]; - int attraddr, attrff; - int attr_palette_enable; - //uint8_t seqregs[64]; - int outflipflop; - int inflipflop; - int iolatch; - - int ioctladdr; - int fctladdr; - int crtcaddr; - - uint32_t decode_mask; - uint32_t vram_max; - uint32_t vram_mask; - - uint32_t gdcla[8]; - uint32_t gdcinput[8]; - uint32_t gdcsrc[8]; - uint32_t debug_vramold[8]; - - uint8_t dac_mask, dac_status; - int dac_read, dac_write, dac_pos; - int dac_r, dac_g; - - uint8_t cgastat; - - uint8_t plane_mask; - - int fb_only; - - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; - uint8_t writemask; - uint32_t charseta, charsetb; - - uint8_t egapal[16]; - uint32_t pallook[512]; - PALETTE vgapal; - - int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; - int lowres, interlace; - int rowcount; - double clock; - uint32_t ma_latch, ca_adj; - - uint64_t dispontime, dispofftime; - pc_timer_t timer; - uint64_t da2const; - - int dispon; - int hdisp_on; - - uint32_t ma, maback, ca; - int vc; - int sc; - int linepos, vslines, linecountff, oddeven; - int con, cursoron, blink, blinkconf; - int scrollcache; - int char_width; - - int firstline, lastline; - int firstline_draw, lastline_draw; - int displine; - - /* Attribute Buffer E0000-E0FFFh (4 KB) */ - uint8_t *cram; - /* (cram size - 1) >> 3 = 0xFFF */ - //uint32_t cram_display_mask; - /* APA Buffer A0000-BFFFFh (128 KB) */ - uint8_t *vram; - /* addr >> 12 = xx000h */ - uint8_t *changedvram; - /* (vram size - 1) >> 3 = 0x1FFFF */ - uint32_t vram_display_mask; - - //uint32_t write_bank, read_bank; - - int fullchange; - - void (*render)(struct da2_t* da2); - - /*If set then another device is driving the monitor output and the SVGA - card should not attempt to display anything */ - int override; - - /* end VGA compatible regs*/ - struct - { - int enable; - mem_mapping_t mapping; - uint8_t ram[256 * 1024]; - uint8_t *font; - int charset; - } mmio; - - struct { - int bitshift_destr; - int raster_op; - uint8_t payload[DA2_BLT_MEMSIZE]; - int32_t reg[DA2_BLT_REGSIZE];//must be signed int - int32_t* debug_reg;//for debug - int debug_reg_ip;//for debug - int payload_addr; - pc_timer_t timer; - int64_t timerspeed; - int exec; - int indata; - int32_t destaddr; - int32_t srcaddr; - int32_t size_x, tile_w; - int32_t size_y; - int16_t destpitch; - int16_t srcpitch; - int32_t fcolor; - int32_t maskl, maskr; - int x, y; - } bitblt; - - FILE* mmdbg_fp; - FILE* mmrdbg_fp; - uint32_t mmdbg_vidaddr; - uint32_t mmrdbg_vidaddr; - - uint8_t pos_regs[8]; - svga_t *mb_vga; - uint8_t monitorid; - - int old_pos2; -} da2_t; - -void da2_recalctimings(da2_t* da2); -static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p); -void da2_bitblt_exec(void* p); -void da2_updatevidselector(da2_t* da2); -void da2_reset_ioctl(da2_t* da2); -static void da2_reset(void* priv); - -typedef union { - uint32_t d; - uint8_t b[4]; -} DA2_VidSeq32; - -typedef struct { - uint32_t p8[8]; -} pixel32; - -/* safety read for internal functions */ -uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) -{ - if (addr & ~da2->vram_mask) return -1; - return da2->vram[addr]; -} - -void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32* srcpx, da2_t* da2) -{ - uint32_t writepx[8]; - destaddr &= 0xfffffffe;/* align to word address to work bit shift correctly */ - //da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); - da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; - da2->changedvram[(da2->vram_display_mask & (destaddr+1)) >> 12] = changeframecount; - destaddr <<= 3; - /* read destination data with big endian order */ - for (int i = 0; i < 8; i++) - writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) - | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); - - DA2_VidSeq32 mask32in; mask32in.d = (uint32_t)mask; - DA2_VidSeq32 mask32; mask32.d = 0; - mask32.b[3] = mask32in.b[0]; - mask32.b[2] = mask32in.b[1]; - mask32.d &= 0xffff0000; - for (int i = 0; i < 8; i++) - { - if (da2->bitblt.bitshift_destr > 0) - srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; - switch (da2->bitblt.raster_op) { - case 0x00: /* None */ - writepx[i] &= ~mask32.d; - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x01: /* AND */ - writepx[i] &= srcpx->p8[i] | ~mask32.d; - break; - case 0x02: /* OR */ - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x03: /* XOR */ - writepx[i] ^= srcpx->p8[i] & mask32.d; - break; - } - } - for (int i = 0; i < 8; i++) { - da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; - da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; - } -} - -void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) -{ - pixel32 srcpx; - //fill data with input color - for (int i = 0; i < 8; i++) - srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;//read in word - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); -} -/* -Param Desc -01 Color -03 Bit Shift -04 Select plane? -05 Dir(10 or 11) + Command?(40 or 48) -08 Mask Left -09 Mask Right -0A Plane Mask? -0B ROP?(8h or 200h + 0-3h) -0D -20 Exec (1) -21 ? -22 ? -23 Tile W -28 Tile H -29 Dest Addr -2A Src Addr -2B Tile Addr -33 Size W -35 Size H - -*/ -void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) -{ - pixel32 srcpx; - srcaddr &= 0xfffffffe; - srcaddr <<= 3; - for (int i = 0; i < 8; i++) - srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) - | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24);//read in word - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); -} -void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) -{ - pixel32 srcpx; - if (srcaddr >= DA2_FONTROM_SIZE) { - da2_log("DA2 Putchar Addr Error %x\n", srcaddr); - return; - } - for (int i = 0; i < 8; i++) - srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) - | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) - | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) - | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); -} -#ifdef ENABLE_DA2_DEBUGBLT -uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { - uint8_t pixeldata = 0; - for (int j = 0; j < 8; j++) { - if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) pixeldata++; - } - return pixeldata; -} -void print_pixelbyte(uint32_t addr, da2_t* da2) { - for (int i = 0; i < 8; i++) - { - pclog("%X", pixel1tohex(addr, i, da2)); - } -} -void print_bytetobin(uint8_t b) { - for (int i = 0; i < 8; i++) - { - if(b & 0x80) - pclog("1"); - else - pclog("0"); - b <<= 1; - } -} -//Convert internal char code to Shift JIS code -inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } -inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } -uint16_t IBMJtoSJIS(uint16_t knj) -{ - if (knj < 0x100) return 0xffff; - knj -= 0x100; - if (knj <= 0x1f7d) - ;/* do nothing */ - else if (knj >= 0xb700 && knj <= 0xb75f) { - knj -= 0x90ec; - } - else if (knj >= 0xb3f0 && knj <= 0xb67f) { - knj -= 0x906c; - } - else if (knj >= 0x8000 && knj <= 0x8183) - { - knj -= 0x5524; - } - else - return 0xffff; - uint32_t knj1 = knj / 0xBC; - uint32_t knj2 = knj - (knj1 * 0xBC); - knj1 += 0x81; - if (knj1 > 0x9F) knj1 += 0x40; - knj2 += 0x40; - if (knj2 > 0x7E) knj2++; - //if (!isKanji1(knj1)) return 0xffff; - //if (!isKanji2(knj2)) return 0xffff; - knj = knj1 << 8; - knj |= knj2; - return knj; -} -#endif -void da2_bitblt_load(da2_t* da2) -{ - uint32_t value32; - uint64_t value64; - da2_log("BITBLT loading params\n"); - //da2_log("BitBlt memory:\n"); - //if (da2->bitblt.payload[0] != 0) - // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) - // { - // int i = j * 8; - // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - // } - int i = 0; - while (i < DA2_BLT_MEMSIZE) - { - if (da2->bitblt.reg[0x20] & 0x1) - break; - switch (da2->bitblt.payload[i]) { - case 0x88: - case 0x89: - case 0x95: - value32 = da2->bitblt.payload[i + 3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - i += 3; - break; - case 0x91: - value32 = da2->bitblt.payload[i + 5]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 4]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - i += 5; - break; - case 0x99: - value64 = da2->bitblt.payload[i + 7]; - value64 <<= 8; - value64 = da2->bitblt.payload[i + 6]; - value64 <<= 8; - value64 = da2->bitblt.payload[i + 5]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 4]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 3]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 2]; - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; - da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - i += 7; - break; - case 0x00: - break; - default: - da2_log("da2_ParseBLT: Unknown PreOP!\n"); - break; - } - i++; - } - da2->bitblt.exec = DA2_BLT_CIDLE; - /* clear payload memory */ - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - da2->bitblt.payload_addr = 0; - /* [89] 20: 0001 (1) then execute payload */ - if (da2->bitblt.reg[0x20] & 0x1) - { -#ifdef ENABLE_DA2_DEBUGBLT - for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { - //if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); - } - for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { - da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; - } - da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; - da2->bitblt.debug_reg_ip++; - if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; -#endif - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);//set bit shift - da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;//01 AND, 03 XOR - da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); - for (int i = 0; i <= 0xb; i++) - da2_log("%02x ", da2->gdcreg[i]); - da2_log("\n"); - - da2->bitblt.destaddr = da2->bitblt.reg[0x29]; - da2->bitblt.size_x = da2->bitblt.reg[0x33]; - da2->bitblt.size_y = da2->bitblt.reg[0x35]; - da2->bitblt.destpitch = da2->bitblt.reg[0x21]; - da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; - if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; - { - da2->bitblt.destaddr -= 2; - da2->bitblt.size_x += 1; - da2->bitblt.destpitch -= 2; - da2->bitblt.srcpitch -= 2; - } - da2->bitblt.fcolor = da2->bitblt.reg[0x0]; - da2->bitblt.maskl = da2->bitblt.reg[0x8]; - da2->bitblt.maskr = da2->bitblt.reg[0x9]; - da2->bitblt.x = 0; - da2->bitblt.y = 0; - da2->bitblt.exec = DA2_BLT_CDONE; - timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - - if (da2->bitblt.reg[0x2f] < 0x80)//MS Paint 3.1 will cause hang up in 256 color mode - { - da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); - da2->bitblt.exec = DA2_BLT_CDONE; - } - else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - /* Todo: addressing */ - //if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; - //{ - // da2->bitblt.destaddr += 2; - // da2->bitblt.size_x -= 1; - // da2->bitblt.destpitch += 2; - // da2->bitblt.srcpitch += 2; - //} - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; - da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ - da2->bitblt.bitshift_destr += 1; - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); - } - else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; - da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ - da2->bitblt.bitshift_destr += 1; - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); - } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {/* Fill a rectangle(or draw a line) */ - da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); - da2->bitblt.exec = DA2_BLT_CFILLRECT; - da2->bitblt.destaddr += 2; - } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ - da2->bitblt.exec = DA2_BLT_CFILLTILE; - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; - da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle (transfer tile data multiple times) */ - da2->bitblt.exec = DA2_BLT_CFILLTILE; - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; - da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {/* Block transfer (range copy) */ - da2->bitblt.exec = DA2_BLT_CCOPYF; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; - da2->bitblt.destaddr += 2; - da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {/* Block copy but reversed direction */ - da2->bitblt.exec = DA2_BLT_CCOPYR; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; - da2->bitblt.destaddr -= 2; - da2->bitblt.srcaddr -= 2; - da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); - } - } -} -void da2_bitblt_exec(void* p) -{ - da2_t* da2 = (da2_t*)p; - timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - //da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); - switch (da2->bitblt.exec) - { - case DA2_BLT_CIDLE: - timer_disable(&da2->bitblt.timer); - break; - case DA2_BLT_CLOAD: - da2->bitblt.indata = 0; - da2_bitblt_load(da2); - break; - case DA2_BLT_CFILLRECT: - //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - break; - case DA2_BLT_CFILLTILE: - int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - break; - case DA2_BLT_CCOPYF: - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr += 2; - break; - case DA2_BLT_CCOPYR: - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr -= da2->bitblt.destpitch; - da2->bitblt.srcaddr -= da2->bitblt.srcpitch; - da2->bitblt.destaddr -= 2; - da2->bitblt.srcaddr -= 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr -= 2; - da2->bitblt.srcaddr -= 2; - break; - case DA2_BLT_CPUTCHAR: - //da2->bitblt.y += 2; - da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; - pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); - //da2->bitblt.srcaddr += 2; - if(da2->bitblt.reg[0x12] < 0x100) - da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; - else - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); - pclog("\n"); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - //if (1) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 3) - { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += 130; - //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - //da2->bitblt.srcaddr += -1; - } - else if (da2->bitblt.x == 0) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; - ////da2->bitblt.srcaddr += 2; - //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; - break; - case DA2_BLT_CDONE: - /* initialize regs for debug dump */ - for (int i = 0; i < DA2_BLT_REGSIZE; i++) { - if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; - } - if(da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; - else da2->bitblt.exec = DA2_BLT_CIDLE; - break; - } -} -void da2_bitblt_dopayload(da2_t* da2) { - if (da2->bitblt.exec == DA2_BLT_CIDLE) - { - da2->bitblt.exec = DA2_BLT_CLOAD; - //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ - da2_log("da2 Do bitblt\n"); - while (da2->bitblt.exec != DA2_BLT_CIDLE) - { - da2_bitblt_exec(da2); - } - da2_log("da2 End bitblt %x\n", da2->bitblt.exec); - } -} - -void da2_out(uint16_t addr, uint16_t val, void *p) -{ - da2_t *da2 = (da2_t *)p; - int oldval; -/* -3E0 3E1 Sequencer Registers (undoc) -3E2 3E3 Font Registers (undoc) -3E4 3E5 CRT Control Registers (undoc) -3E8 3E9 Attribute Controller Registers (undoc) -3EA 3EB 3EC Graphics Contoller Registers -*/ - switch (addr) - { - case 0x3c6: /* PEL Mask */ - da2->dac_mask = val; - break; - case 0x3C7: /* Read Address */ - da2->dac_read = val; - da2->dac_pos = 0; - break; - case 0x3C8: /* Write Address */ - da2->dac_write = val; - da2->dac_read = val - 1; - da2->dac_pos = 0; - break; - case 0x3C9: /* Data */ - //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); - da2->dac_status = 0; - da2->fullchange = changeframecount; - switch (da2->dac_pos) - { - case 0: - da2->dac_r = val; - da2->dac_pos++; - break; - case 1: - da2->dac_g = val; - da2->dac_pos++; - break; - case 2: - da2->vgapal[da2->dac_write].r = da2->dac_r; - da2->vgapal[da2->dac_write].g = da2->dac_g; - da2->vgapal[da2->dac_write].b = val; - //if (da2->ramdac_type == RAMDAC_8BIT) - // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); - //else - da2->pallook[da2->dac_write] = makecol32((da2->vgapal[da2->dac_write].r & 0x3f) * 4, (da2->vgapal[da2->dac_write].g & 0x3f) * 4, (da2->vgapal[da2->dac_write].b & 0x3f) * 4); - da2->dac_pos = 0; - da2->dac_write = (da2->dac_write + 1) & 255; - break; - } - break; - case LS_INDEX: - da2->ioctladdr = val; - break; - case LS_DATA: - //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); - if (da2->ioctladdr > 0xf) return; - if (da2->ioctl[da2->ioctladdr & 15] != val) - da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); - oldval = da2->ioctl[da2->ioctladdr]; - da2->ioctl[da2->ioctladdr] = val; - if (oldval != val) { - if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset register */ - da2_reset_ioctl(da2); - else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ - { - da2->fullchange = changeframecount; - da2_recalctimings(da2); - da2_updatevidselector(da2); - } - else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ - { - //da2->bitblt.indata = 1; - } - } - break; - case LF_INDEX: - da2->fctladdr = val; - break; - case LF_DATA: - //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); - if (da2->fctladdr > 0x1f) return; - if (da2->fctl[da2->fctladdr & 0x1f] != val) - da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); - oldval = da2->fctl[da2->fctladdr]; - da2->fctl[da2->fctladdr] = val; - if (da2->fctladdr == 0 && oldval != val) - { - da2->fullchange = changeframecount; - da2_recalctimings(da2); - } - break; - case LC_INDEX: - da2->crtcaddr = val; - break; - case LC_DATA: - if (da2->crtcaddr > 0x1f) return; - //if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) - // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); - if (!(da2->crtc[da2->crtcaddr] ^ val)) return; - switch (da2->crtcaddr) { - case LC_CRTC_OVERFLOW: - //return; - break; - case LC_MAXIMUM_SCAN_LINE: - if (!(da2->ioctl[LS_MODE] & 0x01)) val = 0; - break; - case LC_START_ADDRESS_HIGH: - //if (da2->crtc[0x1c] & 0x40) return; - break; - case LC_VERTICAL_TOTALJ: /* Vertical Total */ - case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ - case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ - case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ - //val = 0x400; //for debugging bitblt - break; - case LC_VIEWPORT_SELECT: /* ViewPort Select? */ - //return; - break; - case LC_VIEWPORT_NUMBER: /* Compatibility? */ - break; - } - da2->crtc[da2->crtcaddr] = val; - switch (da2->crtcaddr) { - case LC_H_DISPLAY_ENABLE_END: - case LC_VERTICAL_TOTALJ: - case LC_MAXIMUM_SCAN_LINE: - case LC_START_ADDRESS_HIGH: - case LC_START_ADDRESS_LOW: - case LC_VERTICAL_SYNC_START: - case LC_V_DISPLAY_ENABLE_END: - case LC_START_VERTICAL_BLANK: - case LC_END_VERTICAL_BLANK: - case LC_VIEWPORT_PRIORITY: - da2->fullchange = changeframecount; - da2_recalctimings(da2); - break; - default: - break; - } - break; - case LV_PORT: - //da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); - if (!da2->attrff) - { - // da2->attraddr = val & 31; - da2->attraddr = val & 0x3f; - if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) - { - da2->fullchange = 3; - da2->attr_palette_enable = val & 0x20; - da2_recalctimings(da2); - } - //da2_log("set attraddr: %X\n", da2->attraddr); - } - else - { - if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val)) - da2->fullchange = changeframecount; - if (da2->attrc[da2->attraddr & 0x3f] != val) - da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); - da2->attrc[da2->attraddr & 0x3f] = val; - //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); - if (da2->attraddr < 16) - da2->fullchange = changeframecount; - if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) - { - for (int c = 0; c < 16; c++) - { - //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); - //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); - if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; - else da2->egapal[c] = da2->attrc[c] & 0x3f; - } - } - switch (da2->attraddr) - { - case LV_COLOR_PLANE_ENAB: - if ((val & 0xff) != da2->plane_mask) - da2->fullchange = changeframecount; - da2->plane_mask = val & 0xff; - break; - case LV_CURSOR_CONTROL: - switch (val & 0x18) { - case 0x08://fast blink - da2->blinkconf = 0x10; - break; - case 0x18://slow blink - da2->blinkconf = 0x20; - break; - default://no blink - da2->blinkconf = 0xff; - break; - } - break; - case LV_MODE_CONTROL: - case LV_ATTRIBUTE_CNTL: - case LV_COMPATIBILITY: - da2_recalctimings(da2); - break; - default: - break; - } - } - da2->attrff ^= 1; - break; - case 0x3E9: - /* VZ Editor's CURSOR.COM writes data via this port */ - da2->attrc[da2->attraddr & 0x3f] = val; - break; - case LG_INDEX: - da2->gdcaddr = val; - break; - case LG_DATA: - //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); - //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); - switch (da2->gdcaddr & 0x1f) - { - case LG_READ_MAP_SELECT: - da2->readplane = val & 0x7; - break; - case LG_MODE: - da2->writemode = val & 3; - break; - case LG_MAP_MASKJ: - da2->writemask = val & 0xff; - break; - case LG_COMMAND: - break; - case LG_SET_RESET_2: - da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); - return; - } - da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; - break; - //case 0x3ed: /* used by Windows 3.1 display driver */ - // da2->gdcreg[5] = val & 0xff; - // break; - default: - da2_log("DA2? Out addr %03X val %02X\n", addr, val); - break; - } -} - -uint16_t da2_in(uint16_t addr, void *p) -{ - da2_t * da2 = (da2_t *)p; - uint16_t temp; - - switch (addr) - { - case 0x3c3: - temp = 0; - break; - case 0x3c6: temp = da2->dac_mask; - break; - case 0x3c7: temp = da2->dac_status; - break; - case 0x3c8: temp = da2->dac_write; - break; - case 0x3c9: - da2->dac_status = 3; - switch (da2->dac_pos) - { - case 0: - da2->dac_pos++; - temp = da2->vgapal[da2->dac_read].r & 0x3f; - break; - case 1: - da2->dac_pos++; - temp = da2->vgapal[da2->dac_read].g & 0x3f; - break; - case 2: - da2->dac_pos = 0; - da2->dac_read = (da2->dac_read + 1) & 255; - temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; - break; - } - break; - case LS_INDEX: - temp = da2->ioctladdr; - break; - case LS_DATA: - //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) - if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; - temp = da2->ioctl[da2->ioctladdr]; - if (da2->ioctladdr == LS_STATUS) { /* Status register */ - if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ - if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { - /* grayscale monitor */ - if ((da2->vgapal[0].r >= 10) || (da2->vgapal[0].g >= 40) || (da2->vgapal[0].b >= 10)) - temp &= 0x7F; /* Inactive when the RGB output voltage is high (or the cable is not connected to a color monitor). */ - else - temp |= 0x80; /* Active when the RGB output voltage is low and the cable is connected to a color monitor. - If the cable or the monitor is wrong, it becomes inactive. */ - } else { - /* color monitor */ - if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 80) - temp &= 0x7F; - else - temp |= 0x80; - } - } else { - temp |= 0x80; - } - temp &= 0xf6;//clear busy bits - if (da2->bitblt.indata) /* for OS/2 J1.3 */ - da2_bitblt_dopayload(da2); - if (da2->bitblt.exec != DA2_BLT_CIDLE) - { - //da2_log("exec:%x\n", da2->bitblt.exec); - temp |= 0x08;//wait(bit 3 + bit 0) - //if (!da2->bitblt.timer.enabled) - //{ - // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); - // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - //} - } - if (da2->bitblt.indata) - temp |= 0x01; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); - } - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); - break; - case LF_INDEX: - temp = da2->fctladdr; - break; - case LF_DATA: - if (da2->fctladdr > 0x1f) return DA2_INVALIDACCESS8; - temp = da2->fctl[da2->fctladdr]; - break; - case LC_INDEX: - temp = da2->crtcaddr; - break; - case LC_DATA: - if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; - temp = da2->crtc[da2->crtcaddr]; - break; - case LV_PORT: - temp = da2->attraddr | da2->attr_palette_enable; - break; - case 0x3E9: - if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this may equiv to 3ba / 3da Input Status Register 1 */ - { - if (da2->cgastat & 0x01) - da2->cgastat &= ~0x30; - else - da2->cgastat ^= 0x30; - temp = da2->cgastat; - } - else - temp = da2->attrc[da2->attraddr]; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); - da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ - break; - case LG_INDEX: - temp = da2->gdcaddr; - break; - case LG_DATA: - temp = da2->gdcreg[da2->gdcaddr & 0x1f]; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); - break; - } - //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); - return temp; -} -/* -* Write I/O -* out b(idx), out b(data), out b(data) -* out b(idx), out w(data) -* out b(idx), out w(data), out b(data) -* out w(idx) -* Read I/O -* out b(idx), in b(data) -* out b(idx), in b, in b(data) -* out b(idx), in w(data) -*/ -void da2_outb(uint16_t addr, uint8_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - //da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); - da2->inflipflop = 0; - switch (addr) - { - case LS_DATA: - case LF_DATA: - case LC_DATA: - case LG_DATA: - if (da2->outflipflop) - { - /* out b(idx), out b(data), out b(data) */ - da2->iolatch |= (uint16_t)val << 8; - da2->outflipflop = 0; - } - else - {// - da2->iolatch = val; - da2->outflipflop = 1; - } - break; - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - default: - da2->iolatch = val; - da2->outflipflop = 0; - break; - } - da2_out(addr, da2->iolatch, da2); -} -void da2_outw(uint16_t addr, uint16_t val, void* p) -{ - //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_t* da2 = (da2_t*)p; - da2->inflipflop = 0; - switch (addr) - { - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - da2_out(addr, val & 0xff, da2); - da2->iolatch = val >> 8; - da2_out(addr + 1, da2->iolatch, da2); - da2->outflipflop = 1; - break; - case LV_PORT: - da2->attrff = 0; - da2_out(addr, val & 0xff, da2); - da2_out(addr, val >> 8, da2); - da2->outflipflop = 0; - break; - case 0x3EC: - //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_out(LG_DATA, val >> 8, da2); - break; - case 0x3ED: - da2->gdcaddr = LG_MODE; - da2_out(LG_DATA, val, da2); - break; - case LS_DATA: - case LF_DATA: - case LC_DATA: - case LG_DATA: - default: - da2_out(addr, val, da2); - da2->outflipflop = 0; - break; - case 0x3EE: - da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2->reg3ee[val & 0xff] = val >> 8; - break; - } -} -uint8_t da2_inb(uint16_t addr, void* p) -{ - uint8_t temp; - da2_t* da2 = (da2_t*)p; - da2->outflipflop = 0; - switch (addr) - { - case LC_DATA: - if (da2->inflipflop) - { - /* out b(idx), in b(low data), in b(high data) */ - temp = da2->iolatch >> 8; - da2->inflipflop = 0; - } - else - {// - da2->iolatch = da2_in(addr, da2); - temp = da2->iolatch & 0xff; - da2->inflipflop = 1; - } - break; - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - case LS_DATA: - case LF_DATA: - case LG_DATA: - default: - temp = da2_in(addr, da2) & 0xff; - da2->inflipflop = 0; - break; - } - //da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); - return temp; -} -uint16_t da2_inw(uint16_t addr, void* p) -{ - //uint16_t temp; - da2_t* da2 = (da2_t*)p; - da2->inflipflop = 0; - da2->outflipflop = 0; - return da2_in(addr, da2); -} -/* IO 03DAh : Input Status Register 2 for DOSSHELL in DOS J4.0 */ -uint8_t da2_in_ISR(uint16_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - uint8_t temp = 0; - if (addr == 0x3da) { - if (da2->cgastat & 0x01) - da2->cgastat &= ~0x30; - else - da2->cgastat ^= 0x30; - temp = da2->cgastat; - } - //da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); - return temp; -} - -void da2_out_ISR(uint16_t addr, uint8_t val, void* p) -{ - //da2_t* da2 = (da2_t*)p; - da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); -} - -/* -The IBM 5550 character mode addresses video memory between E0000h and E0FFFh. - [Character drawing] - SBCS: - 1 2 ... 13 - 1 | H.Grid - |---------------- - 2 | Space - 3 V| - .| - G| Font Pattern - r| (12x24 pixels) - i| - d| -26 |________________ -27 Space - ---------------- -28 Underscore ] - ---------------- >Cursor Position -29 ] - - DBCS: - 1 2 ... 13 1 2 ... 12 13 - 1 | H.Grid | H.Grid | - -|--------------------------|- - 2 | Space | Space | - -|--------------------------|- - 3 V| | |S - .| | |p - G| Font Pattern |a - r| (24x24 pixels) |c - i| | |e - d| | | -26 |_____________|____________| -27 | Space | Space - ------------------------------ -28 | Underscore | Underscore ] - ------------------------------ >Cursor Position -29 | | ] - - [Attributes] - Video mode 08h: - 7 6 5 4 3 2 1 0 - Blink |Under |HGrid |VGrid |Bright|Revers|FntSet|DBCS/SBCS| - - Video mode 0Eh: - -Blue |-Green|HGrid |VGrid |-Red |Revers|FntSet|DBCS/SBCS| - - Bit 1 switches the font bank to the Extended SBCS. DOS K3.x loads APL characters from $SYSEX24.FNT into it. - DOS Bunsho Program transfers 1/2 and 1/4 fonts fron the font ROM to the Extended SBCS. - This bit is not used for DBCS, but some apps set it as that column is right half of DBCS. - -[Font ROM Map (DA2, Japanese)] -The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. - - Bank 0 - 4800- * - Bank 1, 2, 3 - * - * - Bank 4 - * -0DB6Fh ( 4800-8DB6Fh) : JIS X 0208 DBCS (24 x 24) (IBMJ code: 100-1F7Dh) - 10000-16D1Fh (90000-96D1Fh) : IBM Extended Characters (IBMJ code: 2ADC-2C5Fh) - 18000-1BFCFh (98000-9BFCFh) : JIS X 0201 SBCS (13 x 30) - 1C000-1FFFFh (9C000-9FFFFh) : Codepage 437 characters (13 x 30) - Bank 5 - 00000-0C68Fh (A0000-AC68Fh) : Gaiji used by DOS Bunsho - 10000-13FFFh (B0000-B3FFFh) : Extended SBCS (13 x 30) - 14000-1477Fh (B4000-B477Fh) : Half-width box drawing characters used by DOS Bunsho - 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) - 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) - - Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) - -[Font ROM Map (DA3, Traditional Chinese)] - Bank 0 - 11 : Valid Font ROM data - Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) - Bank 13 : All addresses return 0xFF - -[Gaiji RAM Map (DA2)] - Bank 0 00000-1FFFFh placed between A0000h-BFFFFh - 00000-1F7FFh(A0000-BF7FFh): Gaiji Non-resident (Kuten 103-114 ku,IBM: 2674-2ADBh) 1008 chs 128 bytes - 1F800-1FFFFh(BF800-BFFFFh): Gaiji Resident (SJIS: F040-F04Fh, IBM: 2384-2393h) 16 chs - - Bank 1 20000-3FFFFh placed between A0000h-BFFFFh - 20000-33FFFh(A0000-B3FFFh): Gaiji Resident (SJIS: F050-F39Ch, IBM: 2394-2613h) 640 chs - 34000-37FFFh(B4000-B7FFFh): Basic SBCS(00-FFh, ATTR bit 1 = off) - 38000-3AFFFh(B8000-BAFFFh): Gaiji Resident (SJIS: F39D-F3FCh, IBM: 2614-2673h) 96 chs - 3C000-3FFFFh(BC000-BFFFFh): Extended SBCS(00-FFh, ATTR bit 1 = on) - -[IBMJ code to Gaiji address conv tbl from DOS K3.3] - A B C - 2ADC, 2C5F, +5524 --> 8000 - 2614, 2673, +90EC --> B700 - 2384, 2613, +906C --> B3F0 - 0682, 1F7D, +0000 - - 8000 - 8183h 184h(388 characters) IBM Extended Characters - B3F0 - B75Fh 370h(880 characters) User-defined Characters -*/ - -/* Get character line pattern from jfont rom or gaiji volatile memory */ -uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { - da2_t* da2 = (da2_t*)p; - uint32_t font = 0; - int32_t fline = line - 2;//Start line of drawing character (line >= 1 AND line < 24 + 1 ) - if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) - if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { - font = da2->mmio.font[code * 72 + fline * 3]; //1111 1111 - font <<= 8; //1111 1111 0000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; //1111 1111 2222 0000 - font >>= 1; //0111 1111 1222 2000 - font <<= 4; //0111 1111 1222 2000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; //0111 1111 1222 2000 2222 - font <<= 8; //0111 1111 1222 2000 2222 0000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 2]; //0111 1111 1222 2000 2222 3333 3333 - font <<= 4; //0111 1111 1222 2000 2222 3333 3333 0000 - //font >>= 1;//put blank at column 1 (and 26) - } - else if (code >= 0xb000 && code <= 0xb75f) - { - //convert code->address in gaiji memory - code -= 0xb000; - code *= 0x80; - //code += 0xf800; - font = da2->mmio.ram[code + line * 4]; - font <<= 8; - font |= da2->mmio.ram[code + line * 4 + 1]; - font <<= 8; - font |= da2->mmio.ram[code + line * 4 + 2]; - font <<= 8; - font |= da2->mmio.ram[code + line * 4 + 3]; - } - else if (code > DA2_FONTROM_SIZE) - font = 0xffffffff; - else - font = 0; - return font; -} - -/* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ -uint8_t IRGBtoBGRI(uint8_t attr) -{ - attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); - return attr >>= 4; -} -/* Get the foreground color from the attribute byte */ -uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) -{ - uint8_t foreground = ~attr & 0x08;// 0000 1000 - foreground <<= 2; //0010 0000 - foreground |= ~attr & 0xc0;// 1110 0000 - foreground >>= 4;//0000 1110 - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette - return foreground; -} - -void da2_render_blank(da2_t* da2) -{ - int x, xx; - - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - - for (x = 0; x < da2->hdisp; x++) - { - for (xx = 0; xx < 13; xx++) ((uint32_t*)buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; - } -} -/* Display Adapter Mode 8, E Drawing */ -static void da2_render_text(da2_t* da2) -{ - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - - if (da2->fullchange) - { - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - int x; - int drawcursor; - uint8_t chr, attr; - int fg, bg; - uint32_t chr_dbcs; - int chr_wide = 0; - //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); - for (x = 0; x < da2->hdisp; x += 13) - { - chr = da2->cram[(da2->ma) & da2->vram_display_mask]; - attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; - //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh - {//--Parse attribute byte in color mode-- - bg = 0;//bg color is always black (the only way to change background color is programming PAL) - fg = getPS55ForeColor(attr, da2); - if (attr & 0x04) {//reverse 0000 0100 - bg = fg; - fg = 0; - } - } - else - {//--Parse attribute byte in monochrome mode-- - if (attr & 0x08) fg = 3;//Highlight 0000 1000 - else fg = 2; - bg = 0;//Background is always color #0 (default is black) - if (!(~attr & 0xCC))//Invisible 11xx 11xx -> 00xx 00xx - { - fg = bg; - attr &= 0x33;//disable blinkking, underscore, highlight and reverse - } - if (attr & 0x04) {//reverse 0000 0100 - bg = fg; - fg = 0; - } - // Blinking 1000 0000 - fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; - //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); - } - //Draw character - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank - // SBCS or DBCS left half - if (chr_wide == 0) { - if (attr & 0x01) chr_wide = 1; - //chr_wide = 0; - // Stay drawing If the char code is DBCS and not at last column. - if (chr_wide) { - //Get high DBCS code from the next video address - chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; - chr_dbcs <<= 8; - chr_dbcs |= chr; - // Get the font pattern - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; - font <<= 1; - } - } - else { - // the char code is SBCS (ANK) - uint32_t fontbase; - if (attr & 0x02)//second map of SBCS font - fontbase = DA2_GAIJIRAM_SBEX; - else - fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font - font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font - //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); - // Draw 13 dots - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; - font <<= 1; - } - } - } - // right half of DBCS - else - { - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; - font <<= 1; - } - chr_wide = 0; - } - //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. - if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode - for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[fg]];//under line (white) - } - //Column 1 (Vertical Line) - if (attr & 0x10) { - p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) - } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid - for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) - } - //Drawing text cursor - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) - { - int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); - int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 - fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); - bg = 0; - if (attr & 0x04) {//Color 0 if reverse - bg = fg; - fg = 0; - } - for (uint32_t n = 0; n < cursorwidth; n++) - if (p[n] == da2->pallook[da2->egapal[cursorcolor]] || da2->egapal[bg] == da2->egapal[cursorcolor]) - p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[fg]] : da2->pallook[da2->egapal[bg]]; - else - p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[cursorcolor]] : p[n]; - } - da2->ma += 2; - p += 13; - } - da2->ma &= da2->vram_display_mask; - //da2->writelines++; - } -} - -/* Display Adapter Mode 3 Drawing */ -static void da2_render_textm3(da2_t* da2) -{ - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - - if (da2->fullchange) - { - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - int x; - int drawcursor; - uint8_t chr, attr, extattr; - int fg, bg; - uint32_t chr_dbcs; - int chr_wide = 0; - //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); - for (x = 0; x < da2->hdisp; x += 13) - { - chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; - attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; - extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; - //if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); - bg = attr >> 4; - //if (da2->blink) bg &= ~0x8; - //fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; - fg = attr & 0xf; - fg = IRGBtoBGRI(fg); - bg = IRGBtoBGRI(bg); - //Draw character - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank - // SBCS or DBCS left half - if (chr_wide == 0) { - if (extattr & 0x01) chr_wide = 1; - // Stay drawing if the char code is DBCS and not at last column. - if (chr_wide) { - //Get high DBCS code from the next video address - chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; - chr_dbcs <<= 8; - chr_dbcs |= chr; - // Get the font pattern - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; - font <<= 1; - } - } - else { - // the char code is SBCS (ANK) - uint32_t fontbase; - fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font - font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font - //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; - font <<= 1; - } - } - } - // right half of DBCS - else - { - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots - for (uint32_t n = 0; n < 13; n++) { - p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; - font <<= 1; - } - chr_wide = 0; - } - //Drawing text cursor - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) - { - //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); - //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 - //fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; - //bg = 0; - //if (attr & 0x04) {//Color 0 if reverse - // bg = fg; - // fg = 0; - //} - for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[fg]]; - } - da2->ma += 2; - p += 13; - } - da2->ma &= da2->vram_display_mask; - //da2->writelines++; - } -} - -void da2_render_color_4bpp(da2_t* da2) -{ - int changed_offset = da2->ma >> 12; - //da2_log("ma %x cf %x\n", da2->ma, changed_offset); - da2->plane_mask &= 0x0f;//safety - - if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) - { - int x; - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - //da2_log("d %X\n", da2->ma); - - for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 - { - uint8_t edat[8]; - uint8_t dat; - - //get 8 pixels from vram - da2->ma &= da2->vram_display_mask; - *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); - da2->ma += 1; - - dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); - p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); - p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); - p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); - p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); - p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); - p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); - p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); - p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - p += 8; - } - //da2->writelines++; - } -} - -void da2_render_color_8bpp(da2_t* da2) -{ - int changed_offset = da2->ma >> 12; - //da2_log("ma %x cf %x\n", da2->ma, changed_offset); - - if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) - { - int x; - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - //da2_log("d %X\n", da2->ma); - - for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 - { - uint8_t edat[8]; - uint8_t dat; - - //get 8 pixels from vram - da2->ma &= da2->vram_display_mask; - *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); - *(uint32_t*)(&edat[4]) = *(uint32_t*)(&da2->vram[(da2->ma << 3) + 4]); - da2->ma += 1; - - dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | - ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); - p[0] = da2->pallook[dat]; - dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | - ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); - p[1] = da2->pallook[dat]; - dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | - ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); - p[2] = da2->pallook[dat]; - dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | - ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); - p[3] = da2->pallook[dat]; - dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | - ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); - p[4] = da2->pallook[dat]; - dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | - ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); - p[5] = da2->pallook[dat]; - dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | - ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); - p[6] = da2->pallook[dat]; - dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | - ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); - p[7] = da2->pallook[dat]; - p += 8; - } - //da2->writelines++; - } -} - -void da2_updatevidselector(da2_t* da2) { - /* if VGA passthrough mode */ - da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); - if (da2->ioctl[LS_MODE] & 0x02) - { - da2->override = 1; - svga_set_override(da2->mb_vga, 0); - } - else - { - svga_set_override(da2->mb_vga, 1); - da2->override = 0; - } -} - -void da2_recalctimings(da2_t* da2) -{ - double crtcconst; - double _dispontime, _dispofftime, disptime; - - da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff;//w - da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff;//w - da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff;//w - da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff;//w Line Compare - da2->split = 0xfff; - da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;//w - da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; - - if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { - da2->hdisp--; - da2->dispend -= 29; - } - else { - //da2->vtotal += 2; - da2->dispend--; - //da2->vsyncstart++; - //da2->split++; - //da2->vblankstart++; - //da2->hdisp--; - } - - da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; - da2->htotal += 1; - - da2->rowoffset = da2->crtc[LC_OFFSET];//number of bytes in a scanline - - da2->clock = da2->da2const; - - //da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; - - //da2->interlace = 0; - - //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b - da2->ca_adj = 0; - - da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; - - da2->hdisp_time = da2->hdisp; - da2->render = da2_render_blank; - //determine display mode - //if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) - if (da2->attrc[LV_COMPATIBILITY] & 0x08) - { - if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode - da2->hdisp *= 16; - da2->char_width = 13; - da2->hdisp_old = da2->hdisp; - if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { - da2_log("Set videomode to PS/55 8 bpp graphics.\n"); - da2->render = da2_render_color_8bpp; - da2->vram_display_mask = DA2_MASK_GRAM; - } - else {//PS/55 8-color - da2_log("Set videomode to PS/55 4 bpp graphics.\n"); - da2->vram_display_mask = DA2_MASK_GRAM; - da2->render = da2_render_color_4bpp; - } - } - else {//text mode - if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { - da2_log("Set videomode to PS/55 Mode 03 text.\n"); - da2->render = da2_render_textm3; - da2->vram_display_mask = DA2_MASK_CRAM; - } - else {//PS/55 text(color/mono) - da2_log("Set videomode to PS/55 Mode 8/E text.\n"); - da2->render = da2_render_text; - da2->vram_display_mask = DA2_MASK_CRAM; - } - da2->hdisp *= 13; - da2->hdisp_old = da2->hdisp; - da2->char_width = 13; - } - } - else - { - da2_log("Set videomode to blank.\n"); - } - //if (!da2->scrblank && da2->attr_palette_enable) - //{ - //da2->render = da2_draw_text; - //} - - // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - - //if (da2->recalctimings_ex) - // da2->recalctimings_ex(da2); - - if (da2->vblankstart < da2->dispend) - da2->dispend = da2->vblankstart; - - crtcconst = da2->clock * da2->char_width; - - disptime = da2->htotal; - _dispontime = da2->hdisp_time; - - da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); - //if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } - _dispofftime = disptime - _dispontime; - _dispontime *= crtcconst; - _dispofftime *= crtcconst; - - da2->dispontime = (uint64_t)_dispontime; - da2->dispofftime = (uint64_t)_dispofftime; - if (da2->dispontime < TIMER_USEC) - da2->dispontime = TIMER_USEC; - if (da2->dispofftime < TIMER_USEC) - da2->dispofftime = TIMER_USEC; - da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); - // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); - // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); - - // da2_log("da2->render %08X\n", da2->render); -} - -uint8_t da2_mca_read(int port, void *p) -{ - da2_t *da2 = (da2_t *)p; - return da2->pos_regs[port & 7]; -} - -static void da2_mapping_update(da2_t *da2) -{ - if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) return; - da2->old_pos2 = da2->pos_regs[2]; - //da2_recalc_mapping(da2); - if (da2->pos_regs[2] & 0x01) - { - da2_log("DA2 enable registers\n"); - for (int i = 0; i < 8; i++) - da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); - io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); - mem_mapping_enable(&da2->cmapping); - mem_mapping_enable(&da2->mmio.mapping); - timer_enable(&da2->timer); - } - else - { - da2_log("DA2 disable registers\n"); - timer_disable(&da2->timer); - mem_mapping_disable(&da2->cmapping); - mem_mapping_disable(&da2->mmio.mapping); - io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); - } -} - -void da2_mca_write(int port, uint8_t val, void *p) -{ - da2_t *da2 = (da2_t *)p; - - da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); - - if (port < 0x102) - return; - da2->pos_regs[port & 7] = val; - - da2_mapping_update(da2); -} - -static uint8_t da2_mca_feedb(void* priv) -{ - const da2_t* da2 = (da2_t*)priv; - - return da2->pos_regs[2] & 0x01; -} - -static void da2_mca_reset(void *p) -{ - da2_t *da2 = (da2_t *)p; - da2_reset(da2); - da2_mca_write(0x102, 0, da2); -} -// -static void da2_gdcropB(uint32_t addr, da2_t* da2) { - for (int i = 0; i < 8; i++) { - if (da2->writemask & (1 << i)) { - //da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); - switch (da2->gdcreg[LG_COMMAND] & 0x03) - { - case 0: /*Set*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 1: /*AND*/ - //da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 2: /*OR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 3: /*XOR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - } - } - } -} -static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t* da2) { - uint8_t bitmask_l = bitmask & 0xff; - uint8_t bitmask_h = bitmask >> 8; - for (int i = 0; i < 8; i++) { - if (da2->writemask & (1 << i)) { - //da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); - switch (da2->gdcreg[LG_COMMAND] & 0x03) - { - case 0: /*Set*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); - da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 1: /*AND*/ - //da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 2: /*OR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 3: /*XOR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - } - } - } -} - -static uint8_t da2_mmio_read(uint32_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - addr &= DA2_MASK_MMIO; - - if (da2->ioctl[LS_MMIO] & 0x10) { - if (da2->fctl[LF_MMIO_SEL] == 0x80) - //linear access - addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); - else - { - //64k bank switch access - uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; - index <<= 8; - index |= da2->fctl[LF_MMIO_ADDR]; - addr += index * 0x40; - } - //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); - switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { - case 0xb0://Gaiji RAM - addr &= DA2_MASK_GAIJIRAM;//safety access - //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); - return da2->mmio.ram[addr]; - break; - case 0x10://Font ROM - if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { - if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; - if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, - but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ - } - if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; - //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); - return da2->mmio.font[addr]; - break; - default: - return DA2_INVALIDACCESS8;//invalid memory access - break; - } - } - else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode - { - cycles -= video_timing_read_b; - for (int i = 0; i < 8; i++) - da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte - //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); - if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 - uint8_t ret = 0; - - for (int i = 0; i < 8; i++) - { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register - ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); - } - return ~ret; - } - else return da2->gdcla[da2->readplane]; - } - else //text mode 3 - { - cycles -= video_timing_read_b; - return da2->vram[addr]; - } -} -static uint16_t da2_mmio_readw(uint32_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); - if (da2->ioctl[LS_MMIO] & 0x10) { - return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); - } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode - { - cycles -= video_timing_read_w; - addr &= DA2_MASK_MMIO; - for (int i = 0; i < 8; i++) - da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch - -#ifdef ENABLE_DA2_DEBUGBLT - ////debug - //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) - //{ - // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); - // for (int i = 0; i <= 0xb; i++) - // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); - //} - //for (int i = 0; i < 16; i++) - //{ - // int pixeldata = 0; - // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; - // fprintf(da2->mmrdbg_fp, "%X", pixeldata); - //} - //da2->mmrdbg_vidaddr = addr; -#endif - - if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 - uint16_t ret = 0; - - for (int i = 0; i < 8; i++) - { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register - ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); - } - return ~ret; - } - else - { - //da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); - return da2->gdcla[da2->readplane]; - } - } - else { - return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); - } -} - -static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - //da2_log("da2_mmio_write %x %x\n", addr, val); - if ((addr & ~DA2_MASK_MMIO) != 0xA0000) return; - addr &= DA2_MASK_MMIO; - - if (da2->ioctl[LS_MMIO] & 0x10) { - //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); - //Gaiji RAM - if (da2->fctl[LF_MMIO_SEL] == 0x80) - addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);//xxxy yyyy yyyy yyyy yyyy - else - { - uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; - index <<= 8; - index |= da2->fctl[LF_MMIO_ADDR]; - addr += index * 0x40; - } - switch (da2->fctl[LF_MMIO_MODE]) { - case 0xb0://Gaiji RAM 1011 0000 - addr &= DA2_MASK_GAIJIRAM;//safety access - da2->mmio.ram[addr] = val; - break; - case 0x10://Font ROM 0001 0000 - //Read-Only - break; - case 0x00: - //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - //addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx - //if (addr >= DA2_BLT_MEMSIZE) - //{ - // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - // return; - //} - da2->bitblt.indata = 1; - if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) - da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; - break; - default: - da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - break; - } - } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode - { - uint8_t wm = da2->writemask; - //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); -#ifdef ENABLE_DA2_DEBUGBLT - //debug - //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - //{ - if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - { - fprintf(da2->mmdbg_fp, "\nB %x ", addr); - for (int i = 0; i <= 0xb; i++) - fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); - } - for (int i = 0; i < 8; i++) - { - int pixeldata = 0; - if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); - fprintf(da2->mmdbg_fp, "%X", pixeldata); - } - da2->mmdbg_vidaddr = addr; - //} -#endif - - cycles -= video_timing_write_b; - - da2->changedvram[addr >> 12] = changeframecount; - addr <<= 3; - - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - - //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); - //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); - - if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; - else da2->gdcinput[i] = val; - da2_gdcropB(addr, da2); - return; - } - - switch (da2->writemode) - { - case 2: - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; - break; - case 0: - if (da2->gdcreg[LG_DATA_ROTATION] & 7) - val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; - } - else - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - else da2->gdcinput[i] = val; - - for (int i = 0; i < 8; i++) - da2->debug_vramold[i] = da2->vram[addr | i];//use latch - da2_gdcropB(addr, da2); - //for (int i = 0; i < 8; i++) - // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch - //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 1: - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - } - else - { - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); - da2_gdcropB(addr, da2); - } - break; - case 3: - if (da2->gdcreg[LG_DATA_ROTATION] & 7) - val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - wm = da2->gdcreg[LG_BIT_MASK_LOW]; - da2->gdcreg[LG_BIT_MASK_LOW] &= val; - - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - da2_gdcropB(addr, da2); - da2->gdcreg[LG_BIT_MASK_LOW] = wm; - break; - } - //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); - } - else// mode 3h text - { - cycles -= video_timing_write_b; - da2->vram[addr] = val; - da2->fullchange = 2; - } -} -uint16_t rightRotate(uint16_t data, uint8_t count) -{ - return (data >> count) | (data << (sizeof(data) * 8 - count)); -} -static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - uint8_t wm = da2->writemask; - uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; - bitmask <<= 8; - bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; -#ifdef ENABLE_DA2_DEBUGBLT - //debug - //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - //{ - if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - { - fprintf(da2->mmdbg_fp, "\nW %x ", addr); - for (int i = 0; i <= 0xb; i++) - fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); - } - for (int i = 0; i < 16; i++) - { - int pixeldata = 0; - if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); - fprintf(da2->mmdbg_fp, "%X", pixeldata); - } - da2->mmdbg_vidaddr = addr; - //} -#endif - cycles -= video_timing_write_w; - //cycles_lost += video_timing_write_w; - - //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); - //da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); - - da2->changedvram[addr >> 12] = changeframecount; - da2->changedvram[(addr + 1) >> 12] = changeframecount; - addr <<= 3; - - for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch - - if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; - else da2->gdcinput[i] = val; - da2_gdcropW(addr, bitmask, da2); - return; - } - //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] - // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); - switch (da2->writemode) - { - case 2: - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; - da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; - } - break; - case 0: - if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work - if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - da2->vram[addr | i] = val & 0xff; - da2->vram[(addr + 8) | i] = val >> 8; - } - } - else - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - else da2->gdcinput[i] = val; - da2_gdcropW(addr, bitmask, da2); - // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 1: - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - da2->vram[addr | i] = wdata & 0xff; - da2->vram[(addr + 8) | i] = wdata >> 8; - } - } - else - { - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); - da2_gdcropW(addr, bitmask, da2); - } - break; - case 3: - if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work - wm = bitmask; - bitmask &= val; - - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - da2_gdcropW(addr, bitmask, da2); - bitmask = wm; - break; - } - //da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] - // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); -} -static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - //if ((addr & ~0x1ffff) != 0xA0000) return; - if (da2->ioctl[LS_MMIO] & 0x10) { - //da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); - da2_mmio_write(addr, val & 0xff, da2); - da2_mmio_write(addr + 1, val >> 8, da2); - } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode - { - addr &= DA2_MASK_MMIO; - //return; - //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); - da2_mmio_gc_writeW(addr, val, da2); - } - else {//mode 3h text - //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); - da2_mmio_write(addr, val & 0xff, da2); - da2_mmio_write(addr + 1, val >> 8, da2); - } -} - -static void da2_code_write(uint32_t addr, uint8_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - //if ((addr & ~0xfff) != 0xE0000) return; - addr &= DA2_MASK_CRAM; - da2->cram[addr] = val; - da2->fullchange = 2; -} -static void da2_code_writeb(uint32_t addr, uint8_t val, void* p) -{ - da2_t* da2 = (da2_t*)p; - //da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); - cycles -= video_timing_write_b; - da2_code_write(addr, val, da2); -} -static void da2_code_writew(uint32_t addr, uint16_t val, void* p) -{ - //da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); - da2_t* da2 = (da2_t*)p; - cycles -= video_timing_write_w; - da2_code_write(addr, val & 0xff, da2); - da2_code_write(addr + 1, val >> 8, da2); -} - -static uint8_t da2_code_read(uint32_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return DA2_INVALIDACCESS8; - addr &= DA2_MASK_CRAM; - return da2->cram[addr]; -} -static uint8_t da2_code_readb(uint32_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - cycles -= video_timing_read_b; - return da2_code_read(addr, da2); -} -static uint16_t da2_code_readw(uint32_t addr, void* p) -{ - da2_t* da2 = (da2_t*)p; - cycles -= video_timing_read_w; - return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); - //return 0; -} - -void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) -{ - if (wx != xsize || wy != ysize) { - xsize = wx; - ysize = wy; - set_screen_size(xsize, ysize); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen(32, 0, xsize, ysize); - frames++; - - video_res_x = wx; - video_res_y = wy; - video_bpp = 8; -} - -void da2_poll(void* priv) -{ - da2_t* da2 = (da2_t*)priv; - int x; - - if (!da2->linepos) - { - timer_advance_u64(&da2->timer, da2->dispofftime); - // if (output) printf("Display off %f\n",vidtime); - da2->cgastat |= 1; - da2->linepos = 1; - - if (da2->dispon) - { - da2->hdisp_on = 1; - - da2->ma &= da2->vram_display_mask; - if (da2->firstline == 2000) - { - da2->firstline = da2->displine; - video_wait_for_buffer(); - } - - if (!da2->override) - da2->render(da2); - - if (da2->lastline < da2->displine) - da2->lastline = da2->displine; - } - - //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); - da2->displine++; - //if (da2->interlace) - // da2->displine++; - if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) - { - //da2_log("Vsync off at line %i\n",displine); - da2->cgastat &= ~8; - } - da2->vslines++; - if (da2->displine > 1200) - da2->displine = 0; - // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], - // displine, vc, ma); - } - else - { - // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); - timer_advance_u64(&da2->timer, da2->dispontime); - - // if (output) printf("Display on %f\n",vidtime); - if (da2->dispon) - da2->cgastat &= ~1; - da2->hdisp_on = 0; - - da2->linepos = 0; - if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) - da2->con = 0; - if (da2->dispon) - { - if (da2->sc == da2->rowcount) - { - da2->linecountff = 0; - da2->sc = 0; - - da2->maback += (da2->rowoffset << 1);// color = 0x50(80), mono = 0x40(64) - if (da2->interlace) - da2->maback += (da2->rowoffset << 1); - da2->maback &= da2->vram_display_mask; - da2->ma = da2->maback; - } - else - { - da2->sc++; - da2->sc &= 31; - da2->ma = da2->maback; - } - } - - da2->vc++; - da2->vc &= 2047; - - if (da2->vc == da2->dispend) - { - da2->dispon = 0; - //if (da2->crtc[10] & 0x20) da2->cursoron = 0; - //else da2->cursoron = da2->blink & 16; - if (da2->ioctl[LS_MODE] & 1) {//in text mode - if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)//cursor blinking - { - da2->cursoron = (da2->blink | 1) & da2->blinkconf; - } - else - { - da2->cursoron = 0; - } - if (!(da2->blink & (0x10 - 1)))//force redrawing for cursor and blink attribute - da2->fullchange = 2; - } - da2->blink++; - - for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) - { - if (da2->changedvram[x]) - da2->changedvram[x]--; - } - // memset(changedvram,0,2048); del - if (da2->fullchange) - { - da2->fullchange--; - } - } - if (da2->vc == da2->vsyncstart) - { - int wx, wy; - // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); - da2->dispon = 0; - da2->cgastat |= 8; - x = da2->hdisp; - - //if (da2->interlace && !da2->oddeven) da2->lastline++; - //if (da2->interlace && da2->oddeven) da2->firstline--; - - wx = x; - wy = da2->lastline - da2->firstline; - - da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); - - da2->firstline = 2000; - da2->lastline = 0; - - da2->firstline_draw = 2000; - da2->lastline_draw = 0; - - da2->oddeven ^= 1; - - changeframecount = da2->interlace ? 3 : 2; - da2->vslines = 0; - - //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); - //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); - //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; -/* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; - else*/ da2->ma = da2->maback = da2->ma_latch; - da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; - - da2->ma <<= 1; - da2->maback <<= 1; - da2->ca <<= 1; - - // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); - } - if (da2->vc == da2->vtotal) - { - // da2_log("VC vtotal\n"); - - - // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); - da2->vc = 0; - da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; - da2->dispon = 1; - da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; - da2->scrollcache = da2->attrc[LV_PANNING] & 7; - } - if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) - da2->con = 1; - } - // printf("2 %i\n",da2_vsyncstart); - //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); - //da2_log("r"); -} - -static void da2_loadfont(char* fname, void* p) { - da2_t* da2 = (da2_t*)p; - uint8_t buf; - //uint32_t code = 0; - uint64_t fsize; - if (!fname) return; - if (*fname == '\0') return; - FILE* mfile = rom_fopen(fname, "rb"); - if (!mfile) { - //da2_log("MSG: Can't open binary ROM font file: %s\n", fname); - return; - } - fseek(mfile, 0, SEEK_END); - fsize = ftell(mfile);//get filesize - fseek(mfile, 0, SEEK_SET); - if (fsize > DA2_FONTROM_SIZE) { - fsize = DA2_FONTROM_SIZE;//truncate read data - //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); - //fclose(mfile); - //return 1; - } - uint32_t j = 0; - while (ftell(mfile) < fsize) { - fread(&buf, sizeof(uint8_t), 1, mfile); - da2->mmio.font[j] = buf; - j++; - } - fclose(mfile); - return; -} - -/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ -static uint8_t ps55_palette_color[64][3] = -{ -{0x00,0x00,0x00},{0x00,0x00,0x2A},{0x00,0x2A,0x00},{0x00,0x2A,0x2A},{0x2A,0x00,0x00},{0x2A,0x00,0x2A},{0x2A,0x2A,0x00},{0x2A,0x2A,0x2A}, -{0x00,0x00,0x15},{0x00,0x00,0x3F},{0x00,0x2A,0x15},{0x00,0x2A,0x3F},{0x2A,0x00,0x15},{0x2A,0x00,0x3F},{0x2A,0x2A,0x15},{0x2A,0x2A,0x3F}, -{0x00,0x15,0x00},{0x00,0x15,0x2A},{0x00,0x3F,0x00},{0x00,0x3F,0x2A},{0x2A,0x15,0x00},{0x2A,0x15,0x2A},{0x2A,0x3F,0x00},{0x2A,0x3F,0x2A}, -{0x00,0x15,0x15},{0x00,0x15,0x3F},{0x00,0x3F,0x15},{0x00,0x3F,0x3F},{0x2A,0x15,0x15},{0x2A,0x15,0x3F},{0x2A,0x3F,0x15},{0x2A,0x3F,0x3F}, -{0x15,0x00,0x00},{0x15,0x00,0x2A},{0x15,0x2A,0x00},{0x15,0x2A,0x2A},{0x3F,0x00,0x00},{0x3F,0x00,0x2A},{0x3F,0x2A,0x00},{0x3F,0x2A,0x2A}, -{0x15,0x00,0x15},{0x15,0x00,0x3F},{0x15,0x2A,0x15},{0x15,0x2A,0x3F},{0x3F,0x00,0x15},{0x3F,0x00,0x3F},{0x3F,0x2A,0x15},{0x3F,0x2A,0x3F}, -{0x15,0x15,0x00},{0x15,0x15,0x2A},{0x15,0x3F,0x00},{0x15,0x3F,0x2A},{0x3F,0x15,0x00},{0x3F,0x15,0x2A},{0x3F,0x3F,0x00},{0x3F,0x3F,0x2A}, -{0x15,0x15,0x15},{0x15,0x15,0x3F},{0x15,0x3F,0x15},{0x15,0x3F,0x3F},{0x3F,0x15,0x15},{0x3F,0x15,0x3F},{0x3F,0x3F,0x15},{0x3F,0x3F,0x3F} -}; - -void da2_reset_ioctl(da2_t* da2) -{ - da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ - da2_outw(LS_INDEX, 0x0302, da2); /* Index 02, Bit 1: VGA passthrough, Bit 0: Character Mode */ - da2_outw(LS_INDEX, 0x0008, da2); /* Index 08, Bit 0: Enable MMIO */ -} - -static void -da2_reset(void* priv) -{ - da2_t* da2 = (da2_t*)priv; - - /* Initialize drawing */ - da2->bitblt.exec = DA2_BLT_CIDLE; - da2->render = da2_render_blank; - da2_reset_ioctl(da2); - - da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ - da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ - da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ - da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ - da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ - da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ - da2->fctl[0] = 0x2b; /* 3E3h:0 */ - da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ - da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ - da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ - da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ - da2->ma_latch = 0; - da2->interlace = 0; - da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ - da2->attr_palette_enable = 0; /* disable attribute generator */ - - /* Set default color palette (Windows 3.1 display driver won't reset palette) */ - da2_out(0x3c8, 0, da2); - for (int i = 0; i < 256; i++) { - da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); - da2_out(0x3c9, ps55_palette_color[i & 0x3F][1], da2); - da2_out(0x3c9, ps55_palette_color[i & 0x3F][2], da2); - } -} - -static void *da2_init() -{ - //Todo: init regs, gaiji memory, video memory, I/O handlers, font ROM - - if (svga_get_pri() == NULL) - return NULL; - svga_t *mb_vga = svga_get_pri(); - mb_vga->cable_connected = 0; - - da2_t* da2 = malloc(sizeof(da2_t)); - da2->mb_vga = mb_vga; - - da2->dispontime = 1000ull << 32; - da2->dispofftime = 1000ull << 32; - int memsize = 1024 * 1024; - da2->vram = malloc(memsize); - da2->vram_mask = memsize - 1; - da2->cram = malloc(0x1000); - da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h - da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ - - da2->mmio.charset = device_get_config_int("charset"); - da2->mmio.font= malloc(DA2_FONTROM_SIZE); - switch(da2->mmio.charset) - { - case DA2_DCONFIG_CHARSET_HANT: - da2_loadfont(DA2_FONTROM_PATH_HANT, da2); - break; - case DA2_DCONFIG_CHARSET_JPAN: - da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); - break; - } - - mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); - da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ -#ifdef ENABLE_DA2_DEBUGBLT - da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); - da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); - da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); - da2->bitblt.debug_reg_ip = 0; -#endif - da2->bitblt.payload_addr = 0; - da2_reset(da2); - - mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); - //da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); - - mem_mapping_disable(&da2->mmio.mapping); - - mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); - - mem_mapping_disable(&da2->cmapping); - - timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ - timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); - - return da2; -} -static int da2_available() -{ - return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); -} - -void da2_close(void *p) -{ - da2_t *da2 = (da2_t *)p; - - /* dump mem for debug */ -#ifndef RELEASE_BUILD - FILE* f; - f = fopen("da2_cram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->cram, 0x1000, 1, f); - fclose(f); - } - f = fopen("da2_vram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->vram, 1024*1024, 1, f); - fclose(f); - } - f = fopen("da2_gram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->mmio.ram, 256*1024, 1, f); - fclose(f); - } - f = fopen("da2_attrpal.dmp", "wb"); - if (f != NULL) { - fwrite(da2->attrc, 32, 1, f); - fclose(f); - } - f = fopen("da2_dacrgb.dmp", "wb"); - if (f != NULL) { - fwrite(da2->vgapal, 3*256, 1, f); - fclose(f); - } - f = fopen("da2_daregs.txt", "w"); - if (f != NULL) { - for (int i=0;i<0x10;i++) - fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); - for (int i = 0; i < 0x20; i++) - fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); - for (int i = 0; i < 0x20; i++) - fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); - for (int i = 0; i < 0x40; i++) - fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrc[i]); - for (int i = 0; i < 0x10; i++) - fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); - for (int i = 0; i < 0x10; i++) - fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); - fclose(f); - } -#endif -#ifdef ENABLE_DA2_DEBUGBLT - f = fopen("da2_bltdump.csv", "w"); - if (f != NULL && da2->bitblt.debug_reg_ip > 0) { - /* print header */ - for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { - if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) - fprintf(f, "\"%02X\"\t", y); - } - fprintf(f, "\n"); - /* print data */ - for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { - for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { - if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) - ; - else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) - fprintf(f, "\"\"\t"); - else - fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); - } - fprintf(f, "\n"); - } - fclose(f); - } - if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); - if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); - free(da2->bitblt.debug_reg); -#endif - free(da2->cram); - free(da2->vram); - free(da2->changedvram); - free(da2->mmio.font); - free(da2); -} - -void da2_speed_changed(void *p) -{ - da2_t* da2 = (da2_t*)p; - da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); - da2_recalctimings(da2); -} - -void da2_force_redraw(void *p) -{ - da2_t* da2 = (da2_t*)p; - - da2->fullchange = changeframecount; -} - -static const device_config_t da2_configuration[] = { - // clang-format off - { - .name = "charset", - .description = "Charset", - .type = CONFIG_SELECTION, - .default_int = DA2_DCONFIG_CHARSET_JPAN, - .selection = { - { - .description = "932 (Japanese)", - .value = DA2_DCONFIG_CHARSET_JPAN - }, - { - .description = "938 (Traditional Chinese)", - .value = DA2_DCONFIG_CHARSET_HANT - }, - { .description = "" } - } - }, - { - .name = "montype", - .description = "Monitor type", - .type = CONFIG_SELECTION, - .default_int = DA2_DCONFIG_MONTYPE_COLOR, - .selection = { - { - .description = "Color", - .value = DA2_DCONFIG_MONTYPE_COLOR - }, - { - .description = "IBM 8515", - .value = DA2_DCONFIG_MONTYPE_8515 - }, - { - .description = "Grayscale", - .value = DA2_DCONFIG_MONTYPE_MONO - }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -const device_t ps55da2_device = { - .name = "IBM Display Adapter II (MCA)", - .internal_name = "ps55da2", - .flags = DEVICE_MCA, - .local = 0, - .init = da2_init, - .close = da2_close, - .reset = da2_reset, - { .available = da2_available }, - .speed_changed = da2_speed_changed, - .force_redraw = da2_force_redraw, - .config = da2_configuration -}; - -void -da2_device_add(void) -{ - if (!da2_standalone_enabled) - return; - - if (machine_has_bus(machine, MACHINE_BUS_MCA)) - device_add(&ps55da2_device); - else - return; -} +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * IBM PS/55 Display Adapter II emulation. + * + * Authors: Akamaki. + * + * Copyright 2024 Akamaki. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/mca.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/video.h> +#include <86box/vid_ps55da2.h> +#include <86box/vid_svga.h> +#include <86box/vid_svga_render.h> +#include "cpu.h" + +#define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" +#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" +#define DA2_FONTROM_SIZE 1536*1024 +#define DA2_FONTROM_BASESBCS 0x98000 +#define DA2_GAIJIRAM_SBCS 0x34000 +#define DA2_GAIJIRAM_SBEX 0x3c000 +#define DA2_INVALIDACCESS8 0xff +#define DA2_MASK_MMIO 0x1ffff +#define DA2_MASK_GRAM 0x1ffff +#define DA2_MASK_CRAM 0xfff +#define DA2_MASK_GAIJIRAM 0x3ffff +#define DA2_PIXELCLOCK 58000000.0 +#define DA2_BLT_MEMSIZE 0x100 +#define DA2_BLT_REGSIZE 0x40 +#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) +#define DA2_DEBUG_BLTLOG_MAX 256*1024 +#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe +#define DA2_DEBUG_BLT_USEDRESET 0xfefefe +#define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ +//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ +//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ +#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ +#define DA2_DCONFIG_MONTYPE_COLOR 0x0A +#define DA2_DCONFIG_MONTYPE_8515 0x0B +#define DA2_DCONFIG_MONTYPE_MONO 0x09 + +#define DA2_BLT_CIDLE 0 +#define DA2_BLT_CFILLRECT 1 +#define DA2_BLT_CFILLTILE 2 +#define DA2_BLT_CCOPYF 3 +#define DA2_BLT_CCOPYR 4 +#define DA2_BLT_CPUTCHAR 5 +#define DA2_BLT_CDONE 6 +#define DA2_BLT_CLOAD 7 +/* POS ID = 0xeffe : Display Adapter II, III, V */ +#define DA2_POSID_H 0xef +#define DA2_POSID_L 0xfe +/* + [Identification] + POS ID SYS ID + EFFFh * Display Adapter (PS/55 Model 5571-S0A) [Toledo] + E013h * Layout Display Terminal (PS/55-5571 RPQ model) [LDT] + EFFEh * Display Adapter II (I/O 3E0:0A = xx0x xxxx) [Atlas] + |- FFF2h Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5530Z-SX) + |- FDFEh Display Adapter B2 (I/O 3E0:0A = xx1x xxxx) (PS/55 Model 5550-V2) + |- * Display Adapter III,V (I/O 3E0:0A = xx1x xxxx) + ECECh FF4Fh Display Adapter B1 (PS/55 Model 5531Z-SX) [Atlas-KENT] + |- * Display Adapter IV + ECCEh * Display Adapter IV + 901Fh * Display Adapter A2 + 901Dh * Display Adapter A1 [Atlas II] + 901Eh * Plasma Display Adapter + EFD8h * Display Adapter/J [Atlas-SP2] + + [Japanese DOS and Display Adapter compatibility] + | POS ID | Adapter Name | K3.31 | J4.04 | J5.02 | OS2 J1.3 | Win3 | + |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| + | EFFFh | Display Adapter | X | | | ? | | + | FFEDh | ? [Atlas EVT] | X | | | ? | | + | FFFDh | ? [LDT EVT] | X | | | ? | | + | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | + | E013h | ? [LDT] | X | X | X | X | | + | ECCEh | Display Adapter IV | | X | X | X | | + | ECECh | Display Adapter IV,B1 | | X | X | X | X | + | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | + | EFD8h | Display Adapter /J | | | X | X | X | +*/ +/* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ +#define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ +//#define Mon_ID3 0x10 +#define FontCard 0x08 /* ? */ +/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ +#define Page_One 0x06 /* 80000h 110b */ +#define Page_Two 0x05 /* 100000h 101b */ +#define Page_Four 0x03 /* 200000h 011b */ + +/* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ +#define AddPage 0x08 /* ? */ +//#define Mon_ID2 0x04 +//#define Mon_ID1 0x02 +//#define Mon_ID0 0x01 +/* Monitor ID (imported from OS/2 DDK 1.2) */ +//#define StarbuckC 0x0A //1 010b IBM 8514, 9518 color 1040x768 +//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale +//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp +//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B + +/* DA2 Registers (imported from OS/2 DDK) */ +#define AC_REG 0x3EE +#define AC_DMAE 0x80 +#define AC_FONT_SEL 0x40 +#define FONT_BANK 0x3EF +#define LS_INDEX 0x3E0 +#define LS_DATA 0x3E1 +#define LS_RESET 0x00 +#define LS_MODE 0x02 +#define LS_STATUS 0x03 /* added */ +#define LS_MMIO 0x08 /* added */ +#define LS_CONFIG1 0x0a +#define LS_CONFIG2 0x0b /* added */ +#define LF_INDEX 0x3e2 +#define LF_DATA 0x3e3 +#define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_ADDR 0x0A /* added */ +#define LF_MMIO_MODE 0x0B /* added */ +#define LC_INDEX 0x3E4 +#define LC_DATA 0x3E5 +#define LC_HORIZONTAL_TOTAL 0x00 +#define LC_H_DISPLAY_ENABLE_END 0x01 +#define LC_START_H_BLANKING 0x02 +#define LC_END_H_BLANKING 0x03 +#define LC_START_HSYNC_PULSE 0x04 +#define LC_END_HSYNC_PULSE 0x05 +#define LC_VERTICAL_TOTALJ 0x06 +#define LC_CRTC_OVERFLOW 0x07 +#define LC_PRESET_ROW_SCANJ 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_ROW_CURSOR_LOC 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_COLUMN_CURSOR_LOC 0x0F +#define LC_VERTICAL_SYNC_START 0x10 +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_VERTICAL_SYNC_END 0x11 +#define LC_LIGHT_PEN_LOW 0x11 +#define LC_V_DISPLAY_ENABLE_END 0x12 +#define LC_OFFSET 0x13 +#define LC_UNDERLINE_LOCATION 0x14 +#define LC_START_VERTICAL_BLANK 0x15 +#define LC_END_VERTICAL_BLANK 0x16 +#define LC_LC_MODE_CONTROL 0x17 +#define LC_LINE_COMPAREJ 0x18 +#define LC_START_H_DISPLAY_ENAB 0x19 +#define LC_START_V_DISPLAY_ENAB 0x1A +#define LC_VIEWPORT_COMMAND 0x1B +#define LC_VIEWPORT_SELECT 0x1C +#define LC_VIEWPORT_PRIORITY 0x1D +#define LC_COMMAND 0x1E +#define LC_COMPATIBILITY 0x1F +#define LC_VIEWPORT_NUMBER 0x1F +#define LV_PORT 0x3E8 +#define LV_PALETTE_0 0x00 +#define LV_MODE_CONTROL 0x10 +#define LV_OVERSCAN_COLOR 0x11 +#define LV_COLOR_PLANE_ENAB 0x12 +#define LV_PANNING 0x13 +#define LV_VIEWPORT1_BG 0x14 +#define LV_VIEWPORT2_BG 0x15 +#define LV_VIEWPORT3_BG 0x16 +#define LV_BLINK_COLOR 0x17 +#define LV_BLINK_CODE 0x18 +#define LV_GR_CURSOR_ROTATION 0x19 +#define LV_GR_CURSOR_COLOR 0x1A +#define LV_GR_CURSOR_CONTROL 0x1B +#define LV_COMMAND 0x1C +#define LV_VP_BORDER_LINE 0x1D +#define LV_SYNC_POLARITY 0x1F +#define LV_CURSOR_CODE_0 0x20 +#define LV_GRID_COLOR_0 0x34 +#define LV_GRID_COLOR_1 0x35 +#define LV_GRID_COLOR_2 0x36 +#define LV_GRID_COLOR_3 0x37 +#define LV_ATTRIBUTE_CNTL 0x38 +#define LV_CURSOR_COLOR 0x3A +#define LV_CURSOR_CONTROL 0x3B +#define LV_RAS_STATUS_VIDEO 0x3C +#define LV_PAS_STATUS_CNTRL 0x3D +#define LV_IDENTIFICATION 0x3E +#define LV_OUTPUT 0x3E +#define LV_COMPATIBILITY 0x3F +#define LG_INDEX 0x3EA +#define LG_DATA 0x3EB +#define LG_SET_RESETJ 0x00 +#define LG_ENABLE_SRJ 0x01 +#define LG_COLOR_COMPAREJ 0x02 +#define LG_DATA_ROTATION 0x03 +#define LG_READ_MAP_SELECT 0x04 +#define LG_MODE 0x05 +#define LG_COMPLEMENT 0x06 +#define LG_COLOR_DONT_CARE 0x07 +#define LG_BIT_MASK_LOW 0x08 +#define LG_BIT_MASK_HIGH 0x09 +#define LG_MAP_MASKJ 0x0A +#define LG_COMMAND 0x0B +#define LG_SET_RESET_2 0x10 + +#ifndef RELEASE_BUILD +#define ENABLE_DA2_LOG 1 +#endif + +#ifdef ENABLE_DA2_LOG +int da2_do_log = ENABLE_DA2_LOG; + +static void +da2_log(const char* fmt, ...) +{ + va_list ap; + + if (da2_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define da2_log(fmt, ...) +#endif +#ifndef RELEASE_BUILD +# define ENABLE_DA2_DEBUGBLT 1 +#endif + +typedef struct da2_t +{ + //mem_mapping_t vmapping; + mem_mapping_t cmapping; + + //uint8_t crtcreg; + uint8_t ioctl[16]; + uint8_t fctl[32]; + uint16_t crtc[128]; + uint8_t gdcreg[64]; + uint8_t reg3ee[16]; + int gdcaddr; + uint8_t attrc[0x40]; + int attraddr, attrff; + int attr_palette_enable; + //uint8_t seqregs[64]; + int outflipflop; + int inflipflop; + int iolatch; + + int ioctladdr; + int fctladdr; + int crtcaddr; + + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint32_t gdcla[8]; + uint32_t gdcinput[8]; + uint32_t gdcsrc[8]; + uint32_t debug_vramold[8]; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; + + uint8_t cgastat; + + uint8_t plane_mask; + + int fb_only; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t pallook[512]; + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int rowcount; + double clock; + uint32_t ma_latch, ca_adj; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + uint64_t da2const; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink, blinkconf; + int scrollcache; + int char_width; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + /* Attribute Buffer E0000-E0FFFh (4 KB) */ + uint8_t *cram; + /* (cram size - 1) >> 3 = 0xFFF */ + //uint32_t cram_display_mask; + /* APA Buffer A0000-BFFFFh (128 KB) */ + uint8_t *vram; + /* addr >> 12 = xx000h */ + uint8_t *changedvram; + /* (vram size - 1) >> 3 = 0x1FFFF */ + uint32_t vram_display_mask; + + //uint32_t write_bank, read_bank; + + int fullchange; + + void (*render)(struct da2_t* da2); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + + /* end VGA compatible regs*/ + struct + { + int enable; + mem_mapping_t mapping; + uint8_t ram[256 * 1024]; + uint8_t *font; + int charset; + } mmio; + + struct { + int bitshift_destr; + int raster_op; + uint8_t payload[DA2_BLT_MEMSIZE]; + int32_t reg[DA2_BLT_REGSIZE];//must be signed int + int32_t* debug_reg;//for debug + int debug_reg_ip;//for debug + int payload_addr; + pc_timer_t timer; + int64_t timerspeed; + int exec; + int indata; + int32_t destaddr; + int32_t srcaddr; + int32_t size_x, tile_w; + int32_t size_y; + int16_t destpitch; + int16_t srcpitch; + int32_t fcolor; + int32_t maskl, maskr; + int x, y; + } bitblt; + + FILE* mmdbg_fp; + FILE* mmrdbg_fp; + uint32_t mmdbg_vidaddr; + uint32_t mmrdbg_vidaddr; + + uint8_t pos_regs[8]; + svga_t *mb_vga; + uint8_t monitorid; + + int old_pos2; +} da2_t; + +void da2_recalctimings(da2_t* da2); +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p); +void da2_bitblt_exec(void* p); +void da2_updatevidselector(da2_t* da2); +void da2_reset_ioctl(da2_t* da2); +static void da2_reset(void* priv); + +typedef union { + uint32_t d; + uint8_t b[4]; +} DA2_VidSeq32; + +typedef struct { + uint32_t p8[8]; +} pixel32; + +/* safety read for internal functions */ +uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) +{ + if (addr & ~da2->vram_mask) return -1; + return da2->vram[addr]; +} + +void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32* srcpx, da2_t* da2) +{ + uint32_t writepx[8]; + destaddr &= 0xfffffffe;/* align to word address to work bit shift correctly */ + //da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); + da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; + da2->changedvram[(da2->vram_display_mask & (destaddr+1)) >> 12] = changeframecount; + destaddr <<= 3; + /* read destination data with big endian order */ + for (int i = 0; i < 8; i++) + writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) + | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); + + DA2_VidSeq32 mask32in; mask32in.d = (uint32_t)mask; + DA2_VidSeq32 mask32; mask32.d = 0; + mask32.b[3] = mask32in.b[0]; + mask32.b[2] = mask32in.b[1]; + mask32.d &= 0xffff0000; + for (int i = 0; i < 8; i++) + { + if (da2->bitblt.bitshift_destr > 0) + srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; + switch (da2->bitblt.raster_op) { + case 0x00: /* None */ + writepx[i] &= ~mask32.d; + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x01: /* AND */ + writepx[i] &= srcpx->p8[i] | ~mask32.d; + break; + case 0x02: /* OR */ + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x03: /* XOR */ + writepx[i] ^= srcpx->p8[i] & mask32.d; + break; + } + } + for (int i = 0; i < 8; i++) { + da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; + da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; + } +} + +void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + //fill data with input color + for (int i = 0; i < 8; i++) + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +/* +Param Desc +01 Color +03 Bit Shift +04 Select plane? +05 Dir(10 or 11) + Command?(40 or 48) +08 Mask Left +09 Mask Right +0A Plane Mask? +0B ROP?(8h or 200h + 0-3h) +0D +20 Exec (1) +21 ? +22 ? +23 Tile W +28 Tile H +29 Dest Addr +2A Src Addr +2B Tile Addr +33 Size W +35 Size H + +*/ +void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + srcaddr &= 0xfffffffe; + srcaddr <<= 3; + for (int i = 0; i < 8; i++) + srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) + | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +{ + pixel32 srcpx; + if (srcaddr >= DA2_FONTROM_SIZE) { + da2_log("DA2 Putchar Addr Error %x\n", srcaddr); + return; + } + for (int i = 0; i < 8; i++) + srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) + | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) + | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) + | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word + + DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +#ifdef ENABLE_DA2_DEBUGBLT +uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { + uint8_t pixeldata = 0; + for (int j = 0; j < 8; j++) { + if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) pixeldata++; + } + return pixeldata; +} +void print_pixelbyte(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) + { + pclog("%X", pixel1tohex(addr, i, da2)); + } +} +void print_bytetobin(uint8_t b) { + for (int i = 0; i < 8; i++) + { + if(b & 0x80) + pclog("1"); + else + pclog("0"); + b <<= 1; + } +} +//Convert internal char code to Shift JIS code +inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } +inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } +uint16_t IBMJtoSJIS(uint16_t knj) +{ + if (knj < 0x100) return 0xffff; + knj -= 0x100; + if (knj <= 0x1f7d) + ;/* do nothing */ + else if (knj >= 0xb700 && knj <= 0xb75f) { + knj -= 0x90ec; + } + else if (knj >= 0xb3f0 && knj <= 0xb67f) { + knj -= 0x906c; + } + else if (knj >= 0x8000 && knj <= 0x8183) + { + knj -= 0x5524; + } + else + return 0xffff; + uint32_t knj1 = knj / 0xBC; + uint32_t knj2 = knj - (knj1 * 0xBC); + knj1 += 0x81; + if (knj1 > 0x9F) knj1 += 0x40; + knj2 += 0x40; + if (knj2 > 0x7E) knj2++; + //if (!isKanji1(knj1)) return 0xffff; + //if (!isKanji2(knj2)) return 0xffff; + knj = knj1 << 8; + knj |= knj2; + return knj; +} +#endif +void da2_bitblt_load(da2_t* da2) +{ + uint32_t value32; + uint64_t value64; + da2_log("BITBLT loading params\n"); + //da2_log("BitBlt memory:\n"); + //if (da2->bitblt.payload[0] != 0) + // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) + // { + // int i = j * 8; + // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + // } + int i = 0; + while (i < DA2_BLT_MEMSIZE) + { + if (da2->bitblt.reg[0x20] & 0x1) + break; + switch (da2->bitblt.payload[i]) { + case 0x88: + case 0x89: + case 0x95: + value32 = da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 3; + break; + case 0x91: + value32 = da2->bitblt.payload[i + 5]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 4]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 5; + break; + case 0x99: + value64 = da2->bitblt.payload[i + 7]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 6]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 2]; + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + i += 7; + break; + case 0x00: + break; + default: + da2_log("da2_ParseBLT: Unknown PreOP!\n"); + break; + } + i++; + } + da2->bitblt.exec = DA2_BLT_CIDLE; + /* clear payload memory */ + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; + /* [89] 20: 0001 (1) then execute payload */ + if (da2->bitblt.reg[0x20] & 0x1) + { +#ifdef ENABLE_DA2_DEBUGBLT + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + //if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); + } + for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; + } + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; + da2->bitblt.debug_reg_ip++; + if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);//set bit shift + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;//01 AND, 03 XOR + da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); + for (int i = 0; i <= 0xb; i++) + da2_log("%02x ", da2->gdcreg[i]); + da2_log("\n"); + + da2->bitblt.destaddr = da2->bitblt.reg[0x29]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + da2->bitblt.size_y = da2->bitblt.reg[0x35]; + da2->bitblt.destpitch = da2->bitblt.reg[0x21]; + da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + { + da2->bitblt.destaddr -= 2; + da2->bitblt.size_x += 1; + da2->bitblt.destpitch -= 2; + da2->bitblt.srcpitch -= 2; + } + da2->bitblt.fcolor = da2->bitblt.reg[0x0]; + da2->bitblt.maskl = da2->bitblt.reg[0x8]; + da2->bitblt.maskr = da2->bitblt.reg[0x9]; + da2->bitblt.x = 0; + da2->bitblt.y = 0; + da2->bitblt.exec = DA2_BLT_CDONE; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + + if (da2->bitblt.reg[0x2f] < 0x80)//MS Paint 3.1 will cause hang up in 256 color mode + { + da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); + da2->bitblt.exec = DA2_BLT_CDONE; + } + else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + /* Todo: addressing */ + //if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + //{ + // da2->bitblt.destaddr += 2; + // da2->bitblt.size_x -= 1; + // da2->bitblt.destpitch += 2; + // da2->bitblt.srcpitch += 2; + //} + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; + da2->bitblt.destaddr += 2; + da2->bitblt.srcpitch = 0; + da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ + da2->bitblt.bitshift_destr += 1; + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {/* Fill a rectangle(or draw a line) */ + da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); + da2->bitblt.exec = DA2_BLT_CFILLRECT; + da2->bitblt.destaddr += 2; + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle (transfer tile data multiple times) */ + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {/* Block transfer (range copy) */ + da2->bitblt.exec = DA2_BLT_CCOPYF; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr += 2; + da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {/* Block copy but reversed direction */ + da2->bitblt.exec = DA2_BLT_CCOPYR; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); + } + } +} +void da2_bitblt_exec(void* p) +{ + da2_t* da2 = (da2_t*)p; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + switch (da2->bitblt.exec) + { + case DA2_BLT_CIDLE: + timer_disable(&da2->bitblt.timer); + break; + case DA2_BLT_CLOAD: + da2->bitblt.indata = 0; + da2_bitblt_load(da2); + break; + case DA2_BLT_CFILLRECT: + //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CFILLTILE: + int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CCOPYF: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr += 2; + break; + case DA2_BLT_CCOPYR: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr -= da2->bitblt.destpitch; + da2->bitblt.srcaddr -= da2->bitblt.srcpitch; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + } + else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } + else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + } + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + break; + case DA2_BLT_CPUTCHAR: + //da2->bitblt.y += 2; + da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; + pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + //da2->bitblt.srcaddr += 2; + if(da2->bitblt.reg[0x12] < 0x100) + da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; + else + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); + print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); + pclog("\n"); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + //if (1) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 3) + { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += 130; + //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + //da2->bitblt.srcaddr += -1; + } + else if (da2->bitblt.x == 0) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + else { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + //da2->bitblt.x++; + } + //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; + ////da2->bitblt.srcaddr += 2; + //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; + break; + case DA2_BLT_CDONE: + /* initialize regs for debug dump */ + for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + } + if(da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; + else da2->bitblt.exec = DA2_BLT_CIDLE; + break; + } +} +void da2_bitblt_dopayload(da2_t* da2) { + if (da2->bitblt.exec == DA2_BLT_CIDLE) + { + da2->bitblt.exec = DA2_BLT_CLOAD; + //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ + da2_log("da2 Do bitblt\n"); + while (da2->bitblt.exec != DA2_BLT_CIDLE) + { + da2_bitblt_exec(da2); + } + da2_log("da2 End bitblt %x\n", da2->bitblt.exec); + } +} + +void da2_out(uint16_t addr, uint16_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + int oldval; +/* +3E0 3E1 Sequencer Registers (undoc) +3E2 3E3 Font Registers (undoc) +3E4 3E5 CRT Control Registers (undoc) +3E8 3E9 Attribute Controller Registers (undoc) +3EA 3EB 3EC Graphics Contoller Registers +*/ + switch (addr) + { + case 0x3c6: /* PEL Mask */ + da2->dac_mask = val; + break; + case 0x3C7: /* Read Address */ + da2->dac_read = val; + da2->dac_pos = 0; + break; + case 0x3C8: /* Write Address */ + da2->dac_write = val; + da2->dac_read = val - 1; + da2->dac_pos = 0; + break; + case 0x3C9: /* Data */ + //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); + da2->dac_status = 0; + da2->fullchange = changeframecount; + switch (da2->dac_pos) + { + case 0: + da2->dac_r = val; + da2->dac_pos++; + break; + case 1: + da2->dac_g = val; + da2->dac_pos++; + break; + case 2: + da2->vgapal[da2->dac_write].r = da2->dac_r; + da2->vgapal[da2->dac_write].g = da2->dac_g; + da2->vgapal[da2->dac_write].b = val; + //if (da2->ramdac_type == RAMDAC_8BIT) + // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); + //else + da2->pallook[da2->dac_write] = makecol32((da2->vgapal[da2->dac_write].r & 0x3f) * 4, (da2->vgapal[da2->dac_write].g & 0x3f) * 4, (da2->vgapal[da2->dac_write].b & 0x3f) * 4); + da2->dac_pos = 0; + da2->dac_write = (da2->dac_write + 1) & 255; + break; + } + break; + case LS_INDEX: + da2->ioctladdr = val; + break; + case LS_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); + if (da2->ioctladdr > 0xf) return; + if (da2->ioctl[da2->ioctladdr & 15] != val) + da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); + oldval = da2->ioctl[da2->ioctladdr]; + da2->ioctl[da2->ioctladdr] = val; + if (oldval != val) { + if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset register */ + da2_reset_ioctl(da2); + else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + da2_updatevidselector(da2); + } + else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ + { + //da2->bitblt.indata = 1; + } + } + break; + case LF_INDEX: + da2->fctladdr = val; + break; + case LF_DATA: + //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + if (da2->fctladdr > 0x1f) return; + if (da2->fctl[da2->fctladdr & 0x1f] != val) + da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); + oldval = da2->fctl[da2->fctladdr]; + da2->fctl[da2->fctladdr] = val; + if (da2->fctladdr == 0 && oldval != val) + { + da2->fullchange = changeframecount; + da2_recalctimings(da2); + } + break; + case LC_INDEX: + da2->crtcaddr = val; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return; + //if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + if (!(da2->crtc[da2->crtcaddr] ^ val)) return; + switch (da2->crtcaddr) { + case LC_CRTC_OVERFLOW: + //return; + break; + case LC_MAXIMUM_SCAN_LINE: + if (!(da2->ioctl[LS_MODE] & 0x01)) val = 0; + break; + case LC_START_ADDRESS_HIGH: + //if (da2->crtc[0x1c] & 0x40) return; + break; + case LC_VERTICAL_TOTALJ: /* Vertical Total */ + case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ + case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ + case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ + //val = 0x400; //for debugging bitblt + break; + case LC_VIEWPORT_SELECT: /* ViewPort Select? */ + //return; + break; + case LC_VIEWPORT_NUMBER: /* Compatibility? */ + break; + } + da2->crtc[da2->crtcaddr] = val; + switch (da2->crtcaddr) { + case LC_H_DISPLAY_ENABLE_END: + case LC_VERTICAL_TOTALJ: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + case LC_VERTICAL_SYNC_START: + case LC_V_DISPLAY_ENABLE_END: + case LC_START_VERTICAL_BLANK: + case LC_END_VERTICAL_BLANK: + case LC_VIEWPORT_PRIORITY: + da2->fullchange = changeframecount; + da2_recalctimings(da2); + break; + default: + break; + } + break; + case LV_PORT: + //da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + if (!da2->attrff) + { + // da2->attraddr = val & 31; + da2->attraddr = val & 0x3f; + if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) + { + da2->fullchange = 3; + da2->attr_palette_enable = val & 0x20; + da2_recalctimings(da2); + } + //da2_log("set attraddr: %X\n", da2->attraddr); + } + else + { + if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val)) + da2->fullchange = changeframecount; + if (da2->attrc[da2->attraddr & 0x3f] != val) + da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); + da2->attrc[da2->attraddr & 0x3f] = val; + //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); + if (da2->attraddr < 16) + da2->fullchange = changeframecount; + if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) + { + for (int c = 0; c < 16; c++) + { + //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); + //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); + if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; + else da2->egapal[c] = da2->attrc[c] & 0x3f; + } + } + switch (da2->attraddr) + { + case LV_COLOR_PLANE_ENAB: + if ((val & 0xff) != da2->plane_mask) + da2->fullchange = changeframecount; + da2->plane_mask = val & 0xff; + break; + case LV_CURSOR_CONTROL: + switch (val & 0x18) { + case 0x08://fast blink + da2->blinkconf = 0x10; + break; + case 0x18://slow blink + da2->blinkconf = 0x20; + break; + default://no blink + da2->blinkconf = 0xff; + break; + } + break; + case LV_MODE_CONTROL: + case LV_ATTRIBUTE_CNTL: + case LV_COMPATIBILITY: + da2_recalctimings(da2); + break; + default: + break; + } + } + da2->attrff ^= 1; + break; + case 0x3E9: + /* VZ Editor's CURSOR.COM writes data via this port */ + da2->attrc[da2->attraddr & 0x3f] = val; + break; + case LG_INDEX: + da2->gdcaddr = val; + break; + case LG_DATA: + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + switch (da2->gdcaddr & 0x1f) + { + case LG_READ_MAP_SELECT: + da2->readplane = val & 0x7; + break; + case LG_MODE: + da2->writemode = val & 3; + break; + case LG_MAP_MASKJ: + da2->writemask = val & 0xff; + break; + case LG_COMMAND: + break; + case LG_SET_RESET_2: + da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); + return; + } + da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; + break; + //case 0x3ed: /* used by Windows 3.1 display driver */ + // da2->gdcreg[5] = val & 0xff; + // break; + default: + da2_log("DA2? Out addr %03X val %02X\n", addr, val); + break; + } +} + +uint16_t da2_in(uint16_t addr, void *p) +{ + da2_t * da2 = (da2_t *)p; + uint16_t temp; + + switch (addr) + { + case 0x3c3: + temp = 0; + break; + case 0x3c6: temp = da2->dac_mask; + break; + case 0x3c7: temp = da2->dac_status; + break; + case 0x3c8: temp = da2->dac_write; + break; + case 0x3c9: + da2->dac_status = 3; + switch (da2->dac_pos) + { + case 0: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].r & 0x3f; + break; + case 1: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].g & 0x3f; + break; + case 2: + da2->dac_pos = 0; + da2->dac_read = (da2->dac_read + 1) & 255; + temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case LS_INDEX: + temp = da2->ioctladdr; + break; + case LS_DATA: + //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) + if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; + temp = da2->ioctl[da2->ioctladdr]; + if (da2->ioctladdr == LS_STATUS) { /* Status register */ + if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ + if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { + /* grayscale monitor */ + if ((da2->vgapal[0].r >= 10) || (da2->vgapal[0].g >= 40) || (da2->vgapal[0].b >= 10)) + temp &= 0x7F; /* Inactive when the RGB output voltage is high (or the cable is not connected to a color monitor). */ + else + temp |= 0x80; /* Active when the RGB output voltage is low and the cable is connected to a color monitor. + If the cable or the monitor is wrong, it becomes inactive. */ + } else { + /* color monitor */ + if ((da2->vgapal[0].r + da2->vgapal[0].g + da2->vgapal[0].b) >= 80) + temp &= 0x7F; + else + temp |= 0x80; + } + } else { + temp |= 0x80; + } + temp &= 0xf6;//clear busy bits + if (da2->bitblt.indata) /* for OS/2 J1.3 */ + da2_bitblt_dopayload(da2); + if (da2->bitblt.exec != DA2_BLT_CIDLE) + { + //da2_log("exec:%x\n", da2->bitblt.exec); + temp |= 0x08;//wait(bit 3 + bit 0) + //if (!da2->bitblt.timer.enabled) + //{ + // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); + // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + //} + } + if (da2->bitblt.indata) + temp |= 0x01; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + } + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + break; + case LF_INDEX: + temp = da2->fctladdr; + break; + case LF_DATA: + if (da2->fctladdr > 0x1f) return DA2_INVALIDACCESS8; + temp = da2->fctl[da2->fctladdr]; + break; + case LC_INDEX: + temp = da2->crtcaddr; + break; + case LC_DATA: + if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; + temp = da2->crtc[da2->crtcaddr]; + break; + case LV_PORT: + temp = da2->attraddr | da2->attr_palette_enable; + break; + case 0x3E9: + if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this may equiv to 3ba / 3da Input Status Register 1 */ + { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + else + temp = da2->attrc[da2->attraddr]; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); + da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ + break; + case LG_INDEX: + temp = da2->gdcaddr; + break; + case LG_DATA: + temp = da2->gdcreg[da2->gdcaddr & 0x1f]; + //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + break; + } + //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +/* +* Write I/O +* out b(idx), out b(data), out b(data) +* out b(idx), out w(data) +* out b(idx), out w(data), out b(data) +* out w(idx) +* Read I/O +* out b(idx), in b(data) +* out b(idx), in b, in b(data) +* out b(idx), in w(data) +*/ +void da2_outb(uint16_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + da2->inflipflop = 0; + switch (addr) + { + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + if (da2->outflipflop) + { + /* out b(idx), out b(data), out b(data) */ + da2->iolatch |= (uint16_t)val << 8; + da2->outflipflop = 0; + } + else + {// + da2->iolatch = val; + da2->outflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + default: + da2->iolatch = val; + da2->outflipflop = 0; + break; + } + da2_out(addr, da2->iolatch, da2); +} +void da2_outw(uint16_t addr, uint16_t val, void* p) +{ + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + switch (addr) + { + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + da2_out(addr, val & 0xff, da2); + da2->iolatch = val >> 8; + da2_out(addr + 1, da2->iolatch, da2); + da2->outflipflop = 1; + break; + case LV_PORT: + da2->attrff = 0; + da2_out(addr, val & 0xff, da2); + da2_out(addr, val >> 8, da2); + da2->outflipflop = 0; + break; + case 0x3EC: + //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_out(LG_DATA, val >> 8, da2); + break; + case 0x3ED: + da2->gdcaddr = LG_MODE; + da2_out(LG_DATA, val, da2); + break; + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + default: + da2_out(addr, val, da2); + da2->outflipflop = 0; + break; + case 0x3EE: + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2->reg3ee[val & 0xff] = val >> 8; + break; + } +} +uint8_t da2_inb(uint16_t addr, void* p) +{ + uint8_t temp; + da2_t* da2 = (da2_t*)p; + da2->outflipflop = 0; + switch (addr) + { + case LC_DATA: + if (da2->inflipflop) + { + /* out b(idx), in b(low data), in b(high data) */ + temp = da2->iolatch >> 8; + da2->inflipflop = 0; + } + else + {// + da2->iolatch = da2_in(addr, da2); + temp = da2->iolatch & 0xff; + da2->inflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + case LS_DATA: + case LF_DATA: + case LG_DATA: + default: + temp = da2_in(addr, da2) & 0xff; + da2->inflipflop = 0; + break; + } + //da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +uint16_t da2_inw(uint16_t addr, void* p) +{ + //uint16_t temp; + da2_t* da2 = (da2_t*)p; + da2->inflipflop = 0; + da2->outflipflop = 0; + return da2_in(addr, da2); +} +/* IO 03DAh : Input Status Register 2 for DOSSHELL in DOS J4.0 */ +uint8_t da2_in_ISR(uint16_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t temp = 0; + if (addr == 0x3da) { + if (da2->cgastat & 0x01) + da2->cgastat &= ~0x30; + else + da2->cgastat ^= 0x30; + temp = da2->cgastat; + } + //da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} + +void da2_out_ISR(uint16_t addr, uint8_t val, void* p) +{ + //da2_t* da2 = (da2_t*)p; + da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); +} + +/* +The IBM 5550 character mode addresses video memory between E0000h and E0FFFh. + [Character drawing] + SBCS: + 1 2 ... 13 + 1 | H.Grid + |---------------- + 2 | Space + 3 V| + .| + G| Font Pattern + r| (12x24 pixels) + i| + d| +26 |________________ +27 Space + ---------------- +28 Underscore ] + ---------------- >Cursor Position +29 ] + + DBCS: + 1 2 ... 13 1 2 ... 12 13 + 1 | H.Grid | H.Grid | + -|--------------------------|- + 2 | Space | Space | + -|--------------------------|- + 3 V| | |S + .| | |p + G| Font Pattern |a + r| (24x24 pixels) |c + i| | |e + d| | | +26 |_____________|____________| +27 | Space | Space + ------------------------------ +28 | Underscore | Underscore ] + ------------------------------ >Cursor Position +29 | | ] + + [Attributes] + Video mode 08h: + 7 6 5 4 3 2 1 0 + Blink |Under |HGrid |VGrid |Bright|Revers|FntSet|DBCS/SBCS| + + Video mode 0Eh: + -Blue |-Green|HGrid |VGrid |-Red |Revers|FntSet|DBCS/SBCS| + + Bit 1 switches the font bank to the Extended SBCS. DOS K3.x loads APL characters from $SYSEX24.FNT into it. + DOS Bunsho Program transfers 1/2 and 1/4 fonts fron the font ROM to the Extended SBCS. + This bit is not used for DBCS, but some apps set it as that column is right half of DBCS. + +[Font ROM Map (DA2, Japanese)] +The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. + + Bank 0 + 4800- * + Bank 1, 2, 3 + * - * + Bank 4 + * -0DB6Fh ( 4800-8DB6Fh) : JIS X 0208 DBCS (24 x 24) (IBMJ code: 100-1F7Dh) + 10000-16D1Fh (90000-96D1Fh) : IBM Extended Characters (IBMJ code: 2ADC-2C5Fh) + 18000-1BFCFh (98000-9BFCFh) : JIS X 0201 SBCS (13 x 30) + 1C000-1FFFFh (9C000-9FFFFh) : Codepage 437 characters (13 x 30) + Bank 5 + 00000-0C68Fh (A0000-AC68Fh) : Gaiji used by DOS Bunsho + 10000-13FFFh (B0000-B3FFFh) : Extended SBCS (13 x 30) + 14000-1477Fh (B4000-B477Fh) : Half-width box drawing characters used by DOS Bunsho + 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) + 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) + + Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) + +[Font ROM Map (DA3, Traditional Chinese)] + Bank 0 - 11 : Valid Font ROM data + Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) + Bank 13 : All addresses return 0xFF + +[Gaiji RAM Map (DA2)] + Bank 0 00000-1FFFFh placed between A0000h-BFFFFh + 00000-1F7FFh(A0000-BF7FFh): Gaiji Non-resident (Kuten 103-114 ku,IBM: 2674-2ADBh) 1008 chs 128 bytes + 1F800-1FFFFh(BF800-BFFFFh): Gaiji Resident (SJIS: F040-F04Fh, IBM: 2384-2393h) 16 chs + + Bank 1 20000-3FFFFh placed between A0000h-BFFFFh + 20000-33FFFh(A0000-B3FFFh): Gaiji Resident (SJIS: F050-F39Ch, IBM: 2394-2613h) 640 chs + 34000-37FFFh(B4000-B7FFFh): Basic SBCS(00-FFh, ATTR bit 1 = off) + 38000-3AFFFh(B8000-BAFFFh): Gaiji Resident (SJIS: F39D-F3FCh, IBM: 2614-2673h) 96 chs + 3C000-3FFFFh(BC000-BFFFFh): Extended SBCS(00-FFh, ATTR bit 1 = on) + +[IBMJ code to Gaiji address conv tbl from DOS K3.3] + A B C + 2ADC, 2C5F, +5524 --> 8000 + 2614, 2673, +90EC --> B700 + 2384, 2613, +906C --> B3F0 + 0682, 1F7D, +0000 + + 8000 - 8183h 184h(388 characters) IBM Extended Characters + B3F0 - B75Fh 370h(880 characters) User-defined Characters +*/ + +/* Get character line pattern from jfont rom or gaiji volatile memory */ +uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { + da2_t* da2 = (da2_t*)p; + uint32_t font = 0; + int32_t fline = line - 2;//Start line of drawing character (line >= 1 AND line < 24 + 1 ) + if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) + if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { + font = da2->mmio.font[code * 72 + fline * 3]; //1111 1111 + font <<= 8; //1111 1111 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; //1111 1111 2222 0000 + font >>= 1; //0111 1111 1222 2000 + font <<= 4; //0111 1111 1222 2000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; //0111 1111 1222 2000 2222 + font <<= 8; //0111 1111 1222 2000 2222 0000 0000 + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; //0111 1111 1222 2000 2222 3333 3333 + font <<= 4; //0111 1111 1222 2000 2222 3333 3333 0000 + //font >>= 1;//put blank at column 1 (and 26) + } + else if (code >= 0xb000 && code <= 0xb75f) + { + //convert code->address in gaiji memory + code -= 0xb000; + code *= 0x80; + //code += 0xf800; + font = da2->mmio.ram[code + line * 4]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 1]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 2]; + font <<= 8; + font |= da2->mmio.ram[code + line * 4 + 3]; + } + else if (code > DA2_FONTROM_SIZE) + font = 0xffffffff; + else + font = 0; + return font; +} + +/* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ +uint8_t IRGBtoBGRI(uint8_t attr) +{ + attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); + return attr >>= 4; +} +/* Get the foreground color from the attribute byte */ +uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) +{ + uint8_t foreground = ~attr & 0x08;// 0000 1000 + foreground <<= 2; //0010 0000 + foreground |= ~attr & 0xc0;// 1110 0000 + foreground >>= 4;//0000 1110 + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette + return foreground; +} + +void da2_render_blank(da2_t* da2) +{ + int x, xx; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + for (x = 0; x < da2->hdisp; x++) + { + for (xx = 0; xx < 13; xx++) ((uint32_t*)buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; + } +} +/* Display Adapter Mode 8, E Drawing */ +static void da2_render_text(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->cram[(da2->ma) & da2->vram_display_mask]; + attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; + //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh + {//--Parse attribute byte in color mode-- + bg = 0;//bg color is always black (the only way to change background color is programming PAL) + fg = getPS55ForeColor(attr, da2); + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + } + else + {//--Parse attribute byte in monochrome mode-- + if (attr & 0x08) fg = 3;//Highlight 0000 1000 + else fg = 2; + bg = 0;//Background is always color #0 (default is black) + if (!(~attr & 0xCC))//Invisible 11xx 11xx -> 00xx 00xx + { + fg = bg; + attr &= 0x33;//disable blinkking, underscore, highlight and reverse + } + if (attr & 0x04) {//reverse 0000 0100 + bg = fg; + fg = 0; + } + // Blinking 1000 0000 + fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; + //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); + } + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + // SBCS or DBCS left half + if (chr_wide == 0) { + if (attr & 0x01) chr_wide = 1; + //chr_wide = 0; + // Stay drawing If the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + if (attr & 0x02)//second map of SBCS font + fontbase = DA2_GAIJIRAM_SBEX; + else + fontbase = DA2_GAIJIRAM_SBCS; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. + if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + } + //Column 1 (Vertical Line) + if (attr & 0x10) { + p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + } + if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); + int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) {//Color 0 if reverse + bg = fg; + fg = 0; + } + for (uint32_t n = 0; n < cursorwidth; n++) + if (p[n] == da2->pallook[da2->egapal[cursorcolor]] || da2->egapal[bg] == da2->egapal[cursorcolor]) + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[fg]] : da2->pallook[da2->egapal[bg]]; + else + p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[cursorcolor]] : p[n]; + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +/* Display Adapter Mode 3 Drawing */ +static void da2_render_textm3(da2_t* da2) +{ + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + + if (da2->fullchange) + { + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr, extattr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) + { + chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; + attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; + extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; + //if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); + bg = attr >> 4; + //if (da2->blink) bg &= ~0x8; + //fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; + fg = attr & 0xf; + fg = IRGBtoBGRI(fg); + bg = IRGBtoBGRI(bg); + //Draw character + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank + // SBCS or DBCS left half + if (chr_wide == 0) { + if (extattr & 0x01) chr_wide = 1; + // Stay drawing if the char code is DBCS and not at last column. + if (chr_wide) { + //Get high DBCS code from the next video address + chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + // Get the font pattern + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } + else { + // the char code is SBCS (ANK) + uint32_t fontbase; + fontbase = DA2_GAIJIRAM_SBCS; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + font <<= 8; + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + // right half of DBCS + else + { + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + // Draw 13 dots + for (uint32_t n = 0; n < 13; n++) { + p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + //Drawing text cursor + drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) + { + //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); + //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 + //fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + //bg = 0; + //if (attr & 0x04) {//Color 0 if reverse + // bg = fg; + // fg = 0; + //} + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[fg]]; + } + da2->ma += 2; + p += 13; + } + da2->ma &= da2->vram_display_mask; + //da2->writelines++; + } +} + +void da2_render_color_4bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + da2->plane_mask &= 0x0f;//safety + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); + p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); + p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); + p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); + p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); + p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); + p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); + p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); + p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_render_color_8bpp(da2_t* da2) +{ + int changed_offset = da2->ma >> 12; + //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) + { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + //da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + { + uint8_t edat[8]; + uint8_t dat; + + //get 8 pixels from vram + da2->ma &= da2->vram_display_mask; + *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); + *(uint32_t*)(&edat[4]) = *(uint32_t*)(&da2->vram[(da2->ma << 3) + 4]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | + ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); + p[0] = da2->pallook[dat]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | + ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); + p[1] = da2->pallook[dat]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | + ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); + p[2] = da2->pallook[dat]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | + ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); + p[3] = da2->pallook[dat]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | + ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); + p[4] = da2->pallook[dat]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | + ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); + p[5] = da2->pallook[dat]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | + ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); + p[6] = da2->pallook[dat]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | + ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); + p[7] = da2->pallook[dat]; + p += 8; + } + //da2->writelines++; + } +} + +void da2_updatevidselector(da2_t* da2) { + /* if VGA passthrough mode */ + da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); + if (da2->ioctl[LS_MODE] & 0x02) + { + da2->override = 1; + svga_set_override(da2->mb_vga, 0); + } + else + { + svga_set_override(da2->mb_vga, 1); + da2->override = 0; + } +} + +void da2_recalctimings(da2_t* da2) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + + da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff;//w + da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff;//w + da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff;//w + da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff;//w Line Compare + da2->split = 0xfff; + da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;//w + da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; + + if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { + da2->hdisp--; + da2->dispend -= 29; + } + else { + //da2->vtotal += 2; + da2->dispend--; + //da2->vsyncstart++; + //da2->split++; + //da2->vblankstart++; + //da2->hdisp--; + } + + da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; + da2->htotal += 1; + + da2->rowoffset = da2->crtc[LC_OFFSET];//number of bytes in a scanline + + da2->clock = da2->da2const; + + //da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; + + //da2->interlace = 0; + + //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b + da2->ca_adj = 0; + + da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; + + da2->hdisp_time = da2->hdisp; + da2->render = da2_render_blank; + //determine display mode + //if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) + if (da2->attrc[LV_COMPATIBILITY] & 0x08) + { + if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode + da2->hdisp *= 16; + da2->char_width = 13; + da2->hdisp_old = da2->hdisp; + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { + da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + da2->render = da2_render_color_8bpp; + da2->vram_display_mask = DA2_MASK_GRAM; + } + else {//PS/55 8-color + da2_log("Set videomode to PS/55 4 bpp graphics.\n"); + da2->vram_display_mask = DA2_MASK_GRAM; + da2->render = da2_render_color_4bpp; + } + } + else {//text mode + if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { + da2_log("Set videomode to PS/55 Mode 03 text.\n"); + da2->render = da2_render_textm3; + da2->vram_display_mask = DA2_MASK_CRAM; + } + else {//PS/55 text(color/mono) + da2_log("Set videomode to PS/55 Mode 8/E text.\n"); + da2->render = da2_render_text; + da2->vram_display_mask = DA2_MASK_CRAM; + } + da2->hdisp *= 13; + da2->hdisp_old = da2->hdisp; + da2->char_width = 13; + } + } + else + { + da2_log("Set videomode to blank.\n"); + } + //if (!da2->scrblank && da2->attr_palette_enable) + //{ + //da2->render = da2_draw_text; + //} + + // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + + //if (da2->recalctimings_ex) + // da2->recalctimings_ex(da2); + + if (da2->vblankstart < da2->dispend) + da2->dispend = da2->vblankstart; + + crtcconst = da2->clock * da2->char_width; + + disptime = da2->htotal; + _dispontime = da2->hdisp_time; + + da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); + //if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + da2->dispontime = (uint64_t)_dispontime; + da2->dispofftime = (uint64_t)_dispofftime; + if (da2->dispontime < TIMER_USEC) + da2->dispontime = TIMER_USEC; + if (da2->dispofftime < TIMER_USEC) + da2->dispofftime = TIMER_USEC; + da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); + // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + + // da2_log("da2->render %08X\n", da2->render); +} + +uint8_t da2_mca_read(int port, void *p) +{ + da2_t *da2 = (da2_t *)p; + return da2->pos_regs[port & 7]; +} + +static void da2_mapping_update(da2_t *da2) +{ + if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) return; + da2->old_pos2 = da2->pos_regs[2]; + //da2_recalc_mapping(da2); + if (da2->pos_regs[2] & 0x01) + { + da2_log("DA2 enable registers\n"); + for (int i = 0; i < 8; i++) + da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); + io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + mem_mapping_enable(&da2->cmapping); + mem_mapping_enable(&da2->mmio.mapping); + timer_enable(&da2->timer); + } + else + { + da2_log("DA2 disable registers\n"); + timer_disable(&da2->timer); + mem_mapping_disable(&da2->cmapping); + mem_mapping_disable(&da2->mmio.mapping); + io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + } +} + +void da2_mca_write(int port, uint8_t val, void *p) +{ + da2_t *da2 = (da2_t *)p; + + da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); + + if (port < 0x102) + return; + da2->pos_regs[port & 7] = val; + + da2_mapping_update(da2); +} + +static uint8_t da2_mca_feedb(void* priv) +{ + const da2_t* da2 = (da2_t*)priv; + + return da2->pos_regs[2] & 0x01; +} + +static void da2_mca_reset(void *p) +{ + da2_t *da2 = (da2_t *)p; + da2_reset(da2); + da2_mca_write(0x102, 0, da2); +} +// +static void da2_gdcropB(uint32_t addr, da2_t* da2) { + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + } + } + } +} +static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t* da2) { + uint8_t bitmask_l = bitmask & 0xff; + uint8_t bitmask_h = bitmask >> 8; + for (int i = 0; i < 8; i++) { + if (da2->writemask & (1 << i)) { + //da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) + { + case 0: /*Set*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); + da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 1: /*AND*/ + //da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 2: /*OR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 3: /*XOR*/ + //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; + //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + } + } + } +} + +static uint8_t da2_mmio_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + if (da2->fctl[LF_MMIO_SEL] == 0x80) + //linear access + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); + else + { + //64k bank switch access + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { + case 0xb0://Gaiji RAM + addr &= DA2_MASK_GAIJIRAM;//safety access + //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); + return da2->mmio.ram[addr]; + break; + case 0x10://Font ROM + if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { + if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; + if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, + but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ + } + if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; + //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + return da2->mmio.font[addr]; + break; + default: + return DA2_INVALIDACCESS8;//invalid memory access + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode + { + cycles -= video_timing_read_b; + for (int i = 0; i < 8; i++) + da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte + //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint8_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); + } + return ~ret; + } + else return da2->gdcla[da2->readplane]; + } + else //text mode 3 + { + cycles -= video_timing_read_b; + return da2->vram[addr]; + } +} +static uint16_t da2_mmio_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + if (da2->ioctl[LS_MMIO] & 0x10) { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + cycles -= video_timing_read_w; + addr &= DA2_MASK_MMIO; + for (int i = 0; i < 8; i++) + da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch + +#ifdef ENABLE_DA2_DEBUGBLT + ////debug + //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) + //{ + // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); + //} + //for (int i = 0; i < 16; i++) + //{ + // int pixeldata = 0; + // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; + // fprintf(da2->mmrdbg_fp, "%X", pixeldata); + //} + //da2->mmrdbg_vidaddr = addr; +#endif + + if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + uint16_t ret = 0; + + for (int i = 0; i < 8; i++) + { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); + } + return ~ret; + } + else + { + //da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); + return da2->gdcla[da2->readplane]; + } + } + else { + return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } +} + +static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("da2_mmio_write %x %x\n", addr, val); + if ((addr & ~DA2_MASK_MMIO) != 0xA0000) return; + addr &= DA2_MASK_MMIO; + + if (da2->ioctl[LS_MMIO] & 0x10) { + //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); + //Gaiji RAM + if (da2->fctl[LF_MMIO_SEL] == 0x80) + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);//xxxy yyyy yyyy yyyy yyyy + else + { + uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index <<= 8; + index |= da2->fctl[LF_MMIO_ADDR]; + addr += index * 0x40; + } + switch (da2->fctl[LF_MMIO_MODE]) { + case 0xb0://Gaiji RAM 1011 0000 + addr &= DA2_MASK_GAIJIRAM;//safety access + da2->mmio.ram[addr] = val; + break; + case 0x10://Font ROM 0001 0000 + //Read-Only + break; + case 0x00: + //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + //addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx + //if (addr >= DA2_BLT_MEMSIZE) + //{ + // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + // return; + //} + da2->bitblt.indata = 1; + if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + break; + default: + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + break; + } + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + uint8_t wm = da2->writemask; + //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); +#ifdef ENABLE_DA2_DEBUGBLT + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + { + fprintf(da2->mmdbg_fp, "\nB %x ", addr); + for (int i = 0; i <= 0xb; i++) + fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + } + for (int i = 0; i < 8; i++) + { + int pixeldata = 0; + if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); + fprintf(da2->mmdbg_fp, "%X", pixeldata); + } + da2->mmdbg_vidaddr = addr; + //} +#endif + + cycles -= video_timing_write_b; + + da2->changedvram[addr >> 12] = changeframecount; + addr <<= 3; + + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + + //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); + //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropB(addr, da2); + return; + } + + switch (da2->writemode) + { + case 2: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else da2->gdcinput[i] = val; + + for (int i = 0; i < 8; i++) + da2->debug_vramold[i] = da2->vram[addr | i];//use latch + da2_gdcropB(addr, da2); + //for (int i = 0; i < 8; i++) + // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch + //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); + da2_gdcropB(addr, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + wm = da2->gdcreg[LG_BIT_MASK_LOW]; + da2->gdcreg[LG_BIT_MASK_LOW] &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + da2_gdcropB(addr, da2); + da2->gdcreg[LG_BIT_MASK_LOW] = wm; + break; + } + //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + } + else// mode 3h text + { + cycles -= video_timing_write_b; + da2->vram[addr] = val; + da2->fullchange = 2; + } +} +uint16_t rightRotate(uint16_t data, uint8_t count) +{ + return (data >> count) | (data << (sizeof(data) * 8 - count)); +} +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + uint8_t wm = da2->writemask; + uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + bitmask <<= 8; + bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; +#ifdef ENABLE_DA2_DEBUGBLT + //debug + //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + //{ + if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) + { + fprintf(da2->mmdbg_fp, "\nW %x ", addr); + for (int i = 0; i <= 0xb; i++) + fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + } + for (int i = 0; i < 16; i++) + { + int pixeldata = 0; + if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); + fprintf(da2->mmdbg_fp, "%X", pixeldata); + } + da2->mmdbg_vidaddr = addr; + //} +#endif + cycles -= video_timing_write_w; + //cycles_lost += video_timing_write_w; + + //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); + //da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + + da2->changedvram[addr >> 12] = changeframecount; + da2->changedvram[(addr + 1) >> 12] = changeframecount; + addr <<= 3; + + for (int i = 0; i < 8; i++) + da2->gdcsrc[i] = da2->gdcla[i];//use latch + + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; + else da2->gdcinput[i] = val; + da2_gdcropW(addr, bitmask, da2); + return; + } + //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); + switch (da2->writemode) + { + case 2: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; + da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + } + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work + if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + da2->vram[addr | i] = val & 0xff; + da2->vram[(addr + 8) | i] = val >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else da2->gdcinput[i] = val; + da2_gdcropW(addr, bitmask, da2); + // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) + { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + { + uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + da2->vram[addr | i] = wdata & 0xff; + da2->vram[(addr + 8) | i] = wdata >> 8; + } + } + else + { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); + da2_gdcropW(addr, bitmask, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work + wm = bitmask; + bitmask &= val; + + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + da2_gdcropW(addr, bitmask, da2); + bitmask = wm; + break; + } + //da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); +} +static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0x1ffff) != 0xA0000) return; + if (da2->ioctl[LS_MMIO] & 0x10) { + //da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } + else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + { + addr &= DA2_MASK_MMIO; + //return; + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_gc_writeW(addr, val, da2); + } + else {//mode 3h text + //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_mmio_write(addr, val & 0xff, da2); + da2_mmio_write(addr + 1, val >> 8, da2); + } +} + +static void da2_code_write(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //if ((addr & ~0xfff) != 0xE0000) return; + addr &= DA2_MASK_CRAM; + da2->cram[addr] = val; + da2->fullchange = 2; +} +static void da2_code_writeb(uint32_t addr, uint8_t val, void* p) +{ + da2_t* da2 = (da2_t*)p; + //da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + da2_code_write(addr, val, da2); +} +static void da2_code_writew(uint32_t addr, uint16_t val, void* p) +{ + //da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_write_w; + da2_code_write(addr, val & 0xff, da2); + da2_code_write(addr + 1, val >> 8, da2); +} + +static uint8_t da2_code_read(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return DA2_INVALIDACCESS8; + addr &= DA2_MASK_CRAM; + return da2->cram[addr]; +} +static uint8_t da2_code_readb(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_b; + return da2_code_read(addr, da2); +} +static uint16_t da2_code_readw(uint32_t addr, void* p) +{ + da2_t* da2 = (da2_t*)p; + cycles -= video_timing_read_w; + return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); + //return 0; +} + +void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) +{ + if (wx != xsize || wy != ysize) { + xsize = wx; + ysize = wy; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(32, 0, xsize, ysize); + frames++; + + video_res_x = wx; + video_res_y = wy; + video_bpp = 8; +} + +void da2_poll(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + int x; + + if (!da2->linepos) + { + timer_advance_u64(&da2->timer, da2->dispofftime); + // if (output) printf("Display off %f\n",vidtime); + da2->cgastat |= 1; + da2->linepos = 1; + + if (da2->dispon) + { + da2->hdisp_on = 1; + + da2->ma &= da2->vram_display_mask; + if (da2->firstline == 2000) + { + da2->firstline = da2->displine; + video_wait_for_buffer(); + } + + if (!da2->override) + da2->render(da2); + + if (da2->lastline < da2->displine) + da2->lastline = da2->displine; + } + + //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); + da2->displine++; + //if (da2->interlace) + // da2->displine++; + if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) + { + //da2_log("Vsync off at line %i\n",displine); + da2->cgastat &= ~8; + } + da2->vslines++; + if (da2->displine > 1200) + da2->displine = 0; + // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], + // displine, vc, ma); + } + else + { + // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + timer_advance_u64(&da2->timer, da2->dispontime); + + // if (output) printf("Display on %f\n",vidtime); + if (da2->dispon) + da2->cgastat &= ~1; + da2->hdisp_on = 0; + + da2->linepos = 0; + if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) + da2->con = 0; + if (da2->dispon) + { + if (da2->sc == da2->rowcount) + { + da2->linecountff = 0; + da2->sc = 0; + + da2->maback += (da2->rowoffset << 1);// color = 0x50(80), mono = 0x40(64) + if (da2->interlace) + da2->maback += (da2->rowoffset << 1); + da2->maback &= da2->vram_display_mask; + da2->ma = da2->maback; + } + else + { + da2->sc++; + da2->sc &= 31; + da2->ma = da2->maback; + } + } + + da2->vc++; + da2->vc &= 2047; + + if (da2->vc == da2->dispend) + { + da2->dispon = 0; + //if (da2->crtc[10] & 0x20) da2->cursoron = 0; + //else da2->cursoron = da2->blink & 16; + if (da2->ioctl[LS_MODE] & 1) {//in text mode + if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)//cursor blinking + { + da2->cursoron = (da2->blink | 1) & da2->blinkconf; + } + else + { + da2->cursoron = 0; + } + if (!(da2->blink & (0x10 - 1)))//force redrawing for cursor and blink attribute + da2->fullchange = 2; + } + da2->blink++; + + for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) + { + if (da2->changedvram[x]) + da2->changedvram[x]--; + } + // memset(changedvram,0,2048); del + if (da2->fullchange) + { + da2->fullchange--; + } + } + if (da2->vc == da2->vsyncstart) + { + int wx, wy; + // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); + da2->dispon = 0; + da2->cgastat |= 8; + x = da2->hdisp; + + //if (da2->interlace && !da2->oddeven) da2->lastline++; + //if (da2->interlace && da2->oddeven) da2->firstline--; + + wx = x; + wy = da2->lastline - da2->firstline; + + da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); + + da2->firstline = 2000; + da2->lastline = 0; + + da2->firstline_draw = 2000; + da2->lastline_draw = 0; + + da2->oddeven ^= 1; + + changeframecount = da2->interlace ? 3 : 2; + da2->vslines = 0; + + //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); + //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); + //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; +/* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; + else*/ da2->ma = da2->maback = da2->ma_latch; + da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; + + da2->ma <<= 1; + da2->maback <<= 1; + da2->ca <<= 1; + + // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + } + if (da2->vc == da2->vtotal) + { + // da2_log("VC vtotal\n"); + + + // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); + da2->vc = 0; + da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; + da2->dispon = 1; + da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; + da2->scrollcache = da2->attrc[LV_PANNING] & 7; + } + if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) + da2->con = 1; + } + // printf("2 %i\n",da2_vsyncstart); + //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); + //da2_log("r"); +} + +static void da2_loadfont(char* fname, void* p) { + da2_t* da2 = (da2_t*)p; + uint8_t buf; + //uint32_t code = 0; + uint64_t fsize; + if (!fname) return; + if (*fname == '\0') return; + FILE* mfile = rom_fopen(fname, "rb"); + if (!mfile) { + //da2_log("MSG: Can't open binary ROM font file: %s\n", fname); + return; + } + fseek(mfile, 0, SEEK_END); + fsize = ftell(mfile);//get filesize + fseek(mfile, 0, SEEK_SET); + if (fsize > DA2_FONTROM_SIZE) { + fsize = DA2_FONTROM_SIZE;//truncate read data + //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); + //fclose(mfile); + //return 1; + } + uint32_t j = 0; + while (ftell(mfile) < fsize) { + fread(&buf, sizeof(uint8_t), 1, mfile); + da2->mmio.font[j] = buf; + j++; + } + fclose(mfile); + return; +} + +/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ +static uint8_t ps55_palette_color[64][3] = +{ +{0x00,0x00,0x00},{0x00,0x00,0x2A},{0x00,0x2A,0x00},{0x00,0x2A,0x2A},{0x2A,0x00,0x00},{0x2A,0x00,0x2A},{0x2A,0x2A,0x00},{0x2A,0x2A,0x2A}, +{0x00,0x00,0x15},{0x00,0x00,0x3F},{0x00,0x2A,0x15},{0x00,0x2A,0x3F},{0x2A,0x00,0x15},{0x2A,0x00,0x3F},{0x2A,0x2A,0x15},{0x2A,0x2A,0x3F}, +{0x00,0x15,0x00},{0x00,0x15,0x2A},{0x00,0x3F,0x00},{0x00,0x3F,0x2A},{0x2A,0x15,0x00},{0x2A,0x15,0x2A},{0x2A,0x3F,0x00},{0x2A,0x3F,0x2A}, +{0x00,0x15,0x15},{0x00,0x15,0x3F},{0x00,0x3F,0x15},{0x00,0x3F,0x3F},{0x2A,0x15,0x15},{0x2A,0x15,0x3F},{0x2A,0x3F,0x15},{0x2A,0x3F,0x3F}, +{0x15,0x00,0x00},{0x15,0x00,0x2A},{0x15,0x2A,0x00},{0x15,0x2A,0x2A},{0x3F,0x00,0x00},{0x3F,0x00,0x2A},{0x3F,0x2A,0x00},{0x3F,0x2A,0x2A}, +{0x15,0x00,0x15},{0x15,0x00,0x3F},{0x15,0x2A,0x15},{0x15,0x2A,0x3F},{0x3F,0x00,0x15},{0x3F,0x00,0x3F},{0x3F,0x2A,0x15},{0x3F,0x2A,0x3F}, +{0x15,0x15,0x00},{0x15,0x15,0x2A},{0x15,0x3F,0x00},{0x15,0x3F,0x2A},{0x3F,0x15,0x00},{0x3F,0x15,0x2A},{0x3F,0x3F,0x00},{0x3F,0x3F,0x2A}, +{0x15,0x15,0x15},{0x15,0x15,0x3F},{0x15,0x3F,0x15},{0x15,0x3F,0x3F},{0x3F,0x15,0x15},{0x3F,0x15,0x3F},{0x3F,0x3F,0x15},{0x3F,0x3F,0x3F} +}; + +void da2_reset_ioctl(da2_t* da2) +{ + da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ + da2_outw(LS_INDEX, 0x0302, da2); /* Index 02, Bit 1: VGA passthrough, Bit 0: Character Mode */ + da2_outw(LS_INDEX, 0x0008, da2); /* Index 08, Bit 0: Enable MMIO */ +} + +static void +da2_reset(void* priv) +{ + da2_t* da2 = (da2_t*)priv; + + /* Initialize drawing */ + da2->bitblt.exec = DA2_BLT_CIDLE; + da2->render = da2_render_blank; + da2_reset_ioctl(da2); + + da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ + da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ + da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ + da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ + da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ + da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ + da2->fctl[0] = 0x2b; /* 3E3h:0 */ + da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ + da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ + da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ + da2->ma_latch = 0; + da2->interlace = 0; + da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attr_palette_enable = 0; /* disable attribute generator */ + + /* Set default color palette (Windows 3.1 display driver won't reset palette) */ + da2_out(0x3c8, 0, da2); + for (int i = 0; i < 256; i++) { + da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][1], da2); + da2_out(0x3c9, ps55_palette_color[i & 0x3F][2], da2); + } +} + +static void *da2_init() +{ + //Todo: init regs, gaiji memory, video memory, I/O handlers, font ROM + + if (svga_get_pri() == NULL) + return NULL; + svga_t *mb_vga = svga_get_pri(); + mb_vga->cable_connected = 0; + + da2_t* da2 = malloc(sizeof(da2_t)); + da2->mb_vga = mb_vga; + + da2->dispontime = 1000ull << 32; + da2->dispofftime = 1000ull << 32; + int memsize = 1024 * 1024; + da2->vram = malloc(memsize); + da2->vram_mask = memsize - 1; + da2->cram = malloc(0x1000); + da2->vram_display_mask = DA2_MASK_CRAM; + da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ + + da2->mmio.charset = device_get_config_int("charset"); + da2->mmio.font= malloc(DA2_FONTROM_SIZE); + switch(da2->mmio.charset) + { + case DA2_DCONFIG_CHARSET_HANT: + da2_loadfont(DA2_FONTROM_PATH_HANT, da2); + break; + case DA2_DCONFIG_CHARSET_JPAN: + da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + break; + } + + mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ +#ifdef ENABLE_DA2_DEBUGBLT + da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); + da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); + da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); + da2->bitblt.debug_reg_ip = 0; +#endif + da2->bitblt.payload_addr = 0; + da2_reset(da2); + + mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + //da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); + + mem_mapping_disable(&da2->mmio.mapping); + + mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + + mem_mapping_disable(&da2->cmapping); + + timer_add(&da2->timer, da2_poll, da2, 0); + da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ + timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + + return da2; +} +static int da2_available() +{ + return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); +} + +void da2_close(void *p) +{ + da2_t *da2 = (da2_t *)p; + + /* dump mem for debug */ +#ifndef RELEASE_BUILD + FILE* f; + f = fopen("da2_cram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->cram, 0x1000, 1, f); + fclose(f); + } + f = fopen("da2_vram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vram, 1024*1024, 1, f); + fclose(f); + } + f = fopen("da2_gram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->mmio.ram, 256*1024, 1, f); + fclose(f); + } + f = fopen("da2_attrpal.dmp", "wb"); + if (f != NULL) { + fwrite(da2->attrc, 32, 1, f); + fclose(f); + } + f = fopen("da2_dacrgb.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vgapal, 3*256, 1, f); + fclose(f); + } + f = fopen("da2_daregs.txt", "w"); + if (f != NULL) { + for (int i=0;i<0x10;i++) + fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); + for (int i = 0; i < 0x40; i++) + fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrc[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); + fclose(f); + } +#endif +#ifdef ENABLE_DA2_DEBUGBLT + f = fopen("da2_bltdump.csv", "w"); + if (f != NULL && da2->bitblt.debug_reg_ip > 0) { + /* print header */ + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) + fprintf(f, "\"%02X\"\t", y); + } + fprintf(f, "\n"); + /* print data */ + for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) + ; + else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) + fprintf(f, "\"\"\t"); + else + fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); + } + fprintf(f, "\n"); + } + fclose(f); + } + if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); + if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); + free(da2->bitblt.debug_reg); +#endif + free(da2->cram); + free(da2->vram); + free(da2->changedvram); + free(da2->mmio.font); + free(da2); +} + +void da2_speed_changed(void *p) +{ + da2_t* da2 = (da2_t*)p; + da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + da2_recalctimings(da2); +} + +void da2_force_redraw(void *p) +{ + da2_t* da2 = (da2_t*)p; + + da2->fullchange = changeframecount; +} + +static const device_config_t da2_configuration[] = { + // clang-format off + { + .name = "charset", + .description = "Charset", + .type = CONFIG_SELECTION, + .default_int = DA2_DCONFIG_CHARSET_JPAN, + .selection = { + { + .description = "932 (Japanese)", + .value = DA2_DCONFIG_CHARSET_JPAN + }, + { + .description = "938 (Traditional Chinese)", + .value = DA2_DCONFIG_CHARSET_HANT + }, + { .description = "" } + } + }, + { + .name = "montype", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .default_int = DA2_DCONFIG_MONTYPE_COLOR, + .selection = { + { + .description = "Color", + .value = DA2_DCONFIG_MONTYPE_COLOR + }, + { + .description = "IBM 8515", + .value = DA2_DCONFIG_MONTYPE_8515 + }, + { + .description = "Grayscale", + .value = DA2_DCONFIG_MONTYPE_MONO + }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ps55da2_device = { + .name = "IBM Display Adapter II (MCA)", + .internal_name = "ps55da2", + .flags = DEVICE_MCA, + .local = 0, + .init = da2_init, + .close = da2_close, + .reset = da2_reset, + { .available = da2_available }, + .speed_changed = da2_speed_changed, + .force_redraw = da2_force_redraw, + .config = da2_configuration +}; + +void +da2_device_add(void) +{ + if (!da2_standalone_enabled) + return; + + if (machine_has_bus(machine, MACHINE_BUS_MCA)) + device_add(&ps55da2_device); + else + return; +} From dc7e6c2d7fb2851f06d4a01847870f4fda05e600 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 11:05:16 +0900 Subject: [PATCH 0268/1190] Disabled DA2 debug logging by default --- src/video/vid_ps55da2.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 0ac136630..abbc3de16 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -228,10 +228,11 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 +//#define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG +#define ENABLE_DA2_DEBUGBLT 1 int da2_do_log = ENABLE_DA2_LOG; static void @@ -248,9 +249,6 @@ da2_log(const char* fmt, ...) #else # define da2_log(fmt, ...) #endif -#ifndef RELEASE_BUILD -# define ENABLE_DA2_DEBUGBLT 1 -#endif typedef struct da2_t { @@ -710,31 +708,35 @@ void da2_bitblt_load(da2_t* da2) // da2->bitblt.destpitch += 2; // da2->bitblt.srcpitch += 2; //} - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; +#ifdef ENABLE_DA2_DEBUGBLT + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); +#endif } else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; +#ifdef ENABLE_DA2_DEBUGBLT + uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); +#endif } else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {/* Fill a rectangle(or draw a line) */ da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", @@ -898,15 +900,15 @@ void da2_bitblt_exec(void* p) case DA2_BLT_CPUTCHAR: //da2->bitblt.y += 2; da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; - pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + //pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); //da2->bitblt.srcaddr += 2; if(da2->bitblt.reg[0x12] < 0x100) da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; else da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); - print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); - pclog("\n"); + //print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); + //print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); + //pclog("\n"); if (da2->bitblt.x >= da2->bitblt.size_x - 1) { //if (1) { DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); @@ -3059,7 +3061,7 @@ void da2_close(void *p) da2_t *da2 = (da2_t *)p; /* dump mem for debug */ -#ifndef RELEASE_BUILD +#ifdef ENABLE_DA2_LOG FILE* f; f = fopen("da2_cram.dmp", "wb"); if (f != NULL) { From a850821ecb5a01d73fbcb9e9225b6185a67586e7 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 11:29:44 +0900 Subject: [PATCH 0269/1190] updated comment in monitor detection (vid_svga .c) --- src/video/vid_svga.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index ef6381598..5d0db103b 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -511,10 +511,12 @@ svga_in(uint16_t addr, void *priv) } else { - // The Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). - // When the monitor cable is connected to the Display Adapter, this port returns the value as no cable connection. - // The Power-on Self Test of PS/55 tries detecting the monitor on the planar VGA. - // If it fails, then the POST reads the NVRAM set by the reference diskette, and sets the BIOS Data Area (Mem 487h, 489h). + /* + The IBM PS/55 Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). + When the monitor cable is connected to the Display Adapter, this port returns the value as 'no cable connection'. + The POST of PS/55 has an extra code that tries detecting the monitor on the planar VGA. + If it fails, then the POST reads the NVRAM set by the reference diskette, and updates the BIOS Data Area (Mem 487h, 489h). + */ if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10) ret = 0; else From aa7d5d2dc2c4cd7b58dfdf1d478c176a63f41f0d Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 11:49:26 +0900 Subject: [PATCH 0270/1190] removed unused device decl --- src/floppy/fdc.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 75c2c10af..243df4ca5 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -722,7 +722,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if ((val & 4) && !(fdc->dor & 4)) fdc_soft_reset(fdc); /* We can now simplify this since each motor now spins separately. */ - for (int i = 0; i < FDD_NUM; i++) { + for (i = 0; i < FDD_NUM; i++) { drive_num = real_drive(fdc, i); if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) val &= ~(0x10 << drive_num); @@ -2612,20 +2612,6 @@ const device_t fdc_at_actlow_device = { .config = NULL }; -const device_t fdc_at_ps2_device = { - .name = "PC/AT Floppy Drive Controller (PS/2 internal)", - .internal_name = "fdc_at_ps55", - .flags = 0, - .local = FDC_FLAG_AT | FDC_FLAG_PS2, - .init = fdc_init, - .close = fdc_close, - .reset = fdc_reset, - {.available = NULL }, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - const device_t fdc_at_smc_device = { .name = "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", .internal_name = "fdc_at_smc", From 16fc5e79020a2b65f3126d6a80d8c65dbe7e1aba Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:08:50 +0900 Subject: [PATCH 0271/1190] corrected compile errors, removed garbage --- src/disk/hdc_esdi_mca.c | 2 +- src/floppy/fdc.c | 21 +-------------------- src/machine/m_ps2_mca.c | 6 +++--- src/video/vid_ps55da2.c | 2 +- 4 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 5656181f0..5b471b754 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1514,7 +1514,7 @@ esdi_integrated_device = { .init = esdi_init, .close = esdi_close, .reset = esdi_reset, - {.available = NULL }, + .available = esdi_available, .speed_changed = NULL, .force_redraw = NULL, .config = esdi_integrated_config diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 243df4ca5..1692a7aaa 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -722,7 +722,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if ((val & 4) && !(fdc->dor & 4)) fdc_soft_reset(fdc); /* We can now simplify this since each motor now spins separately. */ - for (i = 0; i < FDD_NUM; i++) { + for (int i = 0; i < FDD_NUM; i++) { drive_num = real_drive(fdc, i); if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) val &= ~(0x10 << drive_num); @@ -1284,25 +1284,6 @@ fdc_read(uint16_t addr, void *priv) if (fdc->fintr || fdc->reset_stat) /* INTR */ ret |= 0x80; } - else if (fdc->flags & FDC_FLAG_PS2) { - /* Status Register A (PS/2, PS/55) */ - /* | INT PEND | nDRV2 | STEP | nTRK0 | HDSEL | nIDX | nWP | DIR | */ - ret = 0x04; - if (!fdc->seek_dir) /* DIRECTION */ - ret |= 0x01; - if (!writeprot[drive]) /* nWRITEPROT */ - ret |= 0x02; - if (fdd_get_head(drive)) /* HDSEL */ - ret |= 0x08; - if (!fdd_track0(drive)) /* nTRK0 */ - ret |= 0x10; - if (fdc->step) /* STEP */ - ret |= 0x20; - if (!fdd_get_type(1)) /* -Drive 2 Installed */ - ret |= 0x40; - if (fdc->fintr || fdc->reset_stat) /* INTR */ - ret |= 0x80; - } else ret = 0xff; break; diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index c355ba4b2..b948c984c 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -780,13 +780,13 @@ ps55_model_50tv_write(uint16_t port, uint8_t val) switch ((val >> 5) & 3) { case 0: - lpt1_init(LPT_MDA_ADDR); + lpt1_setup(LPT_MDA_ADDR); break; case 1: - lpt1_init(LPT1_ADDR); + lpt1_setup(LPT1_ADDR); break; case 2: - lpt1_init(LPT2_ADDR); + lpt1_setup(LPT2_ADDR); break; default: break; diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index abbc3de16..98b827421 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3205,7 +3205,7 @@ const device_t ps55da2_device = { .init = da2_init, .close = da2_close, .reset = da2_reset, - { .available = da2_available }, + .available = da2_available, .speed_changed = da2_speed_changed, .force_redraw = da2_force_redraw, .config = da2_configuration From c6dfd688f4dd8516e611b388fc5c53740deddefd Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 15 Feb 2025 07:09:14 +0100 Subject: [PATCH 0272/1190] Split off the CRC code to its own module. --- src/floppy/fdd_86f.c | 73 +++++++++++++++---------------------- src/include/86box/crc.h | 34 ++++++++++++++++++ src/include/86box/fdd.h | 15 ++------ src/utils/CMakeLists.txt | 1 + src/utils/crc.c | 77 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 57 deletions(-) create mode 100644 src/include/86box/crc.h create mode 100644 src/utils/crc.c diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 140e87899..f5626e35b 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -28,6 +28,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> +#include <86box/crc.h> #include <86box/dma.h> #include <86box/nvr.h> #include <86box/random.h> @@ -223,6 +224,7 @@ typedef struct d86f_t { uint8_t *filebuf; uint8_t *outbuf; sector_t *last_side_sector[2]; + uint16_t crc_table[256]; } d86f_t; static const uint8_t encoded_fm[64] = { @@ -247,7 +249,6 @@ static const uint8_t encoded_mfm[64] = { }; static d86f_t *d86f[FDD_NUM]; -static uint16_t CRCTable[256]; static fdc_t *d86f_fdc; uint64_t poly = 0x42F0E1EBA9EA3693LL; /* ECMA normal */ @@ -276,28 +277,6 @@ d86f_log(const char *fmt, ...) # define d86f_log(fmt, ...) #endif -static void -setup_crc(uint16_t poly) -{ - int c = 256; - int bc; - uint16_t temp; - - while (c--) { - temp = c << 8; - bc = 8; - - while (bc--) { - if (temp & 0x8000) - temp = (temp << 1) ^ poly; - else - temp <<= 1; - - CRCTable[c] = temp; - } - } -} - void d86f_destroy_linked_lists(int drive, int side) { @@ -1237,16 +1216,10 @@ decodefm(UNUSED(int drive), uint16_t dat) return temp; } -void -fdd_calccrc(uint8_t byte, crc_t *crc_var) -{ - crc_var->word = (crc_var->word << 8) ^ CRCTable[(crc_var->word >> 8) ^ byte]; -} - static void d86f_calccrc(d86f_t *dev, uint8_t byte) { - fdd_calccrc(byte, &(dev->calc_crc)); + crc16_calc(dev->crc_table, byte, &(dev->calc_crc)); } int @@ -1274,7 +1247,9 @@ d86f_word_is_aligned(int drive, int side, uint32_t base_pos) /* State 1: Find sector ID */ void -d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, + uint16_t other_am, uint16_t wrong_am, + uint16_t ignore_other_am) { d86f_t *dev = d86f[drive]; @@ -1282,7 +1257,8 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui if (dev->last_word[side] == req_am) { dev->calc_crc.word = 0xFFFF; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; @@ -1302,7 +1278,8 @@ d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, ui if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { dev->calc_crc.word = 0xFFFF; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; if (ignore_other_am & 1) { @@ -1378,7 +1355,8 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; dev->preceding_bit[side] = dev->last_word[side] & 1; @@ -1390,7 +1368,8 @@ d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, u if ((ignore_other_am & 2) && (dev->last_word[side] == other_am) && (find->sync_marks >= 3)) { if (d86f_word_is_aligned(drive, side, find->sync_pos)) { dev->calc_crc.word = 0xCDB4; - fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + crc16_calc(dev->crc_table, decodefm(drive, dev->last_word[side]), + &(dev->calc_crc)); find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; find->sync_pos = 0xFFFFFFFF; if (ignore_other_am & 1) { @@ -1464,8 +1443,11 @@ d86f_read_sector_id(int drive, int side, int match) if (dev->id_find.bytes_obtained < 4) { dev->last_sector.byte_array[dev->id_find.bytes_obtained] = decodefm(drive, dev->last_word[side]); - fdd_calccrc(dev->last_sector.byte_array[dev->id_find.bytes_obtained], &(dev->calc_crc)); - } else if ((dev->id_find.bytes_obtained >= 4) && (dev->id_find.bytes_obtained < 6)) { + crc16_calc(dev->crc_table, + dev->last_sector.byte_array[dev->id_find.bytes_obtained], + &(dev->calc_crc)); + } else if ((dev->id_find.bytes_obtained >= 4) && + (dev->id_find.bytes_obtained < 6)) { dev->track_crc.bytes[(dev->id_find.bytes_obtained & 1) ^ 1] = decodefm(drive, dev->last_word[side]); } @@ -1643,7 +1625,7 @@ d86f_read_sector_data(int drive, int side) } } } - fdd_calccrc(data, &(dev->calc_crc)); + crc16_calc(dev->crc_table, data, &(dev->calc_crc)); } else if (dev->data_find.bytes_obtained < crc_pos) dev->track_crc.bytes[(dev->data_find.bytes_obtained - sector_len) ^ 1] = decodefm(drive, dev->last_word[side]); @@ -1730,11 +1712,12 @@ d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) if (dev->data_find.bytes_obtained < sector_len) { /* This is a data byte, so CRC it. */ - if (!dev->data_find.bytes_obtained) { - fdd_calccrc(decodefm(drive, am), &(dev->calc_crc)); - } else { - fdd_calccrc(dev->current_byte[side], &(dev->calc_crc)); - } + if (!dev->data_find.bytes_obtained) + crc16_calc(dev->crc_table, decodefm(drive, am), + &(dev->calc_crc)); + else + crc16_calc(dev->crc_table, dev->current_byte[side], + &(dev->calc_crc)); } } } else { @@ -3861,8 +3844,6 @@ d86f_load(int drive, char *fn) void d86f_init(void) { - setup_crc(0x1021); - for (uint8_t i = 0; i < FDD_NUM; i++) d86f[i] = NULL; } @@ -3926,6 +3907,8 @@ d86f_setup(int drive) dev->last_side_sector[0] = NULL; dev->last_side_sector[1] = NULL; + crc16_setup(dev->crc_table, 0x1021); + /* Set the drive as active. */ d86f[drive] = dev; } diff --git a/src/include/86box/crc.h b/src/include/86box/crc.h new file mode 100644 index 000000000..1a6e76dab --- /dev/null +++ b/src/include/86box/crc.h @@ -0,0 +1,34 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the CRC code. + * + * Authors: Miran Grca, + * + * Copyright 2016-2025 Miran Grca. + */ +#ifndef EMU_CRC_H +#define EMU_CRC_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef union { + uint16_t word; + uint8_t bytes[2]; +} crc_t; + +extern void crc16_setup(uint16_t *crc_table, uint16_t poly); +extern void crc16_calc(uint16_t *crc_table, uint8_t byte, crc_t *crc_var); + +#ifdef __cplusplus +} +#endif + +#endif /*EMU_CRC_H*/ diff --git a/src/include/86box/fdd.h b/src/include/86box/fdd.h index ff9315f1d..d6ade3bc6 100644 --- a/src/include/86box/fdd.h +++ b/src/include/86box/fdd.h @@ -8,15 +8,13 @@ * * Definitions for the floppy drive emulation. * - * - * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2025 Sarah Walker. + * Copyright 2016-2025 Miran Grca. + * Copyright 2018-2025 Fred N. van Kempen. */ #ifndef EMU_FDD_H #define EMU_FDD_H @@ -129,13 +127,6 @@ extern int drive_empty[FDD_NUM]; #define SECTOR_FIRST -2 #define SECTOR_NEXT -1 -typedef union { - uint16_t word; - uint8_t bytes[2]; -} crc_t; - -void fdd_calccrc(uint8_t byte, crc_t *crc_var); - typedef struct d86f_handler_t { uint16_t (*disk_flags)(int drive); uint16_t (*side_flags)(int drive); diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 1d4b1f73e..2ffe41f7b 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(utils OBJECT cJSON.c + crc.c fifo.c fifo8.c ini.c diff --git a/src/utils/crc.c b/src/utils/crc.c new file mode 100644 index 000000000..096a94c72 --- /dev/null +++ b/src/utils/crc.c @@ -0,0 +1,77 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CRC implementation. + * + * Authors: Miran Grca, + * + * Copyright 2016-2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/dma.h> +#include <86box/nvr.h> +#include <86box/random.h> +#include <86box/plat.h> +#include <86box/ui.h> +#include <86box/crc.h> + +#ifdef ENABLE_CRC_LOG +int d86f_do_log = ENABLE_CRC_LOG; + +static void +crc_log(const char *fmt, ...) +{ + va_list ap; + + if (crc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define crc_log(fmt, ...) +#endif + +void +crc16_setup(uint16_t *crc_table, uint16_t poly) +{ + int c = 256; + int bc; + uint16_t temp; + + while (c--) { + temp = c << 8; + bc = 8; + + while (bc--) { + if (temp & 0x8000) + temp = (temp << 1) ^ poly; + else + temp <<= 1; + + crc_table[c] = temp; + } + } +} + +void +crc16_calc(uint16_t *crc_table, uint8_t byte, crc_t *crc_var) +{ + crc_var->word = (crc_var->word << 8) ^ + crc_table[(crc_var->word >> 8) ^ byte]; +} From db056e0b66ee0262c8db06aada25b39829a98720 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 16:44:07 +0900 Subject: [PATCH 0273/1190] fixed a floppy drive access issue It took a few hours that I noticed fdc.c decides the floppy drive type by the machine name. --- src/floppy/fdc.c | 10 ++++------ src/floppy/fdd.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 1692a7aaa..7f025df2d 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -743,7 +743,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) /* Bit 2: FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. If it fails, then floppy drives will be treated as DD drives. */ - if (fdc->flags & FDC_FLAG_PS2) { + if (fdc->flags & FDC_FLAG_PS2_MCA) { if (val & 0x04) { fdc->tfifo = 8; @@ -769,6 +769,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 5: /*Command register*/ if (fdc->fifointest) { + /* Write FIFO buffer in the test mode (PS/55) */ fdc_log("FIFO buffer position = %X\n", ((fifo_t *)fdc->fifo_p)->end); fifo_write(val, fdc->fifo_p); if (fifo_get_full(fdc->fifo_p)) @@ -1358,10 +1359,7 @@ fdc_read(uint16_t addr, void *priv) ret = 0x10; else ret = 0x00; - } - else if (fdc->flags & FDC_FLAG_PS2) { - /* error when ret = 1, 2*/ - ret = (fdc->fifointest) ? 4 : 0; + /* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */ } else if (!fdc->enh_mode) ret = 0x20; @@ -1374,6 +1372,7 @@ fdc_read(uint16_t addr, void *priv) case 5: /*Data*/ if (fdc->fifointest) { + /* Read FIFO buffer in the test mode (PS/55) */ ret = fifo_read(fdc->fifo_p); break; } @@ -1698,7 +1697,6 @@ fdc_callback(void *priv) else if (fdc->params[5] == 0) fdc->sector++; ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); - //fdc_log("cb_rwsect: %d %d %d %d %d %xh\n", real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); switch (fdc->interrupt) { case 5: case 9: diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index f0a32df75..d3d513b9f 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -294,7 +294,7 @@ fdd_type_invert_densel(int type) int ret; if (drive_types[type].flags & FLAG_PS2) - ret = (!!strstr(machine_getname(), "PS/1")) || (!!strstr(machine_getname(), "PS/2")); + ret = (!!strstr(machine_getname(), "PS/1")) || (!!strstr(machine_getname(), "PS/2")) || (!!strstr(machine_getname(), "PS/55")); else ret = drive_types[type].flags & FLAG_INVERT_DENSEL; From 75ccfc6e2dfccde089a8b47476c24fcc6f94eb0b Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 16:58:11 +0900 Subject: [PATCH 0274/1190] Integrated ESDI doesn't need an external ROM --- src/disk/hdc.c | 2 +- src/disk/hdc_esdi_mca.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 3ec6358d8..f09a9a430 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -77,7 +77,7 @@ static const struct { { &xtide_acculogic_device }, { &xtide_device }, { &esdi_ps2_device }, - { &esdi_integrated_device }, + { &esdi_integrated_device }, { &ide_pci_device }, { &ide_pci_2ch_device }, { &ide_vlb_device }, diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 5b471b754..df2a26349 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1514,7 +1514,7 @@ esdi_integrated_device = { .init = esdi_init, .close = esdi_close, .reset = esdi_reset, - .available = esdi_available, + .available = NULL, /* The Disk BIOS is included in the System ROM */ .speed_changed = NULL, .force_redraw = NULL, .config = esdi_integrated_config From 3a09622a91c6b25d7f10425f731a07926873cdb9 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:36:00 +0900 Subject: [PATCH 0275/1190] added switching ca keys by kbd scancode set --- src/86box.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/86box.c b/src/86box.c index 764f707ba..1cd0ffec8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1094,14 +1094,24 @@ pc_init_modules(void) void pc_send_ca(uint16_t sc) { - /* Use R-Alt because PS/55 DOS assigns L-Alt as Kanji */ - keyboard_input(1, 0x1D); /* Ctrl key pressed */ - keyboard_input(1, 0x138); /* R-Alt key pressed */ - keyboard_input(1, sc); - usleep(50000); - keyboard_input(0, sc); - keyboard_input(0, 0x138); /* R-Alt key released */ - keyboard_input(0, 0x1D); /* Ctrl key released */ + if (keyboard_mode == 0x8A) { + /* Use R-Alt because PS/55 DOS assigns L-Alt Kanji */ + keyboard_input(1, 0x1D); /* Ctrl key pressed */ + keyboard_input(1, 0x138); /* R-Alt key pressed */ + keyboard_input(1, sc); + usleep(50000); + keyboard_input(0, sc); + keyboard_input(0, 0x138); /* R-Alt key released */ + keyboard_input(0, 0x1D); /* Ctrl key released */ + } else { + keyboard_input(1, 0x1D); /* Ctrl key pressed */ + keyboard_input(1, 0x38); /* Alt key pressed */ + keyboard_input(1, sc); + usleep(50000); + keyboard_input(0, sc); + keyboard_input(0, 0x38); /* Alt key released */ + keyboard_input(0, 0x1D); /* Ctrl key released */ + } } /* Send the machine a Control-Alt-DEL sequence. */ From dbeaa2a56b122d175202721ba8efd8cea3a6212e Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:38:24 +0900 Subject: [PATCH 0276/1190] minor update in comparison table --- src/device/keyboard_at.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index b78fbd653..5c66029ad 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1648,14 +1648,14 @@ static const scancode scancode_set3[512] = { Currently, scancode set 81h and 82h are not implemented yet. Also, the key layout is designed to match with the Japanese keyboard. - [Japanese DOS and keyboard scancode set] - | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | PC DOS 5 | + [Japanese DOS and keyboard scancode set comparison] + | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | DOS 5(US)| |---------------------------|:----:|:----:|:----:|:------:|:------:|:---------:|:--------:| | IBM 101-key | n/a | n/a | n/a | n/a | 2 | n/a | 2 | - | IBM-J 5576-00x (obsolete) | 8A | 8A | 8A | 82 | 82 | 82 | 2 | - | OADG (modern JA standard) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | */ + | IBM-J 5576-00x (obsolete) | 8Ah | 8Ah | 8Ah | 82h | 82h | 82h | 2 | + | OADG (modern Japanese) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | */ -/* Scancode set 8Ah : 5556 keyboard compatible scancode set used by J-DOS */ +/* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */ static scancode scancode_set8a[512] = { // clang-format off From 1c7a8e5bbba516fc50b4c91f81fde3521bad3994 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 18:32:12 +0900 Subject: [PATCH 0277/1190] updated comments, modified format --- src/video/vid_ps55da2.c | 336 ++++++++++++++++++++-------------------- 1 file changed, 170 insertions(+), 166 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 98b827421..5098fa64d 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -6,11 +6,11 @@ * * This file is part of the 86Box distribution. * - * IBM PS/55 Display Adapter II emulation. + * IBM PS/55 Display Adapter II (and its successors) emulation. * * Authors: Akamaki. * - * Copyright 2024 Akamaki. + * Copyright 2024-2025 Akamaki. */ #include @@ -58,6 +58,8 @@ #define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ //#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ //#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ +/* These ROMs are currently not found. + At least, IBM-J released a Korean and PRC version of PS/55 for each market. */ #define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ #define DA2_DCONFIG_MONTYPE_COLOR 0x0A #define DA2_DCONFIG_MONTYPE_8515 0x0B @@ -108,21 +110,23 @@ #define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ //#define Mon_ID3 0x10 #define FontCard 0x08 /* ? */ -/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode is not supported). */ #define Page_One 0x06 /* 80000h 110b */ #define Page_Two 0x05 /* 100000h 101b */ #define Page_Four 0x03 /* 200000h 011b */ +/* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode unsupported). */ /* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ #define AddPage 0x08 /* ? */ //#define Mon_ID2 0x04 //#define Mon_ID1 0x02 //#define Mon_ID0 0x01 -/* Monitor ID (imported from OS/2 DDK 1.2) */ -//#define StarbuckC 0x0A //1 010b IBM 8514, 9518 color 1040x768 -//#define StarbuckM 0x09 //1 001b IBM 8507, 8604 grayscale -//#define Lark_B 0x02 //0 010b IBM 9517 color 1040x768 but 4bpp -//#define Dallas 0x0B //1 011b IBM 8515, 9515 color 1040x740 palette B + +/* Monitor ID (imported from OS/2 DDK 1.2) +#define StarbuckC 0x0A // 1 010b IBM 8514, 9518 color 1040x768 +#define StarbuckM 0x09 // 1 001b IBM 8507, 8604 grayscale +#define Lark_B 0x02 // 0 010b IBM 9517 color 1040x768 but 4bpp +#define Dallas 0x0B // 1 011b IBM 8515, 9515 color 1040x740 another palette +*/ /* DA2 Registers (imported from OS/2 DDK) */ #define AC_REG 0x3EE @@ -467,9 +471,9 @@ void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) { pixel32 srcpx; - //fill data with input color + /* fill data with input color */ for (int i = 0; i < 8; i++) - srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;//read in word + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;/* read in word */ DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } @@ -494,7 +498,6 @@ Param Desc 2B Tile Addr 33 Size W 35 Size H - */ void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) { @@ -505,7 +508,7 @@ void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24);//read in word + | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24); DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } @@ -520,7 +523,7 @@ void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) - | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0);//read in word + | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0); DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } @@ -666,8 +669,8 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.debug_reg_ip++; if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; #endif - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);//set bit shift - da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;//01 AND, 03 XOR + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);/* set bit shift */ + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;/* 01 AND, 03 XOR */ da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); for (int i = 0; i <= 0xb; i++) da2_log("%02x ", da2->gdcreg[i]); @@ -678,7 +681,7 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.size_y = da2->bitblt.reg[0x35]; da2->bitblt.destpitch = da2->bitblt.reg[0x21]; da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; - if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ { da2->bitblt.destaddr -= 2; da2->bitblt.size_x += 1; @@ -693,7 +696,7 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.exec = DA2_BLT_CDONE; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - if (da2->bitblt.reg[0x2f] < 0x80)//MS Paint 3.1 will cause hang up in 256 color mode + if (da2->bitblt.reg[0x2f] < 0x80) /* MS Paint 3.1 will cause hang up in 256 color mode */ { da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); da2->bitblt.exec = DA2_BLT_CDONE; @@ -701,7 +704,7 @@ void da2_bitblt_load(da2_t* da2) else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ da2->bitblt.exec = DA2_BLT_CPUTCHAR; /* Todo: addressing */ - //if (da2->bitblt.reg[0x2F] == 0x90) //destaddr -= 2, length += 1; + //if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ //{ // da2->bitblt.destaddr += 2; // da2->bitblt.size_x -= 1; @@ -738,14 +741,16 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #endif } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) {/* Fill a rectangle(or draw a line) */ + /* Fill a rectangle(or draw a line) */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); da2->bitblt.exec = DA2_BLT_CFILLRECT; da2->bitblt.destaddr += 2; } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ + /* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) { da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; @@ -756,7 +761,8 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) {/* Tiling a rectangle (transfer tile data multiple times) */ + /* Tiling a rectangle (transfer tile data multiple times) */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) { da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; @@ -767,7 +773,8 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) {/* Block transfer (range copy) */ + /* Block transfer (range copy) */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { da2->bitblt.exec = DA2_BLT_CCOPYF; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr += 2; @@ -777,7 +784,8 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) {/* Block copy but reversed direction */ + /* Block copy but reversed direction */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) { da2->bitblt.exec = DA2_BLT_CCOPYR; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr -= 2; @@ -1245,7 +1253,7 @@ uint16_t da2_in(uint16_t addr, void *p) temp = da2->ioctladdr; break; case LS_DATA: - //da2->ioctl[3] = 0x80;//3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) + //da2->ioctl[3] = 0x80; /* 3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) */ if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ @@ -1304,7 +1312,7 @@ uint16_t da2_in(uint16_t addr, void *p) temp = da2->attraddr | da2->attr_palette_enable; break; case 0x3E9: - if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this may equiv to 3ba / 3da Input Status Register 1 */ + if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this maybe equivalent to 3ba / 3da Input Status Register 1 */ { if (da2->cgastat & 0x01) da2->cgastat &= ~0x30; @@ -1587,23 +1595,23 @@ The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { da2_t* da2 = (da2_t*)p; uint32_t font = 0; - int32_t fline = line - 2;//Start line of drawing character (line >= 1 AND line < 24 + 1 ) - if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) + int32_t fline = line - 2;/* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ + if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) */ if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { - font = da2->mmio.font[code * 72 + fline * 3]; //1111 1111 - font <<= 8; //1111 1111 0000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; //1111 1111 2222 0000 - font >>= 1; //0111 1111 1222 2000 - font <<= 4; //0111 1111 1222 2000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; //0111 1111 1222 2000 2222 - font <<= 8; //0111 1111 1222 2000 2222 0000 0000 - font |= da2->mmio.font[code * 72 + fline * 3 + 2]; //0111 1111 1222 2000 2222 3333 3333 - font <<= 4; //0111 1111 1222 2000 2222 3333 3333 0000 - //font >>= 1;//put blank at column 1 (and 26) + font = da2->mmio.font[code * 72 + fline * 3]; /* 1111 1111 */ + font <<= 8; /* 1111 1111 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; /* 1111 1111 2222 0000 */ + font >>= 1; /* 0111 1111 1222 2000 */ + font <<= 4; /* 0111 1111 1222 2000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; /* 0111 1111 1222 2000 2222 */ + font <<= 8; /* 0111 1111 1222 2000 2222 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; /* 0111 1111 1222 2000 2222 3333 3333 */ + font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ + /* font >>= 1;//put blank at column 1 (and 26) */ } else if (code >= 0xb000 && code <= 0xb75f) { - //convert code->address in gaiji memory + /* convert code->address in gaiji memory */ code -= 0xb000; code *= 0x80; //code += 0xf800; @@ -1631,11 +1639,11 @@ uint8_t IRGBtoBGRI(uint8_t attr) /* Get the foreground color from the attribute byte */ uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) { - uint8_t foreground = ~attr & 0x08;// 0000 1000 - foreground <<= 2; //0010 0000 - foreground |= ~attr & 0xc0;// 1110 0000 - foreground >>= 4;//0000 1110 - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;//bright color palette + uint8_t foreground = ~attr & 0x08;// 0000 1000 */ + foreground <<= 2; /* 0010 0000 */ + foreground |= ~attr & 0xc0;/* 1110 0000 */ + foreground >>= 4;/* 0000 1110 */ + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;/* bright color palette */ return foreground; } @@ -1675,104 +1683,104 @@ static void da2_render_text(da2_t* da2) chr = da2->cram[(da2->ma) & da2->vram_display_mask]; attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)//IO 3E8h, Index 1Dh - {//--Parse attribute byte in color mode-- - bg = 0;//bg color is always black (the only way to change background color is programming PAL) + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)/* IO 3E8h, Index 1Dh */ + {/* --Parse attribute byte in color mode-- */ + bg = 0;/* bg color is always black (the only way to change background color is programming PAL) */ fg = getPS55ForeColor(attr, da2); - if (attr & 0x04) {//reverse 0000 0100 + if (attr & 0x04) {/* reverse 0000 0100 */ bg = fg; fg = 0; } } else - {//--Parse attribute byte in monochrome mode-- - if (attr & 0x08) fg = 3;//Highlight 0000 1000 + {/* --Parse attribute byte in monochrome mode-- */ + if (attr & 0x08) fg = 3;/* Highlight 0000 1000 */ else fg = 2; - bg = 0;//Background is always color #0 (default is black) - if (!(~attr & 0xCC))//Invisible 11xx 11xx -> 00xx 00xx + bg = 0;/* Background is always color #0 (default is black) */ + if (!(~attr & 0xCC))/* Invisible 11xx 11xx -> 00xx 00xx */ { fg = bg; - attr &= 0x33;//disable blinkking, underscore, highlight and reverse + attr &= 0x33;/* disable blinkking, underscore, highlight and reverse */ } - if (attr & 0x04) {//reverse 0000 0100 + if (attr & 0x04) {/* reverse 0000 0100 */ bg = fg; fg = 0; } - // Blinking 1000 0000 + /* Blinking 1000 0000 */ fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); } - //Draw character - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank - // SBCS or DBCS left half + /* Draw character */ + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];/* draw blank */ + /* SBCS or DBCS left half */ if (chr_wide == 0) { if (attr & 0x01) chr_wide = 1; //chr_wide = 0; - // Stay drawing If the char code is DBCS and not at last column. + /* Stay drawing If the char code is DBCS and not at last column. */ if (chr_wide) { - //Get high DBCS code from the next video address + /* Get high DBCS code from the next video address */ chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; chr_dbcs <<= 8; chr_dbcs |= chr; - // Get the font pattern + /* Get the font pattern */ uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots + /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; font <<= 1; } } else { - // the char code is SBCS (ANK) + /* the char code is SBCS (ANK) */ uint32_t fontbase; - if (attr & 0x02)//second map of SBCS font + if (attr & 0x02)/* second map of SBCS font */ fontbase = DA2_GAIJIRAM_SBEX; else fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];/* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];/* w13xh29 font */ //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); - // Draw 13 dots + /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; font <<= 1; } } } - // right half of DBCS + /* right half of DBCS */ else { uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots + /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; font <<= 1; } chr_wide = 0; } - //Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. - if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {//Underscore only in monochrome mode + /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ + if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {/* Underscore only in monochrome mode */ for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[fg]];//under line (white) + p[n] = da2->pallook[da2->egapal[fg]];/* under line (white) */ } - //Column 1 (Vertical Line) + /* Column 1 (Vertical Line) */ if (attr & 0x10) { - p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//vertical line (white) + p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];/* vertical line (white) */ } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {//HGrid + if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {/* HGrid */ for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];//horizontal line (white) + p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];/* horizontal line (white) */ } - //Drawing text cursor + /* Drawing text cursor */ drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); - int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;//Choose color 2 if mode 8 + int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;/* Choose color 2 if mode 8 */ fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); bg = 0; - if (attr & 0x04) {//Color 0 if reverse + if (attr & 0x04) {/* Color 0 if reverse */ bg = fg; fg = 0; } @@ -1820,32 +1828,32 @@ static void da2_render_textm3(da2_t* da2) fg = attr & 0xf; fg = IRGBtoBGRI(fg); bg = IRGBtoBGRI(bg); - //Draw character - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];//draw blank - // SBCS or DBCS left half + /* Draw character */ + for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];/* draw blank */ + /* BCS or DBCS left half */ if (chr_wide == 0) { if (extattr & 0x01) chr_wide = 1; - // Stay drawing if the char code is DBCS and not at last column. + /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { - //Get high DBCS code from the next video address + /* Get high DBCS code from the next video address */ chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; chr_dbcs <<= 8; chr_dbcs |= chr; - // Get the font pattern + /* Get the font pattern */ uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots + /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; font <<= 1; } } else { - // the char code is SBCS (ANK) + /* the char code is SBCS (ANK) */ uint32_t fontbase; fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];// w13xh29 font + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];/* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];// w13xh29 font + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];/* w13xh29 font */ //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -1853,26 +1861,25 @@ static void da2_render_textm3(da2_t* da2) } } } - // right half of DBCS + /* right half of DBCS */ else { uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); - // Draw 13 dots + /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; font <<= 1; } chr_wide = 0; } - //Drawing text cursor drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); - //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;//Choose color 2 if mode 8 + //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ //fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; //bg = 0; - //if (attr & 0x04) {//Color 0 if reverse + //if (attr & 0x04) {/* Color 0 if reverse */ // bg = fg; // fg = 0; //} @@ -1891,7 +1898,7 @@ void da2_render_color_4bpp(da2_t* da2) { int changed_offset = da2->ma >> 12; //da2_log("ma %x cf %x\n", da2->ma, changed_offset); - da2->plane_mask &= 0x0f;//safety + da2->plane_mask &= 0x0f; /*safety */ if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { @@ -1904,12 +1911,12 @@ void da2_render_color_4bpp(da2_t* da2) da2->lastline_draw = da2->displine; //da2_log("d %X\n", da2->ma); - for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + for (x = 0; x <= da2->hdisp; x += 8)/* hdisp = 1024 */ { uint8_t edat[8]; uint8_t dat; - //get 8 pixels from vram + /* get 8 pixels from vram */ da2->ma &= da2->vram_display_mask; *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); da2->ma += 1; @@ -1952,7 +1959,7 @@ void da2_render_color_8bpp(da2_t* da2) da2->lastline_draw = da2->displine; //da2_log("d %X\n", da2->ma); - for (x = 0; x <= da2->hdisp; x += 8)//hdisp = 1024 + for (x = 0; x <= da2->hdisp; x += 8) /* hdisp = 1024 */ { uint8_t edat[8]; uint8_t dat; @@ -2037,7 +2044,7 @@ void da2_recalctimings(da2_t* da2) da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; da2->htotal += 1; - da2->rowoffset = da2->crtc[LC_OFFSET];//number of bytes in a scanline + da2->rowoffset = da2->crtc[LC_OFFSET];/* number of bytes in a scanline */ da2->clock = da2->da2const; @@ -2052,11 +2059,12 @@ void da2_recalctimings(da2_t* da2) da2->hdisp_time = da2->hdisp; da2->render = da2_render_blank; - //determine display mode + /* determine display mode */ //if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) if (da2->attrc[LV_COMPATIBILITY] & 0x08) { - if (!(da2->ioctl[LS_MODE] & 0x01)) {//16 color graphics mode + /* 16 color graphics mode */ + if (!(da2->ioctl[LS_MODE] & 0x01)) { da2->hdisp *= 16; da2->char_width = 13; da2->hdisp_old = da2->hdisp; @@ -2065,19 +2073,21 @@ void da2_recalctimings(da2_t* da2) da2->render = da2_render_color_8bpp; da2->vram_display_mask = DA2_MASK_GRAM; } - else {//PS/55 8-color + else {/* PS/55 8-color */ da2_log("Set videomode to PS/55 4 bpp graphics.\n"); da2->vram_display_mask = DA2_MASK_GRAM; da2->render = da2_render_color_4bpp; } } - else {//text mode + else { + /* text mode */ if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { da2_log("Set videomode to PS/55 Mode 03 text.\n"); da2->render = da2_render_textm3; da2->vram_display_mask = DA2_MASK_CRAM; } - else {//PS/55 text(color/mono) + /* PS/55 text(color/mono) */ + else { da2_log("Set videomode to PS/55 Mode 8/E text.\n"); da2->render = da2_render_text; da2->vram_display_mask = DA2_MASK_CRAM; @@ -2096,7 +2106,7 @@ void da2_recalctimings(da2_t* da2) //da2->render = da2_draw_text; //} - // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + //da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); //if (da2->recalctimings_ex) // da2->recalctimings_ex(da2); @@ -2122,10 +2132,10 @@ void da2_recalctimings(da2_t* da2) if (da2->dispofftime < TIMER_USEC) da2->dispofftime = TIMER_USEC; da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); - // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); - // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + //da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + //da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); - // da2_log("da2->render %08X\n", da2->render); + //da2_log("da2->render %08X\n", da2->render); } uint8_t da2_mca_read(int port, void *p) @@ -2189,7 +2199,7 @@ static void da2_mca_reset(void *p) da2_reset(da2); da2_mca_write(0x102, 0, da2); } -// + static void da2_gdcropB(uint32_t addr, da2_t* da2) { for (int i = 0; i < 8; i++) { if (da2->writemask & (1 << i)) { @@ -2265,11 +2275,11 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) if (da2->ioctl[LS_MMIO] & 0x10) { if (da2->fctl[LF_MMIO_SEL] == 0x80) - //linear access + /* linear access */ addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); else { - //64k bank switch access + /* 64k bank switch access */ uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; @@ -2277,12 +2287,12 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) } //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { - case 0xb0://Gaiji RAM - addr &= DA2_MASK_GAIJIRAM;//safety access + case 0xb0:/* Gaiji RAM */ + addr &= DA2_MASK_GAIJIRAM;/* safety access */ //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); return da2->mmio.ram[addr]; break; - case 0x10://Font ROM + case 0x10:/* Font ROM */ if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, @@ -2293,29 +2303,29 @@ static uint8_t da2_mmio_read(uint32_t addr, void* p) return da2->mmio.font[addr]; break; default: - return DA2_INVALIDACCESS8;//invalid memory access + return DA2_INVALIDACCESS8;/* invalid memory access */ break; } } - else if (!(da2->ioctl[LS_MODE] & 1))//8 or 256 color mode + else if (!(da2->ioctl[LS_MODE] & 1))/* 8 or 256 color mode */ { cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) - da2->gdcla[i] = da2->vram[(addr << 3) | i];//read in byte + da2->gdcla[i] = da2->vram[(addr << 3) | i];/* read in byte */ //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); - if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + if (da2->gdcreg[LG_MODE] & 0x08) {/* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint8_t ret = 0; for (int i = 0; i < 8; i++) { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))/* color don't care register */ ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); } return ~ret; } else return da2->gdcla[da2->readplane]; } - else //text mode 3 + else /* text mode 3 */ { cycles -= video_timing_read_b; return da2->vram[addr]; @@ -2328,12 +2338,12 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ { cycles -= video_timing_read_w; addr &= DA2_MASK_MMIO; for (int i = 0; i < 8; i++) - da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);//read vram into latch + da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);/* read vram into latch */ #ifdef ENABLE_DA2_DEBUGBLT ////debug @@ -2352,12 +2362,12 @@ static uint16_t da2_mmio_readw(uint32_t addr, void* p) //da2->mmrdbg_vidaddr = addr; #endif - if (da2->gdcreg[LG_MODE] & 0x08) {//compare data across planes if the read mode bit (3EB 05, bit 3) is 1 + if (da2->gdcreg[LG_MODE] & 0x08) {/* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint16_t ret = 0; for (int i = 0; i < 8; i++) { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))//color don't care register + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))/* color don't care register */ ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); } return ~ret; @@ -2382,9 +2392,9 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) if (da2->ioctl[LS_MMIO] & 0x10) { //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); - //Gaiji RAM + /* Gaiji RAM */ if (da2->fctl[LF_MMIO_SEL] == 0x80) - addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);//xxxy yyyy yyyy yyyy yyyy + addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);/* xxxy yyyy yyyy yyyy yyyy */ else { uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; @@ -2393,16 +2403,16 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) addr += index * 0x40; } switch (da2->fctl[LF_MMIO_MODE]) { - case 0xb0://Gaiji RAM 1011 0000 - addr &= DA2_MASK_GAIJIRAM;//safety access + case 0xb0:/* Gaiji RAM 1011 0000 */ + addr &= DA2_MASK_GAIJIRAM;/* safety access */ da2->mmio.ram[addr] = val; break; - case 0x10://Font ROM 0001 0000 - //Read-Only + case 0x10:/* Font ROM 0001 0000 */ + /* Read-Only */ break; case 0x00: //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - //addr &= 0x7f;//OS/2 write addr 1cf80-1cfc3, val xx + //addr &= 0x7f;/* OS/2 write addr 1cf80-1cfc3, val xx */ //if (addr >= DA2_BLT_MEMSIZE) //{ // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); @@ -2419,12 +2429,11 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) break; } } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ { uint8_t wm = da2->writemask; //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); #ifdef ENABLE_DA2_DEBUGBLT - //debug //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) @@ -2449,7 +2458,7 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) addr <<= 3; for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch + da2->gdcsrc[i] = da2->gdcla[i];/* use latch */ //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); @@ -2485,11 +2494,11 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) else da2->gdcinput[i] = val; for (int i = 0; i < 8; i++) - da2->debug_vramold[i] = da2->vram[addr | i];//use latch + da2->debug_vramold[i] = da2->vram[addr | i];/* use latch */ da2_gdcropB(addr, da2); //for (int i = 0; i < 8; i++) // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch - //// da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + ////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; case 1: @@ -2519,7 +2528,7 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) } //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); } - else// mode 3h text + else/* mode 3h text */ { cycles -= video_timing_write_b; da2->vram[addr] = val; @@ -2538,7 +2547,6 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) bitmask <<= 8; bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGBLT - //debug //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) @@ -2567,7 +2575,7 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) addr <<= 3; for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];//use latch + da2->gdcsrc[i] = da2->gdcla[i];/* use latch */ if (!(da2->gdcreg[LG_COMMAND] & 0x08)) { @@ -2608,7 +2616,7 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; else da2->gdcinput[i] = val; da2_gdcropW(addr, bitmask, da2); - // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + //da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; case 1: @@ -2653,14 +2661,14 @@ static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } - else if (!(da2->ioctl[LS_MODE] & 1))//8 color or 256 color mode + else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ { addr &= DA2_MASK_MMIO; //return; //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_gc_writeW(addr, val, da2); } - else {//mode 3h text + else {/* mode 3h text */ //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); @@ -2739,7 +2747,7 @@ void da2_poll(void* priv) if (!da2->linepos) { timer_advance_u64(&da2->timer, da2->dispofftime); - // if (output) printf("Display off %f\n",vidtime); + //if (output) printf("Display off %f\n",vidtime); da2->cgastat |= 1; da2->linepos = 1; @@ -2767,21 +2775,21 @@ void da2_poll(void* priv) // da2->displine++; if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) { - //da2_log("Vsync off at line %i\n",displine); + //da2_log("Vsync off at line %i\n",displine); da2->cgastat &= ~8; } da2->vslines++; if (da2->displine > 1200) da2->displine = 0; - // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], - // displine, vc, ma); + //da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], + //displine, vc, ma); } else { - // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + //da2_log("VC %i ma %05X\n", da2->vc, da2->ma); timer_advance_u64(&da2->timer, da2->dispontime); - // if (output) printf("Display on %f\n",vidtime); + //if (output) printf("Display on %f\n",vidtime); if (da2->dispon) da2->cgastat &= ~1; da2->hdisp_on = 0; @@ -2796,7 +2804,7 @@ void da2_poll(void* priv) da2->linecountff = 0; da2->sc = 0; - da2->maback += (da2->rowoffset << 1);// color = 0x50(80), mono = 0x40(64) + da2->maback += (da2->rowoffset << 1);/* color = 0x50(80), mono = 0x40(64) */ if (da2->interlace) da2->maback += (da2->rowoffset << 1); da2->maback &= da2->vram_display_mask; @@ -2817,9 +2825,9 @@ void da2_poll(void* priv) { da2->dispon = 0; //if (da2->crtc[10] & 0x20) da2->cursoron = 0; - //else da2->cursoron = da2->blink & 16; - if (da2->ioctl[LS_MODE] & 1) {//in text mode - if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)//cursor blinking + //else da2->cursoron = da2->blink & 16; + if (da2->ioctl[LS_MODE] & 1) {/* in text mode */ + if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)/* cursor blinking */ { da2->cursoron = (da2->blink | 1) & da2->blinkconf; } @@ -2827,7 +2835,7 @@ void da2_poll(void* priv) { da2->cursoron = 0; } - if (!(da2->blink & (0x10 - 1)))//force redrawing for cursor and blink attribute + if (!(da2->blink & (0x10 - 1)))/* force redrawing for cursor and blink attribute */ da2->fullchange = 2; } da2->blink++; @@ -2837,7 +2845,7 @@ void da2_poll(void* priv) if (da2->changedvram[x]) da2->changedvram[x]--; } - // memset(changedvram,0,2048); del + //memset(changedvram,0,2048); del if (da2->fullchange) { da2->fullchange--; @@ -2846,7 +2854,7 @@ void da2_poll(void* priv) if (da2->vc == da2->vsyncstart) { int wx, wy; - // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); + //da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); da2->dispon = 0; da2->cgastat |= 8; x = da2->hdisp; @@ -2881,14 +2889,12 @@ void da2_poll(void* priv) da2->maback <<= 1; da2->ca <<= 1; - // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + //da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); } if (da2->vc == da2->vtotal) { - // da2_log("VC vtotal\n"); - - - // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); + //da2_log("VC vtotal\n"); + //printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); da2->vc = 0; da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; da2->dispon = 1; @@ -2898,9 +2904,9 @@ void da2_poll(void* priv) if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; } - // printf("2 %i\n",da2_vsyncstart); + //printf("2 %i\n",da2_vsyncstart); //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); - //da2_log("r"); + //da2_log("r"); } static void da2_loadfont(char* fname, void* p) { @@ -2916,10 +2922,10 @@ static void da2_loadfont(char* fname, void* p) { return; } fseek(mfile, 0, SEEK_END); - fsize = ftell(mfile);//get filesize + fsize = ftell(mfile); /* get filesize */ fseek(mfile, 0, SEEK_SET); if (fsize > DA2_FONTROM_SIZE) { - fsize = DA2_FONTROM_SIZE;//truncate read data + fsize = DA2_FONTROM_SIZE; /* truncate read data */ //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); //fclose(mfile); //return 1; @@ -2991,8 +2997,6 @@ da2_reset(void* priv) static void *da2_init() { - //Todo: init regs, gaiji memory, video memory, I/O handlers, font ROM - if (svga_get_pri() == NULL) return NULL; svga_t *mb_vga = svga_get_pri(); @@ -3008,7 +3012,7 @@ static void *da2_init() da2->vram_mask = memsize - 1; da2->cram = malloc(0x1000); da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12);//XX000h + da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12); /* XX000h */ da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ da2->mmio.charset = device_get_config_int("charset"); From 33b149e521d12da64e27580af1900f3f16ff563c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 18:53:44 +0900 Subject: [PATCH 0278/1190] changed debug message output in keyboard.c --- src/device/keyboard.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 3fa7760c5..de97592bf 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -190,7 +190,7 @@ key_process(uint16_t scan, int down) oldkey[scan] = down; - pclog("keyboard : %04X,%d in process\n", scan, down); + kbc_at_log("Key %04X,%d in process\n", scan, down); c = 0; /* According to Japanese DOS K3.3 manual (N:SC18-2194-1), @@ -206,7 +206,7 @@ key_process(uint16_t scan, int down) if (scan != 0x1d && scan != 0x2a && scan != 0x138) { key5576mode = 0; - pclog("keyboard : 5576-001 key emulation disabled.\n"); + kbc_at_log("5576-001 key emulation disabled.\n"); } } while (scconv55_8a[i].sc != 0) @@ -251,7 +251,7 @@ key_process(uint16_t scan, int down) if (keyboard_mode == 0x8a && down && ((keyboard_get_shift() & 0x43) == 0x43)) { key5576mode = 1; - pclog("keyboard : 5576-001 key emulation enabled.\n"); + kbc_at_log("5576-001 key emulation enabled.\n"); } } @@ -348,7 +348,7 @@ keyboard_input(int down, uint16_t scan) } } - /* pclog("Received scan code: %03X (%s)\n", scan & 0x1ff, down ? "down" : "up"); */ + /* kbc_at_log("Received scan code: %03X (%s)\n", scan & 0x1ff, down ? "down" : "up"); */ recv_key_ui[scan & 0x1ff] = down; if (mouse_capture || !kbd_req_capture || video_fullscreen) { From 59c3bb794f6acf9f02e5eaff786b8ca4d7b29835 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 19:03:42 +0900 Subject: [PATCH 0279/1190] revert wrapping changed in recent edits --- src/floppy/fdc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 7f025df2d..a8d2e6520 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -1284,8 +1284,7 @@ fdc_read(uint16_t addr, void *priv) ret |= 0x40; if (fdc->fintr || fdc->reset_stat) /* INTR */ ret |= 0x80; - } - else + } else ret = 0xff; break; case 1: /* STB */ @@ -1360,8 +1359,7 @@ fdc_read(uint16_t addr, void *priv) else ret = 0x00; /* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */ - } - else if (!fdc->enh_mode) + } else if (!fdc->enh_mode) ret = 0x20; else ret = fdc->rwc[drive] << 4; From 6c5e8897de7a5a0899c9e3230979a1fda8741750 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 19:49:03 +0900 Subject: [PATCH 0280/1190] update comments --- src/video/vid_ps55da2.c | 6 +++--- src/video/vid_svga.c | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 5098fa64d..c7c989c5e 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1562,12 +1562,12 @@ The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. 16000-17FFFh (B6000-B7FFFh) : Codepage 850 characters (13 x 30) 18000-1A3FFh (B8000-BA3FFh) : CAD control icons and box drawing characters (32 x 32) - Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. (it disables hardware text drawing in OS/2 J1.3) + Some models have the signature 80h, 01h placed at Bank 0:1AFFEh. It disables Bitblt text drawing in OS/2 J1.3. [Font ROM Map (DA3, Traditional Chinese)] Bank 0 - 11 : Valid Font ROM data - Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose.) - Bank 13 : All addresses return 0xFF + Bank 12 : Alias of bank 11 (At least, DOS T5.0 uses this on purpose to obtain the SBCS font.) + Bank 13 : Filled by 0xFFh [Gaiji RAM Map (DA2)] Bank 0 00000-1FFFFh placed between A0000h-BFFFFh diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 5d0db103b..db378b754 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -502,20 +502,19 @@ svga_in(uint16_t addr, void *priv) ret = svga->attrregs[svga->attraddr]; break; case 0x3c2: - if (svga->cable_connected) - { + if (svga->cable_connected) { if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) ret = 0; else ret = 0x10; - } - else - { + /* Monitor is not connected to the planar VGA if the PS/55 Display Adapter is installed. */ + } else { /* The IBM PS/55 Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). - When the monitor cable is connected to the Display Adapter, this port returns the value as 'no cable connection'. + When the monitor cable is connected to the Display Adapter, the port 3C2h returns the value as 'no cable connection'. The POST of PS/55 has an extra code that tries detecting the monitor on the planar VGA. - If it fails, then the POST reads the NVRAM set by the reference diskette, and updates the BIOS Data Area (Mem 487h, 489h). + If it fails, then the POST reads the NVRAM set by the reference diskette, and writes the BIOS Data Area (Mem 487h, 489h). + MONCHK.EXE in the reference diskette uses both I/O ports to determine the monitor type, and writes the BDA. */ if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10) ret = 0; From bbc237866bff2458fdfae2bcd2da16902fb14728 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:14:07 +0900 Subject: [PATCH 0281/1190] changed palette initialization method --- src/video/vid_ps55da2.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index c7c989c5e..b4a85bd74 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -2987,11 +2987,11 @@ da2_reset(void* priv) da2->attr_palette_enable = 0; /* disable attribute generator */ /* Set default color palette (Windows 3.1 display driver won't reset palette) */ - da2_out(0x3c8, 0, da2); for (int i = 0; i < 256; i++) { - da2_out(0x3c9, ps55_palette_color[i & 0x3F][0], da2); - da2_out(0x3c9, ps55_palette_color[i & 0x3F][1], da2); - da2_out(0x3c9, ps55_palette_color[i & 0x3F][2], da2); + da2->vgapal[i].r = ps55_palette_color[i & 0x3F][0]; + da2->vgapal[i].g = ps55_palette_color[i & 0x3F][1]; + da2->vgapal[i].b = ps55_palette_color[i & 0x3F][2]; + da2->pallook[i] = makecol32((da2->vgapal[i].r & 0x3f) * 4, (da2->vgapal[i].g & 0x3f) * 4, (da2->vgapal[i].b & 0x3f) * 4); } } @@ -3147,14 +3147,13 @@ void da2_speed_changed(void *p) { da2_t* da2 = (da2_t*)p; da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); - da2_recalctimings(da2); + da2_recalctimings(da2); } void da2_force_redraw(void *p) { da2_t* da2 = (da2_t*)p; - - da2->fullchange = changeframecount; + da2->fullchange = changeframecount; } static const device_config_t da2_configuration[] = { From 5f831603e930bf2e462f72567a7d3aaf44c0fba4 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:15:10 +0900 Subject: [PATCH 0282/1190] fixed cache memory encoding for 5550-V --- src/machine/m_ps2_mca.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index b948c984c..62a5e41cd 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -145,7 +145,7 @@ static struct ps2_t { static uint8_t ps2_cache[65536]; static int ps2_cache_valid[65536 / 8]; static void mem_encoding_update(void); - +#define ENABLE_PS2_MCA_LOG 1 #ifdef ENABLE_PS2_MCA_LOG int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; @@ -452,7 +452,7 @@ ps55_model_50v_read(uint16_t port) } return val; case 0x104: - return ps2.option[2]; + return ps2.option[2] & 0xf3; case 0x105: return ps2.option[3]; case 0x106: @@ -1472,10 +1472,12 @@ mem_encoding_write_cached_ps55(uint16_t addr, uint8_t val, UNUSED(void *priv)) mem_mapping_disable(&ram_low_mapping); mem_mapping_enable(&ps2.cache_mapping); flushmmucache(); + ps2_mca_log("mem_encoding_write: low ram mapping disabled\n"); } else { mem_mapping_disable(&ps2.cache_mapping); mem_mapping_enable(&ram_low_mapping); flushmmucache(); + ps2_mca_log("mem_encoding_write: low ram mapping enabled\n"); } if (ps2.option[2] & 1) /* reset memstate for E0000 - E0FFFh hole */ { @@ -1906,7 +1908,7 @@ ps55_mca_board_model_50v_init() device_add(&ps2_nvr_device); - io_sethandler(0x00e0, 0x0002, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached_ps55, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached_ps55, NULL, NULL, NULL); ps2.mem_regs[1] = 2; ps2.option[2] &= 0xf2; /* Bit 3-2: -Cache IDs, Bit 1: Reserved @@ -1926,6 +1928,20 @@ ps55_mca_board_model_50v_init() NULL); mem_mapping_disable(&ps2.split_mapping); + mem_mapping_add(&ps2.cache_mapping, + 0, + 64 * 1024, + ps2_read_cache_ram, + ps2_read_cache_ramw, + ps2_read_cache_raml, + ps2_write_cache_ram, + NULL, + NULL, + ps2_cache, + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.cache_mapping); + if (mem_size > 8192) { /* Only 8 MB supported on planar, create a memory expansion card for the rest */ ps2_mca_mem_fffc_init(8); From 0a7c3294059aa58a3286a4a4e175ce375907a02c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:25:57 +0900 Subject: [PATCH 0283/1190] cleanup --- src/machine/m_ps2_mca.c | 333 ++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 170 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 62a5e41cd..e89d88f91 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -145,7 +145,7 @@ static struct ps2_t { static uint8_t ps2_cache[65536]; static int ps2_cache_valid[65536 / 8]; static void mem_encoding_update(void); -#define ENABLE_PS2_MCA_LOG 1 + #ifdef ENABLE_PS2_MCA_LOG int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; @@ -367,53 +367,59 @@ static uint8_t ps55_model_50t_read(uint16_t port) { ps2_mca_log(" Read SysBrd %04X xx %04X:%04X\n", port, cs >> 4, cpu_state.pc); - switch (port) - { - case 0x100: - return ps2.planar_id & 0xff; - case 0x101: - return ps2.planar_id >> 8; - case 0x102: - return ps2.option[0]; - case 0x103: - uint8_t val = 0xff; - /* - I/O 103h - Bit 7-4: Memory Card ID (Connector 1 or 3) - Bit 3-0: Memory Card ID (Connector 2) + switch (port) { + case 0x100: + return ps2.planar_id & 0xff; + case 0x101: + return ps2.planar_id >> 8; + case 0x102: + return ps2.option[0]; + case 0x103: + uint8_t val = 0xff; + /* + I/O 103h - Bit 7-4: Memory Card ID (Connector 1 or 3) + Bit 3-0: Memory Card ID (Connector 2) - Memory Card ID: 7h = 2 MB Memory Card 2 or 3 Installed - 5h = 4 MB Memory Card 2 Installed - */ - switch (mem_size / 1024) - { - case 2: - if (ps2.option[1] & 0x04) val = 0xff; - else val = 0x7f; - break; - case 4: - if (ps2.option[1] & 0x04) val = 0xff; - else val = 0x77; - break; - case 6: - if (ps2.option[1] & 0x04) val = 0x7f; - else val = 0x77; - break; - case 8: - default: - if (ps2.option[1] & 0x04) val = 0x5f; - else val = 0x77; - break; - } - ps2_mca_log(" Read MCA %04X %02X %04X:%04X mem_size = %d, ps2option1 = %2X\n", port, val, cs >> 4, cpu_state.pc, mem_size, ps2.option[1]); - return val; - case 0x104: - return ps2.option[2]; - case 0x105: - return ps2.option[3]; - case 0x106: - return ps2.subaddr_lo; - case 0x107: - return ps2.subaddr_hi; + Memory Card ID: 7h = 2 MB Memory Card 2 or 3 Installed + 5h = 4 MB Memory Card 2 Installed + */ + switch (mem_size / 1024) { + case 2: + if (ps2.option[1] & 0x04) + val = 0xff; + else + val = 0x7f; + break; + case 4: + if (ps2.option[1] & 0x04) + val = 0xff; + else + val = 0x77; + break; + case 6: + if (ps2.option[1] & 0x04) + val = 0x7f; + else + val = 0x77; + break; + case 8: + default: + if (ps2.option[1] & 0x04) + val = 0x5f; + else + val = 0x77; + break; + } + ps2_mca_log(" Read MCA %04X %02X %04X:%04X mem_size = %d, ps2option1 = %2X\n", port, val, cs >> 4, cpu_state.pc, mem_size, ps2.option[1]); + return val; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; } return 0xff; } @@ -421,44 +427,47 @@ ps55_model_50t_read(uint16_t port) static uint8_t ps55_model_50v_read(uint16_t port) { - switch (port) - { - case 0x100: - return ps2.planar_id & 0xff; - case 0x101: - return ps2.planar_id >> 8; - case 0x102: - return ps2.option[0]; - case 0x103: - uint8_t val = 0xff; - /* - I/O 103h - Bit 7-4: Reserved - Bit 3-0: Memory Card ID (Connector 3 or 1) + switch (port) { + case 0x100: + return ps2.planar_id & 0xff; + case 0x101: + return ps2.planar_id >> 8; + case 0x102: + return ps2.option[0]; + case 0x103: + uint8_t val = 0xff; + /* + I/O 103h - Bit 7-4: Reserved + Bit 3-0: Memory Card ID (Connector 3 or 1) - Memory Card ID: 8h = 4 MB Memory Card IV Installed - Fh = No Card Installed - */ - switch (mem_size / 1024) - { - case 4: - if (ps2.option[1] & 0x04) val = 0xff; - else val = 0xf8; - break; - case 8: - default: - if (ps2.option[1] & 0x04) val = 0xf8; - else val = 0xf8; - break; - } - return val; - case 0x104: - return ps2.option[2] & 0xf3; - case 0x105: - return ps2.option[3]; - case 0x106: - return ps2.subaddr_lo; - case 0x107: - return ps2.subaddr_hi; + Memory Card ID: 8h = 4 MB Memory Card IV Installed + Fh = No Card Installed + */ + switch (mem_size / 1024) { + case 4: + if (ps2.option[1] & 0x04) + val = 0xff; + else + val = 0xf8; + break; + case 8: + default: + if (ps2.option[1] & 0x04) + val = 0xf8; + else + val = 0xf8; + break; + } + return val; + case 0x104: + /* Reading cache ID (bit 3-2) always returns zero */ + return ps2.option[2] & 0xf3; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; } return 0xff; } @@ -763,71 +772,66 @@ static void ps55_model_50tv_write(uint16_t port, uint8_t val) { ps2_mca_log(" Write SysBrd %04X %02X %04X:%04X\n", port, val, cs >> 4, cpu_state.pc); - switch (port) - { - case 0x102: - lpt1_remove(); - serial_remove(ps2.uart); - if (val & 0x04) - { - if (val & 0x08) - serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); - else - serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); - } - if (val & 0x10) - { - switch ((val >> 5) & 3) - { - case 0: - lpt1_setup(LPT_MDA_ADDR); - break; - case 1: - lpt1_setup(LPT1_ADDR); - break; - case 2: - lpt1_setup(LPT2_ADDR); - break; - default: - break; + switch (port) { + case 0x102: + lpt1_remove(); + serial_remove(ps2.uart); + if (val & 0x04) { + if (val & 0x08) + serial_setup(ps2.uart, COM1_ADDR, COM1_IRQ); + else + serial_setup(ps2.uart, COM2_ADDR, COM2_IRQ); } - } - ps2.option[0] = val; - break; - case 0x103: - ps2.option[1] = val; - break; - case 0x104: - if ((ps2.option[2] ^ val) & 1) { - mem_encoding_update(); - if (val & 1)/* Disable E0000 - E0FFF(Make 2 KB hole for Display Adapter) */ - { - ps2_mca_log("ROM E0000-E0FFF is disabled.\n"); - //mem_mapping_set_addr(&bios_mapping 0xe1000, 0x1f000); - mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - //mem_mapping_disable(&bios_mapping[0]); + if (val & 0x10) { + switch ((val >> 5) & 3) { + case 0: + lpt1_setup(LPT_MDA_ADDR); + break; + case 1: + lpt1_setup(LPT1_ADDR); + break; + case 2: + lpt1_setup(LPT2_ADDR); + break; + default: + break; + } } - else/* Enable E0000 - E0FFF for BIOS */ - { - ps2_mca_log("ROM E0000-E0FFF is enabled.\n"); - //mem_mapping_set_addr(&bios_mapping 0xe0000, 0x20000); - //mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); - //mem_mapping_enable(&bios_mapping[0]); + ps2.option[0] = val; + break; + case 0x103: + ps2.option[1] = val; + break; + case 0x104: + if ((ps2.option[2] ^ val) & 1) { + mem_encoding_update(); + if (val & 1) { + /* Disable E0000 - E0FFF (Make 2 KB hole for Display Adapter) */ + ps2_mca_log("ROM E0000-E0FFF is disabled.\n"); + // mem_mapping_set_addr(&bios_mapping 0xe1000, 0x1f000); + mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + // mem_mapping_disable(&bios_mapping[0]); + } else { + /* Enable E0000 - E0FFF for BIOS */ + ps2_mca_log("ROM E0000-E0FFF is enabled.\n"); + // mem_mapping_set_addr(&bios_mapping 0xe0000, 0x20000); + // mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); + // mem_mapping_enable(&bios_mapping[0]); + } } - } - ps2.option[2] = val; - break; - case 0x105: - ps2.option[3] = val; - break; - case 0x106: - ps2.subaddr_lo = val; - break; - case 0x107: - ps2.subaddr_hi = val; - break; - default: - break; + ps2.option[2] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + default: + break; } } @@ -1339,20 +1343,19 @@ static void mem_encoding_write_ps55(uint16_t addr, uint8_t val, void* p) { //ps2_mca_log(" Write Memory Encoding %04X %02X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - switch (addr) - { - case 0xe0: - ps2.mem_regs[0] = val; - break; - case 0xe1: - ps2.mem_regs[1] = val; - break; - default: - break; + switch (addr) { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + default: + break; } mem_encoding_update(); - if (ps2.option[2] & 1) /* reset memstate for E0000 - E0FFFh hole */ - { + if (ps2.option[2] & 1) { + /* reset memstate for E0000 - E0FFFh hole */ mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); } } @@ -1479,8 +1482,8 @@ mem_encoding_write_cached_ps55(uint16_t addr, uint8_t val, UNUSED(void *priv)) flushmmucache(); ps2_mca_log("mem_encoding_write: low ram mapping enabled\n"); } - if (ps2.option[2] & 1) /* reset memstate for E0000 - E0FFFh hole */ - { + if (ps2.option[2] & 1) { + /* reset memstate for E0000 - E0FFFh hole */ mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); } } @@ -1845,7 +1848,6 @@ ps55_mca_board_model_50t_init() { ps2_mca_board_common_init(); - //mem_remap_top(256); ps2.split_addr = mem_size * 1024; /* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */ mca_init(5); @@ -1861,14 +1863,6 @@ ps55_mca_board_model_50t_init() ps2.mem_regs[1] = 2; ps2.option[2] &= 0xfe; /* Bit 0: Disable E0000-E0FFFh (4 KB) */ - //resize bios_mapping 0,1 - //mem_mapping_set_addr(&bios_mapping[0], 0xe0000, 0x1000); - //mem_mapping_set_exec(&bios_mapping[0], rom + (0x20000 & biosmask)); - //mem_mapping_set_addr(&bios_mapping[1], 0xe1000, 0x7000); - //mem_mapping_set_exec(&bios_mapping[1], rom + (0x21000 & biosmask)); - //mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x20000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0); - //mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x23000 & biosmask), MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM, 0); - mem_mapping_add(&ps2.split_mapping, (mem_size + 256) * 1024, 256 * 1024, @@ -1897,7 +1891,6 @@ ps55_mca_board_model_50v_init() { ps2_mca_board_common_init(); - //mem_remap_top(256); ps2.split_addr = mem_size * 1024; /* The slot 5 is reserved for the Integrated Fixed Disk II (an internal ESDI hard drive). */ mca_init(5); From 4768b3b6fbbc49c5a006524af32c13b86ddd4a1f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 15 Feb 2025 20:02:05 +0100 Subject: [PATCH 0284/1190] Fixed some bus checks in some (S)VGA graphics cards, fixes #5229. --- src/video/vid_ati_mach64.c | 4 ++-- src/video/vid_cl54xx.c | 2 +- src/video/vid_ht216.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 9499f4ecc..2df7782ff 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -4595,7 +4595,7 @@ mach64gx_init(const device_t *info) { mach64_t *mach64 = mach64_common_init(info); - if (info->flags & DEVICE_ISA) + if (info->flags & DEVICE_ISA16) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_isa); else if (info->flags & DEVICE_PCI) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_pci); @@ -4617,7 +4617,7 @@ mach64gx_init(const device_t *info) mach64->config_stat0 |= 6; /*VLB, 256Kx16 DRAM*/ ati_eeprom_load(&mach64->eeprom, "mach64_vlb.nvr", 1); rom_init(&mach64->bios_rom, BIOS_VLB_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - } else if (info->flags & DEVICE_ISA) { + } else if (info->flags & DEVICE_ISA16) { mach64->config_stat0 |= 0; /*ISA 16-bit, 256k16 DRAM*/ ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 73be7cd76..21d9b21d8 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4382,7 +4382,7 @@ gd54xx_init(const device_t *info) rom_init_interleaved(&gd54xx->bios_rom, BIOS_GD5428_BOCA_ISA_PATH_1, BIOS_GD5428_BOCA_ISA_PATH_2, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_ISA) + if ((info->flags & DEVICE_ISA) || (info->flags & DEVICE_ISA16)) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); else if (info->flags & DEVICE_PCI) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_pci); diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 57b0f303c..b650cb53b 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1604,7 +1604,7 @@ ht216_init(const device_t *info, uint32_t mem_size, int has_rom) mem_mapping_disable(&ht216->linear_mapping); ht216->id = info->local; - ht216->isabus = (info->flags & DEVICE_ISA); + ht216->isabus = (info->flags & DEVICE_ISA) || (info->flags & DEVICE_ISA16); ht216->mca = (info->flags & DEVICE_MCA); io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); From 5dfbef2374a11c77cf77407eb109f816ee6944a6 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sun, 16 Feb 2025 11:11:44 +0900 Subject: [PATCH 0285/1190] fixed PS/55 5550-V hangs in warm boot * Fixed PS/55 5550-V hangs in warm boot because it doesn't reset E0000-E0FFFh hole (for video RAM of DA) * Merge code that enable/disable E0000-E0FFFh hole --- src/machine/m_ps2_mca.c | 119 ++++++++-------------------------------- 1 file changed, 24 insertions(+), 95 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index e89d88f91..1edff2991 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -107,6 +107,7 @@ static struct ps2_t { serial_t *uart; vga_t* mb_vga; + int has_e0000_hole; } ps2; /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any @@ -145,7 +146,7 @@ static struct ps2_t { static uint8_t ps2_cache[65536]; static int ps2_cache_valid[65536 / 8]; static void mem_encoding_update(void); - +// #define ENABLE_PS2_MCA_LOG 1 #ifdef ENABLE_PS2_MCA_LOG int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; @@ -804,20 +805,9 @@ ps55_model_50tv_write(uint16_t port, uint8_t val) break; case 0x104: if ((ps2.option[2] ^ val) & 1) { + /* Disable/Enable E0000 - E0FFF (Make 2 KB hole for Display Adapter) */ + ps2.option[2] = val; mem_encoding_update(); - if (val & 1) { - /* Disable E0000 - E0FFF (Make 2 KB hole for Display Adapter) */ - ps2_mca_log("ROM E0000-E0FFF is disabled.\n"); - // mem_mapping_set_addr(&bios_mapping 0xe1000, 0x1f000); - mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - // mem_mapping_disable(&bios_mapping[0]); - } else { - /* Enable E0000 - E0FFF for BIOS */ - ps2_mca_log("ROM E0000-E0FFF is enabled.\n"); - // mem_mapping_set_addr(&bios_mapping 0xe0000, 0x20000); - // mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); - // mem_mapping_enable(&bios_mapping[0]); - } } ps2.option[2] = val; break; @@ -952,8 +942,15 @@ ps2_mca_write(uint16_t port, uint8_t val, UNUSED(void *priv)) ps2.setup = val; break; case 0x96: - if ((val & 0x80) && !(ps2.adapter_setup & 0x80)) + if ((val & 0x80) && !(ps2.adapter_setup & 0x80)) { mca_reset(); + if (ps2.has_e0000_hole) { + /* Reset memstate for E0000 - E0FFFh hole (for PS/55 5550-V) + 5550-T does this in POST, but 5550-V doesn't. */ + ps2.option[2] &= 0xFE; + mem_encoding_update(); + } + } ps2.adapter_setup = val; mca_set_index(val & 7); break; @@ -1306,6 +1303,11 @@ mem_encoding_update(void) ps2_mca_log("PS/2 Model 80-111: Split memory block disabled\n"); } + if (ps2.has_e0000_hole && (ps2.option[2] & 1)) { + /* Set memstate for E0000 - E0FFFh hole (PS/55 only) */ + mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + flushmmucache_nopc(); } @@ -1339,26 +1341,7 @@ mem_encoding_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) } mem_encoding_update(); } -static void -mem_encoding_write_ps55(uint16_t addr, uint8_t val, void* p) -{ - //ps2_mca_log(" Write Memory Encoding %04X %02X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - switch (addr) { - case 0xe0: - ps2.mem_regs[0] = val; - break; - case 0xe1: - ps2.mem_regs[1] = val; - break; - default: - break; - } - mem_encoding_update(); - if (ps2.option[2] & 1) { - /* reset memstate for E0000 - E0FFFh hole */ - mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } -} + static uint8_t mem_encoding_read_cached(uint16_t addr, UNUSED(void *priv)) { @@ -1429,64 +1412,6 @@ mem_encoding_write_cached(uint16_t addr, uint8_t val, UNUSED(void *priv)) } } -static void -mem_encoding_write_cached_ps55(uint16_t addr, uint8_t val, UNUSED(void *priv)) -{ - uint8_t old; - - switch (addr) { - case 0xe0: - ps2.mem_regs[0] = val; - break; - case 0xe1: - ps2.mem_regs[1] = val; - break; - case 0xe2: - old = ps2.mem_regs[2]; - ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88); - if (val & 2) { - ps2_mca_log("Clear latch - %i\n", ps2.pending_cache_miss); - if (ps2.pending_cache_miss) - ps2.mem_regs[2] |= 0x80; - else - ps2.mem_regs[2] &= ~0x80; - ps2.pending_cache_miss = 0; - } - - if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20) - ps2.pending_cache_miss = 1; - if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01) - ps2_cache_clean(); -#if 1 - // FIXME: Look into this!!! - if (val & 0x01) - ram_mid_mapping.flags |= MEM_MAPPING_ROM_WS; - else - ram_mid_mapping.flags &= ~MEM_MAPPING_ROM_WS; -#endif - break; - - default: - break; - } - ps2_mca_log("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS, cpu_state.pc, ps2.mem_regs[1], ps2.mem_regs[2]); - mem_encoding_update(); - if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20) { - mem_mapping_disable(&ram_low_mapping); - mem_mapping_enable(&ps2.cache_mapping); - flushmmucache(); - ps2_mca_log("mem_encoding_write: low ram mapping disabled\n"); - } else { - mem_mapping_disable(&ps2.cache_mapping); - mem_mapping_enable(&ram_low_mapping); - flushmmucache(); - ps2_mca_log("mem_encoding_write: low ram mapping enabled\n"); - } - if (ps2.option[2] & 1) { - /* reset memstate for E0000 - E0FFFh hole */ - mem_set_mem_state(0xe0000, 0x1000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } -} static void ps2_mca_board_model_70_type34_init(int is_type4, int slots) { @@ -1675,6 +1600,8 @@ machine_ps2_common_init(const machine_t *model) nmi_mask = 0x80; ps2.uart = device_add_inst(&ns16550_device, 1); + + ps2.has_e0000_hole = 0; } int @@ -1858,10 +1785,11 @@ ps55_mca_board_model_50t_init() device_add(&ps2_nvr_device); - io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write_ps55, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write, NULL, NULL, NULL); ps2.mem_regs[1] = 2; ps2.option[2] &= 0xfe; /* Bit 0: Disable E0000-E0FFFh (4 KB) */ + ps2.has_e0000_hole = 1; mem_mapping_add(&ps2.split_mapping, (mem_size + 256) * 1024, @@ -1901,11 +1829,12 @@ ps55_mca_board_model_50v_init() device_add(&ps2_nvr_device); - io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached_ps55, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL); ps2.mem_regs[1] = 2; ps2.option[2] &= 0xf2; /* Bit 3-2: -Cache IDs, Bit 1: Reserved Bit 0: Disable E0000-E0FFFh (4 KB) */ + ps2.has_e0000_hole = 1; mem_mapping_add(&ps2.split_mapping, (mem_size + 256) * 1024, From 3f3d77310e769ab52d78b7cf63bd8e20cab433ba Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sun, 16 Feb 2025 12:21:16 +0900 Subject: [PATCH 0286/1190] cleanup format --- src/video/vid_ps55da2.c | 3436 +++++++++++++++++++-------------------- 1 file changed, 1715 insertions(+), 1721 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index b4a85bd74..9ed099f19 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -37,42 +37,42 @@ #include <86box/vid_svga_render.h> #include "cpu.h" -#define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" -#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" -#define DA2_FONTROM_SIZE 1536*1024 -#define DA2_FONTROM_BASESBCS 0x98000 -#define DA2_GAIJIRAM_SBCS 0x34000 -#define DA2_GAIJIRAM_SBEX 0x3c000 -#define DA2_INVALIDACCESS8 0xff -#define DA2_MASK_MMIO 0x1ffff -#define DA2_MASK_GRAM 0x1ffff -#define DA2_MASK_CRAM 0xfff -#define DA2_MASK_GAIJIRAM 0x3ffff -#define DA2_PIXELCLOCK 58000000.0 -#define DA2_BLT_MEMSIZE 0x100 -#define DA2_BLT_REGSIZE 0x40 -#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) -#define DA2_DEBUG_BLTLOG_MAX 256*1024 -#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe -#define DA2_DEBUG_BLT_USEDRESET 0xfefefe +#define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" +#define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" +#define DA2_FONTROM_SIZE 1536 * 1024 +#define DA2_FONTROM_BASESBCS 0x98000 +#define DA2_GAIJIRAM_SBCS 0x34000 +#define DA2_GAIJIRAM_SBEX 0x3c000 +#define DA2_INVALIDACCESS8 0xff +#define DA2_MASK_MMIO 0x1ffff +#define DA2_MASK_GRAM 0x1ffff +#define DA2_MASK_CRAM 0xfff +#define DA2_MASK_GAIJIRAM 0x3ffff +#define DA2_PIXELCLOCK 58000000.0 +#define DA2_BLT_MEMSIZE 0x100 +#define DA2_BLT_REGSIZE 0x40 +#define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) +#define DA2_DEBUG_BLTLOG_MAX 256 * 1024 +#define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe +#define DA2_DEBUG_BLT_USEDRESET 0xfefefe #define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ -//#define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ -//#define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ +// #define DA2_DCONFIG_CHARSET_HANG 1 /* for Code page 934 Hangul */ +// #define DA2_DCONFIG_CHARSET_HANS 2 /* for Code page 936 Simplified Chinese */ /* These ROMs are currently not found. At least, IBM-J released a Korean and PRC version of PS/55 for each market. */ -#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ +#define DA2_DCONFIG_CHARSET_HANT 3 /* for Code page 938 Traditional Chinese */ #define DA2_DCONFIG_MONTYPE_COLOR 0x0A -#define DA2_DCONFIG_MONTYPE_8515 0x0B -#define DA2_DCONFIG_MONTYPE_MONO 0x09 +#define DA2_DCONFIG_MONTYPE_8515 0x0B +#define DA2_DCONFIG_MONTYPE_MONO 0x09 -#define DA2_BLT_CIDLE 0 -#define DA2_BLT_CFILLRECT 1 -#define DA2_BLT_CFILLTILE 2 -#define DA2_BLT_CCOPYF 3 -#define DA2_BLT_CCOPYR 4 -#define DA2_BLT_CPUTCHAR 5 -#define DA2_BLT_CDONE 6 -#define DA2_BLT_CLOAD 7 +#define DA2_BLT_CIDLE 0 +#define DA2_BLT_CFILLRECT 1 +#define DA2_BLT_CFILLTILE 2 +#define DA2_BLT_CCOPYF 3 +#define DA2_BLT_CCOPYR 4 +#define DA2_BLT_CPUTCHAR 5 +#define DA2_BLT_CDONE 6 +#define DA2_BLT_CLOAD 7 /* POS ID = 0xeffe : Display Adapter II, III, V */ #define DA2_POSID_H 0xef #define DA2_POSID_L 0xfe @@ -94,7 +94,7 @@ EFD8h * Display Adapter/J [Atlas-SP2] [Japanese DOS and Display Adapter compatibility] - | POS ID | Adapter Name | K3.31 | J4.04 | J5.02 | OS2 J1.3 | Win3 | + | POS ID | Adapter Name | K3.31 | J4.04 | J4.08 | OS2 J1.3 | Win3 | |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| | EFFFh | Display Adapter | X | | | ? | | | FFEDh | ? [Atlas EVT] | X | | | ? | | @@ -107,21 +107,21 @@ | EFD8h | Display Adapter /J | | | X | X | X | */ /* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ -#define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ -//#define Mon_ID3 0x10 -#define FontCard 0x08 /* ? */ -#define Page_One 0x06 /* 80000h 110b */ -#define Page_Two 0x05 /* 100000h 101b */ -#define Page_Four 0x03 /* 200000h 011b */ +#define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ +// #define Mon_ID3 0x10 +#define FontCard 0x08 /* ? */ +#define Page_One 0x06 /* 80000h 110b */ +#define Page_Two 0x05 /* 100000h 101b */ +#define Page_Four 0x03 /* 200000h 011b */ /* Page Number Mask : Memory Size? = (110b and 111b): vram size is 512k (256 color mode unsupported). */ /* IO 3E0/3E1:0Bh Hardware Configuration Value H (imported from OS/2 DDK) */ -#define AddPage 0x08 /* ? */ -//#define Mon_ID2 0x04 -//#define Mon_ID1 0x02 -//#define Mon_ID0 0x01 +#define AddPage 0x08 /* ? */ +// #define Mon_ID2 0x04 +// #define Mon_ID1 0x02 +// #define Mon_ID0 0x01 -/* Monitor ID (imported from OS/2 DDK 1.2) +/* Monitor ID (imported from OS/2 DDK 1.2) #define StarbuckC 0x0A // 1 010b IBM 8514, 9518 color 1040x768 #define StarbuckM 0x09 // 1 001b IBM 8507, 8604 grayscale #define Lark_B 0x02 // 0 010b IBM 9517 color 1040x768 but 4bpp @@ -133,114 +133,114 @@ #define AC_DMAE 0x80 #define AC_FONT_SEL 0x40 #define FONT_BANK 0x3EF -#define LS_INDEX 0x3E0 -#define LS_DATA 0x3E1 +#define LS_INDEX 0x3E0 +#define LS_DATA 0x3E1 #define LS_RESET 0x00 #define LS_MODE 0x02 #define LS_STATUS 0x03 /* added */ #define LS_MMIO 0x08 /* added */ -#define LS_CONFIG1 0x0a -#define LS_CONFIG2 0x0b /* added */ -#define LF_INDEX 0x3e2 -#define LF_DATA 0x3e3 -#define LF_MMIO_SEL 0x08 /* added */ -#define LF_MMIO_ADDR 0x0A /* added */ -#define LF_MMIO_MODE 0x0B /* added */ -#define LC_INDEX 0x3E4 -#define LC_DATA 0x3E5 -#define LC_HORIZONTAL_TOTAL 0x00 -#define LC_H_DISPLAY_ENABLE_END 0x01 -#define LC_START_H_BLANKING 0x02 -#define LC_END_H_BLANKING 0x03 -#define LC_START_HSYNC_PULSE 0x04 -#define LC_END_HSYNC_PULSE 0x05 -#define LC_VERTICAL_TOTALJ 0x06 -#define LC_CRTC_OVERFLOW 0x07 -#define LC_PRESET_ROW_SCANJ 0x08 -#define LC_MAXIMUM_SCAN_LINE 0x09 -#define LC_CURSOR_ROW_START 0x0A -#define LC_CURSOR_ROW_END 0x0B -#define LC_START_ADDRESS_HIGH 0x0C -#define LC_START_ADDRESS_LOW 0x0D -#define LC_CURSOR_LOC_HIGH 0x0E -#define LC_ROW_CURSOR_LOC 0x0E -#define LC_CURSOR_LOC_LOWJ 0x0F -#define LC_COLUMN_CURSOR_LOC 0x0F -#define LC_VERTICAL_SYNC_START 0x10 -#define LC_LIGHT_PEN_HIGH 0x10 -#define LC_VERTICAL_SYNC_END 0x11 -#define LC_LIGHT_PEN_LOW 0x11 -#define LC_V_DISPLAY_ENABLE_END 0x12 -#define LC_OFFSET 0x13 -#define LC_UNDERLINE_LOCATION 0x14 -#define LC_START_VERTICAL_BLANK 0x15 -#define LC_END_VERTICAL_BLANK 0x16 -#define LC_LC_MODE_CONTROL 0x17 -#define LC_LINE_COMPAREJ 0x18 -#define LC_START_H_DISPLAY_ENAB 0x19 -#define LC_START_V_DISPLAY_ENAB 0x1A -#define LC_VIEWPORT_COMMAND 0x1B -#define LC_VIEWPORT_SELECT 0x1C -#define LC_VIEWPORT_PRIORITY 0x1D -#define LC_COMMAND 0x1E -#define LC_COMPATIBILITY 0x1F -#define LC_VIEWPORT_NUMBER 0x1F +#define LS_CONFIG1 0x0a +#define LS_CONFIG2 0x0b /* added */ +#define LF_INDEX 0x3e2 +#define LF_DATA 0x3e3 +#define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_ADDR 0x0A /* added */ +#define LF_MMIO_MODE 0x0B /* added */ +#define LC_INDEX 0x3E4 +#define LC_DATA 0x3E5 +#define LC_HORIZONTAL_TOTAL 0x00 +#define LC_H_DISPLAY_ENABLE_END 0x01 +#define LC_START_H_BLANKING 0x02 +#define LC_END_H_BLANKING 0x03 +#define LC_START_HSYNC_PULSE 0x04 +#define LC_END_HSYNC_PULSE 0x05 +#define LC_VERTICAL_TOTALJ 0x06 +#define LC_CRTC_OVERFLOW 0x07 +#define LC_PRESET_ROW_SCANJ 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_ROW_CURSOR_LOC 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_COLUMN_CURSOR_LOC 0x0F +#define LC_VERTICAL_SYNC_START 0x10 +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_VERTICAL_SYNC_END 0x11 +#define LC_LIGHT_PEN_LOW 0x11 +#define LC_V_DISPLAY_ENABLE_END 0x12 +#define LC_OFFSET 0x13 +#define LC_UNDERLINE_LOCATION 0x14 +#define LC_START_VERTICAL_BLANK 0x15 +#define LC_END_VERTICAL_BLANK 0x16 +#define LC_LC_MODE_CONTROL 0x17 +#define LC_LINE_COMPAREJ 0x18 +#define LC_START_H_DISPLAY_ENAB 0x19 +#define LC_START_V_DISPLAY_ENAB 0x1A +#define LC_VIEWPORT_COMMAND 0x1B +#define LC_VIEWPORT_SELECT 0x1C +#define LC_VIEWPORT_PRIORITY 0x1D +#define LC_COMMAND 0x1E +#define LC_COMPATIBILITY 0x1F +#define LC_VIEWPORT_NUMBER 0x1F #define LV_PORT 0x3E8 -#define LV_PALETTE_0 0x00 -#define LV_MODE_CONTROL 0x10 -#define LV_OVERSCAN_COLOR 0x11 -#define LV_COLOR_PLANE_ENAB 0x12 -#define LV_PANNING 0x13 -#define LV_VIEWPORT1_BG 0x14 -#define LV_VIEWPORT2_BG 0x15 -#define LV_VIEWPORT3_BG 0x16 -#define LV_BLINK_COLOR 0x17 -#define LV_BLINK_CODE 0x18 -#define LV_GR_CURSOR_ROTATION 0x19 -#define LV_GR_CURSOR_COLOR 0x1A -#define LV_GR_CURSOR_CONTROL 0x1B -#define LV_COMMAND 0x1C -#define LV_VP_BORDER_LINE 0x1D -#define LV_SYNC_POLARITY 0x1F -#define LV_CURSOR_CODE_0 0x20 -#define LV_GRID_COLOR_0 0x34 -#define LV_GRID_COLOR_1 0x35 -#define LV_GRID_COLOR_2 0x36 -#define LV_GRID_COLOR_3 0x37 -#define LV_ATTRIBUTE_CNTL 0x38 -#define LV_CURSOR_COLOR 0x3A -#define LV_CURSOR_CONTROL 0x3B -#define LV_RAS_STATUS_VIDEO 0x3C -#define LV_PAS_STATUS_CNTRL 0x3D -#define LV_IDENTIFICATION 0x3E -#define LV_OUTPUT 0x3E -#define LV_COMPATIBILITY 0x3F -#define LG_INDEX 0x3EA -#define LG_DATA 0x3EB -#define LG_SET_RESETJ 0x00 -#define LG_ENABLE_SRJ 0x01 -#define LG_COLOR_COMPAREJ 0x02 -#define LG_DATA_ROTATION 0x03 -#define LG_READ_MAP_SELECT 0x04 -#define LG_MODE 0x05 -#define LG_COMPLEMENT 0x06 -#define LG_COLOR_DONT_CARE 0x07 -#define LG_BIT_MASK_LOW 0x08 -#define LG_BIT_MASK_HIGH 0x09 -#define LG_MAP_MASKJ 0x0A -#define LG_COMMAND 0x0B -#define LG_SET_RESET_2 0x10 +#define LV_PALETTE_0 0x00 +#define LV_MODE_CONTROL 0x10 +#define LV_OVERSCAN_COLOR 0x11 +#define LV_COLOR_PLANE_ENAB 0x12 +#define LV_PANNING 0x13 +#define LV_VIEWPORT1_BG 0x14 +#define LV_VIEWPORT2_BG 0x15 +#define LV_VIEWPORT3_BG 0x16 +#define LV_BLINK_COLOR 0x17 +#define LV_BLINK_CODE 0x18 +#define LV_GR_CURSOR_ROTATION 0x19 +#define LV_GR_CURSOR_COLOR 0x1A +#define LV_GR_CURSOR_CONTROL 0x1B +#define LV_COMMAND 0x1C +#define LV_VP_BORDER_LINE 0x1D +#define LV_SYNC_POLARITY 0x1F +#define LV_CURSOR_CODE_0 0x20 +#define LV_GRID_COLOR_0 0x34 +#define LV_GRID_COLOR_1 0x35 +#define LV_GRID_COLOR_2 0x36 +#define LV_GRID_COLOR_3 0x37 +#define LV_ATTRIBUTE_CNTL 0x38 +#define LV_CURSOR_COLOR 0x3A +#define LV_CURSOR_CONTROL 0x3B +#define LV_RAS_STATUS_VIDEO 0x3C +#define LV_PAS_STATUS_CNTRL 0x3D +#define LV_IDENTIFICATION 0x3E +#define LV_OUTPUT 0x3E +#define LV_COMPATIBILITY 0x3F +#define LG_INDEX 0x3EA +#define LG_DATA 0x3EB +#define LG_SET_RESETJ 0x00 +#define LG_ENABLE_SRJ 0x01 +#define LG_COLOR_COMPAREJ 0x02 +#define LG_DATA_ROTATION 0x03 +#define LG_READ_MAP_SELECT 0x04 +#define LG_MODE 0x05 +#define LG_COMPLEMENT 0x06 +#define LG_COLOR_DONT_CARE 0x07 +#define LG_BIT_MASK_LOW 0x08 +#define LG_BIT_MASK_HIGH 0x09 +#define LG_MAP_MASKJ 0x0A +#define LG_COMMAND 0x0B +#define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -//#define ENABLE_DA2_LOG 1 +// #define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG -#define ENABLE_DA2_DEBUGBLT 1 +# define ENABLE_DA2_DEBUGBLT 1 int da2_do_log = ENABLE_DA2_LOG; static void -da2_log(const char* fmt, ...) +da2_log(const char *fmt, ...) { va_list ap; @@ -254,22 +254,21 @@ da2_log(const char* fmt, ...) # define da2_log(fmt, ...) #endif -typedef struct da2_t -{ - //mem_mapping_t vmapping; +typedef struct da2_t { + // mem_mapping_t vmapping; mem_mapping_t cmapping; - //uint8_t crtcreg; - uint8_t ioctl[16]; - uint8_t fctl[32]; + // uint8_t crtcreg; + uint8_t ioctl[16]; + uint8_t fctl[32]; uint16_t crtc[128]; - uint8_t gdcreg[64]; - uint8_t reg3ee[16]; - int gdcaddr; - uint8_t attrc[0x40]; - int attraddr, attrff; - int attr_palette_enable; - //uint8_t seqregs[64]; + uint8_t gdcreg[64]; + uint8_t reg3ee[16]; + int gdcaddr; + uint8_t attrc[0x40]; + int attraddr, attrff; + int attr_palette_enable; + // uint8_t seqregs[64]; int outflipflop; int inflipflop; int iolatch; @@ -288,8 +287,8 @@ typedef struct da2_t uint32_t debug_vramold[8]; uint8_t dac_mask, dac_status; - int dac_read, dac_write, dac_pos; - int dac_r, dac_g; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; uint8_t cgastat; @@ -297,37 +296,37 @@ typedef struct da2_t int fb_only; - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; - uint8_t writemask; + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + uint8_t writemask; uint32_t charseta, charsetb; - uint8_t egapal[16]; + uint8_t egapal[16]; uint32_t pallook[512]; - PALETTE vgapal; + PALETTE vgapal; - int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; - int lowres, interlace; - int rowcount; - double clock; + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int rowcount; + double clock; uint32_t ma_latch, ca_adj; - uint64_t dispontime, dispofftime; + uint64_t dispontime, dispofftime; pc_timer_t timer; - uint64_t da2const; + uint64_t da2const; int dispon; int hdisp_on; uint32_t ma, maback, ca; - int vc; - int sc; - int linepos, vslines, linecountff, oddeven; - int con, cursoron, blink, blinkconf; - int scrollcache; - int char_width; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink, blinkconf; + int scrollcache; + int char_width; int firstline, lastline; int firstline_draw, lastline_draw; @@ -336,7 +335,7 @@ typedef struct da2_t /* Attribute Buffer E0000-E0FFFh (4 KB) */ uint8_t *cram; /* (cram size - 1) >> 3 = 0xFFF */ - //uint32_t cram_display_mask; + // uint32_t cram_display_mask; /* APA Buffer A0000-BFFFFh (128 KB) */ uint8_t *vram; /* addr >> 12 = xx000h */ @@ -344,11 +343,11 @@ typedef struct da2_t /* (vram size - 1) >> 3 = 0x1FFFF */ uint32_t vram_display_mask; - //uint32_t write_bank, read_bank; + // uint32_t write_bank, read_bank; int fullchange; - void (*render)(struct da2_t* da2); + void (*render)(struct da2_t *da2); /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ @@ -357,41 +356,41 @@ typedef struct da2_t /* end VGA compatible regs*/ struct { - int enable; + int enable; mem_mapping_t mapping; - uint8_t ram[256 * 1024]; - uint8_t *font; - int charset; + uint8_t ram[256 * 1024]; + uint8_t *font; + int charset; } mmio; struct { - int bitshift_destr; - int raster_op; - uint8_t payload[DA2_BLT_MEMSIZE]; - int32_t reg[DA2_BLT_REGSIZE];//must be signed int - int32_t* debug_reg;//for debug - int debug_reg_ip;//for debug - int payload_addr; + int bitshift_destr; + int raster_op; + uint8_t payload[DA2_BLT_MEMSIZE]; + int32_t reg[DA2_BLT_REGSIZE]; // must be signed int + int32_t *debug_reg; // for debug + int debug_reg_ip; // for debug + int payload_addr; pc_timer_t timer; - int64_t timerspeed; - int exec; - int indata; - int32_t destaddr; - int32_t srcaddr; - int32_t size_x, tile_w; - int32_t size_y; - int16_t destpitch; - int16_t srcpitch; - int32_t fcolor; - int32_t maskl, maskr; - int x, y; + int64_t timerspeed; + int exec; + int indata; + int32_t destaddr; + int32_t srcaddr; + int32_t size_x, tile_w; + int32_t size_y; + int16_t destpitch; + int16_t srcpitch; + int32_t fcolor; + int32_t maskl, maskr; + int x, y; } bitblt; - FILE* mmdbg_fp; - FILE* mmrdbg_fp; + FILE *mmdbg_fp; + FILE *mmrdbg_fp; uint32_t mmdbg_vidaddr; uint32_t mmrdbg_vidaddr; - + uint8_t pos_regs[8]; svga_t *mb_vga; uint8_t monitorid; @@ -399,16 +398,16 @@ typedef struct da2_t int old_pos2; } da2_t; -void da2_recalctimings(da2_t* da2); -static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p); -void da2_bitblt_exec(void* p); -void da2_updatevidselector(da2_t* da2); -void da2_reset_ioctl(da2_t* da2); -static void da2_reset(void* priv); +void da2_recalctimings(da2_t *da2); +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p); +void da2_bitblt_exec(void *p); +void da2_updatevidselector(da2_t *da2); +void da2_reset_ioctl(da2_t *da2); +static void da2_reset(void *priv); typedef union { uint32_t d; - uint8_t b[4]; + uint8_t b[4]; } DA2_VidSeq32; typedef struct { @@ -416,64 +415,69 @@ typedef struct { } pixel32; /* safety read for internal functions */ -uint32_t DA2_readvram_s(uint32_t addr, da2_t* da2) +uint32_t +DA2_readvram_s(uint32_t addr, da2_t *da2) { - if (addr & ~da2->vram_mask) return -1; + if (addr & ~da2->vram_mask) + return -1; return da2->vram[addr]; } -void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32* srcpx, da2_t* da2) +void +DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) { uint32_t writepx[8]; - destaddr &= 0xfffffffe;/* align to word address to work bit shift correctly */ - //da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); - da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; - da2->changedvram[(da2->vram_display_mask & (destaddr+1)) >> 12] = changeframecount; + destaddr &= 0xfffffffe; /* align to word address to work bit shift correctly */ + // da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); + da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; + da2->changedvram[(da2->vram_display_mask & (destaddr + 1)) >> 12] = changeframecount; destaddr <<= 3; /* read destination data with big endian order */ for (int i = 0; i < 8; i++) writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) - | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); + | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); - DA2_VidSeq32 mask32in; mask32in.d = (uint32_t)mask; - DA2_VidSeq32 mask32; mask32.d = 0; + DA2_VidSeq32 mask32in; + mask32in.d = (uint32_t) mask; + DA2_VidSeq32 mask32; + mask32.d = 0; mask32.b[3] = mask32in.b[0]; mask32.b[2] = mask32in.b[1]; mask32.d &= 0xffff0000; - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) { if (da2->bitblt.bitshift_destr > 0) - srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; + srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; switch (da2->bitblt.raster_op) { - case 0x00: /* None */ - writepx[i] &= ~mask32.d; - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x01: /* AND */ - writepx[i] &= srcpx->p8[i] | ~mask32.d; - break; - case 0x02: /* OR */ - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x03: /* XOR */ - writepx[i] ^= srcpx->p8[i] & mask32.d; - break; + case 0x00: /* None */ + writepx[i] &= ~mask32.d; + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x01: /* AND */ + writepx[i] &= srcpx->p8[i] | ~mask32.d; + break; + case 0x02: /* OR */ + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x03: /* XOR */ + writepx[i] ^= srcpx->p8[i] & mask32.d; + break; } } for (int i = 0; i < 8; i++) { - da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; + da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; } } -void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t* da2) +void +DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t *da2) { pixel32 srcpx; /* fill data with input color */ for (int i = 0; i < 8; i++) - srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0;/* read in word */ + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0; /* read in word */ DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } @@ -487,7 +491,7 @@ Param Desc 09 Mask Right 0A Plane Mask? 0B ROP?(8h or 200h + 0-3h) -0D +0D 20 Exec (1) 21 ? 22 ? @@ -499,20 +503,22 @@ Param Desc 33 Size W 35 Size H */ -void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +void +DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) { pixel32 srcpx; srcaddr &= 0xfffffffe; srcaddr <<= 3; for (int i = 0; i < 8; i++) srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) - | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) + | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) + | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24); DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } -void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t* da2) +void +DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) { pixel32 srcpx; if (srcaddr >= DA2_FONTROM_SIZE) { @@ -520,134 +526,147 @@ void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, return; } for (int i = 0; i < 8; i++) - srcpx.p8[i] = ((uint32_t)da2->mmio.font[srcaddr] << 24) - | ((uint32_t)da2->mmio.font[srcaddr + 1] << 16) - | ((uint32_t)da2->mmio.font[srcaddr + 2] << 8) - | ((uint32_t)da2->mmio.font[srcaddr + 3] << 0); + srcpx.p8[i] = ((uint32_t) da2->mmio.font[srcaddr] << 24) + | ((uint32_t) da2->mmio.font[srcaddr + 1] << 16) + | ((uint32_t) da2->mmio.font[srcaddr + 2] << 8) + | ((uint32_t) da2->mmio.font[srcaddr + 3] << 0); DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } #ifdef ENABLE_DA2_DEBUGBLT -uint8_t pixel1tohex(uint32_t addr, int index, da2_t* da2) { +uint8_t +pixel1tohex(uint32_t addr, int index, da2_t *da2) +{ uint8_t pixeldata = 0; for (int j = 0; j < 8; j++) { - if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) pixeldata++; + if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) + pixeldata++; } return pixeldata; } -void print_pixelbyte(uint32_t addr, da2_t* da2) { - for (int i = 0; i < 8; i++) - { +void +print_pixelbyte(uint32_t addr, da2_t *da2) +{ + for (int i = 0; i < 8; i++) { pclog("%X", pixel1tohex(addr, i, da2)); } } -void print_bytetobin(uint8_t b) { - for (int i = 0; i < 8; i++) - { - if(b & 0x80) +void +print_bytetobin(uint8_t b) +{ + for (int i = 0; i < 8; i++) { + if (b & 0x80) pclog("1"); else pclog("0"); b <<= 1; } } -//Convert internal char code to Shift JIS code -inline int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } -inline int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } -uint16_t IBMJtoSJIS(uint16_t knj) +// Convert internal char code to Shift JIS code +inline int +isKanji1(uint8_t chr) { - if (knj < 0x100) return 0xffff; + return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); +} +inline int +isKanji2(uint8_t chr) +{ + return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); +} +uint16_t +IBMJtoSJIS(uint16_t knj) +{ + if (knj < 0x100) + return 0xffff; knj -= 0x100; if (knj <= 0x1f7d) - ;/* do nothing */ + ; /* do nothing */ else if (knj >= 0xb700 && knj <= 0xb75f) { knj -= 0x90ec; - } - else if (knj >= 0xb3f0 && knj <= 0xb67f) { + } else if (knj >= 0xb3f0 && knj <= 0xb67f) { knj -= 0x906c; - } - else if (knj >= 0x8000 && knj <= 0x8183) - { + } else if (knj >= 0x8000 && knj <= 0x8183) { knj -= 0x5524; - } - else + } else return 0xffff; uint32_t knj1 = knj / 0xBC; uint32_t knj2 = knj - (knj1 * 0xBC); knj1 += 0x81; - if (knj1 > 0x9F) knj1 += 0x40; + if (knj1 > 0x9F) + knj1 += 0x40; knj2 += 0x40; - if (knj2 > 0x7E) knj2++; - //if (!isKanji1(knj1)) return 0xffff; - //if (!isKanji2(knj2)) return 0xffff; + if (knj2 > 0x7E) + knj2++; + // if (!isKanji1(knj1)) return 0xffff; + // if (!isKanji2(knj2)) return 0xffff; knj = knj1 << 8; knj |= knj2; return knj; } #endif -void da2_bitblt_load(da2_t* da2) +void +da2_bitblt_load(da2_t *da2) { uint32_t value32; uint64_t value64; da2_log("BITBLT loading params\n"); - //da2_log("BitBlt memory:\n"); - //if (da2->bitblt.payload[0] != 0) - // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) - // { - // int i = j * 8; - // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - // } + // da2_log("BitBlt memory:\n"); + // if (da2->bitblt.payload[0] != 0) + // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) + // { + // int i = j * 8; + // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + // } int i = 0; - while (i < DA2_BLT_MEMSIZE) - { + while (i < DA2_BLT_MEMSIZE) { if (da2->bitblt.reg[0x20] & 0x1) break; switch (da2->bitblt.payload[i]) { - case 0x88: - case 0x89: - case 0x95: - value32 = da2->bitblt.payload[i + 3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - i += 3; - break; - case 0x91: - value32 = da2->bitblt.payload[i + 5]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 4]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - i += 5; - break; - case 0x99: - value64 = da2->bitblt.payload[i + 7]; - value64 <<= 8; - value64 = da2->bitblt.payload[i + 6]; - value64 <<= 8; - value64 = da2->bitblt.payload[i + 5]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 4]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 3]; - value64 <<= 8; - value64 |= da2->bitblt.payload[i + 2]; - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; - da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - i += 7; - break; - case 0x00: - break; - default: - da2_log("da2_ParseBLT: Unknown PreOP!\n"); - break; + case 0x88: + case 0x89: + case 0x95: + value32 = da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 3; + break; + case 0x91: + value32 = da2->bitblt.payload[i + 5]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 4]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[i + 2]; + da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + i += 5; + break; + case 0x99: + value64 = da2->bitblt.payload[i + 7]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 6]; + value64 <<= 8; + value64 = da2->bitblt.payload[i + 5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 2]; + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + i += 7; + break; + case 0x00: + break; + default: + da2_log("da2_ParseBLT: Unknown PreOP!\n"); + break; } i++; } @@ -656,31 +675,31 @@ void da2_bitblt_load(da2_t* da2) memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); da2->bitblt.payload_addr = 0; /* [89] 20: 0001 (1) then execute payload */ - if (da2->bitblt.reg[0x20] & 0x1) - { + if (da2->bitblt.reg[0x20] & 0x1) { #ifdef ENABLE_DA2_DEBUGBLT for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { - //if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); + // if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); } for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; } da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; da2->bitblt.debug_reg_ip++; - if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; + if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) + da2->bitblt.debug_reg_ip = 0; #endif - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f);/* set bit shift */ - da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03;/* 01 AND, 03 XOR */ + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03; /* 01 AND, 03 XOR */ da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); for (int i = 0; i <= 0xb; i++) da2_log("%02x ", da2->gdcreg[i]); da2_log("\n"); - da2->bitblt.destaddr = da2->bitblt.reg[0x29]; - da2->bitblt.size_x = da2->bitblt.reg[0x33]; - da2->bitblt.size_y = da2->bitblt.reg[0x35]; + da2->bitblt.destaddr = da2->bitblt.reg[0x29]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + da2->bitblt.size_y = da2->bitblt.reg[0x35]; da2->bitblt.destpitch = da2->bitblt.reg[0x21]; - da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ { da2->bitblt.destaddr -= 2; @@ -689,63 +708,61 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.srcpitch -= 2; } da2->bitblt.fcolor = da2->bitblt.reg[0x0]; - da2->bitblt.maskl = da2->bitblt.reg[0x8]; - da2->bitblt.maskr = da2->bitblt.reg[0x9]; - da2->bitblt.x = 0; - da2->bitblt.y = 0; - da2->bitblt.exec = DA2_BLT_CDONE; + da2->bitblt.maskl = da2->bitblt.reg[0x8]; + da2->bitblt.maskr = da2->bitblt.reg[0x9]; + da2->bitblt.x = 0; + da2->bitblt.y = 0; + da2->bitblt.exec = DA2_BLT_CDONE; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); if (da2->bitblt.reg[0x2f] < 0x80) /* MS Paint 3.1 will cause hang up in 256 color mode */ { da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); da2->bitblt.exec = DA2_BLT_CDONE; - } - else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ + } else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ da2->bitblt.exec = DA2_BLT_CPUTCHAR; /* Todo: addressing */ - //if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ + // if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ //{ - // da2->bitblt.destaddr += 2; - // da2->bitblt.size_x -= 1; - // da2->bitblt.destpitch += 2; - // da2->bitblt.srcpitch += 2; - //} + // da2->bitblt.destaddr += 2; + // da2->bitblt.size_x -= 1; + // da2->bitblt.destpitch += 2; + // da2->bitblt.srcpitch += 2; + // } da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; + da2->bitblt.srcpitch = 0; da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #endif - } - else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { - da2->bitblt.exec = DA2_BLT_CPUTCHAR; + } else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { + da2->bitblt.exec = DA2_BLT_CPUTCHAR; da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; + da2->bitblt.srcpitch = 0; da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #endif } /* Fill a rectangle(or draw a line) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); da2->bitblt.exec = DA2_BLT_CFILLRECT; da2->bitblt.destaddr += 2; } @@ -754,282 +771,270 @@ void da2_bitblt_load(da2_t* da2) da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); } /* Tiling a rectangle (transfer tile data multiple times) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) { da2->bitblt.exec = DA2_BLT_CFILLTILE; da2->bitblt.destaddr += 2; da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); } /* Block transfer (range copy) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { - da2->bitblt.exec = DA2_BLT_CCOPYF; + da2->bitblt.exec = DA2_BLT_CCOPYF; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr += 2; da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); } /* Block copy but reversed direction */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) { - da2->bitblt.exec = DA2_BLT_CCOPYR; + da2->bitblt.exec = DA2_BLT_CCOPYR; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; da2->bitblt.destaddr -= 2; da2->bitblt.srcaddr -= 2; - da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); - //da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); + // da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); } } } -void da2_bitblt_exec(void* p) +void +da2_bitblt_exec(void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - //da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); - switch (da2->bitblt.exec) - { - case DA2_BLT_CIDLE: - timer_disable(&da2->bitblt.timer); - break; - case DA2_BLT_CLOAD: - da2->bitblt.indata = 0; - da2_bitblt_load(da2); - break; - case DA2_BLT_CFILLRECT: - //da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; + // da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + switch (da2->bitblt.exec) { + case DA2_BLT_CIDLE: + timer_disable(&da2->bitblt.timer); + break; + case DA2_BLT_CLOAD: + da2->bitblt.indata = 0; + da2_bitblt_load(da2); + break; + case DA2_BLT_CFILLRECT: + // da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } else if (da2->bitblt.x == 0) { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } else { + DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); + da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - break; - case DA2_BLT_CFILLTILE: - int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CFILLTILE: + int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } else { + DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - break; - case DA2_BLT_CCOPYF: - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; + da2->bitblt.destaddr += 2; + break; + case DA2_BLT_CCOPYF: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; + } else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr += 2; - break; - case DA2_BLT_CCOPYR: - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) - { - da2->bitblt.exec = DA2_BLT_CDONE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr += 2; + break; + case DA2_BLT_CCOPYR: + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr -= da2->bitblt.destpitch; + da2->bitblt.srcaddr -= da2->bitblt.srcpitch; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + } else if (da2->bitblt.x == 0) { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } else { + DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr -= da2->bitblt.destpitch; - da2->bitblt.srcaddr -= da2->bitblt.srcpitch; da2->bitblt.destaddr -= 2; da2->bitblt.srcaddr -= 2; - } - else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } - else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - } - da2->bitblt.destaddr -= 2; - da2->bitblt.srcaddr -= 2; - break; - case DA2_BLT_CPUTCHAR: - //da2->bitblt.y += 2; - da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; - //pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); - //da2->bitblt.srcaddr += 2; - if(da2->bitblt.reg[0x12] < 0x100) - da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; - else - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - //print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); - //print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); - //pclog("\n"); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - //if (1) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 3) - { - da2->bitblt.exec = DA2_BLT_CDONE; + break; + case DA2_BLT_CPUTCHAR: + // da2->bitblt.y += 2; + da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; + // pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + // da2->bitblt.srcaddr += 2; + if (da2->bitblt.reg[0x12] < 0x100) + da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; + else + da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; + // print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); + // print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); + // pclog("\n"); + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + // if (1) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 3) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += 130; + // da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + // da2->bitblt.srcaddr += -1; + } else if (da2->bitblt.x == 0) { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + // da2->bitblt.x++; + } else { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; + // da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += 130; - //da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - //da2->bitblt.srcaddr += -1; - } - else if (da2->bitblt.x == 0) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - //da2->bitblt.x++; - } - //da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; - ////da2->bitblt.srcaddr += 2; - //da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; - break; - case DA2_BLT_CDONE: - /* initialize regs for debug dump */ - for (int i = 0; i < DA2_BLT_REGSIZE; i++) { - if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; - } - if(da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; - else da2->bitblt.exec = DA2_BLT_CIDLE; - break; + // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; + ////da2->bitblt.srcaddr += 2; + // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; + break; + case DA2_BLT_CDONE: + /* initialize regs for debug dump */ + for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) + da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + } + if (da2->bitblt.indata) + da2->bitblt.exec = DA2_BLT_CLOAD; + else + da2->bitblt.exec = DA2_BLT_CIDLE; + break; } } -void da2_bitblt_dopayload(da2_t* da2) { - if (da2->bitblt.exec == DA2_BLT_CIDLE) - { +void +da2_bitblt_dopayload(da2_t *da2) +{ + if (da2->bitblt.exec == DA2_BLT_CIDLE) { da2->bitblt.exec = DA2_BLT_CLOAD; - //timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ da2_log("da2 Do bitblt\n"); - while (da2->bitblt.exec != DA2_BLT_CIDLE) - { + while (da2->bitblt.exec != DA2_BLT_CIDLE) { da2_bitblt_exec(da2); } da2_log("da2 End bitblt %x\n", da2->bitblt.exec); } } -void da2_out(uint16_t addr, uint16_t val, void *p) +void +da2_out(uint16_t addr, uint16_t val, void *p) { - da2_t *da2 = (da2_t *)p; - int oldval; -/* -3E0 3E1 Sequencer Registers (undoc) -3E2 3E3 Font Registers (undoc) -3E4 3E5 CRT Control Registers (undoc) -3E8 3E9 Attribute Controller Registers (undoc) -3EA 3EB 3EC Graphics Contoller Registers -*/ - switch (addr) - { + da2_t *da2 = (da2_t *) p; + int oldval; + /* + 3E0 3E1 Sequencer Registers (undoc) + 3E2 3E3 Font Registers (undoc) + 3E4 3E5 CRT Control Registers (undoc) + 3E8 3E9 Attribute Controller Registers (undoc) + 3EA 3EB 3EC Graphics Contoller Registers + */ + switch (addr) { case 0x3c6: /* PEL Mask */ da2->dac_mask = val; break; case 0x3C7: /* Read Address */ da2->dac_read = val; - da2->dac_pos = 0; + da2->dac_pos = 0; break; case 0x3C8: /* Write Address */ da2->dac_write = val; - da2->dac_read = val - 1; - da2->dac_pos = 0; + da2->dac_read = val - 1; + da2->dac_pos = 0; break; case 0x3C9: /* Data */ - //da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); + // da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); da2->dac_status = 0; da2->fullchange = changeframecount; - switch (da2->dac_pos) - { - case 0: - da2->dac_r = val; - da2->dac_pos++; - break; - case 1: - da2->dac_g = val; - da2->dac_pos++; - break; - case 2: - da2->vgapal[da2->dac_write].r = da2->dac_r; - da2->vgapal[da2->dac_write].g = da2->dac_g; - da2->vgapal[da2->dac_write].b = val; - //if (da2->ramdac_type == RAMDAC_8BIT) - // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); - //else + switch (da2->dac_pos) { + case 0: + da2->dac_r = val; + da2->dac_pos++; + break; + case 1: + da2->dac_g = val; + da2->dac_pos++; + break; + case 2: + da2->vgapal[da2->dac_write].r = da2->dac_r; + da2->vgapal[da2->dac_write].g = da2->dac_g; + da2->vgapal[da2->dac_write].b = val; + // if (da2->ramdac_type == RAMDAC_8BIT) + // da2->pallook[da2->dac_write] = makecol32(da2->vgapal[da2->dac_write].r, da2->vgapal[da2->dac_write].g, da2->vgapal[da2->dac_write].b); + // else da2->pallook[da2->dac_write] = makecol32((da2->vgapal[da2->dac_write].r & 0x3f) * 4, (da2->vgapal[da2->dac_write].g & 0x3f) * 4, (da2->vgapal[da2->dac_write].b & 0x3f) * 4); - da2->dac_pos = 0; - da2->dac_write = (da2->dac_write + 1) & 255; - break; + da2->dac_pos = 0; + da2->dac_write = (da2->dac_write + 1) & 255; + break; } break; case LS_INDEX: da2->ioctladdr = val; break; case LS_DATA: - //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); - if (da2->ioctladdr > 0xf) return; + // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); + if (da2->ioctladdr > 0xf) + return; if (da2->ioctl[da2->ioctladdr & 15] != val) da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); - oldval = da2->ioctl[da2->ioctladdr]; + oldval = da2->ioctl[da2->ioctladdr]; da2->ioctl[da2->ioctladdr] = val; if (oldval != val) { if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset register */ @@ -1039,10 +1044,9 @@ void da2_out(uint16_t addr, uint16_t val, void *p) da2->fullchange = changeframecount; da2_recalctimings(da2); da2_updatevidselector(da2); - } - else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ + } else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ { - //da2->bitblt.indata = 1; + // da2->bitblt.indata = 1; } } break; @@ -1050,14 +1054,14 @@ void da2_out(uint16_t addr, uint16_t val, void *p) da2->fctladdr = val; break; case LF_DATA: - //da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); - if (da2->fctladdr > 0x1f) return; + // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + if (da2->fctladdr > 0x1f) + return; if (da2->fctl[da2->fctladdr & 0x1f] != val) da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); - oldval = da2->fctl[da2->fctladdr]; + oldval = da2->fctl[da2->fctladdr]; da2->fctl[da2->fctladdr] = val; - if (da2->fctladdr == 0 && oldval != val) - { + if (da2->fctladdr == 0 && oldval != val) { da2->fullchange = changeframecount; da2_recalctimings(da2); } @@ -1066,87 +1070,85 @@ void da2_out(uint16_t addr, uint16_t val, void *p) da2->crtcaddr = val; break; case LC_DATA: - if (da2->crtcaddr > 0x1f) return; - //if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) - // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); - if (!(da2->crtc[da2->crtcaddr] ^ val)) return; + if (da2->crtcaddr > 0x1f) + return; + // if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + if (!(da2->crtc[da2->crtcaddr] ^ val)) + return; switch (da2->crtcaddr) { - case LC_CRTC_OVERFLOW: - //return; - break; - case LC_MAXIMUM_SCAN_LINE: - if (!(da2->ioctl[LS_MODE] & 0x01)) val = 0; - break; - case LC_START_ADDRESS_HIGH: - //if (da2->crtc[0x1c] & 0x40) return; - break; - case LC_VERTICAL_TOTALJ: /* Vertical Total */ - case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ - case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ - case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ - //val = 0x400; //for debugging bitblt - break; - case LC_VIEWPORT_SELECT: /* ViewPort Select? */ - //return; - break; - case LC_VIEWPORT_NUMBER: /* Compatibility? */ - break; + case LC_CRTC_OVERFLOW: + // return; + break; + case LC_MAXIMUM_SCAN_LINE: + if (!(da2->ioctl[LS_MODE] & 0x01)) + val = 0; + break; + case LC_START_ADDRESS_HIGH: + // if (da2->crtc[0x1c] & 0x40) return; + break; + case LC_VERTICAL_TOTALJ: /* Vertical Total */ + case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ + case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ + case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ + // val = 0x400; /* for debugging bitblt in Win 3.x */ + break; + case LC_VIEWPORT_SELECT: /* ViewPort Select? */ + // return; + break; + case LC_VIEWPORT_NUMBER: /* Compatibility? */ + break; } da2->crtc[da2->crtcaddr] = val; switch (da2->crtcaddr) { - case LC_H_DISPLAY_ENABLE_END: - case LC_VERTICAL_TOTALJ: - case LC_MAXIMUM_SCAN_LINE: - case LC_START_ADDRESS_HIGH: - case LC_START_ADDRESS_LOW: - case LC_VERTICAL_SYNC_START: - case LC_V_DISPLAY_ENABLE_END: - case LC_START_VERTICAL_BLANK: - case LC_END_VERTICAL_BLANK: - case LC_VIEWPORT_PRIORITY: - da2->fullchange = changeframecount; - da2_recalctimings(da2); - break; - default: - break; + case LC_H_DISPLAY_ENABLE_END: + case LC_VERTICAL_TOTALJ: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + case LC_VERTICAL_SYNC_START: + case LC_V_DISPLAY_ENABLE_END: + case LC_START_VERTICAL_BLANK: + case LC_END_VERTICAL_BLANK: + case LC_VIEWPORT_PRIORITY: + da2->fullchange = changeframecount; + da2_recalctimings(da2); + break; + default: + break; } break; case LV_PORT: - //da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); - if (!da2->attrff) - { + // da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + if (!da2->attrff) { // da2->attraddr = val & 31; da2->attraddr = val & 0x3f; - if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) - { - da2->fullchange = 3; + if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) { + da2->fullchange = 3; da2->attr_palette_enable = val & 0x20; da2_recalctimings(da2); } - //da2_log("set attraddr: %X\n", da2->attraddr); - } - else - { + // da2_log("set attraddr: %X\n", da2->attraddr); + } else { if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val)) da2->fullchange = changeframecount; if (da2->attrc[da2->attraddr & 0x3f] != val) da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); da2->attrc[da2->attraddr & 0x3f] = val; - //da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); + // da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); if (da2->attraddr < 16) da2->fullchange = changeframecount; - if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) - { - for (int c = 0; c < 16; c++) - { - //if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); - //else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); - if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = da2->attrc[c] & 0xf; - else da2->egapal[c] = da2->attrc[c] & 0x3f; + if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) { + for (int c = 0; c < 16; c++) { + // if (da2->attrc[LV_MODE_CONTROL] & 0x80) da2->egapal[c] = (da2->attrc[c] & 0xf) | ((da2->attrc[0x14] & 0xf) << 4); + // else da2->egapal[c] = (da2->attrc[c] & 0x3f) | ((da2->attrc[0x14] & 0xc) << 4); + if (da2->attrc[LV_MODE_CONTROL] & 0x80) + da2->egapal[c] = da2->attrc[c] & 0xf; + else + da2->egapal[c] = da2->attrc[c] & 0x3f; } } - switch (da2->attraddr) - { + switch (da2->attraddr) { case LV_COLOR_PLANE_ENAB: if ((val & 0xff) != da2->plane_mask) da2->fullchange = changeframecount; @@ -1154,15 +1156,15 @@ void da2_out(uint16_t addr, uint16_t val, void *p) break; case LV_CURSOR_CONTROL: switch (val & 0x18) { - case 0x08://fast blink - da2->blinkconf = 0x10; - break; - case 0x18://slow blink - da2->blinkconf = 0x20; - break; - default://no blink - da2->blinkconf = 0xff; - break; + case 0x08: /* fast blink */ + da2->blinkconf = 0x10; + break; + case 0x18: /* slow blink */ + da2->blinkconf = 0x20; + break; + default: /* no blink */ + da2->blinkconf = 0xff; + break; } break; case LV_MODE_CONTROL: @@ -1184,79 +1186,81 @@ void da2_out(uint16_t addr, uint16_t val, void *p) da2->gdcaddr = val; break; case LG_DATA: - //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); - //if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); - switch (da2->gdcaddr & 0x1f) - { - case LG_READ_MAP_SELECT: - da2->readplane = val & 0x7; - break; - case LG_MODE: - da2->writemode = val & 3; - break; - case LG_MAP_MASKJ: - da2->writemask = val & 0xff; - break; - case LG_COMMAND: - break; - case LG_SET_RESET_2: - da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); - return; + // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + switch (da2->gdcaddr & 0x1f) { + case LG_READ_MAP_SELECT: + da2->readplane = val & 0x7; + break; + case LG_MODE: + da2->writemode = val & 3; + break; + case LG_MAP_MASKJ: + da2->writemask = val & 0xff; + break; + case LG_COMMAND: + break; + case LG_SET_RESET_2: + da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); + return; } da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; break; - //case 0x3ed: /* used by Windows 3.1 display driver */ - // da2->gdcreg[5] = val & 0xff; - // break; + // case 0x3ed: /* used by Windows 3.1 display driver */ + // da2->gdcreg[5] = val & 0xff; + // break; default: da2_log("DA2? Out addr %03X val %02X\n", addr, val); break; - } + } } -uint16_t da2_in(uint16_t addr, void *p) +uint16_t +da2_in(uint16_t addr, void *p) { - da2_t * da2 = (da2_t *)p; - uint16_t temp; + da2_t *da2 = (da2_t *) p; + uint16_t temp; - switch (addr) - { + switch (addr) { case 0x3c3: temp = 0; break; - case 0x3c6: temp = da2->dac_mask; + case 0x3c6: + temp = da2->dac_mask; break; - case 0x3c7: temp = da2->dac_status; + case 0x3c7: + temp = da2->dac_status; break; - case 0x3c8: temp = da2->dac_write; + case 0x3c8: + temp = da2->dac_write; break; case 0x3c9: da2->dac_status = 3; - switch (da2->dac_pos) - { - case 0: - da2->dac_pos++; - temp = da2->vgapal[da2->dac_read].r & 0x3f; - break; - case 1: - da2->dac_pos++; - temp = da2->vgapal[da2->dac_read].g & 0x3f; - break; - case 2: - da2->dac_pos = 0; - da2->dac_read = (da2->dac_read + 1) & 255; - temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; - break; + switch (da2->dac_pos) { + case 0: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].r & 0x3f; + break; + case 1: + da2->dac_pos++; + temp = da2->vgapal[da2->dac_read].g & 0x3f; + break; + case 2: + da2->dac_pos = 0; + da2->dac_read = (da2->dac_read + 1) & 255; + temp = da2->vgapal[(da2->dac_read - 1) & 255].b & 0x3f; + break; } break; case LS_INDEX: temp = da2->ioctladdr; break; case LS_DATA: - //da2->ioctl[3] = 0x80; /* 3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) */ - if (da2->ioctladdr > 0xf) return DA2_INVALIDACCESS8; + // da2->ioctl[3] = 0x80; /* 3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) */ + if (da2->ioctladdr > 0xf) + return DA2_INVALIDACCESS8; temp = da2->ioctl[da2->ioctladdr]; - if (da2->ioctladdr == LS_STATUS) { /* Status register */ + if (da2->ioctladdr == LS_STATUS) { /* Status register */ if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ if (da2->monitorid == DA2_DCONFIG_MONTYPE_MONO) { /* grayscale monitor */ @@ -1275,54 +1279,54 @@ uint16_t da2_in(uint16_t addr, void *p) } else { temp |= 0x80; } - temp &= 0xf6;//clear busy bits + temp &= 0xf6; /* clear busy bit */ if (da2->bitblt.indata) /* for OS/2 J1.3 */ da2_bitblt_dopayload(da2); - if (da2->bitblt.exec != DA2_BLT_CIDLE) - { - //da2_log("exec:%x\n", da2->bitblt.exec); - temp |= 0x08;//wait(bit 3 + bit 0) - //if (!da2->bitblt.timer.enabled) + if (da2->bitblt.exec != DA2_BLT_CIDLE) { + // da2_log("exec:%x\n", da2->bitblt.exec); + temp |= 0x08; // wait(bit 3 + bit 0) + // if (!da2->bitblt.timer.enabled) //{ - // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); - // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - //} + // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); + // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + // } } if (da2->bitblt.indata) temp |= 0x01; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); } - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); break; case LF_INDEX: temp = da2->fctladdr; break; case LF_DATA: - if (da2->fctladdr > 0x1f) return DA2_INVALIDACCESS8; + if (da2->fctladdr > 0x1f) + return DA2_INVALIDACCESS8; temp = da2->fctl[da2->fctladdr]; break; case LC_INDEX: temp = da2->crtcaddr; break; case LC_DATA: - if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS8; + if (da2->crtcaddr > 0x1f) + return DA2_INVALIDACCESS8; temp = da2->crtc[da2->crtcaddr]; break; case LV_PORT: temp = da2->attraddr | da2->attr_palette_enable; break; case 0x3E9: - if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this maybe equivalent to 3ba / 3da Input Status Register 1 */ + if (da2->attraddr == LV_RAS_STATUS_VIDEO) /* this maybe equivalent to 3ba / 3da ISR1 */ { if (da2->cgastat & 0x01) da2->cgastat &= ~0x30; else da2->cgastat ^= 0x30; temp = da2->cgastat; - } - else + } else temp = da2->attrc[da2->attraddr]; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); + // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ break; case LG_INDEX: @@ -1330,149 +1334,145 @@ uint16_t da2_in(uint16_t addr, void *p) break; case LG_DATA: temp = da2->gdcreg[da2->gdcaddr & 0x1f]; - //da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); break; - } - //da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); - return temp; + } + // da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; } /* -* Write I/O -* out b(idx), out b(data), out b(data) -* out b(idx), out w(data) -* out b(idx), out w(data), out b(data) -* out w(idx) -* Read I/O -* out b(idx), in b(data) -* out b(idx), in b, in b(data) -* out b(idx), in w(data) -*/ -void da2_outb(uint16_t addr, uint8_t val, void* p) + * Write I/O + * out b(idx), out b(data), out b(data) + * out b(idx), out w(data) + * out b(idx), out w(data), out b(data) + * out w(idx) + * Read I/O + * out b(idx), in b(data) + * out b(idx), in b, in b(data) + * out b(idx), in w(data) + */ +void +da2_outb(uint16_t addr, uint8_t val, void *p) { - da2_t* da2 = (da2_t*)p; - //da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + da2_t *da2 = (da2_t *) p; + // da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); da2->inflipflop = 0; - switch (addr) - { - case LS_DATA: - case LF_DATA: - case LC_DATA: - case LG_DATA: - if (da2->outflipflop) - { - /* out b(idx), out b(data), out b(data) */ - da2->iolatch |= (uint16_t)val << 8; + switch (addr) { + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + if (da2->outflipflop) { + /* out b(idx), out b(data), out b(data) */ + da2->iolatch |= (uint16_t) val << 8; + da2->outflipflop = 0; + } else { // + da2->iolatch = val; + da2->outflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + default: + da2->iolatch = val; da2->outflipflop = 0; - } - else - {// - da2->iolatch = val; - da2->outflipflop = 1; - } - break; - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - default: - da2->iolatch = val; - da2->outflipflop = 0; - break; + break; } da2_out(addr, da2->iolatch, da2); } -void da2_outw(uint16_t addr, uint16_t val, void* p) +void +da2_outw(uint16_t addr, uint16_t val, void *p) { - //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_t* da2 = (da2_t*)p; + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; - switch (addr) - { - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - da2_out(addr, val & 0xff, da2); - da2->iolatch = val >> 8; - da2_out(addr + 1, da2->iolatch, da2); - da2->outflipflop = 1; - break; - case LV_PORT: - da2->attrff = 0; + switch (addr) { + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + da2_out(addr, val & 0xff, da2); + da2->iolatch = val >> 8; + da2_out(addr + 1, da2->iolatch, da2); + da2->outflipflop = 1; + break; + case LV_PORT: + da2->attrff = 0; da2_out(addr, val & 0xff, da2); da2_out(addr, val >> 8, da2); da2->outflipflop = 0; - break; - case 0x3EC: - //da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_out(LG_DATA, val >> 8, da2); - break; - case 0x3ED: - da2->gdcaddr = LG_MODE; - da2_out(LG_DATA, val, da2); - break; - case LS_DATA: - case LF_DATA: - case LC_DATA: - case LG_DATA: - default: - da2_out(addr, val, da2); - da2->outflipflop = 0; - break; - case 0x3EE: - da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2->reg3ee[val & 0xff] = val >> 8; - break; + break; + case 0x3EC: + // da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_out(LG_DATA, val >> 8, da2); + break; + case 0x3ED: + da2->gdcaddr = LG_MODE; + da2_out(LG_DATA, val, da2); + break; + case LS_DATA: + case LF_DATA: + case LC_DATA: + case LG_DATA: + default: + da2_out(addr, val, da2); + da2->outflipflop = 0; + break; + case 0x3EE: + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2->reg3ee[val & 0xff] = val >> 8; + break; } } -uint8_t da2_inb(uint16_t addr, void* p) +uint8_t +da2_inb(uint16_t addr, void *p) { uint8_t temp; - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; da2->outflipflop = 0; - switch (addr) - { - case LC_DATA: - if (da2->inflipflop) - { - /* out b(idx), in b(low data), in b(high data) */ - temp = da2->iolatch >> 8; + switch (addr) { + case LC_DATA: + if (da2->inflipflop) { + /* out b(idx), in b(low data), in b(high data) */ + temp = da2->iolatch >> 8; + da2->inflipflop = 0; + } else { // + da2->iolatch = da2_in(addr, da2); + temp = da2->iolatch & 0xff; + da2->inflipflop = 1; + } + break; + case LS_INDEX: + case LF_INDEX: + case LC_INDEX: + case LG_INDEX: + case LS_DATA: + case LF_DATA: + case LG_DATA: + default: + temp = da2_in(addr, da2) & 0xff; da2->inflipflop = 0; - } - else - {// - da2->iolatch = da2_in(addr, da2); - temp = da2->iolatch & 0xff; - da2->inflipflop = 1; - } - break; - case LS_INDEX: - case LF_INDEX: - case LC_INDEX: - case LG_INDEX: - case LS_DATA: - case LF_DATA: - case LG_DATA: - default: - temp = da2_in(addr, da2) & 0xff; - da2->inflipflop = 0; - break; + break; } - //da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + // da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); return temp; } -uint16_t da2_inw(uint16_t addr, void* p) +uint16_t +da2_inw(uint16_t addr, void *p) { - //uint16_t temp; - da2_t* da2 = (da2_t*)p; - da2->inflipflop = 0; + // uint16_t temp; + da2_t *da2 = (da2_t *) p; + da2->inflipflop = 0; da2->outflipflop = 0; return da2_in(addr, da2); } -/* IO 03DAh : Input Status Register 2 for DOSSHELL in DOS J4.0 */ -uint8_t da2_in_ISR(uint16_t addr, void* p) +/* IO 03DAh : Input Status Register 2 for DOSSHELL used by DOS J4.0 */ +uint8_t +da2_in_ISR(uint16_t addr, void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; uint8_t temp = 0; if (addr == 0x3da) { if (da2->cgastat & 0x01) @@ -1481,13 +1481,14 @@ uint8_t da2_in_ISR(uint16_t addr, void* p) da2->cgastat ^= 0x30; temp = da2->cgastat; } - //da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + // da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); return temp; } -void da2_out_ISR(uint16_t addr, uint8_t val, void* p) +void +da2_out_ISR(uint16_t addr, uint8_t val, void *p) { - //da2_t* da2 = (da2_t*)p; + // da2_t* da2 = (da2_t*)p; da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); } @@ -1592,29 +1593,30 @@ The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. */ /* Get character line pattern from jfont rom or gaiji volatile memory */ -uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { - da2_t* da2 = (da2_t*)p; - uint32_t font = 0; - int32_t fline = line - 2;/* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ - if (code >= 0x8000 && code <= 0x8183) code -= 0x6000;//shift for IBM extended characters (I don't know how the real card works.) */ +uint32_t +getfont_ps55dbcs(int32_t code, int32_t line, void *p) +{ + da2_t *da2 = (da2_t *) p; + uint32_t font = 0; + int32_t fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ + if (code >= 0x8000 && code <= 0x8183) + code -= 0x6000; /* shift for IBM extended characters (I don't know how the real card works.) */ if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { - font = da2->mmio.font[code * 72 + fline * 3]; /* 1111 1111 */ - font <<= 8; /* 1111 1111 0000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; /* 1111 1111 2222 0000 */ - font >>= 1; /* 0111 1111 1222 2000 */ - font <<= 4; /* 0111 1111 1222 2000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; /* 0111 1111 1222 2000 2222 */ - font <<= 8; /* 0111 1111 1222 2000 2222 0000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 2]; /* 0111 1111 1222 2000 2222 3333 3333 */ - font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ + font = da2->mmio.font[code * 72 + fline * 3]; /* 1111 1111 */ + font <<= 8; /* 1111 1111 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; /* 1111 1111 2222 0000 */ + font >>= 1; /* 0111 1111 1222 2000 */ + font <<= 4; /* 0111 1111 1222 2000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; /* 0111 1111 1222 2000 2222 */ + font <<= 8; /* 0111 1111 1222 2000 2222 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; /* 0111 1111 1222 2000 2222 3333 3333 */ + font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ /* font >>= 1;//put blank at column 1 (and 26) */ - } - else if (code >= 0xb000 && code <= 0xb75f) - { + } else if (code >= 0xb000 && code <= 0xb75f) { /* convert code->address in gaiji memory */ code -= 0xb000; code *= 0x80; - //code += 0xf800; + // code += 0xf800; font = da2->mmio.ram[code + line * 4]; font <<= 8; font |= da2->mmio.ram[code + line * 4 + 1]; @@ -1622,8 +1624,7 @@ uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { font |= da2->mmio.ram[code + line * 4 + 2]; font <<= 8; font |= da2->mmio.ram[code + line * 4 + 3]; - } - else if (code > DA2_FONTROM_SIZE) + } else if (code > DA2_FONTROM_SIZE) font = 0xffffffff; else font = 0; @@ -1631,23 +1632,27 @@ uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void* p) { } /* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ -uint8_t IRGBtoBGRI(uint8_t attr) +uint8_t +IRGBtoBGRI(uint8_t attr) { attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); return attr >>= 4; } /* Get the foreground color from the attribute byte */ -uint8_t getPS55ForeColor(uint8_t attr, da2_t* da2) +uint8_t +getPS55ForeColor(uint8_t attr, da2_t *da2) { - uint8_t foreground = ~attr & 0x08;// 0000 1000 */ - foreground <<= 2; /* 0010 0000 */ - foreground |= ~attr & 0xc0;/* 1110 0000 */ - foreground >>= 4;/* 0000 1110 */ - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) foreground |= 0x01;/* bright color palette */ + uint8_t foreground = ~attr & 0x08; /* 0000 1000 */ + foreground <<= 2; /* 0010 0000 */ + foreground |= ~attr & 0xc0; /* 1110 0000 */ + foreground >>= 4; /* 0000 1110 */ + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x40) + foreground |= 0x01; /* bright color palette */ return foreground; } -void da2_render_blank(da2_t* da2) +void +da2_render_blank(da2_t *da2) { int x, xx; @@ -1655,67 +1660,68 @@ void da2_render_blank(da2_t* da2) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - for (x = 0; x < da2->hdisp; x++) - { - for (xx = 0; xx < 13; xx++) ((uint32_t*)buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; + for (x = 0; x < da2->hdisp; x++) { + for (xx = 0; xx < 13; xx++) + ((uint32_t *) buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; } } /* Display Adapter Mode 8, E Drawing */ -static void da2_render_text(da2_t* da2) +static void +da2_render_text(da2_t *da2) { if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - if (da2->fullchange) - { - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - int x; - int drawcursor; - uint8_t chr, attr; - int fg, bg; - uint32_t chr_dbcs; - int chr_wide = 0; - //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); - for (x = 0; x < da2->hdisp; x += 13) - { - chr = da2->cram[(da2->ma) & da2->vram_display_mask]; + if (da2->fullchange) { + int offset = (8 - da2->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) { + chr = da2->cram[(da2->ma) & da2->vram_display_mask]; attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; - //if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80)/* IO 3E8h, Index 1Dh */ - {/* --Parse attribute byte in color mode-- */ - bg = 0;/* bg color is always black (the only way to change background color is programming PAL) */ + // if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); + if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) /* IO 3E8h, Index 1Dh */ + { /* --Parse attribute byte in color mode-- */ + bg = 0; /* bg color is always black (the only way to change background color is programming PAL) */ fg = getPS55ForeColor(attr, da2); - if (attr & 0x04) {/* reverse 0000 0100 */ + if (attr & 0x04) { /* reverse 0000 0100 */ bg = fg; fg = 0; } - } - else - {/* --Parse attribute byte in monochrome mode-- */ - if (attr & 0x08) fg = 3;/* Highlight 0000 1000 */ - else fg = 2; - bg = 0;/* Background is always color #0 (default is black) */ - if (!(~attr & 0xCC))/* Invisible 11xx 11xx -> 00xx 00xx */ + } else { /* --Parse attribute byte in monochrome mode-- */ + if (attr & 0x08) + fg = 3; /* Highlight 0000 1000 */ + else + fg = 2; + bg = 0; /* Background is always color #0 (default is black) */ + if (!(~attr & 0xCC)) /* Invisible 11xx 11xx -> 00xx 00xx */ { fg = bg; - attr &= 0x33;/* disable blinkking, underscore, highlight and reverse */ + attr &= 0x33; /* disable blinkking, underscore, highlight and reverse */ } - if (attr & 0x04) {/* reverse 0000 0100 */ + if (attr & 0x04) { /* reverse 0000 0100 */ bg = fg; fg = 0; } /* Blinking 1000 0000 */ fg = ((da2->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; - //if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); + // if(chr!=0x20) da2_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, da2->egapal[fg], da2->pallook[da2->egapal[fg]]); } /* Draw character */ - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];/* draw blank */ + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[bg]]; /* draw blank */ /* SBCS or DBCS left half */ if (chr_wide == 0) { - if (attr & 0x01) chr_wide = 1; - //chr_wide = 0; + if (attr & 0x01) + chr_wide = 1; + // chr_wide = 0; /* Stay drawing If the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ @@ -1729,18 +1735,17 @@ static void da2_render_text(da2_t* da2) p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; font <<= 1; } - } - else { + } else { /* the char code is SBCS (ANK) */ uint32_t fontbase; - if (attr & 0x02)/* second map of SBCS font */ + if (attr & 0x02) /* second map of SBCS font */ fontbase = DA2_GAIJIRAM_SBEX; else fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];/* w13xh29 font */ + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];/* w13xh29 font */ - //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ + // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -1749,8 +1754,7 @@ static void da2_render_text(da2_t* da2) } } /* right half of DBCS */ - else - { + else { uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { @@ -1760,27 +1764,26 @@ static void da2_render_text(da2_t* da2) chr_wide = 0; } /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ - if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) {/* Underscore only in monochrome mode */ + if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) { /* Underscore only in monochrome mode */ for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[fg]];/* under line (white) */ + p[n] = da2->pallook[da2->egapal[fg]]; /* under line (white) */ } /* Column 1 (Vertical Line) */ if (attr & 0x10) { - p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];/* vertical line (white) */ + p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */ } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) {/* HGrid */ + if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) { /* HGrid */ for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]];/* horizontal line (white) */ + p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */ } /* Drawing text cursor */ drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) - { + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); - int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2;/* Choose color 2 if mode 8 */ - fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); - bg = 0; - if (attr & 0x04) {/* Color 0 if reverse */ + int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */ + fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) { /* Color 0 if reverse */ bg = fg; fg = 0; } @@ -1794,45 +1797,46 @@ static void da2_render_text(da2_t* da2) p += 13; } da2->ma &= da2->vram_display_mask; - //da2->writelines++; + // da2->writelines++; } } /* Display Adapter Mode 3 Drawing */ -static void da2_render_textm3(da2_t* da2) +static void +da2_render_textm3(da2_t *da2) { if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - if (da2->fullchange) - { - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - int x; - int drawcursor; - uint8_t chr, attr, extattr; - int fg, bg; - uint32_t chr_dbcs; - int chr_wide = 0; - //da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); - for (x = 0; x < da2->hdisp; x += 13) - { - chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; - attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; + if (da2->fullchange) { + int offset = (8 - da2->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[da2->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr, extattr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + for (x = 0; x < da2->hdisp; x += 13) { + chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; + attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; - //if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); + // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; - //if (da2->blink) bg &= ~0x8; - //fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; + // if (da2->blink) bg &= ~0x8; + // fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; fg = attr & 0xf; fg = IRGBtoBGRI(fg); bg = IRGBtoBGRI(bg); /* Draw character */ - for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[bg]];/* draw blank */ + for (uint32_t n = 0; n < 13; n++) + p[n] = da2->pallook[da2->egapal[bg]]; /* draw blank */ /* BCS or DBCS left half */ if (chr_wide == 0) { - if (extattr & 0x01) chr_wide = 1; + if (extattr & 0x01) + chr_wide = 1; /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ @@ -1846,15 +1850,14 @@ static void da2_render_textm3(da2_t* da2) p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; font <<= 1; } - } - else { + } else { /* the char code is SBCS (ANK) */ uint32_t fontbase; - fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2];/* w13xh29 font */ + fontbase = DA2_GAIJIRAM_SBCS; + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1];/* w13xh29 font */ - //if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ + // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; font <<= 1; @@ -1862,8 +1865,7 @@ static void da2_render_textm3(da2_t* da2) } } /* right half of DBCS */ - else - { + else { uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { @@ -1873,16 +1875,15 @@ static void da2_render_textm3(da2_t* da2) chr_wide = 0; } drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) - { - //int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); - //int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ - //fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; - //bg = 0; - //if (attr & 0x04) {/* Color 0 if reverse */ - // bg = fg; - // fg = 0; - //} + if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { + // int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); + // int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ + // fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + // bg = 0; + // if (attr & 0x04) {/* Color 0 if reverse */ + // bg = fg; + // fg = 0; + // } for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[fg]]; } @@ -1890,562 +1891,550 @@ static void da2_render_textm3(da2_t* da2) p += 13; } da2->ma &= da2->vram_display_mask; - //da2->writelines++; + // da2->writelines++; } } -void da2_render_color_4bpp(da2_t* da2) +void +da2_render_color_4bpp(da2_t *da2) { int changed_offset = da2->ma >> 12; - //da2_log("ma %x cf %x\n", da2->ma, changed_offset); + // da2_log("ma %x cf %x\n", da2->ma, changed_offset); da2->plane_mask &= 0x0f; /*safety */ - if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) - { - int x; - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[da2->displine])[offset]; if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - //da2_log("d %X\n", da2->ma); - - for (x = 0; x <= da2->hdisp; x += 8)/* hdisp = 1024 */ - { - uint8_t edat[8]; - uint8_t dat; - - /* get 8 pixels from vram */ - da2->ma &= da2->vram_display_mask; - *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); - da2->ma += 1; - - dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); - p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); - p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); - p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); - p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); - p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); - p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); - p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); - p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; - p += 8; - } - //da2->writelines++; - } -} - -void da2_render_color_8bpp(da2_t* da2) -{ - int changed_offset = da2->ma >> 12; - //da2_log("ma %x cf %x\n", da2->ma, changed_offset); - - if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) - { - int x; - int offset = (8 - da2->scrollcache) + 24; - uint32_t* p = &((uint32_t*)buffer32->line[da2->displine])[offset]; - - if (da2->firstline_draw == 2000) - da2->firstline_draw = da2->displine; - da2->lastline_draw = da2->displine; - //da2_log("d %X\n", da2->ma); + // da2_log("d %X\n", da2->ma); for (x = 0; x <= da2->hdisp; x += 8) /* hdisp = 1024 */ { uint8_t edat[8]; uint8_t dat; - //get 8 pixels from vram + /* get 8 pixels from vram */ da2->ma &= da2->vram_display_mask; - *(uint32_t*)(&edat[0]) = *(uint32_t*)(&da2->vram[da2->ma << 3]); - *(uint32_t*)(&edat[4]) = *(uint32_t*)(&da2->vram[(da2->ma << 3) + 4]); + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->ma << 3]); da2->ma += 1; - dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | - ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); - p[0] = da2->pallook[dat]; - dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | - ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); - p[1] = da2->pallook[dat]; - dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | - ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); - p[2] = da2->pallook[dat]; - dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | - ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); - p[3] = da2->pallook[dat]; - dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | - ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); - p[4] = da2->pallook[dat]; - dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | - ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); - p[5] = da2->pallook[dat]; - dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | - ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); - p[6] = da2->pallook[dat]; - dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | - ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); - p[7] = da2->pallook[dat]; + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); + p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)); + p[1] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)); + p[2] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)); + p[3] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)); + p[4] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)); + p[5] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)); + p[6] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)); + p[7] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; p += 8; } - //da2->writelines++; + // da2->writelines++; } } -void da2_updatevidselector(da2_t* da2) { - /* if VGA passthrough mode */ +void +da2_render_color_8bpp(da2_t *da2) +{ + int changed_offset = da2->ma >> 12; + // da2_log("ma %x cf %x\n", da2->ma, changed_offset); + + if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { + int x; + int offset = (8 - da2->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[da2->displine])[offset]; + + if (da2->firstline_draw == 2000) + da2->firstline_draw = da2->displine; + da2->lastline_draw = da2->displine; + // da2_log("d %X\n", da2->ma); + + for (x = 0; x <= da2->hdisp; x += 8) /* hdisp = 1024 */ + { + uint8_t edat[8]; + uint8_t dat; + + /* get 8 pixels from vram */ + da2->ma &= da2->vram_display_mask; + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->ma << 3]); + *(uint32_t *) (&edat[4]) = *(uint32_t *) (&da2->vram[(da2->ma << 3) + 4]); + da2->ma += 1; + + dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); + p[0] = da2->pallook[dat]; + dat = ((edat[0] >> 6) & (1 << 0)) | ((edat[1] >> 5) & (1 << 1)) | ((edat[2] >> 4) & (1 << 2)) | ((edat[3] >> 3) & (1 << 3)) | ((edat[4] >> 2) & (1 << 4)) | ((edat[5] >> 1) & (1 << 5)) | ((edat[6] >> 0) & (1 << 6)) | ((edat[7] << 1) & (1 << 7)); + p[1] = da2->pallook[dat]; + dat = ((edat[0] >> 5) & (1 << 0)) | ((edat[1] >> 4) & (1 << 1)) | ((edat[2] >> 3) & (1 << 2)) | ((edat[3] >> 2) & (1 << 3)) | ((edat[4] >> 1) & (1 << 4)) | ((edat[5] >> 0) & (1 << 5)) | ((edat[6] << 1) & (1 << 6)) | ((edat[7] << 2) & (1 << 7)); + p[2] = da2->pallook[dat]; + dat = ((edat[0] >> 4) & (1 << 0)) | ((edat[1] >> 3) & (1 << 1)) | ((edat[2] >> 2) & (1 << 2)) | ((edat[3] >> 1) & (1 << 3)) | ((edat[4] >> 0) & (1 << 4)) | ((edat[5] << 1) & (1 << 5)) | ((edat[6] << 2) & (1 << 6)) | ((edat[7] << 3) & (1 << 7)); + p[3] = da2->pallook[dat]; + dat = ((edat[0] >> 3) & (1 << 0)) | ((edat[1] >> 2) & (1 << 1)) | ((edat[2] >> 1) & (1 << 2)) | ((edat[3] >> 0) & (1 << 3)) | ((edat[4] << 1) & (1 << 4)) | ((edat[5] << 2) & (1 << 5)) | ((edat[6] << 3) & (1 << 6)) | ((edat[7] << 4) & (1 << 7)); + p[4] = da2->pallook[dat]; + dat = ((edat[0] >> 2) & (1 << 0)) | ((edat[1] >> 1) & (1 << 1)) | ((edat[2] >> 0) & (1 << 2)) | ((edat[3] << 1) & (1 << 3)) | ((edat[4] << 2) & (1 << 4)) | ((edat[5] << 3) & (1 << 5)) | ((edat[6] << 4) & (1 << 6)) | ((edat[7] << 5) & (1 << 7)); + p[5] = da2->pallook[dat]; + dat = ((edat[0] >> 1) & (1 << 0)) | ((edat[1] >> 0) & (1 << 1)) | ((edat[2] << 1) & (1 << 2)) | ((edat[3] << 2) & (1 << 3)) | ((edat[4] << 3) & (1 << 4)) | ((edat[5] << 4) & (1 << 5)) | ((edat[6] << 5) & (1 << 6)) | ((edat[7] << 6) & (1 << 7)); + p[6] = da2->pallook[dat]; + dat = ((edat[0] >> 0) & (1 << 0)) | ((edat[1] << 1) & (1 << 1)) | ((edat[2] << 2) & (1 << 2)) | ((edat[3] << 3) & (1 << 3)) | ((edat[4] << 4) & (1 << 4)) | ((edat[5] << 5) & (1 << 5)) | ((edat[6] << 6) & (1 << 6)) | ((edat[7] << 7) & (1 << 7)); + p[7] = da2->pallook[dat]; + p += 8; + } + // da2->writelines++; + } +} + +void +da2_updatevidselector(da2_t *da2) +{ da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); - if (da2->ioctl[LS_MODE] & 0x02) - { + if (da2->ioctl[LS_MODE] & 0x02) { + /* VGA passthrough mode */ da2->override = 1; svga_set_override(da2->mb_vga, 0); - } - else - { + } else { svga_set_override(da2->mb_vga, 1); da2->override = 0; } } -void da2_recalctimings(da2_t* da2) +void +da2_recalctimings(da2_t *da2) { double crtcconst; double _dispontime, _dispofftime, disptime; - da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff;//w - da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff;//w - da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff;//w - da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff;//w Line Compare - da2->split = 0xfff; - da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;//w - da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; + da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; + da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; + da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff; + da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff; + da2->split = 0xfff; + da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; + da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { da2->hdisp--; da2->dispend -= 29; - } - else { - //da2->vtotal += 2; + } else { + // da2->vtotal += 2; da2->dispend--; - //da2->vsyncstart++; - //da2->split++; - //da2->vblankstart++; - //da2->hdisp--; + // da2->vsyncstart++; + // da2->split++; + // da2->vblankstart++; + // da2->hdisp--; } da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; da2->htotal += 1; - da2->rowoffset = da2->crtc[LC_OFFSET];/* number of bytes in a scanline */ + da2->rowoffset = da2->crtc[LC_OFFSET]; /* number of bytes in a scanline */ da2->clock = da2->da2const; - //da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; + // da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; - //da2->interlace = 0; + // da2->interlace = 0; - //da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b + // da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b da2->ca_adj = 0; da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; da2->hdisp_time = da2->hdisp; - da2->render = da2_render_blank; + da2->render = da2_render_blank; /* determine display mode */ - //if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) - if (da2->attrc[LV_COMPATIBILITY] & 0x08) - { + // if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) + if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* 16 color graphics mode */ if (!(da2->ioctl[LS_MODE] & 0x01)) { da2->hdisp *= 16; da2->char_width = 13; - da2->hdisp_old = da2->hdisp; + da2->hdisp_old = da2->hdisp; if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { da2_log("Set videomode to PS/55 8 bpp graphics.\n"); - da2->render = da2_render_color_8bpp; + da2->render = da2_render_color_8bpp; da2->vram_display_mask = DA2_MASK_GRAM; - } - else {/* PS/55 8-color */ + } else { /* PS/55 8-color */ da2_log("Set videomode to PS/55 4 bpp graphics.\n"); da2->vram_display_mask = DA2_MASK_GRAM; - da2->render = da2_render_color_4bpp; + da2->render = da2_render_color_4bpp; } - } - else { + } else { /* text mode */ if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { da2_log("Set videomode to PS/55 Mode 03 text.\n"); - da2->render = da2_render_textm3; + da2->render = da2_render_textm3; da2->vram_display_mask = DA2_MASK_CRAM; } /* PS/55 text(color/mono) */ else { da2_log("Set videomode to PS/55 Mode 8/E text.\n"); - da2->render = da2_render_text; + da2->render = da2_render_text; da2->vram_display_mask = DA2_MASK_CRAM; } da2->hdisp *= 13; - da2->hdisp_old = da2->hdisp; + da2->hdisp_old = da2->hdisp; da2->char_width = 13; } - } - else - { + } else { da2_log("Set videomode to blank.\n"); } - //if (!da2->scrblank && da2->attr_palette_enable) + // if (!da2->scrblank && da2->attr_palette_enable) //{ - //da2->render = da2_draw_text; + // da2->render = da2_draw_text; //} - //da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - //if (da2->recalctimings_ex) - // da2->recalctimings_ex(da2); + // if (da2->recalctimings_ex) + // da2->recalctimings_ex(da2); if (da2->vblankstart < da2->dispend) da2->dispend = da2->vblankstart; crtcconst = da2->clock * da2->char_width; - disptime = da2->htotal; + disptime = da2->htotal; _dispontime = da2->hdisp_time; da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); - //if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + // if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; _dispofftime *= crtcconst; - da2->dispontime = (uint64_t)_dispontime; - da2->dispofftime = (uint64_t)_dispofftime; + da2->dispontime = (uint64_t) _dispontime; + da2->dispofftime = (uint64_t) _dispofftime; if (da2->dispontime < TIMER_USEC) da2->dispontime = TIMER_USEC; if (da2->dispofftime < TIMER_USEC) da2->dispofftime = TIMER_USEC; - da2_log("da2 horiz total %i display end %i vidclock %f\n",da2->crtc[0],da2->crtc[1],da2->clock); - //da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); - //da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + da2_log("da2 horiz total %i display end %i vidclock %f\n", da2->crtc[0], da2->crtc[1], da2->clock); + // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); - //da2_log("da2->render %08X\n", da2->render); + // da2_log("da2->render %08X\n", da2->render); } -uint8_t da2_mca_read(int port, void *p) +static void +da2_mapping_update(da2_t *da2) { - da2_t *da2 = (da2_t *)p; - return da2->pos_regs[port & 7]; + /* Has the CardEnable bit been changed? */ + if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) + return; + da2->old_pos2 = da2->pos_regs[2]; + // da2_recalc_mapping(da2); + if (da2->pos_regs[2] & 0x01) { + da2_log("DA2 enable registers\n"); + for (int i = 0; i < 8; i++) + da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); + io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + mem_mapping_enable(&da2->cmapping); + mem_mapping_enable(&da2->mmio.mapping); + timer_enable(&da2->timer); + } else { + da2_log("DA2 disable registers\n"); + timer_disable(&da2->timer); + mem_mapping_disable(&da2->cmapping); + mem_mapping_disable(&da2->mmio.mapping); + io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); + io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); + } } -static void da2_mapping_update(da2_t *da2) +uint8_t +da2_mca_read(int port, void *p) { - if (!((da2->pos_regs[2] ^ da2->old_pos2) & 1)) return; - da2->old_pos2 = da2->pos_regs[2]; - //da2_recalc_mapping(da2); - if (da2->pos_regs[2] & 0x01) - { - da2_log("DA2 enable registers\n"); - for (int i = 0; i < 8; i++) - da2_log("DA2 POS[%d]: %x\n", i, da2->pos_regs[i]); - io_sethandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_sethandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); - mem_mapping_enable(&da2->cmapping); - mem_mapping_enable(&da2->mmio.mapping); - timer_enable(&da2->timer); - } - else - { - da2_log("DA2 disable registers\n"); - timer_disable(&da2->timer); - mem_mapping_disable(&da2->cmapping); - mem_mapping_disable(&da2->mmio.mapping); - io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_removehandler(0x03e0, 0x0010, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); - io_removehandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); - } + da2_t *da2 = (da2_t *) p; + return da2->pos_regs[port & 7]; } -void da2_mca_write(int port, uint8_t val, void *p) +void +da2_mca_write(int port, uint8_t val, void *p) { - da2_t *da2 = (da2_t *)p; + da2_t *da2 = (da2_t *) p; - da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); - - if (port < 0x102) - return; - da2->pos_regs[port & 7] = val; + da2_log("da2_mca_write: port=%04x val=%02x\n", port, val); - da2_mapping_update(da2); + if (port < 0x102) + return; + da2->pos_regs[port & 7] = val; + + da2_mapping_update(da2); } -static uint8_t da2_mca_feedb(void* priv) +static uint8_t +da2_mca_feedb(void *priv) { - const da2_t* da2 = (da2_t*)priv; + const da2_t *da2 = (da2_t *) priv; - return da2->pos_regs[2] & 0x01; + return da2->pos_regs[2] & 0x01; } -static void da2_mca_reset(void *p) +static void +da2_mca_reset(void *p) { - da2_t *da2 = (da2_t *)p; - da2_reset(da2); - da2_mca_write(0x102, 0, da2); + da2_t *da2 = (da2_t *) p; + da2_log("da2_mca_reset called.\n"); + da2_reset(da2); + da2_mca_write(0x102, 0, da2); } -static void da2_gdcropB(uint32_t addr, da2_t* da2) { +static void +da2_gdcropB(uint32_t addr, da2_t *da2) +{ for (int i = 0; i < 8; i++) { if (da2->writemask & (1 << i)) { - //da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); - switch (da2->gdcreg[LG_COMMAND] & 0x03) - { - case 0: /*Set*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 1: /*AND*/ - //da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 2: /*OR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; - case 3: /*XOR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - break; + // da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) { + case 0: /*Set*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 1: /*AND*/ + // da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 2: /*OR*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; + case 3: /*XOR*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + break; } } } } -static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t* da2) { +static void +da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) +{ uint8_t bitmask_l = bitmask & 0xff; uint8_t bitmask_h = bitmask >> 8; for (int i = 0; i < 8; i++) { if (da2->writemask & (1 << i)) { - //da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); - switch (da2->gdcreg[LG_COMMAND] & 0x03) - { - case 0: /*Set*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); - da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 1: /*AND*/ - //da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 2: /*OR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; - case 3: /*XOR*/ - //da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; - //da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); - break; + // da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); + switch (da2->gdcreg[LG_COMMAND] & 0x03) { + case 0: /*Set*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); + // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); + da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 1: /*AND*/ + // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; + // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 2: /*OR*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; + // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; + case 3: /*XOR*/ + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; + // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); + da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h); + break; } } } } -static uint8_t da2_mmio_read(uint32_t addr, void* p) +static uint8_t +da2_mmio_read(uint32_t addr, void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; addr &= DA2_MASK_MMIO; if (da2->ioctl[LS_MMIO] & 0x10) { if (da2->fctl[LF_MMIO_SEL] == 0x80) /* linear access */ - addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17); - else - { + addr |= ((uint32_t) da2->fctl[LF_MMIO_ADDR] << 17); + else { /* 64k bank switch access */ uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; addr += index * 0x40; } - //da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + // da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { - case 0xb0:/* Gaiji RAM */ - addr &= DA2_MASK_GAIJIRAM;/* safety access */ - //da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); - return da2->mmio.ram[addr]; - break; - case 0x10:/* Font ROM */ - if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { - if (addr >= 0x1a0000) return DA2_INVALIDACCESS8; - if (addr >= 0x180000) addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, - but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ - } - if (addr >= DA2_FONTROM_SIZE) return DA2_INVALIDACCESS8; - //da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); - return da2->mmio.font[addr]; - break; - default: - return DA2_INVALIDACCESS8;/* invalid memory access */ - break; + case 0xb0: /* Gaiji RAM */ + addr &= DA2_MASK_GAIJIRAM; /* safety access */ + // da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); + return da2->mmio.ram[addr]; + break; + case 0x10: /* Font ROM */ + if (da2->mmio.charset == DA2_DCONFIG_CHARSET_HANT) { + if (addr >= 0x1a0000) + return DA2_INVALIDACCESS8; + if (addr >= 0x180000) + addr -= 0x40000; /* The bank 12 (180000h-19ffffh) is beyond the available ROM address range, + but the Chinese font sub card actually has this alias, and is used by DOS T5.0. */ + } + if (addr >= DA2_FONTROM_SIZE) + return DA2_INVALIDACCESS8; + // da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); + return da2->mmio.font[addr]; + break; + default: + return DA2_INVALIDACCESS8; /* invalid memory access */ + break; } - } - else if (!(da2->ioctl[LS_MODE] & 1))/* 8 or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 or 256 color mode */ { cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) - da2->gdcla[i] = da2->vram[(addr << 3) | i];/* read in byte */ - //da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); - if (da2->gdcreg[LG_MODE] & 0x08) {/* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ + da2->gdcla[i] = da2->vram[(addr << 3) | i]; /* read in byte */ + // da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); + if (da2->gdcreg[LG_MODE] & 0x08) { /* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint8_t ret = 0; - for (int i = 0; i < 8; i++) - { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))/* color don't care register */ + for (int i = 0; i < 8; i++) { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i)) /* color don't care register */ ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); } return ~ret; - } - else return da2->gdcla[da2->readplane]; - } - else /* text mode 3 */ + } else + return da2->gdcla[da2->readplane]; + } else /* text mode 3 */ { cycles -= video_timing_read_b; return da2->vram[addr]; } } -static uint16_t da2_mmio_readw(uint32_t addr, void* p) +static uint16_t +da2_mmio_readw(uint32_t addr, void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); if (da2->ioctl[LS_MMIO] & 0x10) { - return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); - } - else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ + return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); + } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ { cycles -= video_timing_read_w; addr &= DA2_MASK_MMIO; for (int i = 0; i < 8; i++) - da2->gdcla[i] = (uint16_t)(da2->vram[(addr << 3) | i]) | ((uint16_t)(da2->vram[((addr << 3) + 8) | i]) << 8);/* read vram into latch */ + da2->gdcla[i] = (uint16_t) (da2->vram[(addr << 3) | i]) | ((uint16_t) (da2->vram[((addr << 3) + 8) | i]) << 8); /* read vram into latch */ #ifdef ENABLE_DA2_DEBUGBLT ////debug - //if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) + // if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) //{ - // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); - // for (int i = 0; i <= 0xb; i++) - // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); - //} - //for (int i = 0; i < 16; i++) + // fprintf(da2->mmrdbg_fp, "\nR %x ", addr); + // for (int i = 0; i <= 0xb; i++) + // fprintf(da2->mmrdbg_fp, "%02x ", da2->gdcreg[i]); + // } + // for (int i = 0; i < 16; i++) //{ - // int pixeldata = 0; - // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; - // fprintf(da2->mmrdbg_fp, "%X", pixeldata); - //} - //da2->mmrdbg_vidaddr = addr; + // int pixeldata = 0; + // if (da2->gdcla[da2->readplane] & (1 << (15 - i))) pixeldata = 1; + // fprintf(da2->mmrdbg_fp, "%X", pixeldata); + // } + // da2->mmrdbg_vidaddr = addr; #endif - if (da2->gdcreg[LG_MODE] & 0x08) {/* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ + if (da2->gdcreg[LG_MODE] & 0x08) { /* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint16_t ret = 0; - for (int i = 0; i < 8; i++) - { - if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i))/* color don't care register */ + for (int i = 0; i < 8; i++) { + if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i)) /* color don't care register */ ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xffff : 0); } return ~ret; - } - else - { - //da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); + } else { + // da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); return da2->gdcla[da2->readplane]; } - } - else { - return (uint16_t)da2_mmio_read(addr, da2) | (uint16_t)(da2_mmio_read(addr + 1, da2) << 8); + } else { + return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); } } -static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) +static void +da2_mmio_write(uint32_t addr, uint8_t val, void *p) { - da2_t* da2 = (da2_t*)p; - //da2_log("da2_mmio_write %x %x\n", addr, val); - if ((addr & ~DA2_MASK_MMIO) != 0xA0000) return; + da2_t *da2 = (da2_t *) p; + // da2_log("da2_mmio_write %x %x\n", addr, val); + if ((addr & ~DA2_MASK_MMIO) != 0xA0000) + return; addr &= DA2_MASK_MMIO; if (da2->ioctl[LS_MMIO] & 0x10) { - //if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); + // if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); /* Gaiji RAM */ if (da2->fctl[LF_MMIO_SEL] == 0x80) - addr |= ((uint32_t)da2->fctl[LF_MMIO_ADDR] << 17);/* xxxy yyyy yyyy yyyy yyyy */ - else - { + addr |= ((uint32_t) da2->fctl[LF_MMIO_ADDR] << 17); /* xxxy yyyy yyyy yyyy yyyy */ + else { uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; addr += index * 0x40; } switch (da2->fctl[LF_MMIO_MODE]) { - case 0xb0:/* Gaiji RAM 1011 0000 */ - addr &= DA2_MASK_GAIJIRAM;/* safety access */ - da2->mmio.ram[addr] = val; - break; - case 0x10:/* Font ROM 0001 0000 */ - /* Read-Only */ - break; - case 0x00: - //da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - //addr &= 0x7f;/* OS/2 write addr 1cf80-1cfc3, val xx */ - //if (addr >= DA2_BLT_MEMSIZE) - //{ - // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - // return; - //} - da2->bitblt.indata = 1; - if(da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) - da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; - break; - default: - da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - break; + case 0xb0: /* Gaiji RAM 1011 0000 */ + addr &= DA2_MASK_GAIJIRAM; /* safety access */ + da2->mmio.ram[addr] = val; + break; + case 0x10: /* Font ROM 0001 0000 */ + /* Read-Only */ + break; + case 0x00: + // da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + // addr &= 0x7f;/* OS/2 write addr 1cf80-1cfc3, val xx */ + // if (addr >= DA2_BLT_MEMSIZE) + //{ + // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + // return; + // } + da2->bitblt.indata = 1; + if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + break; + default: + da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + break; } - } - else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ { uint8_t wm = da2->writemask; - //da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); + // da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); #ifdef ENABLE_DA2_DEBUGBLT - //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ - if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - { + if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { fprintf(da2->mmdbg_fp, "\nB %x ", addr); for (int i = 0; i <= 0xb; i++) fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); } - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < 8; i++) { int pixeldata = 0; - if (val & (1 << (7 - i))) pixeldata = (da2->writemask & 0xf); + if (val & (1 << (7 - i))) + pixeldata = (da2->writemask & 0xf); fprintf(da2->mmdbg_fp, "%X", pixeldata); } da2->mmdbg_vidaddr = addr; @@ -2458,270 +2447,270 @@ static void da2_mmio_write(uint32_t addr, uint8_t val, void* p) addr <<= 3; for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];/* use latch */ + da2->gdcsrc[i] = da2->gdcla[i]; /* use latch */ - //da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); - //da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + // da2_log("da2_Wb m%02x r%02x %05x:%02x %x:%x\n", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, cs >> 4, cpu_state.pc); + // da2_log("da2_Wb m%02x r%02x %05x:%02x=%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); - if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - { + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) { for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; - else da2->gdcinput[i] = val; + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) + da2->gdcinput[i] = ~val; + else + da2->gdcinput[i] = val; da2_gdcropB(addr, da2); return; } - switch (da2->writemode) - { - case 2: - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; - break; - case 0: - if (da2->gdcreg[LG_DATA_ROTATION] & 7) - val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { + switch (da2->writemode) { + case 2: for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; - } - else - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - else da2->gdcinput[i] = val; + if (da2->writemask & (1 << i)) + da2->vram[addr | i] = da2->gdcsrc[i]; + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + da2->vram[addr | i] = val; + } else { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + else + da2->gdcinput[i] = val; + + for (int i = 0; i < 8; i++) + da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */ + da2_gdcropB(addr, da2); + // for (int i = 0; i < 8; i++) + // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch + ////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) + da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + } else { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); + da2_gdcropB(addr, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 7) + val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; + wm = da2->gdcreg[LG_BIT_MASK_LOW]; + da2->gdcreg[LG_BIT_MASK_LOW] &= val; for (int i = 0; i < 8; i++) - da2->debug_vramold[i] = da2->vram[addr | i];/* use latch */ + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; da2_gdcropB(addr, da2); - //for (int i = 0; i < 8; i++) - // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch - ////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 1: - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - } - else - { - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); - da2_gdcropB(addr, da2); - } - break; - case 3: - if (da2->gdcreg[LG_DATA_ROTATION] & 7) - val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - wm = da2->gdcreg[LG_BIT_MASK_LOW]; - da2->gdcreg[LG_BIT_MASK_LOW] &= val; - - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - da2_gdcropB(addr, da2); - da2->gdcreg[LG_BIT_MASK_LOW] = wm; - break; + da2->gdcreg[LG_BIT_MASK_LOW] = wm; + break; } - //da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); - } - else/* mode 3h text */ + // da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); + } else /* mode 3h text */ { cycles -= video_timing_write_b; da2->vram[addr] = val; da2->fullchange = 2; } } -uint16_t rightRotate(uint16_t data, uint8_t count) +uint16_t +rightRotate(uint16_t data, uint8_t count) { return (data >> count) | (data << (sizeof(data) * 8 - count)); } -static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void* p) +static void +da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) { - da2_t* da2 = (da2_t*)p; - uint8_t wm = da2->writemask; + da2_t *da2 = (da2_t *) p; + uint8_t wm = da2->writemask; uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; bitmask <<= 8; - bitmask |= (uint16_t)da2->gdcreg[LG_BIT_MASK_LOW]; + bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGBLT - //if (!(da2->gdcreg[LG_COMMAND] & 0x08)) + // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ - if (((int)addr - (int)da2->mmdbg_vidaddr) > 2 || (((int)da2->mmdbg_vidaddr - (int)addr) > 2) || da2->mmdbg_vidaddr == addr) - { - fprintf(da2->mmdbg_fp, "\nW %x ", addr); - for (int i = 0; i <= 0xb; i++) - fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); - } - for (int i = 0; i < 16; i++) - { - int pixeldata = 0; - if (val & (1 << (15 - i))) pixeldata = (da2->writemask & 0xf); - fprintf(da2->mmdbg_fp, "%X", pixeldata); - } - da2->mmdbg_vidaddr = addr; + if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { + fprintf(da2->mmdbg_fp, "\nW %x ", addr); + for (int i = 0; i <= 0xb; i++) + fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); + } + for (int i = 0; i < 16; i++) { + int pixeldata = 0; + if (val & (1 << (15 - i))) + pixeldata = (da2->writemask & 0xf); + fprintf(da2->mmdbg_fp, "%X", pixeldata); + } + da2->mmdbg_vidaddr = addr; //} #endif cycles -= video_timing_write_w; - //cycles_lost += video_timing_write_w; + // cycles_lost += video_timing_write_w; - //da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); - //da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + // da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); + // da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); - da2->changedvram[addr >> 12] = changeframecount; + da2->changedvram[addr >> 12] = changeframecount; da2->changedvram[(addr + 1) >> 12] = changeframecount; addr <<= 3; for (int i = 0; i < 8; i++) - da2->gdcsrc[i] = da2->gdcla[i];/* use latch */ + da2->gdcsrc[i] = da2->gdcla[i]; /* use latch */ - if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - { + if (!(da2->gdcreg[LG_COMMAND] & 0x08)) { for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) da2->gdcinput[i] = ~val; - else da2->gdcinput[i] = val; + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else if (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) + da2->gdcinput[i] = ~val; + else + da2->gdcinput[i] = val; da2_gdcropW(addr, bitmask, da2); return; } - //da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] - // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); - switch (da2->writemode) - { - case 2: - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; - da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + // da2_log("da2_Ww m%02x r%02x %05x:%04x=%02x%02x%02x%02x,%02x%02x%02x%02x->", da2->gdcreg[0x5], da2->gdcreg[LG_COMMAND], addr >> 3, val, da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); + switch (da2->writemode) { + case 2: + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) { + da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; + da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + } + break; + case 0: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work + if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) { + da2->vram[addr | i] = val & 0xff; + da2->vram[(addr + 8) | i] = val >> 8; + } + } else { + for (int i = 0; i < 8; i++) + if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + else + da2->gdcinput[i] = val; + da2_gdcropW(addr, bitmask, da2); + // da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } - break; - case 0: - if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work - if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - da2->vram[addr | i] = val & 0xff; - da2->vram[(addr + 8) | i] = val >> 8; - } - } - else - { - for (int i = 0; i < 8; i++) - if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - else da2->gdcinput[i] = val; - da2_gdcropW(addr, bitmask, da2); - //da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 1: - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) - { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - { - uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - da2->vram[addr | i] = wdata & 0xff; - da2->vram[(addr + 8) | i] = wdata >> 8; - } - } - else - { - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); - da2_gdcropW(addr, bitmask, da2); - } - break; - case 3: - if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15);//val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work - wm = bitmask; - bitmask &= val; + break; + case 1: + if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + for (int i = 0; i < 8; i++) + if (da2->writemask & (1 << i)) { + uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + da2->vram[addr | i] = wdata & 0xff; + da2->vram[(addr + 8) | i] = wdata >> 8; + } + } else { + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); + da2_gdcropW(addr, bitmask, da2); + } + break; + case 3: + if (da2->gdcreg[LG_DATA_ROTATION] & 15) + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work + wm = bitmask; + bitmask &= val; - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; - da2_gdcropW(addr, bitmask, da2); - bitmask = wm; - break; + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + da2_gdcropW(addr, bitmask, da2); + bitmask = wm; + break; } - //da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] - // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); + // da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] + // , da2->vram[addr + 8], da2->vram[addr + 9], da2->vram[addr + 10], da2->vram[addr + 11]); } -static void da2_mmio_writew(uint32_t addr, uint16_t val, void* p) +static void +da2_mmio_writew(uint32_t addr, uint16_t val, void *p) { - da2_t* da2 = (da2_t*)p; - //if ((addr & ~0x1ffff) != 0xA0000) return; + da2_t *da2 = (da2_t *) p; + // if ((addr & ~0x1ffff) != 0xA0000) return; if (da2->ioctl[LS_MMIO] & 0x10) { - //da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + // da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); - } - else if (!(da2->ioctl[LS_MODE] & 1))/* 8 color or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ { addr &= DA2_MASK_MMIO; - //return; - //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + // return; + // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_gc_writeW(addr, val, da2); - } - else {/* mode 3h text */ - //if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - //da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + } else { /* mode 3h text */ + // if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); + // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } } -static void da2_code_write(uint32_t addr, uint8_t val, void* p) +static void +da2_code_write(uint32_t addr, uint8_t val, void *p) { - da2_t* da2 = (da2_t*)p; - //if ((addr & ~0xfff) != 0xE0000) return; + da2_t *da2 = (da2_t *) p; + // if ((addr & ~0xfff) != 0xE0000) return; addr &= DA2_MASK_CRAM; da2->cram[addr] = val; da2->fullchange = 2; } -static void da2_code_writeb(uint32_t addr, uint8_t val, void* p) +static void +da2_code_writeb(uint32_t addr, uint8_t val, void *p) { - da2_t* da2 = (da2_t*)p; - //da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); + da2_t *da2 = (da2_t *) p; + // da2_log("DA2_code_writeb: Write to %x, val %x\n", addr, val); cycles -= video_timing_write_b; da2_code_write(addr, val, da2); } -static void da2_code_writew(uint32_t addr, uint16_t val, void* p) +static void +da2_code_writew(uint32_t addr, uint16_t val, void *p) { - //da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); - da2_t* da2 = (da2_t*)p; + // da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); + da2_t *da2 = (da2_t *) p; cycles -= video_timing_write_w; da2_code_write(addr, val & 0xff, da2); da2_code_write(addr + 1, val >> 8, da2); } -static uint8_t da2_code_read(uint32_t addr, void* p) +static uint8_t +da2_code_read(uint32_t addr, void *p) { - da2_t* da2 = (da2_t*)p; - if ((addr & ~DA2_MASK_CRAM) != 0xE0000) return DA2_INVALIDACCESS8; + da2_t *da2 = (da2_t *) p; + if ((addr & ~DA2_MASK_CRAM) != 0xE0000) + return DA2_INVALIDACCESS8; addr &= DA2_MASK_CRAM; return da2->cram[addr]; } -static uint8_t da2_code_readb(uint32_t addr, void* p) +static uint8_t +da2_code_readb(uint32_t addr, void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; cycles -= video_timing_read_b; return da2_code_read(addr, da2); } -static uint16_t da2_code_readw(uint32_t addr, void* p) +static uint16_t +da2_code_readw(uint32_t addr, void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; cycles -= video_timing_read_w; return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); - //return 0; } -void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) +void +da2_doblit(int y1, int y2, int wx, int wy, da2_t *da2) { if (wx != xsize || wy != ysize) { xsize = wx; @@ -2736,28 +2725,26 @@ void da2_doblit(int y1, int y2, int wx, int wy, da2_t* da2) video_res_x = wx; video_res_y = wy; - video_bpp = 8; + video_bpp = 8; } -void da2_poll(void* priv) +void +da2_poll(void *priv) { - da2_t* da2 = (da2_t*)priv; - int x; + da2_t *da2 = (da2_t *) priv; + int x; - if (!da2->linepos) - { + if (!da2->linepos) { timer_advance_u64(&da2->timer, da2->dispofftime); - //if (output) printf("Display off %f\n",vidtime); + // if (output) printf("Display off %f\n",vidtime); da2->cgastat |= 1; da2->linepos = 1; - if (da2->dispon) - { + if (da2->dispon) { da2->hdisp_on = 1; da2->ma &= da2->vram_display_mask; - if (da2->firstline == 2000) - { + if (da2->firstline == 2000) { da2->firstline = da2->displine; video_wait_for_buffer(); } @@ -2769,27 +2756,24 @@ void da2_poll(void* priv) da2->lastline = da2->displine; } - //da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); + // da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); da2->displine++; - //if (da2->interlace) - // da2->displine++; - if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) - { - //da2_log("Vsync off at line %i\n",displine); + // if (da2->interlace) + // da2->displine++; + if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) { + // da2_log("Vsync off at line %i\n",displine); da2->cgastat &= ~8; } da2->vslines++; if (da2->displine > 1200) da2->displine = 0; - //da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], - //displine, vc, ma); - } - else - { - //da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], + // displine, vc, ma); + } else { + // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); timer_advance_u64(&da2->timer, da2->dispontime); - //if (output) printf("Display on %f\n",vidtime); + // if (output) printf("Display on %f\n",vidtime); if (da2->dispon) da2->cgastat &= ~1; da2->hdisp_on = 0; @@ -2797,21 +2781,17 @@ void da2_poll(void* priv) da2->linepos = 0; if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) da2->con = 0; - if (da2->dispon) - { - if (da2->sc == da2->rowcount) - { + if (da2->dispon) { + if (da2->sc == da2->rowcount) { da2->linecountff = 0; - da2->sc = 0; + da2->sc = 0; - da2->maback += (da2->rowoffset << 1);/* color = 0x50(80), mono = 0x40(64) */ + da2->maback += (da2->rowoffset << 1); /* color = 0x50(80), mono = 0x40(64) */ if (da2->interlace) da2->maback += (da2->rowoffset << 1); da2->maback &= da2->vram_display_mask; da2->ma = da2->maback; - } - else - { + } else { da2->sc++; da2->sc &= 31; da2->ma = da2->maback; @@ -2821,46 +2801,40 @@ void da2_poll(void* priv) da2->vc++; da2->vc &= 2047; - if (da2->vc == da2->dispend) - { + if (da2->vc == da2->dispend) { da2->dispon = 0; - //if (da2->crtc[10] & 0x20) da2->cursoron = 0; - //else da2->cursoron = da2->blink & 16; - if (da2->ioctl[LS_MODE] & 1) {/* in text mode */ - if (da2->attrc[LV_CURSOR_CONTROL] & 0x01)/* cursor blinking */ + // if (da2->crtc[10] & 0x20) da2->cursoron = 0; + // else da2->cursoron = da2->blink & 16; + if (da2->ioctl[LS_MODE] & 1) { /* in text mode */ + if (da2->attrc[LV_CURSOR_CONTROL] & 0x01) /* cursor blinking */ { da2->cursoron = (da2->blink | 1) & da2->blinkconf; - } - else - { + } else { da2->cursoron = 0; } - if (!(da2->blink & (0x10 - 1)))/* force redrawing for cursor and blink attribute */ + if (!(da2->blink & (0x10 - 1))) /* force redrawing for cursor and blink attribute */ da2->fullchange = 2; } da2->blink++; - for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) - { + for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) { if (da2->changedvram[x]) da2->changedvram[x]--; } - //memset(changedvram,0,2048); del - if (da2->fullchange) - { + // memset(changedvram,0,2048); del + if (da2->fullchange) { da2->fullchange--; } } - if (da2->vc == da2->vsyncstart) - { + if (da2->vc == da2->vsyncstart) { int wx, wy; - //da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); + // da2_log("VC vsync %i %i\n", da2->firstline_draw, da2->lastline_draw); da2->dispon = 0; da2->cgastat |= 8; x = da2->hdisp; - //if (da2->interlace && !da2->oddeven) da2->lastline++; - //if (da2->interlace && da2->oddeven) da2->firstline--; + // if (da2->interlace && !da2->oddeven) da2->lastline++; + // if (da2->interlace && da2->oddeven) da2->firstline--; wx = x; wy = da2->lastline - da2->firstline; @@ -2868,57 +2842,62 @@ void da2_poll(void* priv) da2_doblit(da2->firstline_draw, da2->lastline_draw + 1, wx, wy, da2); da2->firstline = 2000; - da2->lastline = 0; + da2->lastline = 0; da2->firstline_draw = 2000; - da2->lastline_draw = 0; + da2->lastline_draw = 0; da2->oddeven ^= 1; changeframecount = da2->interlace ? 3 : 2; - da2->vslines = 0; + da2->vslines = 0; - //if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); - //else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); - //da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; -/* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; - else*/ da2->ma = da2->maback = da2->ma_latch; - da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; + // if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); + // else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); + // da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; + /* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; + else*/ + da2->ma + = da2->maback = da2->ma_latch; + da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; da2->ma <<= 1; da2->maback <<= 1; da2->ca <<= 1; - //da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); } - if (da2->vc == da2->vtotal) - { - //da2_log("VC vtotal\n"); - //printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); - da2->vc = 0; - da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; - da2->dispon = 1; - da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; + if (da2->vc == da2->vtotal) { + // da2_log("VC vtotal\n"); + // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); + da2->vc = 0; + da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; + da2->dispon = 1; + da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; da2->scrollcache = da2->attrc[LV_PANNING] & 7; } if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; } - //printf("2 %i\n",da2_vsyncstart); - //da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); - //da2_log("r"); + // printf("2 %i\n",da2_vsyncstart); + // da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); + // da2_log("r"); } -static void da2_loadfont(char* fname, void* p) { - da2_t* da2 = (da2_t*)p; +static void +da2_loadfont(char *fname, void *p) +{ + da2_t *da2 = (da2_t *) p; uint8_t buf; - //uint32_t code = 0; + // uint32_t code = 0; uint64_t fsize; - if (!fname) return; - if (*fname == '\0') return; - FILE* mfile = rom_fopen(fname, "rb"); + if (!fname) + return; + if (*fname == '\0') + return; + FILE *mfile = rom_fopen(fname, "rb"); if (!mfile) { - //da2_log("MSG: Can't open binary ROM font file: %s\n", fname); + // da2_log("MSG: Can't open binary ROM font file: %s\n", fname); return; } fseek(mfile, 0, SEEK_END); @@ -2926,9 +2905,9 @@ static void da2_loadfont(char* fname, void* p) { fseek(mfile, 0, SEEK_SET); if (fsize > DA2_FONTROM_SIZE) { fsize = DA2_FONTROM_SIZE; /* truncate read data */ - //da2_log("MSG: The binary ROM font is truncated: %s\n", fname); - //fclose(mfile); - //return 1; + // da2_log("MSG: The binary ROM font is truncated: %s\n", fname); + // fclose(mfile); + // return 1; } uint32_t j = 0; while (ftell(mfile) < fsize) { @@ -2941,50 +2920,58 @@ static void da2_loadfont(char* fname, void* p) { } /* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ -static uint8_t ps55_palette_color[64][3] = -{ -{0x00,0x00,0x00},{0x00,0x00,0x2A},{0x00,0x2A,0x00},{0x00,0x2A,0x2A},{0x2A,0x00,0x00},{0x2A,0x00,0x2A},{0x2A,0x2A,0x00},{0x2A,0x2A,0x2A}, -{0x00,0x00,0x15},{0x00,0x00,0x3F},{0x00,0x2A,0x15},{0x00,0x2A,0x3F},{0x2A,0x00,0x15},{0x2A,0x00,0x3F},{0x2A,0x2A,0x15},{0x2A,0x2A,0x3F}, -{0x00,0x15,0x00},{0x00,0x15,0x2A},{0x00,0x3F,0x00},{0x00,0x3F,0x2A},{0x2A,0x15,0x00},{0x2A,0x15,0x2A},{0x2A,0x3F,0x00},{0x2A,0x3F,0x2A}, -{0x00,0x15,0x15},{0x00,0x15,0x3F},{0x00,0x3F,0x15},{0x00,0x3F,0x3F},{0x2A,0x15,0x15},{0x2A,0x15,0x3F},{0x2A,0x3F,0x15},{0x2A,0x3F,0x3F}, -{0x15,0x00,0x00},{0x15,0x00,0x2A},{0x15,0x2A,0x00},{0x15,0x2A,0x2A},{0x3F,0x00,0x00},{0x3F,0x00,0x2A},{0x3F,0x2A,0x00},{0x3F,0x2A,0x2A}, -{0x15,0x00,0x15},{0x15,0x00,0x3F},{0x15,0x2A,0x15},{0x15,0x2A,0x3F},{0x3F,0x00,0x15},{0x3F,0x00,0x3F},{0x3F,0x2A,0x15},{0x3F,0x2A,0x3F}, -{0x15,0x15,0x00},{0x15,0x15,0x2A},{0x15,0x3F,0x00},{0x15,0x3F,0x2A},{0x3F,0x15,0x00},{0x3F,0x15,0x2A},{0x3F,0x3F,0x00},{0x3F,0x3F,0x2A}, -{0x15,0x15,0x15},{0x15,0x15,0x3F},{0x15,0x3F,0x15},{0x15,0x3F,0x3F},{0x3F,0x15,0x15},{0x3F,0x15,0x3F},{0x3F,0x3F,0x15},{0x3F,0x3F,0x3F} +static uint8_t ps55_palette_color[64][3] = { + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x2A }, { 0x00, 0x2A, 0x00 }, { 0x00, 0x2A, 0x2A }, + { 0x2A, 0x00, 0x00 }, { 0x2A, 0x00, 0x2A }, { 0x2A, 0x2A, 0x00 }, { 0x2A, 0x2A, 0x2A }, + { 0x00, 0x00, 0x15 }, { 0x00, 0x00, 0x3F }, { 0x00, 0x2A, 0x15 }, { 0x00, 0x2A, 0x3F }, + { 0x2A, 0x00, 0x15 }, { 0x2A, 0x00, 0x3F }, { 0x2A, 0x2A, 0x15 }, { 0x2A, 0x2A, 0x3F }, + { 0x00, 0x15, 0x00 }, { 0x00, 0x15, 0x2A }, { 0x00, 0x3F, 0x00 }, { 0x00, 0x3F, 0x2A }, + { 0x2A, 0x15, 0x00 }, { 0x2A, 0x15, 0x2A }, { 0x2A, 0x3F, 0x00 }, { 0x2A, 0x3F, 0x2A }, + { 0x00, 0x15, 0x15 }, { 0x00, 0x15, 0x3F }, { 0x00, 0x3F, 0x15 }, { 0x00, 0x3F, 0x3F }, + { 0x2A, 0x15, 0x15 }, { 0x2A, 0x15, 0x3F }, { 0x2A, 0x3F, 0x15 }, { 0x2A, 0x3F, 0x3F }, + { 0x15, 0x00, 0x00 }, { 0x15, 0x00, 0x2A }, { 0x15, 0x2A, 0x00 }, { 0x15, 0x2A, 0x2A }, + { 0x3F, 0x00, 0x00 }, { 0x3F, 0x00, 0x2A }, { 0x3F, 0x2A, 0x00 }, { 0x3F, 0x2A, 0x2A }, + { 0x15, 0x00, 0x15 }, { 0x15, 0x00, 0x3F }, { 0x15, 0x2A, 0x15 }, { 0x15, 0x2A, 0x3F }, + { 0x3F, 0x00, 0x15 }, { 0x3F, 0x00, 0x3F }, { 0x3F, 0x2A, 0x15 }, { 0x3F, 0x2A, 0x3F }, + { 0x15, 0x15, 0x00 }, { 0x15, 0x15, 0x2A }, { 0x15, 0x3F, 0x00 }, { 0x15, 0x3F, 0x2A }, + { 0x3F, 0x15, 0x00 }, { 0x3F, 0x15, 0x2A }, { 0x3F, 0x3F, 0x00 }, { 0x3F, 0x3F, 0x2A }, + { 0x15, 0x15, 0x15 }, { 0x15, 0x15, 0x3F }, { 0x15, 0x3F, 0x15 }, { 0x15, 0x3F, 0x3F }, + { 0x3F, 0x15, 0x15 }, { 0x3F, 0x15, 0x3F }, { 0x3F, 0x3F, 0x15 }, { 0x3F, 0x3F, 0x3F } }; -void da2_reset_ioctl(da2_t* da2) +void +da2_reset_ioctl(da2_t *da2) { - da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ + da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ da2_outw(LS_INDEX, 0x0302, da2); /* Index 02, Bit 1: VGA passthrough, Bit 0: Character Mode */ da2_outw(LS_INDEX, 0x0008, da2); /* Index 08, Bit 0: Enable MMIO */ } static void -da2_reset(void* priv) +da2_reset(void *priv) { - da2_t* da2 = (da2_t*)priv; + da2_t *da2 = (da2_t *) priv; /* Initialize drawing */ da2->bitblt.exec = DA2_BLT_CIDLE; - da2->render = da2_render_blank; + da2->render = da2_render_blank; da2_reset_ioctl(da2); - da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ - da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ - da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ - da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ - da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8 ) << 1); /* Configuration 1 : Monitor ID 3 */ - da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ - da2->fctl[0] = 0x2b; /* 3E3h:0 */ - da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ - da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ - da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ - da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ - da2->ma_latch = 0; - da2->interlace = 0; - da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ - da2->attr_palette_enable = 0; /* disable attribute generator */ + da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ + da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ + da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ + da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ + da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8) << 1); /* Configuration 1 : Monitor ID 3 */ + da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ + da2->fctl[0] = 0x2b; /* 3E3h:0 */ + da2->fctl[LF_MMIO_MODE] = 0xb0; /* 3E3h:0bh */ + da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ + da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ + da2->ma_latch = 0; + da2->interlace = 0; + da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + da2->attr_palette_enable = 0; /* disable attribute generator */ /* Set default color palette (Windows 3.1 display driver won't reset palette) */ for (int i = 0; i < 256; i++) { @@ -2993,171 +2980,178 @@ da2_reset(void* priv) da2->vgapal[i].b = ps55_palette_color[i & 0x3F][2]; da2->pallook[i] = makecol32((da2->vgapal[i].r & 0x3f) * 4, (da2->vgapal[i].g & 0x3f) * 4, (da2->vgapal[i].b & 0x3f) * 4); } + da2_log("da2_reset done.\n"); } -static void *da2_init() +static void * +da2_init() { - if (svga_get_pri() == NULL) - return NULL; - svga_t *mb_vga = svga_get_pri(); - mb_vga->cable_connected = 0; + if (svga_get_pri() == NULL) + return NULL; + svga_t *mb_vga = svga_get_pri(); + mb_vga->cable_connected = 0; - da2_t* da2 = malloc(sizeof(da2_t)); - da2->mb_vga = mb_vga; + da2_t *da2 = malloc(sizeof(da2_t)); + da2->mb_vga = mb_vga; - da2->dispontime = 1000ull << 32; - da2->dispofftime = 1000ull << 32; - int memsize = 1024 * 1024; - da2->vram = malloc(memsize); - da2->vram_mask = memsize - 1; - da2->cram = malloc(0x1000); - da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 12); /* XX000h */ - da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ + da2->dispontime = 1000ull << 32; + da2->dispofftime = 1000ull << 32; + int memsize = 1024 * 1024; + da2->vram = malloc(memsize); + da2->vram_mask = memsize - 1; + da2->cram = malloc(0x1000); + da2->vram_display_mask = DA2_MASK_CRAM; + da2->changedvram = malloc(/*(memsize >> 12) << 1*/ 0x1000000 >> 12); /* XX000h */ + da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ - da2->mmio.charset = device_get_config_int("charset"); - da2->mmio.font= malloc(DA2_FONTROM_SIZE); - switch(da2->mmio.charset) - { - case DA2_DCONFIG_CHARSET_HANT: - da2_loadfont(DA2_FONTROM_PATH_HANT, da2); - break; - case DA2_DCONFIG_CHARSET_JPAN: - da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); - break; - } + da2->mmio.charset = device_get_config_int("charset"); + da2->mmio.font = malloc(DA2_FONTROM_SIZE); + switch (da2->mmio.charset) { + case DA2_DCONFIG_CHARSET_HANT: + da2_loadfont(DA2_FONTROM_PATH_HANT, da2); + break; + case DA2_DCONFIG_CHARSET_JPAN: + da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + break; + } - mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); - da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ + mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); + da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (float) (1ull << 32)); + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ #ifdef ENABLE_DA2_DEBUGBLT - da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); - da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); - da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); - da2->bitblt.debug_reg_ip = 0; + da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); + da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); + da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); + da2->bitblt.debug_reg_ip = 0; #endif - da2->bitblt.payload_addr = 0; - da2_reset(da2); - - mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); - //da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); + da2->bitblt.payload_addr = 0; + da2_reset(da2); - mem_mapping_disable(&da2->mmio.mapping); + mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + // da2_log("DA2mmio new mapping: %X, base: %x, size: %x\n", &da2->mmio.mapping, da2->mmio.mapping.base, da2->mmio.mapping.size); - mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); + mem_mapping_disable(&da2->mmio.mapping); - mem_mapping_disable(&da2->cmapping); + mem_mapping_add(&da2->cmapping, 0xE0000, 0x1000, da2_code_readb, da2_code_readw, NULL, da2_code_writeb, da2_code_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); - timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ - timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + mem_mapping_disable(&da2->cmapping); - return da2; + timer_add(&da2->timer, da2_poll, da2, 0); + da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ + timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + + return da2; } -static int da2_available() +static int +da2_available() { - return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); + return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); } -void da2_close(void *p) +void +da2_close(void *p) { - da2_t *da2 = (da2_t *)p; + da2_t *da2 = (da2_t *) p; - /* dump mem for debug */ + /* dump mem for debug */ #ifdef ENABLE_DA2_LOG - FILE* f; - f = fopen("da2_cram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->cram, 0x1000, 1, f); - fclose(f); - } - f = fopen("da2_vram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->vram, 1024*1024, 1, f); - fclose(f); - } - f = fopen("da2_gram.dmp", "wb"); - if (f != NULL) { - fwrite(da2->mmio.ram, 256*1024, 1, f); - fclose(f); - } - f = fopen("da2_attrpal.dmp", "wb"); - if (f != NULL) { - fwrite(da2->attrc, 32, 1, f); - fclose(f); - } - f = fopen("da2_dacrgb.dmp", "wb"); - if (f != NULL) { - fwrite(da2->vgapal, 3*256, 1, f); - fclose(f); - } - f = fopen("da2_daregs.txt", "w"); - if (f != NULL) { - for (int i=0;i<0x10;i++) - fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); - for (int i = 0; i < 0x20; i++) - fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); - for (int i = 0; i < 0x20; i++) - fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); - for (int i = 0; i < 0x40; i++) - fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrc[i]); - for (int i = 0; i < 0x10; i++) - fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); - for (int i = 0; i < 0x10; i++) - fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); - fclose(f); - } + FILE *f; + f = fopen("da2_cram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->cram, 0x1000, 1, f); + fclose(f); + } + f = fopen("da2_vram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vram, 1024 * 1024, 1, f); + fclose(f); + } + f = fopen("da2_gram.dmp", "wb"); + if (f != NULL) { + fwrite(da2->mmio.ram, 256 * 1024, 1, f); + fclose(f); + } + f = fopen("da2_attrpal.dmp", "wb"); + if (f != NULL) { + fwrite(da2->attrc, 32, 1, f); + fclose(f); + } + f = fopen("da2_dacrgb.dmp", "wb"); + if (f != NULL) { + fwrite(da2->vgapal, 3 * 256, 1, f); + fclose(f); + } + f = fopen("da2_daregs.txt", "w"); + if (f != NULL) { + for (int i = 0; i < 0x10; i++) + fprintf(f, "3e1(ioctl) %02X: %4X\n", i, da2->ioctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e3(fctl) %02X: %4X\n", i, da2->fctl[i]); + for (int i = 0; i < 0x20; i++) + fprintf(f, "3e5(crtc) %02X: %4X\n", i, da2->crtc[i]); + for (int i = 0; i < 0x40; i++) + fprintf(f, "3e8(attr) %02X: %4X\n", i, da2->attrc[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); + for (int i = 0; i < 0x10; i++) + fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); + fclose(f); + } #endif #ifdef ENABLE_DA2_DEBUGBLT - f = fopen("da2_bltdump.csv", "w"); - if (f != NULL && da2->bitblt.debug_reg_ip > 0) { - /* print header */ + f = fopen("da2_bltdump.csv", "w"); + if (f != NULL && da2->bitblt.debug_reg_ip > 0) { + /* print header */ + for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { + if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) + fprintf(f, "\"%02X\"\t", y); + } + fprintf(f, "\n"); + /* print data */ + for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { - if (da2->bitblt.debug_reg[(da2->bitblt.debug_reg_ip - 1) * DA2_DEBUG_BLTLOG_SIZE + y] != DA2_DEBUG_BLT_NEVERUSED) - fprintf(f, "\"%02X\"\t", y); + if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) + ; + else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) + fprintf(f, "\"\"\t"); + else + fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); } fprintf(f, "\n"); - /* print data */ - for (int x = 0; x < da2->bitblt.debug_reg_ip; x++) { - for (int y = 0; y < DA2_DEBUG_BLTLOG_SIZE; y++) { - if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_NEVERUSED) - ; - else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) - fprintf(f, "\"\"\t"); - else - fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); - } - fprintf(f, "\n"); - } - fclose(f); } - if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); - if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); - free(da2->bitblt.debug_reg); + fclose(f); + } + if (da2->mmdbg_fp != NULL) + fclose(da2->mmdbg_fp); + if (da2->mmrdbg_fp != NULL) + fclose(da2->mmrdbg_fp); + free(da2->bitblt.debug_reg); #endif - free(da2->cram); - free(da2->vram); - free(da2->changedvram); - free(da2->mmio.font); - free(da2); + free(da2->cram); + free(da2->vram); + free(da2->changedvram); + free(da2->mmio.font); + free(da2); } -void da2_speed_changed(void *p) +void +da2_speed_changed(void *p) { - da2_t* da2 = (da2_t*)p; - da2->da2const = (uint64_t)((cpuclock / DA2_PIXELCLOCK) * (float)(1ull << 32)); + da2_t *da2 = (da2_t *) p; + da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (float) (1ull << 32)); da2_recalctimings(da2); } -void da2_force_redraw(void *p) +void +da2_force_redraw(void *p) { - da2_t* da2 = (da2_t*)p; + da2_t *da2 = (da2_t *) p; da2->fullchange = changeframecount; } static const device_config_t da2_configuration[] = { - // clang-format off + // clang-format off { .name = "charset", .description = "Charset", @@ -3197,7 +3191,7 @@ static const device_config_t da2_configuration[] = { } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; const device_t ps55da2_device = { From 32c040f8fa6e58feaf288cded6a003e42a383f57 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Feb 2025 05:57:28 +0100 Subject: [PATCH 0287/1190] NEAT: Fix alternate A20 gate, fixes #5168. --- src/chipset/neat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 069fa87e4..c1c2e827a 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -845,7 +845,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) dev->ems_size); } - mem_a20_key = val & RB12_GA20; + mem_a20_alt = val & RB12_GA20; mem_a20_recalc(); break; From f4df7491b0ae16ed5c272b19ff36bce7a4ecc0f2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Feb 2025 14:45:12 +0100 Subject: [PATCH 0288/1190] The Commodore 386SX-16 now correctly has a PS/2 keyboard controller. --- src/machine/m_at_286_386sx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index cb2a04d07..362f035e0 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -628,7 +628,7 @@ machine_at_cmdsl386sx16_init(const machine_t *model) machine_at_common_ide_init(model); - device_add(&keyboard_at_device); + device_add(&keyboard_ps2_device); if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); From 8d54e6adf08746bdf463067abac69b88dcec8479 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Feb 2025 15:38:02 +0100 Subject: [PATCH 0289/1190] NEAT: Fixed chipset A20 gate toggle. --- src/chipset/neat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index c1c2e827a..2990b5216 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -845,7 +845,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) dev->ems_size); } - mem_a20_alt = val & RB12_GA20; + mem_a20_key = !(val & RB12_GA20); mem_a20_recalc(); break; From 58c5d9606e0c24e86e85e7e7adff2a0e25bb3382 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sun, 16 Feb 2025 23:47:10 +0900 Subject: [PATCH 0290/1190] fixed some drawing issues in Win 3.1. * Changed bitblt execution. This fixes a mouse cursor color issue in Windows 3.1. * Fixed splash graphics broken in A-Train IV. --- src/video/vid_ps55da2.c | 145 +++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 61 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 9ed099f19..060e47ce6 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -237,6 +237,7 @@ #ifdef ENABLE_DA2_LOG # define ENABLE_DA2_DEBUGBLT 1 +// # define ENABLE_DA2_DEBUGFULLSCREEN 1 int da2_do_log = ENABLE_DA2_LOG; static void @@ -609,7 +610,7 @@ da2_bitblt_load(da2_t *da2) { uint32_t value32; uint64_t value64; - da2_log("BITBLT loading params\n"); + da2_log("bltload: loading params\n"); // da2_log("BitBlt memory:\n"); // if (da2->bitblt.payload[0] != 0) // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) @@ -665,17 +666,20 @@ da2_bitblt_load(da2_t *da2) case 0x00: break; default: - da2_log("da2_ParseBLT: Unknown PreOP!\n"); + da2_log("bltload: Unknown PreOP!\n"); break; } i++; } da2->bitblt.exec = DA2_BLT_CIDLE; - /* clear payload memory */ - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - da2->bitblt.payload_addr = 0; + // /* clear payload memory */ + // memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + // da2->bitblt.payload_addr = 0; /* [89] 20: 0001 (1) then execute payload */ if (da2->bitblt.reg[0x20] & 0x1) { + /* clear payload memory */ + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; #ifdef ENABLE_DA2_DEBUGBLT for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { // if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); @@ -690,7 +694,7 @@ da2_bitblt_load(da2_t *da2) #endif da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03; /* 01 AND, 03 XOR */ - da2_log("bitblt execute 05: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); + da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); for (int i = 0; i <= 0xb; i++) da2_log("%02x ", da2->gdcreg[i]); da2_log("\n"); @@ -820,11 +824,12 @@ void da2_bitblt_exec(void *p) { da2_t *da2 = (da2_t *) p; - timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + da2_log("bitblt_exec: %d\n", da2->bitblt.exec); // da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: - timer_disable(&da2->bitblt.timer); + // timer_disable(&da2->bitblt.timer); break; case DA2_BLT_CLOAD: da2->bitblt.indata = 0; @@ -960,17 +965,30 @@ da2_bitblt_exec(void *p) } } void -da2_bitblt_dopayload(da2_t *da2) +da2_bitblt_dopayload(void *priv) { - if (da2->bitblt.exec == DA2_BLT_CIDLE) { - da2->bitblt.exec = DA2_BLT_CLOAD; - // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ - da2_log("da2 Do bitblt\n"); - while (da2->bitblt.exec != DA2_BLT_CIDLE) { + da2_t *da2 = (da2_t *) priv; + timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); + // if (da2->bitblt.indata) /* for OS/2 J1.3 */ + // { + // if (da2->bitblt.exec == DA2_BLT_CIDLE) { + // da2->bitblt.exec = DA2_BLT_CLOAD; + // /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ + // da2_log("da2 Do bitblt\n"); + // while (da2->bitblt.exec != DA2_BLT_CIDLE) { + // da2_bitblt_exec(da2); + // } + // da2_log("da2 End bitblt %x\n", da2->bitblt.exec); + // } + // } + if (da2->bitblt.exec != DA2_BLT_CIDLE) + da2_bitblt_exec(da2); + else if (da2->bitblt.indata) /* for OS/2 J1.3 */ + { + if (da2->bitblt.exec == DA2_BLT_CIDLE) { + da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); } - da2_log("da2 End bitblt %x\n", da2->bitblt.exec); } } @@ -1091,7 +1109,9 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ case LC_START_VERTICAL_BLANK: /* Start Vertical Blank Register */ - // val = 0x400; /* for debugging bitblt in Win 3.x */ +#ifdef ENABLE_DA2_DEBUGFULLSCREEN + val = 0x400; /* for debugging bitblt in Win 3.x */ +#endif break; case LC_VIEWPORT_SELECT: /* ViewPort Select? */ // return; @@ -1204,7 +1224,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); return; } - da2->gdcreg[da2->gdcaddr & 15] = val & 0xff; + da2->gdcreg[da2->gdcaddr & 0x0f] = val & 0xff; break; // case 0x3ed: /* used by Windows 3.1 display driver */ // da2->gdcreg[5] = val & 0xff; @@ -1280,11 +1300,11 @@ da2_in(uint16_t addr, void *p) temp |= 0x80; } temp &= 0xf6; /* clear busy bit */ - if (da2->bitblt.indata) /* for OS/2 J1.3 */ - da2_bitblt_dopayload(da2); + // if (da2->bitblt.indata) /* for OS/2 J1.3 */ + // da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { // da2_log("exec:%x\n", da2->bitblt.exec); - temp |= 0x08; // wait(bit 3 + bit 0) + temp |= 0x01; // wait(bit 3 + bit 0) // if (!da2->bitblt.timer.enabled) //{ // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); @@ -1292,8 +1312,8 @@ da2_in(uint16_t addr, void *p) // } } if (da2->bitblt.indata) - temp |= 0x01; - // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); + temp |= 0x08; + da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); } // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); break; @@ -2143,8 +2163,10 @@ da2_mapping_update(da2_t *da2) mem_mapping_enable(&da2->cmapping); mem_mapping_enable(&da2->mmio.mapping); timer_enable(&da2->timer); + timer_enable(&da2->bitblt.timer); } else { da2_log("DA2 disable registers\n"); + timer_disable(&da2->bitblt.timer); timer_disable(&da2->timer); mem_mapping_disable(&da2->cmapping); mem_mapping_disable(&da2->mmio.mapping); @@ -2193,28 +2215,28 @@ da2_mca_reset(void *p) } static void -da2_gdcropB(uint32_t addr, da2_t *da2) +da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) { for (int i = 0; i < 8; i++) { if (da2->writemask & (1 << i)) { - // da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW]); + // da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, bitmask); switch (da2->gdcreg[LG_COMMAND] & 0x03) { case 0: /*Set*/ - // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); - da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->gdcsrc[i] & ~bitmask); + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); + da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); break; case 1: /*AND*/ - // da2->vram[addr | i] = (da2->gdcinput[i] | ~da2->gdcreg[LG_BIT_MASK_LOW]) & da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask) & da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); break; case 2: /*OR*/ - // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) | da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); break; case 3: /*XOR*/ - // da2->vram[addr | i] = (da2->gdcinput[i] & da2->gdcreg[LG_BIT_MASK_LOW]) ^ da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->vram[addr | i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) ^ da2->gdcsrc[i]; + da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); break; } } @@ -2303,15 +2325,13 @@ da2_mmio_read(uint32_t addr, void *p) return DA2_INVALIDACCESS8; /* invalid memory access */ break; } - } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 or 256 color mode */ - { + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 or 256 color mode */ cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) da2->gdcla[i] = da2->vram[(addr << 3) | i]; /* read in byte */ // da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); if (da2->gdcreg[LG_MODE] & 0x08) { /* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint8_t ret = 0; - for (int i = 0; i < 8; i++) { if (~da2->gdcreg[LG_COLOR_DONT_CARE] & (1 << i)) /* color don't care register */ ret |= da2->gdcla[i] ^ ((da2->gdcreg[LG_COLOR_COMPAREJ] & (1 << i)) ? 0xff : 0); @@ -2319,8 +2339,8 @@ da2_mmio_read(uint32_t addr, void *p) return ~ret; } else return da2->gdcla[da2->readplane]; - } else /* text mode 3 */ - { + } else { /* text mode 3 */ + cycles -= video_timing_read_b; return da2->vram[addr]; } @@ -2329,7 +2349,7 @@ static uint16_t da2_mmio_readw(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; - da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ @@ -2419,9 +2439,12 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); break; } - } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ - { + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 color or 256 color mode */ uint8_t wm = da2->writemask; + uint8_t bitmask; + /* align bitmask to even address */ + if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; // da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); #ifdef ENABLE_DA2_DEBUGBLT // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) @@ -2460,20 +2483,20 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2->gdcinput[i] = ~val; else da2->gdcinput[i] = val; - da2_gdcropB(addr, da2); + da2_gdcropB(addr, bitmask, da2); return; } switch (da2->writemode) { - case 2: + case 2: /* equiv to vga write mode 1 */ for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) da2->vram[addr | i] = da2->gdcsrc[i]; break; - case 0: + case 0:/* equiv to vga write mode 0 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - if (da2->gdcreg[LG_BIT_MASK_LOW] == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + if (bitmask == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) da2->vram[addr | i] = val; @@ -2486,38 +2509,39 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) for (int i = 0; i < 8; i++) da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */ - da2_gdcropB(addr, da2); + da2_gdcropB(addr, bitmask, da2); // for (int i = 0; i < 8; i++) - // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch + // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], bitmask, da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch ////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; - case 1: + case 1:/* equiv to vga write mode 2 */ if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) - da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & da2->gdcreg[LG_BIT_MASK_LOW]) | (da2->gdcsrc[i] & ~da2->gdcreg[LG_BIT_MASK_LOW]); + da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + fprintf(da2->mmdbg_fp, "m1-1"); } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); - da2_gdcropB(addr, da2); + da2_gdcropB(addr, bitmask, da2); + fprintf(da2->mmdbg_fp, "m1-2"); } break; - case 3: + case 3:/* equiv to vga write mode 3 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - wm = da2->gdcreg[LG_BIT_MASK_LOW]; - da2->gdcreg[LG_BIT_MASK_LOW] &= val; + wm = bitmask; + bitmask &= val; for (int i = 0; i < 8; i++) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; - da2_gdcropB(addr, da2); - da2->gdcreg[LG_BIT_MASK_LOW] = wm; + da2_gdcropB(addr, bitmask, da2); + bitmask = wm; break; } // da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); - } else /* mode 3h text */ - { + } else { /* mode 3h text */ cycles -= video_timing_write_b; da2->vram[addr] = val; da2->fullchange = 2; @@ -2644,8 +2668,7 @@ da2_mmio_writew(uint32_t addr, uint16_t val, void *p) // da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); - } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ - { + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 color or 256 color mode */ addr &= DA2_MASK_MMIO; // return; // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); @@ -3039,7 +3062,7 @@ da2_init() timer_add(&da2->timer, da2_poll, da2, 0); da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ - timer_add(&da2->bitblt.timer, da2_bitblt_exec, da2, 0); + timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; } From f6b6e39349b5cbe83a8d5d8859dbd4c7be28e4b6 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:06:47 +0900 Subject: [PATCH 0291/1190] cleanup format --- src/disk/hdc_esdi_mca.c | 74 +++++++++++------------------------------ 1 file changed, 20 insertions(+), 54 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index df2a26349..690f658a0 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1385,9 +1385,7 @@ esdi_init(UNUSED(const device_t *info)) if (info->local == ESDI_IS_ADAPTER) { dev->pos_regs[0] = 0xff; dev->pos_regs[1] = 0xdd; - } - else if (info->local == ESDI_IS_INTEGRATED) - { + } else if (info->local == ESDI_IS_INTEGRATED) { dev->pos_regs[0] = 0x9f; dev->pos_regs[1] = 0xdf; } @@ -1400,8 +1398,7 @@ esdi_init(UNUSED(const device_t *info)) mca_add_to_slot(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev, slotno - 1); else mca_add(esdi_mca_read, esdi_integrated_mca_write, esdi_mca_feedb, esdi_reset, dev); - } - else + } else mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, NULL, dev); /* Mark for a reset. */ @@ -1453,56 +1450,25 @@ const device_t esdi_ps2_device = { }; static device_config_t -esdi_integrated_config[] = -{ - { - .name = "in_esdi_slot", - .description = "Slot #", - .type = CONFIG_SELECTION, - .selection = - { - { - .description = "Auto", - .value = 0 - }, - { - .description = "1", - .value = 1 - }, - { - .description = "2", - .value = 2 - }, - { - .description = "3", - .value = 3 - }, - { - .description = "4", - .value = 4 - }, - { - .description = "5", - .value = 5 - }, - { - .description = "6", - .value = 6 - }, - { - .description = "7", - .value = 7 - }, - { - .description = "8", - .value = 8 - } - }, - .default_int = 0 + esdi_integrated_config[] = { + { + .name = "in_esdi_slot", + .description = "Slot #", + .type = CONFIG_SELECTION, + .selection = { + { .description = "Auto", .value = 0 }, + { .description = "1", .value = 1 }, + { .description = "2", .value = 2 }, + { .description = "3", .value = 3 }, + { .description = "4", .value = 4 }, + { .description = "5", .value = 5 }, + { .description = "6", .value = 6 }, + { .description = "7", .value = 7 }, + { .description = "8", .value = 8 } + }, + .default_int = 0 }, - { - .type = -1 - } + { .type = -1 } }; const device_t From 5314f519adb59f4aa70f3ad68d3c47c627087451 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:11:33 +0900 Subject: [PATCH 0292/1190] cleanup format --- src/floppy/fdc.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index a8d2e6520..8a1a33f2f 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -744,13 +744,11 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. If it fails, then floppy drives will be treated as DD drives. */ if (fdc->flags & FDC_FLAG_PS2_MCA) { - if (val & 0x04) - { - fdc->tfifo = 8; + if (val & 0x04) { + fdc->tfifo = 8; fdc->fifointest = 1; - } - else { - fdc->tfifo = 1; + } else { + fdc->tfifo = 1; fdc->fifointest = 0; } } @@ -767,10 +765,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->dsr = val; return; case 5: /*Command register*/ - if (fdc->fifointest) - { + if (fdc->fifointest) { /* Write FIFO buffer in the test mode (PS/55) */ - fdc_log("FIFO buffer position = %X\n", ((fifo_t *)fdc->fifo_p)->end); + fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end); fifo_write(val, fdc->fifo_p); if (fifo_get_full(fdc->fifo_p)) fdc->stat &= ~0x80; @@ -1368,8 +1365,7 @@ fdc_read(uint16_t addr, void *priv) ret = fdc->stat; break; case 5: /*Data*/ - if (fdc->fifointest) - { + if (fdc->fifointest) { /* Read FIFO buffer in the test mode (PS/55) */ ret = fifo_read(fdc->fifo_p); break; From 4b92bb62cbc97bc342b24060e7a6e63223f92aa6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 00:41:34 +0100 Subject: [PATCH 0293/1190] Commodore SL386SX-16: Remove internal IDE controller, sicne the real board has none. --- src/machine/m_at_286_386sx.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 362f035e0..24cb88f09 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -626,7 +626,7 @@ machine_at_cmdsl386sx16_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); + machine_at_common_init(model); device_add(&keyboard_ps2_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 5010f984c..cb6bc964e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4688,7 +4688,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_IDE, + .flags = MACHINE_FLAGS_NONE, .ram = { .min = 1024, .max = 8192, From 3d8bc797725fe49adaeb9ba26e3d16fa55e354d6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 01:17:21 +0100 Subject: [PATCH 0294/1190] NEAT: Fix EMS memory space allocation to correctly take RAM from the bottom rather than from the top. --- src/chipset/neat.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 2990b5216..696f48d20 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -27,6 +27,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> @@ -263,6 +264,64 @@ neat_log(const char *fmt, ...) # define neat_log(fmt, ...) #endif +static uint8_t +neat_read_ram(uint32_t addr, void *priv) +{ + neat_t *dev = (neat_t *) priv; + + if (dev->regs[REG_RB7] & RB7_EMSEN) + addr += (dev->ems_size << 10); + + if (cpu_use_exec) + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + +static uint16_t +neat_read_ramw(uint32_t addr, void *priv) +{ + neat_t *dev = (neat_t *) priv; + + if (dev->regs[REG_RB7] & RB7_EMSEN) + addr += (dev->ems_size << 10); + + if (cpu_use_exec) + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *) &ram[addr]; +} + +static void +neat_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + neat_t *dev = (neat_t *) priv; + + if (dev->regs[REG_RB7] & RB7_EMSEN) + addr += (dev->ems_size << 10); + + if (cpu_use_exec) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); + } else + ram[addr] = val; +} + +static void +neat_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + neat_t *dev = (neat_t *) priv; + + if (dev->regs[REG_RB7] & RB7_EMSEN) + addr += (dev->ems_size << 10); + + if (cpu_use_exec) { + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); + } else + *(uint16_t *) &ram[addr] = val; +} + /* Read one byte from paged RAM. */ static uint8_t ems_readb(uint32_t addr, void *priv) @@ -603,9 +662,11 @@ remap_update(neat_t *dev, uint8_t val) else mem_mapping_set_addr(&ram_low_mapping, 0x00000000, dev->remap_base << 10); - if (dev->remap_base > 1024) + if (dev->remap_base > 1024) { mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); - else + mem_mapping_set_exec(&ram_high_mapping, &(ram[(val & RB7_EMSEN) ? 0x00100000 : + (0x00100000 + (dev->ems_size << 10))])); + } else mem_mapping_disable(&ram_high_mapping); if (val & RB7_UMAREL) { @@ -908,6 +969,12 @@ neat_init(UNUSED(const device_t *info)) /* Create an instance. */ dev = (neat_t *) calloc(1, sizeof(neat_t)); + if (mem_size > 1024) { + mem_mapping_set_handler(&ram_high_mapping, neat_read_ram, neat_read_ramw, NULL, + neat_write_ram, neat_write_ramw, NULL); + mem_mapping_set_p(&ram_high_mapping, dev); + } + /* Get configured I/O address. */ j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH; dev->ems_base = 0x0208 + (0x10 * j); From 63b223973c63828862ee25184d064b573087b0bd Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 01:27:40 +0100 Subject: [PATCH 0295/1190] NEAT: Mirror EMS port 2x8h on port 2x9h for reads as well, fixes EMS detection by Chips Expanded Manager version 2.2.0. --- src/chipset/neat.c | 59 ++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 696f48d20..d4eb3ec7f 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -34,8 +34,6 @@ #include <86box/plat_unused.h> #include <86box/chipset.h> -#define NEAT_DEBUG 0 - #define EMS_MAXPAGE 4 #define EMS_PGSIZE 16384 #define EMS_PGMASK 16383 @@ -328,7 +326,7 @@ ems_readb(uint32_t addr, void *priv) { ram_page_t *dev = (ram_page_t *) priv; uint8_t ret = 0xff; -#ifdef ENABLE_NEAT_LOG +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) uint32_t old = addr; #endif @@ -338,7 +336,9 @@ ems_readb(uint32_t addr, void *priv) if (addr < (mem_size << 10)) ret = *(uint8_t *) &(ram[addr]); +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) neat_log("[R08] %08X -> %08X (%08X): ret = %02X\n", old, addr, (mem_size << 10), ret); +#endif return ret; } @@ -348,7 +348,7 @@ ems_readw(uint32_t addr, void *priv) { ram_page_t *dev = (ram_page_t *) priv; uint16_t ret = 0xffff; -#ifdef ENABLE_NEAT_LOG +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) uint32_t old = addr; #endif @@ -358,7 +358,9 @@ ems_readw(uint32_t addr, void *priv) if (addr < (mem_size << 10)) ret = *(uint16_t *) &(ram[addr]); +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) neat_log("[R16] %08X -> %08X (%08X): ret = %04X\n", old, addr, (mem_size << 10), ret); +#endif return ret; } @@ -367,13 +369,15 @@ static void ems_writeb(uint32_t addr, uint8_t val, void *priv) { ram_page_t *dev = (ram_page_t *) priv; -#ifdef ENABLE_NEAT_LOG +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) uint32_t old = addr; #endif /* Write the data. */ addr = addr - dev->virt_base + dev->phys_base; +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) neat_log("[W08] %08X -> %08X (%08X): val = %02X\n", old, addr, (mem_size << 10), val); +#endif if (addr < (mem_size << 10)) *(uint8_t *) &(ram[addr]) = val; @@ -384,13 +388,15 @@ static void ems_writew(uint32_t addr, uint16_t val, void *priv) { ram_page_t *dev = (ram_page_t *) priv; -#ifdef ENABLE_NEAT_LOG +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) uint32_t old = addr; #endif /* Write the data. */ addr = addr - dev->virt_base + dev->phys_base; +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 3) neat_log("[W16] %08X -> %08X (%08X): val = %04X\n", old, addr, (mem_size << 10), val); +#endif if (addr < (mem_size << 10)) *(uint16_t *) &(ram[addr]) = val; @@ -505,7 +511,7 @@ ems_recalc(neat_t *dev, ram_page_t *ems) neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, MEM_FLAG_EMS, MEM_FMASK_EMS); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT EMS: page %d set to %08lx, %sabled)\n", ems->page, ems->addr - ram, ems->enabled ? "en" : "dis"); #endif @@ -528,7 +534,7 @@ ems_write(uint16_t port, uint8_t val, void *priv) int8_t new_enabled; uint32_t new_phys_base; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: ems_write(%04x, %02x)\n", port, val); #endif @@ -577,6 +583,7 @@ ems_read(uint16_t port, void *priv) switch (port & 0x000f) { case 0x0008: /* page number register */ + case 0x0009: ret = (dev->ems[vpage].phys_base / EMS_PGSIZE) & 0x7f; if (dev->ems[vpage].enabled) ret |= 0x80; @@ -587,7 +594,7 @@ ems_read(uint16_t port, void *priv) neat_log("Port: %04X, ret: %02X\n", port, ret); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret); #endif @@ -686,7 +693,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) uint8_t *reg; int i; -#if NEAT_DEBUG > 2 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: write(%04x, %02x)\n", port, val); #endif @@ -704,7 +711,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) *reg = (*reg & ~RA0_MASK) | val | (RA0_REV_ID << RA0_REV_SH); if ((xval & 0x20) && (val & 0x20)) outb(0x64, 0xfe); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA0=%02x(%02x)\n", val, *reg); #endif break; @@ -712,7 +719,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RA1: val &= RA1_MASK; *reg = (*reg & ~RA1_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg); #endif break; @@ -720,7 +727,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RA2: val &= RA2_MASK; *reg = (*reg & ~RA2_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg); #endif break; @@ -728,7 +735,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB0: val &= RB0_MASK; *reg = (*reg & ~RB0_MASK) | val | (RB0_REV_ID << RB0_REV_SH); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg); #endif break; @@ -737,7 +744,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) val &= RB1_MASK; *reg = (*reg & ~RB1_MASK) | val; shadow_recalc(dev); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg); #endif break; @@ -749,7 +756,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) neat_mem_update_state(dev, 0x00080000, 0x00020000, MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); else neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, MEM_FMASK_SHADOW); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); #endif break; @@ -758,7 +765,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) val &= RB3_MASK; *reg = (*reg & ~RB3_MASK) | val; shadow_recalc(dev); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg); #endif break; @@ -767,7 +774,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) val &= RB4_MASK; *reg = (*reg & ~RB4_MASK) | val; shadow_recalc(dev); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg); #endif break; @@ -776,7 +783,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) val &= RB5_MASK; *reg = (*reg & ~RB5_MASK) | val; shadow_recalc(dev); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg); #endif break; @@ -784,7 +791,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB6: val &= RB6_MASK; *reg = (*reg & ~RB6_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg); #endif break; @@ -803,7 +810,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) if ((xval & RB7_EMSEN) && (val & RB7_EMSEN)) ems_set_handlers(dev); -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg); #endif break; @@ -811,7 +818,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB8: val &= RB8_MASK; *reg = (*reg & ~RB8_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg); #endif break; @@ -819,7 +826,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB9: val &= RB9_MASK; *reg = (*reg & ~RB9_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); #endif @@ -842,7 +849,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB10: val &= RB10_MASK; *reg = (*reg & ~RB10_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); #endif @@ -877,7 +884,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) case REG_RB12: val &= RB12_MASK; *reg = (*reg & ~RB12_MASK) | val; -#if NEAT_DEBUG > 1 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB12=%02x(%02x)\n", val, *reg); #endif i = (val & RB12_EMSLEN) >> RB12_EMSLEN_SH; @@ -944,7 +951,7 @@ neat_read(uint16_t port, void *priv) break; } -#if NEAT_DEBUG > 2 +#if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: read(%04x) = %02x\n", port, ret); #endif From 5c4fcfaf8525768dccaad201ad7e7911f475c1b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 04:49:43 +0100 Subject: [PATCH 0296/1190] ESC/P Printer: No longer assume roms/ is where the binary is, fixes #5221. --- src/include/86box/plat.h | 4 +- src/include/86box/rom.h | 1 + src/io.c | 104 ++++++++++++++++++++++++++++++++++--- src/mem/rom.c | 42 +++++++++++++++ src/printer/prt_escp.c | 10 ++-- src/qt/languages/86box.pot | 6 +++ src/qt/languages/ca-ES.po | 6 +++ src/qt/languages/cs-CZ.po | 6 +++ src/qt/languages/de-DE.po | 6 +++ src/qt/languages/es-ES.po | 6 +++ src/qt/languages/fi-FI.po | 6 +++ src/qt/languages/fr-FR.po | 6 +++ src/qt/languages/hr-HR.po | 10 +++- src/qt/languages/hu-HU.po | 6 +++ src/qt/languages/it-IT.po | 8 ++- src/qt/languages/ja-JP.po | 6 +++ src/qt/languages/ko-KR.po | 6 +++ src/qt/languages/nl-NL.po | 6 +++ src/qt/languages/pl-PL.po | 6 +++ src/qt/languages/pt-BR.po | 6 +++ src/qt/languages/pt-PT.po | 6 +++ src/qt/languages/ru-RU.po | 6 +++ src/qt/languages/sk-SK.po | 6 +++ src/qt/languages/sl-SI.po | 10 +++- src/qt/languages/tr-TR.po | 6 +++ src/qt/languages/uk-UA.po | 6 +++ src/qt/languages/vi-VN.po | 6 +++ src/qt/languages/zh-CN.po | 6 +++ src/qt/languages/zh-TW.po | 8 ++- src/qt/qt_platform.cpp | 2 + 30 files changed, 300 insertions(+), 19 deletions(-) diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index f39f6ba51..81874685e 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -50,7 +50,9 @@ enum { STRING_HW_NOT_AVAILABLE_DEVICE, /* "Device \"%hs\" is not available..." */ STRING_MONITOR_SLEEP, /* "Monitor in sleep mode" */ STRING_GHOSTPCL_ERROR_TITLE, /* "Unable to initialize GhostPCL" */ - STRING_GHOSTPCL_ERROR_DESC /* "gpcl6dll32.dll/gpcl6dll64.dll/libgpcl6 is required..." */ + STRING_GHOSTPCL_ERROR_DESC, /* "gpcl6dll32.dll/gpcl6dll64.dll/libgpcl6 is required..." */ + STRING_ESCP_ERROR_TITLE, /* "Unable to find Dot-Matrix fonts" */ + STRING_ESCP_ERROR_DESC /* "TrueType fonts in the \"roms/printer/fonts\" directory..." */ }; /* The Win32 API uses _wcsicmp. */ diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index 1f6e611b1..83fd7cf90 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -52,6 +52,7 @@ extern uint8_t rom_read(uint32_t addr, void *priv); extern uint16_t rom_readw(uint32_t addr, void *priv); extern uint32_t rom_readl(uint32_t addr, void *priv); +extern void rom_get_full_path(char *dest, const char *fn); extern FILE *rom_fopen(const char *fn, char *mode); extern int rom_getfile(char *fn, char *s, int size); extern int rom_present(const char *fn); diff --git a/src/io.c b/src/io.c index 27f8503b0..2565ac537 100644 --- a/src/io.c +++ b/src/io.c @@ -30,6 +30,7 @@ #include "cpu.h" #include <86box/m_amstrad.h> #include <86box/pci.h> +#include <86box/mem.h> #define NPORTS 65536 /* PC/AT supports 64K ports */ @@ -59,6 +60,7 @@ int initialized = 0; io_t *io[NPORTS]; io_t *io_last[NPORTS]; +// #define ENABLE_IO_LOG 1 #ifdef ENABLE_IO_LOG int io_do_log = ENABLE_IO_LOG; @@ -69,7 +71,8 @@ io_log(const char *fmt, ...) if (io_do_log) { va_start(ap, fmt); - pclog_ex(fmt, ap); + if (CS == 0xf000) + pclog_ex(fmt, ap); va_end(ap); } } @@ -77,6 +80,18 @@ io_log(const char *fmt, ...) # define io_log(fmt, ...) #endif +uint16_t last_port_read = 0xffff; + +static void +print_lpr(void) +{ + FILE *f = fopen("d:\\86boxnew\\ndiags.dmp", "wb"); + fwrite(&(ram[0x24c30]), 1, 65536, f); + fclose(f); + + pclog("last_port_read = %04X\n", last_port_read); +} + void io_init(void) { @@ -106,6 +121,8 @@ io_init(void) /* io[c] should be NULL. */ io[c] = io_last[c] = NULL; } + + atexit(print_lpr); } void @@ -333,6 +350,11 @@ io_debug_check_addr(uint16_t addr) } #endif +#include <86box/random.h> + +uint8_t post_code = 0xc6; +uint8_t action = 0x00; + uint8_t inb(uint16_t port) { @@ -393,7 +415,33 @@ inb(uint16_t port) ret = 0xfe; #endif - io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); +#if 0 + if (port == 0x5f7) + ret = 0xaf; +#endif + + if (port == 0x379) + ret &= 0xf8; + + // io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + + // if (CS == 0xc000) + // pclog("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, port, ret); + + // if (port == 0x62) + // ret = 0xf2; + + // if (port == 0x62) + // ret |= random_generate() & 0x80; + + // if ((port >= 0x60) && (port <= 0x66)) + // pclog("[%04X:%04X] [R] %04X = %02X\n", CS, cpu_state.pc, port, ret); + + if ((port != 0x0061) && (port != 0x0177) && (port != 0x01f7) && (port != 0x0376) && (port != 0x03c7) && (port != 0x03c8) && (port != 0x03c9) && (port != 0x03f6) && (port != 0x03da)) { + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } + + last_port_read = port; return ret; } @@ -447,7 +495,20 @@ outb(uint16_t port, uint8_t val) #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + // io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + + if (port == 0x0068) + action = val; + + if (port == 0x0080) + post_code = val; + + // if (port == 0x3db) + // pclog("[%04X:%04X] [W] %04X = %02X\n", CS, cpu_state.pc, port, val); + + if ((port != 0x0061) && (port != 0x00ed) && (port != 0x03c7) && (port != 0x03c8) && (port != 0x03c9)) { + io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } @@ -525,7 +586,9 @@ inw(uint16_t port) if (!found) cycles -= io_delay; - io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + if (1) { + io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } return ret; } @@ -594,7 +657,21 @@ outw(uint16_t port, uint16_t val) #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + if (port == 0x0080) + post_code = val; + +#if 0 + if (port == 0x0c02) { + if (val) + mem_set_mem_state(0x000e0000, 0x00020000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else + mem_set_mem_state(0x000e0000, 0x00020000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } +#endif + + if (1) { + io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } @@ -704,7 +781,9 @@ inl(uint16_t port) if (!found) cycles -= io_delay; - io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + if (1) { + io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); + } return ret; } @@ -791,7 +870,9 @@ outl(uint16_t port, uint32_t val) #endif } - io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + if (1) { + io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); + } return; } @@ -801,6 +882,7 @@ io_trap_readb(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(1, addr, 0, 0, trap->priv); + pclog("[%04X:%08X] io_trap_readb(%04X)\n", CS, cpu_state.pc, addr); return 0xff; } @@ -809,6 +891,7 @@ io_trap_readw(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(2, addr, 0, 0, trap->priv); + pclog("[%04X:%08X] io_trap_readw(%04X)\n", CS, cpu_state.pc, addr); return 0xffff; } @@ -817,6 +900,7 @@ io_trap_readl(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(4, addr, 0, 0, trap->priv); + pclog("[%04X:%08X] io_trap_readl(%04X)\n", CS, cpu_state.pc, addr); return 0xffffffff; } @@ -825,6 +909,7 @@ io_trap_writeb(uint16_t addr, uint8_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(1, addr, 1, val, trap->priv); + pclog("[%04X:%08X] io_trap_writeb(%04X)\n", CS, cpu_state.pc, addr); } static void @@ -832,6 +917,7 @@ io_trap_writew(uint16_t addr, uint16_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(2, addr, 1, val, trap->priv); + pclog("[%04X:%08X] io_trap_writew(%04X)\n", CS, cpu_state.pc, addr); } static void @@ -839,6 +925,7 @@ io_trap_writel(uint16_t addr, uint32_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(4, addr, 1, val, trap->priv); + pclog("[%04X:%08X] io_trap_writel(%04X)\n", CS, cpu_state.pc, addr); } void * @@ -885,6 +972,9 @@ io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size) io_trap_writeb, io_trap_writew, io_trap_writel, trap); } + + if ((addr == 0x0170) || (addr == 0x0376) || (addr == 0x01f0) || (addr == 0x03f6)) + pclog("io_trap_remape(%04X) = %i\n", addr, trap->enable); } void diff --git a/src/mem/rom.c b/src/mem/rom.c index f9718b7ce..8b2308402 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -86,6 +86,48 @@ rom_add_path(const char *path) path_slash(rom_path->path); } +static int +rom_check(const char *fn) +{ + FILE *fp = NULL; + int ret = 0; + + if ((fn[strlen(fn) - 1] == '/') || (fn[strlen(fn) - 1] == '\\')) + ret = plat_dir_check((char *) fn); + else { + fp = fopen(fn, "rb"); + ret = (fp != NULL); + fclose(fp); + } + + return ret; +} + +void +rom_get_full_path(char *dest, const char *fn) +{ + char temp[1024] = { 0 }; + + dest[0] = 0x00; + + if (strstr(fn, "roms/") == fn) { + /* Relative path */ + for (rom_path_t *rom_path = &rom_paths; rom_path != NULL; rom_path = rom_path->next) { + path_append_filename(temp, rom_path->path, fn + 5); + + if (rom_check(temp)) { + strcpy(dest, temp); + return; + } + } + + return; + } else { + /* Absolute path */ + strcpy(dest, fn); + } +} + FILE * rom_fopen(const char *fn, char *mode) { diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 0198444a0..d0836e5f2 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1968,16 +1968,16 @@ escp_init(void *lpt) dev->ctrl = 0x04; dev->lpt = lpt; + rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); + /* Create a full pathname for the font files. */ - if (strlen(exe_path) >= sizeof(dev->fontpath)) { + if (strlen(dev->fontpath) == 0) { + ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_ESCP_ERROR_TITLE), + plat_get_string(STRING_ESCP_ERROR_DESC)); free(dev); return (NULL); } - strcpy(dev->fontpath, exe_path); - path_slash(dev->fontpath); - strcat(dev->fontpath, "roms/printer/fonts/"); - /* Create the full path for the page images. */ path_append_filename(dev->pagepath, usr_path, "printer"); if (!plat_dir_check(dev->pagepath)) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index ac2db7d07..65cc32f85 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2135,3 +2135,9 @@ msgstr "" msgid "Generic PC/AT Memory Expansion" msgstr "" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index e49ab3223..cf3d5c7f7 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -2129,3 +2129,9 @@ msgstr "Expansió de memòria genèrica PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Expansió de memòria genèrica PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "No es pot trobar tipus de lletra de matriu de punts" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Els tipus de lletra TrueType al directori \"roms/printer/fonts\" són necessaris per a l'emulació de la impressora de matriu de punts ESC/P genèrica." diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index cafadd63b..e3d85dd09 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -2129,3 +2129,9 @@ msgstr "Obecné rozšíření paměti PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Obecné rozšíření paměti PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nastala chyba při nachození jehličkových písem" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Pro emulaci obecné jehličkové tiskárny ESC/P jsou vyžadována písma TrueType ve složce \"roms/printer/fonts\"." diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index aa666cc48..c904cad0d 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2132,3 +2132,9 @@ msgstr "Generische PC/XT-Speichererweiterung" msgid "Generic PC/AT Memory Expansion" msgstr "Generische PC/AT-Speichererweiterung" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nadel-Schriften konnten nicht gefunden werden" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "TrueType-Schriften in das \"roms/printer/fonts\"-Verzeichnis sind für die Allgemeines ESC/P Nadel-Druckers erforderlich." diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 5cac8968f..ca7a3ad53 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -2128,3 +2128,9 @@ msgstr "Expansión de Memoria Generica PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Expansión de Memoria Generica PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "No fué posible encontrar las fuentes matriciales" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Las fuentes TrueType en el directorio \"roms/printer/fonts\" son necesarias para la emulación de la impresora matricial ESC/P genérica." diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 21dcfd1bc..f044365f0 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -2129,3 +2129,9 @@ msgstr "Yleinen PC/XT-muistilaajennus" msgid "Generic PC/AT Memory Expansion" msgstr "Yleinen PC/AT-muistilaajennus" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Pistematriisifontteja ei löydy" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "TrueType-fontteja kansiossa \"roms/printer/fonts\"-hakemistoon yleinen ESC/P pistematriisitulostin emulointiin." diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index ff8a5168f..3b283b3dd 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -2129,3 +2129,9 @@ msgstr "Expansion de la mémoire générique PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Expansion de la mémoire générique PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Impossible de trouver les polices à matrice à points" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Les polices TrueType dans le répertoire \"roms/printer/fonts\" sont nécessaires à l'émulation de l'imprimante générique ESC/P à matrice à points." diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 9d242f8e0..ed4fdf621 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -655,7 +655,7 @@ msgid "ZIP images" msgstr "ZIP slike" msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." -msgstr "86Box nije mogao pronaći upotrebljive ROM datoteke.\n\nMolimte posjetite sknite paket s ROM datotekama i ekstrahirajte paket u \"roms\" mapu." +msgstr "86Box nije mogao pronaći upotrebljive ROM datoteke.\n\nMolimte posjetite sknite paket s ROM datotekama i ekstrahirajte paket u mapu \"roms\"." msgid "(empty)" msgstr "(prazno)" @@ -2062,7 +2062,7 @@ msgid "Generic Text Printer" msgstr "Generični tekstovni pisač" msgid "Generic ESC/P Dot-Matrix Printer" -msgstr "Generični pisač matrični ESC/P" +msgstr "Generični matrični pisač ESC/P" msgid "Generic PostScript Printer" msgstr "Generični pisač PostScript" @@ -2129,3 +2129,9 @@ msgstr "Generičko proširenje memorije PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Generičko proširenje memorije PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nije moguće pronaći matrične fontove" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "TrueType fontovi u mapi \"roms/printer/fonts\" potrebni su za emulaciju generičnog matričnog pisača ESC/P." diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 2b5adacf4..b4afd8010 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -2129,3 +2129,9 @@ msgstr "Általános PC/XT memóriabővítők" msgid "Generic PC/AT Memory Expansion" msgstr "Általános PC/AT memóriabővítők" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nem találja a Dot-Matrix betűtípusokat" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Az általános ESC/P pontmátrixnyomtató emulációjához a \"roms/printer/fonts\" könyvtárban található TrueType betűtípusok szükségesek." diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index c9af80127..73ec57ec0 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -655,7 +655,7 @@ msgid "ZIP images" msgstr "Immagini ZIP" msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." -msgstr "86Box non può trovare immagini ROM utilizzabili.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box non può trovare immagini ROM utilizzabili.\n\nSi prega di scaricare un set di ROM ed estrarlo nella directory \"roms\"." msgid "(empty)" msgstr "(empty)" @@ -2129,3 +2129,9 @@ msgstr "Espansione di memoria generica PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Espansione di memoria generica PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Impossibile trovare i font a matrice di punti" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "I font TrueType presenti nella directory \"roms/printer/fonts\" sono necessari per l'emulazione della stampante a matrice di punti ESC/P generica." diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 9a3289b51..9c6fa66e7 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2129,3 +2129,9 @@ msgstr "汎用PC/XTメモリ拡張カード" msgid "Generic PC/AT Memory Expansion" msgstr "汎用PC/ATメモリ拡張カード" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "ドットマトリクスフォントが見つかりません" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "汎用ESC/Pドットマトリクスプリンタのエミュレーションには、roms/printer/fontsディレクトリ内のTrueTypeフォントが必要です。" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index c6928ad43..ec4b20d0d 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -2129,3 +2129,9 @@ msgstr "일반 PC/XT 메모리 확장 카드" msgid "Generic PC/AT Memory Expansion" msgstr "일반 PC/AT 메모리 확장 카드" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "도트 매트릭스 글꼴을 찾을 수 없습니다" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "일반 ESC/P 도트 매트릭스 프린터의 에뮬레이션을 사용하려면 \"roms/printer/fonts\" 디렉터리에 있는 트루타입 글꼴이 필요합니다." diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 27870db90..c601197ac 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -2129,3 +2129,9 @@ msgstr "Generieke PC/XT geheugenuitbreiding" msgid "Generic PC/AT Memory Expansion" msgstr "Generieke PC/AT geheugenuitbreiding" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Dot-matrix-lettertypen niet gevonden" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "TrueType lettertypen in de map \"roms/printer/fonts\" zijn nodig voor de emulatie van de generieke ESC/P dot-matrix-printer." diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index e42904458..78ded239f 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -2129,3 +2129,9 @@ msgstr "Generyczne rozszerzenie pamięci PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Generyczne rozszerzenie pamięci PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nie można znaleźć czcionek igłowych" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Czcionki TrueType w katalogu \"roms/printer/fonts\" są wymagane do emulacji generyczniej drukarki igłowej ESC/P." diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index de1bcd544..1594e30ab 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2129,3 +2129,9 @@ msgstr "Expansão de memória genérica PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Expansão de memória genérica PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Não foi possível localizar os fontes matriciais de pontos" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "As fontes TrueType no diretório \"roms/printer/fonts\" são necessárias para a emulação da impressora matricial de pontos ESC/P genérica." diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index d4c8bf170..b31f020d4 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2129,3 +2129,9 @@ msgstr "Expansão de memória genérica PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Expansão de memória genérica PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Não foi possível encontrar os fontes matriciais de pontos" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "As fontes TrueType no diretório \"roms/printer/fonts\" são necessárias para a emulação da impressora matricial de pontos ESC/P genérica" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index a2e352faa..a8a4b7794 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2135,3 +2135,9 @@ msgstr "Стандартное расширение памяти PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Стандартное расширение памяти PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Невозможно найти матричные шрифты" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Шрифты TrueType в каталоге \"roms/printer/fonts\" необходимы для эмуляции стандартного матричного принтера ESC/P." diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 6b2074d47..e789d9ef9 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -2129,3 +2129,9 @@ msgstr "Všeobecné rozšírenie pamäte PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Všeobecné rozšírenie pamäte PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Nastala chyba pri hľadaní ihličkových písem" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Písma TrueType v adresári \"roms/printer/fonts\" sú potrebné na emuláciu generickej ihličkovej tlačiarne ESC/P." diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 9d8ccaaf9..1394a3635 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -823,10 +823,10 @@ msgid "Are you sure you want to exit 86Box?" msgstr "Ste prepričani, da želite zapreti 86Box?" msgid "Unable to initialize Ghostscript" -msgstr "Ne morem inicializirati Ghostscript" +msgstr "Ghostscript-a ni bilo mogoče inicializirati" msgid "Unable to initialize GhostPCL" -msgstr "Ne morem inicializirati GhostPCL" +msgstr "GhostPCL-ja ni bilo mogoče inicializirati" msgid "MO %i (%ls): %ls" msgstr "MO %i (%ls): %ls" @@ -2129,3 +2129,9 @@ msgstr "Generična razširitev pomnilnika PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Generična razširitev pomnilnika PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Matričnih pisav ni bilo mogoče najti" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Matrične pisave v imeniku \"roms/printer/fonts\" so potrebne za emulacijo generičnega matričnega tiskalnika ESC/P." diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 288412154..81866b3ce 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -2129,3 +2129,9 @@ msgstr "Sıradan PC/XT bellek artırma" msgid "Generic PC/AT Memory Expansion" msgstr "Sıradan PC/AT bellek artırma" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Dot Matrix yazı tipleri bulunamıyor" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Sıradan ESC/P Dot Matrix Yazıcının emülasyonu için \"roms/printer/fonts\" dizinindeki TrueType yazı tipleri gereklidir." diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 5ce59be01..9b57ac03e 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -2135,3 +2135,9 @@ msgstr "Загальне розширення пам'яті PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Загальне розширення пам'яті PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Неможливо знайти матричні шрифти" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Шрифти TrueType у каталозі \"roms/printer/fonts\" потрібні для емуляції загального матричного принтера Generic ESC/P." diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 707c7ae7f..fafbbc160 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -2129,3 +2129,9 @@ msgstr "Chung mở rộng bộ nhớ qua PC/XT" msgid "Generic PC/AT Memory Expansion" msgstr "Chung mở rộng bộ nhớ qua PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Không tìm thấy phông chữ ma trận chấm" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "Cần có phông chữ TrueType trong thư mục \"roms/printer/fonts\" để mô phỏng máy in generic ESC/P ma trận chấm." diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 81451b2b3..ec5d2c252 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -2129,3 +2129,9 @@ msgstr "通用 PC/XT 内存扩展" msgid "Generic PC/AT Memory Expansion" msgstr "通用 PC/AT 内存扩展" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "无法找到点阵字体" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "仿真通用 ESC/P 点阵打印机需要使用 \"roms/printer/fonts\" 目录中的 TrueType 字体。" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 9bf8edfc6..b0d8163cb 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2062,7 +2062,7 @@ msgid "Generic Text Printer" msgstr "通用文字印表機" msgid "Generic ESC/P Dot-Matrix Printer" -msgstr "通用 ESC/P 點矩陣" +msgstr "通用 ESC/P 點矩陣印表機" msgid "Generic PostScript Printer" msgstr "通用 PostScript 印表機" @@ -2129,3 +2129,9 @@ msgstr "通用 PC/XT 記憶體擴充" msgid "Generic PC/AT Memory Expansion" msgstr "通用 PC/AT 記憶體擴充" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "無法找到點矩陣字型" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "通用 ESC/P 點矩陣印表機的模擬需要 \"roms/printer/fonts\" 目錄中的 TrueType 字體。" diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index dd6c34efc..561c94d8a 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -639,6 +639,8 @@ ProgSettings::reloadStrings() translatedstrings[STRING_MONITOR_SLEEP] = QCoreApplication::translate("", "Monitor in sleep mode").toStdWString(); translatedstrings[STRING_NET_ERROR] = QCoreApplication::translate("", "Failed to initialize network driver").toStdWString(); translatedstrings[STRING_NET_ERROR_DESC] = QCoreApplication::translate("", "The network configuration will be switched to the null driver").toStdWString(); + translatedstrings[STRING_ESCP_ERROR_TITLE] = QCoreApplication::translate("", "Unable to find Dot-Matrix fonts").toStdWString(); + translatedstrings[STRING_ESCP_ERROR_DESC] = QCoreApplication::translate("", "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulatio of the Generic ESC/P Dot-Matrix Printer.").toStdWString(); } wchar_t * From a6a377757f3098eeb38ec3a71c725d31a897de53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 04:57:49 +0100 Subject: [PATCH 0297/1190] Paradise VGA: Override the horizontal skew handling, fixes #5228. --- src/video/vid_paradise.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index d0acaf276..da8bb9aa6 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -571,6 +571,8 @@ paradise_init(const device_t *info, uint32_t memory) paradise->type = info->local; + svga->hoverride = 1; + return paradise; } From f68810b2777ccfa749efe89bc815648fa8651a73 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 15:20:16 +0100 Subject: [PATCH 0298/1190] Reverted the io.c changes that should not have been committed. --- src/io.c | 104 ++++--------------------------------------------------- 1 file changed, 7 insertions(+), 97 deletions(-) diff --git a/src/io.c b/src/io.c index 2565ac537..27f8503b0 100644 --- a/src/io.c +++ b/src/io.c @@ -30,7 +30,6 @@ #include "cpu.h" #include <86box/m_amstrad.h> #include <86box/pci.h> -#include <86box/mem.h> #define NPORTS 65536 /* PC/AT supports 64K ports */ @@ -60,7 +59,6 @@ int initialized = 0; io_t *io[NPORTS]; io_t *io_last[NPORTS]; -// #define ENABLE_IO_LOG 1 #ifdef ENABLE_IO_LOG int io_do_log = ENABLE_IO_LOG; @@ -71,8 +69,7 @@ io_log(const char *fmt, ...) if (io_do_log) { va_start(ap, fmt); - if (CS == 0xf000) - pclog_ex(fmt, ap); + pclog_ex(fmt, ap); va_end(ap); } } @@ -80,18 +77,6 @@ io_log(const char *fmt, ...) # define io_log(fmt, ...) #endif -uint16_t last_port_read = 0xffff; - -static void -print_lpr(void) -{ - FILE *f = fopen("d:\\86boxnew\\ndiags.dmp", "wb"); - fwrite(&(ram[0x24c30]), 1, 65536, f); - fclose(f); - - pclog("last_port_read = %04X\n", last_port_read); -} - void io_init(void) { @@ -121,8 +106,6 @@ io_init(void) /* io[c] should be NULL. */ io[c] = io_last[c] = NULL; } - - atexit(print_lpr); } void @@ -350,11 +333,6 @@ io_debug_check_addr(uint16_t addr) } #endif -#include <86box/random.h> - -uint8_t post_code = 0xc6; -uint8_t action = 0x00; - uint8_t inb(uint16_t port) { @@ -415,33 +393,7 @@ inb(uint16_t port) ret = 0xfe; #endif -#if 0 - if (port == 0x5f7) - ret = 0xaf; -#endif - - if (port == 0x379) - ret &= 0xf8; - - // io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - - // if (CS == 0xc000) - // pclog("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, port, ret); - - // if (port == 0x62) - // ret = 0xf2; - - // if (port == 0x62) - // ret |= random_generate() & 0x80; - - // if ((port >= 0x60) && (port <= 0x66)) - // pclog("[%04X:%04X] [R] %04X = %02X\n", CS, cpu_state.pc, port, ret); - - if ((port != 0x0061) && (port != 0x0177) && (port != 0x01f7) && (port != 0x0376) && (port != 0x03c7) && (port != 0x03c8) && (port != 0x03c9) && (port != 0x03f6) && (port != 0x03da)) { - io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } - - last_port_read = port; + io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return ret; } @@ -495,20 +447,7 @@ outb(uint16_t port, uint8_t val) #endif } - // io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - - if (port == 0x0068) - action = val; - - if (port == 0x0080) - post_code = val; - - // if (port == 0x3db) - // pclog("[%04X:%04X] [W] %04X = %02X\n", CS, cpu_state.pc, port, val); - - if ((port != 0x0061) && (port != 0x00ed) && (port != 0x03c7) && (port != 0x03c8) && (port != 0x03c9)) { - io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outb(%04X, %02X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } @@ -586,9 +525,7 @@ inw(uint16_t port) if (!found) cycles -= io_delay; - if (1) { - io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } + io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return ret; } @@ -657,21 +594,7 @@ outw(uint16_t port, uint16_t val) #endif } - if (port == 0x0080) - post_code = val; - -#if 0 - if (port == 0x0c02) { - if (val) - mem_set_mem_state(0x000e0000, 0x00020000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - else - mem_set_mem_state(0x000e0000, 0x00020000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - } -#endif - - if (1) { - io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outw(%04X, %04X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } @@ -781,9 +704,7 @@ inl(uint16_t port) if (!found) cycles -= io_delay; - if (1) { - io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); - } + io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); return ret; } @@ -870,9 +791,7 @@ outl(uint16_t port, uint32_t val) #endif } - if (1) { - io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); - } + io_log("[%04X:%08X] (%i, %i, %04i) outl(%04X, %08X)\n", CS, cpu_state.pc, in_smm, found, qfound, port, val); return; } @@ -882,7 +801,6 @@ io_trap_readb(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(1, addr, 0, 0, trap->priv); - pclog("[%04X:%08X] io_trap_readb(%04X)\n", CS, cpu_state.pc, addr); return 0xff; } @@ -891,7 +809,6 @@ io_trap_readw(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(2, addr, 0, 0, trap->priv); - pclog("[%04X:%08X] io_trap_readw(%04X)\n", CS, cpu_state.pc, addr); return 0xffff; } @@ -900,7 +817,6 @@ io_trap_readl(uint16_t addr, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(4, addr, 0, 0, trap->priv); - pclog("[%04X:%08X] io_trap_readl(%04X)\n", CS, cpu_state.pc, addr); return 0xffffffff; } @@ -909,7 +825,6 @@ io_trap_writeb(uint16_t addr, uint8_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(1, addr, 1, val, trap->priv); - pclog("[%04X:%08X] io_trap_writeb(%04X)\n", CS, cpu_state.pc, addr); } static void @@ -917,7 +832,6 @@ io_trap_writew(uint16_t addr, uint16_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(2, addr, 1, val, trap->priv); - pclog("[%04X:%08X] io_trap_writew(%04X)\n", CS, cpu_state.pc, addr); } static void @@ -925,7 +839,6 @@ io_trap_writel(uint16_t addr, uint32_t val, void *priv) { io_trap_t *trap = (io_trap_t *) priv; trap->func(4, addr, 1, val, trap->priv); - pclog("[%04X:%08X] io_trap_writel(%04X)\n", CS, cpu_state.pc, addr); } void * @@ -972,9 +885,6 @@ io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size) io_trap_writeb, io_trap_writew, io_trap_writel, trap); } - - if ((addr == 0x0170) || (addr == 0x0376) || (addr == 0x01f0) || (addr == 0x03f6)) - pclog("io_trap_remape(%04X) = %i\n", addr, trap->enable); } void From 464253a8cd4dcbfd3c857ace6dfabe3be2a315ef Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 19:48:31 +0100 Subject: [PATCH 0299/1190] IDE: Fix device bus flags. --- src/disk/hdc_ide.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index b69ddf128..fb95bef28 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3338,7 +3338,7 @@ const device_t ide_vlb_device = { const device_t ide_vlb_sec_device = { .name = "VLB IDE Controller (Secondary)", .internal_name = "ide_vlb_sec", - .flags = DEVICE_VLB | DEVICE_ISA16, + .flags = DEVICE_VLB, .local = 2, .init = ide_sec_init, .close = ide_sec_close, @@ -3352,7 +3352,7 @@ const device_t ide_vlb_sec_device = { const device_t ide_vlb_2ch_device = { .name = "VLB IDE Controller (Dual-Channel)", .internal_name = "ide_vlb_2ch", - .flags = DEVICE_VLB | DEVICE_ISA16, + .flags = DEVICE_VLB, .local = 3, .init = ide_init, .close = ide_close, @@ -3366,7 +3366,7 @@ const device_t ide_vlb_2ch_device = { const device_t ide_pci_device = { .name = "PCI IDE Controller", .internal_name = "ide_pci", - .flags = DEVICE_PCI | DEVICE_ISA16, + .flags = DEVICE_PCI, .local = 4, .init = ide_init, .close = ide_close, @@ -3380,7 +3380,7 @@ const device_t ide_pci_device = { const device_t ide_pci_sec_device = { .name = "PCI IDE Controller (Secondary)", .internal_name = "ide_pci_sec", - .flags = DEVICE_PCI | DEVICE_ISA16, + .flags = DEVICE_PCI, .local = 4, .init = ide_sec_init, .close = ide_sec_close, @@ -3394,7 +3394,7 @@ const device_t ide_pci_sec_device = { const device_t ide_pci_2ch_device = { .name = "PCI IDE Controller (Dual-Channel)", .internal_name = "ide_pci_2ch", - .flags = DEVICE_PCI | DEVICE_ISA16, + .flags = DEVICE_PCI, .local = 5, .init = ide_init, .close = ide_close, From 45dc381251e5769fccc0fe4f0575ae77a8bf3a40 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Feb 2025 19:50:53 +0100 Subject: [PATCH 0300/1190] Forgot the single-channel VLB controller. --- src/disk/hdc_ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index fb95bef28..125cd806d 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -3324,7 +3324,7 @@ const device_t ide_isa_2ch_device = { const device_t ide_vlb_device = { .name = "VLB IDE Controller", .internal_name = "ide_vlb", - .flags = DEVICE_VLB | DEVICE_ISA16, + .flags = DEVICE_VLB, .local = 2, .init = ide_init, .close = ide_close, From a6e866c0e547f4bffca287e425bdf598e7966a62 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:34:27 +0900 Subject: [PATCH 0301/1190] added comments --- src/disk/hdc_esdi_mca.c | 16 ++++++++++++++-- src/floppy/fdc.c | 2 +- src/machine/m_ps2_mca.c | 6 +++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 690f658a0..8f1def137 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1471,16 +1471,28 @@ static device_config_t { .type = -1 } }; +/* +Device for an IBM DBA (Direct Bus Attachment) hard disk. +The Disk BIOS is included in the System ROM. +Some models have an exclusive channel slot for the DBA hard disk. +Following IBM machines are supported: + * PS/2 model 55SX + * PS/2 model 65SX + * PS/2 model 70 type 3 (Slot #4) + * PS/2 model 70 type 4 (Slot #4) + * PS/55 model 5550-T (Slot #5) + * PS/55 model 5550-V (Slot #5) +*/ const device_t esdi_integrated_device = { - .name = "IBM Integrated Fixed Disk Controller (MCA)", + .name = "IBM Integrated Fixed Disk and Controller (MCA)", .internal_name = "esdi_integrated_mca", .flags = DEVICE_MCA, .local = ESDI_IS_INTEGRATED, .init = esdi_init, .close = esdi_close, .reset = esdi_reset, - .available = NULL, /* The Disk BIOS is included in the System ROM */ + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = esdi_integrated_config diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 8a1a33f2f..5de1a8ef4 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -740,7 +740,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) drive = real_drive(fdc, fdc->dor & 3); fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); } - /* Bit 2: FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) + /* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. If it fails, then floppy drives will be treated as DD drives. */ if (fdc->flags & FDC_FLAG_PS2_MCA) { diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 1edff2991..ac22af2fe 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1890,7 +1890,11 @@ machine_ps55_model_50t_init(const machine_t* model) * Planar ID * FFFAh - PS/55 model 5551-S0x, T0x (stage 1?) * FFEEh - PS/55 model 5551-S1x, T1x (stage 2?) - * POST (P/N 38F6933) determination: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error) + * Verification in BIOS P/N 38F6933: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error) + * + * The only difference between S and T models is the CPU speed (16 MHz vs 20 MHz). + * The POST measures the speed, and sets a flag in the BIOS Data Area to indicate the sub model. + * The VM in 86Box runs faster than the real, so the POST always determines it as the T model. */ ps2.planar_id = 0xffee; ps55_mca_board_model_50t_init(); From 2c78e7bb2f5710bfbe57877422b8b6e96c8e3999 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:46:18 +0900 Subject: [PATCH 0302/1190] added comments --- src/disk/hdc_esdi_mca.c | 16 ++++++++++++++-- src/floppy/fdc.c | 2 +- src/machine/m_ps2_mca.c | 6 +++++- src/video/vid_svga.c | 6 +++--- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 690f658a0..8f1def137 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -1471,16 +1471,28 @@ static device_config_t { .type = -1 } }; +/* +Device for an IBM DBA (Direct Bus Attachment) hard disk. +The Disk BIOS is included in the System ROM. +Some models have an exclusive channel slot for the DBA hard disk. +Following IBM machines are supported: + * PS/2 model 55SX + * PS/2 model 65SX + * PS/2 model 70 type 3 (Slot #4) + * PS/2 model 70 type 4 (Slot #4) + * PS/55 model 5550-T (Slot #5) + * PS/55 model 5550-V (Slot #5) +*/ const device_t esdi_integrated_device = { - .name = "IBM Integrated Fixed Disk Controller (MCA)", + .name = "IBM Integrated Fixed Disk and Controller (MCA)", .internal_name = "esdi_integrated_mca", .flags = DEVICE_MCA, .local = ESDI_IS_INTEGRATED, .init = esdi_init, .close = esdi_close, .reset = esdi_reset, - .available = NULL, /* The Disk BIOS is included in the System ROM */ + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = esdi_integrated_config diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 8a1a33f2f..5de1a8ef4 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -740,7 +740,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) drive = real_drive(fdc, fdc->dor & 3); fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); } - /* Bit 2: FIFO test mode (PS/55 only? This is not documented in neither the PS/2 HITR nor the 82077AA datasheet.) + /* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. If it fails, then floppy drives will be treated as DD drives. */ if (fdc->flags & FDC_FLAG_PS2_MCA) { diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 1edff2991..ac22af2fe 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1890,7 +1890,11 @@ machine_ps55_model_50t_init(const machine_t* model) * Planar ID * FFFAh - PS/55 model 5551-S0x, T0x (stage 1?) * FFEEh - PS/55 model 5551-S1x, T1x (stage 2?) - * POST (P/N 38F6933) determination: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error) + * Verification in BIOS P/N 38F6933: FBxx -> 4 slots (error), xxEE -> 5 slots (ok), others -> 8 (error) + * + * The only difference between S and T models is the CPU speed (16 MHz vs 20 MHz). + * The POST measures the speed, and sets a flag in the BIOS Data Area to indicate the sub model. + * The VM in 86Box runs faster than the real, so the POST always determines it as the T model. */ ps2.planar_id = 0xffee; ps55_mca_board_model_50t_init(); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index db378b754..caa20e196 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -512,9 +512,9 @@ svga_in(uint16_t addr, void *priv) /* The IBM PS/55 Display Adapter has own Monitor Type Detection bit in the different I/O port (I/O 3E0h, 3E1h). When the monitor cable is connected to the Display Adapter, the port 3C2h returns the value as 'no cable connection'. - The POST of PS/55 has an extra code that tries detecting the monitor on the planar VGA. - If it fails, then the POST reads the NVRAM set by the reference diskette, and writes the BIOS Data Area (Mem 487h, 489h). - MONCHK.EXE in the reference diskette uses both I/O ports to determine the monitor type, and writes the BDA. + The POST of PS/55 has an extra code. If the monitor is not detected on the planar VGA, + it reads the POS data in NVRAM set by the reference diskette, and writes the BIOS Data Area (Mem 487h, 489h). + MONCHK.EXE in the reference diskette uses both I/O ports to determine the monitor type, updates the NVRAM and BDA. */ if (svga->vgapal[0].r >= 10 || svga->vgapal[0].g >= 10 || svga->vgapal[0].b >= 10) ret = 0; From 244f7665580767eec6b7f6b24a8e01eb1987795d Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 18 Feb 2025 23:45:16 +0900 Subject: [PATCH 0303/1190] fix unexpected write to null fp in rel build --- src/video/vid_ps55da2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 060e47ce6..ba6835e8c 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -369,8 +369,10 @@ typedef struct da2_t { int raster_op; uint8_t payload[DA2_BLT_MEMSIZE]; int32_t reg[DA2_BLT_REGSIZE]; // must be signed int +#ifdef ENABLE_DA2_DEBUGBLT int32_t *debug_reg; // for debug int debug_reg_ip; // for debug +#endif int payload_addr; pc_timer_t timer; int64_t timerspeed; @@ -387,10 +389,12 @@ typedef struct da2_t { int x, y; } bitblt; +#ifdef ENABLE_DA2_DEBUGBLT FILE *mmdbg_fp; FILE *mmrdbg_fp; uint32_t mmdbg_vidaddr; uint32_t mmrdbg_vidaddr; +#endif uint8_t pos_regs[8]; svga_t *mb_vga; @@ -2520,12 +2524,12 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - fprintf(da2->mmdbg_fp, "m1-1"); + //fprintf(da2->mmdbg_fp, "m1-1"); } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); da2_gdcropB(addr, bitmask, da2); - fprintf(da2->mmdbg_fp, "m1-2"); + //fprintf(da2->mmdbg_fp, "m1-2"); } break; case 3:/* equiv to vga write mode 3 */ From 61acd4473609faddb2ee5ef84f2082412a4da8ea Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Feb 2025 00:16:18 +0900 Subject: [PATCH 0304/1190] added comment --- src/video/vid_ps55da2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index ba6835e8c..ca4ba85b4 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -96,9 +96,9 @@ [Japanese DOS and Display Adapter compatibility] | POS ID | Adapter Name | K3.31 | J4.04 | J4.08 | OS2 J1.3 | Win3 | |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| - | EFFFh | Display Adapter | X | | | ? | | - | FFEDh | ? [Atlas EVT] | X | | | ? | | - | FFFDh | ? [LDT EVT] | X | | | ? | | + | EFFFh | Display Adapter | X | | | | | + | FFEDh | ? [Atlas EVT] | X | | | | | + | FFFDh | ? [LDT EVT] | X | | | | | | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | | E013h | ? [LDT] | X | X | X | X | | | ECCEh | Display Adapter IV | | X | X | X | | @@ -1308,7 +1308,7 @@ da2_in(uint16_t addr, void *p) // da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { // da2_log("exec:%x\n", da2->bitblt.exec); - temp |= 0x01; // wait(bit 3 + bit 0) + temp |= 0x01; /* wait (bit 3 + bit 0) ? need verify */ // if (!da2->bitblt.timer.enabled) //{ // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); From 3c00fece65aff62b03f18b8f953c5006db7dfedb Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Feb 2025 00:37:40 +0900 Subject: [PATCH 0305/1190] change machine name, update comments --- src/machine/m_ps2_mca.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index ac22af2fe..400971138 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1919,7 +1919,7 @@ machine_ps55_model_50v_init(const machine_t* model) /* * Planar ID * F1FFh - PS/55 model 5551-V0x, V1x - * POST (P/N 38F6933) determination: FBxx -> 5 slots (ok), F1xx -> 5 slots (ok), others -> 8 (error) + * Verification in BIOS P/N 56F7416,56F7417: FBxx -> 5 slots (ok), F1xx -> 5 slots (ok), others -> 8 (error) */ ps2.planar_id = 0xf1ff; ps55_mca_board_model_50v_init(); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bf540922b..7ec31892a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5680,7 +5680,7 @@ const machine_t machines[] = { }, /* Has IBM PS/55 5551-V0x, V1x firmware. */ { - .name = "[MCA] IBM PS/55 model 5550-V0", + .name = "[MCA] IBM PS/55 model 5550-V", .internal_name = "ibmps55_m50v", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_PROPRIETARY, From 2d115e9b8481069e2f56a258dedce32f2f6192a0 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:02:28 +0900 Subject: [PATCH 0306/1190] added patch for font rom, cleanup * Added magic code for OS/2 J1.3 to disable BitBlt's text drawing function that is not implemented yet. * Added comments * Cleanup --- src/video/vid_ps55da2.c | 46 ++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index ca4ba85b4..ad27c978c 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -7,6 +7,17 @@ * This file is part of the 86Box distribution. * * IBM PS/55 Display Adapter II (and its successors) emulation. + * + * Notes: There are some known issues that should be corrected. + * - Incorrect foreground text color appears on an active window in OS/2 J1.3. + * - BitBlt's text drawing function does not work correctly. + * - The screen resolution and blanking interval time maybe not correct. + * + * The code should be tested with following cases. + * - Execute MODE 0, 1, 3 and 4 commands in DOS K3.3 to test various video modes. + * - Run SAMPLE program with the BASIC interpreter in DOS K3.3. + * - Run DOS J4.0 install program to test video mode 03. + * - Run Win 3.1 (IBM-J OEM) and OS/2 J1.3 with 16 and 256 color driver to test BilBlt operations. * * Authors: Akamaki. * @@ -662,9 +673,9 @@ da2_bitblt_load(da2_t *da2) value64 |= da2->bitblt.payload[i + 3]; value64 <<= 8; value64 |= da2->bitblt.payload[i + 2]; - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; i += 7; break; case 0x00: @@ -699,9 +710,12 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03; /* 01 AND, 03 XOR */ da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); - for (int i = 0; i <= 0xb; i++) - da2_log("%02x ", da2->gdcreg[i]); - da2_log("\n"); + // for (int i = 0; i <= 0xb; i++) + // { + // da2_log("%02x ", da2->gdcreg[i]); + // da2->gdcreg[i] = da2->bitblt.reg[i] & 0xff; + // } + // da2_log("\n"); da2->bitblt.destaddr = da2->bitblt.reg[0x29]; da2->bitblt.size_x = da2->bitblt.reg[0x33]; @@ -919,7 +933,7 @@ da2_bitblt_exec(void *p) da2->bitblt.destaddr -= 2; da2->bitblt.srcaddr -= 2; break; - case DA2_BLT_CPUTCHAR: + case DA2_BLT_CPUTCHAR: /* used in OS/2 J1.3 wo ROM patch. TODO: still not work */ // da2->bitblt.y += 2; da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; // pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); @@ -1346,7 +1360,7 @@ da2_in(uint16_t addr, void *p) if (da2->cgastat & 0x01) da2->cgastat &= ~0x30; else - da2->cgastat ^= 0x30; + da2->cgastat ^= 0x30; /* toggle */ temp = da2->cgastat; } else temp = da2->attrc[da2->attraddr]; @@ -1444,9 +1458,10 @@ da2_outw(uint16_t addr, uint16_t val, void *p) da2_out(addr, val, da2); da2->outflipflop = 0; break; - case 0x3EE: + case AC_REG: + /* no register is revealed */ da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2->reg3ee[val & 0xff] = val >> 8; + da2->reg3ee[val & 0x0f] = val >> 8; break; } } @@ -2444,17 +2459,16 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) break; } } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 color or 256 color mode */ - uint8_t wm = da2->writemask; uint8_t bitmask; /* align bitmask to even address */ if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; - // da2_log("da2_gcB m%d a%x d%x\n", da2->writemode, addr, val); #ifdef ENABLE_DA2_DEBUGBLT + da2_log("da2_wB %x %02x\n", addr, val); // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { - fprintf(da2->mmdbg_fp, "\nB %x ", addr); + fprintf(da2->mmdbg_fp, "\nB %x %02x ", addr, val); for (int i = 0; i <= 0xb; i++) fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); } @@ -2535,13 +2549,11 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) case 3:/* equiv to vga write mode 3 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; - wm = bitmask; bitmask &= val; for (int i = 0; i < 8; i++) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; da2_gdcropB(addr, bitmask, da2); - bitmask = wm; break; } // da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); @@ -2560,7 +2572,6 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *) p; - uint8_t wm = da2->writemask; uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; bitmask <<= 8; bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; @@ -2651,13 +2662,11 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) case 3: if (da2->gdcreg[LG_DATA_ROTATION] & 15) val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work - wm = bitmask; bitmask &= val; for (int i = 0; i < 8; i++) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; da2_gdcropW(addr, bitmask, da2); - bitmask = wm; break; } // da2_log("%02x%02x%02x%02x,%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3] @@ -3039,6 +3048,9 @@ da2_init() break; case DA2_DCONFIG_CHARSET_JPAN: da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + /* Add magic code for OS/2 J1.3. This disables BitBlt's text drawing function. */ + da2->mmio.font[0x1AFFE] = 0x80; + da2->mmio.font[0x1AFFF] = 0x01; break; } @@ -3065,7 +3077,7 @@ da2_init() mem_mapping_disable(&da2->cmapping); timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 1 * TIMER_USEC; /* Todo: Async bitblt won't work in OS/2 J1.3 Command Prompt */ + da2->bitblt.timerspeed = 1 * TIMER_USEC; timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; From ed555c86d72eb6f3f9bdf7060de5567b779fb63f Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Feb 2025 11:38:00 +0900 Subject: [PATCH 0307/1190] correct function declaration in m_ps2_mca.c --- src/machine/m_ps2_mca.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 400971138..1a2f4d6c6 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1770,8 +1770,8 @@ machine_ps2_model_70_type4_init(const machine_t *model) return ret; } -void -ps55_mca_board_model_50t_init() +static void +ps55_mca_board_model_50t_init(void) { ps2_mca_board_common_init(); @@ -1814,8 +1814,8 @@ ps55_mca_board_model_50t_init() ps2.mb_vga = (vga_t *)device_add(&ps1vga_mca_device); } -void -ps55_mca_board_model_50v_init() +static void +ps55_mca_board_model_50v_init(void) { ps2_mca_board_common_init(); From 6328d5110825d6a9ff437400bcc2c3adfd59fe0c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 10:54:22 +0100 Subject: [PATCH 0308/1190] Gave the PCjr the missing MACHINE_CARTRIDGE flag. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b9cc8461b..cc3d6aa9f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -324,7 +324,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PCJR, - .flags = MACHINE_VIDEO_FIXED, + .flags = MACHINE_VIDEO_FIXED | MACHINE_CARTRIDGE, .ram = { .min = 64, .max = 640, From 655a0075795cfe0154c5fac5e8cef04e9e234c18 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 11:12:49 +0100 Subject: [PATCH 0309/1190] SLiRP: Introduce a new queue for packets received immediately transmssion - those are now collected into said queue and processed immediately after, improves SLiRP operation. --- src/include/86box/network.h | 12 +++++--- src/network/net_slirp.c | 60 +++++++++++++++++++++++++++---------- src/network/network.c | 37 +++++++++++++++++++++++ 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2140d62dd..ef9f291ad 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -57,7 +57,7 @@ /* Queue size must be a power of 2 */ #define NET_QUEUE_LEN 16 #define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1) -#define NET_QUEUE_COUNT 3 +#define NET_QUEUE_COUNT 4 #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 @@ -84,9 +84,10 @@ enum { }; enum { - NET_QUEUE_RX = 0, - NET_QUEUE_TX_VM = 1, - NET_QUEUE_TX_HOST = 2 + NET_QUEUE_RX = 0, + NET_QUEUE_TX_VM = 1, + NET_QUEUE_TX_HOST = 2, + NET_QUEUE_RX_ON_TX = 3 }; typedef struct netcard_conf_t { @@ -199,7 +200,10 @@ extern const device_t *network_card_getdevice(int); extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt); extern int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size); extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len); +extern int network_rx_on_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size); +extern int network_rx_on_tx_put(netcard_t *card, uint8_t *bufp, int len); extern int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt); +extern int network_rx_on_tx_put_pkt(netcard_t *card, netpkt_t *pkt); #ifdef EMU_DEVICE_H /* 3Com Etherlink */ diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 11f1a74b2..203428b83 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -60,16 +60,19 @@ enum { }; typedef struct net_slirp_t { - Slirp *slirp; - uint8_t mac_addr[6]; - netcard_t *card; /* netcard attached to us */ - thread_t *poll_tid; - net_evt_t tx_event; - net_evt_t stop_event; - netpkt_t pkt; - netpkt_t pkt_tx_v[SLIRP_PKT_BATCH]; + Slirp * slirp; + uint8_t mac_addr[6]; + netcard_t * card; /* netcard attached to us */ + thread_t * poll_tid; + net_evt_t rx_event; + net_evt_t tx_event; + net_evt_t stop_event; + netpkt_t pkt; + netpkt_t pkt_tx_v[SLIRP_PKT_BATCH]; + int during_tx; + int recv_on_tx; #ifdef _WIN32 - HANDLE sock_event; + HANDLE sock_event; #else uint32_t pfd_len; uint32_t pfd_size; @@ -184,7 +187,11 @@ net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) memcpy(slirp->pkt.data, (uint8_t *) qp, pkt_len); slirp->pkt.len = pkt_len; - network_rx_put_pkt(slirp->card, &slirp->pkt); + if (slirp->during_tx) { + network_rx_on_tx_put_pkt(slirp->card, &slirp->pkt); + slirp->recv_on_tx = 1; + } else + network_rx_put_pkt(slirp->card, &slirp->pkt); return pkt_len; } @@ -324,6 +331,21 @@ net_slirp_in_available(void *priv) net_event_set(&slirp->tx_event); } +static void +net_slirp_rx_deferred_packets(net_slirp_t *slirp) +{ + int packets = 0; + + if (slirp->recv_on_tx) { + do { + packets = network_rx_on_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH); + for (int i = 0; i < packets; i++) + network_rx_put_pkt(slirp->card, &(slirp->pkt_tx_v[i])); + } while (packets > 0); + slirp->recv_on_tx = 0; + } +} + #ifdef _WIN32 static void net_slirp_thread(void *priv) @@ -352,10 +374,13 @@ net_slirp_thread(void *priv) case NET_EVENT_TX: { + slirp->during_tx = 1; int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH); - for (int i = 0; i < packets; i++) { + for (int i = 0; i < packets; i++) net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len); - } + slirp->during_tx = 0; + + net_slirp_rx_deferred_packets(slirp); } break; @@ -398,10 +423,13 @@ net_slirp_thread(void *priv) if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) { net_event_clear(&slirp->tx_event); + slirp->during_tx = 1; int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH); - for (int i = 0; i < packets; i++) { + for (int i = 0; i < packets; i++) net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len); - } + slirp->during_tx = 0; + + net_slirp_rx_deferred_packets(slirp); } } @@ -477,6 +505,7 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv slirp->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME); } slirp->pkt.data = calloc(1, NET_MAX_FRAME); + net_event_init(&slirp->rx_event); net_event_init(&slirp->tx_event); net_event_init(&slirp->stop_event); #ifdef _WIN32 @@ -531,8 +560,9 @@ net_slirp_close(void *priv) slirp_log("SLiRP: waiting for thread to end...\n"); thread_wait(slirp->poll_tid); - net_event_close(&slirp->tx_event); net_event_close(&slirp->stop_event); + net_event_close(&slirp->tx_event); + net_event_close(&slirp->rx_event); slirp_cleanup(slirp->slirp); for (int i = 0; i < SLIRP_PKT_BATCH; i++) { free(slirp->pkt_tx_v[i].data); diff --git a/src/network/network.c b/src/network/network.c index 66990e51d..047642085 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -643,6 +643,43 @@ network_rx_put(netcard_t *card, uint8_t *bufp, int len) return ret; } +int +network_rx_on_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size) +{ + int pkt_count = 0; + + netqueue_t *queue = &card->queues[NET_QUEUE_RX_ON_TX]; + for (int i = 0; i < vec_size; i++) { + if (!network_queue_get_swap(queue, pkt_vec)) + break; + network_dump_packet(pkt_vec); + pkt_count++; + pkt_vec++; + } + + return pkt_count; +} + +int +network_rx_on_tx_put(netcard_t *card, uint8_t *bufp, int len) +{ + int ret = 0; + + ret = network_queue_put(&card->queues[NET_QUEUE_RX_ON_TX], bufp, len); + + return ret; +} + +int +network_rx_on_tx_put_pkt(netcard_t *card, netpkt_t *pkt) +{ + int ret = 0; + + ret = network_queue_put_swap(&card->queues[NET_QUEUE_RX_ON_TX], pkt); + + return ret; +} + int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt) { From c7d9b4c5e78eae31390b4c05045675f2462bdd6e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 11:21:50 +0100 Subject: [PATCH 0310/1190] PS/55: Fix some warnings and compile-breaking errors. --- src/device/keyboard.c | 3 +++ src/include/86box/machine.h | 2 +- src/video/vid_ps55da2.c | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index de97592bf..2b851f36c 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -85,6 +85,8 @@ typedef struct { const uint8_t brk[4]; } scconvtbl; +/* Is this a left-over of something planned earlier? */ +#ifdef USE_SCCONV55_82 static scconvtbl scconv55_82[18 + 1] = { // clang-format off @@ -109,6 +111,7 @@ static scconvtbl scconv55_82[18 + 1] = {.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */ // clang-format on }; +#endif static scconvtbl scconv55_8a[18 + 1] = { diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 690d867db..78f4902eb 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -903,7 +903,7 @@ extern int machine_ps2_model_70_type3_init(const machine_t *); extern int machine_ps2_model_80_init(const machine_t *); extern int machine_ps2_model_80_axx_init(const machine_t *); extern int machine_ps2_model_70_type4_init(const machine_t *); -extern int machine_ps55_model_50t_init(const machine_t*);; +extern int machine_ps55_model_50t_init(const machine_t*); extern int machine_ps55_model_50v_init(const machine_t*); /* m_tandy.c */ diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index ad27c978c..aaf5d4803 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1256,8 +1256,8 @@ da2_out(uint16_t addr, uint16_t val, void *p) uint16_t da2_in(uint16_t addr, void *p) { - da2_t *da2 = (da2_t *) p; - uint16_t temp; + da2_t *da2 = (da2_t *) p; + uint16_t temp = 0xff; switch (addr) { case 0x3c3: @@ -3020,7 +3020,7 @@ da2_reset(void *priv) } static void * -da2_init() +da2_init(UNUSED(const device_t *info)) { if (svga_get_pri() == NULL) return NULL; @@ -3083,7 +3083,7 @@ da2_init() return da2; } static int -da2_available() +da2_available(void) { return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); } From 83d840381a08339a4f275b38a918841633558325 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 11:58:13 +0100 Subject: [PATCH 0311/1190] Fixed more warnings and compile-breaking mistakes. --- src/machine/m_ps2_mca.c | 8 ++++---- src/sound/resid-fp/SID.cpp | 2 ++ src/sound/resid-fp/WaveformGenerator.cpp | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 1a2f4d6c6..d3f881b24 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -375,7 +375,7 @@ ps55_model_50t_read(uint16_t port) return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; - case 0x103: + case 0x103: { uint8_t val = 0xff; /* I/O 103h - Bit 7-4: Memory Card ID (Connector 1 or 3) @@ -413,7 +413,7 @@ ps55_model_50t_read(uint16_t port) } ps2_mca_log(" Read MCA %04X %02X %04X:%04X mem_size = %d, ps2option1 = %2X\n", port, val, cs >> 4, cpu_state.pc, mem_size, ps2.option[1]); return val; - case 0x104: + } case 0x104: return ps2.option[2]; case 0x105: return ps2.option[3]; @@ -435,7 +435,7 @@ ps55_model_50v_read(uint16_t port) return ps2.planar_id >> 8; case 0x102: return ps2.option[0]; - case 0x103: + case 0x103: { uint8_t val = 0xff; /* I/O 103h - Bit 7-4: Reserved @@ -460,7 +460,7 @@ ps55_model_50v_read(uint16_t port) break; } return val; - case 0x104: + } case 0x104: /* Reading cache ID (bit 3-2) always returns zero */ return ps2.option[2] & 0xf3; case 0x105: diff --git a/src/sound/resid-fp/SID.cpp b/src/sound/resid-fp/SID.cpp index 5b5506bc3..4db69af0c 100644 --- a/src/sound/resid-fp/SID.cpp +++ b/src/sound/resid-fp/SID.cpp @@ -107,8 +107,10 @@ constexpr unsigned int OSC_DAC_BITS = 12; * On my 6581R4AR has 0x3A as the only value giving the same output level as 1.prg */ //@{ +#ifdef USE_RESID_UNUSED constexpr unsigned int OFFSET_6581 = 0x380; constexpr unsigned int OFFSET_8580 = 0x9c0; +#endif //@} /** diff --git a/src/sound/resid-fp/WaveformGenerator.cpp b/src/sound/resid-fp/WaveformGenerator.cpp index be0738bba..847560f2a 100644 --- a/src/sound/resid-fp/WaveformGenerator.cpp +++ b/src/sound/resid-fp/WaveformGenerator.cpp @@ -43,7 +43,9 @@ namespace reSIDfp constexpr unsigned int FLOATING_OUTPUT_TTL_6581R3 = 54000; constexpr unsigned int FLOATING_OUTPUT_FADE_6581R3 = 1400; // ~1s +#ifdef USE_RESID_UNUSED constexpr unsigned int FLOATING_OUTPUT_TTL_6581R4 = 1000000; +#endif // ~1s constexpr unsigned int FLOATING_OUTPUT_TTL_8580R5 = 800000; constexpr unsigned int FLOATING_OUTPUT_FADE_8580R5 = 50000; @@ -61,7 +63,9 @@ constexpr unsigned int FLOATING_OUTPUT_FADE_8580R5 = 50000; constexpr unsigned int SHIFT_REGISTER_RESET_6581R3 = 50000; constexpr unsigned int SHIFT_REGISTER_FADE_6581R3 = 15000; // ~2.15s +#ifdef USE_RESID_UNUSED constexpr unsigned int SHIFT_REGISTER_RESET_6581R4 = 2150000; +#endif // ~2.8s constexpr unsigned int SHIFT_REGISTER_RESET_8580R5 = 986000; constexpr unsigned int SHIFT_REGISTER_FADE_8580R5 = 314300; From c262760155c617cf9130ed616303af760f838d37 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 12:56:22 +0100 Subject: [PATCH 0312/1190] PS/1: Move NVR initialization to the end of ps1_setup(), fixes segmentation fault due to the BIOS language being obtained from the wrong device. --- src/machine/m_ps1.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 130481394..41821a4a8 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -320,30 +320,28 @@ ps1_setup(int model) mem_remap_top(384); - device_add(&ps_nvr_device); - device_add(&fdc_ps2_device); if (model == 2011) { - if (!strcmp("english_us", device_get_config_bios("bios_language"))) { - /* US English */ - rom_init(&ps->high_rom, - device_get_bios_file(device_context_get_device(), device_get_config_bios("bios_language"), 0), - 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); + const device_t *d = device_context_get_device(); + const char * bios = device_get_config_bios("bios_language"); + const char * first = device_get_bios_file(d, bios, 0); + const char * second = device_get_bios_file(d, bios, 1); - } else if ((device_get_bios_file(device_context_get_device(), device_get_config_bios("bios_language"), 1)) == NULL) { + if (!strcmp(bios, "english_us")) { + /* US English */ + rom_init(&ps->high_rom, first, + 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); + } else if (second == NULL) { /* Combined ROM. */ - rom_init(&ps->high_rom, - device_get_bios_file(device_context_get_device(), device_get_config_bios("bios_language"), 0), + rom_init(&ps->high_rom, first, 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); } else { /* Split ROM. */ - rom_init(&ps->mid_rom, - device_get_bios_file(device_context_get_device(), device_get_config_bios("bios_language"), 0), + rom_init(&ps->mid_rom, first, 0xf80000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); - rom_init(&ps->high_rom, - device_get_bios_file(device_context_get_device(), device_get_config_bios("bios_language"), 1), + rom_init(&ps->high_rom, second, 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); } @@ -381,6 +379,8 @@ ps1_setup(int model) device_add(&ps1snd_device); } + + device_add(&ps_nvr_device); } static void From baae4c15d65404d7c70ff45ffdf19b8b0fdda2a4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Feb 2025 12:58:40 +0100 Subject: [PATCH 0313/1190] Fixed a compile-breaking error in vid_p55da2.c as well. --- src/video/vid_ps55da2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index aaf5d4803..288aca027 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -872,7 +872,7 @@ da2_bitblt_exec(void *p) } da2->bitblt.destaddr += 2; break; - case DA2_BLT_CFILLTILE: + case DA2_BLT_CFILLTILE: { int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; if (da2->bitblt.x >= da2->bitblt.size_x - 1) { DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); @@ -891,7 +891,7 @@ da2_bitblt_exec(void *p) } da2->bitblt.destaddr += 2; break; - case DA2_BLT_CCOPYF: + } case DA2_BLT_CCOPYF: if (da2->bitblt.x >= da2->bitblt.size_x - 1) { DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); if (da2->bitblt.y >= da2->bitblt.size_y - 1) { From 71c9e694569fa09120f90ae069e5b3d538e94ffc Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 20 Feb 2025 15:35:56 +0100 Subject: [PATCH 0314/1190] Mach32 changes of the day (February 20th, 2025) 1. Actually fix the LFB access by subtracting the linear base address from the current address when LFB/MMIO is on. This fixes blankness of certain Mach32 drivers on Win3.1x. 2. Apply a minor but important fix to the fonts used by said Win3.1x driver when the dpconfig activates bit 2 without bit 12 set (e.g.: 0x2255), ergo, issuing host data as monochrome without swapping it. --- src/video/vid_ati_mach8.c | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 06a60449f..71dd973da 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -336,7 +336,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if ((dev->accel_bpp == 8) || (dev->accel_bpp == 15) || (dev->accel_bpp == 16) || (dev->accel_bpp == 24)) - mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monpattern = %x.\n", + mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monopattern = %x.\n", dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); @@ -1039,7 +1039,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 2: - if (mach->accel.dp_config & 0x1000) { + if ((mach->accel.dp_config & 0x1000) || (mach->accel.dp_config & 0x04)) { mix = mix_dat >> 0x1f; mix_dat <<= 1; } else { @@ -2185,7 +2185,7 @@ mach_accel_out_pixtrans(svga_t *svga, mach_t *mach, ibm8514_t *dev, uint16_t val case 0x200: /*16-bit size*/ if (mono_src == 2) { if ((frgd_sel != 2) && (bkgd_sel != 2)) { - if ((mach->accel.dp_config & 0x1000) && !swap) { + if (((mach->accel.dp_config & 0x1000) && !swap) || swap) { mach_log("16-bit bus size swap.\n"); val = (val >> 8) | (val << 8); } @@ -5184,11 +5184,11 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); } else { @@ -5199,9 +5199,9 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_write_common(addr, val, 1, mach, svga); + mach32_write_common(addr - mach->linear_base, val, 1, mach, svga); else - svga_write_linear(addr, val, svga); + svga_write_linear(addr - mach->linear_base, val, svga); } } @@ -5211,11 +5211,11 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) { mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val, mach); } else { @@ -5224,11 +5224,11 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) } } else { mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writew_linear(addr, val, mach); + mach32_writew_linear(addr - mach->linear_base, val, mach); else - svga_writew_linear(addr, val, svga); + svga_writew_linear(addr - mach->linear_base, val, svga); } } @@ -5238,11 +5238,11 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) { mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach); mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach); @@ -5253,11 +5253,11 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) } } else { mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writel_linear(addr, val, mach); + mach32_writel_linear(addr - mach->linear_base, val, mach); else - svga_writel_linear(addr, val, svga); + svga_writel_linear(addr - mach->linear_base, val, svga); } } @@ -5268,19 +5268,19 @@ mach32_ap_readb(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); else temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_read_common(addr, 1, mach, svga); + temp = mach32_read_common(addr - mach->linear_base, 1, mach, svga); else - temp = svga_read_linear(addr, svga); + temp = svga_read_linear(addr - mach->linear_base, svga); mach_log("Linear WORDB Read=%08x, ret=%02x, fast=%d.\n", addr, temp, svga->fast); } @@ -5295,19 +5295,19 @@ mach32_ap_readw(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint16_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); else temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_readw_linear(addr, mach); + temp = mach32_readw_linear(addr - mach->linear_base, mach); else - temp = svga_readw_linear(addr, svga); + temp = svga_readw_linear(addr - mach->linear_base, svga); mach_log("Linear WORDW Read=%08x, ret=%04x.\n", addr, temp); } @@ -5322,11 +5322,11 @@ mach32_ap_readl(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = (addr - mach->linear_base) & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + if ((addr - mach->linear_base) & 0x100) { temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8); } else { @@ -5335,9 +5335,9 @@ mach32_ap_readl(uint32_t addr, void *priv) } } else { if (dev->on) - temp = mach32_readl_linear(addr, mach); + temp = mach32_readl_linear(addr - mach->linear_base, mach); else - temp = svga_readl_linear(addr, svga); + temp = svga_readl_linear(addr - mach->linear_base, svga); mach_log("Linear WORDL Read=%08x, ret=%08x, ON%d.\n", addr, temp, dev->on); } From 6c933dd15719b3ba96f6f03f9a657a39ca6d8059 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 20 Feb 2025 18:24:38 -0300 Subject: [PATCH 0315/1190] Voodoo: Implement missing AGP CMDFIFO features Note that the reproduction cases for command 6 currently appear to be a result of CMDFIFO corruption instead of actual usage. --- src/include/86box/vid_voodoo_banshee.h | 1 + src/include/86box/vid_voodoo_common.h | 2 + src/video/vid_voodoo_banshee.c | 77 +++++++++++++++++++++++++- src/video/vid_voodoo_fifo.c | 77 ++++++++++++++++++++++++-- 4 files changed, 148 insertions(+), 9 deletions(-) diff --git a/src/include/86box/vid_voodoo_banshee.h b/src/include/86box/vid_voodoo_banshee.h index 89298e94e..257a549dd 100644 --- a/src/include/86box/vid_voodoo_banshee.h +++ b/src/include/86box/vid_voodoo_banshee.h @@ -18,6 +18,7 @@ #ifndef VIDEO_VOODOO_BANSHEE_H #define VIDEO_VOODOO_BANSHEE_H +void banshee_cmd_write(void *priv, uint32_t addr, uint32_t val); void banshee_set_overlay_addr(void *priv, uint32_t addr); #endif /*VIDEO_VOODOO_BANSHEE_H*/ diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h index 5ab63ec3a..4201562c2 100644 --- a/src/include/86box/vid_voodoo_common.h +++ b/src/include/86box/vid_voodoo_common.h @@ -420,6 +420,7 @@ typedef struct voodoo_t { int cmdfifo_rp; int cmdfifo_ret_addr; int cmdfifo_in_sub; + int cmdfifo_in_agp; atomic_int cmdfifo_depth_rd; atomic_int cmdfifo_depth_wr; atomic_int cmdfifo_enabled; @@ -433,6 +434,7 @@ typedef struct voodoo_t { int cmdfifo_rp_2; int cmdfifo_ret_addr_2; int cmdfifo_in_sub_2; + int cmdfifo_in_agp_2; atomic_int cmdfifo_depth_rd_2; atomic_int cmdfifo_depth_wr_2; atomic_int cmdfifo_enabled_2; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index fadd782a5..3727ccf8e 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -30,6 +30,7 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> +#include <86box/dma.h> #include <86box/pci.h> #include <86box/rom.h> #include <86box/timer.h> @@ -43,9 +44,11 @@ #include <86box/vid_svga_render.h> #include <86box/vid_voodoo_common.h> #include <86box/vid_voodoo_display.h> +#include <86box/vid_voodoo_fb.h> #include <86box/vid_voodoo_fifo.h> #include <86box/vid_voodoo_regs.h> #include <86box/vid_voodoo_render.h> +#include <86box/vid_voodoo_texture.h> #define ROM_BANSHEE "roms/video/voodoo/Pci_sg.rom" #define ROM_CREATIVE_BANSHEE "roms/video/voodoo/BlasterPCI.rom" @@ -220,6 +223,7 @@ enum { Agp_agpHostAddressHigh = 0x08, Agp_agpGraphicsAddress = 0x0C, Agp_agpGraphicsStride = 0x10, + Agp_agpMoveCMD = 0x14, }; #define VGAINIT0_RAMDAC_8BIT (1 << 2) @@ -1365,6 +1369,10 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) case cmdBaseSize0: ret = voodoo->cmdfifo_size; + if (voodoo->cmdfifo_enabled) + ret |= 0x100; + if (voodoo->cmdfifo_in_agp) + ret |= 0x200; break; case cmdBaseAddr1: @@ -1394,6 +1402,10 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) case cmdBaseSize1: ret = voodoo->cmdfifo_size_2; + if (voodoo->cmdfifo_enabled_2) + ret |= 0x100; + if (voodoo->cmdfifo_in_agp_2) + ret |= 0x200; break; case 0x108: @@ -1613,10 +1625,11 @@ banshee_reg_writew(uint32_t addr, uint16_t val, void *priv) } } -static void -banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) +void +banshee_cmd_write(void *priv, uint32_t addr, uint32_t val) { - voodoo_t *voodoo = banshee->voodoo; + banshee_t *banshee = (banshee_t *) priv; + voodoo_t *voodoo = banshee->voodoo; #if 0 banshee_log("banshee_cmd_write: addr=%03x val=%08x\n", addr & 0x1fc, val); #endif @@ -1641,6 +1654,62 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) banshee->agpReqSize = val; break; + case Agp_agpMoveCMD: { + uint32_t src_addr = banshee->agpHostAddressLow; + uint32_t src_width = banshee->agpHostAddressHigh & 0x3fff; + uint32_t src_stride = (banshee->agpHostAddressHigh >> 14) & 0x3fff; + uint32_t src_end = src_addr + (banshee->agpReqSize & 0xfffff); /* don't know whether or not stride is accounted for! */ + uint32_t dest_addr = banshee->agpGraphicsAddress & 0x3ffffff; + uint32_t dest_stride = banshee->agpGraphicsStride & 0x7fff; +#if 0 + banshee_log("AGP: %d bytes W%d from %08x S%d to %d:%08x S%d\n", src_end - src_addr, src_width, src_addr, src_stride, (val >> 3) & 3, dest_addr, dest_stride); +#endif + switch ((val >> 3) & 3) { + case 0: /*Linear framebuffer (Banshee)*/ + case 1: /*Planar YUV*/ + if (voodoo->texture_present[0][(dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) { +#if 0 + banshee_log("texture_present at %08x %i\n", dest_addr, (dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); +#endif + flush_texture_cache(voodoo, dest_addr & voodoo->texture_mask, 0); + } + if (voodoo->texture_present[1][(dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) { +#if 0 + banshee_log("texture_present at %08x %i\n", dest_addr, (dest_addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); +#endif + flush_texture_cache(voodoo, dest_addr & voodoo->texture_mask, 1); + } + while ((src_addr < src_end) && (dest_addr <= voodoo->fb_mask)) { + dma_bm_read(src_addr, &voodoo->fb_mem[dest_addr], MIN(src_width, voodoo->fb_mask - dest_addr), 4); + src_addr += src_stride; + dest_addr += dest_stride; + } + break; + case 2: /*Framebuffer*/ + src_width &= ~3; + while (src_addr < src_end) { + for (uint32_t i = 0; i < src_width; i += 4) + voodoo_fb_writel(dest_addr + i, mem_readl_phys(src_addr + i), voodoo); + src_addr += src_stride; + dest_addr += dest_stride; + } + break; + case 3: /*Texture*/ + src_width &= ~3; + while (src_addr < src_end) { + for (uint32_t i = 0; i < src_width; i += 4) + voodoo_tex_writel(dest_addr + i, mem_readl_phys(src_addr + i), voodoo); + src_addr += src_stride; + dest_addr += dest_stride; + } + break; + + default: + break; + } + break; + } + case cmdBaseAddr0: voodoo->cmdfifo_base = (val & 0xfff) << 12; voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); @@ -1655,6 +1724,7 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) voodoo->cmdfifo_enabled = val & 0x100; if (!voodoo->cmdfifo_enabled) voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/ + voodoo->cmdfifo_in_agp = val & 0x200; #if 0 banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); #endif @@ -1694,6 +1764,7 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) voodoo->cmdfifo_enabled_2 = val & 0x100; if (!voodoo->cmdfifo_enabled_2) voodoo->cmdfifo_in_sub_2 = 0; /*Not sure exactly when this should be reset*/ + voodoo->cmdfifo_in_agp_2 = val & 0x200; #if 0 banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); #endif diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index 54a0140f6..83be0f7bb 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -35,6 +35,7 @@ #include <86box/video.h> #include <86box/vid_svga.h> #include <86box/vid_voodoo_common.h> +#include <86box/vid_voodoo_banshee.h> #include <86box/vid_voodoo_banshee_blitter.h> #include <86box/vid_voodoo_fb.h> #include <86box/vid_voodoo_fifo.h> @@ -166,7 +167,10 @@ cmdfifo_get(voodoo_t *voodoo) } } - val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + if (voodoo->cmdfifo_in_agp) + val = mem_readl_phys(voodoo->cmdfifo_rp); + else + val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; if (!voodoo->cmdfifo_in_sub) voodoo->cmdfifo_depth_rd++; @@ -200,7 +204,10 @@ cmdfifo_get_2(voodoo_t *voodoo) } } - val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask]; + if (voodoo->cmdfifo_in_agp_2) + val = mem_readl_phys(voodoo->cmdfifo_rp_2); + else + val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask]; if (!voodoo->cmdfifo_in_sub_2) voodoo->cmdfifo_depth_rd_2++; @@ -362,9 +369,21 @@ voodoo_fifo_thread(void *param) break; case 3: /*JMP local frame buffer*/ - voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_agp = 0; #if 0 - voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + voodoo_fifo_log("JMP LFB to %08x %04x\n", voodoo->cmdfifo_rp, header); +#endif + break; + + case 4: /*JMP AGP*/ + if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) + fatal("CMDFIFO0: Not Banshee %08x\n", header); + + voodoo->cmdfifo_rp = ((header >> 4) & 0x1fffffc) | (cmdfifo_get(voodoo) << 25); + voodoo->cmdfifo_in_agp = 1; +#if 0 + voodoo_fifo_log("JMP AGP to %08x %04x\n", voodoo->cmdfifo_rp, header); #endif break; @@ -573,6 +592,23 @@ voodoo_fifo_thread(void *param) } break; + case 6: + if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) { + fatal("CMDFIFO6: Not Banshee %08x %08x\n", header, voodoo->cmdfifo_rp); + } else { + uint32_t val = cmdfifo_get(voodoo); + banshee_cmd_write(voodoo->priv, 0x00, val >> 5); /* agpReqSize */ + banshee_cmd_write(voodoo->priv, 0x04, cmdfifo_get(voodoo)); /* agpHostAddressLow */ + banshee_cmd_write(voodoo->priv, 0x08, cmdfifo_get(voodoo)); /* agpHostAddressHigh */ + banshee_cmd_write(voodoo->priv, 0x0c, cmdfifo_get(voodoo)); /* agpGraphicsAddress */ + banshee_cmd_write(voodoo->priv, 0x10, cmdfifo_get(voodoo)); /* agpGraphicsStride */ + banshee_cmd_write(voodoo->priv, 0x14, (val & 0x18) | 0x00); /* agpMoveCMD - start transfer */ +#if 0 + voodoo_fifo_log("CMDFIFO6 addr=%08x num=%i\n", addr, banshee->agpReqSize); +#endif + } + break; + default: fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); } @@ -624,9 +660,21 @@ voodoo_fifo_thread(void *param) break; case 3: /*JMP local frame buffer*/ - voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_agp_2 = 0; #if 0 - voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + voodoo_fifo_log("JMP LFB to %08x %04x\n", voodoo->cmdfifo_rp_2, header); +#endif + break; + + case 4: /*JMP AGP*/ + if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) + fatal("CMDFIFO0: Not Banshee %08x\n", header); + + voodoo->cmdfifo_rp_2 = ((header >> 4) & 0x1fffffc) | (cmdfifo_get_2(voodoo) << 25); + voodoo->cmdfifo_in_agp_2 = 1; +#if 0 + voodoo_fifo_log("JMP AGP to %08x %04x\n", voodoo->cmdfifo_rp_2, header); #endif break; @@ -835,6 +883,23 @@ voodoo_fifo_thread(void *param) } break; + case 6: + if (UNLIKELY(voodoo->type < VOODOO_BANSHEE)) { + fatal("CMDFIFO6: Not Banshee %08x %08x\n", header, voodoo->cmdfifo_rp); + } else { + uint32_t val = cmdfifo_get_2(voodoo); + banshee_cmd_write(voodoo->priv, 0x00, val >> 5); /* agpReqSize */ + banshee_cmd_write(voodoo->priv, 0x04, cmdfifo_get_2(voodoo)); /* agpHostAddressLow */ + banshee_cmd_write(voodoo->priv, 0x08, cmdfifo_get_2(voodoo)); /* agpHostAddressHigh */ + banshee_cmd_write(voodoo->priv, 0x0c, cmdfifo_get_2(voodoo)); /* agpGraphicsAddress */ + banshee_cmd_write(voodoo->priv, 0x10, cmdfifo_get_2(voodoo)); /* agpGraphicsStride */ + banshee_cmd_write(voodoo->priv, 0x14, (val & 0x18) | 0x20); /* agpMoveCMD - start transfer */ +#if 0 + voodoo_fifo_log("CMDFIFO6 addr=%08x num=%i\n", addr, banshee->agpReqSize); +#endif + } + break; + default: fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); } From 67c02a53619d2bf1cfd4fa014925264fce675655 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 21 Feb 2025 00:32:15 +0100 Subject: [PATCH 0316/1190] Spock/Tribble (IBM PS/2 SCSI) changes of the late night (February 21st, 2025) 1. Made logs more consistent. 2. Actually add Write and Verify command, used by IBM OS/2 1.2 Extended, and fixes a hang by said OS after inserting disk 6. --- src/scsi/scsi_spock.c | 46 ++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index d6a26b7d0..567879a12 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -196,6 +196,7 @@ typedef struct { #define CMD_UNKNOWN_1C11 0x1c11 #define CMD_WRITE_DATA 0x1c02 #define CMD_VERIFY 0x1c03 +#define CMD_WRITE_VERIFY 0x1c04 #define IRQ_TYPE_NONE 0x0 #define IRQ_TYPE_SCB_COMPLETE 0x1 @@ -291,7 +292,7 @@ spock_write(uint16_t port, uint8_t val, void *priv) { spock_t *scsi = (spock_t *) priv; - spock_log("spock_write: port=%04x val=%02x %04x:%04x\n", port, val, CS, cpu_state.pc); + spock_log("spock_writeb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); switch (port & 7) { case 0: @@ -332,6 +333,8 @@ spock_writew(uint16_t port, uint16_t val, void *priv) { spock_t *scsi = (spock_t *) priv; + spock_log("spock_writew: port=%04x, val=%04x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); + switch (port & 7) { case 0: /*Command Interface Register*/ scsi->cir_pending[0] = val & 0xff; @@ -347,8 +350,6 @@ spock_writew(uint16_t port, uint16_t val, void *priv) default: break; } - - spock_log("spock_writew: port=%04x val=%04x\n", port, val); } static uint8_t @@ -390,7 +391,7 @@ spock_read(uint16_t port, void *priv) break; } - spock_log("spock_read: port=%04x val=%02x %04x(%05x):%04x.\n", port, temp, CS, cs, cpu_state.pc); + spock_log("spock_readb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, temp, CS, cpu_state.pc); return temp; } @@ -412,7 +413,7 @@ spock_readw(uint16_t port, void *priv) break; } - spock_log("spock_readw: port=%04x val=%04x\n", port, temp); + spock_log("spock_readw: port=%04x, val=%04x, %04x:%04x.\n", port & 7, temp, CS, cpu_state.pc); return temp; } @@ -534,7 +535,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) int old_scb_state; if (scsi->in_reset) { - spock_log("Reset type = %d\n", scsi->in_reset); + spock_log("Reset type=%d\n", scsi->in_reset); scsi->status &= ~STATUS_BUSY; scsi->irq_status = 0; @@ -542,9 +543,8 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) for (c = 0; c < SCSI_ID_MAX; c++) spock_clear_irq(scsi, c); - if (scsi->in_reset == 1) { + if (scsi->in_reset == 1) scsi->basic_ctrl |= CTRL_IRQ_ENA; - } spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); @@ -585,6 +585,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) switch (scsi->scb_state) { case 0: /* Idle */ + spock_log("Start Idle.\n"); break; case 1: /* Select */ @@ -820,6 +821,28 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->scb_state = 2; return; + case CMD_WRITE_VERIFY: + if (scsi->present[scsi->scb_id] != 0xff) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + + spock_log("Device Write with Verify\n"); + scsi->cdb[0] = GPCMD_WRITE_AND_VERIFY_10; + scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ + scsi->cdb[3] = (scb->lba_addr >> 16) & 0xff; + scsi->cdb[4] = (scb->lba_addr >> 8) & 0xff; + scsi->cdb[5] = scb->lba_addr & 0xff; + scsi->cdb[6] = 0; /*Reserved*/ + scsi->cdb[7] = (scb->block_count >> 8) & 0xff; + scsi->cdb[8] = scb->block_count & 0xff; + scsi->cdb[9] = 0; /*Control*/ + scsi->cdb_len = 10; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = 2; + return; + case CMD_REQUEST_SENSE: if (scsi->present[scsi->scb_id] != 0xff) scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; @@ -943,7 +966,7 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) sd->buffer_length = spock_get_len(scsi, scb); scsi_device_command_phase0(sd, scsi->temp_cdb); - spock_log("SCSI ID %i: Current CDB[0] = %02x, LUN = %i, data len = %i, max len = %i, phase val = %02x\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1] >> 5, sd->buffer_length, spock_get_len(scsi, scb), sd->phase); + spock_log("SCSI ID %i: Current CDB[0]=%02x, LUN=%i, buffer len=%i, max len=%i, phase val=%02x, data len=%d, enable bit 10=%03x\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1] >> 5, sd->buffer_length, spock_get_len(scsi, scb), sd->phase, scsi->data_len, scb->enable & 0x400); if ((sd->phase != SCSI_PHASE_STATUS) && (sd->buffer_length > 0)) { p = scsi_device_get_callback(sd); @@ -1018,12 +1041,11 @@ spock_callback(void *priv) if (scsi->cmd_timer) { scsi->cmd_timer--; - if (!scsi->cmd_timer) { + if (!scsi->cmd_timer) spock_execute_cmd(scsi, scb); - } } - if (scsi->attention_wait && (scsi->scb_state == 0 || (scsi->attention_pending & 0xf0) == 0xe0)) { + if (scsi->attention_wait && ((scsi->scb_state == 0) || (scsi->attention_pending & 0xf0) == 0xe0)) { scsi->attention_wait--; if (!scsi->attention_wait) { scsi->attention = scsi->attention_pending; From 136183b998d127e4219d52e6e1f5bf81a5240adf Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 21 Feb 2025 01:43:22 +0100 Subject: [PATCH 0317/1190] MO and ZIP: Set phase data out on WRITE SAME command. --- src/disk/mo.c | 1 + src/disk/zip.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/disk/mo.c b/src/disk/mo.c index 5494fc9a8..7808e524e 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1461,6 +1461,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_WRITE_SAME_10: + mo_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; if ((cdb[1] & 6) == 6) diff --git a/src/disk/zip.c b/src/disk/zip.c index 72781281a..f579f23ec 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -1506,6 +1506,7 @@ zip_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_WRITE_SAME_10: + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; if ((cdb[1] & 6) == 6) From 9801e8b1493754d9b22f5fa1c40c14151799bdc9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 21 Feb 2025 19:37:53 +0100 Subject: [PATCH 0318/1190] IBM PS/55 Display Adapter II: Use calloc instead of malloc, fixes incorrect operation when heap protection is enabled. --- src/video/vid_ps55da2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 288aca027..f81a62ffe 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3027,17 +3027,17 @@ da2_init(UNUSED(const device_t *info)) svga_t *mb_vga = svga_get_pri(); mb_vga->cable_connected = 0; - da2_t *da2 = malloc(sizeof(da2_t)); + da2_t *da2 = calloc(1, sizeof(da2_t)); da2->mb_vga = mb_vga; da2->dispontime = 1000ull << 32; da2->dispofftime = 1000ull << 32; int memsize = 1024 * 1024; - da2->vram = malloc(memsize); + da2->vram = calloc(1, memsize); da2->vram_mask = memsize - 1; - da2->cram = malloc(0x1000); + da2->cram = calloc(1, 0x1000); da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = malloc(/*(memsize >> 12) << 1*/ 0x1000000 >> 12); /* XX000h */ + da2->changedvram = calloc(1, /*(memsize >> 12) << 1*/ 0x1000000 >> 12); /* XX000h */ da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ da2->mmio.charset = device_get_config_int("charset"); From ce906664a51a1311f445536d8d0aa7270af410c1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 21 Feb 2025 22:25:00 +0100 Subject: [PATCH 0319/1190] Device: increased the length of the temporary pbus string, should fix heap corruptions. --- src/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index 8b2ddf35e..434bd3776 100644 --- a/src/device.c +++ b/src/device.c @@ -490,7 +490,7 @@ device_get_name(const device_t *dev, int bus, char *name) const char *sbus = NULL; const char *fbus; char *tname; - char pbus[12] = { 0 }; + char pbus[16] = { 0 }; if (dev == NULL) return; From 9047bd48784191920d8fccdb53ac1040ea0461b4 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 12 Feb 2025 05:44:59 -0500 Subject: [PATCH 0320/1190] Corrections to PCjr --- src/include/86box/machine.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 78f4902eb..52af90581 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -48,7 +48,7 @@ #define MACHINE_BUS_AGP 0x00080000 /* sys has AGP bus */ #define MACHINE_BUS_AC97 0x00100000 /* sys has AC97 bus (ACR/AMR/CNR slot) */ /* Aliases. */ -#define MACHINE_CASSETTE (MACHINE_BUS_CASSETTE) /* sys has cassette port */ +#define MACHINE_CASSETTE (MACHINE_BUS_CASSETTE) /* sys has cassette port */ /* Combined flags. */ #define MACHINE_PC (MACHINE_BUS_ISA) /* sys is PC/XT-compatible (ISA) */ #define MACHINE_AT (MACHINE_BUS_ISA | MACHINE_BUS_ISA16) /* sys is AT-compatible (ISA + ISA16) */ @@ -67,18 +67,19 @@ #define MACHINE_AGP (MACHINE_BUS_AGP | MACHINE_PCI) /* sys is AT-compatible with AGP */ #define MACHINE_AGP98 (MACHINE_BUS_AGP | MACHINE_PCI98) /* sys is NEC PC-98x1 series with AGP (did that even exist?) */ -#define MACHINE_PC5150 (MACHINE_PC | MACHINE_CASSETTE) /* sys is IBM PC 5150 */ -#define MACHINE_PCJR (MACHINE_PC | MACHINE_CASSETTE | MACHINE_BUS_SIDECAR) /* sys is PCjr */ -#define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ -#define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ -#define MACHINE_PS2_VLB (MACHINE_VLB | MACHINE_BUS_PS2) /* sys is VLB PS/2 */ -#define MACHINE_PS2_PCI (MACHINE_PCI | MACHINE_BUS_PS2) /* sys is PCI PS/2 */ -#define MACHINE_PS2_PCIV (MACHINE_PCIV | MACHINE_BUS_PS2) /* sys is VLB/PCI PS/2 */ -#define MACHINE_PS2_AGP (MACHINE_AGP | MACHINE_BUS_PS2) /* sys is AGP PS/2 */ -#define MACHINE_PS2_A97 (MACHINE_PS2_AGP | MACHINE_BUS_AC97) /* sys is AGP/AC97 PS/2 */ -#define MACHINE_PS2_NOISA (MACHINE_PS2_AGP & ~MACHINE_AT) /* sys is AGP PS/2 without ISA */ -#define MACHINE_PS2_PCIONLY (MACHINE_PS2_NOISA & ~MACHINE_BUS_AGP) /* sys is PCI PS/2 without ISA */ -#define MACHINE_PS2_NOI97 (MACHINE_PS2_A97 & ~MACHINE_AT) /* sys is AGP/AC97 PS/2 without ISA */ +#define MACHINE_PC5150 (MACHINE_PC | MACHINE_CASSETTE) /* sys is IBM PC 5150 */ +#define MACHINE_PCJR (MACHINE_CASSETTE | MACHINE_BUS_SIDECAR) /* sys is PCjr */ +#define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ +#define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ +#define MACHINE_PS2_VLB (MACHINE_VLB | MACHINE_BUS_PS2) /* sys is VLB PS/2 */ +#define MACHINE_PS2_PCI (MACHINE_PCI | MACHINE_BUS_PS2) /* sys is PCI PS/2 */ +#define MACHINE_PS2_PCIV (MACHINE_PCIV | MACHINE_BUS_PS2) /* sys is VLB/PCI PS/2 */ +#define MACHINE_PS2_AGP (MACHINE_AGP | MACHINE_BUS_PS2) /* sys is AGP PS/2 */ +#define MACHINE_PS2_A97 (MACHINE_PS2_AGP | MACHINE_BUS_AC97) /* sys is AGP/AC97 PS/2 */ +#define MACHINE_PS2_NOISA (MACHINE_PS2_AGP & ~MACHINE_AT) /* sys is AGP PS/2 without ISA */ +#define MACHINE_PS2_PCIONLY (MACHINE_PS2_NOISA & ~MACHINE_BUS_AGP) /* sys is PCI PS/2 without ISA */ +#define MACHINE_PS2_NOI97 (MACHINE_PS2_A97 & ~MACHINE_AT) /* sys is AGP/AC97 PS/2 without ISA */ + /* Feature flags for miscellaneous internal devices. */ #define MACHINE_FLAGS_NONE 0x00000000 /* sys has no int devices */ #define MACHINE_SOFTFLOAT_ONLY 0x00000001 /* sys requires SoftFloat FPU */ From 62444f3da0189caeb065e9b77013011c63eec0d8 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 12 Feb 2025 06:01:18 -0500 Subject: [PATCH 0321/1190] Devices supported on PCjr PC Enterprises GameMaster, Resound jr (adlib) MS Booster/PC Enterprises jrBus-Mouse, PC Enterprises GameMaster (bus mouse) Various (generic) RTC Corel LS2000 SCSI --- src/device/isartc.c | 2 +- src/device/mouse_bus.c | 4 ++-- src/scsi/scsi_ncr53c400.c | 2 +- src/sound/snd_adlib.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/device/isartc.c b/src/device/isartc.c index 63ce0b065..5d6b4aea4 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -862,7 +862,7 @@ static const device_config_t mm58167_config[] = { static const device_t mm58167_device = { .name = "Generic MM58167 RTC", .internal_name = "rtc_mm58167", - .flags = DEVICE_ISA, + .flags = DEVICE_ISA | DEVICE_SIDECAR, .local = ISARTC_MM58167, .init = isartc_init, .close = isartc_close, diff --git a/src/device/mouse_bus.c b/src/device/mouse_bus.c index 7074a71ac..c81bc6aba 100644 --- a/src/device/mouse_bus.c +++ b/src/device/mouse_bus.c @@ -815,7 +815,7 @@ static const device_config_t ms_config[] = { const device_t mouse_logibus_device = { .name = "Logitech/Microsoft Bus Mouse", .internal_name = "logibus", - .flags = DEVICE_ISA, + .flags = DEVICE_ISA | DEVICE_SIDECAR, .local = MOUSE_TYPE_LOGIBUS, .init = bm_init, .close = bm_close, @@ -843,7 +843,7 @@ const device_t mouse_logibus_onboard_device = { const device_t mouse_msinport_device = { .name = "Microsoft Bus Mouse (InPort)", .internal_name = "msbus", - .flags = DEVICE_ISA, + .flags = DEVICE_ISA | DEVICE_SIDECAR, .local = MOUSE_TYPE_INPORT, .init = bm_init, .close = bm_close, diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 10934880f..c83e75442 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -1024,7 +1024,7 @@ const device_t scsi_t130b_device = { const device_t scsi_ls2000_device = { .name = "Corel LS2000", .internal_name = "ls2000", - .flags = DEVICE_ISA, + .flags = DEVICE_ISA | DEVICE_SIDECAR, .local = ROM_LS2000, .init = ncr53c400_init, .close = ncr53c400_close, diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 1f307596c..17990e842 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -145,7 +145,7 @@ adlib_close(void *priv) const device_t adlib_device = { .name = "AdLib", .internal_name = "adlib", - .flags = DEVICE_ISA, + .flags = DEVICE_ISA | DEVICE_SIDECAR, .local = 0, .init = adlib_init, .close = adlib_close, From e821aa1b0a8eed7ebe24959b3fb7d472f350e673 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Fri, 21 Feb 2025 22:52:27 +0100 Subject: [PATCH 0322/1190] Add Packard Bell PB286 (part 1) --- src/include/86box/machine.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 78f4902eb..6d48dbff6 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -438,6 +438,8 @@ extern int machine_at_ibmatquadtel_init(const machine_t *); // IBM AT with Quadt extern int machine_at_ibmxt286_init(const machine_t *); +extern int machine_at_pb286_init(const machine_t *); + extern int machine_at_siemens_init(const machine_t *); // Siemens PCD-2L. N82330 discrete machine. It segfaults in some places extern int machine_at_wellamerastar_init(const machine_t *); // Wells American A*Star with custom award BIOS From e4600291ed0135735021de2984fa73c205d6ff8f Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Fri, 21 Feb 2025 22:56:09 +0100 Subject: [PATCH 0323/1190] Add Packard Bell PB286 (part 2) --- src/machine/m_at.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 3f5e88011..15b828676 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -332,6 +332,22 @@ machine_at_ibmxt286_init(const machine_t *model) return ret; } +machine_at_pb286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/pb286/LB_V332P.BIN", + "roms/machines/pb286/HB_V332P.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + int machine_at_siemens_init(const machine_t *model) { From e0fda208dfa4d1d788a6b0a82e5211b1916d9661 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:03:16 +0100 Subject: [PATCH 0324/1190] Add Packard Bell PB286 (part 3) --- src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3706126a3..eb0584802 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3259,6 +3259,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has IBM AT KBC firmware. */ + /* To configure the BIOS, use PB_2330a_diag.IMA from MS-DOS 3.30 Packard Bell OEM, GSETUP might work too*/ + { + .name = "[ISA] Packard Bell PB286", + .internal_name = "pb286", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_pb286_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 256, + .max = 1024, + .step = 256 + }, + .nvrmask = 63, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* This has a Siemens proprietary KBC which is completely undocumented. */ { .name = "[ISA] Siemens PCD-2L", From e012777244f903fc3ffe9d2dc44229eb12bb6f46 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:19:57 +0100 Subject: [PATCH 0325/1190] Fix compile-breaking mistake (forgot "int") --- src/machine/m_at.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 15b828676..162006803 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -332,6 +332,7 @@ machine_at_ibmxt286_init(const machine_t *model) return ret; } +int machine_at_pb286_init(const machine_t *model) { int ret; From 48da4f3811898058762be3fb5ab374c8e46918db Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:27:23 +0100 Subject: [PATCH 0326/1190] adjust the RAM step, Packard Bell 286s are known to support 640 KB RAM configurations --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index eb0584802..abfdf9d16 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3286,7 +3286,7 @@ const machine_t machines[] = { .ram = { .min = 256, .max = 1024, - .step = 256 + .step = 128 }, .nvrmask = 63, .kbc_device = NULL, From 457601330d169c911d80fb2b18becbba4949a3d7 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 20:15:26 -0500 Subject: [PATCH 0327/1190] Tag cassette_device correctly --- src/device/cassette.c | 2 +- src/include/86box/device.h | 1 + src/include/86box/machine.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/device/cassette.c b/src/device/cassette.c index ac79edff2..5cde2fbd0 100644 --- a/src/device/cassette.c +++ b/src/device/cassette.c @@ -715,7 +715,7 @@ cassette_init(UNUSED(const device_t *info)) const device_t cassette_device = { .name = "IBM PC/PCjr Cassette Device", .internal_name = "cassette", - .flags = 0, + .flags = DEVICE_CASETTE, .local = 0, .init = cassette_init, .close = cassette_close, diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 1c3ef1ef3..4cc283a25 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -79,6 +79,7 @@ // #define CONFIG_STANDALONE 257 /* not available on the on-board variant */ enum { + DEVICE_CASETTE = 1, /* requires a Casette Port */ DEVICE_SIDECAR = 2, /* requires an IBM PCjr */ DEVICE_ISA = 4, /* requires the ISA bus */ DEVICE_XT_KBC = 8, /* requires an XT-compatible keyboard controller */ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 52af90581..b2e4c01f2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -67,7 +67,7 @@ #define MACHINE_AGP (MACHINE_BUS_AGP | MACHINE_PCI) /* sys is AT-compatible with AGP */ #define MACHINE_AGP98 (MACHINE_BUS_AGP | MACHINE_PCI98) /* sys is NEC PC-98x1 series with AGP (did that even exist?) */ -#define MACHINE_PC5150 (MACHINE_PC | MACHINE_CASSETTE) /* sys is IBM PC 5150 */ +#define MACHINE_PC5150 (MACHINE_CASSETTE | MACHINE_PC) /* sys is IBM PC 5150 */ #define MACHINE_PCJR (MACHINE_CASSETTE | MACHINE_BUS_SIDECAR) /* sys is PCjr */ #define MACHINE_PS2 (MACHINE_AT | MACHINE_BUS_PS2) /* sys is PS/2 */ #define MACHINE_PS2_MCA (MACHINE_MCA | MACHINE_BUS_PS2) /* sys is MCA PS/2 */ From c1f8944c402e199c91d2298dda3fa66b3c3d785f Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 22 Feb 2025 20:31:05 +0900 Subject: [PATCH 0328/1190] remove unused 5576 key conv table --- src/device/keyboard.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 2b851f36c..582dcf0b1 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -85,34 +85,6 @@ typedef struct { const uint8_t brk[4]; } scconvtbl; -/* Is this a left-over of something planned earlier? */ -#ifdef USE_SCCONV55_82 -static scconvtbl scconv55_82[18 + 1] = -{ - // clang-format off - {.sc = 0x02 , .mk = { 0x5f, 0 }, .brk = { 0xf0, 0x5f, 0 } }, /* '1' -> 'Clear/ /SysRq' */ - {.sc = 0x03 , .mk = { 0x48, 0 }, .brk = { 0xf0, 0x48, 0 } }, /* '2' -> '終了 (Exit)' */ - {.sc = 0x04 , .mk = { 0x38, 0 }, .brk = { 0xf0, 0x38, 0 } }, /* '3' -> 'メッセージ (Message)/ /応答 (Respond)' */ - {.sc = 0x05 , .mk = { 0x30, 0 }, .brk = { 0xf0, 0x30, 0 } }, /* '4' -> 'サイズ変換 (Change Size)/ /横倍角 (2x Width)' */ - {.sc = 0x06 , .mk = { 0x20, 0 }, .brk = { 0xf0, 0x20, 0 } }, /* '5' -> '単語登録 (Register Word)/ /再交換 (Re-change)' */ - {.sc = 0x07 , .mk = { 0x28, 0 }, .brk = { 0xf0, 0x28, 0 } }, /* '6' -> '漢字 (Kanji)/ /番号 (Number)' */ - {.sc = 0x08 , .mk = { 0x60, 0 }, .brk = { 0xf0, 0x60, 0 } }, /* '7' -> '取消 (Cancel)' */ - {.sc = 0x09 , .mk = { 0x40, 0 }, .brk = { 0xf0, 0x40, 0 } }, /* '8' -> 'コピー (Copy)/ /移動 (Move)' */ - {.sc = 0x3d , .mk = { 0x1f, 0 }, .brk = { 0xf0, 0x1f, 0 } }, /* 'F3' -> 'Cr Bnk/領域呼出 (Call Range)/All Cr/登録 (Register)' */ - {.sc = 0x3e , .mk = { 0x27, 0 }, .brk = { 0xf0, 0x27, 0 } }, /* 'F4' -> '割込み (Interrupt)' */ - {.sc = 0x3f , .mk = { 0x2f, 0 }, .brk = { 0xf0, 0x2f, 0 } }, /* 'F5' -> 'UF1' */ - {.sc = 0x40 , .mk = { 0x5e, 0 }, .brk = { 0xf0, 0x5e, 0 } }, /* 'F6' -> 'UF2' */ - {.sc = 0x41 , .mk = { 0x08, 0 }, .brk = { 0xf0, 0x08, 0 } }, /* 'F7' -> 'UF3' */ - {.sc = 0x42 , .mk = { 0x10, 0 }, .brk = { 0xf0, 0x10, 0 } }, /* 'F8' -> 'UF4' */ - {.sc = 0x43 , .mk = { 0x50, 0 }, .brk = { 0xf0, 0x50, 0 } }, /* 'F9' -> 'EOF/Erase/ErInp' */ - {.sc = 0x44 , .mk = { 0x18, 0 }, .brk = { 0xf0, 0x18, 0 } }, /* 'F10' -> 'Attn/ /CrSel' */ - {.sc = 0x57 , .mk = { 0x17, 0 }, .brk = { 0xf0, 0x17, 0 } }, /* 'F11' -> 'PA1/ /DvCncl' */ - {.sc = 0x58 , .mk = { 0x37, 0 }, .brk = { 0xf0, 0x37, 0 } }, /* 'F12' -> 'PA2/ /PA3' */ - {.sc = 0 , .mk = { 0 }, .brk = { 0 } } /* end */ - // clang-format on -}; -#endif - static scconvtbl scconv55_8a[18 + 1] = { // clang-format off From ffedf62a4a0707acb947a271c7751de3e00157e2 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:02:44 +0900 Subject: [PATCH 0329/1190] add scancode set 81h and 82h (incompleted) need to modify the keyboard initialization --- src/86box.c | 4 +- src/device/keyboard_at.c | 1090 +++++++++++++++++++++++++++++++++++++- 2 files changed, 1071 insertions(+), 23 deletions(-) diff --git a/src/86box.c b/src/86box.c index 1cd0ffec8..6b64cd2ec 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1094,8 +1094,8 @@ pc_init_modules(void) void pc_send_ca(uint16_t sc) { - if (keyboard_mode == 0x8A) { - /* Use R-Alt because PS/55 DOS assigns L-Alt Kanji */ + if (keyboard_mode >= 0x81) { + /* Use R-Alt because PS/55 DOS and OS/2 assign L-Alt Kanji */ keyboard_input(1, 0x1D); /* Ctrl key pressed */ keyboard_input(1, 0x138); /* R-Alt key pressed */ keyboard_input(1, sc); diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 5c66029ad..d44833dd3 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -1651,10 +1651,1045 @@ static const scancode scancode_set3[512] = { [Japanese DOS and keyboard scancode set comparison] | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | DOS 5(US)| |---------------------------|:----:|:----:|:----:|:------:|:------:|:---------:|:--------:| - | IBM 101-key | n/a | n/a | n/a | n/a | 2 | n/a | 2 | - | IBM-J 5576-00x (obsolete) | 8Ah | 8Ah | 8Ah | 82h | 82h | 82h | 2 | - | OADG (modern Japanese) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | */ + | IBM 101 US English | n/a | n/a | n/a | 2 | 2 | 2 | 2 | + | IBM-J 5576-00x (obsolete) | 8Ah | 8Ah | 8Ah | 82h | 82h | 81h | 2 | + | OADG (modern Japanese) | n/a | n/a | n/a | 2 | 2 | 2 | 2 | +*/ +/* Scancode set 81h : Set 01 with language specific keys support used by OS/2 */ +static const scancode scancode_set81[512] = { + // clang-format off + { .mk = { 0 }, .brk = { 0 } }, /* 000 */ + { .mk = { 0x01, 0 }, .brk = { 0x81, 0 } }, /* 001 */ + { .mk = { 0x02, 0 }, .brk = { 0x82, 0 } }, /* 002 */ + { .mk = { 0x03, 0 }, .brk = { 0x83, 0 } }, /* 003 */ + { .mk = { 0x04, 0 }, .brk = { 0x84, 0 } }, /* 004 */ + { .mk = { 0x05, 0 }, .brk = { 0x85, 0 } }, /* 005 */ + { .mk = { 0x06, 0 }, .brk = { 0x86, 0 } }, /* 006 */ + { .mk = { 0x07, 0 }, .brk = { 0x87, 0 } }, /* 007 */ + { .mk = { 0x08, 0 }, .brk = { 0x88, 0 } }, /* 008 */ + { .mk = { 0x09, 0 }, .brk = { 0x89, 0 } }, /* 009 */ + { .mk = { 0x0a, 0 }, .brk = { 0x8a, 0 } }, /* 00a */ + { .mk = { 0x0b, 0 }, .brk = { 0x8b, 0 } }, /* 00b */ + { .mk = { 0x0c, 0 }, .brk = { 0x8c, 0 } }, /* 00c */ + { .mk = { 0x0d, 0 }, .brk = { 0x8d, 0 } }, /* 00d */ + { .mk = { 0x0e, 0 }, .brk = { 0x8e, 0 } }, /* 00e */ + { .mk = { 0x0f, 0 }, .brk = { 0x8f, 0 } }, /* 00f */ + { .mk = { 0x10, 0 }, .brk = { 0x90, 0 } }, /* 010 */ + { .mk = { 0x11, 0 }, .brk = { 0x91, 0 } }, /* 011 */ + { .mk = { 0x12, 0 }, .brk = { 0x92, 0 } }, /* 012 */ + { .mk = { 0x13, 0 }, .brk = { 0x93, 0 } }, /* 013 */ + { .mk = { 0x14, 0 }, .brk = { 0x94, 0 } }, /* 014 */ + { .mk = { 0x15, 0 }, .brk = { 0x95, 0 } }, /* 015 */ + { .mk = { 0x16, 0 }, .brk = { 0x96, 0 } }, /* 016 */ + { .mk = { 0x17, 0 }, .brk = { 0x97, 0 } }, /* 017 */ + { .mk = { 0x18, 0 }, .brk = { 0x98, 0 } }, /* 018 */ + { .mk = { 0x19, 0 }, .brk = { 0x99, 0 } }, /* 019 */ + { .mk = { 0x1a, 0 }, .brk = { 0x9a, 0 } }, /* 01a */ + { .mk = { 0x1b, 0 }, .brk = { 0x9b, 0 } }, /* 01b */ + { .mk = { 0x1c, 0 }, .brk = { 0x9c, 0 } }, /* 01c */ + { .mk = { 0x1d, 0 }, .brk = { 0x9d, 0 } }, /* 01d */ + { .mk = { 0x1e, 0 }, .brk = { 0x9e, 0 } }, /* 01e */ + { .mk = { 0x1f, 0 }, .brk = { 0x9f, 0 } }, /* 01f */ + { .mk = { 0x20, 0 }, .brk = { 0xa0, 0 } }, /* 020 */ + { .mk = { 0x21, 0 }, .brk = { 0xa1, 0 } }, /* 021 */ + { .mk = { 0x22, 0 }, .brk = { 0xa2, 0 } }, /* 022 */ + { .mk = { 0x23, 0 }, .brk = { 0xa3, 0 } }, /* 023 */ + { .mk = { 0x24, 0 }, .brk = { 0xa4, 0 } }, /* 024 */ + { .mk = { 0x25, 0 }, .brk = { 0xa5, 0 } }, /* 025 */ + { .mk = { 0x26, 0 }, .brk = { 0xa6, 0 } }, /* 026 */ + { .mk = { 0x27, 0 }, .brk = { 0xa7, 0 } }, /* 027 */ + { .mk = { 0x28, 0 }, .brk = { 0xa8, 0 } }, /* 028* */ + { .mk = { 0x77, 0 }, .brk = { 0xf7, 0 } }, /* 029 0x45 Hankaku, Zenkaku */ + { .mk = { 0x2a, 0 }, .brk = { 0xaa, 0 } }, /* 02a */ + { .mk = { 0x1b, 0 }, .brk = { 0x9b, 0 } }, /* 02b 0x17 Mu */ + { .mk = { 0x2c, 0 }, .brk = { 0xac, 0 } }, /* 02c */ + { .mk = { 0x2d, 0 }, .brk = { 0xad, 0 } }, /* 02d */ + { .mk = { 0x2e, 0 }, .brk = { 0xae, 0 } }, /* 02e */ + { .mk = { 0x2f, 0 }, .brk = { 0xaf, 0 } }, /* 02f */ + { .mk = { 0x30, 0 }, .brk = { 0xb0, 0 } }, /* 030 */ + { .mk = { 0x31, 0 }, .brk = { 0xb1, 0 } }, /* 031 */ + { .mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 032 */ + { .mk = { 0x33, 0 }, .brk = { 0xb3, 0 } }, /* 033 */ + { .mk = { 0x34, 0 }, .brk = { 0xb4, 0 } }, /* 034 */ + { .mk = { 0x35, 0 }, .brk = { 0xb5, 0 } }, /* 035 */ + { .mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 036 */ + { .mk = { 0x37, 0 }, .brk = { 0xb7, 0 } }, /* 037 * (asterisk) */ + { .mk = { 0x70, 0 }, .brk = { 0xf0, 0 } }, /* 038 0x3A LALT = Kanji */ + { .mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 039 */ + { .mk = { 0x3a, 0 }, .brk = { 0xba, 0 } }, /* 03a */ + { .mk = { 0x3b, 0 }, .brk = { 0xbb, 0 } }, /* 03b */ + { .mk = { 0x3c, 0 }, .brk = { 0xbc, 0 } }, /* 03c */ + { .mk = { 0x3d, 0 }, .brk = { 0xbd, 0 } }, /* 03d */ + { .mk = { 0x3e, 0 }, .brk = { 0xbe, 0 } }, /* 03e */ + { .mk = { 0x3f, 0 }, .brk = { 0xbf, 0 } }, /* 03f */ + { .mk = { 0x40, 0 }, .brk = { 0xc0, 0 } }, /* 040 */ + { .mk = { 0x41, 0 }, .brk = { 0xc1, 0 } }, /* 041 */ + { .mk = { 0x42, 0 }, .brk = { 0xc2, 0 } }, /* 042 */ + { .mk = { 0x43, 0 }, .brk = { 0xc3, 0 } }, /* 043 */ + { .mk = { 0x44, 0 }, .brk = { 0xc4, 0 } }, /* 044 */ + { .mk = { 0x45, 0 }, .brk = { 0xc5, 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */ + { .mk = { 0x46, 0 }, .brk = { 0xc6, 0 } }, /* 046 0x75 SCROLLLOCK */ + { .mk = { 0x47, 0 }, .brk = { 0xc7, 0 } }, /* 047 */ + { .mk = { 0x48, 0 }, .brk = { 0xc8, 0 } }, /* 048 */ + { .mk = { 0x49, 0 }, .brk = { 0xc9, 0 } }, /* 049 */ + { .mk = { 0x4a, 0 }, .brk = { 0xca, 0 } }, /* 04a */ + { .mk = { 0x4b, 0 }, .brk = { 0xcb, 0 } }, /* 04b */ + { .mk = { 0x4c, 0 }, .brk = { 0xcc, 0 } }, /* 04c */ + { .mk = { 0x4d, 0 }, .brk = { 0xcd, 0 } }, /* 04d */ + { .mk = { 0x4e, 0 }, .brk = { 0xce, 0 } }, /* 04e */ + { .mk = { 0x4f, 0 }, .brk = { 0xcf, 0 } }, /* 04f */ + { .mk = { 0x50, 0 }, .brk = { 0xd0, 0 } }, /* 050 */ + { .mk = { 0x51, 0 }, .brk = { 0xd1, 0 } }, /* 051 */ + { .mk = { 0x52, 0 }, .brk = { 0xd2, 0 } }, /* 052 */ + { .mk = { 0x53, 0 }, .brk = { 0xd3, 0 } }, /* 053 */ + { .mk = { 0x54, 0 }, .brk = { 0xd4, 0 } }, /* 054 */ + { .mk = { 0x55, 0 }, .brk = { 0xd5, 0 } }, /* 055 */ + { .mk = { 0x56, 0 }, .brk = { 0xd6, 0 } }, /* 056 */ + { .mk = { 0x57, 0 }, .brk = { 0xd7, 0 } }, /* 057 F11 */ + { .mk = { 0x58, 0 }, .brk = { 0xd8, 0 } }, /* 058 F12 */ + { .mk = { 0x59, 0 }, .brk = { 0xd9, 0 } }, /* 059 */ + { .mk = { 0x5a, 0 }, .brk = { 0xda, 0 } }, /* 05a */ + { .mk = { 0x5b, 0 }, .brk = { 0xdb, 0 } }, /* 05b */ + { .mk = { 0x5c, 0 }, .brk = { 0xdc, 0 } }, /* 05c */ + { .mk = { 0x5d, 0 }, .brk = { 0xdd, 0 } }, /* 05d */ + { .mk = { 0x5e, 0 }, .brk = { 0xde, 0 } }, /* 05e */ + { .mk = { 0x5f, 0 }, .brk = { 0xdf, 0 } }, /* 05f */ + { .mk = { 0x60, 0 }, .brk = { 0xe0, 0 } }, /* 060 */ + { .mk = { 0x61, 0 }, .brk = { 0xe1, 0 } }, /* 061 */ + { .mk = { 0x62, 0 }, .brk = { 0xe2, 0 } }, /* 062 */ + { .mk = { 0x63, 0 }, .brk = { 0xe3, 0 } }, /* 063 */ + { .mk = { 0x64, 0 }, .brk = { 0xe4, 0 } }, /* 064 */ + { .mk = { 0x65, 0 }, .brk = { 0xe5, 0 } }, /* 065 */ + { .mk = { 0x66, 0 }, .brk = { 0xe6, 0 } }, /* 066 */ + { .mk = { 0x67, 0 }, .brk = { 0xe7, 0 } }, /* 067 */ + { .mk = { 0x68, 0 }, .brk = { 0xe8, 0 } }, /* 068 */ + { .mk = { 0x69, 0 }, .brk = { 0xe9, 0 } }, /* 069 */ + { .mk = { 0x6a, 0 }, .brk = { 0xea, 0 } }, /* 06a */ + { .mk = { 0x6b, 0 }, .brk = { 0xeb, 0 } }, /* 06b */ + { .mk = { 0x6c, 0 }, .brk = { 0xec, 0 } }, /* 06c */ + { .mk = { 0x6d, 0 }, .brk = { 0xed, 0 } }, /* 06d */ + { .mk = { 0x6e, 0 }, .brk = { 0xee, 0 } }, /* 06e */ + { .mk = { 0x6f, 0 }, .brk = { 0xef, 0 } }, /* 06f */ + { .mk = {0xe0, 0x38, 0 }, .brk = { 0xe0, 0xb8, 0 } }, /* 070 0x36 Kana */ + { .mk = { 0x71, 0 }, .brk = { 0xf1, 0 } }, /* 071 */ + { .mk = { 0x72, 0 }, .brk = { 0xf2, 0 } }, /* 072 */ + { .mk = { 0x73, 0 }, .brk = { 0xf3, 0 } }, /* 073 0x0b Ro, Underline */ + { .mk = { 0x74, 0 }, .brk = { 0xf4, 0 } }, /* 074 */ + { .mk = { 0x75, 0 }, .brk = { 0xf5, 0 } }, /* 075 */ + { .mk = { 0x76, 0 }, .brk = { 0xf6, 0 } }, /* 076 */ + { .mk = { 0x77, 0 }, .brk = { 0xf7, 0 } }, /* 077 */ + { .mk = { 0x78, 0 }, .brk = { 0xf8, 0 } }, /* 078 */ + { .mk = { 0x79, 0 }, .brk = { 0xf9, 0 } }, /* 079 0x35 Henkan */ + { .mk = { 0x7a, 0 }, .brk = { 0xfa, 0 } }, /* 07a */ + { .mk = { 0x7b, 0 }, .brk = { 0xfb, 0 } }, /* 07b 0x33 Muhenkan */ + { .mk = { 0x7c, 0 }, .brk = { 0xfc, 0 } }, /* 07c */ + { .mk = { 0x2b, 0 }, .brk = { 0xab, 0 } }, /* 07d 0x30 Yen, Vertical line */ + { .mk = { 0x7e, 0 }, .brk = { 0xfe, 0 } }, /* 07e */ + { .mk = { 0x7f, 0 }, .brk = { 0xff, 0 } }, /* 07f */ + { .mk = { 0x80, 0 }, .brk = { 0 } }, /* 080 */ + { .mk = { 0x81, 0 }, .brk = { 0 } }, /* 081 */ + { .mk = { 0x82, 0 }, .brk = { 0 } }, /* 082 */ + { .mk = { 0 }, .brk = { 0 } }, /* 083 */ + { .mk = { 0 }, .brk = { 0 } }, /* 084 */ + { .mk = { 0x85, 0 }, .brk = { 0 } }, /* 085 */ + { .mk = { 0x86, 0 }, .brk = { 0 } }, /* 086 */ + { .mk = { 0x87, 0 }, .brk = { 0 } }, /* 087 */ + { .mk = { 0x88, 0 }, .brk = { 0 } }, /* 088 */ + { .mk = { 0x89, 0 }, .brk = { 0 } }, /* 089 */ + { .mk = { 0x8a, 0 }, .brk = { 0 } }, /* 08a */ + { .mk = { 0x8b, 0 }, .brk = { 0 } }, /* 08b */ + { .mk = { 0x8c, 0 }, .brk = { 0 } }, /* 08c */ + { .mk = { 0x8d, 0 }, .brk = { 0 } }, /* 08d */ + { .mk = { 0x8e, 0 }, .brk = { 0 } }, /* 08e */ + { .mk = { 0x8f, 0 }, .brk = { 0 } }, /* 08f */ + { .mk = { 0x90, 0 }, .brk = { 0 } }, /* 090 */ + { .mk = { 0x91, 0 }, .brk = { 0 } }, /* 091 */ + { .mk = { 0x92, 0 }, .brk = { 0 } }, /* 092 */ + { .mk = { 0x93, 0 }, .brk = { 0 } }, /* 093 */ + { .mk = { 0x94, 0 }, .brk = { 0 } }, /* 094 */ + { .mk = { 0x95, 0 }, .brk = { 0 } }, /* 095 */ + { .mk = { 0x96, 0 }, .brk = { 0 } }, /* 096 */ + { .mk = { 0x97, 0 }, .brk = { 0 } }, /* 097 */ + { .mk = { 0x98, 0 }, .brk = { 0 } }, /* 098 */ + { .mk = { 0x99, 0 }, .brk = { 0 } }, /* 099 */ + { .mk = { 0x9a, 0 }, .brk = { 0 } }, /* 09a */ + { .mk = { 0x9b, 0 }, .brk = { 0 } }, /* 09b */ + { .mk = { 0x9c, 0 }, .brk = { 0 } }, /* 09c */ + { .mk = { 0x9d, 0 }, .brk = { 0 } }, /* 09d */ + { .mk = { 0x9e, 0 }, .brk = { 0 } }, /* 09e */ + { .mk = { 0x9f, 0 }, .brk = { 0 } }, /* 09f */ + { .mk = { 0xa0, 0 }, .brk = { 0 } }, /* 0a0 */ + { .mk = { 0xa1, 0 }, .brk = { 0 } }, /* 0a1 */ + { .mk = { 0xa2, 0 }, .brk = { 0 } }, /* 0a2 */ + { .mk = { 0xa3, 0 }, .brk = { 0 } }, /* 0a3 */ + { .mk = { 0xa4, 0 }, .brk = { 0 } }, /* 0a4 */ + { .mk = { 0xa5, 0 }, .brk = { 0 } }, /* 0a5 */ + { .mk = { 0xa6, 0 }, .brk = { 0 } }, /* 0a6 */ + { .mk = { 0xa7, 0 }, .brk = { 0 } }, /* 0a7 */ + { .mk = { 0xa8, 0 }, .brk = { 0 } }, /* 0a8 */ + { .mk = { 0xa9, 0 }, .brk = { 0 } }, /* 0a9 */ + { .mk = { 0xaa, 0 }, .brk = { 0 } }, /* 0aa */ + { .mk = { 0xab, 0 }, .brk = { 0 } }, /* 0ab */ + { .mk = { 0xac, 0 }, .brk = { 0 } }, /* 0ac */ + { .mk = { 0xad, 0 }, .brk = { 0 } }, /* 0ad */ + { .mk = { 0xae, 0 }, .brk = { 0 } }, /* 0ae */ + { .mk = { 0xaf, 0 }, .brk = { 0 } }, /* 0af */ + { .mk = { 0xb0, 0 }, .brk = { 0 } }, /* 0b0 */ + { .mk = { 0xb1, 0 }, .brk = { 0 } }, /* 0b1 */ + { .mk = { 0xb2, 0 }, .brk = { 0 } }, /* 0b2 */ + { .mk = { 0xb3, 0 }, .brk = { 0 } }, /* 0b3 */ + { .mk = { 0xb4, 0 }, .brk = { 0 } }, /* 0b4 */ + { .mk = { 0xb5, 0 }, .brk = { 0 } }, /* 0b5 */ + { .mk = { 0xb6, 0 }, .brk = { 0 } }, /* 0b6 */ + { .mk = { 0xb7, 0 }, .brk = { 0 } }, /* 0b7 */ + { .mk = { 0xb8, 0 }, .brk = { 0 } }, /* 0b8 */ + { .mk = { 0xb9, 0 }, .brk = { 0 } }, /* 0b9 */ + { .mk = { 0xba, 0 }, .brk = { 0 } }, /* 0ba */ + { .mk = { 0xbb, 0 }, .brk = { 0 } }, /* 0bb */ + { .mk = { 0xbc, 0 }, .brk = { 0 } }, /* 0bc */ + { .mk = { 0xbd, 0 }, .brk = { 0 } }, /* 0bd */ + { .mk = { 0xbe, 0 }, .brk = { 0 } }, /* 0be */ + { .mk = { 0xbf, 0 }, .brk = { 0 } }, /* 0bf */ + { .mk = { 0xc0, 0 }, .brk = { 0 } }, /* 0c0 */ + { .mk = { 0xc1, 0 }, .brk = { 0 } }, /* 0c1 */ + { .mk = { 0xc2, 0 }, .brk = { 0 } }, /* 0c2 */ + { .mk = { 0xc3, 0 }, .brk = { 0 } }, /* 0c3 */ + { .mk = { 0xc4, 0 }, .brk = { 0 } }, /* 0c4 */ + { .mk = { 0xc5, 0 }, .brk = { 0 } }, /* 0c5 */ + { .mk = { 0xc6, 0 }, .brk = { 0 } }, /* 0c6 */ + { .mk = { 0xc7, 0 }, .brk = { 0 } }, /* 0c7 */ + { .mk = { 0xc8, 0 }, .brk = { 0 } }, /* 0c8 */ + { .mk = { 0xc9, 0 }, .brk = { 0 } }, /* 0c9 */ + { .mk = { 0xca, 0 }, .brk = { 0 } }, /* 0ca */ + { .mk = { 0xcb, 0 }, .brk = { 0 } }, /* 0cb */ + { .mk = { 0xcc, 0 }, .brk = { 0 } }, /* 0cc */ + { .mk = { 0xcd, 0 }, .brk = { 0 } }, /* 0cd */ + { .mk = { 0xce, 0 }, .brk = { 0 } }, /* 0ce */ + { .mk = { 0xcf, 0 }, .brk = { 0 } }, /* 0cf */ + { .mk = { 0xd0, 0 }, .brk = { 0 } }, /* 0d0 */ + { .mk = { 0xd1, 0 }, .brk = { 0 } }, /* 0d1 */ + { .mk = { 0xd2, 0 }, .brk = { 0 } }, /* 0d2 */ + { .mk = { 0xd3, 0 }, .brk = { 0 } }, /* 0d3 */ + { .mk = { 0xd4, 0 }, .brk = { 0 } }, /* 0d4 */ + { .mk = { 0xd5, 0 }, .brk = { 0 } }, /* 0d5 */ + { .mk = { 0xd6, 0 }, .brk = { 0 } }, /* 0d6 */ + { .mk = { 0xd7, 0 }, .brk = { 0 } }, /* 0d7 */ + { .mk = { 0xd8, 0 }, .brk = { 0 } }, /* 0d8 */ + { .mk = { 0xd9, 0 }, .brk = { 0 } }, /* 0d9 */ + { .mk = { 0xda, 0 }, .brk = { 0 } }, /* 0da */ + { .mk = { 0xdb, 0 }, .brk = { 0 } }, /* 0db */ + { .mk = { 0xdc, 0 }, .brk = { 0 } }, /* 0dc */ + { .mk = { 0xdd, 0 }, .brk = { 0 } }, /* 0dd */ + { .mk = { 0xde, 0 }, .brk = { 0 } }, /* 0de */ + { .mk = { 0xdf, 0 }, .brk = { 0 } }, /* 0df */ + { .mk = { 0xe0, 0 }, .brk = { 0 } }, /* 0e0 */ + { .mk = { 0xe1, 0 }, .brk = { 0 } }, /* 0e1 */ + { .mk = { 0xe2, 0 }, .brk = { 0 } }, /* 0e2 */ + { .mk = { 0xe3, 0 }, .brk = { 0 } }, /* 0e3 */ + { .mk = { 0xe4, 0 }, .brk = { 0 } }, /* 0e4 */ + { .mk = { 0xe5, 0 }, .brk = { 0 } }, /* 0e5 */ + { .mk = { 0xe6, 0 }, .brk = { 0 } }, /* 0e6 */ + { .mk = { 0xe7, 0 }, .brk = { 0 } }, /* 0e7 */ + { .mk = { 0xe8, 0 }, .brk = { 0 } }, /* 0e8 */ + { .mk = { 0xe9, 0 }, .brk = { 0 } }, /* 0e9 */ + { .mk = { 0xea, 0 }, .brk = { 0 } }, /* 0ea */ + { .mk = { 0xeb, 0 }, .brk = { 0 } }, /* 0eb */ + { .mk = { 0xec, 0 }, .brk = { 0 } }, /* 0ec */ + { .mk = { 0xed, 0 }, .brk = { 0 } }, /* 0ed */ + { .mk = { 0xee, 0 }, .brk = { 0 } }, /* 0ee */ + { .mk = { 0xef, 0 }, .brk = { 0 } }, /* 0ef */ + { .mk = { 0 }, .brk = { 0 } }, /* 0f0 */ + { .mk = { 0xf1, 0 }, .brk = { 0 } }, /* 0f1 */ + { .mk = { 0xf2, 0 }, .brk = { 0 } }, /* 0f2 */ + { .mk = { 0xf3, 0 }, .brk = { 0 } }, /* 0f3 */ + { .mk = { 0xf4, 0 }, .brk = { 0 } }, /* 0f4 */ + { .mk = { 0xf5, 0 }, .brk = { 0 } }, /* 0f5 */ + { .mk = { 0xf6, 0 }, .brk = { 0 } }, /* 0f6 */ + { .mk = { 0xf7, 0 }, .brk = { 0 } }, /* 0f7 */ + { .mk = { 0xf8, 0 }, .brk = { 0 } }, /* 0f8 */ + { .mk = { 0xf9, 0 }, .brk = { 0 } }, /* 0f9 */ + { .mk = { 0xfa, 0 }, .brk = { 0 } }, /* 0fa */ + { .mk = { 0xfb, 0 }, .brk = { 0 } }, /* 0fb */ + { .mk = { 0xfc, 0 }, .brk = { 0 } }, /* 0fc */ + { .mk = { 0xfd, 0 }, .brk = { 0 } }, /* 0fd */ + { .mk = { 0xfe, 0 }, .brk = { 0 } }, /* 0fe */ + { .mk = { 0xff, 0 }, .brk = { 0 } }, /* 0ff */ + { .mk = {0xe1, 0x1d, 0 }, .brk = { 0xe1, 0x9d, 0 } }, /* 100 */ + { .mk = {0xe0, 0x01, 0 }, .brk = { 0xe0, 0x81, 0 } }, /* 101 */ + { .mk = {0xe0, 0x02, 0 }, .brk = { 0xe0, 0x82, 0 } }, /* 102 */ + { .mk = {0xe0, 0x03, 0 }, .brk = { 0xe0, 0x83, 0 } }, /* 103 */ + { .mk = {0xe0, 0x04, 0 }, .brk = { 0xe0, 0x84, 0 } }, /* 104 */ + { .mk = {0xe0, 0x05, 0 }, .brk = { 0xe0, 0x85, 0 } }, /* 105 */ + { .mk = {0xe0, 0x06, 0 }, .brk = { 0xe0, 0x86, 0 } }, /* 106 */ + { .mk = {0xe0, 0x07, 0 }, .brk = { 0xe0, 0x87, 0 } }, /* 107 */ + { .mk = {0xe0, 0x08, 0 }, .brk = { 0xe0, 0x88, 0 } }, /* 108 */ + { .mk = {0xe0, 0x09, 0 }, .brk = { 0xe0, 0x89, 0 } }, /* 109 */ + { .mk = {0xe0, 0x0a, 0 }, .brk = { 0xe0, 0x8a, 0 } }, /* 10a */ + { .mk = {0xe0, 0x0b, 0 }, .brk = { 0xe0, 0x8b, 0 } }, /* 10b */ + { .mk = {0xe0, 0x0c, 0 }, .brk = { 0xe0, 0x8c, 0 } }, /* 10c */ + { .mk = { 0 }, .brk = { 0 } }, /* 10d */ + { .mk = {0xe0, 0x0e, 0 }, .brk = { 0xe0, 0x8e, 0 } }, /* 10e */ + { .mk = {0xe0, 0x0f, 0 }, .brk = { 0xe0, 0x8f, 0 } }, /* 10f */ + { .mk = {0xe0, 0x10, 0 }, .brk = { 0xe0, 0x90, 0 } }, /* 110 */ + { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0x91, 0 } }, /* 112 */ + { .mk = {0xe0, 0x12, 0 }, .brk = { 0xe0, 0x92, 0 } }, /* 113 */ + { .mk = {0xe0, 0x13, 0 }, .brk = { 0xe0, 0x93, 0 } }, /* 113 */ + { .mk = {0xe0, 0x14, 0 }, .brk = { 0xe0, 0x94, 0 } }, /* 114 */ + { .mk = {0xe0, 0x15, 0 }, .brk = { 0xe0, 0x95, 0 } }, /* 115 */ + { .mk = {0xe0, 0x16, 0 }, .brk = { 0xe0, 0x96, 0 } }, /* 116 */ + { .mk = {0xe0, 0x17, 0 }, .brk = { 0xe0, 0x97, 0 } }, /* 117 */ + { .mk = {0xe0, 0x18, 0 }, .brk = { 0xe0, 0x98, 0 } }, /* 118 */ + { .mk = {0xe0, 0x19, 0 }, .brk = { 0xe0, 0x99, 0 } }, /* 119 */ + { .mk = {0xe0, 0x1a, 0 }, .brk = { 0xe0, 0x9a, 0 } }, /* 11a */ + { .mk = {0xe0, 0x1b, 0 }, .brk = { 0xe0, 0x9b, 0 } }, /* 11b */ + { .mk = {0xe0, 0x1c, 0 }, .brk = { 0xe0, 0x9c, 0 } }, /* 11c */ + { .mk = {0xe0, 0x1d, 0 }, .brk = { 0xe0, 0x9d, 0 } }, /* 11d */ + { .mk = {0xe0, 0x1e, 0 }, .brk = { 0xe0, 0x9e, 0 } }, /* 11e */ + { .mk = {0xe0, 0x1f, 0 }, .brk = { 0xe0, 0x9f, 0 } }, /* 11f */ + { .mk = {0xe0, 0x20, 0 }, .brk = { 0xe0, 0xa0, 0 } }, /* 120 */ + { .mk = {0xe0, 0x21, 0 }, .brk = { 0xe0, 0xa1, 0 } }, /* 121 */ + { .mk = {0xe0, 0x22, 0 }, .brk = { 0xe0, 0xa2, 0 } }, /* 122 */ + { .mk = {0xe0, 0x23, 0 }, .brk = { 0xe0, 0xa3, 0 } }, /* 123 */ + { .mk = {0xe0, 0x24, 0 }, .brk = { 0xe0, 0xa4, 0 } }, /* 124 */ + { .mk = {0xe0, 0x25, 0 }, .brk = { 0xe0, 0xa5, 0 } }, /* 125 */ + { .mk = {0xe0, 0x26, 0 }, .brk = { 0xe0, 0xa6, 0 } }, /* 126 */ + { .mk = { 0 }, .brk = { 0 } }, /* 127 */ + { .mk = { 0 }, .brk = { 0 } }, /* 128 */ + { .mk = { 0 }, .brk = { 0 } }, /* 129 */ + { .mk = { 0 }, .brk = { 0 } }, /* 12a */ + { .mk = { 0 }, .brk = { 0 } }, /* 12b */ + { .mk = {0xe0, 0x2c, 0 }, .brk = { 0xe0, 0xac, 0 } }, /* 12c */ + { .mk = {0xe0, 0x2d, 0 }, .brk = { 0xe0, 0xad, 0 } }, /* 12d */ + { .mk = {0xe0, 0x2e, 0 }, .brk = { 0xe0, 0xae, 0 } }, /* 12e */ + { .mk = {0xe0, 0x2f, 0 }, .brk = { 0xe0, 0xaf, 0 } }, /* 12f */ + { .mk = {0xe0, 0x30, 0 }, .brk = { 0xe0, 0xb0, 0 } }, /* 130 */ + { .mk = {0xe0, 0x31, 0 }, .brk = { 0xe0, 0xb1, 0 } }, /* 131 */ + { .mk = {0xe0, 0x32, 0 }, .brk = { 0xe0, 0xb2, 0 } }, /* 132 */ + { .mk = { 0 }, .brk = { 0 } }, /* 133 */ + { .mk = {0xe0, 0x34, 0 }, .brk = { 0xe0, 0xb4, 0 } }, /* 134 */ + { .mk = {0xe0, 0x35, 0 }, .brk = { 0xe0, 0xb5, 0 } }, /* 135 */ + { .mk = { 0 }, .brk = { 0 } }, /* 136 */ + { .mk = {0xe0, 0x37, 0 }, .brk = { 0xe0, 0xb7, 0 } }, /* 137 */ + { .mk = { 0x38, 0 }, .brk = { 0xb8, 0 } }, /* 138* 0x31 R-Alt */ + { .mk = { 0 }, .brk = { 0 } }, /* 139 */ + { .mk = {0xe0, 0x3a, 0 }, .brk = { 0xe0, 0xba, 0 } }, /* 13a */ + { .mk = {0xe0, 0x3b, 0 }, .brk = { 0xe0, 0xbb, 0 } }, /* 13b */ + { .mk = {0xe0, 0x3c, 0 }, .brk = { 0xe0, 0xbc, 0 } }, /* 13c */ + { .mk = {0xe0, 0x3d, 0 }, .brk = { 0xe0, 0xbd, 0 } }, /* 13d */ + { .mk = {0xe0, 0x3e, 0 }, .brk = { 0xe0, 0xbe, 0 } }, /* 13e */ + { .mk = {0xe0, 0x3f, 0 }, .brk = { 0xe0, 0xbf, 0 } }, /* 13f */ + { .mk = {0xe0, 0x40, 0 }, .brk = { 0xe0, 0xc0, 0 } }, /* 140 */ + { .mk = {0xe0, 0x41, 0 }, .brk = { 0xe0, 0xc1, 0 } }, /* 141 */ + { .mk = {0xe0, 0x42, 0 }, .brk = { 0xe0, 0xc2, 0 } }, /* 142 */ + { .mk = {0xe0, 0x43, 0 }, .brk = { 0xe0, 0xc3, 0 } }, /* 143 */ + { .mk = {0xe0, 0x44, 0 }, .brk = { 0xe0, 0xc4, 0 } }, /* 144 */ + { .mk = { 0 }, .brk = { 0 } }, /* 145 */ + { .mk = {0xe0, 0x46, 0 }, .brk = { 0xe0, 0xc6, 0 } }, /* 146 */ + { .mk = {0xe0, 0x47, 0 }, .brk = { 0xe0, 0xc7, 0 } }, /* 147 */ + { .mk = {0xe0, 0x48, 0 }, .brk = { 0xe0, 0xc8, 0 } }, /* 148 */ + { .mk = {0xe0, 0x49, 0 }, .brk = { 0xe0, 0xc9, 0 } }, /* 149 */ + { .mk = { 0 }, .brk = { 0 } }, /* 14a */ + { .mk = {0xe0, 0x4b, 0 }, .brk = { 0xe0, 0xcb, 0 } }, /* 14b */ + { .mk = {0xe0, 0x4c, 0 }, .brk = { 0xe0, 0xcc, 0 } }, /* 14c */ + { .mk = {0xe0, 0x4d, 0 }, .brk = { 0xe0, 0xcd, 0 } }, /* 14d */ + { .mk = {0xe0, 0x4e, 0 }, .brk = { 0xe0, 0xce, 0 } }, /* 14e */ + { .mk = {0xe0, 0x4f, 0 }, .brk = { 0xe0, 0xcf, 0 } }, /* 14f */ + { .mk = {0xe0, 0x50, 0 }, .brk = { 0xe0, 0xd0, 0 } }, /* 150 */ + { .mk = {0xe0, 0x51, 0 }, .brk = { 0xe0, 0xd1, 0 } }, /* 151 */ + { .mk = {0xe0, 0x52, 0 }, .brk = { 0xe0, 0xd2, 0 } }, /* 152 */ + { .mk = {0xe0, 0x53, 0 }, .brk = { 0xe0, 0xd3, 0 } }, /* 153 */ + { .mk = { 0 }, .brk = { 0 } }, /* 154 */ + { .mk = {0xe0, 0x55, 0 }, .brk = { 0xe0, 0xd5, 0 } }, /* 155 */ + { .mk = { 0 }, .brk = { 0 } }, /* 156 */ + { .mk = {0xe0, 0x57, 0 }, .brk = { 0xe0, 0xd7, 0 } }, /* 157 */ + { .mk = {0xe0, 0x58, 0 }, .brk = { 0xe0, 0xd8, 0 } }, /* 158 */ + { .mk = {0xe0, 0x59, 0 }, .brk = { 0xe0, 0xd9, 0 } }, /* 159 */ + { .mk = {0xe0, 0x5a, 0 }, .brk = { 0xe0, 0xaa, 0 } }, /* 15a */ + { .mk = { 0x7b, 0 }, .brk = { 0xfb, 0 } }, /* 15b 0x33 LGUI->Muhenkan (in emulator only) */ + { .mk = { 0x79, 0 }, .brk = { 0xf9, 0 } }, /* 15c 0x35 RGUI->Henkan (in emulator only) */ + { .mk = {0xe0, 0x38, 0 }, .brk = { 0xe0, 0xb8, 0 } }, /* 15d 0x36 APPLICATION->Kana (in emulator only) */ + { .mk = {0xe0, 0x5e, 0 }, .brk = { 0xe0, 0xee, 0 } }, /* 15e */ + { .mk = {0xe0, 0x5f, 0 }, .brk = { 0xe0, 0xdf, 0 } }, /* 15f */ + { .mk = { 0 }, .brk = { 0 } }, /* 160 */ + { .mk = {0xe0, 0x61, 0 }, .brk = { 0xe0, 0xe1, 0 } }, /* 161 */ + { .mk = {0xe0, 0x62, 0 }, .brk = { 0xe0, 0xe2, 0 } }, /* 162 */ + { .mk = {0xe0, 0x63, 0 }, .brk = { 0xe0, 0xe3, 0 } }, /* 163 */ + { .mk = {0xe0, 0x64, 0 }, .brk = { 0xe0, 0xe4, 0 } }, /* 164 */ + { .mk = {0xe0, 0x65, 0 }, .brk = { 0xe0, 0xe5, 0 } }, /* 165 */ + { .mk = {0xe0, 0x66, 0 }, .brk = { 0xe0, 0xe6, 0 } }, /* 166 */ + { .mk = {0xe0, 0x67, 0 }, .brk = { 0xe0, 0xe7, 0 } }, /* 167 */ + { .mk = {0xe0, 0x68, 0 }, .brk = { 0xe0, 0xe8, 0 } }, /* 168 */ + { .mk = {0xe0, 0x69, 0 }, .brk = { 0xe0, 0xe9, 0 } }, /* 169 */ + { .mk = {0xe0, 0x6a, 0 }, .brk = { 0xe0, 0xea, 0 } }, /* 16a */ + { .mk = {0xe0, 0x6b, 0 }, .brk = { 0xe0, 0xeb, 0 } }, /* 16b */ + { .mk = {0xe0, 0x6c, 0 }, .brk = { 0xe0, 0xec, 0 } }, /* 16c */ + { .mk = {0xe0, 0x6d, 0 }, .brk = { 0xe0, 0xed, 0 } }, /* 16d */ + { .mk = {0xe0, 0x6e, 0 }, .brk = { 0xe0, 0xee, 0 } }, /* 16e */ + { .mk = { 0 }, .brk = { 0 } }, /* 16f */ + { .mk = {0xe0, 0x70, 0 }, .brk = { 0xe0, 0xf0, 0 } }, /* 170 */ + { .mk = {0xe0, 0x71, 0 }, .brk = { 0xe0, 0xf1, 0 } }, /* 171 */ + { .mk = {0xe0, 0x72, 0 }, .brk = { 0xe0, 0xf2, 0 } }, /* 172 */ + { .mk = {0xe0, 0x73, 0 }, .brk = { 0xe0, 0xf3, 0 } }, /* 173 */ + { .mk = {0xe0, 0x74, 0 }, .brk = { 0xe0, 0xf4, 0 } }, /* 174 */ + { .mk = {0xe0, 0x75, 0 }, .brk = { 0xe0, 0xf5, 0 } }, /* 175 */ + { .mk = { 0 }, .brk = { 0 } }, /* 176 */ + { .mk = {0xe0, 0x77, 0 }, .brk = { 0xe0, 0xf7, 0 } }, /* 177 */ + { .mk = {0xe0, 0x78, 0 }, .brk = { 0xe0, 0xf8, 0 } }, /* 178 */ + { .mk = {0xe0, 0x79, 0 }, .brk = { 0xe0, 0xf9, 0 } }, /* 179 */ + { .mk = {0xe0, 0x7a, 0 }, .brk = { 0xe0, 0xfa, 0 } }, /* 17a */ + { .mk = {0xe0, 0x7b, 0 }, .brk = { 0xe0, 0xfb, 0 } }, /* 17b */ + { .mk = {0xe0, 0x7c, 0 }, .brk = { 0xe0, 0xfc, 0 } }, /* 17c */ + { .mk = {0xe0, 0x7d, 0 }, .brk = { 0xe0, 0xfd, 0 } }, /* 17d */ + { .mk = {0xe0, 0x7e, 0 }, .brk = { 0xe0, 0xfe, 0 } }, /* 17e */ + { .mk = {0xe0, 0x7f, 0 }, .brk = { 0xe0, 0xff, 0 } }, /* 17f */ + { .mk = { 0 }, .brk = { 0 } }, /* 180 */ + { .mk = { 0 }, .brk = { 0 } }, /* 181 */ + { .mk = { 0 }, .brk = { 0 } }, /* 182 */ + { .mk = { 0 }, .brk = { 0 } }, /* 183 */ + { .mk = { 0 }, .brk = { 0 } }, /* 184 */ + { .mk = { 0 }, .brk = { 0 } }, /* 185 */ + { .mk = { 0 }, .brk = { 0 } }, /* 186 */ + { .mk = { 0 }, .brk = { 0 } }, /* 187 */ + { .mk = { 0 }, .brk = { 0 } }, /* 188 */ + { .mk = { 0 }, .brk = { 0 } }, /* 189 */ + { .mk = { 0 }, .brk = { 0 } }, /* 18a */ + { .mk = { 0 }, .brk = { 0 } }, /* 18b */ + { .mk = { 0 }, .brk = { 0 } }, /* 18c */ + { .mk = { 0 }, .brk = { 0 } }, /* 18d */ + { .mk = { 0 }, .brk = { 0 } }, /* 18e */ + { .mk = { 0 }, .brk = { 0 } }, /* 18f */ + { .mk = { 0 }, .brk = { 0 } }, /* 190 */ + { .mk = { 0 }, .brk = { 0 } }, /* 191 */ + { .mk = { 0 }, .brk = { 0 } }, /* 192 */ + { .mk = { 0 }, .brk = { 0 } }, /* 193 */ + { .mk = { 0 }, .brk = { 0 } }, /* 194 */ + { .mk = { 0 }, .brk = { 0 } }, /* 195 */ + { .mk = { 0 }, .brk = { 0 } }, /* 196 */ + { .mk = { 0 }, .brk = { 0 } }, /* 197 */ + { .mk = { 0 }, .brk = { 0 } }, /* 198 */ + { .mk = { 0 }, .brk = { 0 } }, /* 199 */ + { .mk = { 0 }, .brk = { 0 } }, /* 19a */ + { .mk = { 0 }, .brk = { 0 } }, /* 19b */ + { .mk = { 0 }, .brk = { 0 } }, /* 19c */ + { .mk = { 0 }, .brk = { 0 } }, /* 19d */ + { .mk = { 0 }, .brk = { 0 } }, /* 19e */ + { .mk = { 0 }, .brk = { 0 } }, /* 19f */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1aa */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ab */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ac */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ad */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ae */ + { .mk = { 0 }, .brk = { 0 } }, /* 1af */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ba */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1be */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bf */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ca */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cv */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ce */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cf */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1da */ + { .mk = { 0 }, .brk = { 0 } }, /* 1db */ + { .mk = { 0 }, .brk = { 0 } }, /* 1dc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1dd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1de */ + { .mk = { 0 }, .brk = { 0 } }, /* 1df */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e0 */ + { .mk = {0xe0, 0xe1, 0 }, .brk = { 0 } }, /* 1e1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ea */ + { .mk = { 0 }, .brk = { 0 } }, /* 1eb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ec */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ed */ + { .mk = {0xe0, 0xee, 0 }, .brk = { 0 } }, /* 1ee */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ef */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f0 */ + { .mk = {0xe0, 0xf1, 0 }, .brk = { 0 } }, /* 1f1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fa */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fd */ + { .mk = {0xe0, 0xfe, 0 }, .brk = { 0 } }, /* 1fe */ + { .mk = {0xe0, 0xff, 0 }, .brk = { 0 } } /* 1ff */ + // clang-format on + }; +/* Scancode set 82h : Set 02 with language specific keys support used by DOS/V */ +static const scancode scancode_set82[512] = { + // clang-format off + { .mk = { 0 }, .brk = { 0 } }, /* 000 */ + { .mk = { 0x76, 0 }, .brk = { 0xF0, 0x76, 0 } }, /* 001 */ + { .mk = { 0x16, 0 }, .brk = { 0xF0, 0x16, 0 } }, /* 002 */ + { .mk = { 0x1E, 0 }, .brk = { 0xF0, 0x1E, 0 } }, /* 003 */ + { .mk = { 0x26, 0 }, .brk = { 0xF0, 0x26, 0 } }, /* 004 */ + { .mk = { 0x25, 0 }, .brk = { 0xF0, 0x25, 0 } }, /* 005 */ + { .mk = { 0x2E, 0 }, .brk = { 0xF0, 0x2E, 0 } }, /* 006 */ + { .mk = { 0x36, 0 }, .brk = { 0xF0, 0x36, 0 } }, /* 007 */ + { .mk = { 0x3D, 0 }, .brk = { 0xF0, 0x3D, 0 } }, /* 008 */ + { .mk = { 0x3E, 0 }, .brk = { 0xF0, 0x3E, 0 } }, /* 009 */ + { .mk = { 0x46, 0 }, .brk = { 0xF0, 0x46, 0 } }, /* 00a */ + { .mk = { 0x45, 0 }, .brk = { 0xF0, 0x45, 0 } }, /* 00b */ + { .mk = { 0x4E, 0 }, .brk = { 0xF0, 0x4E, 0 } }, /* 00c */ + { .mk = { 0x55, 0 }, .brk = { 0xF0, 0x55, 0 } }, /* 00d */ + { .mk = { 0x66, 0 }, .brk = { 0xF0, 0x66, 0 } }, /* 00e */ + { .mk = { 0x0D, 0 }, .brk = { 0xF0, 0x0D, 0 } }, /* 00f */ + { .mk = { 0x15, 0 }, .brk = { 0xF0, 0x15, 0 } }, /* 010 */ + { .mk = { 0x1D, 0 }, .brk = { 0xF0, 0x1D, 0 } }, /* 011 */ + { .mk = { 0x24, 0 }, .brk = { 0xF0, 0x24, 0 } }, /* 012 */ + { .mk = { 0x2D, 0 }, .brk = { 0xF0, 0x2D, 0 } }, /* 013 */ + { .mk = { 0x2C, 0 }, .brk = { 0xF0, 0x2C, 0 } }, /* 014 */ + { .mk = { 0x35, 0 }, .brk = { 0xF0, 0x35, 0 } }, /* 015 */ + { .mk = { 0x3C, 0 }, .brk = { 0xF0, 0x3C, 0 } }, /* 016 */ + { .mk = { 0x43, 0 }, .brk = { 0xF0, 0x43, 0 } }, /* 017 */ + { .mk = { 0x44, 0 }, .brk = { 0xF0, 0x44, 0 } }, /* 018 */ + { .mk = { 0x4D, 0 }, .brk = { 0xF0, 0x4D, 0 } }, /* 019 */ + { .mk = { 0x54, 0 }, .brk = { 0xF0, 0x54, 0 } }, /* 01a */ + { .mk = { 0x5B, 0 }, .brk = { 0xF0, 0x5B, 0 } }, /* 01b */ + { .mk = { 0x5A, 0 }, .brk = { 0xF0, 0x5A, 0 } }, /* 01c */ + { .mk = { 0x14, 0 }, .brk = { 0xF0, 0x14, 0 } }, /* 01d */ + { .mk = { 0x1C, 0 }, .brk = { 0xF0, 0x1C, 0 } }, /* 01e */ + { .mk = { 0x1B, 0 }, .brk = { 0xF0, 0x1B, 0 } }, /* 01f */ + { .mk = { 0x23, 0 }, .brk = { 0xF0, 0x23, 0 } }, /* 020 */ + { .mk = { 0x2B, 0 }, .brk = { 0xF0, 0x2B, 0 } }, /* 021 */ + { .mk = { 0x34, 0 }, .brk = { 0xF0, 0x34, 0 } }, /* 022 */ + { .mk = { 0x33, 0 }, .brk = { 0xF0, 0x33, 0 } }, /* 023 */ + { .mk = { 0x3B, 0 }, .brk = { 0xF0, 0x3B, 0 } }, /* 024 */ + { .mk = { 0x42, 0 }, .brk = { 0xF0, 0x42, 0 } }, /* 025 */ + { .mk = { 0x4B, 0 }, .brk = { 0xF0, 0x4B, 0 } }, /* 026 */ + { .mk = { 0x4C, 0 }, .brk = { 0xF0, 0x4C, 0 } }, /* 027 */ + { .mk = { 0x52, 0 }, .brk = { 0xF0, 0x52, 0 } }, /* 028* */ + { .mk = { 0x62, 0 }, .brk = { 0xf0, 0x62, 0 } }, /* 029 0x45 Hankaku, Zenkaku */ + { .mk = { 0x12, 0 }, .brk = { 0xF0, 0x12, 0 } }, /* 02a */ + { .mk = { 0x5b, 0 }, .brk = { 0xf0, 0x5b, 0 } }, /* 02b 0x17 Mu */ + { .mk = { 0x1A, 0 }, .brk = { 0xF0, 0x1A, 0 } }, /* 02c */ + { .mk = { 0x22, 0 }, .brk = { 0xF0, 0x22, 0 } }, /* 02d */ + { .mk = { 0x21, 0 }, .brk = { 0xF0, 0x21, 0 } }, /* 02e */ + { .mk = { 0x2A, 0 }, .brk = { 0xF0, 0x2A, 0 } }, /* 02f */ + { .mk = { 0x32, 0 }, .brk = { 0xF0, 0x32, 0 } }, /* 030 */ + { .mk = { 0x31, 0 }, .brk = { 0xF0, 0x31, 0 } }, /* 031 */ + { .mk = { 0x3A, 0 }, .brk = { 0xF0, 0x3A, 0 } }, /* 032 */ + { .mk = { 0x41, 0 }, .brk = { 0xF0, 0x41, 0 } }, /* 033 */ + { .mk = { 0x49, 0 }, .brk = { 0xF0, 0x49, 0 } }, /* 034 */ + { .mk = { 0x4A, 0 }, .brk = { 0xF0, 0x4A, 0 } }, /* 035 */ + { .mk = { 0x59, 0 }, .brk = { 0xF0, 0x59, 0 } }, /* 036 */ + { .mk = { 0x7C, 0 }, .brk = { 0xF0, 0x7C, 0 } }, /* 037 */ + { .mk = { 0x13, 0 }, .brk = { 0xF0, 0x13, 0 } }, /* 038 0x3A LALT = Kanji */ + { .mk = { 0x29, 0 }, .brk = { 0xF0, 0x29, 0 } }, /* 039 */ + { .mk = { 0x58, 0 }, .brk = { 0xF0, 0x58, 0 } }, /* 03a */ + { .mk = { 0x05, 0 }, .brk = { 0xF0, 0x05, 0 } }, /* 03b */ + { .mk = { 0x06, 0 }, .brk = { 0xF0, 0x06, 0 } }, /* 03c */ + { .mk = { 0x04, 0 }, .brk = { 0xF0, 0x04, 0 } }, /* 03d */ + { .mk = { 0x0C, 0 }, .brk = { 0xF0, 0x0C, 0 } }, /* 03e */ + { .mk = { 0x03, 0 }, .brk = { 0xF0, 0x03, 0 } }, /* 03f */ + { .mk = { 0x0B, 0 }, .brk = { 0xF0, 0x0B, 0 } }, /* 040 */ + { .mk = { 0x83, 0 }, .brk = { 0xF0, 0x83, 0 } }, /* 041 */ + { .mk = { 0x0A, 0 }, .brk = { 0xF0, 0x0A, 0 } }, /* 042 */ + { .mk = { 0x01, 0 }, .brk = { 0xF0, 0x01, 0 } }, /* 043 */ + { .mk = { 0x09, 0 }, .brk = { 0xF0, 0x09, 0 } }, /* 044 */ + { .mk = { 0x77, 0 }, .brk = { 0xF0, 0x77, 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */ + { .mk = { 0x7E, 0 }, .brk = { 0xF0, 0x7E, 0 } }, /* 046 0x75 SCROLLLOCK */ + { .mk = { 0x6C, 0 }, .brk = { 0xF0, 0x6C, 0 } }, /* 047 */ + { .mk = { 0x75, 0 }, .brk = { 0xF0, 0x75, 0 } }, /* 048 */ + { .mk = { 0x7D, 0 }, .brk = { 0xF0, 0x7D, 0 } }, /* 049 */ + { .mk = { 0x7B, 0 }, .brk = { 0xF0, 0x7B, 0 } }, /* 04a */ + { .mk = { 0x6B, 0 }, .brk = { 0xF0, 0x6B, 0 } }, /* 04b */ + { .mk = { 0x73, 0 }, .brk = { 0xF0, 0x73, 0 } }, /* 04c */ + { .mk = { 0x74, 0 }, .brk = { 0xF0, 0x74, 0 } }, /* 04d */ + { .mk = { 0x79, 0 }, .brk = { 0xF0, 0x79, 0 } }, /* 04e */ + { .mk = { 0x69, 0 }, .brk = { 0xF0, 0x69, 0 } }, /* 04f */ + { .mk = { 0x72, 0 }, .brk = { 0xF0, 0x72, 0 } }, /* 050 */ + { .mk = { 0x7A, 0 }, .brk = { 0xF0, 0x7A, 0 } }, /* 051 */ + { .mk = { 0x70, 0 }, .brk = { 0xF0, 0x70, 0 } }, /* 052 */ + { .mk = { 0x71, 0 }, .brk = { 0xF0, 0x71, 0 } }, /* 053 */ + { .mk = { 0x84, 0 }, .brk = { 0xF0, 0x84, 0 } }, /* 054 */ + { .mk = { 0x60, 0 }, .brk = { 0xF0, 0x60, 0 } }, /* 055 */ + { .mk = { 0x61, 0 }, .brk = { 0xF0, 0x61, 0 } }, /* 056 */ + { .mk = { 0x78, 0 }, .brk = { 0xF0, 0x78, 0 } }, /* 057 */ + { .mk = { 0x07, 0 }, .brk = { 0xF0, 0x07, 0 } }, /* 058 */ + { .mk = { 0x0F, 0 }, .brk = { 0xF0, 0x0F, 0 } }, /* 059 */ + { .mk = { 0x17, 0 }, .brk = { 0xF0, 0x17, 0 } }, /* 05a */ + { .mk = { 0x1F, 0 }, .brk = { 0xF0, 0x1F, 0 } }, /* 05b */ + { .mk = { 0x27, 0 }, .brk = { 0xF0, 0x27, 0 } }, /* 05c */ + { .mk = { 0x2F, 0 }, .brk = { 0xF0, 0x2F, 0 } }, /* 05d */ + { .mk = { 0x37, 0 }, .brk = { 0xF0, 0x37, 0 } }, /* 05e */ + { .mk = { 0x3F, 0 }, .brk = { 0xF0, 0x3F, 0 } }, /* 05f */ + { .mk = { 0x47, 0 }, .brk = { 0xF0, 0x47, 0 } }, /* 060 */ + { .mk = { 0x4F, 0 }, .brk = { 0xF0, 0x4F, 0 } }, /* 061 */ + { .mk = { 0x56, 0 }, .brk = { 0xF0, 0x56, 0 } }, /* 062 */ + { .mk = { 0x5E, 0 }, .brk = { 0xF0, 0x5E, 0 } }, /* 063 */ + { .mk = { 0x08, 0 }, .brk = { 0xF0, 0x08, 0 } }, /* 064 */ + { .mk = { 0x10, 0 }, .brk = { 0xF0, 0x10, 0 } }, /* 065 */ + { .mk = { 0x18, 0 }, .brk = { 0xF0, 0x18, 0 } }, /* 066 */ + { .mk = { 0x20, 0 }, .brk = { 0xF0, 0x20, 0 } }, /* 067 */ + { .mk = { 0x28, 0 }, .brk = { 0xF0, 0x28, 0 } }, /* 068 */ + { .mk = { 0x30, 0 }, .brk = { 0xF0, 0x30, 0 } }, /* 069 */ + { .mk = { 0x38, 0 }, .brk = { 0xF0, 0x38, 0 } }, /* 06a */ + { .mk = { 0x40, 0 }, .brk = { 0xF0, 0x40, 0 } }, /* 06b */ + { .mk = { 0x48, 0 }, .brk = { 0xF0, 0x48, 0 } }, /* 06c */ + { .mk = { 0x50, 0 }, .brk = { 0xF0, 0x50, 0 } }, /* 06d */ + { .mk = { 0x57, 0 }, .brk = { 0xF0, 0x57, 0 } }, /* 06e */ + { .mk = { 0x6F, 0 }, .brk = { 0xF0, 0x6F, 0 } }, /* 06f */ + { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0xf0, 0x11, 0 } }, /* 070 0x36 Kana */ + { .mk = { 0x19, 0 }, .brk = { 0xF0, 0x19, 0 } }, /* 071 */ + { .mk = { 0x39, 0 }, .brk = { 0xF0, 0x39, 0 } }, /* 072 */ + { .mk = { 0x51, 0 }, .brk = { 0xF0, 0x51, 0 } }, /* 073 0x0b Ro, Underline */ + { .mk = { 0x53, 0 }, .brk = { 0xF0, 0x53, 0 } }, /* 074 */ + { .mk = { 0x5C, 0 }, .brk = { 0xF0, 0x5C, 0 } }, /* 075 */ + { .mk = { 0x5F, 0 }, .brk = { 0xF0, 0x5F, 0 } }, /* 076 */ + { .mk = { 0x62, 0 }, .brk = { 0xF0, 0x62, 0 } }, /* 077 */ + { .mk = { 0x63, 0 }, .brk = { 0xF0, 0x63, 0 } }, /* 078 */ + { .mk = { 0x64, 0 }, .brk = { 0xF0, 0x64, 0 } }, /* 079 0x35 Henkan */ + { .mk = { 0x65, 0 }, .brk = { 0xF0, 0x65, 0 } }, /* 07a */ + { .mk = { 0x67, 0 }, .brk = { 0xF0, 0x67, 0 } }, /* 07b 0x33 Muhenkan */ + { .mk = { 0x68, 0 }, .brk = { 0xF0, 0x68, 0 } }, /* 07c */ + { .mk = { 0x5d, 0 }, .brk = { 0xf0, 0x5d, 0 } }, /* 07d 0x30 Yen, Vertical line */ + { .mk = { 0x6D, 0 }, .brk = { 0xF0, 0x6D, 0 } }, /* 07e */ + { .mk = { 0x6E, 0 }, .brk = { 0xF0, 0x6E, 0 } }, /* 07f */ + { .mk = { 0x80, 0 }, .brk = { 0xf0, 0x80, 0 } }, /* 080 */ + { .mk = { 0x81, 0 }, .brk = { 0xf0, 0x81, 0 } }, /* 081 */ + { .mk = { 0x82, 0 }, .brk = { 0xf0, 0x82, 0 } }, /* 082 */ + { .mk = { 0 }, .brk = { 0 } }, /* 083 */ + { .mk = { 0 }, .brk = { 0 } }, /* 084 */ + { .mk = { 0x85, 0 }, .brk = { 0xf0, 0x54, 0 } }, /* 085 */ + { .mk = { 0x86, 0 }, .brk = { 0xf0, 0x86, 0 } }, /* 086 */ + { .mk = { 0x87, 0 }, .brk = { 0xf0, 0x87, 0 } }, /* 087 */ + { .mk = { 0x88, 0 }, .brk = { 0xf0, 0x88, 0 } }, /* 088 */ + { .mk = { 0x89, 0 }, .brk = { 0xf0, 0x89, 0 } }, /* 089 */ + { .mk = { 0x8a, 0 }, .brk = { 0xf0, 0x8a, 0 } }, /* 08a */ + { .mk = { 0x8b, 0 }, .brk = { 0xf0, 0x8b, 0 } }, /* 08b */ + { .mk = { 0x8c, 0 }, .brk = { 0xf0, 0x8c, 0 } }, /* 08c */ + { .mk = { 0x8d, 0 }, .brk = { 0xf0, 0x8d, 0 } }, /* 08d */ + { .mk = { 0x8e, 0 }, .brk = { 0xf0, 0x8e, 0 } }, /* 08e */ + { .mk = { 0x8f, 0 }, .brk = { 0xf0, 0x8f, 0 } }, /* 08f */ + { .mk = { 0x90, 0 }, .brk = { 0xf0, 0x90, 0 } }, /* 090 */ + { .mk = { 0x91, 0 }, .brk = { 0xf0, 0x91, 0 } }, /* 091 */ + { .mk = { 0x92, 0 }, .brk = { 0xf0, 0x92, 0 } }, /* 092 */ + { .mk = { 0x93, 0 }, .brk = { 0xf0, 0x93, 0 } }, /* 093 */ + { .mk = { 0x94, 0 }, .brk = { 0xf0, 0x94, 0 } }, /* 094 */ + { .mk = { 0x95, 0 }, .brk = { 0xf0, 0x95, 0 } }, /* 095 */ + { .mk = { 0x96, 0 }, .brk = { 0xf0, 0x96, 0 } }, /* 096 */ + { .mk = { 0x97, 0 }, .brk = { 0xf0, 0x97, 0 } }, /* 097 */ + { .mk = { 0x98, 0 }, .brk = { 0xf0, 0x98, 0 } }, /* 098 */ + { .mk = { 0x99, 0 }, .brk = { 0xf0, 0x99, 0 } }, /* 099 */ + { .mk = { 0x9a, 0 }, .brk = { 0xf0, 0x9a, 0 } }, /* 09a */ + { .mk = { 0x9b, 0 }, .brk = { 0xf0, 0x9b, 0 } }, /* 09b */ + { .mk = { 0x9c, 0 }, .brk = { 0xf0, 0x9c, 0 } }, /* 09c */ + { .mk = { 0x9d, 0 }, .brk = { 0xf0, 0x9d, 0 } }, /* 09d */ + { .mk = { 0x9e, 0 }, .brk = { 0xf0, 0x9e, 0 } }, /* 09e */ + { .mk = { 0x9f, 0 }, .brk = { 0xf0, 0x9f, 0 } }, /* 09f */ + { .mk = { 0xa0, 0 }, .brk = { 0xf0, 0xa0, 0 } }, /* 0a0 */ + { .mk = { 0xa1, 0 }, .brk = { 0xf0, 0xa1, 0 } }, /* 0a1 */ + { .mk = { 0xa2, 0 }, .brk = { 0xf0, 0xa2, 0 } }, /* 0a2 */ + { .mk = { 0xa3, 0 }, .brk = { 0xf0, 0xa3, 0 } }, /* 0a3 */ + { .mk = { 0xa4, 0 }, .brk = { 0xf0, 0xa4, 0 } }, /* 0a4 */ + { .mk = { 0xa5, 0 }, .brk = { 0xf0, 0xa5, 0 } }, /* 0a5 */ + { .mk = { 0xa6, 0 }, .brk = { 0xf0, 0xa6, 0 } }, /* 0a6 */ + { .mk = { 0xa7, 0 }, .brk = { 0xf0, 0xa7, 0 } }, /* 0a7 */ + { .mk = { 0xa8, 0 }, .brk = { 0xf0, 0xa8, 0 } }, /* 0a8 */ + { .mk = { 0xa9, 0 }, .brk = { 0xf0, 0xa9, 0 } }, /* 0a9 */ + { .mk = { 0xaa, 0 }, .brk = { 0xf0, 0xaa, 0 } }, /* 0aa */ + { .mk = { 0xab, 0 }, .brk = { 0xf0, 0xab, 0 } }, /* 0ab */ + { .mk = { 0xac, 0 }, .brk = { 0xf0, 0xac, 0 } }, /* 0ac */ + { .mk = { 0xad, 0 }, .brk = { 0xf0, 0xad, 0 } }, /* 0ad */ + { .mk = { 0xae, 0 }, .brk = { 0xf0, 0xae, 0 } }, /* 0ae */ + { .mk = { 0xaf, 0 }, .brk = { 0xf0, 0xaf, 0 } }, /* 0af */ + { .mk = { 0xb0, 0 }, .brk = { 0xf0, 0xb0, 0 } }, /* 0b0 */ + { .mk = { 0xb1, 0 }, .brk = { 0xf0, 0xb1, 0 } }, /* 0b1 */ + { .mk = { 0xb2, 0 }, .brk = { 0xf0, 0xb2, 0 } }, /* 0b2 */ + { .mk = { 0xb3, 0 }, .brk = { 0xf0, 0xb3, 0 } }, /* 0b3 */ + { .mk = { 0xb4, 0 }, .brk = { 0xf0, 0xb4, 0 } }, /* 0b4 */ + { .mk = { 0xb5, 0 }, .brk = { 0xf0, 0xb5, 0 } }, /* 0b5 */ + { .mk = { 0xb6, 0 }, .brk = { 0xf0, 0xb6, 0 } }, /* 0b6 */ + { .mk = { 0xb7, 0 }, .brk = { 0xf0, 0xb7, 0 } }, /* 0b7 */ + { .mk = { 0xb8, 0 }, .brk = { 0xf0, 0xb8, 0 } }, /* 0b8 */ + { .mk = { 0xb9, 0 }, .brk = { 0xf0, 0xb9, 0 } }, /* 0b9 */ + { .mk = { 0xba, 0 }, .brk = { 0xf0, 0xba, 0 } }, /* 0ba */ + { .mk = { 0xbb, 0 }, .brk = { 0xf0, 0xbb, 0 } }, /* 0bb */ + { .mk = { 0xbc, 0 }, .brk = { 0xf0, 0xbc, 0 } }, /* 0bc */ + { .mk = { 0xbd, 0 }, .brk = { 0xf0, 0xbd, 0 } }, /* 0bd */ + { .mk = { 0xbe, 0 }, .brk = { 0xf0, 0xbe, 0 } }, /* 0be */ + { .mk = { 0xbf, 0 }, .brk = { 0xf0, 0xbf, 0 } }, /* 0bf */ + { .mk = { 0xc0, 0 }, .brk = { 0xf0, 0xc0, 0 } }, /* 0c0 */ + { .mk = { 0xc1, 0 }, .brk = { 0xf0, 0xc1, 0 } }, /* 0c1 */ + { .mk = { 0xc2, 0 }, .brk = { 0xf0, 0xc2, 0 } }, /* 0c2 */ + { .mk = { 0xc3, 0 }, .brk = { 0xf0, 0xc3, 0 } }, /* 0c3 */ + { .mk = { 0xc4, 0 }, .brk = { 0xf0, 0xc4, 0 } }, /* 0c4 */ + { .mk = { 0xc5, 0 }, .brk = { 0xf0, 0xc5, 0 } }, /* 0c5 */ + { .mk = { 0xc6, 0 }, .brk = { 0xf0, 0xc6, 0 } }, /* 0c6 */ + { .mk = { 0xc7, 0 }, .brk = { 0xf0, 0xc7, 0 } }, /* 0c7 */ + { .mk = { 0xc8, 0 }, .brk = { 0xf0, 0xc8, 0 } }, /* 0c8 */ + { .mk = { 0xc9, 0 }, .brk = { 0xf0, 0xc9, 0 } }, /* 0c9 */ + { .mk = { 0xca, 0 }, .brk = { 0xf0, 0xca, 0 } }, /* 0ca */ + { .mk = { 0xcb, 0 }, .brk = { 0xf0, 0xcb, 0 } }, /* 0cb */ + { .mk = { 0xcc, 0 }, .brk = { 0xf0, 0xcc, 0 } }, /* 0cc */ + { .mk = { 0xcd, 0 }, .brk = { 0xf0, 0xcd, 0 } }, /* 0cd */ + { .mk = { 0xce, 0 }, .brk = { 0xf0, 0xce, 0 } }, /* 0ce */ + { .mk = { 0xcf, 0 }, .brk = { 0xf0, 0xcf, 0 } }, /* 0cf */ + { .mk = { 0xd0, 0 }, .brk = { 0xf0, 0xd0, 0 } }, /* 0d0 */ + { .mk = { 0xd1, 0 }, .brk = { 0xf0, 0xd0, 0 } }, /* 0d1 */ + { .mk = { 0xd2, 0 }, .brk = { 0xf0, 0xd2, 0 } }, /* 0d2 */ + { .mk = { 0xd3, 0 }, .brk = { 0xf0, 0xd3, 0 } }, /* 0d3 */ + { .mk = { 0xd4, 0 }, .brk = { 0xf0, 0xd4, 0 } }, /* 0d4 */ + { .mk = { 0xd5, 0 }, .brk = { 0xf0, 0xd5, 0 } }, /* 0d5 */ + { .mk = { 0xd6, 0 }, .brk = { 0xf0, 0xd6, 0 } }, /* 0d6 */ + { .mk = { 0xd7, 0 }, .brk = { 0xf0, 0xd7, 0 } }, /* 0d7 */ + { .mk = { 0xd8, 0 }, .brk = { 0xf0, 0xd8, 0 } }, /* 0d8 */ + { .mk = { 0xd9, 0 }, .brk = { 0xf0, 0xd9, 0 } }, /* 0d9 */ + { .mk = { 0xda, 0 }, .brk = { 0xf0, 0xda, 0 } }, /* 0da */ + { .mk = { 0xdb, 0 }, .brk = { 0xf0, 0xdb, 0 } }, /* 0db */ + { .mk = { 0xdc, 0 }, .brk = { 0xf0, 0xdc, 0 } }, /* 0dc */ + { .mk = { 0xdd, 0 }, .brk = { 0xf0, 0xdd, 0 } }, /* 0dd */ + { .mk = { 0xde, 0 }, .brk = { 0xf0, 0xde, 0 } }, /* 0de */ + { .mk = { 0xdf, 0 }, .brk = { 0xf0, 0xdf, 0 } }, /* 0df */ + { .mk = { 0xe0, 0 }, .brk = { 0xf0, 0xe0, 0 } }, /* 0e0 */ + { .mk = { 0xe1, 0 }, .brk = { 0xf0, 0xe1, 0 } }, /* 0e1 */ + { .mk = { 0xe2, 0 }, .brk = { 0xf0, 0xe2, 0 } }, /* 0e2 */ + { .mk = { 0xe3, 0 }, .brk = { 0xf0, 0xe3, 0 } }, /* 0e3 */ + { .mk = { 0xe4, 0 }, .brk = { 0xf0, 0xe4, 0 } }, /* 0e4 */ + { .mk = { 0xe5, 0 }, .brk = { 0xf0, 0xe5, 0 } }, /* 0e5 */ + { .mk = { 0xe6, 0 }, .brk = { 0xf0, 0xe6, 0 } }, /* 0e6 */ + { .mk = { 0xe7, 0 }, .brk = { 0xf0, 0xe7, 0 } }, /* 0e7 */ + { .mk = { 0xe8, 0 }, .brk = { 0xf0, 0xe8, 0 } }, /* 0e8 */ + { .mk = { 0xe9, 0 }, .brk = { 0xf0, 0xe9, 0 } }, /* 0e9 */ + { .mk = { 0xea, 0 }, .brk = { 0xf0, 0xea, 0 } }, /* 0ea */ + { .mk = { 0xeb, 0 }, .brk = { 0xf0, 0xeb, 0 } }, /* 0eb */ + { .mk = { 0xec, 0 }, .brk = { 0xf0, 0xec, 0 } }, /* 0ec */ + { .mk = { 0xed, 0 }, .brk = { 0xf0, 0xed, 0 } }, /* 0ed */ + { .mk = { 0xee, 0 }, .brk = { 0xf0, 0xee, 0 } }, /* 0ee */ + { .mk = { 0xef, 0 }, .brk = { 0xf0, 0xef, 0 } }, /* 0ef */ + { .mk = { 0 }, .brk = { 0 } }, /* 0f0 */ + { .mk = { 0xf1, 0 }, .brk = { 0xf0, 0xf1, 0 } }, /* 0f1 */ + { .mk = { 0xf2, 0 }, .brk = { 0xf0, 0xf2, 0 } }, /* 0f2 */ + { .mk = { 0xf3, 0 }, .brk = { 0xf0, 0xf3, 0 } }, /* 0f3 */ + { .mk = { 0xf4, 0 }, .brk = { 0xf0, 0xf4, 0 } }, /* 0f4 */ + { .mk = { 0xf5, 0 }, .brk = { 0xf0, 0xf5, 0 } }, /* 0f5 */ + { .mk = { 0xf6, 0 }, .brk = { 0xf0, 0xf6, 0 } }, /* 0f6 */ + { .mk = { 0xf7, 0 }, .brk = { 0xf0, 0xf7, 0 } }, /* 0f7 */ + { .mk = { 0xf8, 0 }, .brk = { 0xf0, 0xf8, 0 } }, /* 0f8 */ + { .mk = { 0xf9, 0 }, .brk = { 0xf0, 0xf9, 0 } }, /* 0f9 */ + { .mk = { 0xfa, 0 }, .brk = { 0xf0, 0xfa, 0 } }, /* 0fa */ + { .mk = { 0xfb, 0 }, .brk = { 0xf0, 0xfb, 0 } }, /* 0fb */ + { .mk = { 0xfc, 0 }, .brk = { 0xf0, 0xfc, 0 } }, /* 0fc */ + { .mk = { 0xfd, 0 }, .brk = { 0xf0, 0xfd, 0 } }, /* 0fd */ + { .mk = { 0xfe, 0 }, .brk = { 0xf0, 0xfe, 0 } }, /* 0fe */ + { .mk = { 0xff, 0 }, .brk = { 0xf0, 0xff, 0 } }, /* 0ff */ + { .mk = {0xe1, 0x14, 0 }, .brk = { 0xe1, 0xf0, 0x14, 0 } }, /* 100 */ + { .mk = {0xe0, 0x76, 0 }, .brk = { 0xe0, 0xF0, 0x76, 0 } }, /* 101 */ + { .mk = {0xe0, 0x16, 0 }, .brk = { 0xe0, 0xF0, 0x16, 0 } }, /* 102 */ + { .mk = {0xe0, 0x1E, 0 }, .brk = { 0xe0, 0xF0, 0x1E, 0 } }, /* 103 */ + { .mk = {0xe0, 0x26, 0 }, .brk = { 0xe0, 0xF0, 0x26, 0 } }, /* 104 */ + { .mk = {0xe0, 0x25, 0 }, .brk = { 0xe0, 0xF0, 0x25, 0 } }, /* 105 */ + { .mk = {0xe0, 0x2E, 0 }, .brk = { 0xe0, 0xF0, 0x2E, 0 } }, /* 106 */ + { .mk = {0xe0, 0x36, 0 }, .brk = { 0xe0, 0xF0, 0x36, 0 } }, /* 107 */ + { .mk = {0xe0, 0x3D, 0 }, .brk = { 0xe0, 0xF0, 0x3D, 0 } }, /* 108 */ + { .mk = {0xe0, 0x3E, 0 }, .brk = { 0xe0, 0xF0, 0x3E, 0 } }, /* 109 */ + { .mk = {0xe0, 0x46, 0 }, .brk = { 0xe0, 0xF0, 0x46, 0 } }, /* 10a */ + { .mk = {0xe0, 0x45, 0 }, .brk = { 0xe0, 0xF0, 0x45, 0 } }, /* 10b */ + { .mk = {0xe0, 0x4E, 0 }, .brk = { 0xe0, 0xF0, 0x4E, 0 } }, /* 10c */ + { .mk = { 0 }, .brk = { 0 } }, /* 10d */ + { .mk = {0xe0, 0x66, 0 }, .brk = { 0xe0, 0xF0, 0x66, 0 } }, /* 10e */ + { .mk = {0xe0, 0x0D, 0 }, .brk = { 0xe0, 0xF0, 0x0D, 0 } }, /* 10f */ + { .mk = {0xe0, 0x15, 0 }, .brk = { 0xe0, 0xF0, 0x15, 0 } }, /* 110 */ + { .mk = {0xe0, 0x1D, 0 }, .brk = { 0xe0, 0xF0, 0x1D, 0 } }, /* 112 */ + { .mk = {0xe0, 0x24, 0 }, .brk = { 0xe0, 0xF0, 0x24, 0 } }, /* 113 */ + { .mk = {0xe0, 0x2D, 0 }, .brk = { 0xe0, 0xF0, 0x2D, 0 } }, /* 113 */ + { .mk = {0xe0, 0x2C, 0 }, .brk = { 0xe0, 0xF0, 0x2C, 0 } }, /* 114 */ + { .mk = {0xe0, 0x35, 0 }, .brk = { 0xe0, 0xF0, 0x35, 0 } }, /* 115 */ + { .mk = {0xe0, 0x3C, 0 }, .brk = { 0xe0, 0xF0, 0x3C, 0 } }, /* 116 */ + { .mk = {0xe0, 0x43, 0 }, .brk = { 0xe0, 0xF0, 0x43, 0 } }, /* 117 */ + { .mk = {0xe0, 0x44, 0 }, .brk = { 0xe0, 0xF0, 0x44, 0 } }, /* 118 */ + { .mk = {0xe0, 0x4D, 0 }, .brk = { 0xe0, 0xF0, 0x4D, 0 } }, /* 119 */ + { .mk = {0xe0, 0x54, 0 }, .brk = { 0xe0, 0xF0, 0x54, 0 } }, /* 11a */ + { .mk = {0xe0, 0x5B, 0 }, .brk = { 0xe0, 0xF0, 0x5B, 0 } }, /* 11b */ + { .mk = {0xe0, 0x5A, 0 }, .brk = { 0xe0, 0xF0, 0x5A, 0 } }, /* 11c */ + { .mk = {0xe0, 0x14, 0 }, .brk = { 0xe0, 0xF0, 0x14, 0 } }, /* 11d */ + { .mk = {0xe0, 0x1C, 0 }, .brk = { 0xe0, 0xF0, 0x1C, 0 } }, /* 11e */ + { .mk = {0xe0, 0x1B, 0 }, .brk = { 0xe0, 0xF0, 0x1B, 0 } }, /* 11f */ + { .mk = {0xe0, 0x23, 0 }, .brk = { 0xe0, 0xF0, 0x23, 0 } }, /* 120 */ + { .mk = {0xe0, 0x2B, 0 }, .brk = { 0xe0, 0xF0, 0x2B, 0 } }, /* 121 */ + { .mk = {0xe0, 0x34, 0 }, .brk = { 0xe0, 0xF0, 0x34, 0 } }, /* 122 */ + { .mk = {0xe0, 0x33, 0 }, .brk = { 0xe0, 0xF0, 0x33, 0 } }, /* 123 */ + { .mk = {0xe0, 0x3B, 0 }, .brk = { 0xe0, 0xF0, 0x3B, 0 } }, /* 124 */ + { .mk = {0xe0, 0x42, 0 }, .brk = { 0xe0, 0xF0, 0x42, 0 } }, /* 125 */ + { .mk = {0xe0, 0x4B, 0 }, .brk = { 0xe0, 0xF0, 0x4B, 0 } }, /* 126 */ + { .mk = { 0 }, .brk = { 0 } }, /* 127 */ + { .mk = { 0 }, .brk = { 0 } }, /* 128 */ + { .mk = { 0 }, .brk = { 0 } }, /* 129 */ + { .mk = { 0 }, .brk = { 0 } }, /* 12a */ + { .mk = { 0 }, .brk = { 0 } }, /* 12b */ + { .mk = {0xe0, 0x1A, 0 }, .brk = { 0xe0, 0xF0, 0x1A, 0 } }, /* 12c */ + { .mk = {0xe0, 0x22, 0 }, .brk = { 0xe0, 0xF0, 0x22, 0 } }, /* 12d */ + { .mk = {0xe0, 0x21, 0 }, .brk = { 0xe0, 0xF0, 0x21, 0 } }, /* 12e */ + { .mk = {0xe0, 0x2A, 0 }, .brk = { 0xe0, 0xF0, 0x2A, 0 } }, /* 12f */ + { .mk = {0xe0, 0x32, 0 }, .brk = { 0xe0, 0xF0, 0x32, 0 } }, /* 130 */ + { .mk = {0xe0, 0x31, 0 }, .brk = { 0xe0, 0xF0, 0x31, 0 } }, /* 131 */ + { .mk = {0xe0, 0x3A, 0 }, .brk = { 0xe0, 0xF0, 0x3A, 0 } }, /* 132 */ + { .mk = { 0 }, .brk = { 0 } }, /* 133 */ + { .mk = {0xe0, 0x49, 0 }, .brk = { 0xe0, 0xF0, 0x49, 0 } }, /* 134 */ + { .mk = {0xe0, 0x4A, 0 }, .brk = { 0xe0, 0xF0, 0x4A, 0 } }, /* 135 */ + { .mk = { 0 }, .brk = { 0 } }, /* 136 */ + { .mk = {0xe0, 0x7C, 0 }, .brk = { 0xe0, 0xF0, 0x7C, 0 } }, /* 137 */ + { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0xF0, 0x11, 0 } }, /* 138* 0x31 R-Alt */ + { .mk = { 0 }, .brk = { 0 } }, /* 139 */ + { .mk = {0xe0, 0x58, 0 }, .brk = { 0xe0, 0xF0, 0x58, 0 } }, /* 13a */ + { .mk = {0xe0, 0x05, 0 }, .brk = { 0xe0, 0xF0, 0x05, 0 } }, /* 13b */ + { .mk = {0xe0, 0x06, 0 }, .brk = { 0xe0, 0xF0, 0x06, 0 } }, /* 13c */ + { .mk = {0xe0, 0x04, 0 }, .brk = { 0xe0, 0xF0, 0x04, 0 } }, /* 13d */ + { .mk = {0xe0, 0x0C, 0 }, .brk = { 0xe0, 0xF0, 0x0C, 0 } }, /* 13e */ + { .mk = {0xe0, 0x03, 0 }, .brk = { 0xe0, 0xF0, 0x03, 0 } }, /* 13f */ + { .mk = {0xe0, 0x0B, 0 }, .brk = { 0xe0, 0xF0, 0x0B, 0 } }, /* 140 */ + { .mk = {0xe0, 0x02, 0 }, .brk = { 0xe0, 0xF0, 0x02, 0 } }, /* 141 */ + { .mk = {0xe0, 0x0A, 0 }, .brk = { 0xe0, 0xF0, 0x0A, 0 } }, /* 142 */ + { .mk = {0xe0, 0x01, 0 }, .brk = { 0xe0, 0xF0, 0x01, 0 } }, /* 143 */ + { .mk = {0xe0, 0x09, 0 }, .brk = { 0xe0, 0xF0, 0x09, 0 } }, /* 144 */ + { .mk = { 0 }, .brk = { 0 } }, /* 145 */ + { .mk = {0xe0, 0x7E, 0 }, .brk = { 0xe0, 0xF0, 0x7E, 0 } }, /* 146 */ + { .mk = {0xe0, 0x6C, 0 }, .brk = { 0xe0, 0xF0, 0x6C, 0 } }, /* 147 */ + { .mk = {0xe0, 0x75, 0 }, .brk = { 0xe0, 0xF0, 0x75, 0 } }, /* 148 */ + { .mk = {0xe0, 0x7D, 0 }, .brk = { 0xe0, 0xF0, 0x7D, 0 } }, /* 149 */ + { .mk = { 0 }, .brk = { 0 } }, /* 14a */ + { .mk = {0xe0, 0x6B, 0 }, .brk = { 0xe0, 0xF0, 0x6B, 0 } }, /* 14b */ + { .mk = {0xe0, 0x73, 0 }, .brk = { 0xe0, 0xF0, 0x73, 0 } }, /* 14c */ + { .mk = {0xe0, 0x74, 0 }, .brk = { 0xe0, 0xF0, 0x74, 0 } }, /* 14d */ + { .mk = {0xe0, 0x79, 0 }, .brk = { 0xe0, 0xF0, 0x79, 0 } }, /* 14e */ + { .mk = {0xe0, 0x69, 0 }, .brk = { 0xe0, 0xF0, 0x69, 0 } }, /* 14f */ + { .mk = {0xe0, 0x72, 0 }, .brk = { 0xe0, 0xF0, 0x72, 0 } }, /* 150 */ + { .mk = {0xe0, 0x7A, 0 }, .brk = { 0xe0, 0xF0, 0x7A, 0 } }, /* 151 */ + { .mk = {0xe0, 0x70, 0 }, .brk = { 0xe0, 0xF0, 0x70, 0 } }, /* 152 */ + { .mk = {0xe0, 0x71, 0 }, .brk = { 0xe0, 0xF0, 0x71, 0 } }, /* 153 */ + { .mk = { 0 }, .brk = { 0 } }, /* 154 */ + { .mk = {0xe0, 0x60, 0 }, .brk = { 0xe0, 0xF0, 0x60, 0 } }, /* 155 */ + { .mk = { 0 }, .brk = { 0 } }, /* 156 */ + { .mk = {0xe0, 0x78, 0 }, .brk = { 0xe0, 0xF0, 0x78, 0 } }, /* 157 */ + { .mk = {0xe0, 0x07, 0 }, .brk = { 0xe0, 0xF0, 0x07, 0 } }, /* 158 */ + { .mk = {0xe0, 0x0F, 0 }, .brk = { 0xe0, 0xF0, 0x0F, 0 } }, /* 159 */ + { .mk = {0xe0, 0x17, 0 }, .brk = { 0xe0, 0xF0, 0x17, 0 } }, /* 15a */ + { .mk = { 0x67, 0 }, .brk = { 0xf0, 0x67, 0 } }, /* 15b 0x33 LGUI->Muhenkan (in emulator only) */ + { .mk = { 0x64, 0 }, .brk = { 0xf0, 0x64, 0 } }, /* 15c 0x35 RGUI->Henkan (in emulator only) */ + { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0xf0, 0x11, 0 } }, /* 15d 0x36 APPLICATION->Kana (in emulator + { .mk = {0xe0, 0x37, 0 }, .brk = { 0xe0, 0xF0, 0x37, 0 } }, /* 15e */ + { .mk = {0xe0, 0x3F, 0 }, .brk = { 0xe0, 0xF0, 0x3F, 0 } }, /* 15f */ + { .mk = { 0 }, .brk = { 0 } }, /* 160 */ + { .mk = {0xe0, 0x4F, 0 }, .brk = { 0xe0, 0xF0, 0x4F, 0 } }, /* 161 */ + { .mk = {0xe0, 0x56, 0 }, .brk = { 0xe0, 0xF0, 0x56, 0 } }, /* 162 */ + { .mk = {0xe0, 0x5E, 0 }, .brk = { 0xe0, 0xF0, 0x5E, 0 } }, /* 163 */ + { .mk = {0xe0, 0x08, 0 }, .brk = { 0xe0, 0xF0, 0x08, 0 } }, /* 164 */ + { .mk = {0xe0, 0x10, 0 }, .brk = { 0xe0, 0xF0, 0x10, 0 } }, /* 165 */ + { .mk = {0xe0, 0x18, 0 }, .brk = { 0xe0, 0xF0, 0x18, 0 } }, /* 166 */ + { .mk = {0xe0, 0x20, 0 }, .brk = { 0xe0, 0xF0, 0x20, 0 } }, /* 167 */ + { .mk = {0xe0, 0x28, 0 }, .brk = { 0xe0, 0xF0, 0x28, 0 } }, /* 168 */ + { .mk = {0xe0, 0x30, 0 }, .brk = { 0xe0, 0xF0, 0x30, 0 } }, /* 169 */ + { .mk = {0xe0, 0x38, 0 }, .brk = { 0xe0, 0xF0, 0x38, 0 } }, /* 16a */ + { .mk = {0xe0, 0x40, 0 }, .brk = { 0xe0, 0xF0, 0x40, 0 } }, /* 16b */ + { .mk = {0xe0, 0x48, 0 }, .brk = { 0xe0, 0xF0, 0x48, 0 } }, /* 16c */ + { .mk = {0xe0, 0x50, 0 }, .brk = { 0xe0, 0xF0, 0x50, 0 } }, /* 16d */ + { .mk = {0xe0, 0x57, 0 }, .brk = { 0xe0, 0xF0, 0x57, 0 } }, /* 16e */ + { .mk = { 0 }, .brk = { 0 } }, /* 16f */ + { .mk = {0xe0, 0x13, 0 }, .brk = { 0xe0, 0xF0, 0x13, 0 } }, /* 170 */ + { .mk = {0xe0, 0x19, 0 }, .brk = { 0xe0, 0xF0, 0x19, 0 } }, /* 171 */ + { .mk = {0xe0, 0x39, 0 }, .brk = { 0xe0, 0xF0, 0x39, 0 } }, /* 172 */ + { .mk = {0xe0, 0x51, 0 }, .brk = { 0xe0, 0xF0, 0x51, 0 } }, /* 173 */ + { .mk = {0xe0, 0x53, 0 }, .brk = { 0xe0, 0xF0, 0x53, 0 } }, /* 174 */ + { .mk = {0xe0, 0x5C, 0 }, .brk = { 0xe0, 0xF0, 0x5C, 0 } }, /* 175 */ + { .mk = { 0 }, .brk = { 0 } }, /* 176 */ + { .mk = {0xe0, 0x62, 0 }, .brk = { 0xe0, 0xF0, 0x62, 0 } }, /* 177 */ + { .mk = {0xe0, 0x63, 0 }, .brk = { 0xe0, 0xF0, 0x63, 0 } }, /* 178 */ + { .mk = {0xe0, 0x64, 0 }, .brk = { 0xe0, 0xF0, 0x64, 0 } }, /* 179 */ + { .mk = {0xe0, 0x65, 0 }, .brk = { 0xe0, 0xF0, 0x65, 0 } }, /* 17a */ + { .mk = {0xe0, 0x67, 0 }, .brk = { 0xe0, 0xF0, 0x67, 0 } }, /* 17b */ + { .mk = {0xe0, 0x68, 0 }, .brk = { 0xe0, 0xF0, 0x68, 0 } }, /* 17c */ + { .mk = {0xe0, 0x6A, 0 }, .brk = { 0xe0, 0xF0, 0x6A, 0 } }, /* 17d */ + { .mk = {0xe0, 0x6D, 0 }, .brk = { 0xe0, 0xF0, 0x6D, 0 } }, /* 17e */ + { .mk = {0xe0, 0x6E, 0 }, .brk = { 0xe0, 0xF0, 0x6E, 0 } }, /* 17f */ + { .mk = { 0 }, .brk = { 0 } }, /* 180 */ + { .mk = { 0 }, .brk = { 0 } }, /* 181 */ + { .mk = { 0 }, .brk = { 0 } }, /* 182 */ + { .mk = { 0 }, .brk = { 0 } }, /* 183 */ + { .mk = { 0 }, .brk = { 0 } }, /* 184 */ + { .mk = { 0 }, .brk = { 0 } }, /* 185 */ + { .mk = { 0 }, .brk = { 0 } }, /* 186 */ + { .mk = { 0 }, .brk = { 0 } }, /* 187 */ + { .mk = { 0 }, .brk = { 0 } }, /* 188 */ + { .mk = { 0 }, .brk = { 0 } }, /* 189 */ + { .mk = { 0 }, .brk = { 0 } }, /* 18a */ + { .mk = { 0 }, .brk = { 0 } }, /* 18b */ + { .mk = { 0 }, .brk = { 0 } }, /* 18c */ + { .mk = { 0 }, .brk = { 0 } }, /* 18d */ + { .mk = { 0 }, .brk = { 0 } }, /* 18e */ + { .mk = { 0 }, .brk = { 0 } }, /* 18f */ + { .mk = { 0 }, .brk = { 0 } }, /* 190 */ + { .mk = { 0 }, .brk = { 0 } }, /* 191 */ + { .mk = { 0 }, .brk = { 0 } }, /* 192 */ + { .mk = { 0 }, .brk = { 0 } }, /* 193 */ + { .mk = { 0 }, .brk = { 0 } }, /* 194 */ + { .mk = { 0 }, .brk = { 0 } }, /* 195 */ + { .mk = { 0 }, .brk = { 0 } }, /* 196 */ + { .mk = { 0 }, .brk = { 0 } }, /* 197 */ + { .mk = { 0 }, .brk = { 0 } }, /* 198 */ + { .mk = { 0 }, .brk = { 0 } }, /* 199 */ + { .mk = { 0 }, .brk = { 0 } }, /* 19a */ + { .mk = { 0 }, .brk = { 0 } }, /* 19b */ + { .mk = { 0 }, .brk = { 0 } }, /* 19c */ + { .mk = { 0 }, .brk = { 0 } }, /* 19d */ + { .mk = { 0 }, .brk = { 0 } }, /* 19e */ + { .mk = { 0 }, .brk = { 0 } }, /* 19f */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1a9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1aa */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ab */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ac */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ad */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ae */ + { .mk = { 0 }, .brk = { 0 } }, /* 1af */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1b9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ba */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1be */ + { .mk = { 0 }, .brk = { 0 } }, /* 1bf */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1c9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ca */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cv */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ce */ + { .mk = { 0 }, .brk = { 0 } }, /* 1cf */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d0 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1d9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1da */ + { .mk = { 0 }, .brk = { 0 } }, /* 1db */ + { .mk = { 0 }, .brk = { 0 } }, /* 1dc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1dd */ + { .mk = { 0 }, .brk = { 0 } }, /* 1de */ + { .mk = { 0 }, .brk = { 0 } }, /* 1df */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e0 */ + { .mk = {0xe0, 0xe1, 0 }, .brk = { 0xe0, 0xF0, 0xE1, 0 } }, /* 1e1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1e9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ea */ + { .mk = { 0 }, .brk = { 0 } }, /* 1eb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ec */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ed */ + { .mk = {0xe0, 0xee, 0 }, .brk = { 0xe0, 0xF0, 0xEE, 0 } }, /* 1ee */ + { .mk = { 0 }, .brk = { 0 } }, /* 1ef */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f0 */ + { .mk = {0xe0, 0xf1, 0 }, .brk = { 0xe0, 0xF0, 0xF1, 0 } }, /* 1f1 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f2 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f3 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f4 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f5 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f6 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f7 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f8 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1f9 */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fa */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fb */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fc */ + { .mk = { 0 }, .brk = { 0 } }, /* 1fd */ + { .mk = {0xe0, 0xfe, 0 }, .brk = { 0xe0, 0xF0, 0xFE, 0 } }, /* 1fe */ + { .mk = {0xe0, 0xff, 0 }, .brk = { 0xe0, 0xF0, 0xFF, 0 } } /* 1ff */ + // clang-format on +}; /* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */ static scancode scancode_set8a[512] = { @@ -1700,9 +2735,9 @@ static scancode scancode_set8a[512] = {.mk = { 0x14, 0 }, .brk = { 0 } }, /* 026 */ {.mk = { 0x15, 0 }, .brk = { 0 } }, /* 027 */ {.mk = { 0x16, 0 }, .brk = { 0 } }, /* 028* */ - {.mk = { 0x45, 0 }, .brk = { 0 } }, /* 029 Hankaku, Zenkaku */ + {.mk = { 0x45, 0 }, .brk = { 0 } }, /* 029 0x45 Hankaku, Zenkaku */ {.mk = { 0x38, 0 }, .brk = { 0xb8, 0 } }, /* 02a LSHIFT */ - {.mk = { 0x17, 0 }, .brk = { 0 } }, /* 02b Mu */ + {.mk = { 0x17, 0 }, .brk = { 0 } }, /* 02b 0x17 Mu */ {.mk = { 0x01, 0 }, .brk = { 0 } }, /* 02c */ {.mk = { 0x02, 0 }, .brk = { 0 } }, /* 02d */ {.mk = { 0x03, 0 }, .brk = { 0 } }, /* 02e */ @@ -1715,7 +2750,7 @@ static scancode scancode_set8a[512] = {.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */ {.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */ {.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */ - {.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 LALT = Kanji */ + {.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */ {.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */ {.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */ {.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */ @@ -1728,8 +2763,8 @@ static scancode scancode_set8a[512] = {.mk = { 0x6f, 0 }, .brk = { 0 } }, /* 042 */ {.mk = { 0x70, 0 }, .brk = { 0 } }, /* 043 */ {.mk = { 0x71, 0 }, .brk = { 0 } }, /* 044 F10 */ - {.mk = { 0 }, .brk = { 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */ - {.mk = { 0x75, 0 }, .brk = { 0 } }, /* 046 SCROLLLOCK */ + {.mk = { 0x47, 0 }, .brk = { 0 } }, /* 045 NUMLOCKCLEAR -> Shift + SCRLOCK :TODO */ + {.mk = { 0x75, 0 }, .brk = { 0 } }, /* 046 0x75 SCROLLLOCK */ {.mk = { 0x5d, 0 }, .brk = { 0 } }, /* 047 KP7 */ {.mk = { 0x5e, 0 }, .brk = { 0 } }, /* 048 */ {.mk = { 0x5f, 0 }, .brk = { 0 } }, /* 049 */ @@ -1771,20 +2806,20 @@ static scancode scancode_set8a[512] = {.mk = { 0 }, .brk = { 0 } }, /* 06d */ {.mk = { 0 }, .brk = { 0 } }, /* 06e */ {.mk = { 0 }, .brk = { 0 } }, /* 06f */ - {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 070 Kana */ + {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 070 0x36 Kana */ {.mk = { 0 }, .brk = { 0 } }, /* 071 */ {.mk = { 0 }, .brk = { 0 } }, /* 072 */ - {.mk = { 0x0b, 0 }, .brk = { 0 } }, /* 073 Ro, Underline */ + {.mk = { 0x0b, 0 }, .brk = { 0 } }, /* 073 0x0b Ro, Underline */ {.mk = { 0 }, .brk = { 0 } }, /* 074 */ {.mk = { 0 }, .brk = { 0 } }, /* 075 */ {.mk = { 0 }, .brk = { 0 } }, /* 076 */ {.mk = { 0 }, .brk = { 0 } }, /* 077 */ {.mk = { 0 }, .brk = { 0 } }, /* 078 */ - {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 079 Henkan */ + {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 079 0x35 Henkan */ {.mk = { 0 }, .brk = { 0 } }, /* 07a */ - {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 07b Muhenkan */ + {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 07b 0x33 Muhenkan */ {.mk = { 0 }, .brk = { 0 } }, /* 07c */ - {.mk = { 0x30, 0 }, .brk = { 0 } }, /* 07d Yen, Vertical line */ + {.mk = { 0x30, 0 }, .brk = { 0 } }, /* 07d 0x30 Yen, Vertical line */ {.mk = { 0 }, .brk = { 0 } }, /* 07e */ {.mk = { 0 }, .brk = { 0 } }, /* 07f */ {.mk = { 0 }, .brk = { 0 } }, /* 080 */ @@ -1915,7 +2950,7 @@ static scancode scancode_set8a[512] = {.mk = { 0 }, .brk = { 0 } }, /* 0fd */ {.mk = { 0 }, .brk = { 0 } }, /* 0fe */ {.mk = { 0 }, .brk = { 0 } }, /* 0ff */ - {.mk = { 0x47, 0 }, .brk = { 0 } }, /* 100 Pause */ + {.mk = { 0 }, .brk = { 0 } }, /* 100 */ {.mk = { 0 }, .brk = { 0 } }, /* 101 */ {.mk = { 0 }, .brk = { 0 } }, /* 102 */ {.mk = { 0 }, .brk = { 0 } }, /* 103 */ @@ -1971,7 +3006,7 @@ static scancode scancode_set8a[512] = {.mk = { 0x65, 0 }, .brk = { 0 } }, /* 135 KP_DIVIDE */ {.mk = { 0 }, .brk = { 0 } }, /* 136 */ {.mk = { 0x74, 0 }, .brk = { 0 } }, /* 137 PRINTSCREEN */ - {.mk = { 0x31, 0 }, .brk = { 0xb1, 0 } }, /* 138* R-Alt */ + {.mk = { 0x31, 0 }, .brk = { 0xb1, 0 } }, /* 138* 0x31 R-Alt */ {.mk = { 0 }, .brk = { 0 } }, /* 139 */ {.mk = { 0 }, .brk = { 0 } }, /* 13a */ {.mk = { 0 }, .brk = { 0 } }, /* 13b */ @@ -2006,9 +3041,9 @@ static scancode scancode_set8a[512] = {.mk = { 0 }, .brk = { 0 } }, /* 158 */ {.mk = { 0 }, .brk = { 0 } }, /* 159 */ {.mk = { 0 }, .brk = { 0 } }, /* 15a */ - {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 15b LGUI->Muhenkan (in emulator only) */ - {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 15c RGUI->Henkan (in emulator only) */ - {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 15d APPLICATION->Kana (in emulator only) */ + {.mk = { 0x33, 0 }, .brk = { 0 } }, /* 15b 0x33 LGUI->Muhenkan (in emulator only) */ + {.mk = { 0x35, 0 }, .brk = { 0 } }, /* 15c 0x35 RGUI->Henkan (in emulator only) */ + {.mk = { 0x36, 0 }, .brk = { 0xb6, 0 } }, /* 15d 0x36 APPLICATION->Kana (in emulator only) */ {.mk = { 0 }, .brk = { 0 } }, /* 15e */ {.mk = { 0 }, .brk = { 0 } }, /* 15f */ {.mk = { 0 }, .brk = { 0 } }, /* 160 */ @@ -2173,7 +3208,7 @@ static scancode scancode_set8a[512] = {.mk = { 0 }, .brk = { 0 } } /* 1ff */ // clang-format on }; - +#define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -2209,6 +3244,14 @@ keyboard_at_set_scancode_set(void) keyboard_set_table(scancode_set3); break; + case 0x81: + keyboard_set_table(scancode_set81); + break; + + case 0x82: + keyboard_set_table(scancode_set82); + break; + case 0x8a: keyboard_set_table(scancode_set8a); break; @@ -2477,6 +3520,8 @@ keyboard_at_write(void *priv) kbc_at_dev_queue_add(dev, keyboard_mode, 0); break; case 0x01 ... 0x03: + case 0x81: + case 0x82: case 0x8a: kbc_at_dev_queue_add(dev, 0xfa, 0); /* ACK */ keyboard_mode = val; @@ -2560,7 +3605,7 @@ keyboard_at_write(void *priv) break; case 0xf2: /* read ID */ - keyboard_at_log("%s: read keyboard id\n", dev->name); + keyboard_at_log("%s: read keyboard id: ", dev->name); /* TODO: After keyboard type selection is implemented, make this return the correct keyboard ID for the selected type. */ kbc_at_dev_queue_add(dev, 0xfa, 0); @@ -2569,7 +3614,9 @@ keyboard_at_write(void *priv) break; kbc_at_dev_queue_add(dev, id_bytes[dev->type][i], 0); + keyboard_at_log("%02X ", id_bytes[dev->type][i]); } + keyboard_at_log("\n"); break; case 0xf3: /* set command mode */ @@ -2694,7 +3741,8 @@ keyboard_at_init(const device_t *info) Key 63 = Japanese key between right Ctrl and right Alt, scan code: 86 (Henkan/Zenkouho 79); Key 65? = Japanese key between right Ctrl and right Alt, scan code: 87 (Hiragana/Katakana 70). */ - dev->type = FLAG_PS2 | KBD_102_KEY /* device_get_config_int("type") */; + // dev->type = FLAG_PS2 | KBD_102_KEY /* device_get_config_int("type") */; + dev->type = FLAG_PS2 | KBD_JIS; keyboard_at_log("%s: type=%d\n", dev->name, dev->type); From 4042fd15fb9dcf5b59d6d916ef3f05c3c3db50c1 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:03:39 +0900 Subject: [PATCH 0330/1190] DA2 skip recalctimings if output is disabled --- src/video/vid_ps55da2.c | 83 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index f81a62ffe..31559cc52 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1075,14 +1075,10 @@ da2_out(uint16_t addr, uint16_t val, void *p) if (oldval != val) { if (da2->ioctladdr == LS_RESET && val & 0x01) /* Reset register */ da2_reset_ioctl(da2); - else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) /* Mode register */ - { + else if (da2->ioctladdr == LS_MODE && ((oldval ^ val) & 0x03)) { /* Mode register */ da2->fullchange = changeframecount; da2_recalctimings(da2); da2_updatevidselector(da2); - } else if (da2->ioctladdr == LS_MMIO && (!(val & 0x01))) /* MMIO register */ - { - // da2->bitblt.indata = 1; } } break; @@ -1117,7 +1113,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) // return; break; case LC_MAXIMUM_SCAN_LINE: - if (!(da2->ioctl[LS_MODE] & 0x01)) + if (!(da2->ioctl[LS_MODE] & 0x01)) /* 16 or 256 color graphics mode */ val = 0; break; case LC_START_ADDRESS_HIGH: @@ -2035,14 +2031,15 @@ da2_render_color_8bpp(da2_t *da2) void da2_updatevidselector(da2_t *da2) { - da2_log("DA2 selector: %d\n", da2->ioctl[LS_MODE]); if (da2->ioctl[LS_MODE] & 0x02) { /* VGA passthrough mode */ da2->override = 1; svga_set_override(da2->mb_vga, 0); + da2_log("DA2 selector: VGA\n"); } else { svga_set_override(da2->mb_vga, 1); da2->override = 0; + da2_log("DA2 selector: DA2\n"); } } @@ -2051,6 +2048,10 @@ da2_recalctimings(da2_t *da2) { double crtcconst; double _dispontime, _dispofftime, disptime; + + /* if output disabled or VGA passthrough */ + if (!(da2->attrc[LV_COMPATIBILITY] & 0x08) || da2->ioctl[LS_MODE] & 0x02) + return; da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; @@ -2092,40 +2093,36 @@ da2_recalctimings(da2_t *da2) da2->render = da2_render_blank; /* determine display mode */ // if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) - if (da2->attrc[LV_COMPATIBILITY] & 0x08) { - /* 16 color graphics mode */ - if (!(da2->ioctl[LS_MODE] & 0x01)) { - da2->hdisp *= 16; - da2->char_width = 13; - da2->hdisp_old = da2->hdisp; - if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { - da2_log("Set videomode to PS/55 8 bpp graphics.\n"); - da2->render = da2_render_color_8bpp; - da2->vram_display_mask = DA2_MASK_GRAM; - } else { /* PS/55 8-color */ - da2_log("Set videomode to PS/55 4 bpp graphics.\n"); - da2->vram_display_mask = DA2_MASK_GRAM; - da2->render = da2_render_color_4bpp; - } - } else { - /* text mode */ - if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { - da2_log("Set videomode to PS/55 Mode 03 text.\n"); - da2->render = da2_render_textm3; - da2->vram_display_mask = DA2_MASK_CRAM; - } - /* PS/55 text(color/mono) */ - else { - da2_log("Set videomode to PS/55 Mode 8/E text.\n"); - da2->render = da2_render_text; - da2->vram_display_mask = DA2_MASK_CRAM; - } - da2->hdisp *= 13; - da2->hdisp_old = da2->hdisp; - da2->char_width = 13; + /* 16 color graphics mode */ + if (!(da2->ioctl[LS_MODE] & 0x01)) { + da2->hdisp *= 16; + da2->char_width = 13; + da2->hdisp_old = da2->hdisp; + if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { + da2_log("Set videomode to PS/55 8 bpp graphics.\n"); + da2->render = da2_render_color_8bpp; + da2->vram_display_mask = DA2_MASK_GRAM; + } else { /* PS/55 8-color */ + da2_log("Set videomode to PS/55 4 bpp graphics.\n"); + da2->vram_display_mask = DA2_MASK_GRAM; + da2->render = da2_render_color_4bpp; } } else { - da2_log("Set videomode to blank.\n"); + /* text mode */ + if (da2->attrc[LV_ATTRIBUTE_CNTL] & 1) { + da2_log("Set videomode to PS/55 Mode 03 text.\n"); + da2->render = da2_render_textm3; + da2->vram_display_mask = DA2_MASK_CRAM; + } + /* PS/55 text(color/mono) */ + else { + da2_log("Set videomode to PS/55 Mode 8/E text.\n"); + da2->render = da2_render_text; + da2->vram_display_mask = DA2_MASK_CRAM; + } + da2->hdisp *= 13; + da2->hdisp_old = da2->hdisp; + da2->char_width = 13; } // if (!da2->scrblank && da2->attr_palette_enable) //{ @@ -2344,7 +2341,7 @@ da2_mmio_read(uint32_t addr, void *p) return DA2_INVALIDACCESS8; /* invalid memory access */ break; } - } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 or 256 color mode */ cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) da2->gdcla[i] = da2->vram[(addr << 3) | i]; /* read in byte */ @@ -2371,7 +2368,7 @@ da2_mmio_readw(uint32_t addr, void *p) //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); - } else if (!(da2->ioctl[LS_MODE] & 1)) /* 8 color or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) /* 16 color or 256 color mode */ { cycles -= video_timing_read_w; addr &= DA2_MASK_MMIO; @@ -2458,7 +2455,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); break; } - } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 color or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ uint8_t bitmask; /* align bitmask to even address */ if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; @@ -2681,7 +2678,7 @@ da2_mmio_writew(uint32_t addr, uint16_t val, void *p) // da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); - } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 8 color or 256 color mode */ + } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ addr &= DA2_MASK_MMIO; // return; // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); From 0b97701e7a43ba1162c15f80bf0a8f1c31ce9ace Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:53:44 +0900 Subject: [PATCH 0331/1190] add keyboard ID switcher for PS/55 --- src/device/keyboard_at.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index d44833dd3..d04ab07e9 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -25,6 +25,7 @@ #include <86box/device.h> #include <86box/keyboard.h> #include <86box/mouse.h> +#include <86box/machine.h> #define FLAG_PS2 0x08 /* dev is AT or PS/2 */ #define FLAG_AT 0x00 /* dev is AT or PS/2 */ @@ -1639,14 +1640,14 @@ static const scancode scancode_set3[512] = { 5576 keyboards kept 101-key compatible scancode sets because PS/55 had to support western (PS/2) versions of operating systems. The default scancode set is 2. In Japanese DOS, the keyboard driver confirms its keyboard ID, and sends a command to switch the scancode set to 8Ah. - Japanese OS/2 and Windows use the scancode set 82h. + Japanese OS/2 and Windows use the scancode set 81h or 82h. - The OADG standard (1991-) and modern Japanese keyboards use the same keyboard ID and scancode set number as PS/2 keyboards use. + The OADG standard (1991-) and modern Japanese keyboards use the same keyboard ID and scancode set ID as PS/2 keyboards use. Three extra scancode sets are no longer available. Instead, language input keys are available in scancode set 1 and 2. However, their physical key layout is a bit-paired layout. Users have to choose the correct keyboard layout on setup, and the driver needs to remap keys. - Currently, scancode set 81h and 82h are not implemented yet. Also, the key layout is designed to match with the Japanese keyboard. + Currently, the key mapping is designed to match with the Japanese layout keyboard. [Japanese DOS and keyboard scancode set comparison] | | K3.3 | J4.0 | J5.0 | J4.0/V | J5.0/V | OS/2 J1.3 | DOS 5(US)| @@ -3208,7 +3209,7 @@ static scancode scancode_set8a[512] = {.mk = { 0 }, .brk = { 0 } } /* 1ff */ // clang-format on }; -#define ENABLE_KEYBOARD_AT_LOG 1 + #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -3741,8 +3742,14 @@ keyboard_at_init(const device_t *info) Key 63 = Japanese key between right Ctrl and right Alt, scan code: 86 (Henkan/Zenkouho 79); Key 65? = Japanese key between right Ctrl and right Alt, scan code: 87 (Hiragana/Katakana 70). */ - // dev->type = FLAG_PS2 | KBD_102_KEY /* device_get_config_int("type") */; - dev->type = FLAG_PS2 | KBD_JIS; + dev->type = FLAG_PS2 | KBD_102_KEY /* device_get_config_int("type") */; + /* + We assume that the IBM PS/55 machine uses the 5576-002 keyboard (JP/CN layout) here. + This is not smart but suitable for supporting a keyboard ID that is rarely used in standard PCs. + At least, the Taiwanese PS/55 uses the same keyboard ID and scancode set. The Korean one is unknown. + */ + if (!!strstr(machine_getname(), "PS/55")) + dev->type = FLAG_PS2 | KBD_JIS; keyboard_at_log("%s: type=%d\n", dev->name, dev->type); From d70f43828c86d72258a2d5737531e3a94b45ab73 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:12:54 +0900 Subject: [PATCH 0332/1190] replace magic numbers with predifined macros --- src/video/vid_ps55da2.c | 46 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 31559cc52..a517b7e6c 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -54,9 +54,14 @@ #define DA2_FONTROM_BASESBCS 0x98000 #define DA2_GAIJIRAM_SBCS 0x34000 #define DA2_GAIJIRAM_SBEX 0x3c000 +#define DA2_VM03_BASECHR 0x18000 +#define DA2_VM03_BASEEXATTR 0x10000 #define DA2_INVALIDACCESS8 0xff #define DA2_MASK_MMIO 0x1ffff -#define DA2_MASK_GRAM 0x1ffff +#define DA2_SIZE_VRAM 1024 * 1024 /* 0x100000 */ +#define DA2_SIZE_CRAM 4 * 1024 /* 0x1000 */ +#define DA2_SIZE_GAIJIRAM 256 * 1024 /* 0x40000 */ +#define DA2_MASK_A000 0x1ffff #define DA2_MASK_CRAM 0xfff #define DA2_MASK_GAIJIRAM 0x3ffff #define DA2_PIXELCLOCK 58000000.0 @@ -243,7 +248,7 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -// #define ENABLE_DA2_LOG 1 +#define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG @@ -370,7 +375,7 @@ typedef struct da2_t { { int enable; mem_mapping_t mapping; - uint8_t ram[256 * 1024]; + uint8_t ram[DA2_SIZE_GAIJIRAM]; uint8_t *font; int charset; } mmio; @@ -1855,10 +1860,10 @@ da2_render_textm3(da2_t *da2) int chr_wide = 0; // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { - chr = da2->vram[(0x18000 + (da2->ma)) & da2->vram_mask]; - attr = da2->vram[((0x18000 + (da2->ma)) + 1) & da2->vram_mask]; - extattr = da2->vram[((0x10000 + (da2->ma)) + 1) & da2->vram_mask]; - // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (0x18000 + da2->ma << 1) & da2->vram_mask, chr, attr); + chr = da2->vram[(DA2_VM03_BASECHR + (da2->ma)) & da2->vram_mask]; + attr = da2->vram[((DA2_VM03_BASECHR + (da2->ma)) + 1) & da2->vram_mask]; + extattr = da2->vram[((DA2_VM03_BASEEXATTR + (da2->ma)) + 1) & da2->vram_mask]; + // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->ma << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; // if (da2->blink) bg &= ~0x8; // fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; @@ -1875,7 +1880,7 @@ da2_render_textm3(da2_t *da2) /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = da2->vram[(0x18000 + (da2->ma) + 2) & da2->vram_mask]; + chr_dbcs = da2->vram[(DA2_VM03_BASECHR + (da2->ma) + 2) & da2->vram_mask]; chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ @@ -1887,11 +1892,9 @@ da2_render_textm3(da2_t *da2) } } else { /* the char code is SBCS (ANK) */ - uint32_t fontbase; - fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ + uint16_t font = da2->mmio.ram[DA2_GAIJIRAM_SBCS + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ + font |= da2->mmio.ram[DA2_GAIJIRAM_SBCS+ chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -2101,10 +2104,10 @@ da2_recalctimings(da2_t *da2) if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { da2_log("Set videomode to PS/55 8 bpp graphics.\n"); da2->render = da2_render_color_8bpp; - da2->vram_display_mask = DA2_MASK_GRAM; + da2->vram_display_mask = DA2_MASK_A000; } else { /* PS/55 8-color */ da2_log("Set videomode to PS/55 4 bpp graphics.\n"); - da2->vram_display_mask = DA2_MASK_GRAM; + da2->vram_display_mask = DA2_MASK_A000; da2->render = da2_render_color_4bpp; } } else { @@ -3029,12 +3032,11 @@ da2_init(UNUSED(const device_t *info)) da2->dispontime = 1000ull << 32; da2->dispofftime = 1000ull << 32; - int memsize = 1024 * 1024; - da2->vram = calloc(1, memsize); - da2->vram_mask = memsize - 1; - da2->cram = calloc(1, 0x1000); + da2->vram = calloc(1, DA2_SIZE_VRAM); + da2->vram_mask = DA2_SIZE_VRAM - 1; + da2->cram = calloc(1, DA2_SIZE_CRAM); da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = calloc(1, /*(memsize >> 12) << 1*/ 0x1000000 >> 12); /* XX000h */ + da2->changedvram = calloc(1, /*(memsize >> 12) << 1*/ DA2_SIZE_VRAM >> 12); /* XX000h */ da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ da2->mmio.charset = device_get_config_int("charset"); @@ -3095,17 +3097,17 @@ da2_close(void *p) FILE *f; f = fopen("da2_cram.dmp", "wb"); if (f != NULL) { - fwrite(da2->cram, 0x1000, 1, f); + fwrite(da2->cram, DA2_SIZE_CRAM, 1, f); fclose(f); } f = fopen("da2_vram.dmp", "wb"); if (f != NULL) { - fwrite(da2->vram, 1024 * 1024, 1, f); + fwrite(da2->vram, DA2_SIZE_VRAM, 1, f); fclose(f); } f = fopen("da2_gram.dmp", "wb"); if (f != NULL) { - fwrite(da2->mmio.ram, 256 * 1024, 1, f); + fwrite(da2->mmio.ram, DA2_SIZE_GAIJIRAM, 1, f); fclose(f); } f = fopen("da2_attrpal.dmp", "wb"); From 4bc47894de81c995c36592b2a1eeafb59e9846c1 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:53:34 +0900 Subject: [PATCH 0333/1190] safety read/write vram memory --- src/video/vid_ps55da2.c | 112 ++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index a517b7e6c..7c7891926 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -437,12 +437,19 @@ typedef struct { /* safety read for internal functions */ uint32_t -DA2_readvram_s(uint32_t addr, da2_t *da2) +DA2_vram_r(uint32_t addr, da2_t *da2) { if (addr & ~da2->vram_mask) return -1; return da2->vram[addr]; } +/* safety write for internal functions */ +void +DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) +{ + da2->vram[addr & da2->vram_mask] = val; + return; +} void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) @@ -455,10 +462,10 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s destaddr <<= 3; /* read destination data with big endian order */ for (int i = 0; i < 8; i++) - writepx[i] = DA2_readvram_s((destaddr + 24) | i, da2) - | (DA2_readvram_s((destaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((destaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((destaddr + 0) | i, da2) << 24); + writepx[i] = DA2_vram_r((destaddr + 24) | i, da2) + | (DA2_vram_r((destaddr + 16) | i, da2) << 8) + | (DA2_vram_r((destaddr + 8) | i, da2) << 16) + | (DA2_vram_r((destaddr + 0) | i, da2) << 24); DA2_VidSeq32 mask32in; mask32in.d = (uint32_t) mask; @@ -487,8 +494,8 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s } } for (int i = 0; i < 8; i++) { - da2->vram[(da2->vram_mask & destaddr) | i] = (writepx[i] >> 24) & 0xff; - da2->vram[(da2->vram_mask & (destaddr + 8)) | i] = (writepx[i] >> 16) & 0xff; + DA2_vram_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); + DA2_vram_w((destaddr + 8) | i, (writepx[i] >> 16) & 0xff, da2); } } @@ -531,10 +538,10 @@ DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, srcaddr &= 0xfffffffe; srcaddr <<= 3; for (int i = 0; i < 8; i++) - srcpx.p8[i] = DA2_readvram_s((srcaddr + 24) | i, da2) - | (DA2_readvram_s((srcaddr + 16) | i, da2) << 8) - | (DA2_readvram_s((srcaddr + 8) | i, da2) << 16) - | (DA2_readvram_s((srcaddr + 0) | i, da2) << 24); + srcpx.p8[i] = DA2_vram_r((srcaddr + 24) | i, da2) + | (DA2_vram_r((srcaddr + 16) | i, da2) << 8) + | (DA2_vram_r((srcaddr + 8) | i, da2) << 16) + | (DA2_vram_r((srcaddr + 0) | i, da2) << 24); DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } @@ -560,7 +567,7 @@ pixel1tohex(uint32_t addr, int index, da2_t *da2) { uint8_t pixeldata = 0; for (int j = 0; j < 8; j++) { - if (da2->vram[(da2->vram_mask & (addr << 3)) | j] & (1 << (7 - index))) + if (DA2_vram_r(((addr << 3) | j) & (1 << (7 - index)), da2)) pixeldata++; } return pixeldata; @@ -1724,8 +1731,8 @@ da2_render_text(da2_t *da2) int chr_wide = 0; // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { - chr = da2->cram[(da2->ma) & da2->vram_display_mask]; - attr = da2->cram[((da2->ma) + 1) & da2->vram_display_mask]; + chr = da2->cram[(da2->ma) & DA2_MASK_CRAM]; + attr = da2->cram[((da2->ma) + 1) & DA2_MASK_CRAM]; // if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) /* IO 3E8h, Index 1Dh */ { /* --Parse attribute byte in color mode-- */ @@ -1860,9 +1867,9 @@ da2_render_textm3(da2_t *da2) int chr_wide = 0; // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { - chr = da2->vram[(DA2_VM03_BASECHR + (da2->ma)) & da2->vram_mask]; - attr = da2->vram[((DA2_VM03_BASECHR + (da2->ma)) + 1) & da2->vram_mask]; - extattr = da2->vram[((DA2_VM03_BASEEXATTR + (da2->ma)) + 1) & da2->vram_mask]; + chr = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma), da2); + attr = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma) + 1, da2); + extattr = DA2_vram_r(DA2_VM03_BASEEXATTR + (da2->ma) + 1, da2); // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->ma << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; // if (da2->blink) bg &= ~0x8; @@ -1880,7 +1887,7 @@ da2_render_textm3(da2_t *da2) /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = da2->vram[(DA2_VM03_BASECHR + (da2->ma) + 2) & da2->vram_mask]; + chr_dbcs = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma) + 2, da2); chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ @@ -2116,9 +2123,7 @@ da2_recalctimings(da2_t *da2) da2_log("Set videomode to PS/55 Mode 03 text.\n"); da2->render = da2_render_textm3; da2->vram_display_mask = DA2_MASK_CRAM; - } - /* PS/55 text(color/mono) */ - else { + } else { /* PS/55 text(color/mono) */ da2_log("Set videomode to PS/55 Mode 8/E text.\n"); da2->render = da2_render_text; da2->vram_display_mask = DA2_MASK_CRAM; @@ -2243,19 +2248,19 @@ da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) case 0: /*Set*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->gdcsrc[i] & ~bitmask); // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); - da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); + DA2_vram_w(addr | i, (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 1: /*AND*/ // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask) & da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); + DA2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 2: /*OR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); + DA2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 3: /*XOR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) ^ da2->gdcsrc[i]; - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask); + DA2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; } } @@ -2273,30 +2278,30 @@ da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) case 0: /*Set*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); - da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); + DA2_vram_w(addr | i, (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + DA2_vram_w((addr + 8) | i, ((da2->gdcinput[i] >> 8) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 1: /*AND*/ // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); + DA2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 2: /*OR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); + DA2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 3: /*XOR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); - da2->vram[addr | i] = ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l); - da2->vram[(addr + 8) | i] = (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) - | (da2->vram[(addr + 8) | i] & ~bitmask_h); + DA2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; } } @@ -2359,7 +2364,6 @@ da2_mmio_read(uint32_t addr, void *p) } else return da2->gdcla[da2->readplane]; } else { /* text mode 3 */ - cycles -= video_timing_read_b; return da2->vram[addr]; } @@ -2371,8 +2375,7 @@ da2_mmio_readw(uint32_t addr, void *p) //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); - } else if (!(da2->ioctl[LS_MODE] & 1)) /* 16 color or 256 color mode */ - { + } else if (!(da2->ioctl[LS_MODE] & 1)) {/* 16 color or 256 color mode */ cycles -= video_timing_read_w; addr &= DA2_MASK_MMIO; for (int i = 0; i < 8; i++) @@ -2417,8 +2420,8 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; // da2_log("da2_mmio_write %x %x\n", addr, val); - if ((addr & ~DA2_MASK_MMIO) != 0xA0000) - return; + // if ((addr & ~DA2_MASK_MMIO) != 0xA0000) + // return; addr &= DA2_MASK_MMIO; if (da2->ioctl[LS_MMIO] & 0x10) { @@ -2434,8 +2437,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } switch (da2->fctl[LF_MMIO_MODE]) { case 0xb0: /* Gaiji RAM 1011 0000 */ - addr &= DA2_MASK_GAIJIRAM; /* safety access */ - da2->mmio.ram[addr] = val; + da2->mmio.ram[addr & DA2_MASK_GAIJIRAM] = val; break; case 0x10: /* Font ROM 0001 0000 */ /* Read-Only */ @@ -2509,7 +2511,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) case 2: /* equiv to vga write mode 1 */ for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) - da2->vram[addr | i] = da2->gdcsrc[i]; + DA2_vram_w(addr | i, da2->gdcsrc[i], da2); break; case 0:/* equiv to vga write mode 0 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) @@ -2517,7 +2519,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) if (bitmask == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) - da2->vram[addr | i] = val; + DA2_vram_w(addr | i, val, da2); } else { for (int i = 0; i < 8; i++) if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) @@ -2537,7 +2539,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) - da2->vram[addr | i] = (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + DA2_vram_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2); //fprintf(da2->mmdbg_fp, "m1-1"); } else { for (int i = 0; i < 8; i++) @@ -2559,7 +2561,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) // da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); } else { /* mode 3h text */ cycles -= video_timing_write_b; - da2->vram[addr] = val; + DA2_vram_w(addr, val, da2); da2->fullchange = 2; } } @@ -2622,8 +2624,8 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) case 2: for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) { - da2->vram[addr | i] = da2->gdcsrc[i] & 0xff; - da2->vram[(addr + 8) | i] = da2->gdcsrc[i] >> 8; + DA2_vram_w(addr | i, da2->gdcsrc[i] & 0xff, da2); + DA2_vram_w((addr + 8) | i, da2->gdcsrc[i] >> 8, da2); } break; case 0: @@ -2632,8 +2634,8 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) { - da2->vram[addr | i] = val & 0xff; - da2->vram[(addr + 8) | i] = val >> 8; + DA2_vram_w(addr | i, val & 0xff, da2); + DA2_vram_w((addr + 8) | i, val >> 8, da2); } } else { for (int i = 0; i < 8; i++) @@ -2649,9 +2651,9 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->writemask & (1 << i)) { - uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - da2->vram[addr | i] = wdata & 0xff; - da2->vram[(addr + 8) | i] = wdata >> 8; + uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + DA2_vram_w(addr | i, wdata & 0xff, da2); + DA2_vram_w((addr + 8) | i, wdata >> 8, da2); } } else { for (int i = 0; i < 8; i++) From 50300a1d9a949ccfb59b2b00a8bd9b794c802527 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 25 Feb 2025 10:08:12 +0900 Subject: [PATCH 0334/1190] Add line drawing function (incomplete) remains a bug that the second hand doesn't appear in the Clock app of Windows 3.1. --- src/video/vid_ps55da2.c | 163 ++++++++++++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 25 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 7c7891926..f157d8fca 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -87,8 +87,9 @@ #define DA2_BLT_CCOPYF 3 #define DA2_BLT_CCOPYR 4 #define DA2_BLT_CPUTCHAR 5 -#define DA2_BLT_CDONE 6 -#define DA2_BLT_CLOAD 7 +#define DA2_BLT_CLINE 6 +#define DA2_BLT_CDONE 7 +#define DA2_BLT_CLOAD 8 /* POS ID = 0xeffe : Display Adapter II, III, V */ #define DA2_POSID_H 0xef #define DA2_POSID_L 0xfe @@ -253,7 +254,9 @@ #ifdef ENABLE_DA2_LOG # define ENABLE_DA2_DEBUGBLT 1 +// # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 +// # define ENABLE_DA2_DEBUGMONWAIT 1 int da2_do_log = ENABLE_DA2_LOG; static void @@ -388,6 +391,7 @@ typedef struct da2_t { #ifdef ENABLE_DA2_DEBUGBLT int32_t *debug_reg; // for debug int debug_reg_ip; // for debug + int debug_exesteps; #endif int payload_addr; pc_timer_t timer; @@ -398,14 +402,20 @@ typedef struct da2_t { int32_t srcaddr; int32_t size_x, tile_w; int32_t size_y; + int32_t dest_x; + int32_t dest_y; int16_t destpitch; int16_t srcpitch; int32_t fcolor; int32_t maskl, maskr; + int32_t count; + // int32_t countj; + int32_t d; + int octdir; int x, y; } bitblt; -#ifdef ENABLE_DA2_DEBUGBLT +#ifdef ENABLE_DA2_DEBUGVRAM FILE *mmdbg_fp; FILE *mmrdbg_fp; uint32_t mmdbg_vidaddr; @@ -520,7 +530,7 @@ Param Desc 0A Plane Mask? 0B ROP?(8h or 200h + 0-3h) 0D -20 Exec (1) +20 Exec (1) or Exec without reset regs (21h) 21 ? 22 ? 23 Tile W @@ -718,6 +728,7 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.debug_reg_ip++; if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; + da2->bitblt.debug_exesteps = 0; #endif da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03; /* 01 AND, 03 XOR */ @@ -749,11 +760,14 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.exec = DA2_BLT_CDONE; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - if (da2->bitblt.reg[0x2f] < 0x80) /* MS Paint 3.1 will cause hang up in 256 color mode */ - { - da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); - da2->bitblt.exec = DA2_BLT_CDONE; - } else if (da2->bitblt.reg[0x10] == 0xbc04) { /* Put char used by OS/2 (i'm not sure what the condition is) */ + // if (da2->bitblt.reg[0x2f] < 0x80) /* MS Paint 3.1 will cause hang up in 256 color mode */ + // { + // da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); + // da2->bitblt.exec = DA2_BLT_CDONE; + // } else + + /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ + if (da2->bitblt.reg[0x10] == 0xbc04) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; /* Todo: addressing */ // if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ @@ -776,7 +790,9 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #endif - } else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { + } + /* Put SBCS char used by OS/2 */ + else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; da2->bitblt.destaddr += 2; @@ -792,7 +808,36 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #endif } - /* Fill a rectangle(or draw a line) */ + /* Draw a line */ + else if (da2->bitblt.reg[0x5] == 0x43) { + // da2_log("drawline x=%d, y=%d, 24=%d, 2A=%d, 2B=%d, 2D=%d\n", + // da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + // n24, n2a, n2b, da2->bitblt.reg[0x2D]); + da2->bitblt.exec = DA2_BLT_CLINE; + da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0x7ff); + da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0x7ff); + da2->bitblt.size_x = abs((da2->bitblt.reg[0x33] & 0x7ff) - (da2->bitblt.reg[0x32] & 0x7ff)); + da2->bitblt.size_y = abs((da2->bitblt.reg[0x35] & 0x7ff) - (da2->bitblt.reg[0x34] & 0x7ff)); + // da2->bitblt.raster_op = 0; + da2->bitblt.count = 0; + da2->bitblt.octdir = da2->bitblt.reg[0x2D]; + da2->bitblt.bitshift_destr = 0; + if (da2->bitblt.octdir & 0x04) /* dX > dY */ + da2->bitblt.d = 2 * da2->bitblt.size_y - da2->bitblt.size_x; + else + da2->bitblt.d = 2 * da2->bitblt.size_x - da2->bitblt.size_y; + da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%d\n", + da2->bitblt.dest_x, da2->bitblt.dest_y, + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); + // FILE *f = fopen("da2_drawline.csv", "a"); + // if (f != NULL) { + // fprintf(f,"drawline,%d,%d,%d,%d,%d,%d\n", + // da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + // n24, n2a, n2b, da2->bitblt.reg[0x2D]); + // fclose(f); + // } + } + /* Fill a rectangle (or draw a horizontal / vertical line) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), @@ -824,7 +869,7 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); } - /* Block transfer (range copy) */ + /* Block copy */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { da2->bitblt.exec = DA2_BLT_CCOPYF; da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; @@ -855,7 +900,13 @@ da2_bitblt_exec(void *p) { da2_t *da2 = (da2_t *) p; // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); +#ifdef ENABLE_DA2_DEBUGBLT + if(!(da2->bitblt.debug_exesteps & 0xf)) + da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); + da2->bitblt.debug_exesteps++; +#else da2_log("bitblt_exec: %d\n", da2->bitblt.exec); +#endif // da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: @@ -865,6 +916,60 @@ da2_bitblt_exec(void *p) da2->bitblt.indata = 0; da2_bitblt_load(da2); break; + case DA2_BLT_CLINE: + int pos_x = da2->bitblt.dest_x + da2->bitblt.x; + int pos_y = da2->bitblt.dest_y + da2->bitblt.y; + + /* Draw a dot */ + // outb(0x680, da2->bitblt.octdir); + // da2_log("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); + int destaddr = pos_y * (da2->rowoffset * 2) + pos_x / 8; + int pixelmask = pos_x % 16; + if (pixelmask >= 8) + pixelmask = (0x8000 >> (pixelmask - 8)); + else + pixelmask = (0x80 >> pixelmask); + DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); + // da2_log("draw: %x %x %x\n", destaddr, da2->bitblt.fcolor, pixelmask); + da2->bitblt.count++; + + /* Bresenham's line */ + if (da2->bitblt.octdir & 0x04) { /* dX > dY */ + if (da2->bitblt.octdir & 0x02) { + da2->bitblt.x++; + } else { + da2->bitblt.x--; + } + if (da2->bitblt.d >= 0) { + da2->bitblt.d -= (2 * da2->bitblt.size_x); + if (da2->bitblt.octdir & 0x01) { + da2->bitblt.y++; + } else { + da2->bitblt.y--; + } + } + da2->bitblt.d += (2 * da2->bitblt.size_y); + if (da2->bitblt.count >= da2->bitblt.size_x) + da2->bitblt.exec = DA2_BLT_CDONE; + } else { + if (da2->bitblt.octdir & 0x01) { + da2->bitblt.y++; + } else { + da2->bitblt.y--; + } + if (da2->bitblt.d >= 0) { + da2->bitblt.d -= (2 * da2->bitblt.size_y); + if (da2->bitblt.octdir & 0x02) { + da2->bitblt.x++; + } else { + da2->bitblt.x--; + } + } + da2->bitblt.d += (2 * da2->bitblt.size_x); + if (da2->bitblt.count >= da2->bitblt.size_y) + da2->bitblt.exec = DA2_BLT_CDONE; + } + break; case DA2_BLT_CFILLRECT: // da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); if (da2->bitblt.x >= da2->bitblt.size_x - 1) { @@ -982,11 +1087,14 @@ da2_bitblt_exec(void *p) // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; break; case DA2_BLT_CDONE: - /* initialize regs for debug dump */ - for (int i = 0; i < DA2_BLT_REGSIZE; i++) { - if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) - da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; - } + if (!(da2->bitblt.reg[0x20] & 0x20)) { + /* initialize regs and set magic value for debug dump */ + for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) + da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + } + } else /* without init regs */ + da2->bitblt.reg[0x20] = 0; /* need to stop execution */ if (da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; else @@ -1013,7 +1121,7 @@ da2_bitblt_dopayload(void *priv) // } if (da2->bitblt.exec != DA2_BLT_CIDLE) da2_bitblt_exec(da2); - else if (da2->bitblt.indata) /* for OS/2 J1.3 */ + else if (da2->bitblt.indata) { if (da2->bitblt.exec == DA2_BLT_CIDLE) { da2->bitblt.exec = DA2_BLT_CLOAD; @@ -1339,9 +1447,10 @@ da2_in(uint16_t addr, void *p) } if (da2->bitblt.indata) temp |= 0x08; - da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); +#ifdef ENABLE_DA2_DEBUGMONWAIT + da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); +#endif } - // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr,temp, cs >> 4, cpu_state.pc); break; case LF_INDEX: temp = da2->fctladdr; @@ -2381,7 +2490,7 @@ da2_mmio_readw(uint32_t addr, void *p) for (int i = 0; i < 8; i++) da2->gdcla[i] = (uint16_t) (da2->vram[(addr << 3) | i]) | ((uint16_t) (da2->vram[((addr << 3) + 8) | i]) << 8); /* read vram into latch */ -#ifdef ENABLE_DA2_DEBUGBLT +#ifdef ENABLE_DA2_DEBUGVRAM ////debug // if (((int)addr - (int)da2->mmrdbg_vidaddr) > 2 || (((int)da2->mmrdbg_vidaddr - (int)addr) > 2) || da2->mmrdbg_vidaddr == addr) //{ @@ -2465,7 +2574,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) /* align bitmask to even address */ if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; -#ifdef ENABLE_DA2_DEBUGBLT +#ifdef ENABLE_DA2_DEBUGVRAM da2_log("da2_wB %x %02x\n", addr, val); // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ @@ -2577,7 +2686,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; bitmask <<= 8; bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; -#ifdef ENABLE_DA2_DEBUGBLT +#ifdef ENABLE_DA2_DEBUGVRAM // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { @@ -3061,9 +3170,11 @@ da2_init(UNUSED(const device_t *info)) memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ #ifdef ENABLE_DA2_DEBUGBLT da2->bitblt.debug_reg = malloc(DA2_DEBUG_BLTLOG_MAX * DA2_DEBUG_BLTLOG_SIZE); + da2->bitblt.debug_reg_ip = 0; +#endif +#ifdef ENABLE_DA2_DEBUGVRAM da2->mmdbg_fp = fopen("da2_mmiowdat.txt", "w"); da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); - da2->bitblt.debug_reg_ip = 0; #endif da2->bitblt.payload_addr = 0; da2_reset(da2); @@ -3162,11 +3273,13 @@ da2_close(void *p) } fclose(f); } + free(da2->bitblt.debug_reg); +#endif +#ifdef ENABLE_DA2_DEBUGVRAM if (da2->mmdbg_fp != NULL) fclose(da2->mmdbg_fp); if (da2->mmrdbg_fp != NULL) fclose(da2->mmrdbg_fp); - free(da2->bitblt.debug_reg); #endif free(da2->cram); free(da2->vram); From e9b8bbd0be4c575e5d420fbb24956c660776bcdf Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:59:46 +0900 Subject: [PATCH 0335/1190] add bit invert operation in bitblt --- src/video/vid_ps55da2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index f157d8fca..4922c6d30 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -502,6 +502,8 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s writepx[i] ^= srcpx->p8[i] & mask32.d; break; } + if (da2->bitblt.raster_op & 0x20) /* NOT */ + writepx[i] ^= 0xFFFFFFFF & mask32.d; } for (int i = 0; i < 8; i++) { DA2_vram_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); @@ -524,11 +526,11 @@ Param Desc 01 Color 03 Bit Shift 04 Select plane? -05 Dir(10 or 11) + Command?(40 or 48) +05 Dir(1000h or 1100h) + Command?(40 or 48) 08 Mask Left 09 Mask Right 0A Plane Mask? -0B ROP?(8h or 200h + 0-3h) +0B ROP?(8h or 200h) + Bitop (0 None, 1 AND, 2 OR, 3 XOR) 0D 20 Exec (1) or Exec without reset regs (21h) 21 ? @@ -709,9 +711,9 @@ da2_bitblt_load(da2_t *da2) i++; } da2->bitblt.exec = DA2_BLT_CIDLE; - // /* clear payload memory */ - // memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - // da2->bitblt.payload_addr = 0; + /* clear payload memory */ + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; /* [89] 20: 0001 (1) then execute payload */ if (da2->bitblt.reg[0x20] & 0x1) { /* clear payload memory */ @@ -731,7 +733,7 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.debug_exesteps = 0; #endif da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ - da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x03; /* 01 AND, 03 XOR */ + da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x23; /* 01 AND, 03 XOR */ da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); // for (int i = 0; i <= 0xb; i++) // { @@ -780,7 +782,6 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; @@ -797,7 +798,6 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; - da2->bitblt.raster_op = da2->bitblt.reg[0x05] & 0x03; /* XOR */ da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; From 813afb8562d8cab16c7fdc88ad066015504584d7 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 26 Feb 2025 04:16:36 +0900 Subject: [PATCH 0336/1190] change bitblt exec speed slower probably the real machine is slower than this --- src/video/vid_ps55da2.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 4922c6d30..fa43ebeb6 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -532,7 +532,7 @@ Param Desc 0A Plane Mask? 0B ROP?(8h or 200h) + Bitop (0 None, 1 AND, 2 OR, 3 XOR) 0D -20 Exec (1) or Exec without reset regs (21h) +20 Exec (1) or Exec without reset regs? (21h) 21 ? 22 ? 23 Tile W @@ -762,12 +762,6 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.exec = DA2_BLT_CDONE; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - // if (da2->bitblt.reg[0x2f] < 0x80) /* MS Paint 3.1 will cause hang up in 256 color mode */ - // { - // da2_log("bitblt not executed 2f:%x\n", da2->bitblt.reg[0x2f]); - // da2->bitblt.exec = DA2_BLT_CDONE; - // } else - /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ if (da2->bitblt.reg[0x10] == 0xbc04) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; @@ -810,15 +804,11 @@ da2_bitblt_load(da2_t *da2) } /* Draw a line */ else if (da2->bitblt.reg[0x5] == 0x43) { - // da2_log("drawline x=%d, y=%d, 24=%d, 2A=%d, 2B=%d, 2D=%d\n", - // da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - // n24, n2a, n2b, da2->bitblt.reg[0x2D]); da2->bitblt.exec = DA2_BLT_CLINE; da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0x7ff); da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0x7ff); da2->bitblt.size_x = abs((da2->bitblt.reg[0x33] & 0x7ff) - (da2->bitblt.reg[0x32] & 0x7ff)); da2->bitblt.size_y = abs((da2->bitblt.reg[0x35] & 0x7ff) - (da2->bitblt.reg[0x34] & 0x7ff)); - // da2->bitblt.raster_op = 0; da2->bitblt.count = 0; da2->bitblt.octdir = da2->bitblt.reg[0x2D]; da2->bitblt.bitshift_destr = 0; @@ -829,13 +819,6 @@ da2_bitblt_load(da2_t *da2) da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%d\n", da2->bitblt.dest_x, da2->bitblt.dest_y, da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); - // FILE *f = fopen("da2_drawline.csv", "a"); - // if (f != NULL) { - // fprintf(f,"drawline,%d,%d,%d,%d,%d,%d\n", - // da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - // n24, n2a, n2b, da2->bitblt.reg[0x2D]); - // fclose(f); - // } } /* Fill a rectangle (or draw a horizontal / vertical line) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { @@ -922,7 +905,7 @@ da2_bitblt_exec(void *p) /* Draw a dot */ // outb(0x680, da2->bitblt.octdir); - // da2_log("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); + da2_log("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); int destaddr = pos_y * (da2->rowoffset * 2) + pos_x / 8; int pixelmask = pos_x % 16; if (pixelmask >= 8) @@ -1107,26 +1090,15 @@ da2_bitblt_dopayload(void *priv) { da2_t *da2 = (da2_t *) priv; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - // if (da2->bitblt.indata) /* for OS/2 J1.3 */ - // { - // if (da2->bitblt.exec == DA2_BLT_CIDLE) { - // da2->bitblt.exec = DA2_BLT_CLOAD; - // /* do all queues (ignore async executing) for OS/2 J1.3 commannd prompt that doesn't wait for idle */ - // da2_log("da2 Do bitblt\n"); - // while (da2->bitblt.exec != DA2_BLT_CIDLE) { - // da2_bitblt_exec(da2); - // } - // da2_log("da2 End bitblt %x\n", da2->bitblt.exec); - // } - // } if (da2->bitblt.exec != DA2_BLT_CIDLE) da2_bitblt_exec(da2); - else if (da2->bitblt.indata) - { + else if (da2->bitblt.indata) { if (da2->bitblt.exec == DA2_BLT_CIDLE) { da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); } + } else { + // timer_disable(&da2->bitblt.timer); } } @@ -3189,7 +3161,7 @@ da2_init(UNUSED(const device_t *info)) mem_mapping_disable(&da2->cmapping); timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 1 * TIMER_USEC; + da2->bitblt.timerspeed = 10 * TIMER_USEC; timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; From 168910b72ff1820a2524b642496483a910ecc81b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Feb 2025 11:39:04 +0600 Subject: [PATCH 0337/1190] All held-down keys are now released when Alt-Tab'ing out Only applies when Raw Input is in use on Windows --- src/device/keyboard.c | 14 ++++++++++++++ src/include/86box/keyboard.h | 1 + src/qt/qt_mainwindow.cpp | 2 ++ 3 files changed, 17 insertions(+) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 582dcf0b1..58d5a4724 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -332,6 +332,20 @@ keyboard_input(int down, uint16_t scan) } } +void +keyboard_all_up(void) +{ + for (unsigned short i = 0; i < 0x200; i++) { + if (recv_key_ui[i]) { + recv_key_ui[i] = 0; + } + if (recv_key[i]) { + recv_key[i] = 0; + key_process(i, 0); + } + } +} + static uint8_t keyboard_do_break(uint16_t scan) { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index ec5c05775..110e4f760 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -269,6 +269,7 @@ extern void keyboard_poll_host(void); extern void keyboard_process(void); extern uint16_t keyboard_convert(int ch); extern void keyboard_input(int down, uint16_t scan); +extern void keyboard_all_up(void); extern void keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl); extern uint8_t keyboard_get_shift(void); extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 3ee58f23b..62ac94f30 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -277,6 +277,8 @@ MainWindow::MainWindow(QWidget *parent) if (mouse_capture) emit setMouseCapture(false); + keyboard_all_up(); + if (do_auto_pause && !dopause) { auto_paused = 1; plat_pause(1); From 6d3816df64aac6cb0e604bab30239c3b4b888265 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 01:03:00 +0600 Subject: [PATCH 0338/1190] x87: Fix Final Reality discolored screen for interpreter --- src/cpu/x87_ops.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index f1362bf76..276c32876 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -113,12 +113,33 @@ typedef union { static __inline void x87_push(double i) { +#ifdef X87_INLINE_ASM + unsigned char buffer[10]; +#else + x87_conv_t test; +#endif #ifdef USE_NEW_DYNAREC cpu_state.TOP--; #else cpu_state.TOP = (cpu_state.TOP - 1) & 7; #endif cpu_state.ST[cpu_state.TOP & 7] = i; + +#ifdef X87_INLINE_ASM + __asm volatile("" + : + : + : "memory"); + + __asm volatile("fldl %1\n" + "fstpt %0\n" : "=m"(buffer) : "m"(i)); + + cpu_state.MM[cpu_state.TOP & 7].q = (*(uint64_t*)buffer); +#else + x87_to80(i, &test); + cpu_state.MM[cpu_state.TOP & 7].q = test.eind.ll; +#endif + #ifdef USE_NEW_DYNAREC cpu_state.tag[cpu_state.TOP & 7] = TAG_VALID; #else @@ -129,6 +150,11 @@ x87_push(double i) static __inline void x87_push_u64(uint64_t i) { +#ifdef X87_INLINE_ASM + unsigned char buffer[10]; +#else + x87_conv_t test; +#endif union { double d; uint64_t ll; @@ -142,6 +168,21 @@ x87_push_u64(uint64_t i) cpu_state.TOP = (cpu_state.TOP - 1) & 7; #endif cpu_state.ST[cpu_state.TOP & 7] = td.d; + +#ifdef X87_INLINE_ASM + __asm volatile("" + : + : + : "memory"); + + __asm volatile("fldl %1\n" + "fstpt %0\n" : "=m"(buffer) : "m"(td.d)); + + cpu_state.MM[cpu_state.TOP & 7].q = (*(uint64_t*)buffer); +#else + x87_to80(td.d, &test); + cpu_state.MM[cpu_state.TOP & 7].q = test.eind.ll; +#endif #ifdef USE_NEW_DYNAREC cpu_state.tag[cpu_state.TOP & 7] = TAG_VALID; #else From 3cde104ff683bb91c71768d32fbd8c8a26bf643b Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 27 Feb 2025 08:29:06 +0900 Subject: [PATCH 0339/1190] add inversion ROPs (still in debug) --- src/video/vid_ps55da2.c | 75 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index fa43ebeb6..91752a7a8 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -387,13 +387,13 @@ typedef struct da2_t { int bitshift_destr; int raster_op; uint8_t payload[DA2_BLT_MEMSIZE]; + int payload_addr; int32_t reg[DA2_BLT_REGSIZE]; // must be signed int #ifdef ENABLE_DA2_DEBUGBLT int32_t *debug_reg; // for debug int debug_reg_ip; // for debug int debug_exesteps; #endif - int payload_addr; pc_timer_t timer; int64_t timerspeed; int exec; @@ -409,7 +409,6 @@ typedef struct da2_t { int32_t fcolor; int32_t maskl, maskr; int32_t count; - // int32_t countj; int32_t d; int octdir; int x, y; @@ -460,7 +459,7 @@ DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) da2->vram[addr & da2->vram_mask] = val; return; } - +/* write pixel data with rop (Note: bitmask must be in big endian) */ void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) { @@ -487,7 +486,11 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s for (int i = 0; i < 8; i++) { if (da2->bitblt.bitshift_destr > 0) srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; - switch (da2->bitblt.raster_op) { + if (da2->bitblt.raster_op & 0x2010) /* NOT Src or NOT Pattern */ + srcpx->p8[i] = ~srcpx->p8[i] & mask32.d; + if (da2->bitblt.raster_op & 0x20) /* Dest NOT */ + writepx[i] = (~writepx[i] & mask32.d) | (writepx[i] & ~mask32.d); + switch (da2->bitblt.raster_op & 0x03) { case 0x00: /* None */ writepx[i] &= ~mask32.d; writepx[i] |= srcpx->p8[i] & mask32.d; @@ -502,8 +505,6 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s writepx[i] ^= srcpx->p8[i] & mask32.d; break; } - if (da2->bitblt.raster_op & 0x20) /* NOT */ - writepx[i] ^= 0xFFFFFFFF & mask32.d; } for (int i = 0; i < 8; i++) { DA2_vram_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); @@ -530,7 +531,13 @@ Param Desc 08 Mask Left 09 Mask Right 0A Plane Mask? -0B ROP?(8h or 200h) + Bitop (0 None, 1 AND, 2 OR, 3 XOR) +0B ROP + 2000 NOT Source + 200 Source / Pattern + 20 NOT Dest + 10 NOT Pattern + 8 ? + 0-3 Bit op (0 None, 1 AND, 2 OR, 3 XOR) 0D 20 Exec (1) or Exec without reset regs? (21h) 21 ? @@ -602,7 +609,7 @@ print_bytetobin(uint8_t b) b <<= 1; } } -// Convert internal char code to Shift JIS code +/* Convert internal char code to Shift JIS code */ inline int isKanji1(uint8_t chr) { @@ -649,17 +656,19 @@ da2_bitblt_load(da2_t *da2) { uint32_t value32; uint64_t value64; +#ifdef ENABLE_DA2_DEBUGBLT da2_log("bltload: loading params\n"); - // da2_log("BitBlt memory:\n"); - // if (da2->bitblt.payload[0] != 0) - // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) - // { - // int i = j * 8; - // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - // da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - // } + da2_log("BitBlt memory:\n"); + if (da2->bitblt.payload[0] != 0) + for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) + { + int i = j * 8; + da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); + } +#endif int i = 0; - while (i < DA2_BLT_MEMSIZE) { + while (i < da2->bitblt.payload_addr) { if (da2->bitblt.reg[0x20] & 0x1) break; switch (da2->bitblt.payload[i]) { @@ -712,36 +721,26 @@ da2_bitblt_load(da2_t *da2) } da2->bitblt.exec = DA2_BLT_CIDLE; /* clear payload memory */ - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - da2->bitblt.payload_addr = 0; + // memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + // da2->bitblt.payload_addr = 0; /* [89] 20: 0001 (1) then execute payload */ if (da2->bitblt.reg[0x20] & 0x1) { /* clear payload memory */ memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); da2->bitblt.payload_addr = 0; #ifdef ENABLE_DA2_DEBUGBLT - for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { - // if(da2->bitblt.reg[i] != 0xfefe && da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) da2_log("%02x: %04x (%d)\n",i, da2->bitblt.reg[i], da2->bitblt.reg[i]); - } for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; } da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; da2->bitblt.debug_reg_ip++; - if (da2->bitblt.debug_reg_ip >= DA2_DEBUG_BLTLOG_MAX) + if ((DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip) >= DA2_DEBUG_BLTLOG_MAX) da2->bitblt.debug_reg_ip = 0; da2->bitblt.debug_exesteps = 0; #endif - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ - da2->bitblt.raster_op = da2->bitblt.reg[0x0b] & 0x23; /* 01 AND, 03 XOR */ da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); - // for (int i = 0; i <= 0xb; i++) - // { - // da2_log("%02x ", da2->gdcreg[i]); - // da2->gdcreg[i] = da2->bitblt.reg[i] & 0xff; - // } - // da2_log("\n"); - + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ + da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; da2->bitblt.destaddr = da2->bitblt.reg[0x29]; da2->bitblt.size_x = da2->bitblt.reg[0x33]; da2->bitblt.size_y = da2->bitblt.reg[0x35]; @@ -890,14 +889,13 @@ da2_bitblt_exec(void *p) #else da2_log("bitblt_exec: %d\n", da2->bitblt.exec); #endif - // da2_log("blt %x %x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: // timer_disable(&da2->bitblt.timer); break; case DA2_BLT_CLOAD: - da2->bitblt.indata = 0; da2_bitblt_load(da2); + da2->bitblt.indata = 0; break; case DA2_BLT_CLINE: int pos_x = da2->bitblt.dest_x + da2->bitblt.x; @@ -1512,7 +1510,7 @@ da2_outb(uint16_t addr, uint8_t val, void *p) void da2_outw(uint16_t addr, uint16_t val, void *p) { - da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + // da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; switch (addr) { @@ -2534,8 +2532,10 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2->bitblt.indata = 1; if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; + else { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + } break; default: da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); @@ -3008,7 +3008,6 @@ da2_loadfont(char *fname, void *p) { da2_t *da2 = (da2_t *) p; uint8_t buf; - // uint32_t code = 0; uint64_t fsize; if (!fname) return; From e49be34d3070730b63053a0df9bdffa833c01e8e Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 27 Feb 2025 11:15:57 +0900 Subject: [PATCH 0340/1190] fix an issue when loading bitblt data in async --- src/video/vid_ps55da2.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 91752a7a8..f8c72833e 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -273,6 +273,11 @@ da2_log(const char *fmt, ...) #else # define da2_log(fmt, ...) #endif +#ifdef ENABLE_DA2_DEBUGBLT +# define da2_bltlog da2_log +#else +# define da2_bltlog(fmt, ...) +#endif typedef struct da2_t { // mem_mapping_t vmapping; @@ -678,7 +683,7 @@ da2_bitblt_load(da2_t *da2) value32 = da2->bitblt.payload[i + 3]; value32 <<= 8; value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2_bltlog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; i += 3; break; @@ -690,7 +695,7 @@ da2_bitblt_load(da2_t *da2) value32 |= da2->bitblt.payload[i + 3]; value32 <<= 8; value32 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); + da2_bltlog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; i += 5; break; @@ -706,7 +711,7 @@ da2_bitblt_load(da2_t *da2) value64 |= da2->bitblt.payload[i + 3]; value64 <<= 8; value64 |= da2->bitblt.payload[i + 2]; - da2_log("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2_bltlog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; i += 7; @@ -721,13 +726,10 @@ da2_bitblt_load(da2_t *da2) } da2->bitblt.exec = DA2_BLT_CIDLE; /* clear payload memory */ - // memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - // da2->bitblt.payload_addr = 0; + memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); + da2->bitblt.payload_addr = 0; /* [89] 20: 0001 (1) then execute payload */ if (da2->bitblt.reg[0x20] & 0x1) { - /* clear payload memory */ - memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); - da2->bitblt.payload_addr = 0; #ifdef ENABLE_DA2_DEBUGBLT for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; @@ -759,7 +761,6 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.x = 0; da2->bitblt.y = 0; da2->bitblt.exec = DA2_BLT_CDONE; - timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ if (da2->bitblt.reg[0x10] == 0xbc04) { @@ -886,8 +887,6 @@ da2_bitblt_exec(void *p) if(!(da2->bitblt.debug_exesteps & 0xf)) da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); da2->bitblt.debug_exesteps++; -#else - da2_log("bitblt_exec: %d\n", da2->bitblt.exec); #endif switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: @@ -903,7 +902,7 @@ da2_bitblt_exec(void *p) /* Draw a dot */ // outb(0x680, da2->bitblt.octdir); - da2_log("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); + da2_bltlog("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); int destaddr = pos_y * (da2->rowoffset * 2) + pos_x / 8; int pixelmask = pos_x % 16; if (pixelmask >= 8) @@ -1090,11 +1089,9 @@ da2_bitblt_dopayload(void *priv) timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); if (da2->bitblt.exec != DA2_BLT_CIDLE) da2_bitblt_exec(da2); - else if (da2->bitblt.indata) { - if (da2->bitblt.exec == DA2_BLT_CIDLE) { + else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); - } } else { // timer_disable(&da2->bitblt.timer); } @@ -2656,6 +2653,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *) p; uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + addr &= DA2_MASK_MMIO; bitmask <<= 8; bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGVRAM @@ -2676,7 +2674,6 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) //} #endif cycles -= video_timing_write_w; - // cycles_lost += video_timing_write_w; // da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); // da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); @@ -2765,7 +2762,6 @@ da2_mmio_writew(uint32_t addr, uint16_t val, void *p) da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ - addr &= DA2_MASK_MMIO; // return; // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_gc_writeW(addr, val, da2); @@ -2808,8 +2804,8 @@ static uint8_t da2_code_read(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; - if ((addr & ~DA2_MASK_CRAM) != 0xE0000) - return DA2_INVALIDACCESS8; + // if ((addr & ~DA2_MASK_CRAM) != 0xE0000) + // return DA2_INVALIDACCESS8; addr &= DA2_MASK_CRAM; return da2->cram[addr]; } From 03dd94f361259b102fad8cfce2592fa81b801ee8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 13:50:45 +0600 Subject: [PATCH 0341/1190] x87: Fix Final Reality discolored screen for all dynarecs --- src/codegen/codegen_ops_x86-64.h | 14 +++++++++ src/codegen/codegen_ops_x86.h | 7 +++++ src/codegen_new/codegen_ops_helpers.h | 3 ++ src/cpu/386_dynarec.c | 45 +++++++++++++++++++++++++++ src/cpu/cpu.h | 6 ++++ 5 files changed, 75 insertions(+) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index e46f55a05..01fb292cf 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -3571,6 +3571,8 @@ FP_FLD(int reg) addbyte(0x89); /*MOV [TOP], EBX*/ addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3688,6 +3690,8 @@ FP_LOAD_S(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_D(void) @@ -3717,6 +3721,8 @@ FP_LOAD_D(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3754,6 +3760,8 @@ FP_LOAD_IW(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IL(void) @@ -3787,6 +3795,8 @@ FP_LOAD_IL(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IQ(void) @@ -3831,6 +3841,8 @@ FP_LOAD_IQ(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3863,6 +3875,8 @@ FP_LOAD_IMM_Q(uint64_t v) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); addbyte(v ? 0 : 1); + + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index c48324c2a..3b47d81a9 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -1794,6 +1794,7 @@ FP_FLD(int reg) addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -2037,6 +2038,7 @@ FP_LOAD_S(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_D(void) @@ -2096,6 +2098,7 @@ FP_LOAD_D(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IW(void) @@ -2154,6 +2157,7 @@ FP_LOAD_IW(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IL(void) @@ -2210,6 +2214,7 @@ FP_LOAD_IL(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IQ(void) @@ -2285,6 +2290,7 @@ FP_LOAD_IQ(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -2336,6 +2342,7 @@ FP_LOAD_IMM_Q(uint64_t v) addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); } + CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline int diff --git a/src/codegen_new/codegen_ops_helpers.h b/src/codegen_new/codegen_ops_helpers.h index 92b721099..2304aa542 100644 --- a/src/codegen_new/codegen_ops_helpers.h +++ b/src/codegen_new/codegen_ops_helpers.h @@ -64,6 +64,9 @@ fpu_POP2(codeblock_t *block, ir_data_t *ir) static inline void fpu_PUSH(codeblock_t *block, ir_data_t *ir) { + uop_LOAD_FUNC_ARG_IMM(ir, 0, ((uint16_t)cpu_state.TOP - 1)); + uop_CALL_FUNC(ir, x87_to_mmxreg); + if (block->flags & CODEBLOCK_STATIC_TOP) uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP - 1); else diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5f41c416a..5cb385122 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -74,6 +74,51 @@ x386_dynarec_log(const char *fmt, ...) # define x386_dynarec_log(fmt, ...) #endif +/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ +#if defined(_MSC_VER) && !defined(__clang__) +# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 +# define X87_INLINE_ASM +# endif +#else +# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 || defined __amd64__ +# define X87_INLINE_ASM +# endif +#endif + +#ifdef USE_NEW_DYNAREC +void +x87_to_mmxreg(uint16_t reg) +#else +void +x87_to_mmxreg(void) +#endif +{ +#ifndef USE_NEW_DYNAREC + uint32_t reg = cpu_state.TOP & 7; +#endif + double val = cpu_state.ST[reg & 7]; +#ifdef X87_INLINE_ASM + unsigned char buffer[10]; +#else + x87_conv_t test; +#endif + +#ifdef X87_INLINE_ASM + __asm volatile("" + : + : + : "memory"); + + __asm volatile("fldl %1\n" + "fstpt %0\n" : "=m"(buffer) : "m"(val)); + + cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); +#else + x87_to80(val, &test); + cpu_state.MM[reg & 7].q = test.eind.ll; +#endif +} + static __inline void fetch_ea_32_long(uint32_t rmdat) { diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 1d003ddc9..98c6f4938 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -829,6 +829,12 @@ extern uint16_t prefetch_queue_get_ip(void); extern int prefetch_queue_get_prefetching(void); extern int prefetch_queue_get_size(void); +#ifdef USE_NEW_DYNAREC +extern void x87_to_mmxreg(uint16_t reg); +#else +extern void x87_to_mmxreg(void); +#endif + #define prefetch_queue_set_suspended(s) prefetch_queue_set_prefetching(!s) #define prefetch_queue_get_suspended !prefetch_queue_get_prefetching From c7153916eb21c67647e4df2512cda9b8776e5653 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 14:33:44 +0600 Subject: [PATCH 0342/1190] Fix compile on ARM64 --- src/cpu/386_dynarec.c | 70 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5cb385122..04681c9dc 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -74,7 +74,6 @@ x386_dynarec_log(const char *fmt, ...) # define x386_dynarec_log(fmt, ...) #endif -/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ #if defined(_MSC_VER) && !defined(__clang__) # if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 # define X87_INLINE_ASM @@ -85,40 +84,6 @@ x386_dynarec_log(const char *fmt, ...) # endif #endif -#ifdef USE_NEW_DYNAREC -void -x87_to_mmxreg(uint16_t reg) -#else -void -x87_to_mmxreg(void) -#endif -{ -#ifndef USE_NEW_DYNAREC - uint32_t reg = cpu_state.TOP & 7; -#endif - double val = cpu_state.ST[reg & 7]; -#ifdef X87_INLINE_ASM - unsigned char buffer[10]; -#else - x87_conv_t test; -#endif - -#ifdef X87_INLINE_ASM - __asm volatile("" - : - : - : "memory"); - - __asm volatile("fldl %1\n" - "fstpt %0\n" : "=m"(buffer) : "m"(val)); - - cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); -#else - x87_to80(val, &test); - cpu_state.MM[reg & 7].q = test.eind.ll; -#endif -} - static __inline void fetch_ea_32_long(uint32_t rmdat) { @@ -278,6 +243,41 @@ fetch_ea_16_long(uint32_t rmdat) # define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) #endif +/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ +#ifdef USE_NEW_DYNAREC +void +x87_to_mmxreg(uint16_t reg) +#else +void +x87_to_mmxreg(void) +#endif +{ +#ifndef USE_NEW_DYNAREC + uint32_t reg = cpu_state.TOP & 7; +#endif + double val = cpu_state.ST[reg & 7]; +#ifdef X87_INLINE_ASM + unsigned char buffer[10]; +#else + x87_conv_t test; +#endif + +#ifdef X87_INLINE_ASM + __asm volatile("" + : + : + : "memory"); + + __asm volatile("fldl %1\n" + "fstpt %0\n" : "=m"(buffer) : "m"(val)); + + cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); +#else + x87_to80(val, &test); + cpu_state.MM[reg & 7].q = test.eind.ll; +#endif +} + #ifdef USE_DYNAREC int32_t cycles_main = 0; static int32_t cycles_old = 0; From fc656cbe0519b1a108aef25a333bf61cd5131cf8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 16:31:27 +0600 Subject: [PATCH 0343/1190] Mouse cursor now properly appears after uncapture --- src/qt/qt_mainwindow.cpp | 4 +++- src/qt/qt_rendererstack.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 62ac94f30..89d17a07c 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -262,8 +262,10 @@ MainWindow::MainWindow(QWidget *parent) ui->stackedWidget->mouse_capture_func(this->windowHandle()); } else { this->releaseKeyboard(); - if (ui->stackedWidget->mouse_uncapture_func) + if (ui->stackedWidget->mouse_uncapture_func) { ui->stackedWidget->mouse_uncapture_func(); + } + ui->stackedWidget->unsetCursor(); } }); diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index a8bd47a79..8c31da2b2 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -155,7 +155,7 @@ RendererStack::mouseReleaseEvent(QMouseEvent *event) } if (mouse_capture && (event->button() == Qt::MiddleButton) && (mouse_get_buttons() < 3)) { plat_mouse_capture(0); - this->setCursor(Qt::ArrowCursor); + this->unsetCursor(); isMouseDown &= ~1; return; } From 95f12bc206e955324731bfcac18025f034d6db09 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 28 Feb 2025 00:50:01 +0900 Subject: [PATCH 0344/1190] fix glitch in Bitblt's line drawing function fix a line glitch issue occurs in MS Paint and QEMM Manifest apps. --- src/video/vid_ps55da2.c | 58 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index f8c72833e..c476d12b9 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -405,10 +405,11 @@ typedef struct da2_t { int indata; int32_t destaddr; int32_t srcaddr; - int32_t size_x, tile_w; - int32_t size_y; - int32_t dest_x; - int32_t dest_y; + int16_t size_x; + int16_t tile_w; + int16_t size_y; + int16_t dest_x; + int16_t dest_y; int16_t destpitch; int16_t srcpitch; int32_t fcolor; @@ -416,7 +417,7 @@ typedef struct da2_t { int32_t count; int32_t d; int octdir; - int x, y; + int x, y, wx1, wx2, wy1, wy2; } bitblt; #ifdef ENABLE_DA2_DEBUGVRAM @@ -805,20 +806,32 @@ da2_bitblt_load(da2_t *da2) /* Draw a line */ else if (da2->bitblt.reg[0x5] == 0x43) { da2->bitblt.exec = DA2_BLT_CLINE; - da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0x7ff); - da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0x7ff); - da2->bitblt.size_x = abs((da2->bitblt.reg[0x33] & 0x7ff) - (da2->bitblt.reg[0x32] & 0x7ff)); - da2->bitblt.size_y = abs((da2->bitblt.reg[0x35] & 0x7ff) - (da2->bitblt.reg[0x34] & 0x7ff)); - da2->bitblt.count = 0; - da2->bitblt.octdir = da2->bitblt.reg[0x2D]; + da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0xffff); + da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0xffff); + da2->bitblt.wx1 = (da2->bitblt.reg[0x32]) >> 16; + da2->bitblt.wx2 = (da2->bitblt.reg[0x33]) >> 16; + da2->bitblt.wy1 = (da2->bitblt.reg[0x34]) >> 16; + da2->bitblt.wy2 = (da2->bitblt.reg[0x35]) >> 16; + da2->bitblt.size_x = abs((int16_t)(da2->bitblt.reg[0x33] & 0xffff) - da2->bitblt.dest_x); + da2->bitblt.size_y = abs((int16_t)(da2->bitblt.reg[0x35] & 0xffff) - da2->bitblt.dest_y); + da2->bitblt.count = 0; + da2->bitblt.octdir = da2->bitblt.reg[0x2D]; da2->bitblt.bitshift_destr = 0; if (da2->bitblt.octdir & 0x04) /* dX > dY */ da2->bitblt.d = 2 * da2->bitblt.size_y - da2->bitblt.size_x; else da2->bitblt.d = 2 * da2->bitblt.size_x - da2->bitblt.size_y; - da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%d\n", + da2->bitblt.x = da2->bitblt.dest_x; + da2->bitblt.y = da2->bitblt.dest_y; + da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%dn", da2->bitblt.dest_x, da2->bitblt.dest_y, da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); + da2_log(" x1=%d, x2=%d, y1=%d, y2=%d\n", + da2->bitblt.reg[0x32] & 0x7ff, da2->bitblt.reg[0x33] & 0x7ff, + da2->bitblt.reg[0x34] & 0x7ff, da2->bitblt.reg[0x35] & 0x7ff); + da2_log(" ux1=%d,ux2=%d,uy1=%d,uy2=%d\n", + (da2->bitblt.reg[0x32] >> 16) & 0x7ff, (da2->bitblt.reg[0x33] >> 16) & 0x7ff, + (da2->bitblt.reg[0x34] >> 16) & 0x7ff, (da2->bitblt.reg[0x35] >> 16) & 0x7ff); } /* Fill a rectangle (or draw a horizontal / vertical line) */ else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { @@ -884,7 +897,7 @@ da2_bitblt_exec(void *p) da2_t *da2 = (da2_t *) p; // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); #ifdef ENABLE_DA2_DEBUGBLT - if(!(da2->bitblt.debug_exesteps & 0xf)) + if(!(da2->bitblt.debug_exesteps & 0xff)) da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); da2->bitblt.debug_exesteps++; #endif @@ -897,23 +910,26 @@ da2_bitblt_exec(void *p) da2->bitblt.indata = 0; break; case DA2_BLT_CLINE: - int pos_x = da2->bitblt.dest_x + da2->bitblt.x; - int pos_y = da2->bitblt.dest_y + da2->bitblt.y; - /* Draw a dot */ // outb(0x680, da2->bitblt.octdir); - da2_bltlog("point: %d %d %d %d %d\n", pos_x, pos_y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); - int destaddr = pos_y * (da2->rowoffset * 2) + pos_x / 8; - int pixelmask = pos_x % 16; + da2_bltlog("point: %d %d %d %d %d\n", da2->bitblt.x, da2->bitblt.y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); + int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; + int pixelmask = da2->bitblt.x % 16; if (pixelmask >= 8) pixelmask = (0x8000 >> (pixelmask - 8)); else pixelmask = (0x80 >> pixelmask); - DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); + + /* check the current position is inside the window */ + if (da2->bitblt.x < da2->bitblt.wx1 || da2->bitblt.x > da2->bitblt.wx2 + || da2->bitblt.y < da2->bitblt.wy1 || da2->bitblt.y > da2->bitblt.wy2) + ; + else + DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); // da2_log("draw: %x %x %x\n", destaddr, da2->bitblt.fcolor, pixelmask); da2->bitblt.count++; - /* Bresenham's line */ + /* calculate the next position with Bresenham's line algorithm */ if (da2->bitblt.octdir & 0x04) { /* dX > dY */ if (da2->bitblt.octdir & 0x02) { da2->bitblt.x++; From 95f30192e5cb7b20755c1235625c107a3391fe93 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 22:09:55 +0600 Subject: [PATCH 0345/1190] USB multimedia keys now work on Windows --- src/qt/qt_main.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 72b0eef53..7723261b4 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -211,8 +211,121 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) (GetForegroundWindow() == ((HWND) secondaryRenderer->winId()))); } - if ((nCode < 0) || (nCode != HC_ACTION) || !is_over_window) + bool skip = ((nCode < 0) || (nCode != HC_ACTION) || !is_over_window); + + if (skip) return CallNextHookEx(NULL, nCode, wParam, lParam); + + /* USB keyboards send a scancode of 0x00 for multimedia keys. */ + if (lpKdhs->scanCode == 0x00) { + /* Handle USB keyboard multimedia keys where possible. + Only a handful of keys can be handled via Virtual Key + detection; rest can't be reliably detected. */ + DWORD vkCode = lpKdhs->vkCode; + bool up = !!(lpKdhs->flags & LLKHF_UP); + ret = CallNextHookEx(NULL, nCode, wParam, lParam);; + + switch (vkCode) + { + case VK_MEDIA_PLAY_PAUSE: + { + win_keyboard_handle(0x22, up, 1, 0); + break; + } + case VK_MEDIA_STOP: + { + win_keyboard_handle(0x24, up, 1, 0); + break; + } + case VK_VOLUME_UP: + { + win_keyboard_handle(0x30, up, 1, 0); + break; + } + case VK_VOLUME_DOWN: + { + win_keyboard_handle(0x2E, up, 1, 0); + break; + } + case VK_VOLUME_MUTE: + { + win_keyboard_handle(0x20, up, 1, 0); + break; + } + case VK_MEDIA_NEXT_TRACK: + { + win_keyboard_handle(0x19, up, 1, 0); + break; + } + case VK_MEDIA_PREV_TRACK: + { + win_keyboard_handle(0x10, up, 1, 0); + break; + } + case VK_LAUNCH_MEDIA_SELECT: + { + win_keyboard_handle(0x6D, up, 1, 0); + break; + } + case VK_LAUNCH_MAIL: + { + win_keyboard_handle(0x6C, up, 1, 0); + break; + } + case VK_LAUNCH_APP1: + { + win_keyboard_handle(0x6B, up, 1, 0); + break; + } + case VK_LAUNCH_APP2: + { + win_keyboard_handle(0x21, up, 1, 0); + break; + } + case VK_BROWSER_BACK: + { + win_keyboard_handle(0x6A, up, 1, 0); + break; + } + case VK_BROWSER_FORWARD: + { + win_keyboard_handle(0x69, up, 1, 0); + break; + } + case VK_BROWSER_STOP: + { + win_keyboard_handle(0x68, up, 1, 0); + break; + } + case VK_BROWSER_HOME: + { + win_keyboard_handle(0x32, up, 1, 0); + break; + } + case VK_BROWSER_SEARCH: + { + win_keyboard_handle(0x65, up, 1, 0); + break; + } + case VK_BROWSER_REFRESH: + { + win_keyboard_handle(0x67, up, 1, 0); + break; + } + case VK_BROWSER_FAVORITES: + { + win_keyboard_handle(0x66, up, 1, 0); + break; + } + case VK_HELP: + { + win_keyboard_handle(0x3b, up, 1, 0); + break; + } + } + + return ret; + } else if ((lpKdhs->scanCode == 0x01) && (lpKdhs->flags & LLKHF_ALTDOWN) && !(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED))) ret = TRUE; From 86342bfffe057d4ff01b18b05cd89816228c636c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Feb 2025 23:26:42 +0600 Subject: [PATCH 0346/1190] OS/2 3.0 icon backgrounds are now drawn properly --- src/video/vid_mga.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 3937c2a7d..f11983a20 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -4677,6 +4677,7 @@ blit_trap(mystique_t *mystique) int err_l = (int32_t)mystique->dwgreg.ar[1]; int err_r = (int32_t)mystique->dwgreg.ar[4]; const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + bool transc = !!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC); switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { case DWGCTRL_ATYPE_BLK: @@ -4699,6 +4700,7 @@ blit_trap(mystique_t *mystique) int pattern = mystique->dwgreg.pattern[yoff][xoff]; uint32_t dst; + if (!transc || (transc && pattern)) switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { case MACCESS_PWIDTH_8: svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xff; @@ -4770,6 +4772,7 @@ blit_trap(mystique_t *mystique) uint32_t dst; uint32_t old_dst; + if (!transc || (transc && pattern)) switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { case MACCESS_PWIDTH_8: dst = svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]; From 726ce6c574076807772b4cbcfaedcfb309b2555d Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:29:17 +0900 Subject: [PATCH 0347/1190] modify video memory mask and screen updating --- src/video/vid_ps55da2.c | 109 ++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index c476d12b9..441df620b 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -50,25 +50,29 @@ #define DA2_FONTROM_PATH_JPAN "roms/video/da2/94X1320.BIN" #define DA2_FONTROM_PATH_HANT "roms/video/da2/23F2698.BIN" -#define DA2_FONTROM_SIZE 1536 * 1024 +#define DA2_FONTROM_SIZE (1536 * 1024) #define DA2_FONTROM_BASESBCS 0x98000 #define DA2_GAIJIRAM_SBCS 0x34000 #define DA2_GAIJIRAM_SBEX 0x3c000 #define DA2_VM03_BASECHR 0x18000 #define DA2_VM03_BASEEXATTR 0x10000 -#define DA2_INVALIDACCESS8 0xff +#define DA2_INVALIDACCESS8 0xffu +#define DA2_INVALIDACCESS16 0xffffu +#define DA2_INVALIDACCESS32 0xffffffffu #define DA2_MASK_MMIO 0x1ffff -#define DA2_SIZE_VRAM 1024 * 1024 /* 0x100000 */ -#define DA2_SIZE_CRAM 4 * 1024 /* 0x1000 */ -#define DA2_SIZE_GAIJIRAM 256 * 1024 /* 0x40000 */ -#define DA2_MASK_A000 0x1ffff -#define DA2_MASK_CRAM 0xfff -#define DA2_MASK_GAIJIRAM 0x3ffff -#define DA2_PIXELCLOCK 58000000.0 +#define DA2_SIZE_VRAM (1024 * 1024) /* 0x100000 */ +#define DA2_SIZE_CRAM (4 * 1024) /* 0x1000 */ +#define DA2_SIZE_GAIJIRAM (256 * 1024) /* 0x40000 */ +#define DA2_MASK_A000 0x1ffff /* 0x1FFFF */ +#define DA2_MASK_CRAM 0xfff /* 0xFFF */ +#define DA2_MASK_GAIJIRAM 0x3ffff /* 0x3FFFF */ +#define DA2_MASK_VRAM 0xfffff /* 0xFFFFF */ +#define DA2_MASK_VRAMPLANE 0x1ffff /* 0x1FFFF */ +#define DA2_PIXELCLOCK 29000000.0 /* 58 MHz interlaced */ #define DA2_BLT_MEMSIZE 0x100 #define DA2_BLT_REGSIZE 0x40 #define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) -#define DA2_DEBUG_BLTLOG_MAX 256 * 1024 +#define DA2_DEBUG_BLTLOG_MAX (256 * 1024) #define DA2_DEBUG_BLT_NEVERUSED 0xfefefefe #define DA2_DEBUG_BLT_USEDRESET 0xfefefe #define DA2_DCONFIG_CHARSET_JPAN 0 /* for Code page 932 Japanese */ @@ -253,7 +257,7 @@ #endif #ifdef ENABLE_DA2_LOG -# define ENABLE_DA2_DEBUGBLT 1 +// # define ENABLE_DA2_DEBUGBLT 1 // # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 @@ -304,7 +308,6 @@ typedef struct da2_t { uint32_t decode_mask; uint32_t vram_max; - uint32_t vram_mask; uint32_t gdcla[8]; uint32_t gdcinput[8]; @@ -363,13 +366,11 @@ typedef struct da2_t { // uint32_t cram_display_mask; /* APA Buffer A0000-BFFFFh (128 KB) */ uint8_t *vram; - /* addr >> 12 = xx000h */ + /* xxh */ uint8_t *changedvram; /* (vram size - 1) >> 3 = 0x1FFFF */ uint32_t vram_display_mask; - // uint32_t write_bank, read_bank; - int fullchange; void (*render)(struct da2_t *da2); @@ -454,15 +455,17 @@ typedef struct { uint32_t DA2_vram_r(uint32_t addr, da2_t *da2) { - if (addr & ~da2->vram_mask) - return -1; + if (addr & ~DA2_MASK_VRAM) + return DA2_INVALIDACCESS32; return da2->vram[addr]; } /* safety write for internal functions */ void DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) { - da2->vram[addr & da2->vram_mask] = val; + if (addr & ~DA2_MASK_VRAM) + return; + da2->vram[addr] = val; return; } /* write pixel data with rop (Note: bitmask must be in big endian) */ @@ -472,8 +475,7 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s uint32_t writepx[8]; destaddr &= 0xfffffffe; /* align to word address to work bit shift correctly */ // da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); - da2->changedvram[(da2->vram_display_mask & destaddr) >> 12] = changeframecount; - da2->changedvram[(da2->vram_display_mask & (destaddr + 1)) >> 12] = changeframecount; + da2->changedvram[(DA2_MASK_VRAMPLANE & destaddr) >> 9] = changeframecount; destaddr <<= 3; /* read destination data with big endian order */ for (int i = 0; i < 8; i++) @@ -485,7 +487,6 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s DA2_VidSeq32 mask32in; mask32in.d = (uint32_t) mask; DA2_VidSeq32 mask32; - mask32.d = 0; mask32.b[3] = mask32in.b[0]; mask32.b[2] = mask32in.b[1]; mask32.d &= 0xffff0000; @@ -1395,7 +1396,7 @@ da2_in(uint16_t addr, void *p) case LS_DATA: // da2->ioctl[3] = 0x80; /* 3E1h:3 bit 7 color monitor, bit 3 busy(GC) bit 0 busy (IO?) */ if (da2->ioctladdr > 0xf) - return DA2_INVALIDACCESS8; + return DA2_INVALIDACCESS16; temp = da2->ioctl[da2->ioctladdr]; if (da2->ioctladdr == LS_STATUS) { /* Status register */ if (da2->attrc[LV_COMPATIBILITY] & 0x08) { /* for detecting monitor type and cable wiring */ @@ -1440,7 +1441,7 @@ da2_in(uint16_t addr, void *p) break; case LF_DATA: if (da2->fctladdr > 0x1f) - return DA2_INVALIDACCESS8; + return DA2_INVALIDACCESS16; temp = da2->fctl[da2->fctladdr]; break; case LC_INDEX: @@ -1448,7 +1449,7 @@ da2_in(uint16_t addr, void *p) break; case LC_DATA: if (da2->crtcaddr > 0x1f) - return DA2_INVALIDACCESS8; + return DA2_INVALIDACCESS16; temp = da2->crtc[da2->crtcaddr]; break; case LV_PORT: @@ -1741,14 +1742,13 @@ getfont_ps55dbcs(int32_t code, int32_t line, void *p) if (code >= 0x8000 && code <= 0x8183) code -= 0x6000; /* shift for IBM extended characters (I don't know how the real card works.) */ if (code < DA2_FONTROM_SIZE / 72 && fline >= 0 && fline < 24) { - font = da2->mmio.font[code * 72 + fline * 3]; /* 1111 1111 */ - font <<= 8; /* 1111 1111 0000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; /* 1111 1111 2222 0000 */ - font >>= 1; /* 0111 1111 1222 2000 */ - font <<= 4; /* 0111 1111 1222 2000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; /* 0111 1111 1222 2000 2222 */ - font <<= 8; /* 0111 1111 1222 2000 2222 0000 0000 */ - font |= da2->mmio.font[code * 72 + fline * 3 + 2]; /* 0111 1111 1222 2000 2222 3333 3333 */ + font = da2->mmio.font[code * 72 + fline * 3]; /* 0000 0000 0000 0000 0000 0000 1111 1111 */ + font <<= 8; /* 0000 0000 0000 0000 1111 1111 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0xf0; /* 0000 0000 0000 0000 1111 1111 2222 0000 */ + font <<= 3; /* 0000 0000 0000 0111 1111 1222 2000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 1] & 0x0f; /* 0000 0000 0000 0111 1111 1222 2000 2222 */ + font <<= 8; /* 0000 0111 1111 1222 2000 2222 0000 0000 */ + font |= da2->mmio.font[code * 72 + fline * 3 + 2]; /* 0000 0111 1111 1222 2000 2222 3333 3333 */ font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ /* font >>= 1;//put blank at column 1 (and 26) */ } else if (code >= 0xb000 && code <= 0xb75f) { @@ -1824,7 +1824,7 @@ da2_render_text(da2_t *da2) // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { chr = da2->cram[(da2->ma) & DA2_MASK_CRAM]; - attr = da2->cram[((da2->ma) + 1) & DA2_MASK_CRAM]; + attr = da2->cram[(da2->ma + 1) & DA2_MASK_CRAM]; // if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) /* IO 3E8h, Index 1Dh */ { /* --Parse attribute byte in color mode-- */ @@ -1864,7 +1864,7 @@ da2_render_text(da2_t *da2) /* Stay drawing If the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = da2->cram[((da2->ma) + 2) & da2->vram_display_mask]; + chr_dbcs = da2->cram[(da2->ma + 2) & DA2_MASK_CRAM]; chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ @@ -1935,7 +1935,7 @@ da2_render_text(da2_t *da2) da2->ma += 2; p += 13; } - da2->ma &= da2->vram_display_mask; + // da2->ma &= DA2_MASK_CRAM; // da2->writelines++; } } @@ -1959,9 +1959,9 @@ da2_render_textm3(da2_t *da2) int chr_wide = 0; // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { - chr = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma), da2); - attr = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma) + 1, da2); - extattr = DA2_vram_r(DA2_VM03_BASEEXATTR + (da2->ma) + 1, da2); + chr = DA2_vram_r(DA2_VM03_BASECHR + da2->ma, da2); + attr = DA2_vram_r(DA2_VM03_BASECHR + da2->ma + 1, da2); + extattr = DA2_vram_r(DA2_VM03_BASEEXATTR + da2->ma + 1, da2); // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->ma << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; // if (da2->blink) bg &= ~0x8; @@ -1979,7 +1979,7 @@ da2_render_textm3(da2_t *da2) /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = DA2_vram_r(DA2_VM03_BASECHR + (da2->ma) + 2, da2); + chr_dbcs = DA2_vram_r(DA2_VM03_BASECHR + da2->ma + 2, da2); chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ @@ -2027,7 +2027,7 @@ da2_render_textm3(da2_t *da2) da2->ma += 2; p += 13; } - da2->ma &= da2->vram_display_mask; + // da2->ma &= DA2_MASK_CRAM; // da2->writelines++; } } @@ -2035,7 +2035,7 @@ da2_render_textm3(da2_t *da2) void da2_render_color_4bpp(da2_t *da2) { - int changed_offset = da2->ma >> 12; + int changed_offset = da2->ma >> 9; // da2_log("ma %x cf %x\n", da2->ma, changed_offset); da2->plane_mask &= 0x0f; /*safety */ @@ -2084,7 +2084,7 @@ da2_render_color_4bpp(da2_t *da2) void da2_render_color_8bpp(da2_t *da2) { - int changed_offset = da2->ma >> 12; + int changed_offset = da2->ma >> 9; // da2_log("ma %x cf %x\n", da2->ma, changed_offset); if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { @@ -2255,8 +2255,8 @@ da2_recalctimings(da2_t *da2) if (da2->dispofftime < TIMER_USEC) da2->dispofftime = TIMER_USEC; da2_log("da2 horiz total %i display end %i vidclock %f\n", da2->crtc[0], da2->crtc[1], da2->clock); - // da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); - // da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); + da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); + da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); // da2_log("da2->render %08X\n", da2->render); } @@ -2580,7 +2580,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) cycles -= video_timing_write_b; - da2->changedvram[addr >> 12] = changeframecount; + da2->changedvram[addr >> 9] = changeframecount;/* 0x1FFFF -> 0x1F */ addr <<= 3; for (int i = 0; i < 8; i++) @@ -2694,8 +2694,8 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) // da2_log("da2_gcW m%d a%x d%x\n", da2->writemode, addr, val); // da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); - da2->changedvram[addr >> 12] = changeframecount; - da2->changedvram[(addr + 1) >> 12] = changeframecount; + da2->changedvram[addr >> 9] = changeframecount; + // da2->changedvram[(addr + 1) >> 12] = changeframecount; addr <<= 3; for (int i = 0; i < 8; i++) @@ -2948,7 +2948,7 @@ da2_poll(void *priv) } da2->blink++; - for (x = 0; x < ((da2->vram_mask + 1) >> 12); x++) { + for (x = 0; x <= (DA2_MASK_VRAMPLANE >> 9); x++) { if (da2->changedvram[x]) da2->changedvram[x]--; } @@ -3089,7 +3089,7 @@ da2_reset(void *priv) da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ da2->pos_regs[1] = DA2_POSID_H; /* Adapter Identification Byte (High byte) */ - da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (they are changed by system software) */ + da2->pos_regs[2] = 0x40; /* Bit 7-5: 010=Mono, 100=Color, Bit 0 : Card Enable (set by reference diskette) */ da2->ioctl[LS_CONFIG1] = OldLSI | Page_Two; /* Configuration 1 : DA-II, 1024 KB */ da2->ioctl[LS_CONFIG1] |= ((da2->monitorid & 0x8) << 1); /* Configuration 1 : Monitor ID 3 */ da2->ioctl[LS_CONFIG2] = (da2->monitorid & 0x7); /* Configuration 2: Monitor ID 0-2 */ @@ -3127,11 +3127,10 @@ da2_init(UNUSED(const device_t *info)) da2->dispontime = 1000ull << 32; da2->dispofftime = 1000ull << 32; da2->vram = calloc(1, DA2_SIZE_VRAM); - da2->vram_mask = DA2_SIZE_VRAM - 1; da2->cram = calloc(1, DA2_SIZE_CRAM); da2->vram_display_mask = DA2_MASK_CRAM; - da2->changedvram = calloc(1, /*(memsize >> 12) << 1*/ DA2_SIZE_VRAM >> 12); /* XX000h */ - da2->monitorid = device_get_config_int("montype"); /* Configuration for Monitor ID (aaaa) -> (xxax xxxx, xxxx xaaa) */ + da2->monitorid = device_get_config_int("montype"); + da2->changedvram = calloc(1, (DA2_MASK_VRAMPLANE + 1) >> 9); /* XX000h */ da2->mmio.charset = device_get_config_int("charset"); da2->mmio.font = malloc(DA2_FONTROM_SIZE); @@ -3148,7 +3147,7 @@ da2_init(UNUSED(const device_t *info)) } mca_add(da2_mca_read, da2_mca_write, da2_mca_feedb, da2_mca_reset, da2); - da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (float) (1ull << 32)); + da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (double) (1ull << 32)); memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); memset(da2->bitblt.reg, 0xfe, DA2_BLT_REGSIZE * sizeof(uint32_t)); /* clear memory */ #ifdef ENABLE_DA2_DEBUGBLT @@ -3172,7 +3171,7 @@ da2_init(UNUSED(const device_t *info)) mem_mapping_disable(&da2->cmapping); timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 10 * TIMER_USEC; + da2->bitblt.timerspeed = 10ull * TIMER_USEC; timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; @@ -3275,7 +3274,7 @@ void da2_speed_changed(void *p) { da2_t *da2 = (da2_t *) p; - da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (float) (1ull << 32)); + da2->da2const = (uint64_t) ((cpuclock / DA2_PIXELCLOCK) * (double) (1ull << 32)); da2_recalctimings(da2); } From 0bb89be0ad0e718841ca99ef2405cb42f9666f6f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Feb 2025 16:51:13 +0600 Subject: [PATCH 0348/1190] Revert "Fix compile on ARM64" This reverts commit c7153916eb21c67647e4df2512cda9b8776e5653. --- src/cpu/386_dynarec.c | 70 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 04681c9dc..5cb385122 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -74,6 +74,7 @@ x386_dynarec_log(const char *fmt, ...) # define x386_dynarec_log(fmt, ...) #endif +/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ #if defined(_MSC_VER) && !defined(__clang__) # if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 # define X87_INLINE_ASM @@ -84,6 +85,40 @@ x386_dynarec_log(const char *fmt, ...) # endif #endif +#ifdef USE_NEW_DYNAREC +void +x87_to_mmxreg(uint16_t reg) +#else +void +x87_to_mmxreg(void) +#endif +{ +#ifndef USE_NEW_DYNAREC + uint32_t reg = cpu_state.TOP & 7; +#endif + double val = cpu_state.ST[reg & 7]; +#ifdef X87_INLINE_ASM + unsigned char buffer[10]; +#else + x87_conv_t test; +#endif + +#ifdef X87_INLINE_ASM + __asm volatile("" + : + : + : "memory"); + + __asm volatile("fldl %1\n" + "fstpt %0\n" : "=m"(buffer) : "m"(val)); + + cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); +#else + x87_to80(val, &test); + cpu_state.MM[reg & 7].q = test.eind.ll; +#endif +} + static __inline void fetch_ea_32_long(uint32_t rmdat) { @@ -243,41 +278,6 @@ fetch_ea_16_long(uint32_t rmdat) # define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) #endif -/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ -#ifdef USE_NEW_DYNAREC -void -x87_to_mmxreg(uint16_t reg) -#else -void -x87_to_mmxreg(void) -#endif -{ -#ifndef USE_NEW_DYNAREC - uint32_t reg = cpu_state.TOP & 7; -#endif - double val = cpu_state.ST[reg & 7]; -#ifdef X87_INLINE_ASM - unsigned char buffer[10]; -#else - x87_conv_t test; -#endif - -#ifdef X87_INLINE_ASM - __asm volatile("" - : - : - : "memory"); - - __asm volatile("fldl %1\n" - "fstpt %0\n" : "=m"(buffer) : "m"(val)); - - cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); -#else - x87_to80(val, &test); - cpu_state.MM[reg & 7].q = test.eind.ll; -#endif -} - #ifdef USE_DYNAREC int32_t cycles_main = 0; static int32_t cycles_old = 0; From 6bb2b447fda8011e992472fa0959d3ee4cd8deed Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Feb 2025 16:51:33 +0600 Subject: [PATCH 0349/1190] Revert "x87: Fix Final Reality discolored screen for all dynarecs" This reverts commit 03dd94f361259b102fad8cfce2592fa81b801ee8. --- src/codegen/codegen_ops_x86-64.h | 14 --------- src/codegen/codegen_ops_x86.h | 7 ----- src/codegen_new/codegen_ops_helpers.h | 3 -- src/cpu/386_dynarec.c | 45 --------------------------- src/cpu/cpu.h | 6 ---- 5 files changed, 75 deletions(-) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index 01fb292cf..e46f55a05 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -3571,8 +3571,6 @@ FP_FLD(int reg) addbyte(0x89); /*MOV [TOP], EBX*/ addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3690,8 +3688,6 @@ FP_LOAD_S(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_D(void) @@ -3721,8 +3717,6 @@ FP_LOAD_D(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3760,8 +3754,6 @@ FP_LOAD_IW(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IL(void) @@ -3795,8 +3787,6 @@ FP_LOAD_IL(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IQ(void) @@ -3841,8 +3831,6 @@ FP_LOAD_IQ(void) addbyte(0x44); addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -3875,8 +3863,6 @@ FP_LOAD_IMM_Q(uint64_t v) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag)); addbyte(v ? 0 : 1); - - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index 3b47d81a9..c48324c2a 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -1794,7 +1794,6 @@ FP_FLD(int reg) addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -2038,7 +2037,6 @@ FP_LOAD_S(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_D(void) @@ -2098,7 +2096,6 @@ FP_LOAD_D(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IW(void) @@ -2157,7 +2154,6 @@ FP_LOAD_IW(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IL(void) @@ -2214,7 +2210,6 @@ FP_LOAD_IL(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void FP_LOAD_IQ(void) @@ -2290,7 +2285,6 @@ FP_LOAD_IQ(void) addbyte(0x1d); addbyte((uint8_t) cpu_state_offset(tag[0])); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline void @@ -2342,7 +2336,6 @@ FP_LOAD_IMM_Q(uint64_t v) addbyte(0x5d); addbyte((uint8_t) cpu_state_offset(TOP)); } - CALL_FUNC((uintptr_t) x87_to_mmxreg); } static __inline int diff --git a/src/codegen_new/codegen_ops_helpers.h b/src/codegen_new/codegen_ops_helpers.h index 2304aa542..92b721099 100644 --- a/src/codegen_new/codegen_ops_helpers.h +++ b/src/codegen_new/codegen_ops_helpers.h @@ -64,9 +64,6 @@ fpu_POP2(codeblock_t *block, ir_data_t *ir) static inline void fpu_PUSH(codeblock_t *block, ir_data_t *ir) { - uop_LOAD_FUNC_ARG_IMM(ir, 0, ((uint16_t)cpu_state.TOP - 1)); - uop_CALL_FUNC(ir, x87_to_mmxreg); - if (block->flags & CODEBLOCK_STATIC_TOP) uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP - 1); else diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5cb385122..5f41c416a 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -74,51 +74,6 @@ x386_dynarec_log(const char *fmt, ...) # define x386_dynarec_log(fmt, ...) #endif -/* Deliberately stashed here; this function is only relevant for dynamic recompilers. */ -#if defined(_MSC_VER) && !defined(__clang__) -# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 -# define X87_INLINE_ASM -# endif -#else -# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 || defined __amd64__ -# define X87_INLINE_ASM -# endif -#endif - -#ifdef USE_NEW_DYNAREC -void -x87_to_mmxreg(uint16_t reg) -#else -void -x87_to_mmxreg(void) -#endif -{ -#ifndef USE_NEW_DYNAREC - uint32_t reg = cpu_state.TOP & 7; -#endif - double val = cpu_state.ST[reg & 7]; -#ifdef X87_INLINE_ASM - unsigned char buffer[10]; -#else - x87_conv_t test; -#endif - -#ifdef X87_INLINE_ASM - __asm volatile("" - : - : - : "memory"); - - __asm volatile("fldl %1\n" - "fstpt %0\n" : "=m"(buffer) : "m"(val)); - - cpu_state.MM[reg & 7].q = (*(uint64_t*)buffer); -#else - x87_to80(val, &test); - cpu_state.MM[reg & 7].q = test.eind.ll; -#endif -} - static __inline void fetch_ea_32_long(uint32_t rmdat) { diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 98c6f4938..1d003ddc9 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -829,12 +829,6 @@ extern uint16_t prefetch_queue_get_ip(void); extern int prefetch_queue_get_prefetching(void); extern int prefetch_queue_get_size(void); -#ifdef USE_NEW_DYNAREC -extern void x87_to_mmxreg(uint16_t reg); -#else -extern void x87_to_mmxreg(void); -#endif - #define prefetch_queue_set_suspended(s) prefetch_queue_set_prefetching(!s) #define prefetch_queue_get_suspended !prefetch_queue_get_prefetching From 23b89d88c4e4fee4914d4c20b92a741e25e7c0ca Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Feb 2025 16:51:48 +0600 Subject: [PATCH 0350/1190] Revert "x87: Fix Final Reality discolored screen for interpreter" This reverts commit 6d3816df64aac6cb0e604bab30239c3b4b888265. --- src/cpu/x87_ops.h | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 276c32876..f1362bf76 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -113,33 +113,12 @@ typedef union { static __inline void x87_push(double i) { -#ifdef X87_INLINE_ASM - unsigned char buffer[10]; -#else - x87_conv_t test; -#endif #ifdef USE_NEW_DYNAREC cpu_state.TOP--; #else cpu_state.TOP = (cpu_state.TOP - 1) & 7; #endif cpu_state.ST[cpu_state.TOP & 7] = i; - -#ifdef X87_INLINE_ASM - __asm volatile("" - : - : - : "memory"); - - __asm volatile("fldl %1\n" - "fstpt %0\n" : "=m"(buffer) : "m"(i)); - - cpu_state.MM[cpu_state.TOP & 7].q = (*(uint64_t*)buffer); -#else - x87_to80(i, &test); - cpu_state.MM[cpu_state.TOP & 7].q = test.eind.ll; -#endif - #ifdef USE_NEW_DYNAREC cpu_state.tag[cpu_state.TOP & 7] = TAG_VALID; #else @@ -150,11 +129,6 @@ x87_push(double i) static __inline void x87_push_u64(uint64_t i) { -#ifdef X87_INLINE_ASM - unsigned char buffer[10]; -#else - x87_conv_t test; -#endif union { double d; uint64_t ll; @@ -168,21 +142,6 @@ x87_push_u64(uint64_t i) cpu_state.TOP = (cpu_state.TOP - 1) & 7; #endif cpu_state.ST[cpu_state.TOP & 7] = td.d; - -#ifdef X87_INLINE_ASM - __asm volatile("" - : - : - : "memory"); - - __asm volatile("fldl %1\n" - "fstpt %0\n" : "=m"(buffer) : "m"(td.d)); - - cpu_state.MM[cpu_state.TOP & 7].q = (*(uint64_t*)buffer); -#else - x87_to80(td.d, &test); - cpu_state.MM[cpu_state.TOP & 7].q = test.eind.ll; -#endif #ifdef USE_NEW_DYNAREC cpu_state.tag[cpu_state.TOP & 7] = TAG_VALID; #else From 843dee57076a28d4028b9105c87ead95e64d7933 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 1 Mar 2025 15:05:39 +0600 Subject: [PATCH 0351/1190] x64 NDR: Properly address the entire cpu_state struct All missing edge cases are now handled where possible --- src/codegen_new/codegen_backend_x86-64_ops.c | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index 236a86ce7..2f65b46e3 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -509,6 +509,11 @@ host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) codegen_alloc_bytes(block, 4); codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ codegen_addbyte(block, imm_data); + } else if (offset < (1ULL << 32)) { + codegen_alloc_bytes(block, 7); + codegen_addbyte2(block, 0xc6, 0x85); /*MOVB offset[RBP], imm_data*/ + codegen_addlong(block, offset); + codegen_addbyte(block, imm_data); } else { if ((uintptr_t) p >> 32) fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); @@ -527,6 +532,11 @@ host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) codegen_alloc_bytes(block, 6); codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addword(block, imm_data); + } else if (offset < (1ULL << 32)) { + codegen_alloc_bytes(block, 8); + codegen_addbyte3(block, 0x66, 0xc7, 0x85); /*MOV offset[RBP], imm_data*/ + codegen_addlong(block, offset); + codegen_addword(block, imm_data); } else { if ((uintptr_t) p >> 32) fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); @@ -545,6 +555,11 @@ host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) codegen_alloc_bytes(block, 7); codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addlong(block, imm_data); + } else if (offset < (1ULL << 32)) { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0xc7, 0x85); /*MOV offset[RBP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); } else { if ((uintptr_t) p >> 32) fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); @@ -566,6 +581,10 @@ host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) if (offset >= -128 && offset < 127) { codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ + } else if (offset < (1ULL << 32)) { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x88, 0x85 | ((src_reg & 7) << 3)); /*MOVB offset[RBP], src_reg*/ + codegen_addlong(block, offset); } else { if ((uintptr_t) p >> 32) fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); @@ -630,6 +649,10 @@ host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) if (offset >= -128 && offset < 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } else if (offset < (1ULL << 32)) { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x48, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); } else { if ((uintptr_t) p >> 32) fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); From d15def050aba3e2652355c718918fb78e9c79b53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 1 Mar 2025 10:11:45 +0100 Subject: [PATCH 0352/1190] Fix an unclosed comment in device/keyboard_at.c. --- src/device/keyboard_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index d04ab07e9..e61b8547a 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2526,7 +2526,7 @@ static const scancode scancode_set82[512] = { { .mk = {0xe0, 0x17, 0 }, .brk = { 0xe0, 0xF0, 0x17, 0 } }, /* 15a */ { .mk = { 0x67, 0 }, .brk = { 0xf0, 0x67, 0 } }, /* 15b 0x33 LGUI->Muhenkan (in emulator only) */ { .mk = { 0x64, 0 }, .brk = { 0xf0, 0x64, 0 } }, /* 15c 0x35 RGUI->Henkan (in emulator only) */ - { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0xf0, 0x11, 0 } }, /* 15d 0x36 APPLICATION->Kana (in emulator + { .mk = {0xe0, 0x11, 0 }, .brk = { 0xe0, 0xf0, 0x11, 0 } }, /* 15d 0x36 APPLICATION->Kana (in emulator only) */ { .mk = {0xe0, 0x37, 0 }, .brk = { 0xe0, 0xF0, 0x37, 0 } }, /* 15e */ { .mk = {0xe0, 0x3F, 0 }, .brk = { 0xe0, 0xF0, 0x3F, 0 } }, /* 15f */ { .mk = { 0 }, .brk = { 0 } }, /* 160 */ From 31d05b3e45a60ab1bf0eb057bac8d012d788e031 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 1 Mar 2025 23:58:31 +0900 Subject: [PATCH 0353/1190] modify blank render --- src/video/vid_ps55da2.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 441df620b..46ef4caf6 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -257,9 +257,9 @@ #endif #ifdef ENABLE_DA2_LOG -// # define ENABLE_DA2_DEBUGBLT 1 -// # define ENABLE_DA2_DEBUGVRAM 1 -// # define ENABLE_DA2_DEBUGFULLSCREEN 1 +# define ENABLE_DA2_DEBUGBLT 1 +# define ENABLE_DA2_DEBUGVRAM 1 +# define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 int da2_do_log = ENABLE_DA2_LOG; @@ -1208,8 +1208,8 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LC_DATA: if (da2->crtcaddr > 0x1f) return; - // if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) - // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) + da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); if (!(da2->crtc[da2->crtcaddr] ^ val)) return; switch (da2->crtcaddr) { @@ -1325,6 +1325,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) break; case LG_DATA: // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); switch (da2->gdcaddr & 0x1f) { case LG_READ_MAP_SELECT: @@ -1332,6 +1333,11 @@ da2_out(uint16_t addr, uint16_t val, void *p) break; case LG_MODE: da2->writemode = val & 3; + /* reset bit mask and plane mask (? idk when) */ + da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; + da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; + da2->writemask = 0xff; + da2->gdcreg[LG_MAP_MASKJ] = 0xff; break; case LG_MAP_MASKJ: da2->writemask = val & 0xff; @@ -1429,8 +1435,7 @@ da2_in(uint16_t addr, void *p) // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); // } } - if (da2->bitblt.indata) - temp |= 0x08; + if (da2->bitblt.indata) temp |= 0x09; #ifdef ENABLE_DA2_DEBUGMONWAIT da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); #endif @@ -1524,7 +1529,7 @@ da2_outb(uint16_t addr, uint8_t val, void *p) void da2_outw(uint16_t addr, uint16_t val, void *p) { - // da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; switch (addr) { @@ -1794,14 +1799,17 @@ void da2_render_blank(da2_t *da2) { int x, xx; + int cwidth; + if (da2->ioctl[LS_MODE] & 0x01) cwidth = 13; /* in character mode */ + else cwidth = 16; if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; for (x = 0; x < da2->hdisp; x++) { - for (xx = 0; xx < 13; xx++) - ((uint32_t *) buffer32->line[da2->displine])[(x * 13) + xx + 32] = 0; + for (xx = 0; xx < cwidth; xx++) + ((uint32_t *) buffer32->line[da2->displine])[(x * cwidth) + xx + 32] = 0; } } /* Display Adapter Mode 8, E Drawing */ @@ -2152,8 +2160,10 @@ da2_recalctimings(da2_t *da2) double _dispontime, _dispofftime, disptime; /* if output disabled or VGA passthrough */ - if (!(da2->attrc[LV_COMPATIBILITY] & 0x08) || da2->ioctl[LS_MODE] & 0x02) + if (da2->ioctl[LS_MODE] & 0x02 || !(da2->attrc[LV_COMPATIBILITY] & 0x08)) { + da2->render = da2_render_blank; return; + } da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; @@ -3171,7 +3181,7 @@ da2_init(UNUSED(const device_t *info)) mem_mapping_disable(&da2->cmapping); timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 10ull * TIMER_USEC; + da2->bitblt.timerspeed = 8ull * TIMER_USEC; /* Bitblt execution speed */ timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; From f290cc017309494ec6c7bc952b63b2de1e8b1935 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 1 Mar 2025 22:31:10 +0600 Subject: [PATCH 0354/1190] x64 NDR: Fix crashes/undefined behaviour with 2+ GB of allocated RAM --- src/codegen_new/codegen_backend_x86-64.c | 2 +- src/codegen_new/codegen_backend_x86-64_defs.h | 2 +- src/codegen_new/codegen_backend_x86-64_ops.c | 64 +++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64.c b/src/codegen_new/codegen_backend_x86-64.c index 3cbca28f8..f4a5d024a 100644 --- a/src/codegen_new/codegen_backend_x86-64.c +++ b/src/codegen_new/codegen_backend_x86-64.c @@ -360,7 +360,7 @@ codegen_backend_prologue(codeblock_t *block) host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, IREG_TOP_diff_stack_offset, REG_EAX); } if (block->flags & CODEBLOCK_NO_IMMEDIATES) - host_x86_MOV64_REG_IMM(block, REG_R12, (uintptr_t) ram); + host_x86_MOV64_REG_IMM(block, REG_R12, ((uintptr_t) ram) + 2147483648ULL); } void diff --git a/src/codegen_new/codegen_backend_x86-64_defs.h b/src/codegen_new/codegen_backend_x86-64_defs.h index 12f05f01c..7c58fec31 100644 --- a/src/codegen_new/codegen_backend_x86-64_defs.h +++ b/src/codegen_new/codegen_backend_x86-64_defs.h @@ -1,5 +1,5 @@ /*RBP = cpu_state + 128 - R12 = ram (if block->flags & CODEBLOCK_NO_IMMEDIATES)*/ + R12 = ram + 2147483648 (if block->flags & CODEBLOCK_NO_IMMEDIATES)*/ #define REG_AX 0 #define REG_CX 1 #define REG_DX 2 diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index 2f65b46e3..e53c58083 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -505,7 +505,7 @@ host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ codegen_addbyte(block, imm_data); @@ -528,7 +528,7 @@ host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 6); codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addword(block, imm_data); @@ -551,7 +551,7 @@ host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 7); codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addlong(block, imm_data); @@ -578,7 +578,7 @@ host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) if (src_reg & 8) fatal("host_x86_MOV8_ABS_REG - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ } else if (offset < (1ULL << 32)) { @@ -602,7 +602,7 @@ host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg) if (src_reg & 8) fatal("host_x86_MOV16_ABS_REG - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x66, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ } else if (offset < (1ULL << 32)) { @@ -622,7 +622,7 @@ host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) if (src_reg & 8) fatal("host_x86_MOV32_ABS_REG - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ } else if (offset < (1ULL << 32)) { @@ -646,7 +646,7 @@ host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) if (src_reg & 8) fatal("host_x86_MOV64_ABS_REG - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ } else if (offset < (1ULL << 32)) { @@ -706,19 +706,19 @@ void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); if (dst_reg & 8) fatal("host_x86_MOV8_REG_ABS reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x8a, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ } else if (offset < (1ULL << 32)) { codegen_alloc_bytes(block, 6); codegen_addbyte2(block, 0x8a, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ codegen_addlong(block, offset); - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0x41, 0x8a, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ codegen_addlong(block, ram_offset); @@ -730,19 +730,19 @@ void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); if (dst_reg & 8) fatal("host_x86_MOV16_REG_ABS reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x66, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ } else if (offset < (1ULL << 32)) { codegen_alloc_bytes(block, 7); codegen_addbyte3(block, 0x66, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ codegen_addlong(block, offset); - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { codegen_alloc_bytes(block, 9); codegen_addbyte4(block, 0x66, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3)); /*MOV dst_reg, ram_offset[R12]*/ codegen_addbyte(block, 0x24); @@ -760,19 +760,19 @@ void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); if (dst_reg & 8) fatal("host_x86_MOV32_REG_ABS reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ } else if (offset < (1ULL << 32)) { codegen_alloc_bytes(block, 6); codegen_addbyte2(block, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ codegen_addlong(block, offset); - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ codegen_addlong(block, ram_offset); @@ -792,7 +792,7 @@ host_x86_MOV64_REG_ABS(codeblock_t *block, int dst_reg, void *p) if (dst_reg & 8) fatal("host_x86_MOV64_REG_ABS reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x48, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ } else if (offset < (1ULL << 32)) { @@ -845,7 +845,7 @@ host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if ((dst_reg & 8) || (base_reg & 8)) fatal("host_x86_MOV16_REG_BASE_OFFSET reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); codegen_addbyte(block, 0x66); @@ -863,7 +863,7 @@ host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if ((dst_reg & 8) || (base_reg & 8)) fatal("host_x86_MOV32_REG_BASE_OFFSET reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); @@ -880,7 +880,7 @@ host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if ((dst_reg & 8) || (base_reg & 8)) fatal("host_x86_MOV64_REG_BASE_OFFSET reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); codegen_addbyte(block, 0x48); @@ -899,7 +899,7 @@ host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int if ((src_reg & 8) || (base_reg & 8)) fatal("host_x86_MOV32_BASE_OFFSET_REG reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); @@ -916,7 +916,7 @@ host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int if ((src_reg & 8) || (base_reg & 8)) fatal("host_x86_MOV64_BASE_OFFSET_REG reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); codegen_addbyte(block, 0x48); @@ -935,7 +935,7 @@ host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uin if (base_reg & 8) fatal("host_x86_MOV32_BASE_OFFSET_IMM reg & 8\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); @@ -1107,16 +1107,16 @@ void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_16_8 - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 5); codegen_addbyte(block, 0x66); codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { codegen_alloc_bytes(block, 10); codegen_addbyte2(block, 0x66, 0x41); codegen_addbyte4(block, 0x0f, 0xb6, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ @@ -1134,14 +1134,14 @@ void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); #if 0 if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); #endif - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { if (dst_reg & 8) { codegen_alloc_bytes(block, 5); codegen_addbyte(block, 0x44); @@ -1150,7 +1150,7 @@ host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ } - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); @@ -1173,15 +1173,15 @@ void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) { int64_t offset = (uintptr_t) p - (((uintptr_t) &cpu_state) + 128); - int64_t ram_offset = (uintptr_t) p - (uintptr_t) ram; + int64_t ram_offset = (uintptr_t) p - (((uintptr_t) ram) + 2147483648ULL); if (dst_reg & 8) fatal("host_x86_MOVZX_REG_ABS_32_16 - bad reg\n"); - if (offset >= -128 && offset < 127) { + if (offset >= -128 && offset <= 127) { codegen_alloc_bytes(block, 4); codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ - } else if ((ram_offset < (1ULL << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { + } else if ((ram_offset >= -2147483648LL) && (ram_offset <= 2147483647LL) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) { codegen_alloc_bytes(block, 9); codegen_addbyte(block, 0x41); codegen_addbyte4(block, 0x0f, 0xb7, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ From 6b55b2383a3fd6096f0e39a4c749272ecddc5650 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 2 Mar 2025 23:14:10 +0600 Subject: [PATCH 0355/1190] Misc NDR changes Force NDR on ARMv7/ARM64 Make GCC/Clang not use anything in the red zone Compile with `-fno-omit-frame-pointer` --- CMakeLists.txt | 7 +++++- src/CMakeLists.txt | 3 +++ src/codegen_new/codegen_backend_x86-64.c | 18 +++++++++++++++ src/codegen_new/codegen_backend_x86-64_ops.c | 24 ++++++++++---------- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa687222a..5c33bb3e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,13 +132,18 @@ option(RTMIDI "RtMidi" option(FLUIDSYNTH "FluidSynth" ON) option(MUNT "MUNT" ON) option(VNC "VNC renderer" OFF) -option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) option(MINITRACE "Enable Chrome tracing using the modified minitrace library" OFF) option(GDBSTUB "Enable GDB stub server for debugging" OFF) option(DEV_BRANCH "Development branch" OFF) option(DISCORD "Discord Rich Presence support" ON) option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs" OFF) +if((ARCH STREQUAL "arm64") OR (ARCH STREQUAL "arm")) + set(NEW_DYNAREC ON) +else() + option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d6daff9c..ee17a7a21 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -223,6 +223,9 @@ elseif(APPLE AND NOT QT) COMPONENT Runtime) endif() +if(NEW_DYNAREC AND (ARCH STREQUAL "x86_64") AND (NOT WIN32)) + add_compile_options(-mno-red-zone -fno-omit-frame-pointer) +endif() # Install the PDB file on Windows builds if(MSVC) diff --git a/src/codegen_new/codegen_backend_x86-64.c b/src/codegen_new/codegen_backend_x86-64.c index f4a5d024a..6242ea40b 100644 --- a/src/codegen_new/codegen_backend_x86-64.c +++ b/src/codegen_new/codegen_backend_x86-64.c @@ -315,13 +315,19 @@ codegen_backend_init(void) # endif host_x86_CALL(block, (void *) x86gpf); codegen_exit_rout = &codeblock[block_current].data[block_pos]; +#ifdef _WIN64 host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); +#else + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x48); +#endif host_x86_POP(block, REG_R15); host_x86_POP(block, REG_R14); host_x86_POP(block, REG_R13); host_x86_POP(block, REG_R12); +#ifdef _WIN64 host_x86_POP(block, REG_RDI); host_x86_POP(block, REG_RSI); +#endif host_x86_POP(block, REG_RBP); host_x86_POP(block, REG_RDX); host_x86_RET(block); @@ -346,13 +352,19 @@ codegen_backend_prologue(codeblock_t *block) block_pos = BLOCK_START; /*Entry code*/ host_x86_PUSH(block, REG_RBX); host_x86_PUSH(block, REG_RBP); +#ifdef _WIN64 host_x86_PUSH(block, REG_RSI); host_x86_PUSH(block, REG_RDI); +#endif host_x86_PUSH(block, REG_R12); host_x86_PUSH(block, REG_R13); host_x86_PUSH(block, REG_R14); host_x86_PUSH(block, REG_R15); +#ifdef _WIN64 host_x86_SUB64_REG_IMM(block, REG_RSP, 0x38); +#else + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x48); +#endif host_x86_MOV64_REG_IMM(block, REG_RBP, ((uintptr_t) &cpu_state) + 128); if (block->flags & CODEBLOCK_HAS_FPU) { host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); @@ -366,13 +378,19 @@ codegen_backend_prologue(codeblock_t *block) void codegen_backend_epilogue(codeblock_t *block) { +#ifdef _WIN64 host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); +#else + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x48); +#endif host_x86_POP(block, REG_R15); host_x86_POP(block, REG_R14); host_x86_POP(block, REG_R13); host_x86_POP(block, REG_R12); +#ifdef _WIN64 host_x86_POP(block, REG_RDI); host_x86_POP(block, REG_RSI); +#endif host_x86_POP(block, REG_RBP); host_x86_POP(block, REG_RDX); host_x86_RET(block); diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index e53c58083..39173505b 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -848,11 +848,11 @@ host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); - codegen_addbyte(block, 0x66); + codegen_addbyte(block, 0x66); /* MOV dst_reg, [RSP + offset] */ codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); } else { codegen_alloc_bytes(block, 4); - codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); /* MOV dst_reg, [base_reg + offset] */ } } else fatal("MOV16_REG_BASE_OFFSET - offset %i\n", offset); @@ -866,10 +866,10 @@ host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 4); - codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); /* MOV dst_reg, [RSP + offset] */ } else { codegen_alloc_bytes(block, 3); - codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); /* MOV dst_reg, [base_reg + offset] */ } } else fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); @@ -883,11 +883,11 @@ host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, in if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); - codegen_addbyte(block, 0x48); + codegen_addbyte(block, 0x48); /* MOV dst_reg, [RSP + offset] */ codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); } else { codegen_alloc_bytes(block, 4); - codegen_addbyte4(block, 0x48, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + codegen_addbyte4(block, 0x48, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); /* MOV dst_reg, [base_reg + offset] */ } } else fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); @@ -901,11 +901,11 @@ host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { - codegen_alloc_bytes(block, 4); + codegen_alloc_bytes(block, 4); /* MOV [RSP + offset], src_reg*/ codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); } else { codegen_alloc_bytes(block, 3); - codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); /* MOV [base_reg + offset], src_reg*/ } } else fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); @@ -919,11 +919,11 @@ host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 5); - codegen_addbyte(block, 0x48); + codegen_addbyte(block, 0x48); /* MOV [RSP + offset], src_reg*/ codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); } else { codegen_alloc_bytes(block, 4); - codegen_addbyte4(block, 0x48, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + codegen_addbyte4(block, 0x48, 0x89, 0x40 | base_reg | (src_reg << 3), offset); /* MOV [base_reg + offset], src_reg*/ } } else fatal("MOV64_BASE_OFFSET_REG - offset %i\n", offset); @@ -938,11 +938,11 @@ host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uin if (offset >= -128 && offset <= 127) { if (base_reg == REG_RSP) { codegen_alloc_bytes(block, 8); - codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); + codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); /* MOV [RSP + offset], imm_data */ codegen_addlong(block, imm_data); } else { codegen_alloc_bytes(block, 7); - codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); + codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); /* MOV [base_reg + offset], src_reg*/ codegen_addlong(block, imm_data); } } else From 8d6087a016ba1eb034c9c6d6d99533d124cb418e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 3 Mar 2025 01:06:03 +0600 Subject: [PATCH 0356/1190] Revert some unnecessary changes for NDR --- src/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee17a7a21..fb3bf9f50 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -223,10 +223,6 @@ elseif(APPLE AND NOT QT) COMPONENT Runtime) endif() -if(NEW_DYNAREC AND (ARCH STREQUAL "x86_64") AND (NOT WIN32)) - add_compile_options(-mno-red-zone -fno-omit-frame-pointer) -endif() - # Install the PDB file on Windows builds if(MSVC) # CMake fully supports PDB files on MSVC-compatible compilers From 54650963f02a995264d2b4cb3fb103c9bc0dac52 Mon Sep 17 00:00:00 2001 From: The Dax Date: Sun, 2 Mar 2025 14:12:25 -0500 Subject: [PATCH 0357/1190] Fix Acer 100T machine not showing up on Linux due to case-sensitivity. --- src/machine/m_at_286_386sx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 24cb88f09..9086f7c8a 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -742,7 +742,7 @@ machine_at_acer100t_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/acer100t/acer386.bin", + ret = bios_load_linear("roms/machines/acer100t/acer386.BIN", 0x000f0000, 65536, 0); if (bios_only || !ret) From fae26729f103010ddc7e621a37083bc4ae6d5736 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 3 Mar 2025 22:03:52 +0600 Subject: [PATCH 0358/1190] S3 ViRGE: Make IRQs happen in main thread FIFO is also no longer immediately woken up upon writes --- src/video/vid_s3_virge.c | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 91b186240..05cd42459 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -338,6 +338,7 @@ typedef struct virge_t { event_t * fifo_not_full_event; atomic_int virge_busy; + atomic_uint virge_irq_req; uint8_t subsys_stat; uint8_t subsys_cntl; @@ -373,6 +374,9 @@ typedef struct virge_t { uint32_t dma_mmio_addr; uint32_t dma_data_type; + pc_timer_t wake_timer; + pc_timer_t irq_timer; + int pci; int is_agp; } virge_t; @@ -383,6 +387,28 @@ wake_fifo_thread(virge_t *virge) { thread_set_event(virge->wake_fifo_thread); } +void +s3_virge_wake_fifo_timer(void* priv) +{ + virge_t *virge = (virge_t *) priv; + + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +void +s3_virge_wake_fifo_thread(virge_t *virge) +{ + if (!timer_is_enabled(&virge->wake_timer)) { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_on_auto(&virge->wake_timer, 100.0); + } + if (!timer_is_enabled(&virge->irq_timer)) + timer_on_auto(&virge->irq_timer, 100.0); +} + static virge_t *reset_state = NULL; static video_timings_t timing_diamond_stealth3d_2000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; @@ -471,6 +497,19 @@ s3_virge_update_irqs(virge_t *virge) pci_clear_irq(virge->pci_slot, PCI_INTA, &virge->irq_state); } +void +s3_virge_update_irq_timer(void* priv) +{ + virge_t *virge = (virge_t *) priv; + + if (virge->virge_irq_req) { + virge->virge_irq_req--; + s3_virge_update_irqs(virge); + } + + timer_on_auto(&virge->irq_timer, 100.); +} + static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { @@ -1101,6 +1140,9 @@ static void s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *) svga->priv; + if (virge->virge_irq_req) + virge->virge_irq_req--; + virge->subsys_stat |= INT_VSY; s3_virge_update_irqs(virge); } @@ -1795,7 +1837,8 @@ fifo_thread(void *param) if (virge->cmd_dma) virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); - s3_virge_update_irqs(virge); + //s3_virge_update_irqs(virge); + virge->virge_irq_req++; } } @@ -1835,10 +1878,8 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) virge->fifo_write_idx++; - if (FIFO_ENTRIES > 0xe000) - wake_fifo_thread(virge); - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) - wake_fifo_thread(virge); + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 16) + s3_virge_wake_fifo_thread(virge); } static void @@ -3642,7 +3683,8 @@ render_thread(void *param) } virge->s3d_busy = 0; virge->subsys_stat |= INT_S3D_DONE; - s3_virge_update_irqs(virge); + //s3_virge_update_irqs(virge); + virge->virge_irq_req++; } } @@ -4571,6 +4613,9 @@ s3_virge_init(const device_t *info) virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); + timer_add(&virge->wake_timer, s3_virge_wake_fifo_timer, virge, 0); + timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 0); + virge->local = info->local; *reset_state = *virge; From e24c9d51633730b165aa7c332600df8aee140c79 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 3 Mar 2025 23:22:24 +0600 Subject: [PATCH 0359/1190] S3 ViRGE: Use a significantly faster version of the ROP code DirectDraw tests now run significantly faster, and Direct3D tests also now run smoothly. --- src/video/vid_s3_virge.c | 788 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 775 insertions(+), 13 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 05cd42459..62ffcff0c 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -2216,19 +2216,781 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } \ } while (0) -#define MIX() \ - do { \ - int c; \ - for (c = 0; c < 24; c++) { \ - int d = (dest & (1 << c)) ? 1 : 0; \ - if (source & (1 << c)) \ - d |= 2; \ - if (pattern & (1 << c)) \ - d |= 4; \ - if (virge->s3d.rop & (1 << d)) \ - out |= (1 << c); \ - } \ - } while (0) +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ + } + +#define MIX() do { ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); out &= 0xFFFFFF; } while (0) #define WRITE(addr, val) \ do { \ From 21f5415328cd5c101d020f3d1c601ba16322c53f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 4 Mar 2025 01:31:19 +0600 Subject: [PATCH 0360/1190] Trident TGUI: Use a significantly faster version of the ROP code At least 30%-40% performance improvement seen --- src/video/vid_tgui9440.c | 790 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 778 insertions(+), 12 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index d1391f1d1..c6edabac5 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -1457,18 +1457,784 @@ enum { else \ dat = vram_l[(addr) & (tgui->vram_mask >> 2)]; -#define MIX() \ - do { \ - out = 0; \ - for (c = 0; c < 32; c++) { \ - d = (dst_dat & (1 << c)) ? 1 : 0; \ - if (src_dat & (1 << c)) \ - d |= 2; \ - if (pat_dat & (1 << c)) \ - d |= 4; \ - if (tgui->accel.rop & (1 << d)) \ - out |= (1 << c); \ - } \ +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ + } + +#define MIX() \ + do { \ + out = 0; \ + ROPMIX(tgui->accel.rop, dst_dat, pat_dat, src_dat, out); \ } while (0) #define WRITE(addr, dat) \ From a9653e5a99393924f09ab6f6c72fb8afc47310bf Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 3 Mar 2025 21:21:02 +0100 Subject: [PATCH 0361/1190] TGUI9440: Fix two newly introduced warnings. --- src/video/vid_tgui9440.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index c6edabac5..af203f327 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -2256,8 +2256,6 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) const uint32_t *pattern_data; int x; int y; - int c; - int d; uint32_t out; uint32_t src_dat = 0; uint32_t dst_dat; From 6f53e69efe666ac6824b03f098edc11cf8db97ff Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 4 Mar 2025 07:47:15 +0900 Subject: [PATCH 0362/1190] added bit mask reset and alignment for compatibility with OS/2 J2.1 (beta), Windows 3.1 and Multitool Chart K3.1 in J-DOS. --- src/video/vid_ps55da2.c | 125 ++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 51 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 46ef4caf6..1b9ec473e 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -327,7 +327,7 @@ typedef struct da2_t { int fast; uint8_t colourcompare, colournocare; int readmode, writemode, readplane; - uint8_t writemask; + uint8_t planemask; uint32_t charseta, charsetb; uint8_t egapal[16]; @@ -441,6 +441,7 @@ void da2_bitblt_exec(void *p); void da2_updatevidselector(da2_t *da2); void da2_reset_ioctl(da2_t *da2); static void da2_reset(void *priv); +uint16_t rightRotate(uint16_t data, uint8_t count); typedef union { uint32_t d; @@ -687,6 +688,7 @@ da2_bitblt_load(da2_t *da2) value32 |= da2->bitblt.payload[i + 2]; da2_bltlog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + // da2->gdcreg[da2->bitblt.payload[i + 1]] = value32; i += 3; break; case 0x91: @@ -699,6 +701,7 @@ da2_bitblt_load(da2_t *da2) value32 |= da2->bitblt.payload[i + 2]; da2_bltlog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; + // da2->gdcreg[da2->bitblt.payload[i + 1]] = value32; i += 5; break; case 0x99: @@ -716,6 +719,7 @@ da2_bitblt_load(da2_t *da2) da2_bltlog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + // da2->gdcreg[da2->bitblt.payload[i + 1]] = value64; i += 7; break; case 0x00: @@ -1321,26 +1325,27 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->attrc[da2->attraddr & 0x3f] = val; break; case LG_INDEX: + da2_log("DA2 Out addr %03X val %02X\n", addr, val); da2->gdcaddr = val; break; case LG_DATA: - // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); - // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + da2->gdcreg[da2->gdcaddr & 0x0f] = val & 0xff; switch (da2->gdcaddr & 0x1f) { case LG_READ_MAP_SELECT: da2->readplane = val & 0x7; break; case LG_MODE: da2->writemode = val & 3; - /* reset bit mask and plane mask (? idk when) */ - da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; - da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; - da2->writemask = 0xff; - da2->gdcreg[LG_MAP_MASKJ] = 0xff; + /* Resettting masks here gliches the screen in IBM Multitool Chart K3.1 */ + // da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; + // da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; + // da2->planemask = 0xff; + // da2->gdcreg[LG_MAP_MASKJ] = 0xff; break; case LG_MAP_MASKJ: - da2->writemask = val & 0xff; + da2->planemask = val & 0xff; break; case LG_COMMAND: break; @@ -1348,7 +1353,6 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); return; } - da2->gdcreg[da2->gdcaddr & 0x0f] = val & 0xff; break; // case 0x3ed: /* used by Windows 3.1 display driver */ // da2->gdcreg[5] = val & 0xff; @@ -1424,7 +1428,7 @@ da2_in(uint16_t addr, void *p) temp |= 0x80; } temp &= 0xf6; /* clear busy bit */ - // if (da2->bitblt.indata) /* for OS/2 J1.3 */ + // if (da2->bitblt.indata) /* for OS/2 J1.3 command prompt scrolling */ // da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { // da2_log("exec:%x\n", da2->bitblt.exec); @@ -1435,7 +1439,7 @@ da2_in(uint16_t addr, void *p) // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); // } } - if (da2->bitblt.indata) temp |= 0x09; + if (da2->bitblt.indata) temp |= 0x08; #ifdef ENABLE_DA2_DEBUGMONWAIT da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); #endif @@ -1529,7 +1533,7 @@ da2_outb(uint16_t addr, uint8_t val, void *p) void da2_outw(uint16_t addr, uint16_t val, void *p) { - da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_log("DA2 Outw addr %03X val %04X\n", addr, val); da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; switch (addr) { @@ -1550,7 +1554,15 @@ da2_outw(uint16_t addr, uint16_t val, void *p) break; case 0x3EC: // da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_log(" "); + // val = rightRotate(val, 8); + // da2_out(LG_DATA, val, da2); da2_out(LG_DATA, val >> 8, da2); + /* reset masks */ + da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; + da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; + da2->planemask = 0xff; + da2->gdcreg[LG_MAP_MASKJ] = 0xff; break; case 0x3ED: da2->gdcaddr = LG_MODE; @@ -2340,11 +2352,12 @@ da2_mca_reset(void *p) da2_mca_write(0x102, 0, da2); } +/* ROP gdcinput and gdcsrc, and write the result with bitmask at addr (byte) */ static void da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) { for (int i = 0; i < 8; i++) { - if (da2->writemask & (1 << i)) { + if (da2->planemask & (1 << i)) { // da2_log("da2_gdcropB o%x a%x d%x p%d m%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, bitmask); switch (da2->gdcreg[LG_COMMAND] & 0x03) { case 0: /*Set*/ @@ -2368,13 +2381,15 @@ da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) } } } +/* ROP gdcinput and gdcsrc, and write the result with bitmask at addr (word) */ static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) { + if((addr & 8) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = rightRotate(bitmask, 8); uint8_t bitmask_l = bitmask & 0xff; uint8_t bitmask_h = bitmask >> 8; for (int i = 0; i < 8; i++) { - if (da2->writemask & (1 << i)) { + if (da2->planemask & (1 << i)) { // da2_log("da2_gdcropW m%x a%x d%x i%d ml%x mh%x\n", da2->gdcreg[LG_COMMAND] & 0x03, addr, da2->gdcinput[i], i, da2->gdcreg[LG_BIT_MASK_LOW], da2->gdcreg[LG_BIT_MASK_HIGH]); switch (da2->gdcreg[LG_COMMAND] & 0x03) { case 0: /*Set*/ @@ -2415,7 +2430,6 @@ da2_mmio_read(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; addr &= DA2_MASK_MMIO; - if (da2->ioctl[LS_MMIO] & 0x10) { if (da2->fctl[LF_MMIO_SEL] == 0x80) /* linear access */ @@ -2455,7 +2469,7 @@ da2_mmio_read(uint32_t addr, void *p) cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) da2->gdcla[i] = da2->vram[(addr << 3) | i]; /* read in byte */ - // da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); + da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); if (da2->gdcreg[LG_MODE] & 0x08) { /* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint8_t ret = 0; for (int i = 0; i < 8; i++) { @@ -2474,7 +2488,9 @@ static uint16_t da2_mmio_readw(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; - //da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + // da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); + da2_log("da2_readW: %x %x %x %x %x CS:PC=%4x:%4x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, CS, cpu_state.pc); + if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); } else if (!(da2->ioctl[LS_MODE] & 1)) {/* 16 color or 256 color mode */ @@ -2566,11 +2582,14 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ uint8_t bitmask; - /* align bitmask to even address */ - if (addr & 1) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + /* align bitmask with even address for OS/2 J2.0 (need to verify the condition with Win 3.x) */ + if ((addr & 1) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; + #ifdef ENABLE_DA2_DEBUGVRAM - da2_log("da2_wB %x %02x\n", addr, val); + // da2_log("da2_wB %x %02x\n", addr, val); + da2_log("da2_wB %x %d %d %02x\n", addr, + addr % (da2->rowoffset * 2) * 8, addr / (da2->rowoffset * 2), val); // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { @@ -2581,7 +2600,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) for (int i = 0; i < 8; i++) { int pixeldata = 0; if (val & (1 << (7 - i))) - pixeldata = (da2->writemask & 0xf); + pixeldata = (da2->planemask & 0xf); fprintf(da2->mmdbg_fp, "%X", pixeldata); } da2->mmdbg_vidaddr = addr; @@ -2614,7 +2633,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) switch (da2->writemode) { case 2: /* equiv to vga write mode 1 */ for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) + if (da2->planemask & (1 << i)) DA2_vram_w(addr | i, da2->gdcsrc[i], da2); break; case 0:/* equiv to vga write mode 0 */ @@ -2622,7 +2641,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; if (bitmask == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) + if (da2->planemask & (1 << i)) DA2_vram_w(addr | i, val, da2); } else { for (int i = 0; i < 8; i++) @@ -2631,8 +2650,8 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) else da2->gdcinput[i] = val; - for (int i = 0; i < 8; i++) - da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */ + // for (int i = 0; i < 8; i++) + // da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */ da2_gdcropB(addr, bitmask, da2); // for (int i = 0; i < 8; i++) // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], bitmask, da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch @@ -2640,17 +2659,17 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } break; case 1:/* equiv to vga write mode 2 */ - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) - DA2_vram_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2); - //fprintf(da2->mmdbg_fp, "m1-1"); - } else { + // if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + // for (int i = 0; i < 8; i++) + // if (da2->planemask & (1 << i)) + // DA2_vram_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2); + // //fprintf(da2->mmdbg_fp, "m1-1"); + // } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); da2_gdcropB(addr, bitmask, da2); //fprintf(da2->mmdbg_fp, "m1-2"); - } + // } break; case 3:/* equiv to vga write mode 3 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) @@ -2658,7 +2677,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) bitmask &= val; for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; da2_gdcropB(addr, bitmask, da2); break; } @@ -2678,22 +2697,25 @@ static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *) p; - uint16_t bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + uint16_t bitmask; addr &= DA2_MASK_MMIO; + bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; bitmask <<= 8; bitmask |= (uint16_t) da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGVRAM + da2_log("da2_wW %x %d %d %02x\n", addr, + addr % (da2->rowoffset * 2) * 8, addr / (da2->rowoffset * 2), val); // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) //{ if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { - fprintf(da2->mmdbg_fp, "\nW %x ", addr); + fprintf(da2->mmdbg_fp, "\nW %x %x ", addr, val); for (int i = 0; i <= 0xb; i++) fprintf(da2->mmdbg_fp, "%02x ", da2->gdcreg[i]); } for (int i = 0; i < 16; i++) { int pixeldata = 0; if (val & (1 << (15 - i))) - pixeldata = (da2->writemask & 0xf); + pixeldata = (da2->planemask & 0xf); fprintf(da2->mmdbg_fp, "%X", pixeldata); } da2->mmdbg_vidaddr = addr; @@ -2727,7 +2749,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) switch (da2->writemode) { case 2: for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) { + if (da2->planemask & (1 << i)) { DA2_vram_w(addr | i, da2->gdcsrc[i] & 0xff, da2); DA2_vram_w((addr + 8) | i, da2->gdcsrc[i] >> 8, da2); } @@ -2737,7 +2759,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) { + if (da2->planemask & (1 << i)) { DA2_vram_w(addr | i, val & 0xff, da2); DA2_vram_w((addr + 8) | i, val >> 8, da2); } @@ -2752,18 +2774,18 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) } break; case 1: - if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { - for (int i = 0; i < 8; i++) - if (da2->writemask & (1 << i)) { - uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - DA2_vram_w(addr | i, wdata & 0xff, da2); - DA2_vram_w((addr + 8) | i, wdata >> 8, da2); - } - } else { + // if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { + // for (int i = 0; i < 8; i++) + // if (da2->planemask & (1 << i)) { + // uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); + // DA2_vram_w(addr | i, wdata & 0xff, da2); + // DA2_vram_w((addr + 8) | i, wdata >> 8, da2); + // } + // } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); da2_gdcropW(addr, bitmask, da2); - } + // } break; case 3: if (da2->gdcreg[LG_DATA_ROTATION] & 15) @@ -2771,7 +2793,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) bitmask &= val; for (int i = 0; i < 8; i++) - da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; + da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xffff : 0; da2_gdcropW(addr, bitmask, da2); break; } @@ -2782,13 +2804,14 @@ static void da2_mmio_writew(uint32_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *) p; + // if (da2->bitblt.exec != DA2_BLT_CIDLE) /* Bitblt is in operation. */ + // return; // if ((addr & ~0x1ffff) != 0xA0000) return; if (da2->ioctl[LS_MMIO] & 0x10) { // da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ - // return; // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); da2_mmio_gc_writeW(addr, val, da2); } else { /* mode 3h text */ @@ -3181,7 +3204,7 @@ da2_init(UNUSED(const device_t *info)) mem_mapping_disable(&da2->cmapping); timer_add(&da2->timer, da2_poll, da2, 0); - da2->bitblt.timerspeed = 8ull * TIMER_USEC; /* Bitblt execution speed */ + da2->bitblt.timerspeed = 5ull * TIMER_USEC; /* Bitblt execution speed */ timer_add(&da2->bitblt.timer, da2_bitblt_dopayload, da2, 0); return da2; From e798030022d9ac1d0adfdbeada832a26aa9d33ed Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:38:31 +0900 Subject: [PATCH 0363/1190] modify bit mask alignment, added delay for vidsel for Win 3.1. And added delay for switching video selector --- src/video/vid_ps55da2.c | 72 +++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 1b9ec473e..0f5851c6f 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -431,6 +431,7 @@ typedef struct da2_t { uint8_t pos_regs[8]; svga_t *mb_vga; uint8_t monitorid; + pc_timer_t timer_vidupd; int old_pos2; } da2_t; @@ -1108,11 +1109,13 @@ da2_bitblt_dopayload(void *priv) { da2_t *da2 = (da2_t *) priv; timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - if (da2->bitblt.exec != DA2_BLT_CIDLE) - da2_bitblt_exec(da2); - else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { - da2->bitblt.exec = DA2_BLT_CLOAD; + /* do async operation but it causes the scrolling text glitch in OS/2 J1.3 Command Prompt (TODO) */ + if (da2->bitblt.exec != DA2_BLT_CIDLE) { + while (da2->bitblt.exec != DA2_BLT_CIDLE) da2_bitblt_exec(da2); + } else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { + da2->bitblt.exec = DA2_BLT_CLOAD; + da2_bitblt_exec(da2); } else { // timer_disable(&da2->bitblt.timer); } @@ -1202,8 +1205,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) oldval = da2->fctl[da2->fctladdr]; da2->fctl[da2->fctladdr] = val; if (da2->fctladdr == 0 && oldval != val) { - da2->fullchange = changeframecount; - da2_recalctimings(da2); + da2_log("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); } break; case LC_INDEX: @@ -1338,7 +1340,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) break; case LG_MODE: da2->writemode = val & 3; - /* Resettting masks here gliches the screen in IBM Multitool Chart K3.1 */ + /* Resettting masks here gliches chart drawing in IBM Multitool Chart K3.1 */ // da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; // da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; // da2->planemask = 0xff; @@ -1558,11 +1560,13 @@ da2_outw(uint16_t addr, uint16_t val, void *p) // val = rightRotate(val, 8); // da2_out(LG_DATA, val, da2); da2_out(LG_DATA, val >> 8, da2); - /* reset masks */ - da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; - da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; - da2->planemask = 0xff; - da2->gdcreg[LG_MAP_MASKJ] = 0xff; + /* reset masks for compatibility with Win 3.1 solitaire */ + if (da2->gdcaddr == LG_MODE) { + da2->gdcreg[LG_BIT_MASK_LOW] = 0xff; + da2->gdcreg[LG_BIT_MASK_HIGH] = 0xff; + da2->planemask = 0xff; + da2->gdcreg[LG_MAP_MASKJ] = 0xff; + } break; case 0x3ED: da2->gdcaddr = LG_MODE; @@ -2151,8 +2155,9 @@ da2_render_color_8bpp(da2_t *da2) } void -da2_updatevidselector(da2_t *da2) +da2_updatevidselector_tick(void *priv) { + da2_t *da2 = (da2_t *) priv; if (da2->ioctl[LS_MODE] & 0x02) { /* VGA passthrough mode */ da2->override = 1; @@ -2165,6 +2170,12 @@ da2_updatevidselector(da2_t *da2) } } +void +da2_updatevidselector(da2_t *da2) +{ + timer_set_delay_u64(&da2->timer_vidupd, 100000ull * TIMER_USEC); +} + void da2_recalctimings(da2_t *da2) { @@ -2386,6 +2397,7 @@ static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) { if((addr & 8) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = rightRotate(bitmask, 8); + // if((addr & 8)) bitmask = rightRotate(bitmask, 8); uint8_t bitmask_l = bitmask & 0xff; uint8_t bitmask_h = bitmask >> 8; for (int i = 0; i < 8; i++) { @@ -2582,9 +2594,15 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ uint8_t bitmask; - /* align bitmask with even address for OS/2 J2.0 (need to verify the condition with Win 3.x) */ - if ((addr & 1) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; - else bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; + /* align bitmask with even address (need to verify the condition with OS/2 J2.x, Win 3.x and A-Train IV Win) */ + /* With byte align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): bad, OS/2 J2.0(cmd) - ok */ + // if ((addr & 1) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + /* Without byte align: Win 3.1 (Window Title) - bad, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok */ + /* With byte align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok, DOS J4.0 MC - ok */ + if ((addr & 1)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; + else + /* No align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): bad, OS/2 J2.0(cmd) - bad */ + bitmask = da2->gdcreg[LG_BIT_MASK_LOW]; #ifdef ENABLE_DA2_DEBUGVRAM // da2_log("da2_wB %x %02x\n", addr, val); @@ -2756,7 +2774,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) break; case 0: if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val]; TODO this wont work + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->planemask & (1 << i)) { @@ -2774,22 +2792,13 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) } break; case 1: - // if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { - // for (int i = 0; i < 8; i++) - // if (da2->planemask & (1 << i)) { - // uint16_t wdata = (((val & (1 << i)) ? 0xffff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask); - // DA2_vram_w(addr | i, wdata & 0xff, da2); - // DA2_vram_w((addr + 8) | i, wdata >> 8, da2); - // } - // } else { - for (int i = 0; i < 8; i++) - da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); - da2_gdcropW(addr, bitmask, da2); - // } + for (int i = 0; i < 8; i++) + da2->gdcinput[i] = ((val & (1 << i)) ? 0xffff : 0); + da2_gdcropW(addr, bitmask, da2); break; case 3: if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); // val = svga_rotate[da2->gdcreg[LG_DATA_ROTATION] & 7][val];; TODO this wont work + val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); bitmask &= val; for (int i = 0; i < 8; i++) @@ -3117,7 +3126,6 @@ da2_reset(void *priv) /* Initialize drawing */ da2->bitblt.exec = DA2_BLT_CIDLE; - da2->render = da2_render_blank; da2_reset_ioctl(da2); da2->pos_regs[0] = DA2_POSID_L; /* Adapter Identification Byte (Low byte) */ @@ -3192,6 +3200,8 @@ da2_init(UNUSED(const device_t *info)) da2->mmrdbg_fp = fopen("da2_mmiordat.txt", "w"); #endif da2->bitblt.payload_addr = 0; + + timer_add(&da2->timer_vidupd, da2_updatevidselector_tick, da2, 0);/* Init timer before executing reset */ da2_reset(da2); mem_mapping_add(&da2->mmio.mapping, 0xA0000, 0x20000, da2_mmio_read, da2_mmio_readw, NULL, da2_mmio_write, da2_mmio_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, da2); From 5a77092a717164bd67c3a8f786753f30e8c67e04 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 5 Mar 2025 00:38:39 +0900 Subject: [PATCH 0364/1190] add support for 2nd sbcs in videomode 03 --- src/video/vid_ps55da2.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 0f5851c6f..1338304f1 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1111,7 +1111,7 @@ da2_bitblt_dopayload(void *priv) timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); /* do async operation but it causes the scrolling text glitch in OS/2 J1.3 Command Prompt (TODO) */ if (da2->bitblt.exec != DA2_BLT_CIDLE) { - while (da2->bitblt.exec != DA2_BLT_CIDLE) + while (da2->bitblt.exec != DA2_BLT_CIDLE) /* this disables async operation */ da2_bitblt_exec(da2); } else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { da2->bitblt.exec = DA2_BLT_CLOAD; @@ -2015,9 +2015,14 @@ da2_render_textm3(da2_t *da2) } } else { /* the char code is SBCS (ANK) */ - uint16_t font = da2->mmio.ram[DA2_GAIJIRAM_SBCS + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ + uint32_t fontbase; + if (extattr & 0x80) /* second map of SBCS font */ + fontbase = DA2_GAIJIRAM_SBEX; + else + fontbase = DA2_GAIJIRAM_SBCS; + uint16_t font = da2->mmio.ram[fontbase+ chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[DA2_GAIJIRAM_SBCS+ chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -2176,6 +2181,17 @@ da2_updatevidselector(da2_t *da2) timer_set_delay_u64(&da2->timer_vidupd, 100000ull * TIMER_USEC); } +/* + Video modes supported by DOS J4.0 for the DA-2 (The DA-2 doesn't have a video BIOS on its card.) + Mode (hex) Type Colors Format Base Address PELs + 3 A/N/K 16 80 x 25 B8000h 1040 x 725 + 8 A/N/K 1 80 x 25 E0000h 1040 x 725 + A APA 1 78 x 25 A0000h 1024 x 768 + D APA 16 78 x 25 A0000h 1024 x 768 + E A/N/K 16 80 x 25 E0000h 1040 x 725 + F APA 256 A0000h 1024 x 768 + 45 (undoc) APA 16 A0000h 1040 x 768 +*/ void da2_recalctimings(da2_t *da2) { From 73576bb61ed1fb90be962f87028c3a6244b7723d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 5 Mar 2025 01:23:37 +0600 Subject: [PATCH 0365/1190] Revert "S3 ViRGE: Make IRQs happen in main thread" This reverts commit fae26729f103010ddc7e621a37083bc4ae6d5736. --- src/video/vid_s3_virge.c | 57 +++++----------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 62ffcff0c..af33003cb 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -338,7 +338,6 @@ typedef struct virge_t { event_t * fifo_not_full_event; atomic_int virge_busy; - atomic_uint virge_irq_req; uint8_t subsys_stat; uint8_t subsys_cntl; @@ -374,9 +373,6 @@ typedef struct virge_t { uint32_t dma_mmio_addr; uint32_t dma_data_type; - pc_timer_t wake_timer; - pc_timer_t irq_timer; - int pci; int is_agp; } virge_t; @@ -387,28 +383,6 @@ wake_fifo_thread(virge_t *virge) { thread_set_event(virge->wake_fifo_thread); } -void -s3_virge_wake_fifo_timer(void* priv) -{ - virge_t *virge = (virge_t *) priv; - - thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -void -s3_virge_wake_fifo_thread(virge_t *virge) -{ - if (!timer_is_enabled(&virge->wake_timer)) { - /*Don't wake FIFO thread immediately - if we do that it will probably - process one word and go back to sleep, requiring it to be woken on - almost every write. Instead, wait a short while so that the CPU - emulation writes more data so we have more batched-up work.*/ - timer_on_auto(&virge->wake_timer, 100.0); - } - if (!timer_is_enabled(&virge->irq_timer)) - timer_on_auto(&virge->irq_timer, 100.0); -} - static virge_t *reset_state = NULL; static video_timings_t timing_diamond_stealth3d_2000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; @@ -497,19 +471,6 @@ s3_virge_update_irqs(virge_t *virge) pci_clear_irq(virge->pci_slot, PCI_INTA, &virge->irq_state); } -void -s3_virge_update_irq_timer(void* priv) -{ - virge_t *virge = (virge_t *) priv; - - if (virge->virge_irq_req) { - virge->virge_irq_req--; - s3_virge_update_irqs(virge); - } - - timer_on_auto(&virge->irq_timer, 100.); -} - static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { @@ -1140,9 +1101,6 @@ static void s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *) svga->priv; - if (virge->virge_irq_req) - virge->virge_irq_req--; - virge->subsys_stat |= INT_VSY; s3_virge_update_irqs(virge); } @@ -1837,8 +1795,7 @@ fifo_thread(void *param) if (virge->cmd_dma) virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); - //s3_virge_update_irqs(virge); - virge->virge_irq_req++; + s3_virge_update_irqs(virge); } } @@ -1878,8 +1835,10 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) virge->fifo_write_idx++; - if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 16) - s3_virge_wake_fifo_thread(virge); + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); } static void @@ -4445,8 +4404,7 @@ render_thread(void *param) } virge->s3d_busy = 0; virge->subsys_stat |= INT_S3D_DONE; - //s3_virge_update_irqs(virge); - virge->virge_irq_req++; + s3_virge_update_irqs(virge); } } @@ -5375,9 +5333,6 @@ s3_virge_init(const device_t *info) virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); - timer_add(&virge->wake_timer, s3_virge_wake_fifo_timer, virge, 0); - timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 0); - virge->local = info->local; *reset_state = *virge; From 92d69475f4eea136226842784ffdcf2d862dbb77 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 5 Mar 2025 02:17:51 +0600 Subject: [PATCH 0366/1190] Only retain the newer IRQ updating code --- src/video/vid_s3_virge.c | 43 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index af33003cb..904d4a4cf 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -338,6 +338,7 @@ typedef struct virge_t { event_t * fifo_not_full_event; atomic_int virge_busy; + atomic_uint irq_pending; uint8_t subsys_stat; uint8_t subsys_cntl; @@ -375,6 +376,8 @@ typedef struct virge_t { int pci; int is_agp; + + pc_timer_t irq_timer; } virge_t; static __inline void @@ -471,6 +474,19 @@ s3_virge_update_irqs(virge_t *virge) pci_clear_irq(virge->pci_slot, PCI_INTA, &virge->irq_state); } +static void +s3_virge_update_irq_timer(void* priv) +{ + virge_t *virge = (virge_t *) priv; + + if (virge->irq_pending) { + virge->irq_pending--; + s3_virge_update_irqs(virge); + } + + timer_on_auto(&virge->irq_timer, 100.); +} + static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { @@ -1101,6 +1117,8 @@ static void s3_virge_vblank_start(svga_t *svga) { virge_t *virge = (virge_t *) svga->priv; + if (virge->irq_pending) + virge->irq_pending--; virge->subsys_stat |= INT_VSY; s3_virge_update_irqs(virge); } @@ -1784,18 +1802,18 @@ fifo_thread(void *param) virge->fifo_read_idx++; fifo->addr_type = FIFO_INVALID; - if (FIFO_ENTRIES > 0xe000) - thread_set_event(virge->fifo_not_full_event); + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); - end_time = plat_timer_read(); - virge_time += end_time - start_time; - } - virge->virge_busy = 0; - virge->subsys_stat |= (INT_FIFO_EMP | INT_3DF_EMP); - if (virge->cmd_dma) - virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); + end_time = plat_timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + virge->subsys_stat |= (INT_FIFO_EMP | INT_3DF_EMP); + if (virge->cmd_dma) + virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); - s3_virge_update_irqs(virge); + virge->irq_pending++; } } @@ -4404,7 +4422,7 @@ render_thread(void *param) } virge->s3d_busy = 0; virge->subsys_stat |= INT_S3D_DONE; - s3_virge_update_irqs(virge); + virge->irq_pending++; } } @@ -5062,6 +5080,7 @@ s3_virge_disable_handlers(virge_t *dev) reset_state->svga.timer = dev->svga.timer; reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->irq_timer = dev->irq_timer; } static void @@ -5333,6 +5352,8 @@ s3_virge_init(const device_t *info) virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); + timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 1); + virge->local = info->local; *reset_state = *virge; From 6c92eb61bf4e8c0d225b9f6354324ff766cc13ab Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 5 Mar 2025 07:12:15 +0900 Subject: [PATCH 0367/1190] fix a screen glitch in OS/2 DOS MODE 1 fix a glitch in OS/2 DOS MODE 1 (monochrome graphics) --- src/video/vid_ps55da2.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 1338304f1..6568d9b45 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -259,7 +259,7 @@ #ifdef ENABLE_DA2_LOG # define ENABLE_DA2_DEBUGBLT 1 # define ENABLE_DA2_DEBUGVRAM 1 -# define ENABLE_DA2_DEBUGFULLSCREEN 1 +// # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 int da2_do_log = ENABLE_DA2_LOG; @@ -1227,7 +1227,9 @@ da2_out(uint16_t addr, uint16_t val, void *p) val = 0; break; case LC_START_ADDRESS_HIGH: - // if (da2->crtc[0x1c] & 0x40) return; + case LC_START_ADDRESS_LOW: + /* OS/2 DOS in MODE 1 read this to set the base line, but it does not work correctly. */ + val = 0; break; case LC_VERTICAL_TOTALJ: /* Vertical Total */ case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ @@ -1248,8 +1250,8 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LC_H_DISPLAY_ENABLE_END: case LC_VERTICAL_TOTALJ: case LC_MAXIMUM_SCAN_LINE: - case LC_START_ADDRESS_HIGH: - case LC_START_ADDRESS_LOW: + // case LC_START_ADDRESS_HIGH: + // case LC_START_ADDRESS_LOW: case LC_VERTICAL_SYNC_START: case LC_V_DISPLAY_ENABLE_END: case LC_START_VERTICAL_BLANK: @@ -2235,7 +2237,7 @@ da2_recalctimings(da2_t *da2) // da2->interlace = 0; - // da2->ma_latch = ((da2->crtc[0xc] & 0x3ff) << 8) | da2->crtc[0xd];//w + b + // da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW];//w + b da2->ca_adj = 0; da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; @@ -2517,7 +2519,7 @@ da2_mmio_readw(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; // da2_log("da2_readW: %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); - da2_log("da2_readW: %x %x %x %x %x CS:PC=%4x:%4x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, CS, cpu_state.pc); + // da2_log("da2_readW: %x %x %x %x %x CS:PC=%4x:%4x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, CS, cpu_state.pc); if (da2->ioctl[LS_MMIO] & 0x10) { return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); @@ -2553,7 +2555,7 @@ da2_mmio_readw(uint32_t addr, void *p) } return ~ret; } else { - // da2_log("da2_Rw: %05x=%04x\n", addr, da2->gdcla[da2->readplane]); + da2_log("da2_Rw: %05x(%d) = %04x\n", addr, da2->readplane, da2->gdcla[da2->readplane]); return da2->gdcla[da2->readplane]; } } else { @@ -3050,11 +3052,11 @@ da2_poll(void *priv) = da2->maback = da2->ma_latch; da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; - da2->ma <<= 1; - da2->maback <<= 1; + // da2->ma <<= 1; + // da2->maback <<= 1; da2->ca <<= 1; - // da2_log("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,da2_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], da2_interlace, oddeven); + // da2_log("Addr %08X vson %03X vsoff %01X\n",da2->ma,da2->vsyncstart,da2->crtc[0x11]&0xF); } if (da2->vc == da2->vtotal) { // da2_log("VC vtotal\n"); From 5b7766bb7ab571aee906dac14f8548e53905586c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 5 Mar 2025 12:35:56 +0900 Subject: [PATCH 0368/1190] disable debug logging, update comments --- src/video/vid_ps55da2.c | 45 ++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 6568d9b45..335cbf86d 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -10,7 +10,7 @@ * * Notes: There are some known issues that should be corrected. * - Incorrect foreground text color appears on an active window in OS/2 J1.3. - * - BitBlt's text drawing function does not work correctly. + * - Glitches some part of graphics on the Control Panel in OS/2 J2.1 beta. * - The screen resolution and blanking interval time maybe not correct. * * The code should be tested with following cases. @@ -253,11 +253,11 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 +// #define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG -# define ENABLE_DA2_DEBUGBLT 1 +// # define ENABLE_DA2_DEBUGBLT 1 # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 @@ -1228,7 +1228,8 @@ da2_out(uint16_t addr, uint16_t val, void *p) break; case LC_START_ADDRESS_HIGH: case LC_START_ADDRESS_LOW: - /* OS/2 DOS in MODE 1 read this to set the base line, but it does not work correctly. */ + /* The DOS J4.0 MODE 4 command and OS/2 driver write 0xFF00. + OS/2 DOS MODE 1 setup reads this to set the base line, but it causes the screen glitch. */ val = 0; break; case LC_VERTICAL_TOTALJ: /* Vertical Total */ @@ -1625,11 +1626,13 @@ da2_inb(uint16_t addr, void *p) uint16_t da2_inw(uint16_t addr, void *p) { - // uint16_t temp; + uint16_t temp; da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; da2->outflipflop = 0; - return da2_in(addr, da2); + temp = da2_in(addr, da2); + da2_log("DA2 Inw addr %03X val %04X\n", addr, temp); + return temp; } /* IO 03DAh : Input Status Register 2 for DOSSHELL used by DOS J4.0 */ uint8_t @@ -2184,15 +2187,15 @@ da2_updatevidselector(da2_t *da2) } /* - Video modes supported by DOS J4.0 for the DA-2 (The DA-2 doesn't have a video BIOS on its card.) - Mode (hex) Type Colors Format Base Address PELs - 3 A/N/K 16 80 x 25 B8000h 1040 x 725 - 8 A/N/K 1 80 x 25 E0000h 1040 x 725 - A APA 1 78 x 25 A0000h 1024 x 768 - D APA 16 78 x 25 A0000h 1024 x 768 - E A/N/K 16 80 x 25 E0000h 1040 x 725 - F APA 256 A0000h 1024 x 768 - 45 (undoc) APA 16 A0000h 1040 x 768 + INT 10h video modes supported in DOS J4.0 (The DA-2 doesn't have a video BIOS on its card.) + Mode Type Colors Text Base Address PELs Render + 3 A/N/K 16 80 x 25 B0000h/B8000h 1040 x 725 textm3 + 8 A/N/K 2 80 x 25 E0000h 1040 x 725 text + Ah APA 1 78 x 25 A0000h 1024 x 768 color_4bpp + Dh APA 16 78 x 25 A0000h 1024 x 768 color_4bpp + Eh A/N/K 16 80 x 25 E0000h 1040 x 725 text + Fh APA 256 NA A0000h 1024 x 768 color_8bpp + 45h(undoc) APA 16 NA A0000h 1040 x 768 color_4bpp */ void da2_recalctimings(da2_t *da2) @@ -2499,7 +2502,9 @@ da2_mmio_read(uint32_t addr, void *p) cycles -= video_timing_read_b; for (int i = 0; i < 8; i++) da2->gdcla[i] = da2->vram[(addr << 3) | i]; /* read in byte */ +#ifdef ENABLE_DA2_DEBUGVRAM da2_log("da2_Rb: %05x=%02x\n", addr, da2->gdcla[da2->readplane]); +#endif if (da2->gdcreg[LG_MODE] & 0x08) { /* compare data across planes if the read mode bit (3EB 05, bit 3) is 1 */ uint8_t ret = 0; for (int i = 0; i < 8; i++) { @@ -2555,7 +2560,9 @@ da2_mmio_readw(uint32_t addr, void *p) } return ~ret; } else { +#ifdef ENABLE_DA2_DEBUGVRAM da2_log("da2_Rw: %05x(%d) = %04x\n", addr, da2->readplane, da2->gdcla[da2->readplane]); +#endif return da2->gdcla[da2->readplane]; } } else { @@ -2612,11 +2619,11 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ uint8_t bitmask; - /* align bitmask with even address (need to verify the condition with OS/2 J2.x, Win 3.x and A-Train IV Win) */ - /* With byte align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): bad, OS/2 J2.0(cmd) - ok */ + /* Align bitmask with even address */ + /* With byte align: Win 3.1 (Window) - ok, Solitaire 3.1 - ok, A-Train IV (splash): bad, OS/2 J2.0(cmd) - ok */ // if ((addr & 1) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; - /* Without byte align: Win 3.1 (Window Title) - bad, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok */ - /* With byte align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok, DOS J4.0 MC - ok */ + /* Without byte align: Win 3.1 (Window) - bad, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok */ + /* With byte align: Win 3.1 (Window) - ok, Solitaire 3.1 - ok, A-Train IV (splash): ok, OS/2 J2.0(cmd) - ok */ if ((addr & 1)) bitmask = da2->gdcreg[LG_BIT_MASK_HIGH]; else /* No align: Win 3.1 (Window Title) - ok, Solitaire 3.1 - ok, A-Train IV (splash): bad, OS/2 J2.0(cmd) - bad */ From 1a60f5aac4b7874cd0e16f78fa513b7b72a78949 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:01:58 +0900 Subject: [PATCH 0369/1190] remove video timing modification --- src/video/vid_ps55da2.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 335cbf86d..823ef4d2f 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -2220,14 +2220,7 @@ da2_recalctimings(da2_t *da2) if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { da2->hdisp--; da2->dispend -= 29; - } else { - // da2->vtotal += 2; - da2->dispend--; - // da2->vsyncstart++; - // da2->split++; - // da2->vblankstart++; - // da2->hdisp--; - } + } da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; da2->htotal += 1; From 8c2db2892d98b8b599f002c944667c47b10dc39e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 5 Mar 2025 21:52:17 +0100 Subject: [PATCH 0370/1190] CPU: Fix Cyrix SMM instructions. --- src/cpu/386_ops.h | 104 +++++++++++++++++++++++++++++++++++++++++--- src/cpu/cpu.c | 10 +---- src/cpu/cpu.h | 50 +++++++++++---------- src/cpu/cpu_table.c | 87 ++++++++++++++++++++++++++++++++++++ src/cpu/x86_ops.h | 2 + 5 files changed, 215 insertions(+), 38 deletions(-) diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index b8ef9edda..80a856482 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -859,12 +859,12 @@ const OpFn OP_TABLE(c486_0f)[1024] = { /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, /*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, /*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, @@ -1392,7 +1392,7 @@ const OpFn OP_TABLE(c6x86_0f)[1024] = { /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1414,7 +1414,7 @@ const OpFn OP_TABLE(c6x86_0f)[1024] = { /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1436,7 +1436,7 @@ const OpFn OP_TABLE(c6x86_0f)[1024] = { /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -1458,7 +1458,99 @@ const OpFn OP_TABLE(c6x86_0f)[1024] = { /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + // clang-format on +}; + +const OpFn OP_TABLE(c6x86l_0f)[1024] = { + // clang-format off + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, opRSM, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, opRSM, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 0802fa3ac..2d22ed796 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1462,22 +1462,16 @@ cpu_set(void) if (cpu_s->cpu_type == CPU_Cx6x86MX) x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); else if (cpu_s->cpu_type == CPU_Cx6x86L) - x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + x86_setopcodes(ops_386, ops_c6x86l_0f, dynarec_ops_386, dynarec_ops_c6x86l_0f); else - x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); -# if 0 x86_setopcodes(ops_386, ops_c6x86_0f, dynarec_ops_386, dynarec_ops_c6x86_0f); -# endif # else if (cpu_s->cpu_type == CPU_Cx6x86MX) x86_setopcodes(ops_386, ops_c6x86mx_0f); else if (cpu_s->cpu_type == CPU_Cx6x86L) - x86_setopcodes(ops_386, ops_pentium_0f); + x86_setopcodes(ops_386, ops_c6x86l_0f); else - x86_setopcodes(ops_386, ops_c6x86mx_0f); -# if 0 x86_setopcodes(ops_386, ops_c6x86_0f); -# endif # endif /* USE_DYNAREC */ timing_rr = 1; /* register dest - register src */ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 1d003ddc9..3e72db005 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -87,30 +87,32 @@ enum { enum { CPU_PKG_8088 = (1 << 0), CPU_PKG_8088_EUROPC = (1 << 1), - CPU_PKG_8086 = (1 << 2), - CPU_PKG_8086_MAZOVIA = (1 << 3), - CPU_PKG_188 = (1 << 4), - CPU_PKG_186 = (1 << 5), - CPU_PKG_286 = (1 << 6), - CPU_PKG_386SX = (1 << 7), - CPU_PKG_386DX = (1 << 8), - CPU_PKG_386DX_DESKPRO386 = (1 << 9), - CPU_PKG_M6117 = (1 << 10), - CPU_PKG_386SLC_IBM = (1 << 11), - CPU_PKG_486SLC = (1 << 12), - CPU_PKG_486SLC_IBM = (1 << 13), - CPU_PKG_486BL = (1 << 14), - CPU_PKG_486DLC = (1 << 15), - CPU_PKG_SOCKET1 = (1 << 16), - CPU_PKG_SOCKET3 = (1 << 17), - CPU_PKG_SOCKET3_PC330 = (1 << 18), - CPU_PKG_STPC = (1 << 19), - CPU_PKG_SOCKET4 = (1 << 20), - CPU_PKG_SOCKET5_7 = (1 << 21), - CPU_PKG_SOCKET8 = (1 << 22), - CPU_PKG_SLOT1 = (1 << 23), - CPU_PKG_SLOT2 = (1 << 24), - CPU_PKG_SOCKET370 = (1 << 25) + CPU_PKG_8088_VTECH = (1 << 2), + CPU_PKG_8086 = (1 << 3), + CPU_PKG_8086_MAZOVIA = (1 << 4), + CPU_PKG_8086_VTECH = (1 << 5), + CPU_PKG_188 = (1 << 6), + CPU_PKG_186 = (1 << 7), + CPU_PKG_286 = (1 << 8), + CPU_PKG_386SX = (1 << 9), + CPU_PKG_386DX = (1 << 10), + CPU_PKG_386DX_DESKPRO386 = (1 << 11), + CPU_PKG_M6117 = (1 << 12), + CPU_PKG_386SLC_IBM = (1 << 13), + CPU_PKG_486SLC = (1 << 14), + CPU_PKG_486SLC_IBM = (1 << 15), + CPU_PKG_486BL = (1 << 16), + CPU_PKG_486DLC = (1 << 17), + CPU_PKG_SOCKET1 = (1 << 18), + CPU_PKG_SOCKET3 = (1 << 19), + CPU_PKG_SOCKET3_PC330 = (1 << 20), + CPU_PKG_STPC = (1 << 21), + CPU_PKG_SOCKET4 = (1 << 22), + CPU_PKG_SOCKET5_7 = (1 << 23), + CPU_PKG_SOCKET8 = (1 << 24), + CPU_PKG_SLOT1 = (1 << 25), + CPU_PKG_SLOT2 = (1 << 26), + CPU_PKG_SOCKET370 = (1 << 27) }; #define CPU_SUPPORTS_DYNAREC 1 diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index b2ef71075..104d56d05 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -262,6 +262,50 @@ const cpu_family_t cpu_families[] = { { .name = "", 0 } } }, + { + .package = CPU_PKG_8088_VTECH, + .manufacturer = "Intel", + .name = "8088", + .internal_name = "8088_vtech", + .cpus = (const CPU[]) { + { + .name = "4.77", + .cpu_type = CPU_8088, + .fpus = fpus_8088, + .rspeed = 4772728, + .multi = 1, + .voltage = 5000, + .edx_reset = 0, + .cpuid_model = 0, + .cyrix_id = 0, + .cpu_flags = 0, + .mem_read_cycles = 0, + .mem_write_cycles = 0, + .cache_read_cycles = 0, + .cache_write_cycles = 0, + .atclk_div = 1 + }, + + { + .name = "10", + .cpu_type = CPU_8088, + .fpus = fpus_8088, + .rspeed = 10000000, + .multi = 1, + .voltage = 5000, + .edx_reset = 0, + .cpuid_model = 0, + .cyrix_id = 0, + .cpu_flags = 0, + .mem_read_cycles = 0, + .mem_write_cycles = 0, + .cache_read_cycles = 0, + .cache_write_cycles = 0, + .atclk_div = 1 + }, + { .name = "", 0 } + } + }, { .package = CPU_PKG_8086, .manufacturer = "Intel", @@ -399,6 +443,49 @@ const cpu_family_t cpu_families[] = { { .name = "", 0 } } }, + { + .package = CPU_PKG_8086_VTECH, + .manufacturer = "Intel", + .name = "8086", + .internal_name = "8086_vtech", + .cpus = (const CPU[]) { + { + .name = "4.77", + .cpu_type = CPU_8086, + .fpus = fpus_8088, + .rspeed = 4772728, + .multi = 1, + .voltage = 5000, + .edx_reset = 0, + .cpuid_model = 0, + .cyrix_id = 0, + .cpu_flags = 0, + .mem_read_cycles = 0, + .mem_write_cycles = 0, + .cache_read_cycles = 0, + .cache_write_cycles = 0, + .atclk_div = 1 + }, + { + .name = "10", + .cpu_type = CPU_8086, + .fpus = fpus_8088, + .rspeed = 10000000, + .multi = 1, + .voltage = 5000, + .edx_reset = 0, + .cpuid_model = 0, + .cyrix_id = 0, + .cpu_flags = 0, + .mem_read_cycles = 0, + .mem_write_cycles = 0, + .cache_read_cycles = 0, + .cache_write_cycles = 0, + .atclk_div = 1 + }, + { .name = "", 0 } + } + }, { .package = CPU_PKG_188, .manufacturer = "Intel", diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 3dfb3f917..7aec16855 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -92,6 +92,7 @@ extern const OpFn dynarec_ops_pentiummmx_0f[1024]; # ifdef USE_CYRIX_6X86 extern const OpFn dynarec_ops_c6x86_0f[1024]; +extern const OpFn dynarec_ops_c6x86l_0f[1024]; extern const OpFn dynarec_ops_c6x86mx_0f[1024]; # endif /* USE_CYRIX_6X86 */ @@ -234,6 +235,7 @@ extern const OpFn ops_pentiummmx_0f[1024]; #ifdef USE_CYRIX_6X86 extern const OpFn ops_c6x86_0f[1024]; +extern const OpFn ops_c6x86l_0f[1024]; extern const OpFn ops_c6x86mx_0f[1024]; #endif /* USE_CYRIX_6X86 */ From 5f3641ecbd7faf5caa77016392207a42ff9a2377 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 00:54:28 +0600 Subject: [PATCH 0371/1190] Implement Cyrix EMMI extensions and 4 FPU instructions PADDSIW, PSUBSIW, PMULHRW (named PMULHRWC in the code as recognized by some assemblers), PMULHRIW, PDISTIB, PMACHRIW, PAVEB, PMAGW, PMVZB, PMVNZB, PMVLZB, PMVGEZB, FTSTP, FRINT2, FRINEAR, FRICHOP are implemented for Cyrix 6x86MX. Cyrix 6x86(L) only has the last 4 instructions. --- src/cpu/386_ops.h | 9 +- src/cpu/cpu.c | 47 +- src/cpu/cpu.h | 10 + src/cpu/x86.c | 4 + src/cpu/x86_ops.h | 18 + src/cpu/x86_ops_mmx_emmi.h | 807 +++++++++++++++++++++++++++++++++++ src/cpu/x87_ops.h | 664 ++++++++++++++++++++++++++++ src/cpu/x87_ops_misc.h | 77 ++++ src/cpu/x87_ops_sf_arith.h | 81 ++++ src/cpu/x87_ops_sf_compare.h | 26 ++ 10 files changed, 1723 insertions(+), 20 deletions(-) create mode 100644 src/cpu/x86_ops_mmx_emmi.h diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 80a856482..e8300f134 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -206,6 +206,7 @@ extern void x386_dynarec_log(const char *fmt, ...); # include "x86_ops_mmx_mov.h" # include "x86_ops_mmx_pack.h" # include "x86_ops_mmx_shift.h" +# include "x86_ops_mmx_emmi.h" #endif #include "x86_ops_mov.h" #ifdef OPS_286_386 @@ -1857,7 +1858,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ opPAVEB_a16, opPADDSIW_a16, opPMAGW_a16, ILLEGAL, opPDISTIB_a16, opPSUBSIW_a16, ILLEGAL, ILLEGAL, opPMVZB_a16, opPMULHRWC_a16, opPMVNZB_a16, opPMVLZB_a16, opPMVGEZB_a16, opPMULHRIW_a16, opPMACHRIW_a16, ILLEGAL, /*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, /*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,opMOVQ_mm_q_a16, @@ -1879,7 +1880,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ opPAVEB_a16, opPADDSIW_a16, opPMAGW_a16, ILLEGAL, opPDISTIB_a16, opPSUBSIW_a16, ILLEGAL, ILLEGAL, opPMVZB_a16, opPMULHRWC_a16, opPMVNZB_a16, opPMVLZB_a16, opPMVGEZB_a16, opPMULHRIW_a16, opPMACHRIW_a16, ILLEGAL, /*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, /*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,opMOVQ_mm_q_a16, @@ -1901,7 +1902,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ opPAVEB_a32, opPADDSIW_a32, opPMAGW_a32, ILLEGAL, opPDISTIB_a32, opPSUBSIW_a32, ILLEGAL, ILLEGAL, opPMVZB_a32, opPMULHRWC_a32, opPMVNZB_a32, opPMVLZB_a32, opPMVGEZB_a32, opPMULHRIW_a32, opPMACHRIW_a32, ILLEGAL, /*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, /*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opMOVD_mm_l_a32_cx,opMOVQ_mm_q_a32, @@ -1923,7 +1924,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, -/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ opPAVEB_a32, opPADDSIW_a32, opPMAGW_a32, ILLEGAL, opPDISTIB_a32, opPSUBSIW_a32, ILLEGAL, ILLEGAL, opPMVZB_a32, opPMULHRWC_a32, opPMVNZB_a32, opPMVLZB_a32, opPMVGEZB_a32, opPMULHRIW_a32, opPMACHRIW_a32, ILLEGAL, /*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, /*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a32_cx,opMOVQ_mm_q_a32, diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 2d22ed796..13a109d38 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -279,13 +279,14 @@ uint8_t do_translate2 = 0; void (*cpu_exec)(int32_t cycs); -static uint8_t ccr0; -static uint8_t ccr1; -static uint8_t ccr2; -static uint8_t ccr3; -static uint8_t ccr4; -static uint8_t ccr5; -static uint8_t ccr6; +uint8_t ccr0; +uint8_t ccr1; +uint8_t ccr2; +uint8_t ccr3; +uint8_t ccr4; +uint8_t ccr5; +uint8_t ccr6; +uint8_t ccr7; static int cyrix_addr; @@ -557,7 +558,8 @@ cpu_set(void) cpu_busspeed = cpu_s->rspeed; cpu_multi = (int) ceil(cpu_s->multi); cpu_dmulti = cpu_s->multi; - ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = ccr7 = 0; + ccr4 = 0x85; cpu_update_waitstates(); @@ -1442,19 +1444,27 @@ cpu_set(void) } # endif /* USE_DYNAREC */ if (fpu_softfloat) { + x86_opcodes_d9_a16 = ops_sf_fpu_cyrix_d9_a16; + x86_opcodes_d9_a32 = ops_sf_fpu_cyrix_d9_a32; x86_opcodes_da_a16 = ops_sf_fpu_686_da_a16; x86_opcodes_da_a32 = ops_sf_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_sf_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_sf_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_sf_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_sf_fpu_686_df_a32; + x86_opcodes_db_a16 = ops_sf_fpu_cyrix_686_db_a16; + x86_opcodes_db_a32 = ops_sf_fpu_cyrix_686_db_a32; + x86_opcodes_dd_a16 = ops_sf_fpu_cyrix_dd_a16; + x86_opcodes_dd_a32 = ops_sf_fpu_cyrix_dd_a32; + x86_opcodes_df_a16 = ops_sf_fpu_cyrix_686_df_a16; + x86_opcodes_df_a32 = ops_sf_fpu_cyrix_686_df_a32; } else { + x86_opcodes_d9_a16 = ops_fpu_cyrix_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_cyrix_d9_a32; x86_opcodes_da_a16 = ops_fpu_686_da_a16; x86_opcodes_da_a32 = ops_fpu_686_da_a32; - x86_opcodes_db_a16 = ops_fpu_686_db_a16; - x86_opcodes_db_a32 = ops_fpu_686_db_a32; - x86_opcodes_df_a16 = ops_fpu_686_df_a16; - x86_opcodes_df_a32 = ops_fpu_686_df_a32; + x86_opcodes_db_a16 = ops_fpu_cyrix_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_cyrix_686_db_a32; + x86_opcodes_dd_a16 = ops_fpu_cyrix_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_cyrix_dd_a32; + x86_opcodes_df_a16 = ops_fpu_cyrix_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_cyrix_686_df_a32; } } @@ -4291,6 +4301,9 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) if ((ccr3 & 0xf0) == 0x10) ccr6 = val; break; + case 0xeb: /* CCR7 */ + ccr7 = val & 5; + break; } } @@ -4319,6 +4332,8 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xeb: + return ccr7; case 0xfe: return cpu_s->cyrix_id & 0xff; case 0xff: diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 3e72db005..8324c543e 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -589,6 +589,16 @@ extern uint32_t _tr[8]; extern uint32_t cache_index; extern uint8_t _cache[2048]; +/* For the Cyrix 6x86(MX) */ +extern uint8_t ccr0; +extern uint8_t ccr1; +extern uint8_t ccr2; +extern uint8_t ccr3; +extern uint8_t ccr4; +extern uint8_t ccr5; +extern uint8_t ccr6; +extern uint8_t ccr7; + /*Segments - _cs,_ds,_es,_ss are the segment structures CS,DS,ES,SS is the 16-bit data diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 6f15560f3..f1f5004d9 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -272,6 +272,10 @@ reset_common(int hard) msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); msw = 0; new_ne = 0; + + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = ccr7 = 0; + ccr4 = 0x85; + if (hascache) cr0 = 1 << 30; else diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 7aec16855..6d93fb435 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -265,14 +265,20 @@ extern const OpFn ops_sf_fpu_d8_a16[32]; extern const OpFn ops_sf_fpu_d8_a32[32]; extern const OpFn ops_sf_fpu_d9_a16[256]; extern const OpFn ops_sf_fpu_d9_a32[256]; +extern const OpFn ops_sf_fpu_cyrix_d9_a16[256]; +extern const OpFn ops_sf_fpu_cyrix_d9_a32[256]; extern const OpFn ops_sf_fpu_da_a16[256]; extern const OpFn ops_sf_fpu_da_a32[256]; extern const OpFn ops_sf_fpu_db_a16[256]; extern const OpFn ops_sf_fpu_db_a32[256]; +extern const OpFn ops_sf_fpu_cyrix_686_db_a16[256]; +extern const OpFn ops_sf_fpu_cyrix_686_db_a32[256]; extern const OpFn ops_sf_fpu_dc_a16[32]; extern const OpFn ops_sf_fpu_dc_a32[32]; extern const OpFn ops_sf_fpu_dd_a16[256]; extern const OpFn ops_sf_fpu_dd_a32[256]; +extern const OpFn ops_sf_fpu_cyrix_dd_a16[256]; +extern const OpFn ops_sf_fpu_cyrix_dd_a32[256]; extern const OpFn ops_sf_fpu_de_a16[256]; extern const OpFn ops_sf_fpu_de_a32[256]; extern const OpFn ops_sf_fpu_df_a16[256]; @@ -297,6 +303,8 @@ extern const OpFn ops_fpu_d8_a16[32]; extern const OpFn ops_fpu_d8_a32[32]; extern const OpFn ops_fpu_d9_a16[256]; extern const OpFn ops_fpu_d9_a32[256]; +extern const OpFn ops_fpu_cyrix_d9_a16[256]; +extern const OpFn ops_fpu_cyrix_d9_a32[256]; extern const OpFn ops_fpu_da_a16[256]; extern const OpFn ops_fpu_da_a32[256]; extern const OpFn ops_fpu_db_a16[256]; @@ -305,6 +313,8 @@ extern const OpFn ops_fpu_dc_a16[32]; extern const OpFn ops_fpu_dc_a32[32]; extern const OpFn ops_fpu_dd_a16[256]; extern const OpFn ops_fpu_dd_a32[256]; +extern const OpFn ops_fpu_cyrix_dd_a16[256]; +extern const OpFn ops_fpu_cyrix_dd_a32[256]; extern const OpFn ops_fpu_de_a16[256]; extern const OpFn ops_fpu_de_a32[256]; extern const OpFn ops_fpu_df_a16[256]; @@ -316,15 +326,23 @@ extern const OpFn ops_sf_fpu_686_da_a16[256]; extern const OpFn ops_sf_fpu_686_da_a32[256]; extern const OpFn ops_sf_fpu_686_db_a16[256]; extern const OpFn ops_sf_fpu_686_db_a32[256]; +extern const OpFn ops_sf_fpu_cyrix_686_db_a16[256]; +extern const OpFn ops_sf_fpu_cyrix_686_db_a32[256]; extern const OpFn ops_sf_fpu_686_df_a16[256]; extern const OpFn ops_sf_fpu_686_df_a32[256]; +extern const OpFn ops_sf_fpu_cyrix_686_df_a16[256]; +extern const OpFn ops_sf_fpu_cyrix_686_df_a32[256]; extern const OpFn ops_fpu_686_da_a16[256]; extern const OpFn ops_fpu_686_da_a32[256]; extern const OpFn ops_fpu_686_db_a16[256]; extern const OpFn ops_fpu_686_db_a32[256]; +extern const OpFn ops_fpu_cyrix_686_db_a16[256]; +extern const OpFn ops_fpu_cyrix_686_db_a32[256]; extern const OpFn ops_fpu_686_df_a16[256]; extern const OpFn ops_fpu_686_df_a32[256]; +extern const OpFn ops_fpu_cyrix_686_df_a16[256]; +extern const OpFn ops_fpu_cyrix_686_df_a32[256]; extern const OpFn ops_REPE[1024]; extern const OpFn ops_REPNE[1024]; diff --git a/src/cpu/x86_ops_mmx_emmi.h b/src/cpu/x86_ops_mmx_emmi.h new file mode 100644 index 000000000..4c994be0f --- /dev/null +++ b/src/cpu/x86_ops_mmx_emmi.h @@ -0,0 +1,807 @@ +/* Notes: "src2" means "first operand" */ + +static int +opPMULHRWC_a16(UNUSED(uint32_t fetchdat)) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + dst->w[0] = ((int32_t) (dst->sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] = ((int32_t) (dst->sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] = ((int32_t) (dst->sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] = ((int32_t) (dst->sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPMULHRWC_a32(UNUSED(uint32_t fetchdat)) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + dst->w[0] = ((int32_t) (dst->sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] = ((int32_t) (dst->sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] = ((int32_t) (dst->sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] = ((int32_t) (dst->sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPMULHRIW_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->w[0] = (((int32_t) src2.sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] = (((int32_t) src2.sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] = (((int32_t) src2.sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] = (((int32_t) src2.sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPMULHRIW_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->w[0] = (((int32_t) src2.sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] = (((int32_t) src2.sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] = (((int32_t) src2.sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] = (((int32_t) src2.sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPDISTIB_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->b[0] = USATB(dst->b[0] + abs(src2.b[0] - src.b[0])); + dst->b[1] = USATB(dst->b[1] + abs(src2.b[1] - src.b[1])); + dst->b[2] = USATB(dst->b[2] + abs(src2.b[2] - src.b[2])); + dst->b[3] = USATB(dst->b[3] + abs(src2.b[3] - src.b[3])); + dst->b[4] = USATB(dst->b[4] + abs(src2.b[4] - src.b[4])); + dst->b[5] = USATB(dst->b[5] + abs(src2.b[5] - src.b[5])); + dst->b[6] = USATB(dst->b[6] + abs(src2.b[6] - src.b[6])); + dst->b[7] = USATB(dst->b[7] + abs(src2.b[7] - src.b[7])); + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPDISTIB_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->b[0] = USATB(dst->b[0] + abs(src2.b[0] - src.b[0])); + dst->b[1] = USATB(dst->b[1] + abs(src2.b[1] - src.b[1])); + dst->b[2] = USATB(dst->b[2] + abs(src2.b[2] - src.b[2])); + dst->b[3] = USATB(dst->b[3] + abs(src2.b[3] - src.b[3])); + dst->b[4] = USATB(dst->b[4] + abs(src2.b[4] - src.b[4])); + dst->b[5] = USATB(dst->b[5] + abs(src2.b[5] - src.b[5])); + dst->b[6] = USATB(dst->b[6] + abs(src2.b[6] - src.b[6])); + dst->b[7] = USATB(dst->b[7] + abs(src2.b[7] - src.b[7])); + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPMACHRIW_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->w[0] += (((int32_t) src2.sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] += (((int32_t) src2.sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] += (((int32_t) src2.sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] += (((int32_t) src2.sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPMACHRIW_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->w[0] += (((int32_t) src2.sw[0] * (int32_t) src.sw[0]) + 0x4000) >> 15; + dst->w[1] += (((int32_t) src2.sw[1] * (int32_t) src.sw[1]) + 0x4000) >> 15; + dst->w[2] += (((int32_t) src2.sw[2] * (int32_t) src.sw[2]) + 0x4000) >> 15; + dst->w[3] += (((int32_t) src2.sw[3] * (int32_t) src.sw[3]) + 0x4000) >> 15; + + MMX_SETEXP(cpu_reg ^ 1); + return 0; +} + +static int +opPADDSIW_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->sw[0] = SSATW(src2.sw[0] + src.sw[0]); + dst->sw[1] = SSATW(src2.sw[1] + src.sw[1]); + dst->sw[2] = SSATW(src2.sw[2] + src.sw[2]); + dst->sw[3] = SSATW(src2.sw[3] + src.sw[3]); + + MMX_SETEXP(cpu_reg ^ 1); + + return 0; +} + +static int +opPADDSIW_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->sw[0] = SSATW(src2.sw[0] + src.sw[0]); + dst->sw[1] = SSATW(src2.sw[1] + src.sw[1]); + dst->sw[2] = SSATW(src2.sw[2] + src.sw[2]); + dst->sw[3] = SSATW(src2.sw[3] + src.sw[3]); + + MMX_SETEXP(cpu_reg ^ 1); + + return 0; +} + +static int +opPSUBSIW_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->sw[0] = SSATW(src2.sw[0] - src.sw[0]); + dst->sw[1] = SSATW(src2.sw[1] - src.sw[1]); + dst->sw[2] = SSATW(src2.sw[2] - src.sw[2]); + dst->sw[3] = SSATW(src2.sw[3] - src.sw[3]); + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPSUBSIW_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + src2 = MMX_GETREG(cpu_reg); + dst = MMX_GETREGP(cpu_reg ^ 1); + + MMX_GETSRC(); + + dst->sw[0] = SSATW(src2.sw[0] - src.sw[0]); + dst->sw[1] = SSATW(src2.sw[1] - src.sw[1]); + dst->sw[2] = SSATW(src2.sw[2] - src.sw[2]); + dst->sw[3] = SSATW(src2.sw[3] - src.sw[3]); + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPAVEB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + dst->b[0] = (dst->b[0] + src.b[0]) >> 1; + dst->b[1] = (dst->b[1] + src.b[1]) >> 1; + dst->b[2] = (dst->b[2] + src.b[2]) >> 1; + dst->b[3] = (dst->b[3] + src.b[3]) >> 1; + dst->b[4] = (dst->b[4] + src.b[4]) >> 1; + dst->b[5] = (dst->b[5] + src.b[5]) >> 1; + dst->b[6] = (dst->b[6] + src.b[6]) >> 1; + dst->b[7] = (dst->b[7] + src.b[7]) >> 1; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPAVEB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + dst->b[0] = (dst->b[0] + src.b[0]) >> 1; + dst->b[1] = (dst->b[1] + src.b[1]) >> 1; + dst->b[2] = (dst->b[2] + src.b[2]) >> 1; + dst->b[3] = (dst->b[3] + src.b[3]) >> 1; + dst->b[4] = (dst->b[4] + src.b[4]) >> 1; + dst->b[5] = (dst->b[5] + src.b[5]) >> 1; + dst->b[6] = (dst->b[6] + src.b[6]) >> 1; + dst->b[7] = (dst->b[7] + src.b[7]) >> 1; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMAGW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + if (abs(src.sw[0]) > abs(dst->sw[0])) dst->sw[0] = src.sw[0]; + if (abs(src.sw[1]) > abs(dst->sw[1])) dst->sw[1] = src.sw[1]; + if (abs(src.sw[2]) > abs(dst->sw[2])) dst->sw[2] = src.sw[2]; + if (abs(src.sw[3]) > abs(dst->sw[3])) dst->sw[3] = src.sw[3]; + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPMAGW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + dst = MMX_GETREGP(cpu_reg); + + MMX_GETSRC(); + + if (abs(src.sw[0]) > abs(dst->sw[0])) dst->sw[0] = src.sw[0]; + if (abs(src.sw[1]) > abs(dst->sw[1])) dst->sw[1] = src.sw[1]; + if (abs(src.sw[2]) > abs(dst->sw[2])) dst->sw[2] = src.sw[2]; + if (abs(src.sw[3]) > abs(dst->sw[3])) dst->sw[3] = src.sw[3]; + + MMX_SETEXP(cpu_reg); + + return 0; +} + +static int +opPMVZB_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.b[0] == 0) dst->b[0] = src.b[0]; + if (src2.b[1] == 0) dst->b[1] = src.b[1]; + if (src2.b[2] == 0) dst->b[2] = src.b[2]; + if (src2.b[3] == 0) dst->b[3] = src.b[3]; + if (src2.b[4] == 0) dst->b[4] = src.b[4]; + if (src2.b[5] == 0) dst->b[5] = src.b[5]; + if (src2.b[6] == 0) dst->b[6] = src.b[6]; + if (src2.b[7] == 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVZB_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.b[0] == 0) dst->b[0] = src.b[0]; + if (src2.b[1] == 0) dst->b[1] = src.b[1]; + if (src2.b[2] == 0) dst->b[2] = src.b[2]; + if (src2.b[3] == 0) dst->b[3] = src.b[3]; + if (src2.b[4] == 0) dst->b[4] = src.b[4]; + if (src2.b[5] == 0) dst->b[5] = src.b[5]; + if (src2.b[6] == 0) dst->b[6] = src.b[6]; + if (src2.b[7] == 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVNZB_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.b[0] != 0) dst->b[0] = src.b[0]; + if (src2.b[1] != 0) dst->b[1] = src.b[1]; + if (src2.b[2] != 0) dst->b[2] = src.b[2]; + if (src2.b[3] != 0) dst->b[3] = src.b[3]; + if (src2.b[4] != 0) dst->b[4] = src.b[4]; + if (src2.b[5] != 0) dst->b[5] = src.b[5]; + if (src2.b[6] != 0) dst->b[6] = src.b[6]; + if (src2.b[7] != 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVNZB_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.b[0] != 0) dst->b[0] = src.b[0]; + if (src2.b[1] != 0) dst->b[1] = src.b[1]; + if (src2.b[2] != 0) dst->b[2] = src.b[2]; + if (src2.b[3] != 0) dst->b[3] = src.b[3]; + if (src2.b[4] != 0) dst->b[4] = src.b[4]; + if (src2.b[5] != 0) dst->b[5] = src.b[5]; + if (src2.b[6] != 0) dst->b[6] = src.b[6]; + if (src2.b[7] != 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVLZB_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.sb[0] < 0) dst->b[0] = src.b[0]; + if (src2.sb[1] < 0) dst->b[1] = src.b[1]; + if (src2.sb[2] < 0) dst->b[2] = src.b[2]; + if (src2.sb[3] < 0) dst->b[3] = src.b[3]; + if (src2.sb[4] < 0) dst->b[4] = src.b[4]; + if (src2.sb[5] < 0) dst->b[5] = src.b[5]; + if (src2.sb[6] < 0) dst->b[6] = src.b[6]; + if (src2.sb[7] < 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVLZB_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.sb[0] < 0) dst->b[0] = src.b[0]; + if (src2.sb[1] < 0) dst->b[1] = src.b[1]; + if (src2.sb[2] < 0) dst->b[2] = src.b[2]; + if (src2.sb[3] < 0) dst->b[3] = src.b[3]; + if (src2.sb[4] < 0) dst->b[4] = src.b[4]; + if (src2.sb[5] < 0) dst->b[5] = src.b[5]; + if (src2.sb[6] < 0) dst->b[6] = src.b[6]; + if (src2.sb[7] < 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVGEZB_a16(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.sb[0] >= 0) dst->b[0] = src.b[0]; + if (src2.sb[1] >= 0) dst->b[1] = src.b[1]; + if (src2.sb[2] >= 0) dst->b[2] = src.b[2]; + if (src2.sb[3] >= 0) dst->b[3] = src.b[3]; + if (src2.sb[4] >= 0) dst->b[4] = src.b[4]; + if (src2.sb[5] >= 0) dst->b[5] = src.b[5]; + if (src2.sb[6] >= 0) dst->b[6] = src.b[6]; + if (src2.sb[7] >= 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} + +static int +opPMVGEZB_a32(uint32_t fetchdat) +{ + MMX_REG src, src2; + MMX_REG *dst; + + if (!(ccr7 & 1)) { + x86illegal(); + return 1; + } + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_mod == 3) { + x86illegal(); + return 1; + } + + dst = MMX_GETREGP(cpu_reg); + src2 = MMX_GETREG(cpu_reg ^ 1); + + MMX_GETSRC(); + + if (src2.sb[0] >= 0) dst->b[0] = src.b[0]; + if (src2.sb[1] >= 0) dst->b[1] = src.b[1]; + if (src2.sb[2] >= 0) dst->b[2] = src.b[2]; + if (src2.sb[3] >= 0) dst->b[3] = src.b[3]; + if (src2.sb[4] >= 0) dst->b[4] = src.b[4]; + if (src2.sb[5] >= 0) dst->b[5] = src.b[5]; + if (src2.sb[6] >= 0) dst->b[6] = src.b[6]; + if (src2.sb[7] >= 0) dst->b[7] = src.b[7]; + + MMX_SETEXP(cpu_reg); + return 0; +} \ No newline at end of file diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index f1362bf76..97f5415b9 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -241,6 +241,24 @@ x87_fround32_64(double b) return (int64_t) x87_fround32(b); } +static __inline int64_t +x87_fround_nearest(double b) +{ + double da, dc; + int64_t a, c; + + da = floor(b); + dc = floor(b + 1.0); + a = (int64_t) da; + c = (int64_t) dc; + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; +} + static __inline int64_t x87_fround(double b) { @@ -1267,6 +1285,86 @@ const OpFn OP_TABLE(sf_fpu_d9_a32)[256] = { // clang-format on }; +const OpFn OP_TABLE(sf_fpu_cyrix_d9_a16)[256] = { + // clang-format off + /*0x00*/ sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, + /*0x08*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x10*/ sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, + /*0x18*/ sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, + /*0x20*/ sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, + /*0x28*/ sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, + /*0x30*/ sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, + /*0x38*/ sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, + + /*0x40*/ sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, + /*0x48*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x50*/ sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, + /*0x58*/ sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, + /*0x60*/ sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, + /*0x68*/ sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, + /*0x70*/ sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, + /*0x78*/ sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, + + /*0x80*/ sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, + /*0x88*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x90*/ sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, sf_FSTs_a16, + /*0x98*/ sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, sf_FSTPs_a16, + /*0xa0*/ sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, sf_FLDENV_a16, + /*0xa8*/ sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, sf_FLDCW_a16, + /*0xb0*/ sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, sf_FNSTENV_a16, + /*0xb8*/ sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, sf_FNSTCW_a16, + + /*0xc0*/ sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, + /*0xc8*/ sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + /*0xd0*/ sf_FNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0xd8*/ sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, /*Invalid*/ + /*0xe0*/ sf_FCHS, sf_FABS, ILLEGAL_a16, ILLEGAL_a16, sf_FTST, sf_FXAM, sf_FTSTP, ILLEGAL_a16, + /*0xe8*/ sf_FLD1, sf_FLDL2T, sf_FLDL2E, sf_FLDPI, sf_FLDEG2, sf_FLDLN2, sf_FLDZ, ILLEGAL_a16, + /*0xf0*/ sf_F2XM1, sf_FYL2X, sf_FPTAN, sf_FPATAN, sf_FXTRACT, sf_FPREM1, sf_FDECSTP, sf_FINCSTP, + /*0xf8*/ sf_FPREM, sf_FYL2XP1, sf_FSQRT, sf_FSINCOS, sf_FRNDINT, sf_FSCALE, sf_FSIN, sf_FCOS, + // clang-format on +}; + +const OpFn OP_TABLE(sf_fpu_cyrix_d9_a32)[256] = { + // clang-format off + sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, + sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, + sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, + sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, + sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, + sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, + + sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, + sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, + sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, + sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, + sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, + sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, + + sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, sf_FLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, sf_FSTs_a32, + sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, sf_FSTPs_a32, + sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, sf_FLDENV_a32, + sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, sf_FLDCW_a32, + sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, sf_FNSTENV_a32, + sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, sf_FNSTCW_a32, + + sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, sf_FLD_sti, + sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + sf_FNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, /*Invalid*/ + sf_FCHS, sf_FABS, ILLEGAL_a32, ILLEGAL_a32, sf_FTST, sf_FXAM, sf_FTSTP, ILLEGAL_a32, + sf_FLD1, sf_FLDL2T, sf_FLDL2E, sf_FLDPI, sf_FLDEG2, sf_FLDLN2, sf_FLDZ, ILLEGAL_a32, + sf_F2XM1, sf_FYL2X, sf_FPTAN, sf_FPATAN, sf_FXTRACT, sf_FPREM1, sf_FDECSTP, sf_FINCSTP, + sf_FPREM, sf_FYL2XP1, sf_FSQRT, sf_FSINCOS, sf_FRNDINT, sf_FSCALE, sf_FSIN, sf_FCOS, + // clang-format on +}; + const OpFn OP_TABLE(sf_fpu_287_da_a16)[256] = { // clang-format off sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, @@ -1750,6 +1848,87 @@ const OpFn OP_TABLE(sf_fpu_686_db_a32)[256] = { }; # endif +# ifndef OPS_286_386 +const OpFn OP_TABLE(sf_fpu_cyrix_686_db_a16)[256] = { + // clang-format off + sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, + sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, + + sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, + sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, + + sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, sf_FISTil_a16, + sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, sf_FISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, sf_FLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, sf_FSTPe_a16, + + sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, + sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, + sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, + sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, + sf_FNOP, sf_FNOP, sf_FNCLEX, sf_FNINIT, sf_FNOP, sf_FNOP, ILLEGAL_a16, ILLEGAL_a16, + sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, + sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, sf_FRINT2, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; +const OpFn OP_TABLE(sf_fpu_cyrix_686_db_a32)[256] = { + // clang-format off + sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, + sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, + + sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, + sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, + + sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, sf_FILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, sf_FISTil_a32, + sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, sf_FISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, sf_FLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, sf_FSTPe_a32, + + sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, sf_FCMOVNB, + sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, sf_FCMOVNE, + sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, sf_FCMOVNBE, + sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, sf_FCMOVNU, + sf_FNOP, sf_FNOP, sf_FNCLEX, sf_FNINIT, sf_FNOP, sf_FNOP, ILLEGAL_a32, ILLEGAL_a32, + sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, sf_FUCOMI_st0_stj, + sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, sf_FCOMI_st0_stj, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, sf_FRINT2, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; +# endif + const OpFn OP_TABLE(sf_fpu_287_dc_a16)[32] = { // clang-format off sf_FADDd_a16, sf_FMULd_a16, sf_FCOMd_a16, sf_FCOMPd_a16, sf_FSUBd_a16, sf_FSUBRd_a16, sf_FDIVd_a16, sf_FDIVRd_a16, @@ -1946,6 +2125,86 @@ const OpFn OP_TABLE(sf_fpu_dd_a32)[256] = { // clang-format on }; +const OpFn OP_TABLE(sf_fpu_cyrix_dd_a16)[256] = { + // clang-format off + /*0x00*/ sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, + /*0x08*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x10*/ sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, + /*0x18*/ sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, + /*0x20*/ sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, + /*0x28*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x30*/ sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, + /*0x38*/ sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, + + /*0x40*/ sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, + /*0x48*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x50*/ sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, + /*0x58*/ sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, + /*0x60*/ sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, + /*0x68*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x70*/ sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, + /*0x78*/ sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, + + /*0x80*/ sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, + /*0x88*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0x90*/ sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, sf_FSTd_a16, + /*0x98*/ sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, sf_FSTPd_a16, + /*0xa0*/ sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, sf_FRSTOR_a16, + /*0xa8*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0xb0*/ sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, sf_FNSAVE_a16, + /*0xb8*/ sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, sf_FNSTSW_a16, + + /*0xc0*/ sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, + /*0xc8*/ sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + /*0xd0*/ sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, + /*0xd8*/ sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + /*0xe0*/ sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, + /*0xe8*/ sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, + /*0xf0*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + /*0xf8*/ ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, sf_FRICHOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; + +const OpFn OP_TABLE(sf_fpu_cyrix_dd_a32)[256] = { + // clang-format off + sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, + sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, + sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, + sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, + + sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, + sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, + sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, + sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, + + sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, sf_FLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, sf_FSTd_a32, + sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, sf_FSTPd_a32, + sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, sf_FRSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, sf_FNSAVE_a32, + sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, sf_FNSTSW_a32, + + sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, sf_FFREE_sti, + sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, sf_FST_sti, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, sf_FUCOM_sti, + sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, sf_FUCOMP_sti, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, sf_FRICHOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; + const OpFn OP_TABLE(sf_fpu_287_de_a16)[256] = { // clang-format off sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, @@ -2348,6 +2607,88 @@ const OpFn OP_TABLE(sf_fpu_686_df_a32)[256] = { }; # endif +# ifndef OPS_286_386 +const OpFn OP_TABLE(sf_fpu_cyrix_686_df_a16)[256] = { + // clang-format off + sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, + sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, + sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, + sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, + sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, + sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, + + sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, + sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, + sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, + sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, + sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, + sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, + + sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, sf_FISTiw_a16, + sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, sf_FISTPiw_a16, + sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, sf_FBLD_PACKED_BCD_a16, + sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, sf_FILDiq_a16, + sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, sf_FBSTP_PACKED_BCD_a16, + sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, sf_FISTPiq_a16, + + sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, + sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + sf_FNSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, + sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, sf_FRINEAR, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; + +const OpFn OP_TABLE(sf_fpu_cyrix_686_df_a32)[256] = { + // clang-format off + sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, + sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, + sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, + sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, + sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, + sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, + + sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, + sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, + sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, + sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, + sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, + sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, + + sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, sf_FILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, sf_FISTiw_a32, + sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, sf_FISTPiw_a32, + sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, sf_FBLD_PACKED_BCD_a32, + sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, sf_FILDiq_a32, + sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, sf_FBSTP_PACKED_BCD_a32, + sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, sf_FISTPiq_a32, + + sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, sf_FFREEP_sti, + sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, sf_FXCH_sti, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, sf_FSTP_sti, + sf_FNSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, sf_FUCOMIP_st0_stj, + sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, sf_FCOMIP_st0_stj, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, sf_FRINEAR, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; +# endif + const OpFn OP_TABLE(fpu_d8_a16)[32] = { // clang-format off opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, @@ -2526,6 +2867,86 @@ const OpFn OP_TABLE(fpu_d9_a32)[256] = { // clang-format on }; +const OpFn OP_TABLE(fpu_cyrix_d9_a16)[256] = { + // clang-format off + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, opFTSTP, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, opFXTRACT, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS + // clang-format on +}; + +const OpFn OP_TABLE(fpu_cyrix_d9_a32)[256] = { + // clang-format off + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, opFTSTP, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, opFXTRACT, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS + // clang-format on +}; + const OpFn OP_TABLE(fpu_287_da_a16)[256] = { // clang-format off opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, @@ -3009,6 +3430,87 @@ const OpFn OP_TABLE(fpu_686_db_a32)[256] = { }; # endif +# ifndef OPS_286_386 +const OpFn OP_TABLE(fpu_cyrix_686_db_a16)[256] = { + // clang-format off + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFRINT2, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; +const OpFn OP_TABLE(fpu_cyrix_686_db_a32)[256] = { + // clang-format off + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFRINT2, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; +# endif + const OpFn OP_TABLE(fpu_287_dc_a16)[32] = { // clang-format off opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, @@ -3205,6 +3707,86 @@ const OpFn OP_TABLE(fpu_dd_a32)[256] = { // clang-format on }; +const OpFn OP_TABLE(fpu_cyrix_dd_a16)[256] = { + // clang-format off + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFRICHOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; + +const OpFn OP_TABLE(fpu_cyrix_dd_a32)[256] = { + // clang-format off + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFRICHOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; + const OpFn OP_TABLE(fpu_287_de_a16)[256] = { // clang-format off opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, @@ -3607,6 +4189,88 @@ const OpFn OP_TABLE(fpu_686_df_a32)[256] = { }; # endif +# ifndef OPS_286_386 +const OpFn OP_TABLE(fpu_cyrix_686_df_a16)[256] = { + // clang-format off + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, FBLD_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, opFRINEAR, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + // clang-format on +}; + +const OpFn OP_TABLE(fpu_cyrix_686_df_a32)[256] = { + // clang-format off + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, FBLD_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, opFRINEAR, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + // clang-format on +}; +# endif + const OpFn OP_TABLE(nofpu_a16)[256] = { // clang-format off op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index c1f09fda9..cbad12e56 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -554,6 +554,22 @@ opFTST(UNUSED(uint32_t fetchdat)) return 0; } +static int +opFTSTP(UNUSED(uint32_t fetchdat)) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); + if (ST(0) == 0.0) + cpu_state.npxs |= FPU_SW_C3; + else if (ST(0) < 0.0) + cpu_state.npxs |= FPU_SW_C0; + x87_pop(); + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ftst) : (x87_timings.ftst * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi)); + return 0; +} + static int opFXAM(UNUSED(uint32_t fetchdat)) { @@ -838,6 +854,67 @@ opFRNDINT(UNUSED(uint32_t fetchdat)) return 0; } +static int +opFRINT2(UNUSED(uint32_t fetchdat)) +{ + double dst0, st0, integral, frac; + int prevRound; + + FP_ENTER(); + cpu_state.pc++; + prevRound = fegetround(); + fesetround(FE_TONEAREST); + st0 = ST(0); + frac = modf(st0, &integral); + if (frac == 0.5 || frac == -0.5) { + dst0 = (st0 < 0) ? floor(st0) : ceil(st0); + } else { + dst0 = round(st0); + } + fesetround(prevRound); + ST(0) = (double) dst0; + FP_TAG_VALID; + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} + +static int +opFRINEAR(UNUSED(uint32_t fetchdat)) +{ + double dst0, st0, integral, frac; + int prevRound; + + FP_ENTER(); + cpu_state.pc++; + prevRound = fegetround(); + fesetround(FE_TONEAREST); + ST(0) = (double) x87_fround_nearest(ST(0)); + fesetround(prevRound); + FP_TAG_VALID; + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} + +static int +opFRICHOP(UNUSED(uint32_t fetchdat)) +{ + double dst0, st0, integral, frac; + int prevRound; + + FP_ENTER(); + cpu_state.pc++; + prevRound = fegetround(); + fesetround(FE_TONEAREST); + ST(0) = (double) ((int64_t)(ST(0))); + fesetround(prevRound); + FP_TAG_VALID; + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} + static int opFSCALE(UNUSED(uint32_t fetchdat)) { diff --git a/src/cpu/x87_ops_sf_arith.h b/src/cpu/x87_ops_sf_arith.h index c9e25e97c..620c44691 100644 --- a/src/cpu/x87_ops_sf_arith.h +++ b/src/cpu/x87_ops_sf_arith.h @@ -800,3 +800,84 @@ next_ins: CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } + +static int +sf_FRINT2(uint32_t fetchdat) +{ + floatx80 result; + struct softfloat_status_t status; + + FP_ENTER(); + FPU_check_pending_exceptions(); + cpu_state.pc++; + clear_C1(); + if (IS_TAG_EMPTY(0)) { + FPU_stack_underflow(fetchdat, 0, 0); + goto next_ins; + } + status = i387cw_to_softfloat_status_word(i387_get_control_word()); + result = extF80_roundToInt(FPU_read_regi(0), softfloat_round_near_maxMag, true, &status); + + if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) { + FPU_save_regi(result, 0); + } + +next_ins: + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} + +static int +sf_FRINEAR(uint32_t fetchdat) +{ + floatx80 result; + struct softfloat_status_t status; + + FP_ENTER(); + FPU_check_pending_exceptions(); + cpu_state.pc++; + clear_C1(); + if (IS_TAG_EMPTY(0)) { + FPU_stack_underflow(fetchdat, 0, 0); + goto next_ins; + } + status = i387cw_to_softfloat_status_word(i387_get_control_word()); + result = extF80_roundToInt(FPU_read_regi(0), softfloat_round_near_even, true, &status); + + if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) { + FPU_save_regi(result, 0); + } + +next_ins: + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} + +static int +sf_FRICHOP(uint32_t fetchdat) +{ + floatx80 result; + struct softfloat_status_t status; + + FP_ENTER(); + FPU_check_pending_exceptions(); + cpu_state.pc++; + clear_C1(); + if (IS_TAG_EMPTY(0)) { + FPU_stack_underflow(fetchdat, 0, 0); + goto next_ins; + } + status = i387cw_to_softfloat_status_word(i387_get_control_word()); + result = extF80_roundToInt(FPU_read_regi(0), softfloat_round_to_zero, true, &status); + + if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) { + FPU_save_regi(result, 0); + } + +next_ins: + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.frndint) : (x87_timings.frndint * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); + return 0; +} diff --git a/src/cpu/x87_ops_sf_compare.h b/src/cpu/x87_ops_sf_compare.h index 945ed99d3..d1d9bc1dd 100644 --- a/src/cpu/x87_ops_sf_compare.h +++ b/src/cpu/x87_ops_sf_compare.h @@ -459,6 +459,32 @@ sf_FTST(uint32_t fetchdat) return 0; } +static int +sf_FTSTP(uint32_t fetchdat) +{ + const floatx80 Const_Z = packFloatx80(0, 0x0000, 0); + struct softfloat_status_t status; + int rc; + + FP_ENTER(); + FPU_check_pending_exceptions(); + cpu_state.pc++; + clear_C1(); + if (IS_TAG_EMPTY(0)) { + FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0); + setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); + } else { + status = i387cw_to_softfloat_status_word(i387_get_control_word()); + rc = extF80_compare_normal(FPU_read_regi(0), Const_Z, &status); + setcc(FPU_status_word_flags_fpu_compare(rc)); + FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0); + FPU_pop(); + } + CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ftst) : (x87_timings.ftst * cpu_multi)); + CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi)); + return 0; +} + static int sf_FXAM(UNUSED(uint32_t fetchdat)) { From c40aa61be419c6c6ed2365a2c69607964878b95a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 02:09:23 +0600 Subject: [PATCH 0372/1190] Cyrix 6x86: Correctly initalize ARR3 on reset to avoid some SMM problems --- src/cpu/x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cpu/x86.c b/src/cpu/x86.c index f1f5004d9..97ae19f3a 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -275,6 +275,8 @@ reset_common(int hard) ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = ccr7 = 0; ccr4 = 0x85; + cyrix.arr[3].base = 0x30000; + cyrix.arr[3].size = 65536; if (hascache) cr0 = 1 << 30; From a62a6594e6d437b88bcc46bfc65c2688497dce64 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 5 Mar 2025 23:48:47 +0100 Subject: [PATCH 0373/1190] SCSI CD-ROM: Fixed SCSI standard reporting in INQUIRY. --- src/scsi/scsi_cdrom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 840bec6a0..0626fbee9 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -3444,7 +3444,8 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->buffer[1] = 0x80; /* Removable */ if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->buffer[3] = cdrom_get_scsi_std(dev->drv->type); + dev->buffer[2] = (dev->ven_cmd == scsi_cdrom_command_nec) ? + 0x00 : cdrom_get_scsi_std(dev->drv->type); if (dev->drv->is_toshiba) /* Linked Command and Relative Addressing supported */ From 4c3ea296c3dbe7ab10c9660e2225059eebb1b676 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 5 Mar 2025 17:58:01 -0500 Subject: [PATCH 0374/1190] Fix ES1370 detection --- src/sound/snd_audiopci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index f8a6e4153..e3e2b9f1a 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -489,7 +489,10 @@ es137x_reset(void *priv) /* Serial Interface Control Register, Address 20H Addressable as byte, word, longword */ - dev->si_cr = 0xff800000; + if (dev->type == AUDIOPCI_ES1370) + dev->si_cr = 0x00000000; + else + dev->si_cr = 0xff800000; /* DAC1 Channel Sample Count Register, Address 24H Addressable as word, longword */ From 2300339588f42744c8f5485a60a91b884fe6f8b3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 6 Mar 2025 00:05:16 +0100 Subject: [PATCH 0375/1190] Included stdlib.h. --- src/cpu/386_dynarec_ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index c31b725b2..3d9a7e080 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -1,6 +1,7 @@ #include -#include #include +#include +#include #include #include #include From 9b47522f43116dfaa04a03d18ced128ecbf31299 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 6 Mar 2025 00:12:45 +0100 Subject: [PATCH 0376/1190] FPU: Fix newly-introduced x87-related warnings. --- src/cpu/x87_ops_misc.h | 8 ++++++-- src/cpu/x87_ops_sf_arith.h | 4 ++++ src/cpu/x87_ops_sf_compare.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index cbad12e56..5821a5cd5 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -554,6 +554,7 @@ opFTST(UNUSED(uint32_t fetchdat)) return 0; } +#ifndef FPU_8087 static int opFTSTP(UNUSED(uint32_t fetchdat)) { @@ -569,6 +570,7 @@ opFTSTP(UNUSED(uint32_t fetchdat)) CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi)); return 0; } +#endif static int opFXAM(UNUSED(uint32_t fetchdat)) @@ -854,6 +856,8 @@ opFRNDINT(UNUSED(uint32_t fetchdat)) return 0; } +#ifndef FPU_8087 +#ifndef OPS_286_386 static int opFRINT2(UNUSED(uint32_t fetchdat)) { @@ -882,7 +886,6 @@ opFRINT2(UNUSED(uint32_t fetchdat)) static int opFRINEAR(UNUSED(uint32_t fetchdat)) { - double dst0, st0, integral, frac; int prevRound; FP_ENTER(); @@ -896,11 +899,11 @@ opFRINEAR(UNUSED(uint32_t fetchdat)) CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } +#endif static int opFRICHOP(UNUSED(uint32_t fetchdat)) { - double dst0, st0, integral, frac; int prevRound; FP_ENTER(); @@ -914,6 +917,7 @@ opFRICHOP(UNUSED(uint32_t fetchdat)) CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } +#endif static int opFSCALE(UNUSED(uint32_t fetchdat)) diff --git a/src/cpu/x87_ops_sf_arith.h b/src/cpu/x87_ops_sf_arith.h index 620c44691..7abde322b 100644 --- a/src/cpu/x87_ops_sf_arith.h +++ b/src/cpu/x87_ops_sf_arith.h @@ -801,6 +801,8 @@ next_ins: return 0; } +#ifndef FPU_8087 +#ifndef OPS_286_386 static int sf_FRINT2(uint32_t fetchdat) { @@ -854,6 +856,7 @@ next_ins: CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } +#endif static int sf_FRICHOP(uint32_t fetchdat) @@ -881,3 +884,4 @@ next_ins: CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.frndint) : (x87_concurrency.frndint * cpu_multi)); return 0; } +#endif diff --git a/src/cpu/x87_ops_sf_compare.h b/src/cpu/x87_ops_sf_compare.h index d1d9bc1dd..d90526b82 100644 --- a/src/cpu/x87_ops_sf_compare.h +++ b/src/cpu/x87_ops_sf_compare.h @@ -459,6 +459,7 @@ sf_FTST(uint32_t fetchdat) return 0; } +#ifndef FPU_8087 static int sf_FTSTP(uint32_t fetchdat) { @@ -484,6 +485,7 @@ sf_FTSTP(uint32_t fetchdat) CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi)); return 0; } +#endif static int sf_FXAM(UNUSED(uint32_t fetchdat)) From 78f50c5b042ebd69c4fec875d47e10cf434e5806 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 6 Mar 2025 00:17:16 +0100 Subject: [PATCH 0377/1190] Move the Cyrix 6x86 out of the Dev branch. --- CMakeLists.txt | 1 - src/cpu/386_ops.h | 4 ---- src/cpu/CMakeLists.txt | 10 +--------- src/cpu/cpu.c | 10 ---------- src/cpu/cpu_table.c | 2 -- src/cpu/x86_ops.h | 4 ---- src/cpu/x86_ops_mmx_mov.h | 2 -- 7 files changed, 1 insertion(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c33bb3e9..fb71553e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,7 +163,6 @@ endif() cmake_dependent_option(AMD_K5 "AMD K5" ON "DEV_BRANCH" OFF) cmake_dependent_option(AN430TX "Intel AN430TX" ON "DEV_BRANCH" OFF) cmake_dependent_option(CDROM_MITSUMI "Mitsumi CDROM" ON "DEV_BRANCH" OFF) -cmake_dependent_option(CYRIX_6X86 "Cyrix 6x86" ON "DEV_BRANCH" OFF) cmake_dependent_option(G100 "Matrox Productiva G100" ON "DEV_BRANCH" OFF) cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF) diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index e8300f134..5113ca817 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -1385,7 +1385,6 @@ const OpFn OP_TABLE(pentium_0f)[1024] = { // clang-format on }; -# ifdef USE_CYRIX_6X86 const OpFn OP_TABLE(c6x86_0f)[1024] = { // clang-format off /*16-bit data, 16-bit addr*/ @@ -1569,7 +1568,6 @@ const OpFn OP_TABLE(c6x86l_0f)[1024] = { /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, // clang-format on }; -# endif /* USE_CYRIX_6X86 */ const OpFn OP_TABLE(pentiummmx_0f)[1024] = { // clang-format off @@ -1847,7 +1845,6 @@ const OpFn OP_TABLE(k62_0f)[1024] = { // clang-format on }; -# ifdef USE_CYRIX_6X86 const OpFn OP_TABLE(c6x86mx_0f)[1024] = { // clang-format off /*16-bit data, 16-bit addr*/ @@ -1939,7 +1936,6 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, // clang-format on }; -# endif /* USE_CYRIX_6X86 */ const OpFn OP_TABLE(pentiumpro_0f)[1024] = { // clang-format off diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index 890d02e3e..9c1385d4f 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -42,20 +42,12 @@ endif() endif() -if(CYRIX_6X86) - target_compile_definitions(cpu PRIVATE USE_CYRIX_6X86) - -if(DYNAREC) - add_library(ct686 OBJECT codegen_timing_686.c) - target_link_libraries(86Box ct686) -endif() -endif() - if(DYNAREC) target_sources(cpu PRIVATE 386_dynarec_ops.c) add_library(cgt OBJECT codegen_timing_486.c + codegen_timing_686.c codegen_timing_common.c codegen_timing_k6.c codegen_timing_pentium.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 13a109d38..e6a22394a 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1420,7 +1420,6 @@ cpu_set(void) #endif /* USE_DYNAREC */ break; -#ifdef USE_CYRIX_6X86 case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -1541,7 +1540,6 @@ cpu_set(void) else if (CPU_Cx6x86) CPUID = 0; /* Disabled on powerup by default */ break; -#endif /* USE_CYRIX_6X86 */ #ifdef USE_AMD_K5 case CPU_K5: @@ -2386,7 +2384,6 @@ cpu_CPUID(void) EAX = EBX = ECX = EDX = 0; break; -#ifdef USE_CYRIX_6X86 case CPU_Cx6x86: if (!EAX) { EAX = 0x00000001; @@ -2447,7 +2444,6 @@ cpu_CPUID(void) } else EAX = EBX = ECX = EDX = 0; break; -#endif /* USE_CYRIX_6X86 */ case CPU_PENTIUMPRO: if (!EAX) { @@ -3124,7 +3120,6 @@ pentium_invalid_rdmsr: cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); break; -#ifdef USE_CYRIX_6X86 case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -3164,7 +3159,6 @@ pentium_invalid_rdmsr: } cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX); break; -#endif /* USE_CYRIX_6X86 */ case CPU_PENTIUMPRO: case CPU_PENTIUM2: @@ -3945,7 +3939,6 @@ pentium_invalid_wrmsr: } break; -#ifdef USE_CYRIX_6X86 case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -3979,7 +3972,6 @@ pentium_invalid_wrmsr: break; } break; -#endif /* USE_CYRIX_6X86 */ case CPU_PENTIUMPRO: case CPU_PENTIUM2: @@ -4283,14 +4275,12 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) case 0xe8: /* CCR4 */ if ((ccr3 & 0xf0) == 0x10) { ccr4 = val; -#ifdef USE_CYRIX_6X86 if (cpu_s->cpu_type >= CPU_Cx6x86) { if (val & 0x80) CPUID = cpu_s->cpuid_model; else CPUID = 0; } -#endif /* USE_CYRIX_6X86 */ } break; case 0xe9: /* CCR5 */ diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 104d56d05..5a156853e 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -6095,7 +6095,6 @@ const cpu_family_t cpu_families[] = { { .name = "", 0 } } }, -#ifdef USE_CYRIX_6X86 { .package = CPU_PKG_SOCKET5_7, .manufacturer = "Cyrix", @@ -6455,7 +6454,6 @@ const cpu_family_t cpu_families[] = { { .name = "", 0 } } }, -#endif /* USE_CYRIX_6X86 */ { .package = CPU_PKG_SOCKET8, .manufacturer = "Intel", diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 6d93fb435..ed95d04d9 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -90,11 +90,9 @@ extern const OpFn dynarec_ops_winchip2_0f[1024]; extern const OpFn dynarec_ops_pentium_0f[1024]; extern const OpFn dynarec_ops_pentiummmx_0f[1024]; -# ifdef USE_CYRIX_6X86 extern const OpFn dynarec_ops_c6x86_0f[1024]; extern const OpFn dynarec_ops_c6x86l_0f[1024]; extern const OpFn dynarec_ops_c6x86mx_0f[1024]; -# endif /* USE_CYRIX_6X86 */ extern const OpFn dynarec_ops_k6_0f[1024]; extern const OpFn dynarec_ops_k62_0f[1024]; @@ -233,11 +231,9 @@ extern const OpFn ops_winchip2_0f[1024]; extern const OpFn ops_pentium_0f[1024]; extern const OpFn ops_pentiummmx_0f[1024]; -#ifdef USE_CYRIX_6X86 extern const OpFn ops_c6x86_0f[1024]; extern const OpFn ops_c6x86l_0f[1024]; extern const OpFn ops_c6x86mx_0f[1024]; -#endif /* USE_CYRIX_6X86 */ extern const OpFn ops_k6_0f[1024]; extern const OpFn ops_k62_0f[1024]; diff --git a/src/cpu/x86_ops_mmx_mov.h b/src/cpu/x86_ops_mmx_mov.h index 8855f8ccd..0bf928198 100644 --- a/src/cpu/x86_ops_mmx_mov.h +++ b/src/cpu/x86_ops_mmx_mov.h @@ -110,7 +110,6 @@ opMOVD_mm_l_a32(uint32_t fetchdat) return 0; } -#ifdef USE_CYRIX_6X86 /*Cyrix maps both MOVD and SMINT to the same opcode*/ static int opMOVD_mm_l_a16_cx(uint32_t fetchdat) @@ -170,7 +169,6 @@ opMOVD_mm_l_a32_cx(uint32_t fetchdat) return 0; } -#endif /* USE_CYRIX_6X86 */ static int opMOVQ_q_mm_a16(uint32_t fetchdat) From 4be691afe76181f3a885a3626bc814219a805424 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 6 Mar 2025 01:44:02 +0100 Subject: [PATCH 0378/1190] IDE: Correctly terminate ATAPI command on DMA underrun, fixes Windows 9x freezes. --- src/disk/hdc_ide.c | 19 +++++++++++++------ src/scsi/scsi_cdrom.c | 1 - 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index afc466644..eb160c41b 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -241,7 +241,6 @@ int ide_qua_enabled = 0; static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -// #define ENABLE_IDE_LOG 1 #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -1092,12 +1091,16 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - // pclog("Reading block %i... ", ide->sc->sector_len + 1); + // pclog("Reading block %i (%i, %i)... ", ide->sc->sector_len + 1, ide->sc->block_len, ide->sc->packet_len); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - if (ide->sc->block_len == 0) + if (ide->sc->block_len == 0) { ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); - else { + + /* Underrun. */ + if (ret == 1) + ret = 3; + } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - ide->sc->block_len, ide->sc->block_len, 0, bm->priv); @@ -1145,9 +1148,13 @@ ide_atapi_callback(ide_t *ide) case PHASE_DATA_OUT_DMA: if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { - if (ide->sc->block_len == 0) + if (ide->sc->block_len == 0) { ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); - else { + + /* Underrun. */ + if (ret == 1) + ret = 3; + } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, ide->sc->block_len, 1, bm->priv); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 0626fbee9..c505d9f53 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,7 +15,6 @@ */ #include #include -// #define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif From 74368bfe7ab523f92d3533f0bdaf49c7c0611b4b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 19:26:11 +0600 Subject: [PATCH 0379/1190] Don't include `cpu.h` in `timer.h` Change the name of the define used to indicate SVGA multi-monitor-capable cards --- src/chipset/ali1531.c | 1 + src/chipset/ali1541.c | 1 + src/chipset/ali1543.c | 1 + src/chipset/ali6117.c | 1 + src/chipset/gc100.c | 1 + src/chipset/sis_5511_h2p.c | 1 + src/chipset/sis_5513_p2i.c | 1 + src/chipset/sis_5571_h2p.c | 1 + src/chipset/sis_5581_h2p.c | 1 + src/chipset/sis_5591_h2p.c | 1 + src/chipset/sis_5600_h2p.c | 1 + src/chipset/sis_85c50x.c | 1 + src/device/cartridge.c | 1 + src/device/keyboard_xt.c | 1 + src/device/serial.c | 1 + src/include/86box/timer.h | 2 +- src/include/86box/video.h | 2 ++ src/machine/m_at_socket5.c | 1 + src/machine/m_xt_olivetti.c | 1 + src/machine/m_xt_philips.c | 1 + src/mem/sst_flash.c | 1 + src/qt/qt_main.cpp | 1 + src/qt/qt_settingsdisplay.cpp | 6 +++--- src/scsi/scsi_t128.c | 1 + src/sound/snd_audiopci.c | 1 + src/sound/snd_gus.c | 1 + src/sound/snd_opl_esfm.c | 1 + src/sound/snd_opl_nuked.c | 1 + src/sound/snd_sb.c | 1 + src/timer.c | 1 + src/video/vid_ati_mach64.c | 1 + src/video/vid_ati_mach8.c | 1 + src/video/vid_chips_69000.c | 1 + src/video/vid_mga.c | 1 + src/video/vid_nga.c | 1 + src/video/vid_ogc.c | 1 + src/video/vid_table.c | 6 +++--- 37 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/chipset/ali1531.c b/src/chipset/ali1531.c index e765e6d45..53324f8e6 100644 --- a/src/chipset/ali1531.c +++ b/src/chipset/ali1531.c @@ -22,6 +22,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/device.h> diff --git a/src/chipset/ali1541.c b/src/chipset/ali1541.c index eed6ddbc5..ebbcd7e63 100644 --- a/src/chipset/ali1541.c +++ b/src/chipset/ali1541.c @@ -22,6 +22,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/device.h> diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 69a8990e9..2f9273736 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -22,6 +22,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/device.h> #include <86box/io.h> diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index 707b528b2..88bb4b572 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -26,6 +26,7 @@ #include <86box/io.h> #include <86box/pci.h> #include <86box/pic.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/pit.h> #include <86box/device.h> diff --git a/src/chipset/gc100.c b/src/chipset/gc100.c index 23455b952..e9eb05ecf 100644 --- a/src/chipset/gc100.c +++ b/src/chipset/gc100.c @@ -27,6 +27,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/nmi.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/pit.h> #include <86box/mem.h> diff --git a/src/chipset/sis_5511_h2p.c b/src/chipset/sis_5511_h2p.c index 543fcacc5..b94e69f26 100644 --- a/src/chipset/sis_5511_h2p.c +++ b/src/chipset/sis_5511_h2p.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/mem.h> diff --git a/src/chipset/sis_5513_p2i.c b/src/chipset/sis_5513_p2i.c index 95a890fcf..b2346bbc4 100644 --- a/src/chipset/sis_5513_p2i.c +++ b/src/chipset/sis_5513_p2i.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> diff --git a/src/chipset/sis_5571_h2p.c b/src/chipset/sis_5571_h2p.c index d04964581..a28553487 100644 --- a/src/chipset/sis_5571_h2p.c +++ b/src/chipset/sis_5571_h2p.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/mem.h> diff --git a/src/chipset/sis_5581_h2p.c b/src/chipset/sis_5581_h2p.c index d01e9dd28..83983376d 100644 --- a/src/chipset/sis_5581_h2p.c +++ b/src/chipset/sis_5581_h2p.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/mem.h> diff --git a/src/chipset/sis_5591_h2p.c b/src/chipset/sis_5591_h2p.c index 048e7deea..74dd6dfbd 100644 --- a/src/chipset/sis_5591_h2p.c +++ b/src/chipset/sis_5591_h2p.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/mem.h> diff --git a/src/chipset/sis_5600_h2p.c b/src/chipset/sis_5600_h2p.c index a15c6fff5..c23309de4 100644 --- a/src/chipset/sis_5600_h2p.c +++ b/src/chipset/sis_5600_h2p.c @@ -22,6 +22,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/mem.h> diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c index 192ae3767..e932ff6ca 100644 --- a/src/chipset/sis_85c50x.c +++ b/src/chipset/sis_85c50x.c @@ -24,6 +24,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/apm.h> #include <86box/machine.h> diff --git a/src/device/cartridge.c b/src/device/cartridge.c index d2e91ecb3..00464026a 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -22,6 +22,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/plat.h> #include <86box/ui.h> diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 644168004..ddbcae61b 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -29,6 +29,7 @@ #include #include <86box/86box.h> #include <86box/device.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/fdd.h> #include <86box/machine.h> diff --git a/src/device/serial.c b/src/device/serial.c index c25da0070..deb97225a 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -27,6 +27,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/machine.h> #include <86box/io.h> diff --git a/src/include/86box/timer.h b/src/include/86box/timer.h index 25aff6b2f..37a03d9ca 100644 --- a/src/include/86box/timer.h +++ b/src/include/86box/timer.h @@ -1,7 +1,7 @@ #ifndef _TIMER_H_ #define _TIMER_H_ -#include "cpu.h" +extern uint64_t tsc; /* Maximum period, currently 1 second. */ #define MAX_USEC64 1000000ULL diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 7ad29838c..2985559e1 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -69,6 +69,8 @@ enum { #define VIDEO_FLAG_TYPE_NONE 5 #define VIDEO_FLAG_TYPE_MASK 7 +#define VIDEO_FLAG_TYPE_SECONDARY VIDEO_FLAG_TYPE_SPECIAL + typedef struct video_timings_t { int type; int write_b; diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index b6e82301b..02922b425 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -29,6 +29,7 @@ #include <86box/fdc_ext.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/fdd.h> #include <86box/fdc.h> diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index b6e4fb94a..34ca441ec 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -30,6 +30,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/io.h> #include <86box/pic.h> diff --git a/src/machine/m_xt_philips.c b/src/machine/m_xt_philips.c index 604ccebaf..eed54e07f 100644 --- a/src/machine/m_xt_philips.c +++ b/src/machine/m_xt_philips.c @@ -23,6 +23,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/nmi.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/pit.h> #include <86box/mem.h> diff --git a/src/mem/sst_flash.c b/src/mem/sst_flash.c index b41e0f2e2..34bfae83a 100644 --- a/src/mem/sst_flash.c +++ b/src/mem/sst_flash.c @@ -25,6 +25,7 @@ #include <86box/device.h> #include <86box/mem.h> #include <86box/machine.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/nvr.h> #include <86box/plat.h> diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 7723261b4..719208c18 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -86,6 +86,7 @@ extern MainWindow *main_window; extern "C" { #include <86box/keyboard.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/nvr.h> extern int qt_nvr_save(void); diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index 75f8d376b..b7a930711 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -220,9 +220,9 @@ SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) int secondaryFlags = video_card_get_flags(c); if (video_card_available(c) && device_is_valid(video_dev, machineId) - && !((secondaryFlags == primaryFlags) && (secondaryFlags != VIDEO_FLAG_TYPE_SPECIAL)) - && !(((primaryFlags == VIDEO_FLAG_TYPE_8514) || (primaryFlags == VIDEO_FLAG_TYPE_XGA)) && (secondaryFlags != VIDEO_FLAG_TYPE_MDA) && (secondaryFlags != VIDEO_FLAG_TYPE_SPECIAL)) - && !((primaryFlags != VIDEO_FLAG_TYPE_MDA) && (primaryFlags != VIDEO_FLAG_TYPE_SPECIAL) && ((secondaryFlags == VIDEO_FLAG_TYPE_8514) || (secondaryFlags == VIDEO_FLAG_TYPE_XGA)))) { + && !((secondaryFlags == primaryFlags) && (secondaryFlags != VIDEO_FLAG_TYPE_SECONDARY)) + && !(((primaryFlags == VIDEO_FLAG_TYPE_8514) || (primaryFlags == VIDEO_FLAG_TYPE_XGA)) && (secondaryFlags != VIDEO_FLAG_TYPE_MDA) && (secondaryFlags != VIDEO_FLAG_TYPE_SECONDARY)) + && !((primaryFlags != VIDEO_FLAG_TYPE_MDA) && (primaryFlags != VIDEO_FLAG_TYPE_SECONDARY) && ((secondaryFlags == VIDEO_FLAG_TYPE_8514) || (secondaryFlags == VIDEO_FLAG_TYPE_XGA)))) { ui->comboBoxVideoSecondary->addItem(name, c); if (c == curVideoCard_2) ui->comboBoxVideoSecondary->setCurrentIndex(ui->comboBoxVideoSecondary->count() - 1); diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index a40d803f1..5ac3b5d67 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/dma.h> #include <86box/pic.h> diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index e3e2b9f1a..8d1de442b 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -39,6 +39,7 @@ #include <86box/pci.h> #include <86box/snd_ac97.h> #include <86box/sound.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/plat_unused.h> #include <86box/snd_akm4531.h> diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 43638473c..1885581a5 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -15,6 +15,7 @@ #include <86box/nmi.h> #include <86box/pic.h> #include <86box/sound.h> +#include "cpu.h" #include <86box/timer.h> #ifdef USE_GUSMAX # include <86box/snd_ad1848.h> diff --git a/src/sound/snd_opl_esfm.c b/src/sound/snd_opl_esfm.c index bcd2a56e9..b80d264d5 100644 --- a/src/sound/snd_opl_esfm.c +++ b/src/sound/snd_opl_esfm.c @@ -32,6 +32,7 @@ #include <86box/86box.h> #include <86box/sound.h> #include <86box/device.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/snd_opl.h> #include <86box/plat_unused.h> diff --git a/src/sound/snd_opl_nuked.c b/src/sound/snd_opl_nuked.c index 03851a589..60f5ed2a6 100644 --- a/src/sound/snd_opl_nuked.c +++ b/src/sound/snd_opl_nuked.c @@ -46,6 +46,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/sound.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/device.h> #include <86box/snd_opl.h> diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 4f8b8a0bd..689d0b91e 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -39,6 +39,7 @@ #include <86box/pic.h> #include <86box/rom.h> #include <86box/sound.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/snd_sb.h> #include <86box/plat_unused.h> diff --git a/src/timer.c b/src/timer.c index 9fed37511..03908890f 100644 --- a/src/timer.c +++ b/src/timer.c @@ -3,6 +3,7 @@ #include #include #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/nv/vid_nv_rivatimer.h> diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 2df7782ff..24935e3a2 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -28,6 +28,7 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/pci.h> #include <86box/rom.h> diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 71dd973da..2038f1b1d 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -27,6 +27,7 @@ #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/mca.h> #include <86box/pci.h> diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 012a16348..a387e99fa 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -27,6 +27,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/video.h> #include <86box/vid_svga.h> diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index f11983a20..00570bd9f 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -23,6 +23,7 @@ #include #include <86box/86box.h> #include <86box/io.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/mem.h> #include <86box/pci.h> diff --git a/src/video/vid_nga.c b/src/video/vid_nga.c index 3640e5106..ef1c6cd40 100644 --- a/src/video/vid_nga.c +++ b/src/video/vid_nga.c @@ -30,6 +30,7 @@ #include <86box/io.h> #include <86box/video.h> #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/mem.h> #include <86box/pit.h> diff --git a/src/video/vid_ogc.c b/src/video/vid_ogc.c index 7fe5fbbeb..a49cd8a22 100644 --- a/src/video/vid_ogc.c +++ b/src/video/vid_ogc.c @@ -31,6 +31,7 @@ #include <86box/io.h> #include <86box/video.h> #include <86box/86box.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/mem.h> #include <86box/pit.h> diff --git a/src/video/vid_table.c b/src/video/vid_table.c index ff3073c73..d1df2ba20 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -141,10 +141,10 @@ video_cards[] = { { .device = &chips_69000_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5430_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5434_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &gd5436_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &gd5436_pci_device, .flags = VIDEO_FLAG_TYPE_SECONDARY }, { .device = &gd5440_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &gd5446_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, - { .device = &gd5446_stb_pci_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, + { .device = &gd5446_pci_device, .flags = VIDEO_FLAG_TYPE_SECONDARY }, + { .device = &gd5446_stb_pci_device, .flags = VIDEO_FLAG_TYPE_SECONDARY }, { .device = &gd5480_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &et4000w32p_videomagic_revb_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &et4000w32p_revc_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, From 0e42547cca39beb1d07fd007b4c2d8a1e0a92a8d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 19:34:24 +0600 Subject: [PATCH 0380/1190] Remove some `timer.h`-related include hacks --- src/qt/qt_machinestatus.cpp | 3 --- src/qt/qt_mainwindow.cpp | 9 ++++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index d1335873c..dee90f11c 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -19,9 +19,6 @@ #include "qt_machinestatus.hpp" extern "C" { -#define EMU_CPU_H // superhack - don't want timer.h to include cpu.h here, and some combo is preventing a compile -extern uint64_t tsc; - #include <86box/hdd.h> #include <86box/timer.h> #include <86box/86box.h> diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 89d17a07c..552fd0310 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -48,11 +48,10 @@ extern "C" { #include <86box/machine.h> #include <86box/vid_ega.h> #include <86box/version.h> -#if 0 -#include <86box/acpi.h> /* Requires timer.h include, which conflicts with Qt headers */ -#endif -extern atomic_int acpi_pwrbut_pressed; -extern int acpi_enabled; +#include <86box/timer.h> +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> #ifdef USE_VNC # include <86box/vnc.h> From 9badd32c9cc14efde3fc7352d4edc9e8c1e1ec71 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 19:44:37 +0600 Subject: [PATCH 0381/1190] Remove more `nvr.h` hacks --- src/qt/qt_settingsmachine.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp index 771f1cbec..9b1f9849e 100644 --- a/src/qt/qt_settingsmachine.cpp +++ b/src/qt/qt_settingsmachine.cpp @@ -32,13 +32,9 @@ extern "C" { #include <86box/config.h> #include <86box/device.h> #include <86box/machine.h> +#include <86box/nvr.h> } -// from nvr.h, which we can't import into CPP code -#define TIME_SYNC_DISABLED 0 -#define TIME_SYNC_ENABLED 1 -#define TIME_SYNC_UTC 2 - #include "qt_deviceconfig.hpp" #include "qt_models_common.hpp" From 4090c5a62cf61bc4f4437bb7df0577aed37106ee Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 6 Mar 2025 19:56:08 +0600 Subject: [PATCH 0382/1190] Fix SDL builds --- src/unix/unix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/unix.c b/src/unix/unix.c index 7f653b9b6..33b78ddb1 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -38,6 +38,7 @@ #include <86box/device.h> #include <86box/gameport.h> #include <86box/unix_sdl.h> +#include "cpu.h" #include <86box/timer.h> #include <86box/nvr.h> #include <86box/version.h> From 5c78fa52035892bbe695afc7eca72ec58d68de5a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 6 Mar 2025 16:03:11 +0100 Subject: [PATCH 0383/1190] 8514/A compatible changes of the day (March 6th, 2025) 1. Follow the Mach32 manual more closely regarding vblank support. 2. The subsystem status now takes account of the other bits more accurately. 3. The Mach32 PCI, when used with the ATI 68860 ramdac, has its own bpp's when in accelerator mode, separate from the VGA compatible side, so fix this accordingly. 4. Reset the vram when a mapping change occurs, should clear the messups in the ATI Mach8/32 accel video mode tests. --- src/include/86box/vid_8514a.h | 2 +- src/video/vid_8514a.c | 71 +++++++++++++++----------- src/video/vid_ati68860_ramdac.c | 18 +++---- src/video/vid_ati_mach8.c | 88 ++++++++++++++++++++++++--------- 4 files changed, 115 insertions(+), 64 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index 57e98cc44..bfde22d5e 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -213,7 +213,7 @@ typedef struct ibm8514_t { int vdisp2; int disp_cntl; int interlace; - uint8_t subsys_cntl; + uint16_t subsys_cntl; uint8_t subsys_stat; atomic_int fifo_idx; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 379772820..765258237 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -715,27 +715,13 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) break; case 0x42e8: - if (val & 0x01) - dev->subsys_stat &= ~0x01; - if (val & 0x02) - dev->subsys_stat &= ~0x02; - if (val & 0x04) - dev->subsys_stat &= ~0x04; - if (val & 0x08) - dev->subsys_stat &= ~0x08; + ibm8514_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); + dev->subsys_cntl = (dev->subsys_cntl & 0xff00) | val; + dev->subsys_stat &= ~val; break; case 0x42e9: - dev->subsys_cntl = val; - if (val & 0x01) - dev->subsys_stat |= 0x01; - if (val & 0x02) - dev->subsys_stat |= 0x02; - if (val & 0x04) - dev->subsys_stat |= 0x04; - if (val & 0x08) - dev->subsys_stat |= 0x08; - - if ((val & 0xc0) == 0xc0) { + dev->subsys_cntl = (dev->subsys_cntl & 0xff) | (val << 8); + if ((val & 0xc0) == 0x80) { dev->fifo_idx = 0; dev->force_busy = 0; dev->force_busy2 = 0; @@ -882,10 +868,10 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) switch (port) { case 0x2e8: - if (dev->vc == dev->v_syncstart) + if (dev->vc == dev->dispend) temp |= 0x02; - ibm8514_log("0x2E8 read: Display Status=%02x.\n", temp); + ibm8514_log("Read: Display Status1=%02x.\n", temp); break; case 0x6e8: @@ -910,21 +896,25 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) case 0x42e8: case 0x42e9: - if (dev->vc == dev->v_syncstart) - dev->subsys_stat |= 0x01; + if ((dev->subsys_cntl & 0x01) && !(dev->subsys_stat & 0x01) && (dev->vc == dev->dispend)) + temp |= 0x01; if (cmd == 6) { - if ((dev->accel.dx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.dx >= clip_l) && (dev->accel.dx <= clip_r_ibm) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b_ibm)) - dev->subsys_stat |= 0x02; + temp |= 0x02; } else { - if ((dev->accel.cx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r_ibm) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b_ibm)) - dev->subsys_stat |= 0x02; + temp |= 0x02; } if (!dev->fifo_idx) { @@ -932,9 +922,10 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) temp |= 0x08; } - if (port & 1) + if (port & 1) { temp = dev->vram_512k_8514 ? 0x00 : 0x80; - else { + temp |= (dev->subsys_cntl >> 8); + } else { temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); temp |= 0x20; } @@ -1155,6 +1146,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1250,6 +1242,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1385,6 +1378,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -1543,6 +1537,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; if (ibm8514_cpu_dest(svga)) { READ((dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); } else @@ -1634,6 +1629,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -1832,6 +1828,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1989,6 +1986,7 @@ skip_vector_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -2150,6 +2148,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2232,6 +2231,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2313,6 +2313,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2424,6 +2425,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2546,6 +2548,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2650,9 +2653,10 @@ skip_nibble_rect_write: dev->accel.cx = CLAMP(dev->accel.cx, clip_l, clip_r); if ((dev->accel.cx >= clip_l) && - (dev->accel.cx < clip_r) && + (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2811,6 +2815,7 @@ skip_nibble_rect_write: (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -2978,6 +2983,7 @@ skip_nibble_bitblt_write: (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3075,6 +3081,7 @@ skip_nibble_bitblt_write: (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3174,6 +3181,7 @@ skip_nibble_bitblt_write: (dx <= (((uint64_t)clip_r) * 3)) && (dev->accel.dy >= (clip_t << 1)) && (dev->accel.dy <= (clip_b << 1))) { + dev->subsys_stat |= 0x02; READ(dev->accel.src + cx, src_dat); READ(dev->accel.dest + dx, dest_dat); @@ -3196,6 +3204,7 @@ skip_nibble_bitblt_write: (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -3704,6 +3713,8 @@ ibm8514_poll(void *priv) dev->vc &= 0xfff; if (dev->vc == dev->dispend) { + dev->subsys_stat |= 0x01; + ibm8514_log("VBLANK irq.\n"); dev->dispon = 0; for (x = 0; x < ((dev->vram_mask + 1) >> 12); x++) { diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index bb5ccbf31..17b2a6d22 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -70,20 +70,19 @@ void ati68860_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga) { ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv; - const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; switch (addr) { case 0: - svga_out((dev && dev->on) ? 0x2ec : 0x3c8, val, svga); + svga_out(0x3c8, val, svga); break; case 1: - svga_out((dev && dev->on) ? 0x2ed : 0x3c9, val, svga); + svga_out(0x3c9, val, svga); break; case 2: - svga_out((dev && dev->on) ? 0x2ea : 0x3c6, val, svga); + svga_out(0x3c6, val, svga); break; case 3: - svga_out((dev && dev->on) ? 0x2eb : 0x3c7, val, svga); + svga_out(0x3c7, val, svga); break; default: ramdac->regs[addr & 0xf] = val; @@ -176,21 +175,20 @@ uint8_t ati68860_ramdac_in(uint16_t addr, void *priv, svga_t *svga) { const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) priv; - const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp = 0; switch (addr) { case 0: - temp = svga_in((dev && dev->on) ? 0x2ec : 0x3c8, svga); + temp = svga_in(0x3c8, svga); break; case 1: - temp = svga_in((dev && dev->on) ? 0x2ed : 0x3c9, svga); + temp = svga_in(0x3c9, svga); break; case 2: - temp = svga_in((dev && dev->on) ? 0x2ea : 0x3c6, svga); + temp = svga_in(0x3c6, svga); break; case 3: - temp = svga_in((dev && dev->on) ? 0x2eb : 0x3c7, svga); + temp = svga_in(0x3c7, svga); break; case 4: case 8: diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 2038f1b1d..6e2798295 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -438,6 +438,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; switch (mix ? frgd_sel : bkgd_sel) { case 0: src_dat = dev->accel.bkgd_color; @@ -661,6 +662,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; switch (mix ? frgd_sel : bkgd_sel) { case 0: src_dat = dev->accel.bkgd_color; @@ -1067,6 +1069,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; if (mach->accel.dp_config & 0x02) { READ(dev->accel.src + dev->accel.cx, poly_src); poly_src = ((poly_src & rd_mask) == rd_mask); @@ -1308,6 +1311,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: @@ -1441,6 +1445,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; mach->accel.clip_overrun = 0; if (mach->accel.linedraw_opt & 0x02) { if (dev->bpp) { @@ -1599,6 +1604,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: @@ -1733,6 +1739,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= 0x02; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: @@ -2028,6 +2035,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= 0x02; switch (mix ? frgd_sel : bkgd_sel) { case 0: src_dat = dev->accel.bkgd_color; @@ -2333,6 +2341,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); + mach_log("8514/A RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); if ((dev->local & 0xff) >= 0x02) { if (mach->regs[0xb0] & 0x20) { /*ATI extended 8514/A mode.*/ mach_log("Extended 8514/A mode.\n"); @@ -2341,10 +2350,14 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga_recalctimings(svga); mach32_updatemapping(mach, svga); } - if (mach->pci_bus && !mach->ramdac_type) - ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); - else - ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + if (dev->on) + svga_out(addr, val, svga); + else { + if (mach->pci_bus && !mach->ramdac_type) + ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); + else + ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + } } else svga_out(addr, val, svga); return; @@ -2355,6 +2368,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x3C9: rs2 = !!(mach->regs[0xa0] & 0x20); rs3 = !!(mach->regs[0xa0] & 0x40); + mach_log("VGA RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); if ((dev->local & 0xff) >= 0x02) { if (svga->attrregs[0x10] & 0x40) { mach_log("VGA mode.\n"); @@ -2363,10 +2377,14 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga_recalctimings(svga); mach32_updatemapping(mach, svga); } - if (mach->pci_bus && !mach->ramdac_type) - ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); - else - ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + if (dev->on) + svga_out(addr, val, svga); + else { + if (mach->pci_bus && !mach->ramdac_type) + ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); + else + ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); + } } else svga_out(addr, val, svga); return; @@ -2481,10 +2499,14 @@ mach_in(uint16_t addr, void *priv) rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); if ((dev->local & 0xff) >= 0x02) { - if (mach->pci_bus && !mach->ramdac_type) - temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); - else - temp = ati68875_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); + if (dev->on) + temp = svga_in(addr, svga); + else { + if (mach->pci_bus && !mach->ramdac_type) + temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); + else + temp = ati68875_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); + } } else temp = svga_in(addr, svga); break; @@ -3407,7 +3429,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u static void mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8514_t *dev) { - if (port != 0x42e8 && port != 0x42e9) + if (port == 0x42e8 || port == 0x42e9) mach_log("[%04X:%08X]: Port CALL OUT=%04x, val=%02x.\n", CS, cpu_state.pc, port, val); switch (port) { @@ -3422,7 +3444,7 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 break; case 0x42e9: ibm8514_accel_out(port, val, svga, 2); - if ((val & 0xc0) == 0xc0) { + if ((val & 0xc0) == 0x80) { dev->ext_fifo_idx = 0; mach->force_busy = 0; } @@ -3513,6 +3535,11 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 svga_recalctimings(svga); break; + case 0x46e8: + case 0x46e9: + mach_log("0x%04x write: VGA subsystem enable add-on=%02x.\n", port, val); + break; + case 0x4ae8: dev->accel.advfunc_cntl = val; dev->on = dev->accel.advfunc_cntl & 0x01; @@ -4201,6 +4228,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) switch (port) { case 0x2e8: + case 0x2e9: case 0x6e8: case 0x22e8: case 0x26e8: @@ -4212,18 +4240,22 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x42e8: case 0x42e9: - if (dev->vc == dev->v_syncstart) + if ((dev->subsys_cntl & 0x01) && !(dev->subsys_stat & 0x01) && (dev->vc == dev->dispend)) temp |= 0x01; if (mach->accel.cmd_type == -1) { if (cmd == 6) { - if ((dev->accel.dx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.dx >= clip_l) && (dev->accel.dx <= clip_r_ibm) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b_ibm)) temp |= 0x02; } else { - if ((dev->accel.cx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r_ibm) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b_ibm)) @@ -4234,7 +4266,9 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 1: case 2: case 5: - if ((dev->accel.dx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.dx >= clip_l) && (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) @@ -4242,7 +4276,9 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) break; case 3: case 4: - if ((dev->accel.cx >= clip_l) && + if ((dev->subsys_cntl & 0x02) && + !(dev->subsys_stat & 0x02) && + (dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) @@ -4257,16 +4293,17 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) if ((!dev->force_busy && !dev->force_busy2) || !mach->force_busy) temp |= 0x08; } - if (port & 1) + if (port & 1) { temp = dev->vram_512k_8514 ? 0x00 : 0x80; - else { + temp |= (dev->subsys_cntl >> 8); + } else { temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); if (mach->accel.ext_ge_config & 0x08) temp |= ((mach->accel.ext_ge_config & 0x07) << 4); else temp |= 0x20; } - mach_log("0x%04x read: Subsystem Status=%02x.\n", port, temp); + mach_log("0x%04x read: Subsystem Status=%02x, monitoralias=%02x.\n", port, temp, mach->accel.ext_ge_config & 0x07); break; /*ATI Mach8/32 specific registers*/ @@ -4403,7 +4440,8 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) default: break; } - mach_log("[%04X:%08X]: Port NORMAL IN=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); + if (port == 0x2ee8 || port == 0x2ee9 || port == 0x42e8 || port == 0x42e9) + mach_log("[%04X:%08X]: Port NORMAL IN=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); return temp; } @@ -5419,6 +5457,10 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel); mem_mapping_set_p(&svga->mapping, mach); } else { + if (!dev->on) { + memset(dev->vram, 0, dev->vram_size); + memset(dev->changedvram, 0, (dev->vram_size >> 12) + 1); + } mach_log("IBM compatible banked mapping.\n"); mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); mem_mapping_set_p(&svga->mapping, svga); From d25aed2da98cfc4e2208bb46cd24776d5e6b6020 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 7 Mar 2025 00:36:09 +0600 Subject: [PATCH 0384/1190] Add global mute option --- src/86box.c | 1 + src/config.c | 5 ++++ src/include/86box/86box.h | 1 + src/qt/icons/sound_mute.ico | Bin 0 -> 9622 bytes src/qt/qt_machinestatus.cpp | 45 +++++++++++++++++++++++++++++++----- src/qt/qt_machinestatus.hpp | 6 +++++ src/qt/qt_mainwindow.cpp | 1 + src/qt_resources.qrc | 1 + src/sound/openal.c | 2 +- src/sound/xaudio2.c | 2 +- 10 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/qt/icons/sound_mute.ico diff --git a/src/86box.c b/src/86box.c index 6b64cd2ec..aa3afb085 100644 --- a/src/86box.c +++ b/src/86box.c @@ -213,6 +213,7 @@ int do_auto_pause = 0; /* (C) Auto-pa int hook_enabled = 1; /* (C) Keyboard hook is enabled */ int test_mode = 0; /* (C) Test mode */ char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ +int sound_muted = 0; /* (C) Is sound muted? */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are present */ diff --git a/src/config.c b/src/config.c index 6c34c4790..07e770822 100644 --- a/src/config.c +++ b/src/config.c @@ -168,6 +168,7 @@ load_general(void) kbd_req_capture = ini_section_get_int(cat, "kbd_req_capture", 0); hide_status_bar = ini_section_get_int(cat, "hide_status_bar", 0); hide_tool_bar = ini_section_get_int(cat, "hide_tool_bar", 0); + sound_muted = ini_section_get_int(cat, "sound_muted", 0); confirm_reset = ini_section_get_int(cat, "confirm_reset", 1); confirm_exit = ini_section_get_int(cat, "confirm_exit", 1); @@ -1846,6 +1847,10 @@ save_general(void) const char *va_name; + ini_section_set_int(cat, "sound_muted", sound_muted); + if (sound_muted == 0) + ini_section_delete_var(cat, "sound_muted"); + ini_section_set_int(cat, "vid_resize", vid_resize); if (vid_resize == 0) ini_section_delete_var(cat, "vid_resize"); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e4e5ecae1..79bb84009 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -158,6 +158,7 @@ extern int other_scsi_present; /* SCSI controllers from non-SCSI ca extern int hard_reset_pending; extern int fixed_size_x; extern int fixed_size_y; +extern int sound_muted; /* (C) Is sound muted? */ extern int do_auto_pause; /* (C) Auto-pause the emulator on focus loss */ extern int auto_paused; extern double mouse_sensitivity; /* (C) Mouse sensitivity scale */ diff --git a/src/qt/icons/sound_mute.ico b/src/qt/icons/sound_mute.ico new file mode 100644 index 0000000000000000000000000000000000000000..89a8407354ce0ef805689d75763cd17fd58ce52b GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkV}|7)cl>6Qq^_YQ}#ChW|*I z0W610CsYqqFUSory)YdhK6W!u^@7yH^n=)7eGCw{VCskI1t|cjK5*c`e+CAGeuzBC z3=oFv2m1vg$H1^;!2%RMsu>`CAPh1SWCO$u{CXLX!U3eO;Xh10$b@Ilo`LOy*$ZagjB$-(r%)WGz@#L;P(K4coE24)5lA6Xe*HcStU#;X{&Bsg8*mS$l1pZx#- zzsCRn|ML9*|7*(s|6c|E|6kSk|9`0C|NpC2|NkEv3Zbut{{R1K_y7N2L;wH(wg3PB zzxDtB|NH;{Kd77$VSto3jNsCSfnfq0J{w7r1Gyg^lVkvrVx+PMl>cBDkr$BE;$%YN z1C$5h`jOPa#XxRG635Aes)LyaQU@{vM8hzc4^;;f!=xeZg5_~!^FV6BW`G!=BndJL zgrR&)3e_x-Ji2)xF_@WP8mDum{~9yW(JIg zsmDcw%!HN8Fg-A{VD5s^FnJgsq!)_8VFhJ_DVTjQv(e3jnFUjaWG2ik7!5WLnLsxa zW(LemB(q@JaGC{D0MZXL6Q&nt7Dx`J1{)0$!-ZjH!pwk~iA6nL_aUoCHxpS7jZL(f zFh9fGiDnLnONv<_^&m`+9*{nY@c$q7|NnoG|NsAR|Ns9>&;S4LcK-jr<^KQwI`aSj zwLt#=)c|>DeHH(I)$0BKuZG6||FwGm|DU1p|NpJu|Nnpd{r~?#^!@)}0IIhn7#J7~ zklM!yoD?|`T{9@0&@s9ia`;d)5oHpjeG1}(%NLM5Ip%`&AeDKbvJ)MH>;Pe~Js|bO zVz9ZOfQPiZK`cxRlY{t&Xgi?(Z2%jHW(JD;Knfu8MEe1Y*~s>Q%^}wgsM#QYVw#EO zR%rVlOzDJbJnC62tpxc2(4B31b8%!h2#_oQY8_?}Qn0GWe~LE<0`5(9-RtUZTl^PsyQ#)sGiu>;kuAoCy?Bo4wLzasq2z(Ab)85kgT zf!v0$2V@=$gUp3saFBrsm_4vCftZ2t4@fUqAp^v}FnNeM5W5g;uu5=zf>}@kW(T@I zAYlSl1l9vH8>Svz9-WV*4jPA;@d49=#cZ&}SO~CNu!zHjVD`eo4917q0au8dL9`vX z+z+#p5RKajh_Hg$0W%Aq9;h5a_e0fT#0yNE2%2a+VD2ZvOqddw*)SR=KIG{Cf8_uF z|G@tL{{!a#{~H+p|95=&|6jw0|9@Em{{Lz-_#j6ty=Z}YWVm6zt;c$|2H)B|G)LW|NoEw`~Uy`U!ZIc#-Mf>XpGVUsU6k; z8n~oiNP*%A9n-^hsGaC#9EcAt3qkU(Zpe9g5~fKFm+%WR$n39fN4L-EHt}7LJVkPVDrEdxCyWt{B>2b><3|FHz2cN=7H2;!FcT^E9_xz zfVdqw4q$eG>_NsLaS#THVdQ_Xov<*0*$Jaz;xId5G|Ybxd59ZO{R*-Vf;m##%u>co} z1z>Yv>R@)E(jaA+7`=TBvlE?0w+rS5OcRM0ftd-j3uY#a52IoJf~kk8gYjWBx;mIR zE*j)gV*L+_N054$9WXaQ#mJ&y?t=LfW+sdeqhWT!)Wg)l_(+zcr31JOOdKu%W5CQH z6b>*qpxX`852In~(D~@%Nb(r%eVD&tG)yndZWxVh2FyP=Xqf+DG!A8mJO;BHM#Joa z*$ty{8bpBv%r2PSg!~UvPl$$@15=03i7+*|+yIluX9lHmFgsvwfbl5^dszI#Xo60J z*$E3fnB7R?1kFHGK(yU3eMokJ^&;_MN@z~Q?1a%Yw-CDpVE<#68WkOCA@Cn%AmRYy z|L+GM{(s%@;s4c^g8!@94E~3<3;bKv-tafn(ec-+1B_Qg9hg_GTEG+<8X~`H6=)qp zXefj(y}xSJs#RA*>#zS>^&d1Y5&Cb{|Ns9(|9}0z>i_TmSO5S2|N8&`|KCBiI06Fz D@pane literal 0 HcmV?d00001 diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index dee90f11c..3c3f4019f 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -39,6 +39,7 @@ extern "C" { #include <86box/network.h> #include <86box/ui.h> #include <86box/machine_status.h> +#include <86box/config.h> }; #include @@ -89,7 +90,7 @@ struct Pixmaps { PixmapSetEmptyActive mo; PixmapSetActive hd; PixmapSetEmptyActive net; - QPixmap sound; + QPixmap sound, soundMuted; }; struct StateActive { @@ -215,6 +216,7 @@ struct MachineStatus::States { pixmaps.hd.load("/hard_disk%1.ico"); pixmaps.net.load("/network%1.ico"); pixmaps.sound = ProgSettings::loadIcon("/sound.ico").pixmap(pixmap_size); + pixmaps.soundMuted = ProgSettings::loadIcon("/sound_mute.ico").pixmap(pixmap_size); cartridge[0].pixmaps = &pixmaps.cartridge; cartridge[1].pixmaps = &pixmaps.cartridge; @@ -256,12 +258,19 @@ MachineStatus::MachineStatus(QObject *parent) , refreshTimer(new QTimer(this)) { d = std::make_unique(this); + muteUnmuteAction = nullptr; connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons); refreshTimer->start(75); } MachineStatus::~MachineStatus() = default; +void +MachineStatus::setSoundGainAction(QAction* action) +{ + soundGainAction = action; +} + bool MachineStatus::hasCassette() { @@ -494,6 +503,28 @@ MachineStatus::refresh(QStatusBar *sbar) } sbar->removeWidget(d->sound.get()); + if (!muteUnmuteAction) { + muteUnmuteAction = new QAction; + connect(muteUnmuteAction, &QAction::triggered, this, [this]() { + sound_muted ^= 1; + config_save(); + if (d->sound) + d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); + + muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); + }); + } + + if (!soundMenu) { + soundMenu = new QMenu((QWidget*)parent()); + + soundMenu->addAction(muteUnmuteAction); + soundMenu->addSeparator(); + soundMenu->addAction(soundGainAction); + + muteUnmuteAction->setParent(soundMenu); + } + if (cassette_enable) { d->cassette.label = std::make_unique(); d->cassette.setEmpty(QString(cassette_fname).isEmpty()); @@ -662,12 +693,14 @@ MachineStatus::refresh(QStatusBar *sbar) } d->sound = std::make_unique(); - d->sound->setPixmap(d->pixmaps.sound); - - connect(d->sound.get(), &ClickableLabel::doubleClicked, d->sound.get(), [](QPoint pos) { - SoundGain gain(main_window); - gain.exec(); + d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); + if (muteUnmuteAction) + muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); + + connect(d->sound.get(), &ClickableLabel::clicked, this, [this](QPoint pos) { + this->soundMenu->popup(pos - QPoint(0, this->soundMenu->sizeHint().height())); }); + d->sound->setToolTip(tr("Sound")); sbar->addWidget(d->sound.get()); d->text = std::make_unique(); diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp index fc0e33e91..90b420763 100644 --- a/src/qt/qt_machinestatus.hpp +++ b/src/qt/qt_machinestatus.hpp @@ -1,6 +1,8 @@ #ifndef QT_MACHINESTATUS_HPP #define QT_MACHINESTATUS_HPP +#include +#include #include #include #include @@ -71,6 +73,7 @@ public: QString getMessage(); void clearActivity(); + void setSoundGainAction(QAction* action); public slots: void refresh(QStatusBar *sbar); void message(const QString &msg); @@ -82,6 +85,9 @@ private: struct States; std::unique_ptr d; QTimer *refreshTimer; + QAction *soundGainAction; + QAction *muteUnmuteAction; + QMenu *soundMenu; }; #endif // QT_MACHINESTATUS_HPP diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 552fd0310..61f5f6fe1 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -178,6 +178,7 @@ MainWindow::MainWindow(QWidget *parent) extern MainWindow *main_window; main_window = this; ui->setupUi(this); + status->setSoundGainAction(ui->actionSound_gain); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); statusBar()->setStyleSheet("QStatusBar::item {border: None; } QStatusBar QLabel { margin-right: 2px; margin-bottom: 1px; }"); diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index 1f6341786..6ca323b89 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -43,6 +43,7 @@ qt/icons/other_removable_devices.ico qt/icons/ports.ico qt/icons/sound.ico + qt/icons/sound_mute.ico qt/icons/storage_controllers.ico qt/icons/zip.ico qt/icons/zip_active.ico diff --git a/src/sound/openal.c b/src/sound/openal.c index a41199b23..90f626362 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -278,7 +278,7 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size, const in alGetSourcei(source[src], AL_BUFFERS_PROCESSED, &processed); if (processed >= 1) { - const double gain = pow(10.0, (double) sound_gain / 20.0); + const double gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); alListenerf(AL_GAIN, (float) gain); alSourceUnqueueBuffers(source[src], 1, &buffer); diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c index 9b341f574..2aee97efc 100644 --- a/src/sound/xaudio2.c +++ b/src/sound/xaudio2.c @@ -245,7 +245,7 @@ givealbuffer_common(const void *buf, IXAudio2SourceVoice *sourcevoice, const siz if (!initialized) return; - (void) IXAudio2MasteringVoice_SetVolume(mastervoice, pow(10.0, (double) sound_gain / 20.0), + (void) IXAudio2MasteringVoice_SetVolume(mastervoice, sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0), XAUDIO2_COMMIT_NOW); XAUDIO2_BUFFER buffer = { 0 }; buffer.Flags = 0; From c1c4bcc889d59f5a4f714d6802e5592054f5cacf Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 1 Mar 2025 15:54:50 +0500 Subject: [PATCH 0385/1190] Disable Win11 rounded window corners when the status bar is hidden --- src/qt/qt_mainwindow.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 61f5f6fe1..9802a2666 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -122,6 +122,19 @@ extern int qt_nvr_save(void); #include "x11_util.h" #endif +#ifdef Q_OS_WINDOWS +#include +#ifndef DWMWA_WINDOW_CORNER_PREFERENCE +#define DWMWA_WINDOW_CORNER_PREFERENCE 33 +#endif +#ifndef DWMWCP_DEFAULT +#define DWMWCP_DEFAULT 0 +#endif +#ifndef DWMWCP_DONOTROUND +#define DWMWCP_DONOTROUND 1 +#endif +#endif + #ifdef Q_OS_MACOS # include "cocoa_keyboard.hpp" // The namespace is required to avoid clashing typedefs; we only use this @@ -181,6 +194,10 @@ MainWindow::MainWindow(QWidget *parent) status->setSoundGainAction(ui->actionSound_gain); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); +#ifdef Q_OS_WINDOWS + auto cornerPreference = (hide_status_bar ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT); + DwmSetWindowAttribute((HWND) this->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); +#endif statusBar()->setStyleSheet("QStatusBar::item {border: None; } QStatusBar QLabel { margin-right: 2px; margin-bottom: 1px; }"); this->centralWidget()->setStyleSheet("background-color: black;"); ui->toolBar->setVisible(!hide_tool_bar); @@ -1833,6 +1850,10 @@ MainWindow::on_actionHide_status_bar_triggered() hide_status_bar ^= 1; ui->actionHide_status_bar->setChecked(hide_status_bar); statusBar()->setVisible(!hide_status_bar); +#ifdef Q_OS_WINDOWS + auto cornerPreference = (hide_status_bar ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT); + DwmSetWindowAttribute((HWND) main_window->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); +#endif if (vid_resize >= 2) { setFixedSize(fixed_size_x, fixed_size_y + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); } else { From d6fa4d4f98f15f6b21ebffcff0bfa3a2f6b8a76a Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 6 Mar 2025 22:20:13 +0500 Subject: [PATCH 0386/1190] Disable Win11 rounded corners on the secondary monitor windows --- src/qt/qt_mainwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 9802a2666..036f56375 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -816,6 +816,10 @@ MainWindow::initRendererMonitorSlot(int monitor_index) if (vid_resize == 2) secondaryRenderer->setFixedSize(fixed_size_x, fixed_size_y); secondaryRenderer->setWindowIcon(this->windowIcon()); +#ifdef Q_OS_WINDOWS + auto cornerPreference = DWMWCP_DONOTROUND; + DwmSetWindowAttribute((HWND) secondaryRenderer->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); +#endif if (show_second_monitors) { secondaryRenderer->show(); if (window_remember) { From e6f96352e083a9df48e87babed6e3afadf7a0e89 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 1 Mar 2025 02:01:00 +0500 Subject: [PATCH 0387/1190] Fix serial passthrough configure buttons not re-enabling when the checkboxes are toggled --- src/qt/qt_settingsports.cpp | 43 ++++++++++++++++--------------------- src/qt/qt_settingsports.hpp | 14 ++++++------ 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index 9679c9e21..3855a8b68 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -68,21 +68,14 @@ SettingsPorts::SettingsPorts(QWidget *parent) for (int i = 0; i < SERIAL_MAX; i++) { auto *checkBox = findChild(QString("checkBoxSerial%1").arg(i + 1)); auto *checkBoxPass = findChild(QString("checkBoxSerialPassThru%1").arg(i + 1)); + auto *buttonPass = findChild(QString("pushButtonSerialPassThru%1").arg(i + 1)); if (checkBox != NULL) checkBox->setChecked(com_ports[i].enabled > 0); - if (checkBoxPass != NULL) + if (checkBoxPass != NULL) { checkBoxPass->setChecked(serial_passthrough_enabled[i]); + buttonPass->setEnabled(serial_passthrough_enabled[i]); + } } - - ui->pushButtonSerialPassThru1->setEnabled(serial_passthrough_enabled[0]); - ui->pushButtonSerialPassThru2->setEnabled(serial_passthrough_enabled[1]); - ui->pushButtonSerialPassThru3->setEnabled(serial_passthrough_enabled[2]); - ui->pushButtonSerialPassThru4->setEnabled(serial_passthrough_enabled[3]); -#if 0 - ui->pushButtonSerialPassThru5->setEnabled(serial_passthrough_enabled[4]); - ui->pushButtonSerialPassThru6->setEnabled(serial_passthrough_enabled[5]); - ui->pushButtonSerialPassThru7->setEnabled(serial_passthrough_enabled[6]); -#endif } SettingsPorts::~SettingsPorts() @@ -181,45 +174,45 @@ SettingsPorts::on_pushButtonSerialPassThru7_clicked() #endif void -SettingsPorts::on_checkBoxSerialPassThru1_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru1_stateChanged(int state) { - ui->pushButtonSerialPassThru1->setEnabled(checked); + ui->pushButtonSerialPassThru1->setEnabled(state == Qt::Checked); } void -SettingsPorts::on_checkBoxSerialPassThru2_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru2_stateChanged(int state) { - ui->pushButtonSerialPassThru2->setEnabled(checked); + ui->pushButtonSerialPassThru2->setEnabled(state == Qt::Checked); } void -SettingsPorts::on_checkBoxSerialPassThru3_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru3_stateChanged(int state) { - ui->pushButtonSerialPassThru3->setEnabled(checked); + ui->pushButtonSerialPassThru3->setEnabled(state == Qt::Checked); } void -SettingsPorts::on_checkBoxSerialPassThru4_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru4_stateChanged(int state) { - ui->pushButtonSerialPassThru4->setEnabled(checked); + ui->pushButtonSerialPassThru4->setEnabled(state == Qt::Checked); } #if 0 void -SettingsPorts::on_checkBoxSerialPassThru5_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru5_stateChanged(int state) { - ui->pushButtonSerialPassThru5->setEnabled(checked); + ui->pushButtonSerialPassThru5->setEnabled(state == Qt::Checked); } void -SettingsPorts::on_checkBoxSerialPassThru6_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru6_stateChanged(int state) { - ui->pushButtonSerialPassThru6->setEnabled(checked); + ui->pushButtonSerialPassThru6->setEnabled(state == Qt::Checked); } void -SettingsPorts::on_checkBoxSerialPassThru7_clicked(bool checked) +SettingsPorts::on_checkBoxSerialPassThru7_stateChanged(int state) { - ui->pushButtonSerialPassThru7->setEnabled(checked); + ui->pushButtonSerialPassThru7->setEnabled(state == Qt::Checked); } #endif diff --git a/src/qt/qt_settingsports.hpp b/src/qt/qt_settingsports.hpp index fb9cdb343..cba5bceff 100644 --- a/src/qt/qt_settingsports.hpp +++ b/src/qt/qt_settingsports.hpp @@ -18,14 +18,14 @@ public: #if 0 private slots: - void on_checkBoxSerialPassThru7_clicked(bool checked); - void on_checkBoxSerialPassThru6_clicked(bool checked); - void on_checkBoxSerialPassThru5_clicked(bool checked); + void on_checkBoxSerialPassThru7_stateChanged(int state); + void on_checkBoxSerialPassThru6_stateChanged(int state); + void on_checkBoxSerialPassThru5_stateChanged(int state); #endif - void on_checkBoxSerialPassThru4_clicked(bool checked); - void on_checkBoxSerialPassThru3_clicked(bool checked); - void on_checkBoxSerialPassThru2_clicked(bool checked); - void on_checkBoxSerialPassThru1_clicked(bool checked); + void on_checkBoxSerialPassThru4_stateChanged(int state); + void on_checkBoxSerialPassThru3_stateChanged(int state); + void on_checkBoxSerialPassThru2_stateChanged(int state); + void on_checkBoxSerialPassThru1_stateChanged(int state); private slots: #if 0 From b018017c55a5f2c8c80cc6816369ac56ef76811f Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 1 Mar 2025 02:05:30 +0500 Subject: [PATCH 0388/1190] Disable serial passthrough checkboxes when the corresponding port is disabled --- src/qt/qt_settingsports.cpp | 54 ++++++++++++++++++++++++++++++++++++- src/qt/qt_settingsports.hpp | 22 ++++++++++----- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index 3855a8b68..e5a8039a4 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -72,8 +72,9 @@ SettingsPorts::SettingsPorts(QWidget *parent) if (checkBox != NULL) checkBox->setChecked(com_ports[i].enabled > 0); if (checkBoxPass != NULL) { + checkBoxPass->setEnabled(com_ports[i].enabled > 0); checkBoxPass->setChecked(serial_passthrough_enabled[i]); - buttonPass->setEnabled(serial_passthrough_enabled[i]); + buttonPass->setEnabled((com_ports[i].enabled > 0) && serial_passthrough_enabled[i]); } } } @@ -173,6 +174,57 @@ SettingsPorts::on_pushButtonSerialPassThru7_clicked() } #endif +void +SettingsPorts::on_checkBoxSerial1_stateChanged(int state) +{ + ui->checkBoxSerialPassThru1->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru1->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru1->isChecked()); +} + +void +SettingsPorts::on_checkBoxSerial2_stateChanged(int state) +{ + ui->checkBoxSerialPassThru2->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru2->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru2->isChecked()); +} + +void +SettingsPorts::on_checkBoxSerial3_stateChanged(int state) +{ + ui->checkBoxSerialPassThru3->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru3->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru3->isChecked()); +} + +void +SettingsPorts::on_checkBoxSerial4_stateChanged(int state) +{ + ui->checkBoxSerialPassThru4->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru4->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru4->isChecked()); +} + +#if 0 +void +SettingsPorts::on_checkBoxSerial5_stateChanged(int state) +{ + ui->checkBoxSerialPassThru5->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru5->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru5->isChecked()); +} + +void +SettingsPorts::on_checkBoxSerial6_stateChanged(int state) +{ + ui->checkBoxSerialPassThru6->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru6->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru6->isChecked()); +} + +void +SettingsPorts::on_checkBoxSerial7_stateChanged(int state) +{ + ui->checkBoxSerialPassThru7->setEnabled(state == Qt::Checked); + ui->pushButtonSerialPassThru7->setEnabled((state == Qt::Checked) && ui->checkBoxSerialPassThru7->isChecked()); +} +#endif + void SettingsPorts::on_checkBoxSerialPassThru1_stateChanged(int state) { diff --git a/src/qt/qt_settingsports.hpp b/src/qt/qt_settingsports.hpp index cba5bceff..7d332509c 100644 --- a/src/qt/qt_settingsports.hpp +++ b/src/qt/qt_settingsports.hpp @@ -16,8 +16,8 @@ public: void save(); -#if 0 private slots: +#if 0 void on_checkBoxSerialPassThru7_stateChanged(int state); void on_checkBoxSerialPassThru6_stateChanged(int state); void on_checkBoxSerialPassThru5_stateChanged(int state); @@ -27,7 +27,16 @@ private slots: void on_checkBoxSerialPassThru2_stateChanged(int state); void on_checkBoxSerialPassThru1_stateChanged(int state); -private slots: +#if 0 + void on_checkBoxSerial7_stateChanged(int state); + void on_checkBoxSerial6_stateChanged(int state); + void on_checkBoxSerial5_stateChanged(int state); +#endif + void on_checkBoxSerial4_stateChanged(int state); + void on_checkBoxSerial3_stateChanged(int state); + void on_checkBoxSerial2_stateChanged(int state); + void on_checkBoxSerial1_stateChanged(int state); + #if 0 void on_pushButtonSerialPassThru7_clicked(); void on_pushButtonSerialPassThru6_clicked(); @@ -38,11 +47,10 @@ private slots: void on_pushButtonSerialPassThru2_clicked(); void on_pushButtonSerialPassThru1_clicked(); -private slots: - void on_checkBoxParallel4_stateChanged(int arg1); - void on_checkBoxParallel3_stateChanged(int arg1); - void on_checkBoxParallel2_stateChanged(int arg1); - void on_checkBoxParallel1_stateChanged(int arg1); + void on_checkBoxParallel4_stateChanged(int state); + void on_checkBoxParallel3_stateChanged(int state); + void on_checkBoxParallel2_stateChanged(int state); + void on_checkBoxParallel1_stateChanged(int state); private: Ui::SettingsPorts *ui; From 3bbeae91d1c405ea979b948c3407f3cef3479327 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 1 Mar 2025 15:22:36 +0500 Subject: [PATCH 0389/1190] Add plumbing for updates on machine change to the port settings page --- src/qt/qt_settings.cpp | 2 + src/qt/qt_settingsports.cpp | 149 +++++++++++++++++++----------------- src/qt/qt_settingsports.hpp | 69 +++++++++-------- 3 files changed, 116 insertions(+), 104 deletions(-) diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp index 67064b73a..471558e22 100644 --- a/src/qt/qt_settings.cpp +++ b/src/qt/qt_settings.cpp @@ -153,6 +153,8 @@ Settings::Settings(QWidget *parent) &SettingsSound::onCurrentMachineChanged); connect(machine, &SettingsMachine::currentMachineChanged, network, &SettingsNetwork::onCurrentMachineChanged); + connect(machine, &SettingsMachine::currentMachineChanged, ports, + &SettingsPorts::onCurrentMachineChanged); connect(machine, &SettingsMachine::currentMachineChanged, storageControllers, &SettingsStorageControllers::onCurrentMachineChanged); connect(machine, &SettingsMachine::currentMachineChanged, otherPeripherals, diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index e5a8039a4..630c843b9 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -38,6 +38,40 @@ SettingsPorts::SettingsPorts(QWidget *parent) , ui(new Ui::SettingsPorts) { ui->setupUi(this); + onCurrentMachineChanged(machine); +} + +SettingsPorts::~SettingsPorts() +{ + delete ui; +} + +void +SettingsPorts::save() +{ + for (int i = 0; i < PARALLEL_MAX; i++) { + auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); + auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); + if (cbox != NULL) + lpt_ports[i].device = cbox->currentData().toInt(); + if (checkBox != NULL) + lpt_ports[i].enabled = checkBox->isChecked() ? 1 : 0; + } + + for (int i = 0; i < SERIAL_MAX; i++) { + auto *checkBox = findChild(QString("checkBoxSerial%1").arg(i + 1)); + auto *checkBoxPass = findChild(QString("checkBoxSerialPassThru%1").arg(i + 1)); + if (checkBox != NULL) + com_ports[i].enabled = checkBox->isChecked() ? 1 : 0; + if (checkBoxPass != NULL) + serial_passthrough_enabled[i] = checkBoxPass->isChecked(); + } +} + +void +SettingsPorts::onCurrentMachineChanged(int machineId) +{ + this->machineId = machineId; for (int i = 0; i < PARALLEL_MAX; i++) { auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); @@ -79,33 +113,6 @@ SettingsPorts::SettingsPorts(QWidget *parent) } } -SettingsPorts::~SettingsPorts() -{ - delete ui; -} - -void -SettingsPorts::save() -{ - for (int i = 0; i < PARALLEL_MAX; i++) { - auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); - auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); - if (cbox != NULL) - lpt_ports[i].device = cbox->currentData().toInt(); - if (checkBox != NULL) - lpt_ports[i].enabled = checkBox->isChecked() ? 1 : 0; - } - - for (int i = 0; i < SERIAL_MAX; i++) { - auto *checkBox = findChild(QString("checkBoxSerial%1").arg(i + 1)); - auto *checkBoxPass = findChild(QString("checkBoxSerialPassThru%1").arg(i + 1)); - if (checkBox != NULL) - com_ports[i].enabled = checkBox->isChecked() ? 1 : 0; - if (checkBoxPass != NULL) - serial_passthrough_enabled[i] = checkBoxPass->isChecked(); - } -} - void SettingsPorts::on_checkBoxParallel1_stateChanged(int state) { @@ -130,50 +137,6 @@ SettingsPorts::on_checkBoxParallel4_stateChanged(int state) ui->comboBoxLpt4->setEnabled(state == Qt::Checked); } -void -SettingsPorts::on_pushButtonSerialPassThru1_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 1, qobject_cast(Settings::settings)); -} - -void -SettingsPorts::on_pushButtonSerialPassThru2_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 2, qobject_cast(Settings::settings)); -} - -void -SettingsPorts::on_pushButtonSerialPassThru3_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 3, qobject_cast(Settings::settings)); -} - -void -SettingsPorts::on_pushButtonSerialPassThru4_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 4, qobject_cast(Settings::settings)); -} - -#if 0 -void -SettingsPorts::on_pushButtonSerialPassThru5_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 5, qobject_cast(Settings::settings)); -} - -void -SettingsPorts::on_pushButtonSerialPassThru6_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 6, qobject_cast(Settings::settings)); -} - -void -SettingsPorts::on_pushButtonSerialPassThru7_clicked() -{ - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 7, qobject_cast(Settings::settings)); -} -#endif - void SettingsPorts::on_checkBoxSerial1_stateChanged(int state) { @@ -268,3 +231,47 @@ SettingsPorts::on_checkBoxSerialPassThru7_stateChanged(int state) ui->pushButtonSerialPassThru7->setEnabled(state == Qt::Checked); } #endif + +void +SettingsPorts::on_pushButtonSerialPassThru1_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 1, qobject_cast(Settings::settings)); +} + +void +SettingsPorts::on_pushButtonSerialPassThru2_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 2, qobject_cast(Settings::settings)); +} + +void +SettingsPorts::on_pushButtonSerialPassThru3_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 3, qobject_cast(Settings::settings)); +} + +void +SettingsPorts::on_pushButtonSerialPassThru4_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 4, qobject_cast(Settings::settings)); +} + +#if 0 +void +SettingsPorts::on_pushButtonSerialPassThru5_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 5, qobject_cast(Settings::settings)); +} + +void +SettingsPorts::on_pushButtonSerialPassThru6_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 6, qobject_cast(Settings::settings)); +} + +void +SettingsPorts::on_pushButtonSerialPassThru7_clicked() +{ + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 7, qobject_cast(Settings::settings)); +} +#endif diff --git a/src/qt/qt_settingsports.hpp b/src/qt/qt_settingsports.hpp index 7d332509c..83560914f 100644 --- a/src/qt/qt_settingsports.hpp +++ b/src/qt/qt_settingsports.hpp @@ -16,44 +16,47 @@ public: void save(); +public slots: + void onCurrentMachineChanged(int machineId); + private slots: -#if 0 - void on_checkBoxSerialPassThru7_stateChanged(int state); - void on_checkBoxSerialPassThru6_stateChanged(int state); - void on_checkBoxSerialPassThru5_stateChanged(int state); -#endif - void on_checkBoxSerialPassThru4_stateChanged(int state); - void on_checkBoxSerialPassThru3_stateChanged(int state); - void on_checkBoxSerialPassThru2_stateChanged(int state); - void on_checkBoxSerialPassThru1_stateChanged(int state); - -#if 0 - void on_checkBoxSerial7_stateChanged(int state); - void on_checkBoxSerial6_stateChanged(int state); - void on_checkBoxSerial5_stateChanged(int state); -#endif - void on_checkBoxSerial4_stateChanged(int state); - void on_checkBoxSerial3_stateChanged(int state); - void on_checkBoxSerial2_stateChanged(int state); - void on_checkBoxSerial1_stateChanged(int state); - -#if 0 - void on_pushButtonSerialPassThru7_clicked(); - void on_pushButtonSerialPassThru6_clicked(); - void on_pushButtonSerialPassThru5_clicked(); -#endif - void on_pushButtonSerialPassThru4_clicked(); - void on_pushButtonSerialPassThru3_clicked(); - void on_pushButtonSerialPassThru2_clicked(); - void on_pushButtonSerialPassThru1_clicked(); - - void on_checkBoxParallel4_stateChanged(int state); - void on_checkBoxParallel3_stateChanged(int state); - void on_checkBoxParallel2_stateChanged(int state); void on_checkBoxParallel1_stateChanged(int state); + void on_checkBoxParallel2_stateChanged(int state); + void on_checkBoxParallel3_stateChanged(int state); + void on_checkBoxParallel4_stateChanged(int state); + + void on_checkBoxSerial1_stateChanged(int state); + void on_checkBoxSerial2_stateChanged(int state); + void on_checkBoxSerial3_stateChanged(int state); + void on_checkBoxSerial4_stateChanged(int state); +#if 0 + void on_checkBoxSerial5_stateChanged(int state); + void on_checkBoxSerial6_stateChanged(int state); + void on_checkBoxSerial7_stateChanged(int state); +#endif + void on_checkBoxSerialPassThru1_stateChanged(int state); + void on_checkBoxSerialPassThru2_stateChanged(int state); + void on_checkBoxSerialPassThru3_stateChanged(int state); + void on_checkBoxSerialPassThru4_stateChanged(int state); +#if 0 + void on_checkBoxSerialPassThru5_stateChanged(int state); + void on_checkBoxSerialPassThru6_stateChanged(int state); + void on_checkBoxSerialPassThru7_stateChanged(int state); +#endif + + void on_pushButtonSerialPassThru1_clicked(); + void on_pushButtonSerialPassThru2_clicked(); + void on_pushButtonSerialPassThru3_clicked(); + void on_pushButtonSerialPassThru4_clicked(); +#if 0 + void on_pushButtonSerialPassThru5_clicked(); + void on_pushButtonSerialPassThru6_clicked(); + void on_pushButtonSerialPassThru7_clicked(); +#endif private: Ui::SettingsPorts *ui; + int machineId = 0; }; #endif // QT_SETTINGSPORTS_HPP From 676087bcaecd2986f48fdc919b430481023c06b9 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 00:11:45 +0500 Subject: [PATCH 0390/1190] Refactor into a function --- src/qt/qt_mainwindow.cpp | 22 +++------------------- src/qt/qt_util.cpp | 22 ++++++++++++++++++++++ src/qt/qt_util.hpp | 3 +++ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 036f56375..1cc6c33c9 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -122,19 +122,6 @@ extern int qt_nvr_save(void); #include "x11_util.h" #endif -#ifdef Q_OS_WINDOWS -#include -#ifndef DWMWA_WINDOW_CORNER_PREFERENCE -#define DWMWA_WINDOW_CORNER_PREFERENCE 33 -#endif -#ifndef DWMWCP_DEFAULT -#define DWMWCP_DEFAULT 0 -#endif -#ifndef DWMWCP_DONOTROUND -#define DWMWCP_DONOTROUND 1 -#endif -#endif - #ifdef Q_OS_MACOS # include "cocoa_keyboard.hpp" // The namespace is required to avoid clashing typedefs; we only use this @@ -195,8 +182,7 @@ MainWindow::MainWindow(QWidget *parent) ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); #ifdef Q_OS_WINDOWS - auto cornerPreference = (hide_status_bar ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT); - DwmSetWindowAttribute((HWND) this->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); + util::setWin11RoundedCorners(this->winId(), (hide_status_bar ? false : true)); #endif statusBar()->setStyleSheet("QStatusBar::item {border: None; } QStatusBar QLabel { margin-right: 2px; margin-bottom: 1px; }"); this->centralWidget()->setStyleSheet("background-color: black;"); @@ -817,8 +803,7 @@ MainWindow::initRendererMonitorSlot(int monitor_index) secondaryRenderer->setFixedSize(fixed_size_x, fixed_size_y); secondaryRenderer->setWindowIcon(this->windowIcon()); #ifdef Q_OS_WINDOWS - auto cornerPreference = DWMWCP_DONOTROUND; - DwmSetWindowAttribute((HWND) secondaryRenderer->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); + util::setWin11RoundedCorners(secondaryRenderer->winId(), false); #endif if (show_second_monitors) { secondaryRenderer->show(); @@ -1855,8 +1840,7 @@ MainWindow::on_actionHide_status_bar_triggered() ui->actionHide_status_bar->setChecked(hide_status_bar); statusBar()->setVisible(!hide_status_bar); #ifdef Q_OS_WINDOWS - auto cornerPreference = (hide_status_bar ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT); - DwmSetWindowAttribute((HWND) main_window->winId(), DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); + util::setWin11RoundedCorners(main_window->winId(), (hide_status_bar ? false : true)); #endif if (vid_resize >= 2) { setFixedSize(fixed_size_x, fixed_size_y + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); diff --git a/src/qt/qt_util.cpp b/src/qt/qt_util.cpp index 5c9059272..0c78c2f5e 100644 --- a/src/qt/qt_util.cpp +++ b/src/qt/qt_util.cpp @@ -26,6 +26,19 @@ #include #include "qt_util.hpp" +#ifdef Q_OS_WINDOWS +# include +# ifndef DWMWA_WINDOW_CORNER_PREFERENCE +# define DWMWA_WINDOW_CORNER_PREFERENCE 33 +# endif +# ifndef DWMWCP_DEFAULT +# define DWMWCP_DEFAULT 0 +# endif +# ifndef DWMWCP_DONOTROUND +# define DWMWCP_DONOTROUND 1 +# endif +#endif + extern "C" { #include <86box/86box.h> #include <86box/config.h> @@ -48,6 +61,15 @@ screenOfWidget(QWidget *widget) #endif } +#ifdef Q_OS_WINDOWS +void +setWin11RoundedCorners(WId hwnd, bool enable) +{ + auto cornerPreference = (enable ? DWMWCP_DEFAULT : DWMWCP_DONOTROUND); + DwmSetWindowAttribute((HWND) hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, (LPCVOID) &cornerPreference, sizeof(cornerPreference)); +} +#endif + QString DlgFilter(std::initializer_list extensions, bool last) { diff --git a/src/qt/qt_util.hpp b/src/qt/qt_util.hpp index 6a0bdc30b..9432610b6 100644 --- a/src/qt/qt_util.hpp +++ b/src/qt/qt_util.hpp @@ -13,6 +13,9 @@ static constexpr auto UUID_MIN_LENGTH = 36; QString DlgFilter(std::initializer_list extensions, bool last = false); /* Returns screen the widget is on */ QScreen *screenOfWidget(QWidget *widget); +#ifdef Q_OS_WINDOWS +void setWin11RoundedCorners(WId hwnd, bool enable); +#endif QString currentUuid(); void storeCurrentUuid(); bool compareUuid(); From 05a005b6f0a681b965ab60ae7638c2c2408fd8e7 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 05:21:16 +0500 Subject: [PATCH 0391/1190] Initialize the sound icon menu pointer Fixes a crash when clicking the icon --- src/qt/qt_machinestatus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index 3c3f4019f..a00cc032b 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -259,6 +259,7 @@ MachineStatus::MachineStatus(QObject *parent) { d = std::make_unique(this); muteUnmuteAction = nullptr; + soundMenu = nullptr; connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons); refreshTimer->start(75); } From 265152db754b7b60cc3eeafd2b6b596ef0c4da0b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 7 Mar 2025 19:58:36 +0100 Subject: [PATCH 0392/1190] NCR 53c400: slightly more accurate speed. See above. --- src/scsi/scsi_ncr53c400.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index c83e75442..fc62a1cab 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -425,8 +425,8 @@ ncr53c400_callback(void *priv) if (scsi_bus->tx_mode != PIO_TX_BUS) { if (ncr400->type == ROM_T130B) { - ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 200.0); - timer_on_auto(&ncr400->timer, scsi_bus->period / 200.0); + ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0); + timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0); } else timer_on_auto(&ncr400->timer, 1.0); } From 86343327be6d2cd41424d1deeaa659b493bc31f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 02:13:14 +0600 Subject: [PATCH 0393/1190] Initial PCem OpenGL 3.x renderer port --- src/86box.c | 2 + src/device/kbc_at_dev.c | 3 + src/include/86box/86box.h | 2 + src/include/86box/ini.h | 28 + src/include/86box/keyboard.h | 27 +- src/include/86box/qt-glsl.h | 158 +++ src/include/86box/qt-glslp-parser.h | 56 + src/ini.c | 22 + src/qt/CMakeLists.txt | 3 + src/qt/qt.c | 5 + src/qt/qt_glsl_parser.cpp | 308 +++++ src/qt/qt_main.cpp | 1 + src/qt/qt_mainwindow.cpp | 3 + src/qt/qt_openglrenderer_pcem.cpp | 1679 +++++++++++++++++++++++++++ src/qt/qt_openglrenderer_pcem.hpp | 127 ++ src/qt/qt_rendererstack.cpp | 33 +- src/qt/qt_rendererstack.hpp | 1 + 17 files changed, 2442 insertions(+), 16 deletions(-) create mode 100644 src/include/86box/qt-glsl.h create mode 100644 src/include/86box/qt-glslp-parser.h create mode 100644 src/qt/qt_glsl_parser.cpp create mode 100644 src/qt/qt_openglrenderer_pcem.cpp create mode 100644 src/qt/qt_openglrenderer_pcem.hpp diff --git a/src/86box.c b/src/86box.c index aa3afb085..13167b1bd 100644 --- a/src/86box.c +++ b/src/86box.c @@ -252,6 +252,8 @@ int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ int efscrnsz_y = SCREEN_RES_Y; #endif +__thread int is_cpu_thread = 0; + static wchar_t mouse_msg[3][200]; static volatile atomic_int do_pause_ack = 0; diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index c1041e6e1..82ce31bfd 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -88,6 +88,9 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) { if (main) { kbc_at_dev_log("%s: dev->queue[%02X] = %02X;\n", dev->name, dev->queue_end, val); + if (!is_cpu_thread && kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) { + while (kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) {} + } dev->queue[dev->queue_end] = val; dev->queue_end = (dev->queue_end + 1) & dev->fifo_mask; } else { diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 79bb84009..30905741c 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -188,6 +188,8 @@ extern FILE *stdlog; /* file to log output to */ #endif extern int config_changed; /* config has changed */ +extern __thread int is_cpu_thread; /* Is this the CPU thread? */ + /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index d52620f69..2a73a18b0 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -58,6 +58,7 @@ extern void ini_section_set_hex20(ini_section_t section, const char *name, i extern void ini_section_set_mac(ini_section_t section, const char *name, int val); extern void ini_section_set_string(ini_section_t section, const char *name, const char *val); extern void ini_section_set_wstring(ini_section_t section, const char *name, wchar_t *val); +extern int ini_has_entry(ini_section_t self, const char *name); #define ini_delete_var(ini, head, name) ini_section_delete_var(ini_find_section(ini, head), name) @@ -90,6 +91,33 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); +static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); }; +static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); + if (size == 0) + return res; + strncpy(dst, str, size); + return res; +} +static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = ini_get_int((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = (float)ini_get_double((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = !!ini_get_int((ini_t)config, "", name, defVal); + return res; +} +static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } +static inline void wx_config_free(void *config) { ini_close(config); }; + #ifdef __cplusplus } #endif diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 110e4f760..b7f301a58 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -22,6 +22,13 @@ #ifndef EMU_KEYBOARD_H #define EMU_KEYBOARD_H +#ifdef __cplusplus +# include +using atomic_uint = std::atomic_uint; +#else +# include +#endif + enum { DEV_KBD = 0, DEV_AUX = 1 @@ -54,16 +61,16 @@ typedef struct kbc_at_port_t { typedef struct atkbc_dev_t { const char *name; /* name of this device */ - uint8_t type; - uint8_t command; - uint8_t last_scan_code; - uint8_t state; - uint8_t resolution; - uint8_t rate; - uint8_t cmd_queue_start; - uint8_t cmd_queue_end; - uint8_t queue_start; - uint8_t queue_end; + uint8_t type; + uint8_t command; + uint8_t last_scan_code; + uint8_t state; + uint8_t resolution; + uint8_t rate; + uint8_t cmd_queue_start; + uint8_t cmd_queue_end; + atomic_uint queue_start; + atomic_uint queue_end; uint16_t flags; diff --git a/src/include/86box/qt-glsl.h b/src/include/86box/qt-glsl.h new file mode 100644 index 000000000..0cd8e27cd --- /dev/null +++ b/src/include/86box/qt-glsl.h @@ -0,0 +1,158 @@ +#ifndef SRC_WX_GLSL_H_ +#define SRC_WX_GLSL_H_ + +#define MAX_PREV 7 + +#define MAX_SHADERS 20 +#define MAX_TEXTURES 20 +#define MAX_PARAMETERS 100 + +#define MAX_USER_SHADERS 20 +//#define SDL2_SHADER_DEBUG + +struct shader_scale { + int mode[2]; + float value[2]; +}; + +struct shader_state { + float input_size[2]; + float input_texture_size[2]; + float output_texture_size[2]; + float output_size[2]; + float tex_coords[8]; +}; + +struct shader_vbo { + int vertex_coord; + int tex_coord; + int color; +}; + +struct shader_texture { + int id; + int width; + int height; + int type; + int internal_format; + int format; + int min_filter; + int mag_filter; + int wrap_mode; + void *data; + int mipmap; +}; + +struct shader_lut_texture { + char name[50]; + struct shader_texture texture; +}; + +struct shader_fbo { + int id; + struct shader_texture texture; + int srgb; + int mipmap_input; +}; + +struct shader_prev { + struct shader_fbo fbo; + struct shader_vbo vbo; +}; + +struct shader_input { + int texture; + int input_size; + int texture_size; + int tex_coord; +}; + +struct shader_uniforms { + int mvp_matrix; + int vertex_coord; + int tex_coord; + int color; + + int texture; + int input_size; + int texture_size; + int output_size; + + int frame_count; + int frame_direction; + + struct shader_input orig; + struct shader_input pass[MAX_SHADERS]; + struct shader_input prev_pass[MAX_SHADERS]; + struct shader_input prev[MAX_PREV]; + + int parameters[MAX_PARAMETERS]; + int lut_textures[MAX_TEXTURES]; +}; + +struct shader_program { + int vertex_shader; + int fragment_shader; + int id; +}; + +struct shader_parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct shader_pass { + int active; + char alias[64]; + int vertex_array; + int frame_count_mod; + struct shader_program program; + struct shader_uniforms uniforms; + struct shader_fbo fbo; + struct shader_vbo vbo; + struct shader_state state; + struct shader_scale scale; +}; + +struct glsl_shader { + int active; + char name[64]; + + int num_passes; + struct shader_pass passes[MAX_SHADERS]; + + int num_lut_textures; + struct shader_lut_texture lut_textures[MAX_TEXTURES]; + + int num_parameters; + struct shader_parameter parameters[MAX_PARAMETERS]; + + struct shader_pass prev_scene; + struct shader_prev prev[MAX_PREV + 1]; + + int last_prev_update; + int has_prev; + + float shader_refresh_rate; + + int input_filter_linear; +}; + +typedef struct glsl_t { + int num_shaders; + struct glsl_shader shaders[MAX_USER_SHADERS]; + struct shader_pass scene; + struct shader_pass final_pass; + struct shader_pass fs_color; +#ifdef SDL2_SHADER_DEBUG + struct shader_pass debug; +#endif + int srgb; +} glsl_t; + +#endif \ No newline at end of file diff --git a/src/include/86box/qt-glslp-parser.h b/src/include/86box/qt-glslp-parser.h new file mode 100644 index 000000000..cf2ac464a --- /dev/null +++ b/src/include/86box/qt-glslp-parser.h @@ -0,0 +1,56 @@ +#ifndef SRC_WX_GLSLP_PARSER_H_ +#define SRC_WX_GLSLP_PARSER_H_ + +#include "qt-glsl.h" + +struct parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct texture { + char path[256]; + char name[50]; + int linear; + int mipmap; + char wrap_mode[50]; +}; + +struct shader { + char shader_fn[1024]; + char *shader_program; + char alias[64]; + int filter_linear; + int float_framebuffer; + int srgb_framebuffer; + int mipmap_input; + int frame_count_mod; + char wrap_mode[50]; + char scale_type_x[9], scale_type_y[9]; + float scale_x, scale_y; +}; + +typedef struct glslp_t { + char name[64]; + int num_shaders; + struct shader shaders[MAX_SHADERS]; + + int num_textures; + struct texture textures[MAX_TEXTURES]; + + int num_parameters; + struct parameter parameters[MAX_PARAMETERS]; + + int input_filter_linear; +} glslp_t; + +void get_glslp_name(const char *f, char *s, int size); +glslp_t *glslp_parse(const char *f); +void glslp_free(glslp_t *p); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ \ No newline at end of file diff --git a/src/ini.c b/src/ini.c index 78c873758..4ea6f6381 100644 --- a/src/ini.c +++ b/src/ini.c @@ -157,6 +157,23 @@ find_entry(section_t *section, const char *name) return (NULL); } +int +ini_has_entry(ini_section_t self, const char *name) +{ + section_t *section = (section_t *) self; + const entry_t *entry; + int value = 0; + + if (section == NULL) + return 0; + + entry = find_entry(section, name); + if (entry == NULL) + return 0; + + return 1; +} + static int entries_num(section_t *section) { @@ -593,6 +610,11 @@ ini_section_get_int(ini_section_t self, const char *name, int def) if (entry == NULL) return def; + if (stricmp(entry->data, "true") == 0) + return 1; + if (stricmp(entry->data, "false") == 0) + return 0; + sscanf(entry->data, "%i", &value); return value; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index c08a03016..fd82b9053 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -89,6 +89,9 @@ add_library(ui STATIC qt_hardwarerenderer.hpp qt_openglrenderer.cpp qt_openglrenderer.hpp + qt_openglrenderer_pcem.cpp + qt_openglrenderer_pcem.hpp + qt_glsl_parser.cpp qt_opengloptions.cpp qt_opengloptions.hpp qt_opengloptionsdialog.cpp diff --git a/src/qt/qt.c b/src/qt/qt.c index a9a6460eb..13ddbf498 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -54,6 +54,8 @@ plat_vidapi(const char *api) return 4; } else if (!strcasecmp(api, "vnc")) { return 5; + } else if (!strcasecmp(api, "qt_opengl3_pcem")) { + return 6; } return 0; @@ -83,6 +85,9 @@ plat_vidapi_name(int api) case 5: name = "vnc"; break; + case 6: + name = "qt_opengl3_pcem"; + break; default: fatal("Unknown renderer: %i\n", api); break; diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp new file mode 100644 index 000000000..7cf032a52 --- /dev/null +++ b/src/qt/qt_glsl_parser.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +extern "C" +{ +#include <86box/86box.h> +#include <86box/ini.h> +#include <86box/qt-glslp-parser.h> +#include <86box/path.h> +} + +#define safe_strncpy(a, b, n) \ + do { \ + strncpy((a), (b), (n)-1); \ + (a)[(n)-1] = 0; \ + } while (0) + +static int endswith(const char *str, const char *ext) { + int i; + const char *p; + int elen = strlen(ext); + int slen = strlen(str); + if (slen >= elen) { + p = &str[slen - elen]; + for (i = 0; i < elen; ++i) { + if (tolower(p[i]) != tolower(ext[i])) + return 0; + } + return 1; + } + return 0; +} + +static char *load_file(const char *fn) { + FILE *f = fopen(fn, "rb"); + if (!f) + return 0; + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char *data = (char*)malloc(fsize + 1); + + fread(data, fsize, 1, f); + fclose(f); + + data[fsize] = 0; + + return data; +} + +static void strip_lines(const char *program, const char *starts_with) { + /* strip parameters */ + char *ptr = strstr(program, starts_with); + while (ptr) { + while (*ptr != '\n' && *ptr != '\0') + *ptr++ = ' '; + ptr = strstr(program, starts_with); + } +} + +static void strip_parameters(const char *program) { + /* strip parameters */ + strip_lines(program, "#pragma parameter"); +} + +static void strip_defines(const char *program) { + /* strip texture define */ + strip_lines(program, "#define texture"); +} + +static int has_parameter(glslp_t *glsl, char *id) { + int i; + for (i = 0; i < glsl->num_parameters; ++i) + if (!strcmp(glsl->parameters[i].id, id)) + return 1; + return 0; +} + +static int get_parameters(glslp_t *glsl) { + int i; + struct parameter p; + for (i = 0; i < glsl->num_shaders; ++i) { + struct shader *shader = &glsl->shaders[i]; + FILE *f = fopen(shader->shader_fn, "rb"); + if (!f) + return 0; + + char line[1024]; + while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { + int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, + &p.default_value, &p.min, &p.max, &p.step); + if (num < 5) + continue; + p.id[63] = 0; + p.description[63] = 0; + + if (num == 5) + p.step = 0.1f * (p.max - p.min); + + p.value = p.default_value; + + if (!has_parameter(glsl, p.id)) { + memcpy(&glsl->parameters[glsl->num_parameters++], &p, sizeof(struct parameter)); + pclog("Read parameter: %s (%s) %f, %f -> %f (%f)\n", p.id, p.description, p.default_value, p.min, + p.max, p.step); + } + } + + fclose(f); + } + + return 1; +} + +static struct parameter *get_parameter(glslp_t *glslp, const char *id) { + int i; + for (i = 0; i < glslp->num_parameters; ++i) { + if (!strcmp(glslp->parameters[i].id, id)) { + return &glslp->parameters[i]; + } + } + return 0; +} + +static glslp_t *glsl_parse(const char *f) { + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + glslp->num_shaders = 1; + struct shader *shader = &glslp->shaders[0]; + strcpy(shader->shader_fn, f); + shader->shader_program = load_file(f); + if (!shader->shader_program) { + //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + shader->scale_x = shader->scale_y = 1.0f; + strcpy(shader->scale_type_x, "source"); + strcpy(shader->scale_type_y, "source"); + get_parameters(glslp); + return glslp; +} + +extern "C" { + +void get_glslp_name(const char *f, char *s, int size) { safe_strncpy(s, path_get_filename((char *)f), size); } + +glslp_t *glslp_parse(const char *f) { + int i, j, len, sublen; + char s[513], t[513], z[540]; + + memset(s, 0, sizeof(s)); + if (endswith(f, ".glsl")) + return glsl_parse(f); + + void *cfg = wx_config_load(f); + + if (!cfg) { + fprintf(stderr, "GLSLP Error: Could not load GLSLP-file %s\n", f); + return 0; + } + + glslp_t *glslp = (glslp_t*)malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + + get_glslp_name(f, glslp->name, sizeof(glslp->name)); + + wx_config_get_int(cfg, "shaders", &glslp->num_shaders, 0); + + wx_config_get_bool(cfg, "filter_linear0", &glslp->input_filter_linear, -1); + + for (i = 0; i < glslp->num_shaders; ++i) { + struct shader *shader = &glslp->shaders[i]; + + snprintf(s, sizeof(s) - 1, "shader%d", i); + if (!wx_config_get_string(cfg, s, t, sizeof(t), 0)) { + /* shader doesn't exist, lets break here */ + glslp->num_shaders = i; + break; + } + strcpy(s, f); + *path_get_filename(s) = 0; + snprintf(shader->shader_fn, sizeof(shader->shader_fn) - 1, "%s%s", s, t); + shader->shader_program = load_file(shader->shader_fn); + if (!shader->shader_program) { + fprintf(stderr, "GLSLP Error: Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + + snprintf(s, sizeof(s) - 1, "alias%d", i); + wx_config_get_string(cfg, s, shader->alias, sizeof(shader->alias), 0); + + snprintf(s, sizeof(s) - 1, "filter_linear%d", i + 1); + wx_config_get_bool(cfg, s, &shader->filter_linear, 0); + + snprintf(s, sizeof(s) - 1, "wrap_mode%d", i); + wx_config_get_string(cfg, s, shader->wrap_mode, sizeof(shader->wrap_mode), 0); + + snprintf(s, sizeof(s) - 1, "float_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->float_framebuffer, 0); + snprintf(s, sizeof(s) - 1, "srgb_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->srgb_framebuffer, 0); + + snprintf(s, sizeof(s) - 1, "mipmap_input%d", i); + wx_config_get_bool(cfg, s, &shader->mipmap_input, 0); + + strcpy(shader->scale_type_x, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_x%d", i); + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + strcpy(shader->scale_type_y, "source"); + snprintf(s, sizeof(s) - 1, "scale_type_y%d", i); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + snprintf(s, sizeof(s) - 1, "scale_type%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + } + + snprintf(s, sizeof(s) - 1, "scale_x%d", i); + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + snprintf(s, sizeof(s) - 1, "scale_y%d", i); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + snprintf(s, sizeof(s) - 1, "scale%d", i); + if (wx_config_has_entry(cfg, s)) { + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + } + + snprintf(s, sizeof(s) - 1, "frame_count_mod%d", i); + wx_config_get_int(cfg, s, &shader->frame_count_mod, 0); + } + + /* textures */ + glslp->num_textures = 0; + wx_config_get_string(cfg, "textures", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct texture *tex = &glslp->textures[glslp->num_textures++]; + + strcpy(tex->name, s); + wx_config_get_string(cfg, s, tex->path, sizeof(tex->path), 0); + + snprintf(z, sizeof(z) - 1, "%s_linear", s); + wx_config_get_bool(cfg, z, &tex->linear, 0); + + snprintf(z, sizeof(z) - 1, "%s_mipmap", s); + wx_config_get_bool(cfg, z, &tex->mipmap, 0); + + snprintf(z, sizeof(z) - 1, "%s_wrap_mode", s); + wx_config_get_string(cfg, z, tex->wrap_mode, sizeof(tex->wrap_mode), 0); + + j = i + 1; + } + } + + /* parameters */ + get_parameters(glslp); + + wx_config_get_string(cfg, "parameters", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) { + if (t[i] == ';' || i == len - 1) { + sublen = (i - j) + ((i == len - 1) ? 1 : 0) + 1; + safe_strncpy(s, t + j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct parameter *p = get_parameter(glslp, s); + + if (p) + wx_config_get_float(cfg, s, &p->default_value, 0); + + j = i + 1; + } + } + + wx_config_free(cfg); + + return glslp; +} + +void glslp_free(glslp_t *p) { + int i; + for (i = 0; i < p->num_shaders; ++i) + if (p->shaders[i].shader_program) + free(p->shaders[i].shader_program); + free(p); +} + +} \ No newline at end of file diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 719208c18..9d965be31 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -389,6 +389,7 @@ main_thread_fn() // title_update = 1; uint64_t old_time = elapsed_timer.elapsed(); int drawits = frames = 0; + is_cpu_thread = 1; while (!is_quit && cpu_thread_run) { /* See if it is time to run a frame of code. */ const uint64_t new_time = elapsed_timer.elapsed(); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1cc6c33c9..4c1738e63 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -452,6 +452,9 @@ MainWindow::MainWindow(QWidget *parent) endblit(); } #endif + case 6: + newVidApi = RendererStack::Renderer::OpenGL3PCem; + break; } ui->stackedWidget->switchRenderer(newVidApi); if (!show_second_monitors) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp new file mode 100644 index 000000000..4ab66105c --- /dev/null +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -0,0 +1,1679 @@ +#include "qt_renderercommon.hpp" +#include "qt_mainwindow.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "qt_openglrenderer_pcem.hpp" + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> +} + +#define SCALE_SOURCE 0 +#define SCALE_VIEWPORT 1 +#define SCALE_ABSOLUTE 2 + +float gl3_shader_refresh_rate = 0; +float gl3_input_scale = 1.0f; +int gl3_input_stretch = FULLSCR_SCALE_FULL; +char gl3_shader_file[MAX_USER_SHADERS][512]; + +static int max_texture_size = 65536; + +static struct shader_texture scene_texture; + +static glsl_t *active_shader; + +static QOpenGLExtraFunctions glw; + +static GLfloat matrix[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + +extern int video_filter_method; +extern int video_vsync; +extern int video_focus_dim; +extern int video_refresh_rate; + +static int glsl_version[2]; + +const char *vertex_shader_default_tex_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; + +const char *fragment_shader_default_tex_src = "#version 130\n" + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; + +const char *vertex_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; + +const char *fragment_shader_default_color_src = "#version 130\n" + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; + +static int +next_pow2(unsigned int n) +{ + n--; + n |= n >> 1; // Divide by 2^k for consecutive doublings of k up to 32, + n |= n >> 2; // and then or the results. + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; +} + +static int +create_program(struct shader_program *program) +{ + GLint status; + program->id = glw.glCreateProgram(); + glw.glAttachShader(program->id, program->vertex_shader); + glw.glAttachShader(program->id, program->fragment_shader); + + glw.glLinkProgram(program->id); + + glw.glDeleteShader(program->vertex_shader); + glw.glDeleteShader(program->fragment_shader); + + program->vertex_shader = program->fragment_shader = 0; + + glw.glGetProgramiv(program->id, GL_LINK_STATUS, &status); + + if (!status) { + int maxLength; + int length; + glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); + char *log = (char *) malloc(maxLength); + glw.glGetProgramInfoLog(program->id, maxLength, &length, log); + // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); + free(log); + return 0; + } + + return 1; +} + +static int +compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +{ + const char *source[3]; + char version[50]; + int ver = 0; + char *version_loc = strstr(program, "#version"); + if (version_loc) + ver = (int) strtol(version_loc + 8, (char **) &program, 10); + else { + ver = glsl_version[0] * 100 + glsl_version[1] * 10; + if (ver == 300) + ver = 130; + else if (ver == 310) + ver = 140; + else if (ver == 320) + ver = 150; + } + sprintf(version, "#version %d\n", ver); + source[0] = version; + source[1] = prepend ? prepend : ""; + source[2] = program; + + pclog("GLSL version %d\n", ver); + + GLuint shader = glw.glCreateShader(shader_type); + glw.glShaderSource(shader, 3, source, NULL); + glw.glCompileShader(shader); + + GLint status = 0; + glw.glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) { + GLint length; + glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + char *log = (char *) malloc(length); + glw.glGetShaderInfoLog(shader, length, &length, log); + // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + + pclog("Could not compile shader: %s\n", log); + // pclog("Shader: %s\n", program); + + free(log); + return 0; + } + + *dst = shader; + + return 1; +} + +static GLuint +get_uniform(GLuint program, const char *name) +{ + return glw.glGetUniformLocation(program, name); +} + +static GLuint +get_attrib(GLuint program, const char *name) +{ + return glw.glGetAttribLocation(program, name); +} + +static void +find_uniforms(struct glsl_shader *glsl, int num_pass) +{ + int i; + char s[50]; + struct shader_pass *pass = &glsl->passes[num_pass]; + int p = pass->program.id; + glw.glUseProgram(p); + + struct shader_uniforms *u = &pass->uniforms; + + u->mvp_matrix = get_uniform(p, "MVPMatrix"); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->color = get_attrib(p, "Color"); + + u->frame_count = get_uniform(p, "FrameCount"); + u->frame_direction = get_uniform(p, "FrameDirection"); + + u->texture = get_uniform(p, "Texture"); + u->input_size = get_uniform(p, "InputSize"); + u->texture_size = get_uniform(p, "TextureSize"); + u->output_size = get_uniform(p, "OutputSize"); + + u->orig.texture = get_uniform(p, "OrigTexture"); + u->orig.input_size = get_uniform(p, "OrigInputSize"); + u->orig.texture_size = get_uniform(p, "OrigTextureSize"); + + for (i = 0; i < glsl->num_passes; ++i) { + sprintf(s, "Pass%dTexture", (i + 1)); + u->pass[i].texture = get_uniform(p, s); + sprintf(s, "Pass%dInputSize", (i + 1)); + u->pass[i].input_size = get_uniform(p, s); + sprintf(s, "Pass%dTextureSize", (i + 1)); + u->pass[i].texture_size = get_uniform(p, s); + + sprintf(s, "PassPrev%dTexture", num_pass - i); + u->prev_pass[i].texture = get_uniform(p, s); + sprintf(s, "PassPrev%dInputSize", num_pass - i); + u->prev_pass[i].input_size = get_uniform(p, s); + sprintf(s, "PassPrev%dTextureSize", num_pass - i); + u->prev_pass[i].texture_size = get_uniform(p, s); + } + + u->prev[0].texture = get_uniform(p, "PrevTexture"); + u->prev[0].tex_coord = get_attrib(p, "PrevTexCoord"); + for (i = 1; i < MAX_PREV; ++i) { + sprintf(s, "Prev%dTexture", i); + u->prev[i].texture = get_uniform(p, s); + sprintf(s, "Prev%dTexCoord", i); + u->prev[i].tex_coord = get_attrib(p, s); + } + for (i = 0; i < MAX_PREV; ++i) + if (u->prev[i].texture >= 0) + glsl->has_prev = 1; + + for (i = 0; i < glsl->num_lut_textures; ++i) + u->lut_textures[i] = get_uniform(p, glsl->lut_textures[i].name); + + for (i = 0; i < glsl->num_parameters; ++i) + u->parameters[i] = get_uniform(p, glsl->parameters[i].id); + + glw.glUseProgram(0); +} + +static void +set_scale_mode(char *scale, int *dst) +{ + if (!strcmp(scale, "viewport")) + *dst = SCALE_VIEWPORT; + else if (!strcmp(scale, "absolute")) + *dst = SCALE_ABSOLUTE; + else + *dst = SCALE_SOURCE; +} + +static void +setup_scale(struct shader *shader, struct shader_pass *pass) +{ + set_scale_mode(shader->scale_type_x, &pass->scale.mode[0]); + set_scale_mode(shader->scale_type_y, &pass->scale.mode[1]); + pass->scale.value[0] = shader->scale_x; + pass->scale.value[1] = shader->scale_y; +} + +static void +create_texture(struct shader_texture *tex) +{ + if (tex->width > max_texture_size) + tex->width = max_texture_size; + if (tex->height > max_texture_size) + tex->height = max_texture_size; + pclog("Create texture with size %dx%d\n", tex->width, tex->height); + glw.glGenTextures(1, (GLuint *) &tex->id); + glw.glBindTexture(GL_TEXTURE_2D, tex->id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex->wrap_mode); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex->min_filter); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex->mag_filter); + glw.glTexImage2D(GL_TEXTURE_2D, 0, tex->internal_format, tex->width, tex->height, 0, tex->format, tex->type, tex->data); + if (tex->mipmap) + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); +} + +static void +delete_texture(struct shader_texture *tex) +{ + if (tex->id > 0) + glw.glDeleteTextures(1, (GLuint *) &tex->id); + tex->id = 0; +} + +static void +delete_fbo(struct shader_fbo *fbo) +{ + if (fbo->id >= 0) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + delete_texture(&fbo->texture); + } +} + +static void +delete_program(struct shader_program *program) +{ + if (program->vertex_shader) + glw.glDeleteShader(program->vertex_shader); + if (program->fragment_shader) + glw.glDeleteShader(program->fragment_shader); + glw.glDeleteProgram(program->id); +} + +static void +delete_vbo(struct shader_vbo *vbo) +{ + if (vbo->color >= 0) + glw.glDeleteBuffers(1, (GLuint *) &vbo->color); + glw.glDeleteBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glDeleteBuffers(1, (GLuint *) &vbo->tex_coord); +} + +static void +delete_pass(struct shader_pass *pass) +{ + delete_fbo(&pass->fbo); + delete_vbo(&pass->vbo); + delete_program(&pass->program); + glw.glDeleteVertexArrays(1, (GLuint *) &pass->vertex_array); +} + +static void +delete_prev(struct shader_prev *prev) +{ + delete_fbo(&prev->fbo); + delete_vbo(&prev->vbo); +} + +static void +delete_shader(struct glsl_shader *glsl) +{ + int i; + for (i = 0; i < glsl->num_passes; ++i) + delete_pass(&glsl->passes[i]); + if (glsl->has_prev) { + delete_pass(&glsl->prev_scene); + for (i = 0; i < MAX_PREV; ++i) + delete_prev(&glsl->prev[i]); + } + for (i = 0; i < glsl->num_lut_textures; ++i) + delete_texture(&glsl->lut_textures[i].texture); +} + +static void +delete_glsl(glsl_t *glsl) +{ + int i; + for (i = 0; i < glsl->num_shaders; ++i) + delete_shader(&glsl->shaders[i]); + delete_pass(&glsl->scene); + delete_pass(&glsl->fs_color); + delete_pass(&glsl->final_pass); +#ifdef SDL2_SHADER_DEBUG + delete_pass(&glsl->debug); +#endif +} + +static void +create_fbo(struct shader_fbo *fbo) +{ + create_texture(&fbo->texture); + + glw.glGenFramebuffers(1, (GLuint *) &fbo->id); + glw.glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + glw.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->texture.id, 0); + + if (glw.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + pclog("Could not create framebuffer!\n"); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +static void +setup_fbo(struct shader *shader, struct shader_fbo *fbo) +{ + fbo->texture.internal_format = GL_RGBA8; + fbo->texture.format = GL_RGBA; + fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; + fbo->texture.width = 1024; + fbo->texture.height = 1024; + fbo->texture.type = GL_UNSIGNED_BYTE; + if (!strcmp(shader->wrap_mode, "repeat")) + fbo->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(shader->wrap_mode, "mirrored_repeat")) + fbo->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(shader->wrap_mode, "clamp_to_edge")) + fbo->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + fbo->texture.wrap_mode = GL_CLAMP_TO_BORDER; + fbo->srgb = 0; + if (shader->srgb_framebuffer) { + fbo->texture.internal_format = GL_SRGB8_ALPHA8; + fbo->srgb = 1; + } else if (shader->float_framebuffer) { + fbo->texture.internal_format = GL_RGBA32F; + fbo->texture.type = GL_FLOAT; + } + + if (fbo->texture.mipmap) + fbo->texture.min_filter = shader->filter_linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_fbo(fbo); +} + +static void +recreate_fbo(struct shader_fbo *fbo, int width, int height) +{ + if (width != fbo->texture.width || height != fbo->texture.height) { + glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); + glw.glDeleteTextures(1, (GLuint *) &fbo->texture.id); + fbo->texture.width = width; + fbo->texture.height = height; + create_fbo(fbo); + } +} + +static int +create_default_shader_tex(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->texture = get_uniform(p, "Texture"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +static int +create_default_shader_color(struct shader_pass *pass) +{ + if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) + return 0; + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + + struct shader_uniforms *u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->color = get_attrib(p, "Color"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +/* create the default scene shader */ +static void +create_scene_shader() +{ + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_tex(&active_shader->scene); + scene_shader_conf.filter_linear = video_filter_method; + if (active_shader->num_shaders > 0 && active_shader->shaders[0].input_filter_linear >= 0) + scene_shader_conf.filter_linear = active_shader->shaders[0].input_filter_linear; + setup_fbo(&scene_shader_conf, &active_shader->scene.fbo); + + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_color(&active_shader->fs_color); + setup_fbo(&scene_shader_conf, &active_shader->fs_color.fbo); +} + +static int +load_texture(const char *f, struct shader_texture *tex) +{ + QImage img; + if (!img.load(f)) + return 0; + int width, height; + width = img.size().width(); + height = img.size().height(); + + if (width != next_pow2(width) || height != next_pow2(height)) + img = img.scaled(next_pow2(width), next_pow2(height)); + + width = img.size().width(); + height = img.size().height(); + + img.convertTo(QImage::Format_RGBA8888); + + const GLubyte *rgb = img.constBits(); + + int bpp = 4; + + GLubyte *data = (GLubyte *) malloc(width * height * bpp); + + int x, y, Y; + for (y = 0; y < height; ++y) { + Y = height - y - 1; + for (x = 0; x < width; x++) { + data[(y * width + x) * bpp + 0] = rgb[(Y * width + x) * 3 + 0]; + data[(y * width + x) * bpp + 1] = rgb[(Y * width + x) * 3 + 1]; + data[(y * width + x) * bpp + 2] = rgb[(Y * width + x) * 3 + 2]; + data[(y * width + x) * bpp + 3] = rgb[(Y * width + x) * 3 + 3]; + } + } + + tex->width = width; + tex->height = height; + tex->internal_format = GL_RGBA8; + tex->format = GL_RGBA; + tex->type = GL_UNSIGNED_BYTE; + tex->data = data; + return 1; +} + +static glsl_t * +load_glslp(glsl_t *glsl, int num_shader, const char *f) +{ + int i, j; + glslp_t *p = glslp_parse(f); + + if (p) { + char path[512]; + char file[1024]; + int failed = 0; + strcpy(path, f); + char *filename = path_get_filename(path); + + struct glsl_shader *gshader = &glsl->shaders[num_shader]; + + strcpy(gshader->name, p->name); + *filename = 0; + + gshader->num_lut_textures = p->num_textures; + + for (i = 0; i < p->num_textures; ++i) { + struct texture *texture = &p->textures[i]; + + sprintf(file, "%s%s", path, texture->path); + + struct shader_lut_texture *tex = &gshader->lut_textures[i]; + strcpy(tex->name, texture->name); + + pclog("Load texture %s...\n", file); + + if (!load_texture(file, &tex->texture)) { + // wx_simple_messagebox("GLSL Error", "Could not load texture: %s", file); + pclog("Could not load texture %s!\n", file); + failed = 1; + break; + } + + if (!strcmp(texture->wrap_mode, "repeat")) + tex->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(texture->wrap_mode, "mirrored_repeat")) + tex->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(texture->wrap_mode, "clamp_to_edge")) + tex->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + tex->texture.wrap_mode = GL_CLAMP_TO_BORDER; + + tex->texture.mipmap = texture->mipmap; + + tex->texture.min_filter = tex->texture.mag_filter = texture->linear ? GL_LINEAR : GL_NEAREST; + if (tex->texture.mipmap) + tex->texture.min_filter = texture->linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_texture(&tex->texture); + free(tex->texture.data); + tex->texture.data = 0; + } + + if (!failed) { + gshader->input_filter_linear = p->input_filter_linear; + + gshader->num_parameters = p->num_parameters; + for (j = 0; j < gshader->num_parameters; ++j) + memcpy(&gshader->parameters[j], &p->parameters[j], sizeof(struct shader_parameter)); + + gshader->num_passes = p->num_shaders; + + for (i = 0; i < p->num_shaders; ++i) { + struct shader *shader = &p->shaders[i]; + struct shader_pass *pass = &gshader->passes[i]; + + strcpy(pass->alias, shader->alias); + if (!strlen(pass->alias)) + sprintf(pass->alias, "Pass %u", (i + 1)); + + pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); + pclog("Loading shader %s...\n", shader->shader_fn); + if (!shader->shader_program) { + // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); + pclog("Could not load shader %s\n", shader->shader_fn); + failed = 1; + break; + } else + pclog("Shader %s loaded\n", shader->shader_fn); + failed = !compile_shader(GL_VERTEX_SHADER, "#define VERTEX\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.vertex_shader) + || !compile_shader(GL_FRAGMENT_SHADER, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", + shader->shader_program, &pass->program.fragment_shader); + if (failed) + break; + + if (!create_program(&pass->program)) { + failed = 1; + break; + } + pass->frame_count_mod = shader->frame_count_mod; + pass->fbo.mipmap_input = shader->mipmap_input; + + glw.glGenVertexArrays(1, (GLuint *) &pass->vertex_array); + find_uniforms(gshader, i); + setup_scale(shader, pass); + if (i == p->num_shaders - 1) /* last pass may or may not be an fbo depending on scale */ + { + if (num_shader == glsl->num_shaders - 1) { + pass->fbo.id = -1; + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] != SCALE_SOURCE || pass->scale.value[j] != 1) { + setup_fbo(shader, &pass->fbo); + break; + } + } + } else { + /* check if next shaders' first pass wants the input mipmapped (will this ever + * happen?) */ + pass->fbo.texture.mipmap = glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].passes[0].fbo.mipmap_input; + /* check if next shader wants the output of this pass to be filtered */ + if (glsl->shaders[num_shader + 1].num_passes > 0 && glsl->shaders[num_shader + 1].input_filter_linear >= 0) + shader->filter_linear = glsl->shaders[num_shader + 1].input_filter_linear; + setup_fbo(shader, &pass->fbo); + } + } else { + /* check if next pass wants the input mipmapped, if so we need to generate mipmaps of this + * pass */ + pass->fbo.texture.mipmap = (i + 1) < p->num_shaders && p->shaders[i + 1].mipmap_input; + setup_fbo(shader, &pass->fbo); + } + if (pass->fbo.srgb) + glsl->srgb = 1; + pass->active = 1; + } + if (!failed) { + if (gshader->has_prev) { + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + for (i = 0; i < MAX_PREV; ++i) { + setup_fbo(&scene_shader_conf, &gshader->prev[i].fbo); + } + } + } + } + + glslp_free(p); + + return glsl; + } + return 0; +} + +static glsl_t * +load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +{ + int i; + glsl_t *glsl; + + glsl = (glsl_t *) malloc(sizeof(glsl_t)); + memset(glsl, 0, sizeof(glsl_t)); + + glsl->num_shaders = num; + int failed = 0; + for (i = num - 1; i >= 0; --i) { + const char *f = shaders[i]; + if (f && strlen(f)) { + if (!load_glslp(glsl, i, f)) { + failed = 1; + break; + } + } + } + if (failed) { + delete_glsl(glsl); + memset(glsl, 0, sizeof(glsl_t)); + } + return glsl; +} + +static void +read_shader_config() +{ + char s[512]; + int i, j; + for (i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + // shader->shader_refresh_rate = config_get_float(CFG_MACHINE, s, "shader_refresh_rate", -1); + for (j = 0; j < shader->num_parameters; ++j) { + struct shader_parameter *param = &shader->parameters[j]; + param->value = config_get_double(s, param->id, param->default_value); + } + } +} + +OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) + : QWindow(parent->windowHandle()) + , renderTimer(new QTimer(this)) + , options(nullptr) +{ + connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); + imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + imagebufs[1] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); + + buf_usage = std::vector(2); + buf_usage[0].clear(); + buf_usage[1].clear(); + + QSurfaceFormat format; + + setSurfaceType(QWindow::OpenGLSurface); + +#ifdef Q_OS_MACOS + format.setVersion(4, 1); +#else + format.setVersion(3, 2); +#endif + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + format.setRenderableType(QSurfaceFormat::OpenGLES); + + setFormat(format); + + parentWidget = parent; + + source.setRect(0, 0, 2048, 2048); + isInitialized = false; + isFinalized = false; +} + +OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); } + +void +OpenGLRendererPCem::initialize() +{ + try { + context = new QOpenGLContext(this); + + context->setFormat(format()); + + if (!context->create()) + throw opengl_init_error_pcem(tr("Couldn't create OpenGL context.")); + + if (!context->makeCurrent(this)) + throw opengl_init_error_pcem(tr("Couldn't switch to OpenGL context.")); + + auto version = context->format().version(); + + if (version.first < 3) + throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + + glw.initializeOpenGLFunctions(); + + QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + + logger->initialize(); // initializes in the current context, i.e. ctx + connect(logger, QOpenGLDebugLogger::messageLogged, [this] (const QOpenGLDebugMessage &message) { + qDebug() << message; + //fprintf(stderr, "OpenGL DBG: %s\n", message.message().toUtf8()); + }); + logger->enableMessages(); + logger->startLogging(); + + glw.glEnable(GL_TEXTURE_2D); + + renderTimer->start(75); + + scene_texture.data = NULL; + scene_texture.width = 2048; + scene_texture.height = 2048; + scene_texture.internal_format = GL_RGBA8; + scene_texture.format = GL_BGRA; + scene_texture.type = GL_UNSIGNED_INT_8_8_8_8_REV; + scene_texture.wrap_mode = GL_CLAMP_TO_BORDER; + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + scene_texture.mipmap = 0; + + create_texture(&scene_texture); + + /* load shader */ + // const char* shaders[1]; + // shaders[0] = gl3_shader_file; + // + // active_shader = load_shaders(1, shaders); + + // const char* shaders[3]; + // shaders[0] = "/home/phantasy/git/glsl-shaders/ntsc/ntsc-320px.glslp"; + // shaders[1] = "/home/phantasy/git/glsl-shaders/motionblur/motionblur-simple.glslp"; + // shaders[2] = "/home/phantasy/git/glsl-shaders/crt/crt-lottes-multipass.glslp"; + // + // active_shader = load_shaders(3, shaders); + int num_shaders = 0; + for (int i = 0; i < MAX_USER_SHADERS; ++i) { + if (strlen(gl3_shader_file[i])) + ++num_shaders; + else + break; + } + active_shader = load_shaders(num_shaders, gl3_shader_file); + + create_scene_shader(); + + /* read config */ + read_shader_config(); + + /* buffers */ + + GLfloat vertex[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }; + + GLfloat inv_vertex[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; + + GLfloat tex_coords[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; + + GLfloat colors[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + + /* set the scene shader buffers */ + { + glw.glBindVertexArray(active_shader->scene.vertex_array); + + struct shader_vbo *vbo = &active_shader->scene.vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(inv_vertex), inv_vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(active_shader->scene.uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + /* set buffers for all passes */ + for (int j = 0; j < active_shader->num_shaders; ++j) { + struct glsl_shader *shader = &active_shader->shaders[j]; + for (int i = 0; i < shader->num_passes; ++i) { + struct shader_uniforms *u = &shader->passes[i].uniforms; + + glw.glBindVertexArray(shader->passes[i].vertex_array); + + struct shader_vbo *vbo = &shader->passes[i].vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glVertexAttribPointer(u->vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(u->tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + if (u->color) { + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); + glw.glVertexAttribPointer(u->color, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } + } + } + + for (int i = 0; i < active_shader->num_shaders; ++i) { + struct glsl_shader *shader = &active_shader->shaders[i]; + if (shader->has_prev) { + struct shader_pass *prev_pass = &shader->prev_scene; + create_default_shader_tex(prev_pass); + + struct shader_vbo *vbo = &prev_pass->vbo; + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(prev_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + for (int j = 0; j < MAX_PREV; ++j) { + struct shader_prev *prev = &shader->prev[j]; + struct shader_vbo *prev_vbo = &prev->vbo; + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw.glGenBuffers(1, (GLuint *) &prev_vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + } + } + } + + /* create final pass */ + if (active_shader->num_shaders == 0 || active_shader->shaders[active_shader->num_shaders - 1].passes[active_shader->shaders[active_shader->num_shaders - 1].num_passes - 1].fbo.id >= 0) { + struct shader_pass *final_pass = &active_shader->final_pass; + create_default_shader_tex(final_pass); + + glw.glBindVertexArray(final_pass->vertex_array); + + struct shader_vbo *vbo = &final_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(final_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + } + + { + struct shader_pass *color_pass = &active_shader->fs_color; + create_default_shader_color(color_pass); + + glw.glBindVertexArray(color_pass->vertex_array); + + struct shader_vbo *vbo = &color_pass->vbo; + + glw.glGenBuffers(1, (GLuint *) &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), + (GLvoid *) 0); + + glw.glGenBuffers(1, (GLuint *) &vbo->color); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(color_pass->uniforms.color, 4, GL_FLOAT, GL_TRUE, 4 * sizeof(GLfloat), (GLvoid *) 0); + } +#ifdef SDL2_SHADER_DEBUG + struct shader_pass *debug_pass = &active_shader->debug; + create_default_shader(debug_pass); + + glw.glBindVertexArray(debug_pass->vertex_array); + + struct shader_vbo *vbo = &debug_pass->vbo; + + glw.glGenBuffers(1, &vbo->vertex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid *) 0); + + glw.glGenBuffers(1, &vbo->tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw.glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw.glVertexAttribPointer(debug_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(GLfloat), (GLvoid *) 0); +#endif + + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + glw.glBindVertexArray(0); + + isInitialized = true; + isFinalized = false; + + emit initialized(); + + glw.glClearColor(0, 0, 0, 1); + + glw.glClear(GL_COLOR_BUFFER_BIT); + + context->swapBuffers(this); + } catch (const opengl_init_error_pcem &e) { + /* Mark all buffers as in use */ + for (auto &flag : buf_usage) + flag.test_and_set(); + + QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + + context->doneCurrent(); + isFinalized = true; + isInitialized = true; + + emit errorInitializing(); + } +} + +void +OpenGLRendererPCem::finalize() +{ + if (isFinalized) + return; + + context->makeCurrent(this); + + delete_texture(&scene_texture); + + if (active_shader) { + delete_glsl(active_shader); + free(active_shader); + } + active_shader = NULL; + + context->doneCurrent(); + + context = nullptr; + + isFinalized = true; +} + +void +OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) +{ + if (notReady()) + return; + + context->makeCurrent(this); + +#ifdef Q_OS_MACOS + glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +#endif + source.setRect(x, y, w, h); + + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 2048); + glw.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); + glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + buf_usage[buf_idx].clear(); + source.setRect(x, y, w, h); + onResize(this->width(), this->height()); + + render(); +} + +std::vector> +OpenGLRendererPCem::getBuffers() +{ + std::vector> buffers; + + buffers.push_back(std::make_tuple(imagebufs[0].get(), &buf_usage[0])); + buffers.push_back(std::make_tuple(imagebufs[1].get(), &buf_usage[1])); + + return buffers; +} + +void +OpenGLRendererPCem::exposeEvent(QExposeEvent *event) +{ + Q_UNUSED(event); + + if (!isInitialized) + initialize(); + + onResize(size().width(), size().height()); +} + +void +OpenGLRendererPCem::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + + onResize(event->size().width(), event->size().height()); + + if (notReady()) + return; + + context->makeCurrent(this); + + glw.glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +} + +struct render_data { + int pass; + struct glsl_shader *shader; + struct shader_pass *shader_pass; + GLfloat *output_size; + struct shader_pass *orig_pass; + GLint texture; + int frame_count; +}; + +static void +render_pass(struct render_data *data) +{ + int i; + GLuint texture_unit = 0; + + // pclog("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], + // pass->state.input_size[1], pass->state.input_texture_size[0], pass->state.input_texture_size[1], + // pass->state.output_size[0], pass->state.output_size[1], pass->state.output_texture_size[0], + // pass->state.output_texture_size[1], output_size[0], output_size[1]); + + glw.glBindVertexArray(data->shader_pass->vertex_array); + + GLint p = data->shader_pass->program.id; + struct shader_uniforms *u = &data->shader_pass->uniforms; + + glw.glUseProgram(p); + + if (data->texture) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->texture); + glw.glUniform1i(u->texture, texture_unit); + texture_unit++; + } + + if (u->color >= 0) + glw.glEnableVertexAttribArray(u->color); + + if (u->mvp_matrix >= 0) + glw.glUniformMatrix4fv(u->mvp_matrix, 1, 0, matrix); + if (u->frame_direction >= 0) + glw.glUniform1i(u->frame_direction, 1); + + int framecnt = data->frame_count; + if (data->shader_pass->frame_count_mod > 0) + framecnt = framecnt % data->shader_pass->frame_count_mod; + if (u->frame_count >= 0) + glw.glUniform1i(u->frame_count, framecnt); + + if (u->input_size >= 0) + glw.glUniform2fv(u->input_size, 1, data->shader_pass->state.input_size); + if (u->texture_size >= 0) + glw.glUniform2fv(u->texture_size, 1, data->shader_pass->state.input_texture_size); + if (u->output_size >= 0) + glw.glUniform2fv(u->output_size, 1, data->output_size); + + if (data->shader) { + /* parameters */ + for (i = 0; i < data->shader->num_parameters; ++i) + if (u->parameters[i] >= 0) + glw.glUniform1f(u->parameters[i], data->shader->parameters[i].value); + + if (data->pass > 0) { + struct shader_pass *passes = data->shader->passes; + struct shader_pass *orig = data->orig_pass; + if (u->orig.texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, orig->fbo.texture.id); + glw.glUniform1i(u->orig.texture, texture_unit); + texture_unit++; + } + if (u->orig.input_size >= 0) + glw.glUniform2fv(u->orig.input_size, 1, orig->state.input_size); + if (u->orig.texture_size >= 0) + glw.glUniform2fv(u->orig.texture_size, 1, orig->state.input_texture_size); + + for (i = 0; i < data->pass; ++i) { + if (u->pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->pass[i].texture, texture_unit); + texture_unit++; + } + if (u->pass[i].texture_size >= 0) + glw.glUniform2fv(u->pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->pass[i].input_size >= 0) + glw.glUniform2fv(u->pass[i].input_size, 1, passes[i].state.input_size); + + if (u->prev_pass[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw.glUniform1i(u->prev_pass[i].texture, texture_unit); + texture_unit++; + } + if (u->prev_pass[i].texture_size >= 0) + glw.glUniform2fv(u->prev_pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->prev_pass[i].input_size >= 0) + glw.glUniform2fv(u->prev_pass[i].input_size, 1, passes[i].state.input_size); + } + } + + if (data->shader->has_prev) { + /* loop through each previous frame */ + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].texture >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->prev[i].fbo.texture.id); + glw.glUniform1i(u->prev[i].texture, texture_unit); + texture_unit++; + } + if (u->prev[i].tex_coord >= 0) { + glw.glBindBuffer(GL_ARRAY_BUFFER, data->shader->prev[i].vbo.tex_coord); + glw.glVertexAttribPointer(u->prev[i].tex_coord, 2, GL_FLOAT, GL_TRUE, + 2 * sizeof(GLfloat), (GLvoid *) 0); + glw.glEnableVertexAttribArray(u->prev[i].tex_coord); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + } + + for (i = 0; i < data->shader->num_lut_textures; ++i) { + if (u->lut_textures[i] >= 0) { + glw.glActiveTexture(GL_TEXTURE0 + texture_unit); + glw.glBindTexture(GL_TEXTURE_2D, data->shader->lut_textures[i].texture.id); + glw.glUniform1i(u->lut_textures[i], texture_unit); + texture_unit++; + } + } + } + + glw.glEnableVertexAttribArray(u->vertex_coord); + glw.glEnableVertexAttribArray(u->tex_coord); + + glw.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, 0); + + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.vertex_coord); + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.tex_coord); + if (data->shader_pass->uniforms.color >= 0) + glw.glDisableVertexAttribArray(data->shader_pass->uniforms.color); + + if (data->shader && data->shader->has_prev) { + for (i = 0; i < MAX_PREV; ++i) { + if (u->prev[i].tex_coord >= 0) + glw.glDisableVertexAttribArray(u->prev[i].tex_coord); + } + } + + glw.glBindVertexArray(0); + + glw.glUseProgram(0); +} + +bool +OpenGLRendererPCem::event(QEvent *event) +{ + Q_UNUSED(event); + + bool res = false; + if (!eventDelegate(event, res)) + return QWindow::event(event); + return res; +} + +void +OpenGLRendererPCem::render() +{ + if (!context) + return; + + int s, i, j; + + struct { + uint32_t x, y, w, h; + } window_rect; + + window_rect.w = this->size().width() * devicePixelRatio(); + window_rect.h = this->size().height() * devicePixelRatio(); + + GLfloat orig_output_size[] = { (GLfloat)window_rect.w, (GLfloat)window_rect.h }; + + if (active_shader->srgb) + glw.glEnable(GL_FRAMEBUFFER_SRGB); + + struct render_data data; + + /* render scene to texture */ + { + struct shader_pass *pass = &active_shader->scene; + + struct { + uint32_t x, y, w, h; + } rect, video_rect; + rect.x = destination.x(); + rect.y = destination.y(); + rect.w = destination.width(); + rect.h = destination.height(); + + video_rect.x = source.x(); + video_rect.y = source.y(); + video_rect.w = source.width(); + video_rect.h = source.height(); + + pass->state.input_size[0] = pass->state.output_size[0] = rect.w; + pass->state.input_size[1] = pass->state.output_size[1] = rect.h; + + pass->state.input_texture_size[0] = pass->state.output_texture_size[0] = next_pow2(pass->state.output_size[0]); + pass->state.input_texture_size[1] = pass->state.output_texture_size[1] = next_pow2(pass->state.output_size[1]); + + recreate_fbo(&active_shader->scene.fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, active_shader->scene.fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + // create input tex coords + minx = video_rect.x / 2048.f; + miny = video_rect.y / 2048.f; + maxx = (video_rect.x + video_rect.w) / (float) 2048.f; + maxy = (video_rect.y + video_rect.h) / (float) 2048.f; + + GLfloat tex_coords[] = { minx, miny, minx, maxy, maxx, miny, maxx, maxy }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -1; + data.shader_pass = &active_shader->scene; + data.texture = scene_texture.id; + data.output_size = orig_output_size; + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + struct shader_pass *orig = &active_shader->scene; + struct shader_pass *input = &active_shader->scene; + + for (s = 0; s < active_shader->num_shaders; ++s) { + struct glsl_shader *shader = &active_shader->shaders[s]; + + // float refresh_rate = shader->shader_refresh_rate; + // if (refresh_rate < 0) + // refresh_rate = gl3_shader_refresh_rate; + float refresh_rate = gl3_shader_refresh_rate; + if (refresh_rate == 0) + refresh_rate = video_refresh_rate; + int frame_count = frameCounter; + + /* loop through each pass */ + for (i = 0; i < shader->num_passes; ++i) { + struct shader_pass *pass = &shader->passes[i]; + + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + if (pass->fbo.id >= 0) { + recreate_fbo(&pass->fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id); + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + } else + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = i; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + data.frame_count = frame_count; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (pass->fbo.texture.mipmap) { + glw.glActiveTexture(GL_TEXTURE0); + glw.glBindTexture(GL_TEXTURE_2D, pass->fbo.texture.id); + glw.glGenerateMipmap(GL_TEXTURE_2D); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + + input = pass; + } + + if (shader->has_prev) { + /* shift array */ + memmove(&shader->prev[1], &shader->prev[0], MAX_PREV * sizeof(struct shader_prev)); + memcpy(&shader->prev[0], &shader->prev[MAX_PREV], sizeof(struct shader_prev)); + + struct shader_pass *pass = orig; + struct shader_pass *prev_pass = &shader->prev_scene; + struct shader_prev *prev = &shader->prev[0]; + + memcpy(&prev_pass->state, &pass->state, sizeof(struct shader_state)); + + recreate_fbo(&prev->fbo, prev_pass->state.output_texture_size[0], + prev_pass->state.output_texture_size[1]); + + memcpy(&prev_pass->fbo, &prev->fbo, sizeof(struct shader_fbo)); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, prev->fbo.id); + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + glw.glBindVertexArray(prev_pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + glw.glBindBuffer(GL_ARRAY_BUFFER, prev_pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), pass->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = -10; + data.shader_pass = prev_pass; + data.texture = pass->fbo.texture.id; + data.output_size = orig_output_size; + + render_pass(&data); + + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + orig = input; + } + + if (active_shader->final_pass.active) { + struct shader_pass *pass = &active_shader->final_pass; + + memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2 * sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j] * pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j] * pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glw.glClearColor(0, 0, 0, 1); + glw.glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0] / (GLfloat) pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1] / (GLfloat) pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(GLfloat), input->state.tex_coords); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -2; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + + render_pass(&data); + } + + if (1) { + // if (video_focus_dim && !(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)) { +#if 0 + if (0) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = 0; + GLfloat g = 0; + GLfloat b = 0; + GLfloat a = 0x80 / (float) 0xff; + + GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } + + if (flash.enabled) { + struct shader_pass *pass = &active_shader->fs_color; + GLfloat r = (flash.color[0] & 0xff) / (float)0xff; + GLfloat g = (flash.color[1] & 0xff) / (float)0xff; + GLfloat b = (flash.color[2] & 0xff) / (float)0xff; + GLfloat a = (flash.color[3] & 0xff) / (float)0xff; + + GLfloat colors[] = {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}; + + glw.glBindVertexArray(pass->vertex_array); + + glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); + glw.glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } +#endif + } else { +#if 0 + take_screenshot = 0; + + int width = window_rect.w; + int height = window_rect.h; + + SDL_GetWindowSize(window, &width, &height); + + unsigned char *rgba = (unsigned char *)malloc(width * height * 4); + + glFinish(); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + + int x, y; + unsigned char *rgb = (unsigned char *)malloc(width * height * 3); + + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + rgb[(y * width + x) * 3 + 0] = rgba[((height - y - 1) * width + x) * 4 + 0]; + rgb[(y * width + x) * 3 + 1] = rgba[((height - y - 1) * width + x) * 4 + 1]; + rgb[(y * width + x) * 3 + 2] = rgba[((height - y - 1) * width + x) * 4 + 2]; + } + } + + screenshot_taken(rgb, width, height); + + free(rgb); + free(rgba); +#endif + } + + glw.glDisable(GL_FRAMEBUFFER_SRGB); + + context->swapBuffers(this); +} \ No newline at end of file diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp new file mode 100644 index 000000000..0e3069536 --- /dev/null +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -0,0 +1,127 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header file for OpenGL renderer + * + * + * + * Authors: Teemu Korhonen + * + * Copyright 2022 Teemu Korhonen + */ + +#ifndef QT_OpenGLRendererPCem_HPP +#define QT_OpenGLRendererPCem_HPP + +#if defined Q_OS_MACOS || __arm__ +# define NO_BUFFER_STORAGE +#endif + +#include +#include +#include +#include +#include +#include +#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include +#endif + +#include +#include +#include +#include + +#include "qt_opengloptions.hpp" +#include "qt_renderercommon.hpp" + +typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); + +class OpenGLRendererPCem : public QWindow, public RendererCommon { + Q_OBJECT + +public: + QOpenGLContext *context; + + OpenGLRendererPCem(QWidget *parent = nullptr); + ~OpenGLRendererPCem(); + + std::vector> getBuffers() override; + + void finalize() override final; + //bool hasOptions() const override { return true; } + //QDialog *getOptions(QWidget *parent) override; + //void reloadOptions() override; + +signals: + void initialized(); + void errorInitializing(); + +public slots: + void onBlit(int buf_idx, int x, int y, int w, int h); + +protected: + void exposeEvent(QExposeEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + bool event(QEvent *event) override; + +private: + static constexpr int INIT_WIDTH = 640; + static constexpr int INIT_HEIGHT = 400; + static constexpr int ROW_LENGTH = 2048; + static constexpr int BUFFERPIXELS = 4194304; + static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ + static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ + + std::array, 2> imagebufs; + + QTimer *renderTimer; + OpenGLOptions *options; + + QString glslVersion; + + bool isInitialized = false; + bool isFinalized = false; + + GLuint unpackBufferID = 0; + GLuint vertexArrayID = 0; + GLuint vertexBufferID = 0; + GLuint textureID = 0; + int frameCounter = 0; + + OpenGLOptions::FilterType currentFilter; + + void *unpackBuffer = nullptr; + + void initialize(); + void initializeExtensions(); + void initializeBuffers(); + void applyOptions(); + void applyShader(const OpenGLShaderPass &shader); + bool notReady() const { return !isInitialized || isFinalized; } + + /* GL_ARB_buffer_storage */ + bool hasBufferStorage = false; +#ifndef NO_BUFFER_STORAGE + PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; +#endif + +private slots: + void render(); + //void updateOptions(OpenGLOptions *newOptions); +}; + +class opengl_init_error_pcem : public std::runtime_error { +public: + opengl_init_error_pcem(const QString &what) + : std::runtime_error(what.toStdString()) + { + } +}; + +#endif diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 8c31da2b2..63d35e719 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -23,6 +23,7 @@ #include "qt_hardwarerenderer.hpp" #include "qt_openglrenderer.hpp" +#include "qt_openglrenderer_pcem.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" @@ -337,19 +338,39 @@ RendererStack::createRenderer(Renderer renderer) current.reset(this->createWindowContainer(hw, this)); break; } - case Renderer::OpenGL3: + case Renderer::OpenGL3PCem: { this->createWinId(); - auto hw = new OpenGLRenderer(this); + auto hw = new OpenGLRendererPCem(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRenderer::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRendererPCem::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRenderer::errorInitializing, [=]() { + connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + /* Renderer not could initialize, fallback to software. */ + imagebufs = {}; + QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); + }); + current.reset(this->createWindowContainer(hw, this)); + break; + } + case Renderer::OpenGL3: + { + this->createWinId(); + auto hw = new OpenGLRendererPCem(this); + rendererWindow = hw; + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRendererPCem::initialized, [=]() { + /* Buffers are available only after initialization. */ + imagebufs = rendererWindow->getBuffers(); + endblit(); + emit rendererChanged(); + }); + connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); @@ -406,7 +427,7 @@ RendererStack::createRenderer(Renderer renderer) currentBuf = 0; - if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 5a08b351c..8059d59c5 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -59,6 +59,7 @@ public: OpenGLES, OpenGL3, Vulkan, + OpenGL3PCem = 6, None = -1 }; void switchRenderer(Renderer renderer); From 05f6940844f9fed4bc6d68cd6819ae7fb76cad8e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Mar 2025 05:47:44 +0100 Subject: [PATCH 0394/1190] Fixed ROM BASIC loading on XT 1982, fixes #5243. --- src/machine/m_xt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 9f232ac95..78d2daa13 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -366,7 +366,11 @@ machine_xt_init(const machine_t *model) fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); (void) bios_load_aux_linear(fn, 0x000f8000, 24576, 0); fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); - (void) bios_load_aux_linear(fn, 0x000f0000, 32768, 0); + /* On the real machine, the BASIC is repeated. */ + (void) bios_load_aux_linear(fn, 0x000f0000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f2000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f4000, 8192, 0); + (void) bios_load_aux_linear(fn, 0x000f6000, 8192, 0); } device_context_restore(); From 16d7bc26dcddf666f67ba0f5d12d6c8ec237a3ab Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 8 Mar 2025 10:14:58 +0500 Subject: [PATCH 0395/1190] Fix the LPT device list duplicating on every machine change --- src/qt/qt_settingsports.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index 630c843b9..cb1ab794a 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -74,22 +74,26 @@ SettingsPorts::onCurrentMachineChanged(int machineId) this->machineId = machineId; for (int i = 0; i < PARALLEL_MAX; i++) { - auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); - auto *model = cbox->model(); - int c = 0; - int selectedRow = 0; + auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); + auto *model = cbox->model(); + const auto removeRows = model->rowCount(); + int c = 0; + int selectedRow = 0; while (true) { const char *lptName = lpt_device_get_name(c); if (lptName == nullptr) { break; } - Models::AddEntry(model, tr(lptName), c); + int row = Models::AddEntry(model, tr(lptName), c); if (c == lpt_ports[i].device) { - selectedRow = c; + selectedRow = row - removeRows; } c++; } + model->removeRows(0, removeRows); + cbox->setEnabled(model->rowCount() > 0); + cbox->setCurrentIndex(-1); cbox->setCurrentIndex(selectedRow); auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); From 63c5b6003f7c9fed9d12212cde9a58808bdcc1f0 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:29:13 +0100 Subject: [PATCH 0396/1190] Spock/Tribble changes of the day (March 8th, 2025) 1. Make IRQ's more correct and per manual. 2. Only an adapter reset command should reset the SCSI devices connected to it. 3. Differentiate the two controllers by the connector bit (pos3 bit 12) in the CMD GET POS INFO SCB command. 4. Actually emulate bit 7 of pos4 in the pos writes so that selection between 16KB and 32KB rom loading is done properly. 5. Some cleanups. --- src/scsi/scsi_spock.c | 144 +++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 567879a12..c500abfbc 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -206,7 +206,6 @@ typedef struct { #define IRQ_TYPE_COMMAND_FAIL 0xc #define IRQ_TYPE_COMMAND_ERROR 0xe #define IRQ_TYPE_SW_SEQ_ERROR 0xf -#define IRQ_TYPE_RESET_COMPLETE 0x10 #ifdef ENABLE_SPOCK_LOG int spock_do_log = ENABLE_SPOCK_LOG; @@ -226,7 +225,9 @@ spock_log(const char *fmt, ...) # define spock_log(fmt, ...) #endif -static void +static void spock_reset(void *priv); + +static __inline void spock_rethink_irqs(spock_t *scsi) { int irq_pending = 0; @@ -236,7 +237,7 @@ spock_rethink_irqs(spock_t *scsi) if (scsi->irq_requests[c] != IRQ_TYPE_NONE) { /* Found IRQ */ scsi->irq_status = c | (scsi->irq_requests[c] << 4); - spock_log("Found IRQ: status = %02x\n", scsi->irq_status); + spock_log("Found IRQ: status=%02x.\n", scsi->irq_status); scsi->status |= STATUS_IRQ; irq_pending = 1; break; @@ -245,38 +246,37 @@ spock_rethink_irqs(spock_t *scsi) } else irq_pending = 1; + spock_log("spock_rethink_irqs: irqstat=%02x, ctrl=%02x, irqpend=%d.\n", scsi->irq_status, scsi->basic_ctrl, irq_pending); if (scsi->basic_ctrl & CTRL_IRQ_ENA) { if (irq_pending) { spock_log("IRQ issued\n"); - scsi->irq_inactive = 0; + scsi->status |= STATUS_IRQ; picint(1 << scsi->irq); } else { /* No IRQs pending, clear IRQ state */ spock_log("IRQ cleared\n"); - scsi->irq_status = 0; - scsi->irq_inactive = 1; - scsi->status &= ~STATUS_IRQ; picintc(1 << scsi->irq); } } else { - spock_log("IRQ disabled\n"); - picintc(1 << scsi->irq); + spock_log("IRQ disabled, pending=%d.\n", irq_pending); + if (irq_pending) + scsi->status |= STATUS_IRQ; } } -static __inline void +static void spock_set_irq(spock_t *scsi, int id, int type) { - spock_log("spock_set_irq id=%i type=%x %02x\n", id, type, scsi->irq_status); + spock_log("spock_set_irq: id=%i, type=%x, irqstat=%02x\n", id, type, scsi->irq_status); scsi->irq_requests[id] = type; if (!scsi->irq_status) /* Don't change IRQ status if one is currently being processed */ spock_rethink_irqs(scsi); } -static __inline void +static void spock_clear_irq(spock_t *scsi, int id) { - spock_log("spock_clear_irq id=%i\n", id); + spock_log("spock_clear_irq: id=%i.\n", id); scsi->irq_requests[id] = IRQ_TYPE_NONE; spock_rethink_irqs(scsi); } @@ -292,7 +292,7 @@ spock_write(uint16_t port, uint8_t val, void *priv) { spock_t *scsi = (spock_t *) priv; - spock_log("spock_writeb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_writeb: port=%04x, val=%02x.\n", CS, cpu_state.pc, port & 7, val); switch (port & 7) { case 0: @@ -308,16 +308,14 @@ spock_write(uint16_t port, uint8_t val, void *priv) case 4: /*Attention Register*/ scsi->attention_pending = val; - scsi->attention_wait = 2; + scsi->attention_wait = 2; scsi->status |= STATUS_BUSY; break; case 5: /*Basic Control Register*/ - if ((scsi->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { + if (!(scsi->basic_ctrl & CTRL_RESET) && (val & CTRL_RESET)) { spock_log("Spock: SCSI reset and busy\n"); - scsi->in_reset = 1; - scsi->cmd_timer = SPOCK_TIME * 2; - scsi->status |= STATUS_BUSY; + spock_reset(scsi); } scsi->basic_ctrl = val; spock_rethink_irqs(scsi); @@ -333,7 +331,7 @@ spock_writew(uint16_t port, uint16_t val, void *priv) { spock_t *scsi = (spock_t *) priv; - spock_log("spock_writew: port=%04x, val=%04x, %04x:%04x.\n", port & 7, val, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_writew: port=%04x, val=%04x.\n", CS, cpu_state.pc, port & 7, val); switch (port & 7) { case 0: /*Command Interface Register*/ @@ -391,7 +389,7 @@ spock_read(uint16_t port, void *priv) break; } - spock_log("spock_readb: port=%04x, val=%02x, %04x:%04x.\n", port & 7, temp, CS, cpu_state.pc); + spock_log("%04X:%08X: spock_readb: port=%04x, temp=%02x.\n", CS, cpu_state.pc, port & 7, temp); return temp; } @@ -442,9 +440,8 @@ spock_get_len(spock_t *scsi, scb_t *scb) DataToTransfer += scb->sge.sys_buf_byte_count; } return DataToTransfer; - } else { - return (scsi->data_len); } + return (scsi->data_len); } static void @@ -494,15 +491,14 @@ spock_process_imm_cmd(spock_t *scsi) spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_INVALID_412: - spock_log("Invalid 412\n"); + spock_log("Invalid 412.\n"); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_RESET: - spock_log("Reset Command, attention = %d.\n", scsi->attention & 0x0f); + spock_log("Reset command, attention=%02x.\n", scsi->attention & 0x0f); if ((scsi->attention & 0x0f) == 0x0f) { /*Adapter reset*/ - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) scsi_device_reset(&scsi_devices[scsi->bus][i]); - } for (i = 6; i > -1; i--) { if (scsi_device_present(&scsi_devices[scsi->bus][i])) { @@ -514,10 +510,21 @@ spock_process_imm_cmd(spock_t *scsi) spock_log("Adapter Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); } } + } else if ((scsi->attention & 0x0f) < 7) { /*Device reset*/ + scsi_device_reset(&scsi_devices[scsi->bus][scsi->attention & 0x0f]); - scsi->scb_state = 0; + for (i = 6; i > -1; i--) { + if (scsi_device_present(&scsi_devices[scsi->bus][i])) { + spock_log("Device Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + scsi->present[j] = i; + j++; + } else { + scsi->present[j] = 0xff; + spock_log("Device Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + } + } } - + scsi->scb_state = 0; spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; @@ -535,18 +542,10 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) int old_scb_state; if (scsi->in_reset) { - spock_log("Reset type=%d\n", scsi->in_reset); - scsi->status &= ~STATUS_BUSY; - scsi->irq_status = 0; - for (c = 0; c < SCSI_ID_MAX; c++) - spock_clear_irq(scsi, c); - - if (scsi->in_reset == 1) - scsi->basic_ctrl |= CTRL_IRQ_ENA; - - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); + scsi->irq_status = 0x0f; + spock_rethink_irqs(scsi); /*Reset device mappings*/ for (c = 0; c < 7; c++) { @@ -558,7 +557,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->in_reset = 0; - for (c = 6; c > -1; c--) { + for (c = 6; c >= 0; c--) { if (scsi_device_present(&scsi_devices[scsi->bus][c])) { spock_log("Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); scsi->present[j] = c; @@ -678,7 +677,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) get_pos_info->pos = scsi->spock_16bit ? 0x8efe : 0x8eff; get_pos_info->pos1 = scsi->pos_regs[3] | (scsi->pos_regs[2] << 8); get_pos_info->pos2 = scsi->irq | (scsi->pos_regs[4] << 8); - get_pos_info->pos3 = 1 << 12; + get_pos_info->pos3 = scsi->spock_16bit ? (1 << 12) : (0 << 12); get_pos_info->pos4 = (7 << 8) | 8; get_pos_info->pos5 = (16 << 8) | scsi->pacing; get_pos_info->pos6 = (30 << 8) | 1; @@ -965,6 +964,8 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) else sd->buffer_length = spock_get_len(scsi, scb); + scsi_device_identify(sd, scsi->temp_cdb[1] >> 5); + scsi_device_command_phase0(sd, scsi->temp_cdb); spock_log("SCSI ID %i: Current CDB[0]=%02x, LUN=%i, buffer len=%i, max len=%i, phase val=%02x, data len=%d, enable bit 10=%03x\n", scsi->cdb_id, scsi->temp_cdb[0], scsi->temp_cdb[1] >> 5, sd->buffer_length, spock_get_len(scsi, scb), sd->phase, scsi->data_len, scb->enable & 0x400); @@ -1018,8 +1019,12 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) break; case SCSI_STATE_END_PHASE: + sd = &scsi_devices[scsi->bus][scsi->cdb_id]; scsi->scsi_state = SCSI_STATE_IDLE; + if (sd->type != SCSI_NONE) + scsi_device_identify(sd, SCSI_LUN_USE_CDB); + spock_log("State to idle, cmd timer %d\n", scsi->cmd_timer); if (!scsi->cmd_timer) scsi->cmd_timer = 1; @@ -1045,7 +1050,7 @@ spock_callback(void *priv) spock_execute_cmd(scsi, scb); } - if (scsi->attention_wait && ((scsi->scb_state == 0) || (scsi->attention_pending & 0xf0) == 0xe0)) { + if (scsi->attention_wait) { scsi->attention_wait--; if (!scsi->attention_wait) { scsi->attention = scsi->attention_pending; @@ -1094,6 +1099,7 @@ spock_callback(void *priv) case 0x0e: /*EOI*/ scsi->irq_status = 0; + scsi->status &= ~STATUS_IRQ; spock_clear_irq(scsi, scsi->attention & 0x0f); break; @@ -1118,23 +1124,30 @@ spock_mca_write(int port, uint8_t val, void *priv) if (port < 0x102) return; - io_removehandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); + io_removehandler((((scsi->pos_regs[2] >> 1) & 7) << 3) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); mem_mapping_disable(&scsi->bios_rom.mapping); scsi->pos_regs[port & 7] = val; scsi->adapter_id = (scsi->pos_regs[3] & 0xe0) >> 5; - if (scsi->pos_regs[2] & 1) { - io_sethandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); - if (scsi->pos_regs[4] & 2) { - if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { - mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); - mem_mapping_enable(&scsi->bios_rom.mapping); + if (scsi->pos_regs[2] & 0x01) { + io_sethandler((((scsi->pos_regs[2] >> 1) & 7) << 3) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); + if (scsi->pos_regs[4] & 0x02) { + if (scsi->pos_regs[4] & 0x80) { + if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { + mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); + mem_mapping_enable(&scsi->bios_rom.mapping); + } + } else { + if (((scsi->pos_regs[2] >> 4) & 0x0f) != 0x0f) { + mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x4000); + mem_mapping_enable(&scsi->bios_rom.mapping); + } } } } - spock_log("[%04X:%08X]: POS Write Port = %x, val = %02x, rom addr = %05x\n", CS, cpu_state.pc, port & 7, val, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000); + spock_log("%04X:%08X: POS Write Port=%x, val=%02x.\n", CS, cpu_state.pc, port & 7, val); } static uint8_t @@ -1142,7 +1155,7 @@ spock_mca_read(int port, void *priv) { const spock_t *scsi = (spock_t *) priv; - spock_log("[%04X:%08X]: POS Read Port = %x, val = %02x\n", CS, cpu_state.pc, + spock_log("%04X:%08X: POS Read Port=%x, temp=%02x.\n", CS, cpu_state.pc, port & 7, scsi->pos_regs[port & 7]); return scsi->pos_regs[port & 7]; } @@ -1155,12 +1168,13 @@ spock_mca_feedb(void *priv) return (scsi->pos_regs[2] & 0x01); } + static void -spock_mca_reset(void *priv) +spock_reset(void *priv) { spock_t *scsi = (spock_t *) priv; - scsi->in_reset = 2; + scsi->in_reset = 1; scsi->cmd_timer = SPOCK_TIME * 50; scsi->status = STATUS_BUSY; scsi->scsi_state = SCSI_STATE_IDLE; @@ -1169,13 +1183,15 @@ spock_mca_reset(void *priv) scsi->attention_wait = 0; scsi->basic_ctrl = 0; - /* Reset all devices on controller reset. */ - for (uint8_t i = 0; i < 8; i++) { - scsi_device_reset(&scsi_devices[scsi->bus][i]); - scsi->present[i] = 0xff; - } + spock_log("Actual Reset.\n"); +} - spock_log("Reset.\n"); +static void +spock_mca_reset(void *priv) +{ + spock_t *scsi = (spock_t *) priv; + + spock_reset(scsi); mem_mapping_disable(&scsi->bios_rom.mapping); scsi->pos_regs[4] = 0x02; spock_mca_write(0x102, 0, scsi); @@ -1213,10 +1229,6 @@ spock_init(const device_t *info) scsi->pos_regs[4] = 0x02; mca_add(spock_mca_read, spock_mca_write, spock_mca_feedb, spock_mca_reset, scsi); - scsi->in_reset = 2; - scsi->cmd_timer = SPOCK_TIME * 50; - scsi->status = STATUS_BUSY; - for (uint8_t c = 0; c < (SCSI_ID_MAX - 1); c++) scsi->dev_id[c].phys_id = -1; @@ -1230,6 +1242,8 @@ spock_init(const device_t *info) scsi_bus_set_speed(scsi->bus, 5000000.0); + spock_reset(scsi); + return scsi; } @@ -1278,7 +1292,7 @@ const device_t spock_device = { .local = 0, .init = spock_init, .close = spock_close, - .reset = NULL, + .reset = spock_reset, .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, @@ -1292,7 +1306,7 @@ const device_t tribble_device = { .local = 1, .init = spock_init, .close = spock_close, - .reset = NULL, + .reset = spock_reset, .available = spock_available, .speed_changed = NULL, .force_redraw = NULL, From a2534c1f4f655c6675f1b324344aa7233900ec0b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:41:59 +0100 Subject: [PATCH 0397/1190] Trantor T128/MediaVision SCSI changes of the day (March 8th, 2025) 1. Made as best as possible implementation of the status bits 1-2 of the Trantor 128 so to make a more accurate speed for SCSI devices (CD-ROM and HDD) without stalls. 2. Slightly reorganized the timer of the T128. --- src/scsi/scsi_t128.c | 292 +++++++++++++++++++++---------------------- 1 file changed, 142 insertions(+), 150 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 5ac3b5d67..6b73ae131 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -77,11 +77,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv) if ((addr >= 0x1800) && (addr < 0x1880)) t128->ext_ram[addr & 0x7f] = val; else if ((addr >= 0x1c00) && (addr < 0x1c20)) { - if ((val & 0x02) && !(t128->ctrl & 0x02)) - t128->status |= 0x02; - + t128_log("T128 ctrl write=%02x, mode=%02x.\n", val, ncr->mode & MODE_DMA); t128->ctrl = val; - t128_log("T128 ctrl write=%02x\n", val); } else if ((addr >= 0x1d00) && (addr < 0x1e00)) ncr5380_write((addr - 0x1d00) >> 5, val, ncr); else if ((addr >= 0x1e00) && (addr < 0x2000)) { @@ -90,13 +87,15 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->buffer[t128->host_pos] = val; t128->host_pos++; - t128_log("T128 Write transfer, addr = %i, pos = %i, val = %02x\n", - addr & 0x1ff, t128->host_pos, val); + t128_log("T128 Write transfer: pos=%i, addr=%x.\n", + t128->host_pos, addr & 0x1ff); if (t128->host_pos == MIN(512, dev->buffer_length)) { + t128_log("T128 Transfer busy write, status=%02x, period=%lf, enabled=%d, loaded=%d.\n", + t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); + t128->status &= ~0x04; - t128_log("Transfer busy write, status = %02x\n", t128->status); - timer_on_auto(&t128->timer, 0.02); + timer_on_auto(&t128->timer, 1.0); } } } @@ -119,31 +118,45 @@ t128_read(uint32_t addr, void *priv) ret = t128->ext_ram[addr & 0x7f]; else if ((addr >= 0x1c00) && (addr < 0x1c20)) { ret = t128->ctrl; - t128_log("T128 ctrl read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA); + t128_log("T128 ctrl read=%02x, dma=%02x, load=%d, cnt=%d.\n", ret, ncr->mode & MODE_DMA, t128->block_loaded, t128->block_count); } else if ((addr >= 0x1c20) && (addr < 0x1c40)) { ret = t128->status; - t128_log("T128 status read=%02x, dma=%02x\n", ret, ncr->mode & MODE_DMA); + t128_log("T128 status read=%02x, dma=%02x, blockload=%d, timer=%d.\n", ret, ncr->mode & MODE_DMA, t128->block_loaded, timer_is_enabled(&t128->timer)); } else if ((addr >= 0x1d00) && (addr < 0x1e00)) ret = ncr5380_read((addr - 0x1d00) >> 5, ncr); else if (addr >= 0x1e00 && addr < 0x2000) { - if ((t128->host_pos >= MIN(512, dev->buffer_length)) || - (scsi_bus->tx_mode != DMA_IN_TX_BUS)) - ret = 0xff; - else { + if ((scsi_bus->tx_mode == DMA_IN_TX_BUS) && + (t128->host_pos < MIN(512, dev->buffer_length))) { ret = t128->buffer[t128->host_pos++]; - t128_log("T128 Read transfer, addr = %i, pos = %i\n", addr & 0x1ff, - t128->host_pos); + t128_log("T128 Read transfer: pos=%i, addr=%x.\n", + t128->host_pos, addr & 0x1ff); if (t128->host_pos == MIN(512, dev->buffer_length)) { - t128->status &= ~0x04; - t128_log("T128 Transfer busy read, status = %02x, period = %lf\n", - t128->status, scsi_bus->period); - if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02)) - timer_on_auto(&t128->timer, 40.2); - } else if ((t128->host_pos < MIN(512, dev->buffer_length)) && - (scsi_device_get_callback(dev) > 100.0)) - cycles += 100; /*Needed to avoid timer de-syncing with transfers.*/ + t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d.\n", + t128->status, scsi_bus->period, timer_is_enabled(&t128->timer)); + + if (!t128->block_loaded) { + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + t128_log("T128 read irq\n"); + ncr5380_irq(ncr, 1); + } + t128->status &= ~0x04; + scsi_bus->bus_out |= BUS_CD; + scsi_bus->tx_mode = PIO_TX_BUS; + timer_stop(&t128->timer); + } else if (!timer_is_enabled(&t128->timer)) + timer_on_auto(&t128->timer, 1.0); + else + t128->status &= ~0x04; + } + } else { + /*According to the WinNT DDK sources, just get the status timeout bit from here.*/ + if (!(t128->status & 0x02)) + t128->status |= 0x02; + + t128_log("Read not allowed.\n"); } } @@ -151,24 +164,20 @@ t128_read(uint32_t addr, void *priv) } static void -t128_dma_mode_ext(void *priv, void *ext_priv, UNUSED(uint8_t val)) +t128_dma_mode_ext(void *priv, void *ext_priv, uint8_t val) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; scsi_bus_t *scsi_bus = &ncr->scsibus; - /*Don't stop the timer until it finishes the transfer*/ - if (t128->block_loaded && (ncr->mode & MODE_DMA)) { - t128_log("Continuing DMA mode\n"); - timer_on_auto(&t128->timer, scsi_bus->period + 1.0); - } - /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!t128->block_loaded && !(ncr->mode & MODE_DMA)) { - t128_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - scsi_bus->tx_mode = PIO_TX_BUS; + if (!t128->block_loaded) { + if (!(val & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + scsi_bus->tx_mode = PIO_TX_BUS; + t128_log("End of DMA.\n"); + } } } @@ -180,9 +189,9 @@ t128_dma_send_ext(void *priv, void *ext_priv) scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; - if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { + if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { + t128_log("T128 DMA OUT, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); - t128->status |= 0x04; t128->host_pos = 0; t128->block_count = dev->buffer_length >> 9; @@ -190,6 +199,7 @@ t128_dma_send_ext(void *priv, void *ext_priv) t128->block_count = 1; t128->block_loaded = 1; + t128->status |= 0x04; } return 1; } @@ -202,9 +212,9 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; - if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { + if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { + t128_log("T128 DMA IN, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); - t128->status |= 0x04; t128->host_pos = MIN(512, dev->buffer_length); t128->block_count = dev->buffer_length >> 9; @@ -212,7 +222,8 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128->block_count = 1; t128->block_loaded = 1; - timer_on_auto(&t128->timer, 0.02); + t128->status &= ~0x04; + timer_on_auto(&t128->timer, 1.0); } return 1; } @@ -222,16 +233,16 @@ t128_timer_on_auto(void *ext_priv, double period) { t128_t *t128 = (t128_t *) ext_priv; - if (period == 0.0) + if (period <= 0.0) timer_stop(&t128->timer); - else + else if ((period > 0.0) && !timer_is_enabled(&t128->timer)) timer_on_auto(&t128->timer, period); } void t128_callback(void *priv) { - t128_t *t128 = (void *) priv; + t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; scsi_bus_t *scsi_bus = &ncr->scsibus; scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; @@ -240,128 +251,110 @@ t128_callback(void *priv) uint8_t temp; uint8_t status; - if ((scsi_bus->tx_mode != PIO_TX_BUS) && (ncr->mode & MODE_DMA) && t128->block_loaded) { - if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count) - t128->status |= 0x04; - - timer_on_auto(&t128->timer, scsi_bus->period / 55.0); - } + if (scsi_bus->tx_mode != PIO_TX_BUS) + timer_on_auto(&t128->timer, scsi_bus->period / 65.0); if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; scsi_bus->data_wait &= ~1; - if (scsi_bus->tx_mode == PIO_TX_BUS) - return; + } + + if (scsi_bus->tx_mode == PIO_TX_BUS) { + t128_log("Timer CMD=%02x.\n", scsi_bus->command[0]); + return; } switch (scsi_bus->tx_mode) { case DMA_OUT_TX_BUS: - if (!(t128->status & 0x04)) { - t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); - break; - } - - if (!t128->block_loaded) { - t128_log("Write block not loaded\n"); - break; - } - if (t128->host_pos < MIN(512, dev->buffer_length)) break; -write_again: - for (c = 0; c < 10; c++) { - status = scsi_bus_read(scsi_bus); - if (status & BUS_REQ) - break; - } - - /* Data ready. */ - temp = t128->buffer[t128->pos]; - - bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; - bus |= BUS_SETDATA(temp); - - scsi_bus_update(scsi_bus, bus | BUS_ACK); - scsi_bus_update(scsi_bus, bus & ~BUS_ACK); - - t128->pos++; - t128_log("T128 Buffer pos for writing = %d\n", t128->pos); - - if (t128->pos == MIN(512, dev->buffer_length)) { - t128->pos = 0; - t128->host_pos = 0; - t128->status &= ~0x02; - t128->block_count = (t128->block_count - 1) & 0xff; - t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); - if (!t128->block_count) { - t128->block_loaded = 0; - t128_log("IO End of write transfer\n"); - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&t128->timer); - if (ncr->mode & MODE_ENA_EOP_INT) { - t128_log("T128 write irq\n"); - ncr5380_irq(ncr, 1); - } - } + if (!t128->block_loaded) break; - } else - goto write_again; + + while (1) { + for (c = 0; c < 10; c++) { + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) + break; + } + + /* Data ready. */ + temp = t128->buffer[t128->pos]; + + bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(temp); + + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); + + t128->pos++; + t128_log("T128 Buffer pos for writing = %d\n", t128->pos); + + if (t128->pos == MIN(512, dev->buffer_length)) { + t128->status |= 0x04; + t128->status &= ~0x02; + t128->pos = 0; + t128->host_pos = 0; + t128->block_count = (t128->block_count - 1) & 0xff; + t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); + if (!t128->block_count) { + t128->block_loaded = 0; + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + t128_log("T128 write irq\n"); + ncr5380_irq(ncr, 1); + } + scsi_bus->tx_mode = PIO_TX_BUS; + timer_stop(&t128->timer); + t128_log("IO End of write transfer\n"); + } + break; + } + } break; case DMA_IN_TX_BUS: - if (!(t128->status & 0x04)) { - t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); - break; - } - - if (!t128->block_loaded) { - t128_log("Read block not loaded\n"); - break; - } - if (t128->host_pos < MIN(512, dev->buffer_length)) break; -read_again: - for (c = 0; c < 10; c++) { - status = scsi_bus_read(scsi_bus); - if (status & BUS_REQ) - break; - } - - /* Data ready. */ - bus = scsi_bus_read(scsi_bus); - temp = BUS_GETDATA(bus); - - bus = ncr5380_get_bus_host(ncr); - - scsi_bus_update(scsi_bus, bus | BUS_ACK); - scsi_bus_update(scsi_bus, bus & ~BUS_ACK); - - t128->buffer[t128->pos++] = temp; - t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length); - - if (t128->pos == MIN(512, dev->buffer_length)) { - t128->pos = 0; - t128->host_pos = 0; - t128->status &= ~0x02; - t128->block_count = (t128->block_count - 1) & 0xff; - t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]); - if (!t128->block_count) { - t128->block_loaded = 0; - t128_log("IO End of read transfer\n"); - ncr->isr |= STATUS_END_OF_DMA; - timer_stop(&t128->timer); - if (ncr->mode & MODE_ENA_EOP_INT) { - t128_log("NCR read irq\n"); - ncr5380_irq(ncr, 1); - } - } + if (!t128->block_loaded) break; - } else - goto read_again; + + while (1) { + for (c = 0; c < 10; c++) { + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) + break; + } + /* Data ready. */ + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); + + bus = ncr5380_get_bus_host(ncr); + + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); + + t128->buffer[t128->pos++] = temp; + t128_log("T128 Buffer pos for reading = %d\n", t128->pos); + + if (t128->pos == MIN(512, dev->buffer_length)) { + t128->status |= 0x04; + t128->status &= ~0x02; + t128->pos = 0; + t128->host_pos = 0; + t128->block_count = (t128->block_count - 1) & 0xff; + t128_log("T128 Remaining blocks to be read=%d\n", t128->block_count); + if (!t128->block_count) { + t128->block_loaded = 0; + scsi_bus->bus_out |= BUS_REQ; + t128_log("IO End of read transfer\n"); + } + break; + } + } break; default: @@ -374,7 +367,7 @@ read_again: t128_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; scsi_bus->tx_mode = PIO_TX_BUS; - timer_on_auto(&t128->timer, 10.0); + t128->block_loaded = 0; } } @@ -513,7 +506,7 @@ t128_init(const device_t *info) scsi_bus->bus_device = ncr->bus; scsi_bus->timer = ncr->timer; scsi_bus->priv = ncr->priv; - t128->status = 0x00 /*0x04*/; + t128->status = 0x00; t128->host_pos = 512; if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) t128->status |= 0x80; @@ -528,7 +521,6 @@ t128_init(const device_t *info) scsi_bus->speed = 0.2; scsi_bus->divider = 1.0; scsi_bus->multi = 1.0; - return t128; } From 5f833a0963a1e868b107157d75a09e7ccec77bd7 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 14:45:41 +0100 Subject: [PATCH 0398/1190] Mach32 LFB changes of the day (March 8th, 2025) Do not subtract from the linear base when it's not in the range, should fix NT 3.x graphics bugs using the LFB. --- src/video/vid_ati_mach8.c | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 6e2798295..0c8fb6691 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5223,11 +5223,11 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); } else { @@ -5238,9 +5238,9 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_write_common(addr - mach->linear_base, val, 1, mach, svga); + mach32_write_common(addr, val, 1, mach, svga); else - svga_write_linear(addr - mach->linear_base, val, svga); + svga_write_linear(addr, val, svga); } } @@ -5250,11 +5250,11 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val, mach); } else { @@ -5265,9 +5265,9 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writew_linear(addr - mach->linear_base, val, mach); + mach32_writew_linear(addr, val, mach); else - svga_writew_linear(addr - mach->linear_base, val, svga); + svga_writew_linear(addr, val, svga); } } @@ -5277,11 +5277,11 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach); mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach); @@ -5294,9 +5294,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) - mach32_writel_linear(addr - mach->linear_base, val, mach); + mach32_writel_linear(addr, val, mach); else - svga_writel_linear(addr - mach->linear_base, val, svga); + svga_writel_linear(addr, val, svga); } } @@ -5307,19 +5307,19 @@ mach32_ap_readb(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) + if (addr & 0x100) temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); else temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_read_common(addr - mach->linear_base, 1, mach, svga); + temp = mach32_read_common(addr, 1, mach, svga); else - temp = svga_read_linear(addr - mach->linear_base, svga); + temp = svga_read_linear(addr, svga); mach_log("Linear WORDB Read=%08x, ret=%02x, fast=%d.\n", addr, temp, svga->fast); } @@ -5338,15 +5338,15 @@ mach32_ap_readw(uint32_t addr, void *priv) if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) + if (addr & 0x100) temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); else temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); } else { if (dev->on) - temp = mach32_readw_linear(addr - mach->linear_base, mach); + temp = mach32_readw_linear(addr, mach); else - temp = svga_readw_linear(addr - mach->linear_base, svga); + temp = svga_readw_linear(addr, svga); mach_log("Linear WORDW Read=%08x, ret=%04x.\n", addr, temp); } @@ -5361,11 +5361,11 @@ mach32_ap_readl(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t temp; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if ((addr - mach->linear_base) & 0x100) { + if (addr & 0x100) { temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8); } else { @@ -5374,9 +5374,9 @@ mach32_ap_readl(uint32_t addr, void *priv) } } else { if (dev->on) - temp = mach32_readl_linear(addr - mach->linear_base, mach); + temp = mach32_readl_linear(addr, mach); else - temp = svga_readl_linear(addr - mach->linear_base, svga); + temp = svga_readl_linear(addr, svga); mach_log("Linear WORDL Read=%08x, ret=%08x, ON%d.\n", addr, temp, dev->on); } From a4a521b3453ed28a3c19c38a2c57f53b5a836bbd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 20:18:27 +0600 Subject: [PATCH 0399/1190] Instantiate the renderer properly --- src/qt/qt_openglrenderer_pcem.cpp | 169 ++++++++++++++---------------- src/qt/qt_openglrenderer_pcem.hpp | 71 +++++++++---- 2 files changed, 127 insertions(+), 113 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4ab66105c..8b2a25663 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -29,25 +29,14 @@ extern "C" { #include <86box/ini.h> #include <86box/config.h> #include <86box/qt-glslp-parser.h> + +char gl3_shader_file[MAX_USER_SHADERS][512]; } #define SCALE_SOURCE 0 #define SCALE_VIEWPORT 1 #define SCALE_ABSOLUTE 2 -float gl3_shader_refresh_rate = 0; -float gl3_input_scale = 1.0f; -int gl3_input_stretch = FULLSCR_SCALE_FULL; -char gl3_shader_file[MAX_USER_SHADERS][512]; - -static int max_texture_size = 65536; - -static struct shader_texture scene_texture; - -static glsl_t *active_shader; - -static QOpenGLExtraFunctions glw; - static GLfloat matrix[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; extern int video_filter_method; @@ -55,8 +44,6 @@ extern int video_vsync; extern int video_focus_dim; extern int video_refresh_rate; -static int glsl_version[2]; - const char *vertex_shader_default_tex_src = "#version 130\n" "\n" "in vec4 VertexCoord;\n" @@ -106,7 +93,7 @@ const char *fragment_shader_default_color_src = "#version 130\n" " outColor = color;\n" "}\n"; -static int +static inline int next_pow2(unsigned int n) { n--; @@ -120,8 +107,8 @@ next_pow2(unsigned int n) return n; } -static int -create_program(struct shader_program *program) +int +OpenGLRendererPCem::create_program(struct shader_program *program) { GLint status; program->id = glw.glCreateProgram(); @@ -151,8 +138,8 @@ create_program(struct shader_program *program) return 1; } -static int -compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +int +OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { const char *source[3]; char version[50]; @@ -201,20 +188,20 @@ compile_shader(GLenum shader_type, const char *prepend, const char *program, int return 1; } -static GLuint -get_uniform(GLuint program, const char *name) +GLuint +OpenGLRendererPCem::get_uniform(GLuint program, const char *name) { return glw.glGetUniformLocation(program, name); } -static GLuint -get_attrib(GLuint program, const char *name) +GLuint +OpenGLRendererPCem::get_attrib(GLuint program, const char *name) { return glw.glGetAttribLocation(program, name); } -static void -find_uniforms(struct glsl_shader *glsl, int num_pass) +void +OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass) { int i; char s[50]; @@ -298,8 +285,8 @@ setup_scale(struct shader *shader, struct shader_pass *pass) pass->scale.value[1] = shader->scale_y; } -static void -create_texture(struct shader_texture *tex) +void +OpenGLRendererPCem::create_texture(struct shader_texture *tex) { if (tex->width > max_texture_size) tex->width = max_texture_size; @@ -318,16 +305,16 @@ create_texture(struct shader_texture *tex) glw.glBindTexture(GL_TEXTURE_2D, 0); } -static void -delete_texture(struct shader_texture *tex) +void +OpenGLRendererPCem::delete_texture(struct shader_texture *tex) { if (tex->id > 0) glw.glDeleteTextures(1, (GLuint *) &tex->id); tex->id = 0; } -static void -delete_fbo(struct shader_fbo *fbo) +void +OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) { if (fbo->id >= 0) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -335,8 +322,8 @@ delete_fbo(struct shader_fbo *fbo) } } -static void -delete_program(struct shader_program *program) +void +OpenGLRendererPCem::delete_program(struct shader_program *program) { if (program->vertex_shader) glw.glDeleteShader(program->vertex_shader); @@ -345,8 +332,8 @@ delete_program(struct shader_program *program) glw.glDeleteProgram(program->id); } -static void -delete_vbo(struct shader_vbo *vbo) +void +OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) { if (vbo->color >= 0) glw.glDeleteBuffers(1, (GLuint *) &vbo->color); @@ -354,8 +341,8 @@ delete_vbo(struct shader_vbo *vbo) glw.glDeleteBuffers(1, (GLuint *) &vbo->tex_coord); } -static void -delete_pass(struct shader_pass *pass) +void +OpenGLRendererPCem::delete_pass(struct shader_pass *pass) { delete_fbo(&pass->fbo); delete_vbo(&pass->vbo); @@ -363,15 +350,15 @@ delete_pass(struct shader_pass *pass) glw.glDeleteVertexArrays(1, (GLuint *) &pass->vertex_array); } -static void -delete_prev(struct shader_prev *prev) +void +OpenGLRendererPCem::delete_prev(struct shader_prev *prev) { delete_fbo(&prev->fbo); delete_vbo(&prev->vbo); } -static void -delete_shader(struct glsl_shader *glsl) +void +OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) { int i; for (i = 0; i < glsl->num_passes; ++i) @@ -385,8 +372,8 @@ delete_shader(struct glsl_shader *glsl) delete_texture(&glsl->lut_textures[i].texture); } -static void -delete_glsl(glsl_t *glsl) +void +OpenGLRendererPCem::delete_glsl(glsl_t *glsl) { int i; for (i = 0; i < glsl->num_shaders; ++i) @@ -399,8 +386,8 @@ delete_glsl(glsl_t *glsl) #endif } -static void -create_fbo(struct shader_fbo *fbo) +void +OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) { create_texture(&fbo->texture); @@ -414,14 +401,14 @@ create_fbo(struct shader_fbo *fbo) glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); } -static void -setup_fbo(struct shader *shader, struct shader_fbo *fbo) +void +OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) { fbo->texture.internal_format = GL_RGBA8; fbo->texture.format = GL_RGBA; fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; - fbo->texture.width = 1024; - fbo->texture.height = 1024; + fbo->texture.width = 2048; + fbo->texture.height = 2048; fbo->texture.type = GL_UNSIGNED_BYTE; if (!strcmp(shader->wrap_mode, "repeat")) fbo->texture.wrap_mode = GL_REPEAT; @@ -446,8 +433,8 @@ setup_fbo(struct shader *shader, struct shader_fbo *fbo) create_fbo(fbo); } -static void -recreate_fbo(struct shader_fbo *fbo, int width, int height) +void +OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) { if (width != fbo->texture.width || height != fbo->texture.height) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -458,8 +445,8 @@ recreate_fbo(struct shader_fbo *fbo, int width, int height) } } -static int -create_default_shader_tex(struct shader_pass *pass) +int +OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -478,8 +465,8 @@ create_default_shader_tex(struct shader_pass *pass) return 1; } -static int -create_default_shader_color(struct shader_pass *pass) +int +OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -498,8 +485,8 @@ create_default_shader_color(struct shader_pass *pass) } /* create the default scene shader */ -static void -create_scene_shader() +void +OpenGLRendererPCem::create_scene_shader() { struct shader scene_shader_conf; memset(&scene_shader_conf, 0, sizeof(struct shader)); @@ -558,8 +545,8 @@ load_texture(const char *f, struct shader_texture *tex) return 1; } -static glsl_t * -load_glslp(glsl_t *glsl, int num_shader, const char *f) +glsl_t * +OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) { int i, j; glslp_t *p = glslp_parse(f); @@ -706,8 +693,8 @@ load_glslp(glsl_t *glsl, int num_shader, const char *f) return 0; } -static glsl_t * -load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +glsl_t * +OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) { int i; glsl_t *glsl; @@ -733,8 +720,8 @@ load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) return glsl; } -static void -read_shader_config() +void +OpenGLRendererPCem::read_shader_config() { char s[512]; int i, j; @@ -810,19 +797,22 @@ OpenGLRendererPCem::initialize() glw.initializeOpenGLFunctions(); - QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); + pclog("OpenGL information: [%s] %s (%s)\n", glw.glGetString(GL_VENDOR), glw.glGetString(GL_RENDERER), glw.glGetString(GL_VERSION)); + glsl_version[0] = glsl_version[1] = -1; + glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); + glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); + if (glsl_version[0] < 3) { + throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); + } + pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); + pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); - logger->initialize(); // initializes in the current context, i.e. ctx - connect(logger, QOpenGLDebugLogger::messageLogged, [this] (const QOpenGLDebugMessage &message) { - qDebug() << message; - //fprintf(stderr, "OpenGL DBG: %s\n", message.message().toUtf8()); - }); - logger->enableMessages(); - logger->startLogging(); + glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); glw.glEnable(GL_TEXTURE_2D); - renderTimer->start(75); + //renderTimer->start(75); scene_texture.data = NULL; scene_texture.width = 2048; @@ -1140,18 +1130,8 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event) destination.height() * devicePixelRatio()); } -struct render_data { - int pass; - struct glsl_shader *shader; - struct shader_pass *shader_pass; - GLfloat *output_size; - struct shader_pass *orig_pass; - GLint texture; - int frame_count; -}; - -static void -render_pass(struct render_data *data) +void +OpenGLRendererPCem::render_pass(struct render_data *data) { int i; GLuint texture_unit = 0; @@ -1318,8 +1298,16 @@ OpenGLRendererPCem::render() uint32_t x, y, w, h; } window_rect; - window_rect.w = this->size().width() * devicePixelRatio(); - window_rect.h = this->size().height() * devicePixelRatio(); + window_rect.x = destination.x() * devicePixelRatio(); + window_rect.y = destination.y() * devicePixelRatio(); + window_rect.w = destination.width() * devicePixelRatio(); + window_rect.h = destination.height() * devicePixelRatio(); + + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, 0); GLfloat orig_output_size[] = { (GLfloat)window_rect.w, (GLfloat)window_rect.h }; @@ -1403,12 +1391,6 @@ OpenGLRendererPCem::render() for (s = 0; s < active_shader->num_shaders; ++s) { struct glsl_shader *shader = &active_shader->shaders[s]; - // float refresh_rate = shader->shader_refresh_rate; - // if (refresh_rate < 0) - // refresh_rate = gl3_shader_refresh_rate; - float refresh_rate = gl3_shader_refresh_rate; - if (refresh_rate == 0) - refresh_rate = video_refresh_rate; int frame_count = frameCounter; /* loop through each pass */ @@ -1675,5 +1657,6 @@ OpenGLRendererPCem::render() glw.glDisable(GL_FRAMEBUFFER_SRGB); + frameCounter++; context->swapBuffers(this); } \ No newline at end of file diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 0e3069536..88844bb02 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -40,7 +40,20 @@ #include "qt_opengloptions.hpp" #include "qt_renderercommon.hpp" -typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} + +struct render_data { + int pass; + struct glsl_shader *shader; + struct shader_pass *shader_pass; + GLfloat *output_size; + struct shader_pass *orig_pass; + GLint texture; + int frame_count; +}; class OpenGLRendererPCem : public QWindow, public RendererCommon { Q_OBJECT @@ -71,45 +84,63 @@ protected: bool event(QEvent *event) override; private: - static constexpr int INIT_WIDTH = 640; - static constexpr int INIT_HEIGHT = 400; - static constexpr int ROW_LENGTH = 2048; - static constexpr int BUFFERPIXELS = 4194304; - static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ - static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ std::array, 2> imagebufs; QTimer *renderTimer; OpenGLOptions *options; - QString glslVersion; + QString glslVersion = ""; bool isInitialized = false; bool isFinalized = false; - GLuint unpackBufferID = 0; - GLuint vertexArrayID = 0; - GLuint vertexBufferID = 0; - GLuint textureID = 0; - int frameCounter = 0; + int max_texture_size = 65536; + int frameCounter = 0; OpenGLOptions::FilterType currentFilter; + QOpenGLExtraFunctions glw; + struct shader_texture scene_texture; + glsl_t *active_shader; void *unpackBuffer = nullptr; + int glsl_version[2] = { 0, 0 }; + void initialize(); void initializeExtensions(); void initializeBuffers(); void applyOptions(); - void applyShader(const OpenGLShaderPass &shader); - bool notReady() const { return !isInitialized || isFinalized; } + + void create_scene_shader(); + void create_texture(struct shader_texture *tex); + void create_fbo(struct shader_fbo *fbo); + void recreate_fbo(struct shader_fbo *fbo, int width, int height); + void setup_fbo(struct shader *shader, struct shader_fbo *fbo); - /* GL_ARB_buffer_storage */ - bool hasBufferStorage = false; -#ifndef NO_BUFFER_STORAGE - PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; -#endif + bool notReady() const { return !isInitialized || isFinalized; } + glsl_t* load_glslp(glsl_t *glsl, int num_shader, const char *f); + glsl_t* load_shaders(int num, char shaders[MAX_USER_SHADERS][512]); + int compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst); + int create_default_shader_tex(struct shader_pass *pass); + int create_default_shader_color(struct shader_pass *pass); + int create_program(struct shader_program *program); + + GLuint get_uniform(GLuint program, const char *name); + GLuint get_attrib(GLuint program, const char *name); + + void find_uniforms(struct glsl_shader *glsl, int num_pass); + void delete_texture(struct shader_texture *tex); + void delete_fbo(struct shader_fbo *fbo); + void delete_program(struct shader_program *program); + void delete_vbo(struct shader_vbo *vbo); + void delete_pass(struct shader_pass *pass); + void delete_prev(struct shader_prev *prev); + void delete_shader(struct glsl_shader *glsl); + void delete_glsl(glsl_t *glsl); + void read_shader_config(); + + void render_pass(struct render_data *data); private slots: void render(); From 2e46cc479c446b43ddf76ddf2d6f801c5b5ca964 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 8 Mar 2025 23:19:37 +0600 Subject: [PATCH 0400/1190] Fix Preferences dialog crash --- src/qt/qt_mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1cc6c33c9..9864584d3 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1267,6 +1267,7 @@ void MainWindow::refreshMediaMenu() { mm->refresh(ui->menuMedia); + status->setSoundGainAction(ui->actionSound_gain); status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); From 5db4de199bfc97a55b6f7c7fc9a9a05b0968f8cc Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 19:26:33 +0100 Subject: [PATCH 0401/1190] PAS16 SCSI change of the day (March 8th, 2025) Signal DRQ once the transfers are complete for real. --- src/sound/snd_pas16.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 353f9a3d5..675582367 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -789,6 +789,10 @@ pas16_in(uint16_t port, void *priv) scsi_bus = &pas16->scsi->ncr.scsibus; /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + if ((scsi_bus->tx_mode == PIO_TX_BUS) && !(ret & 0x80)) + ret |= 0x80; + + pas16_log("5C01 read ret=%02x, status=%02x, txmode=%x.\n", ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode); } break; case 0x5c03: @@ -1190,6 +1194,7 @@ pas16_scsi_callback(void *priv) t128_callback(pas16->scsi); + pas16_log("TimeOutStatus=%02x, t128stat=%02x.\n", pas16->timeout_status, dev->status); if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) { timer_stop(&pas16->scsi_timer); pas16->timeout_status &= 0x7f; From a39bef1ab881bac586532a498b5ca7cb748202d5 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 19:39:55 +0100 Subject: [PATCH 0402/1190] ESS/SB changes of the day (March 8th, 2025) 1. Correct ChipChat mixer port length as well as making mixer reg 0x3a read back its value. 2. Swap the sb port addresses back so that they match the Piper adf. This fixes SoundPiper 16/32 detection. 3. Log cleanups and additions for better debugging. --- src/sound/snd_sb.c | 100 ++++++++++++++++++++--------------------- src/sound/snd_sb_dsp.c | 15 +++++-- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 689d0b91e..5f660509a 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1335,7 +1335,7 @@ sb_ct1745_mixer_read(uint16_t addr, void *priv) break; case 0x82: - ; /* Empty statement to make compilers happy about the following variable declaration. */ + /* Empty statement to make compilers happy about the following variable declaration. */ /* The Interrupt status register, addressed as register 82h on the Mixer register map, is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, in which case it should chain to the previous routine. */ @@ -1727,6 +1727,7 @@ ess_mixer_read(uint16_t addr, void *priv) case 0x32: case 0x36: case 0x38: + case 0x3a: case 0x3e: ret = mixer->regs[mixer->index]; break; @@ -2593,10 +2594,10 @@ ess_soundpiper_mca_write(const int port, const uint8_t val, void *priv) ess->dsp.sb_addr = 0x0000; break; case 0x08: - ess->dsp.sb_addr = 0x0240; + ess->dsp.sb_addr = 0x0220; break; case 0x0c: - ess->dsp.sb_addr = 0x0220; + ess->dsp.sb_addr = 0x0240; break; } @@ -2750,64 +2751,59 @@ ess_chipchat_mca_write(int port, uint8_t val, void *priv) ess->pos_regs[port & 7] = val; - if (ess->pos_regs[2] & 1) { - ess->dsp.sb_addr = (ess->pos_regs[2] == 0x51) ? 0x0220 : 0x0000; + if (ess->pos_regs[2] & 0x01) { + ess->dsp.sb_addr = 0x0220; - if (ess->dsp.sb_addr != 0x0000) { - io_sethandler(ess->dsp.sb_addr, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + io_sethandler(ess->dsp.sb_addr, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 4, 0x0002, + ess_mixer_read, NULL, NULL, + ess_mixer_write, NULL, NULL, + ess); + + io_sethandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { + mpu401_change_addr(ess->mpu, 0x0330); + + io_sethandler(0x0330, 0x0002, ess_fm_midi_read, NULL, NULL, ess_fm_midi_write, NULL, NULL, ess); - io_sethandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, ess->opl.priv); - io_sethandler(0x0388, 0x0004, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 4, 0x0004, - ess_mixer_read, NULL, NULL, - ess_mixer_write, NULL, NULL, - ess); - - io_sethandler(ess->dsp.sb_addr + 2, 0x0004, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 6, 0x0001, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, - ess_base_read, NULL, NULL, - ess_base_write, NULL, NULL, - ess); - - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { - mpu401_change_addr(ess->mpu, (ess->pos_regs[2] == 0x51) ? 0x0330 : 0); - - if (ess->pos_regs[2] == 0x51) - io_sethandler(0x0330, 0x0002, - ess_fm_midi_read, NULL, NULL, - ess_fm_midi_write, NULL, NULL, - ess); - } } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&ess->dsp, ess->dsp.sb_addr); - gameport_remap(ess->gameport, (ess->pos_regs[2] == 0x51) ? 0x200 : 0); - } + gameport_remap(ess->gameport, 0x0200); - if (ess->pos_regs[2] == 0x51) { sb_dsp_setirq(&ess->dsp, 7); mpu401_setirq(ess->mpu, 7); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 9ce0b9fb7..10e5601f4 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -388,6 +388,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) { int masked = 0; + sb_dsp_log("SBIRQ8=%d, irqnum=%d, bit=%x, set=%x.\n", dsp->sb_irq8, dsp->sb_irqnum, bit, set); if (dsp->sb_irq8 || dsp->sb_irq16) return; @@ -423,6 +424,7 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set) } } + sb_dsp_log("Masked=%02x.\n", masked); if (set && !masked) dsp->irq_update(dsp->irq_priv, 1); else if (!set) @@ -1039,6 +1041,8 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) { uint8_t chg; + sb_dsp_log("ESS Write reg=%02x, val=%02x.\n", reg, data); + switch (reg) { case 0xA1: /* Extended Mode Sample Rate Generator */ { @@ -1110,6 +1114,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_irqnum = 10; break; } + sb_dsp_log("Legacy Audio IRQ control=%d.\n", dsp->sb_irqnum); sb_ess_update_irq_drq_readback_regs(dsp, false); break; case 0xB2: /* DRQ Control */ @@ -1131,6 +1136,7 @@ sb_ess_write_reg(sb_dsp_t *dsp, const uint8_t reg, uint8_t data) dsp->sb_8_dmanum = 3; break; } + sb_dsp_log("Legacy Audio DRQ control=%d, chg=%02x.\n", dsp->sb_8_dmanum, chg); sb_ess_update_irq_drq_readback_regs(dsp, false); if (chg & 0x40) sb_ess_update_dma_status(dsp); @@ -1876,12 +1882,12 @@ sb_write(uint16_t addr, uint8_t val, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *) priv; - sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); - /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) addr &= 0xfffe; + sb_dsp_log("[%04X:%08X] DSP: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr & 0xF) { case 6: /* Reset */ sb_do_reset(dsp, val); @@ -1962,7 +1968,7 @@ sb_read(uint16_t addr, void *priv) uint8_t ret = 0x00; /* Sound Blasters prior to Sound Blaster 16 alias the I/O ports. */ - if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xF))) + if ((dsp->sb_type < SB16_DSP_404) && (IS_NOT_ESS(dsp) || ((addr & 0xF) != 0xE))) /* Exception: ESS AudioDrive does not alias port base+0xf */ addr &= 0xfffe; @@ -2085,7 +2091,7 @@ sb_read(uint16_t addr, void *priv) break; } - sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, a, ret); + sb_dsp_log("[%04X:%08X] DSP: [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); return ret; } @@ -2319,6 +2325,7 @@ pollsb(void *priv) if (dsp->sb_8_enable && dsp->sb_pausetime < 0 && dsp->sb_8_output) { sb_dsp_update(dsp); + sb_dsp_log("8-bit format=%02x, pause=%x, length=%d.\n", dsp->sb_8_format, dsp->sb_8_pause, dsp->sb_8_length); switch (dsp->sb_8_format) { case 0x00: /* Mono unsigned */ if (!dsp->sb_8_pause) { From e0603b28769a3c25f26f61e41e3f63d528b84159 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sat, 8 Mar 2025 14:35:59 -0500 Subject: [PATCH 0403/1190] Fix compile error --- src/sound/snd_sb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 5f660509a..e89946486 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1335,7 +1335,7 @@ sb_ct1745_mixer_read(uint16_t addr, void *priv) break; case 0x82: - /* Empty statement to make compilers happy about the following variable declaration. */ + ; /* Empty statement to make compilers happy about the following variable declaration. */ /* The Interrupt status register, addressed as register 82h on the Mixer register map, is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, in which case it should chain to the previous routine. */ From 757246998838dd1ccd84e1f3a30b53f060098b52 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 01:39:07 +0600 Subject: [PATCH 0404/1190] Current OpenGL port status --- src/config.c | 58 +++++++++ src/include/86box/ini.h | 7 +- src/include/86box/qt-glslp-parser.h | 5 +- src/qt/CMakeLists.txt | 4 + src/qt/qt_glsl_parser.cpp | 31 ++++- src/qt/qt_mainwindow.cpp | 11 +- src/qt/qt_openglrenderer_pcem.cpp | 9 +- src/qt/qt_openglrenderer_pcem.hpp | 6 +- src/qt/qt_openglshadermanagerdialog.cpp | 159 ++++++++++++++++++++++++ src/qt/qt_openglshadermanagerdialog.hpp | 40 ++++++ src/qt/qt_openglshadermanagerdialog.ui | 148 ++++++++++++++++++++++ src/qt/qt_renderercommon.hpp | 2 + src/qt/qt_rendererstack.hpp | 2 + 13 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 src/qt/qt_openglshadermanagerdialog.cpp create mode 100644 src/qt/qt_openglshadermanagerdialog.hpp create mode 100644 src/qt/qt_openglshadermanagerdialog.ui diff --git a/src/config.c b/src/config.c index 07e770822..3ff802952 100644 --- a/src/config.c +++ b/src/config.c @@ -77,6 +77,10 @@ #include <86box/snd_opl.h> #include <86box/version.h> +/* Deliberate to not make the 86box.h header kitchen-sink. */ +#include <86box/qt-glsl.h> +extern char gl3_shader_file[MAX_USER_SHADERS][512]; + static int cx; static int cy; static int cw; @@ -1714,6 +1718,30 @@ load_other_peripherals(void) ini_section_delete_var(cat, temp); } +/* Load OpenGL 3.0 renderer options. */ +static void +load_gl3_shaders(void) +{ + ini_section_t cat = ini_find_section(config, "GL3 Shaders"); + char *p; + char temp[512]; + int i = 0; + memset(temp, 0, sizeof(temp)); + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + + for (int i = 0; i < MAX_USER_SHADERS; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + p = ini_section_get_string(cat, temp, ""); + if (p[0]) { + strncpy(gl3_shader_file[i], p, 512); + } else { + gl3_shader_file[i][0] = 0; + break; + } + } +} + /* Load the specified or a default configuration file. */ void config_load(void) @@ -1810,6 +1838,7 @@ config_load(void) load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ load_other_removable_devices(); /* Other removable devices */ load_other_peripherals(); /* Other peripherals */ + load_gl3_shaders(); /* GL3 Shaders */ /* Migrate renamed device configurations. */ c = ini_find_section(config, "MDA"); @@ -2632,6 +2661,34 @@ save_other_peripherals(void) ini_delete_section_if_empty(config, cat); } +/* Save "GL3 Shaders" section. */ +static void +save_gl3_shaders(void) +{ + ini_section_t cat = ini_find_or_create_section(config, "GL3 Shaders"); + char temp[512]; + int shaders = 0, i = 0; + + for (i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] == 0) + break; + shaders++; + } + + ini_section_set_int(cat, "shaders", shaders); + if (shaders == 0) { + ini_section_delete_var(cat, "shaders"); + } else { + for (i = 0; i < shaders; i++) { + temp[0] = 0; + snprintf(temp, 512, "shader%d"); + ini_section_set_string(cat, temp, gl3_shader_file[i]); + } + } + + ini_delete_section_if_empty(config, cat); +} + /* Save "Hard Disks" section. */ static void save_hard_disks(void) @@ -2987,6 +3044,7 @@ config_save(void) save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ save_other_peripherals(); /* Other peripherals */ + save_gl3_shaders(); /* GL3 Shaders */ ini_write(config, cfg_path); } diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 2a73a18b0..2ce89f788 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -91,13 +91,16 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); }; +static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); } static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); if (size == 0) return res; - strncpy(dst, str, size); + if (str != NULL) + strncpy(dst, str, size - 1); + else + dst[0] = 0; return res; } static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { diff --git a/src/include/86box/qt-glslp-parser.h b/src/include/86box/qt-glslp-parser.h index cf2ac464a..853e50e66 100644 --- a/src/include/86box/qt-glslp-parser.h +++ b/src/include/86box/qt-glslp-parser.h @@ -53,4 +53,7 @@ void get_glslp_name(const char *f, char *s, int size); glslp_t *glslp_parse(const char *f); void glslp_free(glslp_t *p); -#endif /* SRC_WX_GLSLP_PARSER_H_ */ \ No newline at end of file +void glslp_read_shader_config(glslp_t *shader); +void glslp_write_shader_config(glslp_t *shader); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index fd82b9053..8a06cbe5a 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -193,6 +193,10 @@ add_library(ui STATIC ../qt_resources.qrc ./qdarkstyle/dark/darkstyle.qrc + + qt_openglshadermanagerdialog.hpp + qt_openglshadermanagerdialog.cpp + qt_openglshadermanagerdialog.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 7cf032a52..b1a96a312 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -7,8 +7,12 @@ extern "C" { #include <86box/86box.h> #include <86box/ini.h> +#include <86box/config.h> #include <86box/qt-glslp-parser.h> #include <86box/path.h> + +extern void startblit(); +extern void endblit(); } #define safe_strncpy(a, b, n) \ @@ -305,4 +309,29 @@ void glslp_free(glslp_t *p) { free(p); } -} \ No newline at end of file +void glslp_read_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + param->value = config_get_double(s, param->id, param->default_value); + } +} + +void glslp_write_shader_config(glslp_t *shader) { + char s[512]; + int i; + char *name = shader->name; + + startblit(); + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) { + struct parameter *param = &shader->parameters[i]; + config_set_double(s, param->id, param->value); + } + endblit(); +} + +} diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 4c1738e63..60e0494fc 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1987,7 +1987,16 @@ MainWindow::on_actionRenderer_options_triggered() { if (const auto dlg = ui->stackedWidget->getOptions(this)) { if (dlg->exec() == QDialog::Accepted) { - for (int i = 1; i < MONITORS_NUM; i++) { + if (ui->stackedWidget->reloadRendererOption()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } + } else for (int i = 1; i < MONITORS_NUM; i++) { if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); } diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 8b2a25663..17f4299d7 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -20,6 +20,7 @@ #include #include "qt_openglrenderer_pcem.hpp" +#include "qt_openglshadermanagerdialog.hpp" extern "C" { #include <86box/86box.h> @@ -1286,6 +1287,12 @@ OpenGLRendererPCem::event(QEvent *event) return res; } +QDialog* +OpenGLRendererPCem::getOptions(QWidget *parent) +{ + return new OpenGLShaderManagerDialog(parent); +} + void OpenGLRendererPCem::render() { @@ -1659,4 +1666,4 @@ OpenGLRendererPCem::render() frameCounter++; context->swapBuffers(this); -} \ No newline at end of file +} diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 88844bb02..706a744fa 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -67,9 +67,9 @@ public: std::vector> getBuffers() override; void finalize() override final; - //bool hasOptions() const override { return true; } - //QDialog *getOptions(QWidget *parent) override; - //void reloadOptions() override; + bool hasOptions() const override { return true; } + QDialog *getOptions(QWidget *parent) override; + bool reloadRendererOption() { return true; } signals: void initialized(); diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp new file mode 100644 index 000000000..26f206a0e --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -0,0 +1,159 @@ +#include "qt_openglshadermanagerdialog.hpp" +#include "ui_qt_openglshadermanagerdialog.h" + +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/video.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/qt-glslp-parser.h> + +extern char gl3_shader_file[MAX_USER_SHADERS][512]; +} + +OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::OpenGLShaderManagerDialog) +{ + ui->setupUi(this); + + for (int i = 0; i < MAX_USER_SHADERS; i++) { + if (gl3_shader_file[i][0] != 0) { + char* filename = path_get_filename(gl3_shader_file[i]); + if (filename[0] != 0) { + glslp_t* shaderfile = glslp_parse(gl3_shader_file[i]); + if (shaderfile) { + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, QString(gl3_shader_file[i])); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + } + } + } + } + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + } else { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + } +} + +OpenGLShaderManagerDialog::~OpenGLShaderManagerDialog() +{ + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + if (ui->shaderListWidget->item(i) && ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)ui->shaderListWidget->item(i)->data(Qt::UserRole + 2).toULongLong()); + } + } + delete ui; +} + +void OpenGLShaderManagerDialog::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) { + accept(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { + reject(); + } +} + + +void OpenGLShaderManagerDialog::on_buttonMoveUp_clicked() +{ + if (ui->shaderListWidget->currentRow() == 0) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row - 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + } + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_shaderListWidget_currentRowChanged(int currentRow) +{ + ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); + ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); +} + + +void OpenGLShaderManagerDialog::on_buttonMoveDown_clicked() +{ + if (ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)) + return; + + int row = ui->shaderListWidget->currentRow(); + auto item = ui->shaderListWidget->takeItem(row); + ui->shaderListWidget->insertItem(row + 1, item); + ui->shaderListWidget->setCurrentItem(item); +} + + +void OpenGLShaderManagerDialog::on_buttonAdd_clicked() +{ + auto res = QFileDialog::getOpenFileName(this, QString(), QString(), "GLSL Shaders (*.glslp *.glsl);;All files (*.*)"); + if (!res.isEmpty()) { + auto glslp_file = res.toUtf8(); + glslp_t* shaderfile = glslp_parse(glslp_file.data()); + if (shaderfile) { + auto filename = path_get_filename(glslp_file.data()); + QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); + item->setText(filename); + item->setData(Qt::UserRole + 1, res); + item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + if (ui->shaderListWidget->count()) { + ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + } + } else { + QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); + } + } +} + + +void OpenGLShaderManagerDialog::on_buttonRemove_clicked() +{ + if (ui->shaderListWidget->currentItem()) { + auto item = ui->shaderListWidget->takeItem(ui->shaderListWidget->currentRow()); + + if (item->data(Qt::UserRole + 2).toULongLong()) { + glslp_free((glslp_t*)item->data(Qt::UserRole + 2).toULongLong()); + } + delete item; + } +} + +void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() +{ + memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); + for (int i = 0; i < ui->shaderListWidget->count(); i++) { + strncpy(gl3_shader_file[i], ui->shaderListWidget->item(i)->data(Qt::UserRole + 1).toString().toUtf8(), 512); + } + startblit(); + config_save(); + endblit(); +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp new file mode 100644 index 000000000..bac0205cf --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -0,0 +1,40 @@ +#ifndef QT_OPENGLSHADERMANAGERDIALOG_H +#define QT_OPENGLSHADERMANAGERDIALOG_H + +#include +#include +#include + +namespace Ui { +class OpenGLShaderManagerDialog; +} + +class OpenGLShaderManagerDialog : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderManagerDialog(QWidget *parent = nullptr); + ~OpenGLShaderManagerDialog(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_buttonMoveUp_clicked(); + + void on_shaderListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + void on_shaderListWidget_currentRowChanged(int currentRow); + + void on_buttonMoveDown_clicked(); + + void on_buttonAdd_clicked(); + + void on_buttonRemove_clicked(); + + void on_OpenGLShaderManagerDialog_accepted(); + +private: + Ui::OpenGLShaderManagerDialog *ui; +}; + +#endif // QT_OPENGLSHADERMANAGERDIALOG_H diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui new file mode 100644 index 000000000..2888e106f --- /dev/null +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -0,0 +1,148 @@ + + + OpenGLShaderManagerDialog + + + + 0 + 0 + 400 + 465 + + + + Dialog + + + + QLayout::SizeConstraint::SetFixedSize + + + + + QAbstractItemView::DragDropMode::InternalMove + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + + + Add + + + + + + + Remove + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + false + + + Configure + + + + + + + Move up + + + + + + + Move down + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + false + + + + + + + + + + + buttonBox + accepted() + OpenGLShaderManagerDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLShaderManagerDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index af72474c7..f3f5d2223 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -34,6 +34,8 @@ public: virtual QDialog *getOptions(QWidget *parent) { return nullptr; } /* Reloads options of renderer */ virtual void reloadOptions() { } + /* Make the renderer reload itself */ + virtual bool reloadRendererOption() { return false; } int r_monitor_index = 0; diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 8059d59c5..32ed5f7ca 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -70,6 +70,8 @@ public: void reloadOptions() const { return rendererWindow->reloadOptions(); } /* Returns options dialog for current renderer */ QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; } + /* Reload the renderer itself */ + bool reloadRendererOption() { return rendererWindow ? rendererWindow->reloadRendererOption() : false; } void setFocusRenderer(); void onResize(int width, int height); From f8517d05ef7f885a2d91629aec21fbf13a70d366 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 20:49:28 +0100 Subject: [PATCH 0405/1190] XGA/VGA changes of the evening (March 8th, 2025) Workaround xga/vga toggle bug in the inmos card so that it switches from xga to vga and viceversa on ami bioses. --- src/video/vid_svga.c | 5 +++-- src/video/vid_xga.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index caa20e196..1fd2460bd 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -782,7 +782,8 @@ svga_recalctimings(svga_t *svga) if (xga_active && (svga->xga != NULL)) { if (xga->on) { - if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl == 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ + svga_log("XGA on=%d, base=%05x, ap=%x.\n", xga->on, svga->mapping.base, xga->aperture_cntl); + if ((svga->mapping.base == 0xb8000) && (xga->aperture_cntl >= 1)) /*Some operating systems reset themselves with ctrl-alt-del by going into text mode.*/ xga->on = 0; } } @@ -1541,7 +1542,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; - + svga->cable_connected = 1; svga->ksc5601_english_font_type = 0; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 2cc20044a..4c08b7b71 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -2738,7 +2738,7 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga_t *xga = (xga_t *) svga->xga; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { xga_log("WriteAddr=%05x.\n", addr); if (val == 0xa5) { /*Memory size test of XGA*/ xga->test = val; @@ -2843,7 +2843,7 @@ xga_read_test(uint32_t addr, void *priv) uint8_t ret = 0x00; if (xga_active && xga) { - if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl) { + if (((xga->op_mode & 7) >= 1) && xga->aperture_cntl && (svga->mapping.base == 0xb8000)) { if (xga->test == 0xa5) { /*Memory size test of XGA*/ if (addr == 0xa0001) { ret = xga->test; From 2f2a14e0e768dab93c78f8ee02ccac38642b6305 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 01:58:47 +0600 Subject: [PATCH 0406/1190] Fix not saving shader section properly --- src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 3ff802952..46f935f7e 100644 --- a/src/config.c +++ b/src/config.c @@ -2681,7 +2681,7 @@ save_gl3_shaders(void) } else { for (i = 0; i < shaders; i++) { temp[0] = 0; - snprintf(temp, 512, "shader%d"); + snprintf(temp, 512, "shader%d", i); ini_section_set_string(cat, temp, gl3_shader_file[i]); } } From dad0a37ab3e7c66abecf54515f5679e39a708314 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 8 Mar 2025 20:58:49 +0100 Subject: [PATCH 0407/1190] Mach32 LFB changes (March 8th, 2025) The Byte Write access of the LFB of the Mach32 was not correctly taking account of the subtraction of the address, this fixes possible graphics bugs using the LFB (Linear Aperture). --- src/video/vid_ati_mach8.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 0c8fb6691..d35257ea7 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5226,7 +5226,7 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); @@ -5279,6 +5279,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { @@ -5291,8 +5294,6 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); } } else { - mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); if (dev->on) mach32_writel_linear(addr, val, mach); else From 9da53a611d8bfbd0100cd3caa6e88ca0d799f0fa Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Mar 2025 01:58:48 +0100 Subject: [PATCH 0408/1190] VIA PIPC: Fix SCI IRQ readout. --- src/chipset/via_pipc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index dcfe41811..19355431e 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -413,7 +413,9 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = 0x50; + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + dev->power_regs[0x48] = 0x01; if (dev->local == VIA_PIPC_686B) { @@ -1593,6 +1595,9 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); + dev->power_regs[0x42] = 0x00; + acpi_set_irq_line(dev->acpi, 0x00); + pipc_write(1, 0x04, 0x80, priv); pipc_write(1, 0x09, 0x85, priv); pipc_write(1, 0x10, 0xf1, priv); From 0c7c85e66314fdbb7e8bad7a6392e43e1a3a0526 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Mar 2025 02:18:18 +0100 Subject: [PATCH 0409/1190] ACPI: Do not raise or lower IRQ if IRQ line is set to IRQ 0. --- src/acpi.c | 10 ++++++++-- src/chipset/via_pipc.c | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index b33653663..ccd51ebca 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -211,7 +211,10 @@ acpi_update_irq(acpi_t *dev) if ((dev->regs.pmcntrl & 0x01) && sci_level) switch (dev->irq_mode) { default: - picintlevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintlevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 1; break; case 1: pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state); @@ -223,7 +226,10 @@ acpi_update_irq(acpi_t *dev) break; } else switch (dev->irq_mode) { default: - picintclevel(1 << dev->irq_line, &dev->irq_state); + if (dev->irq_line != 0) + picintclevel(1 << dev->irq_line, &dev->irq_state); + else + dev->irq_state = 0; break; case 1: pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state); diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 19355431e..11a192450 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1699,6 +1699,8 @@ pipc_init(const device_t *info) acpi_set_nvr(dev->acpi, dev->nvr); acpi_init_gporeg(dev->acpi, 0xff, 0xbf, 0xff, 0x7f); + + acpi_set_irq_mode(dev->acpi, 0); } return dev; From 7a4d5ee75e971fe4ddca1e72a2f8630cb2f8356e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 13:06:58 +0600 Subject: [PATCH 0410/1190] Some optimizations --- src/qt/qt_openglrenderer_pcem.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 17f4299d7..e53b8b77b 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -770,7 +770,7 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) parentWidget = parent; - source.setRect(0, 0, 2048, 2048); + source.setRect(0, 0, 100, 100); isInitialized = false; isFinalized = false; } @@ -1075,11 +1075,18 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) destination.width() * devicePixelRatio(), destination.height() * devicePixelRatio()); #endif + + if (source.width() != w || source.height() != h) { + glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glw.glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, w, h, 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + source.setRect(x, y, w, h); glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 2048); - glw.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); + glw.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, (const void *) ((uintptr_t) imagebufs[buf_idx].get() + (uintptr_t) (2048 * 4 * y + x * 4))); glw.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glw.glBindTexture(GL_TEXTURE_2D, 0); @@ -1369,10 +1376,10 @@ OpenGLRendererPCem::render() pass->state.tex_coords[7] = maxy; // create input tex coords - minx = video_rect.x / 2048.f; - miny = video_rect.y / 2048.f; - maxx = (video_rect.x + video_rect.w) / (float) 2048.f; - maxy = (video_rect.y + video_rect.h) / (float) 2048.f; + minx = 0; + miny = 0; + maxx = 1; + maxy = 1; GLfloat tex_coords[] = { minx, miny, minx, maxy, maxx, miny, maxx, maxy }; From 7e61d2d58692c10566b891c6f387920486fa54f5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 9 Mar 2025 23:58:54 +0600 Subject: [PATCH 0411/1190] OpenGL Shader configuration UI --- src/config.c | 14 +++- src/include/86box/ini.h | 3 +- src/ini.c | 52 +++++++++++--- src/qt/CMakeLists.txt | 1 + src/qt/qt_glsl_parser.cpp | 2 + src/qt/qt_mainwindow.cpp | 16 +++++ src/qt/qt_mainwindow.hpp | 4 ++ src/qt/qt_openglshaderconfig.cpp | 85 +++++++++++++++++++++++ src/qt/qt_openglshaderconfig.hpp | 40 +++++++++++ src/qt/qt_openglshaderconfig.ui | 92 +++++++++++++++++++++++++ src/qt/qt_openglshadermanagerdialog.cpp | 50 ++++++++++++++ src/qt/qt_openglshadermanagerdialog.hpp | 2 + src/qt/qt_openglshadermanagerdialog.ui | 4 +- 13 files changed, 349 insertions(+), 16 deletions(-) create mode 100644 src/qt/qt_openglshaderconfig.cpp create mode 100644 src/qt/qt_openglshaderconfig.hpp create mode 100644 src/qt/qt_openglshaderconfig.ui diff --git a/src/config.c b/src/config.c index 46f935f7e..20981885a 100644 --- a/src/config.c +++ b/src/config.c @@ -1725,11 +1725,15 @@ load_gl3_shaders(void) ini_section_t cat = ini_find_section(config, "GL3 Shaders"); char *p; char temp[512]; - int i = 0; + int i = 0, shaders = 0; memset(temp, 0, sizeof(temp)); memset(gl3_shader_file, 0, sizeof(gl3_shader_file)); - for (int i = 0; i < MAX_USER_SHADERS; i++) { + shaders = ini_section_get_int(cat, "shaders", 0); + if (shaders > MAX_USER_SHADERS) + shaders = MAX_USER_SHADERS; + + for (int i = 0; i < shaders; i++) { temp[0] = 0; snprintf(temp, 512, "shader%d", i); p = ini_section_get_string(cat, temp, ""); @@ -2670,8 +2674,12 @@ save_gl3_shaders(void) int shaders = 0, i = 0; for (i = 0; i < MAX_USER_SHADERS; i++) { - if (gl3_shader_file[i][0] == 0) + if (gl3_shader_file[i][0] == 0) { + temp[0] = 0; + snprintf(temp, 512, "shader%d", i); + ini_section_delete_var(cat, temp); break; + } shaders++; } diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 2ce89f788..3139f410e 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -31,6 +31,7 @@ typedef void *ini_section_t; extern ini_t ini_new(void); extern ini_t ini_read(const char *fn); +extern void ini_strip_quotes(ini_t ini); extern void ini_write(ini_t ini, const char *fn); extern void ini_dump(ini_t ini); extern void ini_close(ini_t ini); @@ -91,7 +92,7 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { return (void*) ini_read(path); } +static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); diff --git a/src/ini.c b/src/ini.c index 4ea6f6381..b4c905489 100644 --- a/src/ini.c +++ b/src/ini.c @@ -254,9 +254,8 @@ ini_delete_section_if_empty(ini_t ini, ini_section_t section) static section_t * create_section(list_t *head, const char *name) { - section_t *ns = malloc(sizeof(section_t)); + section_t *ns = calloc(1, sizeof(section_t)); - memset(ns, 0x00, sizeof(section_t)); memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, head); @@ -279,9 +278,8 @@ ini_find_or_create_section(ini_t ini, const char *name) static entry_t * create_entry(section_t *section, const char *name) { - entry_t *ne = malloc(sizeof(entry_t)); + entry_t *ne = calloc(1, sizeof(entry_t)); - memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); @@ -390,11 +388,8 @@ ini_read(const char *fn) if (fp == NULL) return NULL; - head = malloc(sizeof(list_t)); - memset(head, 0x00, sizeof(list_t)); - - sec = malloc(sizeof(section_t)); - memset(sec, 0x00, sizeof(section_t)); + head = calloc(1, sizeof(list_t)); + sec = calloc(1, sizeof(section_t)); list_add(&sec->list, head); if (bom) @@ -475,7 +470,7 @@ ini_read(const char *fn) d = c; /* Allocate a new variable entry.. */ - ne = malloc(sizeof(entry_t)); + ne = calloc(1, sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, ename, 128); wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata) - 1); @@ -551,6 +546,43 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +void +ini_strip_quotes(ini_t ini) +{ + list_t *list = (list_t *) ini; + section_t *sec; + + sec = (section_t *) list->next; + + while (sec != NULL) { + entry_t *ent; + + ent = (entry_t *) sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + int i = 0; + if (ent->wdata[0] == L'\"') { + memmove(ent->wdata, &ent->wdata[1], sizeof(ent->wdata) - sizeof(wchar_t)); + } + if (ent->wdata[wcslen(ent->wdata) - 1] == L'\"') { + ent->wdata[wcslen(ent->wdata) - 1] = 0; + } + + if (ent->data[0] == '\"') { + memmove(ent->data, &ent->data[1], sizeof(ent->data) - sizeof(char)); + } + if (ent->data[strlen(ent->data) - 1] == '\"') { + ent->data[strlen(ent->data) - 1] = 0; + } + } + + ent = (entry_t *) ent->list.next; + } + + sec = (section_t *) sec->list.next; + } +} + ini_t ini_new(void) { diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 8a06cbe5a..574aae7b7 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -197,6 +197,7 @@ add_library(ui STATIC qt_openglshadermanagerdialog.hpp qt_openglshadermanagerdialog.cpp qt_openglshadermanagerdialog.ui + qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index b1a96a312..f43897506 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -255,6 +255,8 @@ glslp_t *glslp_parse(const char *f) { safe_strncpy(s, t + j, sublen); s[511 < sublen ? 511 : sublen] = 0; + if (s[strlen(s) - 1] == ';') s[strlen(s) - 1] = 0; + struct texture *tex = &glslp->textures[glslp->num_textures++]; strcpy(tex->name, s); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 60e0494fc..7e0cecdeb 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1982,6 +1982,12 @@ MainWindow::changeEvent(QEvent *event) } } +void +MainWindow::reloadAllRenderers() +{ + reload_renderers = true; +} + void MainWindow::on_actionRenderer_options_triggered() { @@ -2000,6 +2006,16 @@ MainWindow::on_actionRenderer_options_triggered() if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); } + } else if (reload_renderers && ui->stackedWidget->reloadRendererOption()) { + reload_renderers = false; + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (show_second_monitors) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { + ui->stackedWidget->switchRenderer(static_cast(vid_api)); + } + } + } } } } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 25e33d77c..dced698bb 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -32,6 +32,7 @@ public: QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); void checkFullscreenHotkey(); + void reloadAllRenderers(); std::array, 8> renderers; signals: @@ -173,6 +174,9 @@ private: bool fs_on_signal = false; bool fs_off_signal = false; + /* Reload the renderers after closing renderer options dialog. */ + bool reload_renderers = false; + friend class SpecifyDimensions; friend class ProgSettings; friend class RendererCommon; diff --git a/src/qt/qt_openglshaderconfig.cpp b/src/qt/qt_openglshaderconfig.cpp new file mode 100644 index 000000000..25f9d38a8 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.cpp @@ -0,0 +1,85 @@ +#include "qt_openglshaderconfig.hpp" +#include "ui_qt_openglshaderconfig.h" + +#include "qt_mainwindow.hpp" + +extern MainWindow* main_window; + +extern "C" +{ +#include <86box/86box.h> +#include <86box/plat.h> +#include <86box/config.h> +} + +OpenGLShaderConfig::OpenGLShaderConfig(QWidget *parent, glslp_t* shader) + : QDialog(parent) + , ui(new Ui::OpenGLShaderConfig) +{ + ui->setupUi(this); + + currentShader = shader; + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + glslp_read_shader_config(currentShader); + + for (int i = 0; i < currentShader->num_parameters; i++) { + auto spinBox = new QDoubleSpinBox; + spinBox->setObjectName(currentShader->parameters[i].id); + spinBox->setRange(currentShader->parameters[i].min, currentShader->parameters[i].max); + spinBox->setValue(currentShader->parameters[i].value); + spinBox->setSingleStep(currentShader->parameters[i].step); + QFormLayout* layout = (QFormLayout*)ui->scrollAreaWidgetContents->layout(); + layout->addRow(currentShader->parameters[i].description, spinBox); + } +} + +OpenGLShaderConfig::~OpenGLShaderConfig() +{ + delete ui; +} + +void OpenGLShaderConfig::on_buttonBox_clicked(QAbstractButton *button) +{ + if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) { + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + box->setValue(currentShader->parameters[i].default_value); + } + } + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); + } +} + + +void OpenGLShaderConfig::on_OpenGLShaderConfig_accepted() +{ + startblit(); + for (int i = 0; i < currentShader->num_parameters; i++) { + QDoubleSpinBox* box = (QDoubleSpinBox*)this->findChild(QString(currentShader->parameters[i].id)); + if (box) { + float val = (float)box->value(); + currentShader->parameters[i].value = val; + } + } + glslp_write_shader_config(currentShader); + config_save(); + endblit(); + main_window->reloadAllRenderers(); +} + diff --git a/src/qt/qt_openglshaderconfig.hpp b/src/qt/qt_openglshaderconfig.hpp new file mode 100644 index 000000000..f71299d38 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.hpp @@ -0,0 +1,40 @@ +#ifndef QT_OPENGLSHADERCONFIG_HPP +#define QT_OPENGLSHADERCONFIG_HPP + +#include +#include +#include +#include + +#include +#include + +extern "C" +{ +#include <86box/qt-glslp-parser.h> +} + +namespace Ui { +class OpenGLShaderConfig; +} + +class OpenGLShaderConfig : public QDialog { + Q_OBJECT + +public: + explicit OpenGLShaderConfig(QWidget *parent = nullptr, glslp_t* shader = nullptr); + ~OpenGLShaderConfig(); + +private slots: + void on_buttonBox_clicked(QAbstractButton *button); + + void on_OpenGLShaderConfig_accepted(); + +private: + Ui::OpenGLShaderConfig *ui; + glslp_t* currentShader; + + std::map defaultValues; +}; + +#endif // QT_OPENGLSHADERCONFIG_HPP diff --git a/src/qt/qt_openglshaderconfig.ui b/src/qt/qt_openglshaderconfig.ui new file mode 100644 index 000000000..1aebdb6f6 --- /dev/null +++ b/src/qt/qt_openglshaderconfig.ui @@ -0,0 +1,92 @@ + + + OpenGLShaderConfig + + + + 0 + 0 + 400 + 300 + + + + Shader Configuration + + + + QLayout::SizeConstraint::SetMinAndMaxSize + + + + + true + + + + + 0 + 0 + 380 + 250 + + + + + QLayout::SizeConstraint::SetMaximumSize + + + QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow + + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::Reset + + + + + + + + + buttonBox + accepted() + OpenGLShaderConfig + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OpenGLShaderConfig + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 26f206a0e..08cf94fd7 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -1,6 +1,8 @@ #include "qt_openglshadermanagerdialog.hpp" #include "ui_qt_openglshadermanagerdialog.h" +#include "qt_openglshaderconfig.hpp" + #include #include #include @@ -39,10 +41,21 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) } if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + auto current = ui->shaderListWidget->currentItem(); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + else + ui->buttonConfigure->setEnabled(false); + } else { + ui->buttonConfigure->setEnabled(false); + } } else { ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); } } @@ -84,9 +97,16 @@ void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidg ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); return; } else { ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } } ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); @@ -95,6 +115,22 @@ void OpenGLShaderManagerDialog::on_shaderListWidget_currentItemChanged(QListWidg void OpenGLShaderManagerDialog::on_shaderListWidget_currentRowChanged(int currentRow) { + auto current = ui->shaderListWidget->currentItem(); + if (current == nullptr) { + ui->buttonRemove->setDisabled(true); + ui->buttonMoveUp->setDisabled(true); + ui->buttonMoveDown->setDisabled(true); + ui->buttonConfigure->setDisabled(true); + return; + } else { + ui->buttonRemove->setDisabled(false); + ui->buttonConfigure->setDisabled(true); + if (current) { + glslp_t* shader = (glslp_t*)current->data(Qt::UserRole + 2).toULongLong(); + if (shader->num_parameters > 0) + ui->buttonConfigure->setEnabled(true); + } + } ui->buttonMoveUp->setDisabled(ui->shaderListWidget->currentRow() == 0); ui->buttonMoveDown->setDisabled(ui->shaderListWidget->currentRow() == (ui->shaderListWidget->count() - 1)); } @@ -143,6 +179,8 @@ void OpenGLShaderManagerDialog::on_buttonRemove_clicked() glslp_free((glslp_t*)item->data(Qt::UserRole + 2).toULongLong()); } delete item; + + on_shaderListWidget_currentRowChanged(ui->shaderListWidget->currentRow()); } } @@ -157,3 +195,15 @@ void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() endblit(); } + +void OpenGLShaderManagerDialog::on_buttonConfigure_clicked() +{ + auto item = ui->shaderListWidget->currentItem(); + if (item) { + glslp_t* shader = (glslp_t*)item->data(Qt::UserRole + 2).toULongLong(); + + auto configDialog = new OpenGLShaderConfig(this, shader); + configDialog->exec(); + } +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp index bac0205cf..b8885e3a3 100644 --- a/src/qt/qt_openglshadermanagerdialog.hpp +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -33,6 +33,8 @@ private slots: void on_OpenGLShaderManagerDialog_accepted(); + void on_buttonConfigure_clicked(); + private: Ui::OpenGLShaderManagerDialog *ui; }; diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui index 2888e106f..f68827436 100644 --- a/src/qt/qt_openglshadermanagerdialog.ui +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -11,7 +11,7 @@ - Dialog + Shader Manager @@ -59,7 +59,7 @@ - false + true Configure From f4479d34854a75777a7717287ac34cff42fd87c1 Mon Sep 17 00:00:00 2001 From: barnacl437 Date: Mon, 10 Mar 2025 01:05:37 +0700 Subject: [PATCH 0412/1190] some translation fixes for vi-VN lang --- src/qt/languages/vi-VN.po | 122 +++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 15802fc2d..abb17351b 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -682,13 +682,13 @@ msgid "Surface images" msgstr "Ảnh bề mặt" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/machines. Hãy chọn mẫu máy khác." +msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/machines. Hãy chọn mẫu máy khác." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Hãy chọn card đồ họa khác." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Machine" msgstr "Mẫu máy" @@ -1216,7 +1216,7 @@ msgid "Development of the WinBox manager stopped in 2022 due to a lack of mainta msgstr "Trình quản lý phiên WinBox đã bị dừng phát triển năm 2022 do thiếu nhân sự duy trì. Vì những quyết định để cho 86Box trở nên tốt hơn, chúng tôi đã không còn hỗ trợ trình quản lý WinBox.\n\n Sẽ không có bản cập nhật mới cho WinBox nữa, và nếu bạn tiếp tục sử dụng với các bản 86Box mới hơn có thể gặp lỗi. Bất kì các bản bug report liên quan đến lỗi của WinBox sẽ bị coi là không hợp lệ và bị đóng.\n\nTruy cập 86Box.net để tìm qua các trình quản lý phiên/manager khác cho phù hợp." msgid "Generate" -msgstr "Phát ra" +msgstr "Tạo" msgid "Joystick configuration" msgstr "Cấu hình cần điều khiển" @@ -1237,7 +1237,7 @@ msgid "List of MCA devices:" msgstr "Danh sách các thiết bị MCA:" msgid "Tablet tool" -msgstr "Công cụ máy tính bảng" +msgstr "Công cụ bảng nhập liệu" msgid "Qt (OpenGL &ES)" msgstr "QT (OpenGL &ES)" @@ -1261,19 +1261,19 @@ msgid "Cursor/Puck" msgstr "Con trỏ/puck" msgid "Pen" -msgstr "Cái bút" +msgstr "Bút" msgid "Host CD/DVD Drive (%1:)" msgstr "Máy chủ CD/DVD ổ đĩa (%1 :)" msgid "&Connected" -msgstr "& Kết nối" +msgstr "&Đã kết nối" msgid "Clear image history" msgstr "Xóa lịch sử ảnh đĩa" msgid "Create..." -msgstr "Tạo nên..." +msgstr "Tạo..." msgid "previous image" msgstr "đĩa trước đó" @@ -1306,7 +1306,7 @@ msgid "OpenGL 3.0 renderer options" msgstr "Tùy chọn kết xuất OpenGL 3.0" msgid "Render behavior" -msgstr "Hiện ra hành vi" +msgstr "Hành vi kết xuất" msgid "Use target framerate:" msgstr "Dùng số khung hình mục tiêu:" @@ -1318,16 +1318,16 @@ msgid "VSync" msgstr "Vsync" msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không sử dụng hình chữ nhật cho các hiệu ứng hoạt hình.</span></p></body></html>" +msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không tối ưu frametime cho các hiệu ứng động.</span></p></body></html>" msgid "Synchronize with video" -msgstr "Đồng bộ hóa với video" +msgstr "Đồng bộ với video" msgid "Shaders" msgstr "Shaders" msgid "Remove" -msgstr "Di dời" +msgstr "Loại bỏ" msgid "No shader selected" msgstr "Không có shader được chọn" @@ -1360,19 +1360,19 @@ msgid "Error initializing OpenGL" msgstr "Lỗi khởi tạo OpenGL" msgid "Falling back to software rendering.\n" -msgstr "Rơi trở lại kết xuất phần mềm.\n" +msgstr "Quay trở lại kết xuất phần mềm.\n" msgid "Allocating memory for unpack buffer failed.\n" msgstr "Phân bổ bộ nhớ cho bộ đệm giải nén không thành công.\n" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, FLOPPY, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" +msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" msgid "This machine might have been moved or copied." -msgstr "Máy này có thể đã được di chuyển hoặc sao chép." +msgstr "Cấu hình máy này có thể đã được di chuyển hoặc sao chép." msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." -msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." +msgstr "Để đảm bảo chức năng kết nối mạng thích hợp, 86Box cần biết liệu máy này có được di chuyển hay sao chép không.\n\nNếu bạn không chắc chắn, chọn \"Tôi đã sao chép nó\"." msgid "I Moved It" msgstr "Tôi đã di chuyển nó" @@ -1387,7 +1387,7 @@ msgid "No MCA devices." msgstr "Không có thiết bị MCA." msgid "MiB" -msgstr "Mib" +msgstr "MiB" msgid "Network Card #1" msgstr "Thẻ mạng 1" @@ -1402,7 +1402,7 @@ msgid "Network Card #4" msgstr "Thẻ mạng 4" msgid "Mode" -msgstr "Cách thức" +msgstr "Chế độ" msgid "Interface" msgstr "Giao diện" @@ -1414,7 +1414,7 @@ msgid "VDE Socket" msgstr "Ổ cắm VDE" msgid "86Box Unit Tester" -msgstr "Người kiểm tra đơn vị 86box" +msgstr "Trình kiểm tra đơn vị 86box" msgid "Novell NetWare 2.x Key Card" msgstr "Thẻ khóa Novell Netware 2.x" @@ -1432,7 +1432,7 @@ msgid "Serial port passthrough 4" msgstr "Thông qua cổng serial 4" msgid "Vision Systems LBA Enhancer" -msgstr "Hệ thống tầm nhìn LBA Enhancer" +msgstr "Vision Systems LBA Enhancer" msgid "Renderer options..." msgstr "Tùy chọn kết xuất ..." @@ -1474,7 +1474,7 @@ msgid "Roland CM-32LN Emulation" msgstr "Mô phỏng Roland CM-32LN" msgid "OPL4-ML Daughterboard" -msgstr "Con gái OPL4-ML" +msgstr "Bo mạch con OPL4-ML" msgid "System MIDI" msgstr "MIDI của hệ thống" @@ -1486,7 +1486,7 @@ msgid "BIOS Address" msgstr "Địa chỉ BIOS" msgid "Enable BIOS extension ROM Writes" -msgstr "Bật ROM mở rộng BIOS" +msgstr "Kích hoạt ghi ROM mở rộng BIOS" msgid "Address" msgstr "Địa chỉ" @@ -1513,22 +1513,22 @@ msgid "BIOS size" msgstr "Kích thước BIOS" msgid "Map C0000-C7FFF as UMB" -msgstr "Bản đồ C0000-C7FFF dưới dạng UMB" +msgstr "Map C0000-C7FFF dưới dạng UMB" msgid "Map C8000-CFFFF as UMB" -msgstr "Bản đồ C8000-CFFFF dưới dạng UMB" +msgstr "Map C8000-CFFFF dưới dạng UMB" msgid "Map D0000-D7FFF as UMB" -msgstr "Bản đồ D0000-D7FFF dưới dạng UMB" +msgstr "Map D0000-D7FFF dưới dạng UMB" msgid "Map D8000-DFFFF as UMB" -msgstr "Bản đồ D8000-Dffff dưới dạng UMB" +msgstr "Map D8000-Dffff dưới dạng UMB" msgid "Map E0000-E7FFF as UMB" -msgstr "Bản đồ E0000-E7FFF dưới dạng UMB" +msgstr "Map E0000-E7FFF dưới dạng UMB" msgid "Map E8000-EFFFF as UMB" -msgstr "Bản đồ e8000-effff dưới dạng umb" +msgstr "Map e8000-effff dưới dạng umb" msgid "JS9 Jumper (JIM)" msgstr "JS9 Jumper (Jim)" @@ -1543,13 +1543,13 @@ msgid "MIDI Thru" msgstr "Thông qua đầu vào MIDI" msgid "MIDI Clockout" -msgstr "MIDI đồng hồ" +msgstr "MIDI Clockout" msgid "SoundFont" -msgstr "Soundfont" +msgstr "Font âm thanh" msgid "Output Gain" -msgstr "Đầu ra tăng" +msgstr "Tăng đầu ra" msgid "Chorus" msgstr "Điệp khúc" @@ -1588,7 +1588,7 @@ msgid "Interpolation Method" msgstr "Phương pháp nội suy" msgid "Reverb Output Gain" -msgstr "Gợi ý đầu ra hồi âm" +msgstr "Tăng đầu ra hồi âm" msgid "Reversed stereo" msgstr "Đảo ngược âm thanh nổi" @@ -1609,10 +1609,10 @@ msgid "RTS toggle" msgstr "RT chuyển đổi" msgid "Revision" -msgstr "Ôn tập" +msgstr "Bản sửa đổi" msgid "Controller" -msgstr "Người điều khiển" +msgstr "Bộ điều khiển" msgid "Show Crosshair" msgstr "Hiển thị hình chữ thập" @@ -1624,7 +1624,7 @@ msgid "MAC Address" msgstr "Địa chỉ MAC" msgid "MAC Address OUI" -msgstr " OUI địa chỉ MAC" +msgstr "OUI địa chỉ MAC" msgid "Enable BIOS" msgstr "Bật BIOS" @@ -1696,7 +1696,7 @@ msgid "Enable OPL" msgstr "Bật OPL" msgid "Receive MIDI input (MPU-401)" -msgstr "Nhận nhập MIDI (MPU-401)" +msgstr "Nhận đầu vào MIDI (MPU-401)" msgid "SB low DMA" msgstr "SB DMA thấp" @@ -1708,7 +1708,7 @@ msgid "Enable CMS" msgstr "Bật CMS" msgid "Mixer" -msgstr "Máy trộn" +msgstr "Bộ trộn" msgid "High DMA" msgstr "DMA cao" @@ -1744,13 +1744,13 @@ msgid "RGB type" msgstr "Loại RGB" msgid "Line doubling type" -msgstr "Dòng nhân đôi" +msgstr "Loại dòng kép" msgid "Snow emulation" -msgstr "Đun tuyết" +msgstr "Giả lập hiệu ứng tuyết" msgid "Monitor type" -msgstr "Loại giám sát" +msgstr "Loại màn hình" msgid "Character set" msgstr "Bộ ký tự" @@ -1759,13 +1759,13 @@ msgid "XGA type" msgstr "Loại XGA" msgid "Instance" -msgstr "Ví dụ" +msgstr "Bản chạy" msgid "MMIO Address" msgstr "Địa chỉ MMIO" msgid "RAMDAC type" -msgstr "Loại Ramdac" +msgstr "Loại RAMDAC" msgid "Blend" msgstr "Trộn" @@ -1789,13 +1789,13 @@ msgid "Texture memory size" msgstr "Kích thước bộ nhớ kết cấu" msgid "Dither subtraction" -msgstr "Phân biệt trừ" +msgstr "Giảm ngân tán" msgid "Screen Filter" msgstr "Bộ lọc màn hình" msgid "Render threads" -msgstr "Kết xuất chủ đề" +msgstr "Luồng kết xuất" msgid "SLI" msgstr "SLI" @@ -1810,13 +1810,13 @@ msgid "I/O Width" msgstr "Chiều rộng I/O" msgid "Transfer Speed" -msgstr "Tốc độ chuyển" +msgstr "Tốc độ truyền tải" msgid "EMS mode" msgstr "Chế độ EMS" msgid "Address for > 2 MB" -msgstr "Địa chỉ cho> 2 MB" +msgstr "Địa chỉ cho > 2 MB" msgid "Frame Address" msgstr "Địa chỉ khung" @@ -1831,7 +1831,7 @@ msgid "Always at selected speed" msgstr "Luôn ở tốc độ đã chọn" msgid "BIOS setting + Hotkeys (off during POST)" -msgstr "Cài đặt BIOS + phím nóng (TẮT trong bài đăng)" +msgstr "Cài đặt BIOS + phím nóng (TẮT trong POST)" msgid "64 kB starting from F0000" msgstr "64 kb bắt đầu từ f0000" @@ -1858,7 +1858,7 @@ msgid "Non-timed (original)" msgstr "Không đúng lúc (bản gốc)" msgid "45 Hz (JMP2 not populated)" -msgstr "45 Hz (JMP2 không dân cư)" +msgstr "45 Hz (JMP2 không phổ cập)" msgid "Two" msgstr "Hai" @@ -1867,10 +1867,10 @@ msgid "Three" msgstr "Ba" msgid "Wheel" -msgstr "Bánh xe" +msgstr "Con lăn" msgid "Five + Wheel" -msgstr "Năm + bánh xe" +msgstr "Năm + con lăn" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" @@ -2005,7 +2005,7 @@ msgid "Color" msgstr "Màu sắc" msgid "U.S. English" -msgstr "Tiếng Anh Hoa Kỳ" +msgstr "Tiếng Anh Mỹ" msgid "Scandinavian" msgstr "Scandinavia" @@ -2017,13 +2017,13 @@ msgid "Bochs latest" msgstr "Bochs mới nhất" msgid "Mono Non-Interlaced" -msgstr "Đơn sắc không được xen kẽ" +msgstr "Đơn sắc không xen kẽ" msgid "Color Interlaced" msgstr "Màu sắc xen kẽ" msgid "Color Non-Interlaced" -msgstr "Màu sắc không được xen kẽ" +msgstr "Màu sắc không xen kẽ" msgid "3Dfx Voodoo Graphics" msgstr "Đồ họa 3Dfx Voodoo" @@ -2071,7 +2071,7 @@ msgid "Parallel Line Internet Protocol" msgstr "Parallel Line Internet Protocol" msgid "Protection Dongle for Savage Quest" -msgstr "Bảo vệ dongle cho Savage Quest" +msgstr "Dongle bảo vệ cho Savage Quest" msgid "Serial Passthrough Device" msgstr "Thiết bị thông qua cổng serial" @@ -2083,7 +2083,7 @@ msgid "Host Serial Device" msgstr "Thiết bị serial máy chủ" msgid "Name of pipe" -msgstr "Tên của đường ống" +msgstr "Tên đường ống" msgid "Data bits" msgstr "Bit dữ liệu" @@ -2092,10 +2092,10 @@ msgid "Stop bits" msgstr "Dừng bit" msgid "Baud Rate of Passthrough" -msgstr "Tốc độ baud của qua đường" +msgstr "Tốc độ baud của đường thông" msgid "Named Pipe (Server)" -msgstr "Đường ống được đặt tên (máy chủ)" +msgstr "Đường ống có tên (máy chủ)" msgid "Host Serial Passthrough" msgstr "Thông qua cổng serial của máy chủ" @@ -2104,19 +2104,19 @@ msgid "Eject %s" msgstr "Đẩy đĩa ra %s" msgid "&Unmute" -msgstr "&Không quay được" +msgstr "&Mở tiếng" msgid "Softfloat FPU" msgstr "Softfloat FPU" msgid "High performance impact" -msgstr "Tác động cao đến hiệu suất" +msgstr "Ảnh hưởng lớn đến hiệu suất" msgid "RAM Disk (max. speed)" -msgstr "Đĩa RAM (Tối đa. Tốc độ)" +msgstr "Đĩa RAM (tốc độ tối đa)" msgid "IBM 8514/A clone (ISA)" -msgstr "IBM 8514/A dòng vô tính (ISA)" +msgstr "IBM 8514/A bản nhái (ISA)" msgid "Vendor" msgstr "Nhà sản xuất" From ff8b96aaede62c0c4b0dbf39ca3b0341ee3be9b3 Mon Sep 17 00:00:00 2001 From: Barnacl437 Date: Mon, 10 Mar 2025 01:20:25 +0700 Subject: [PATCH 0413/1190] fixing master branch conflict (vi-VN qt translation) --- src/qt/languages/vi-VN.po | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index abb17351b..6a2203de2 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -687,8 +687,11 @@ msgstr "Mẫu máy \"%hs\" không giả lập được do thiếu file ROM tươ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Sẽ vô hiệu hóa card đồ họa thứ hai." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Thiết bị sẽ bị bỏ qua." msgid "Machine" msgstr "Mẫu máy" From 34023692e15d8075127f16e14ae831f01b038fa0 Mon Sep 17 00:00:00 2001 From: Barnacl437 Date: Mon, 10 Mar 2025 01:24:41 +0700 Subject: [PATCH 0414/1190] conflict solving attempt #2 --- src/qt/languages/vi-VN.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 6a2203de2..93b800471 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -688,10 +688,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Card đồ họa \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Hãy chọn card đồ họa khác." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong thư mục roms/video. Sẽ vô hiệu hóa card đồ họa thứ hai." +msgstr "Card đồ họa 2 \"%hs\" không giả lập được do thiếu file ROM tương ứng trong mục roms/video. Vô hiệu hóa card đồ họa thứ hai." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Thiết bị sẽ bị bỏ qua." +msgstr "Thiết bị \"%hs\" không giả lập được do thiếu file ROM. Bỏ qua thiết bị." msgid "Machine" msgstr "Mẫu máy" From e854c5b4318b55898443c706d50b223fe29ef20d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 00:32:57 +0600 Subject: [PATCH 0415/1190] Some final fixes --- src/qt/qt_glsl_parser.cpp | 8 ++++++++ src/qt/qt_openglrenderer_pcem.cpp | 14 +++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index f43897506..a39e6d7bc 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -1,3 +1,10 @@ +#include "qt_mainwindow.hpp" +#include +#include +#include + +extern MainWindow* main_window; + #include #include #include @@ -137,6 +144,7 @@ static glslp_t *glsl_parse(const char *f) { strcpy(shader->shader_fn, f); shader->shader_program = load_file(f); if (!shader->shader_program) { + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %s").arg(shader->shader_fn)); //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); glslp_free(glslp); return 0; diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index e53b8b77b..4644dc7be 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,6 +1,7 @@ #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" +#include #include #include #include @@ -131,6 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -175,6 +177,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); @@ -577,7 +580,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - // wx_simple_messagebox("GLSL Error", "Could not load texture: %s", file); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -623,6 +626,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; @@ -1337,10 +1341,10 @@ OpenGLRendererPCem::render() struct { uint32_t x, y, w, h; } rect, video_rect; - rect.x = destination.x(); - rect.y = destination.y(); - rect.w = destination.width(); - rect.h = destination.height(); + rect.x = 0; + rect.y = 0; + rect.w = source.width(); + rect.h = source.height(); video_rect.x = source.x(); video_rect.y = source.y(); From 1ca2aabf2f5f7e2d4c6e1a466e84b3b959585775 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 00:37:20 +0600 Subject: [PATCH 0416/1190] Remove some things that shouldn't be there --- src/device/kbc_at_dev.c | 3 --- src/include/86box/keyboard.h | 11 ++--------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index 82ce31bfd..c1041e6e1 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -88,9 +88,6 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) { if (main) { kbc_at_dev_log("%s: dev->queue[%02X] = %02X;\n", dev->name, dev->queue_end, val); - if (!is_cpu_thread && kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) { - while (kbc_at_dev_queue_pos(dev, 1) == dev->fifo_mask) {} - } dev->queue[dev->queue_end] = val; dev->queue_end = (dev->queue_end + 1) & dev->fifo_mask; } else { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index b7f301a58..3a7260c72 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -22,13 +22,6 @@ #ifndef EMU_KEYBOARD_H #define EMU_KEYBOARD_H -#ifdef __cplusplus -# include -using atomic_uint = std::atomic_uint; -#else -# include -#endif - enum { DEV_KBD = 0, DEV_AUX = 1 @@ -69,8 +62,8 @@ typedef struct atkbc_dev_t { uint8_t rate; uint8_t cmd_queue_start; uint8_t cmd_queue_end; - atomic_uint queue_start; - atomic_uint queue_end; + uint8_t queue_start; + uint8_t queue_end; uint16_t flags; From 4d5907eac6d1955c1b7f7f6da09354f6a81fba3d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 9 Mar 2025 20:32:44 +0100 Subject: [PATCH 0417/1190] T128 changes of the evening (March 9th, 2025) 1. More accurate speed without stalls. 2. Added more IRQ's for AT compatibles. --- src/scsi/scsi_t128.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 6b73ae131..eada27246 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -95,7 +95,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } } } @@ -147,7 +147,7 @@ t128_read(uint32_t addr, void *priv) scsi_bus->tx_mode = PIO_TX_BUS; timer_stop(&t128->timer); } else if (!timer_is_enabled(&t128->timer)) - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); else t128->status &= ~0x04; } @@ -223,7 +223,7 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128->block_loaded = 1; t128->status &= ~0x04; - timer_on_auto(&t128->timer, 1.0); + timer_on_auto(&t128->timer, 10.0); } return 1; } @@ -252,7 +252,7 @@ t128_callback(void *priv) uint8_t status; if (scsi_bus->tx_mode != PIO_TX_BUS) - timer_on_auto(&t128->timer, scsi_bus->period / 65.0); + timer_on_auto(&t128->timer, scsi_bus->period / 60.0); if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; @@ -350,6 +350,7 @@ t128_callback(void *priv) if (!t128->block_count) { t128->block_loaded = 0; scsi_bus->bus_out |= BUS_REQ; + timer_on_auto(&t128->timer, 10.0); t128_log("IO End of read transfer\n"); } break; @@ -576,6 +577,10 @@ static const device_config_t t128_config[] = { { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 14", .value = 14 }, + { .description = "IRQ 15", .value = 15 }, { .description = "" } }, .bios = { { 0 } } From 144558e60ec806aa9643645c6774876f19a30430 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 01:33:18 +0600 Subject: [PATCH 0418/1190] Fix another string mistake --- src/qt/qt_glsl_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index a39e6d7bc..2a4c4ddd1 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -144,7 +144,7 @@ static glslp_t *glsl_parse(const char *f) { strcpy(shader->shader_fn, f); shader->shader_program = load_file(f); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %s").arg(shader->shader_fn)); + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %1").arg(shader->shader_fn)); //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); glslp_free(glslp); return 0; From 9756fa04062c7f4306939860fe49622c22998f98 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 02:00:24 +0600 Subject: [PATCH 0419/1190] Fix the parser for trailing hash comments --- src/ini.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ini.c b/src/ini.c index b4c905489..8dca54754 100644 --- a/src/ini.c +++ b/src/ini.c @@ -561,6 +561,10 @@ ini_strip_quotes(ini_t ini) while (ent != NULL) { if (ent->name[0] != '\0') { int i = 0; + int trailing_hash = strcspn(ent->data, "#"); + int trailing_quote; + ent->wdata[trailing_hash] = 0; + ent->data[trailing_hash] = 0; if (ent->wdata[0] == L'\"') { memmove(ent->wdata, &ent->wdata[1], sizeof(ent->wdata) - sizeof(wchar_t)); } @@ -574,6 +578,12 @@ ini_strip_quotes(ini_t ini) if (ent->data[strlen(ent->data) - 1] == '\"') { ent->data[strlen(ent->data) - 1] = 0; } + + trailing_quote = strcspn(ent->data, "\""); + ent->wdata[trailing_quote] = 0; + ent->data[trailing_quote] = 0; + + pclog("Section %s, entry %s, value %ls\n", sec->name, ent->name, ent->wdata); } ent = (entry_t *) ent->list.next; From cfe630e5239cd46207649028f2873223ae6224d2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 02:09:40 +0600 Subject: [PATCH 0420/1190] Temp changes --- src/qt/qt_openglrenderer_pcem.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4644dc7be..8ee4dff39 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -132,7 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); + throw opengl_init_error_pcem(tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,10 +177,9 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); - // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); - pclog("Could not compile shader: %s\n", log); + throw opengl_init_error_pcem(tr("Could not compile shader:\n%1").arg(log)); + // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); // pclog("Shader: %s\n", program); free(log); @@ -580,7 +579,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + throw opengl_init_error_pcem(tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -626,7 +625,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + throw opengl_init_error_pcem(tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; From 29b6cd484cfdd5e2477b33cfc0fe40f3e710aef1 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 Jan 2025 21:48:38 -0500 Subject: [PATCH 0421/1190] Fix a few potential segfaults found in device.c --- src/device.c | 143 ++++++++++++++++++++++++++++----------------------- 1 file changed, 79 insertions(+), 64 deletions(-) diff --git a/src/device.c b/src/device.c index 434bd3776..604f7e2f6 100644 --- a/src/device.c +++ b/src/device.c @@ -660,13 +660,15 @@ device_get_config_string(const char *str) int device_get_config_int(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -675,13 +677,15 @@ device_get_config_int(const char *str) int device_get_config_int_ex(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -690,13 +694,15 @@ device_get_config_int_ex(const char *str, int def) int device_get_config_hex16(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex16((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -705,13 +711,15 @@ device_get_config_hex16(const char *str) int device_get_config_hex20(const char *str) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_hex20((char *) device_current.name, (char *) str, cfg->default_int)); - cfg++; + cfg++; + } } return 0; @@ -720,13 +728,15 @@ device_get_config_hex20(const char *str) int device_get_config_mac(const char *str, int def) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_mac((char *) device_current.name, (char *) str, def)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_mac((char *) device_current.name, (char *) str, def)); - cfg++; + cfg++; + } } return def; @@ -735,60 +745,68 @@ device_get_config_mac(const char *str, int def) void device_set_config_int(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_int((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_int((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex16(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex16((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex16((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } void device_set_config_hex20(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_hex20((char *) device_current.name, (char *) str, val); - break; - } + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_hex20((char *) device_current.name, (char *) str, val); + break; + } cfg++; + } } } void device_set_config_mac(const char *str, int val) { - const device_config_t *cfg = device_current.dev->config; + if (device_current.dev != NULL) { + const device_config_t *cfg = device_current.dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) { - config_set_mac((char *) device_current.name, (char *) str, val); - break; + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) { + config_set_mac((char *) device_current.name, (char *) str, val); + break; + } + + cfg++; } - - cfg++; } } @@ -806,20 +824,18 @@ device_is_valid(const device_t *device, int mch) int machine_get_config_int(char *str) { - const device_t *dev = machine_get_device(machine); - const device_config_t *cfg; + const device_t *dev = machine_get_device(machine); - if (dev == NULL) - return 0; + if (dev != NULL) { + const device_config_t *cfg = dev->config; - cfg = dev->config; - while (cfg && cfg->type != CONFIG_END) { - if (!strcmp(str, cfg->name)) - return (config_get_int((char *) dev->name, str, cfg->default_int)); + while ((cfg != NULL) && (cfg->type != CONFIG_END)) { + if (!strcmp(str, cfg->name)) + return (config_get_int((char *) dev->name, str, cfg->default_int)); - cfg++; + cfg++; + } } - return 0; } @@ -830,9 +846,8 @@ machine_get_config_string(char *str) const char *ret = ""; if (dev != NULL) { - const device_config_t *cfg; + const device_config_t *cfg = dev->config; - cfg = dev->config; while ((cfg != NULL) && (cfg->type != CONFIG_END)) { if (!strcmp(str, cfg->name)) { const char *s = config_get_string((char *) dev->name, str, From a7d8f4a4e1e0808fae91ecc28149d443fc6b54d4 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 6 Jan 2025 23:30:51 -0500 Subject: [PATCH 0422/1190] Extra CONFIG_BIOS Helpers --- src/device.c | 107 +++++++++++++++++++++++++++++++++++++ src/include/86box/device.h | 9 +++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/device.c b/src/device.c index 604f7e2f6..814320c29 100644 --- a/src/device.c +++ b/src/device.c @@ -429,6 +429,113 @@ device_available(const device_t *dev) return 0; } +uint8_t +device_get_bios_type(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->bios_type; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint8_t +device_get_bios_num_files(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->files_no; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_local(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + while (bios->files_no != 0) { + printf("Internal name was: %s", internal_name); + if (!strcmp(internal_name, bios->internal_name)) + return bios->local; + bios++; + } + } + config++; + } + } + } + + return 0; +} + +uint32_t +device_get_bios_file_size(const device_t *dev, const char *internal_name) +{ + const device_config_t *config = NULL; + const device_config_bios_t *bios = NULL; + + if (dev != NULL) { + config = dev->config; + if (config != NULL) { + while (config->type != CONFIG_END) { + if (config->type == CONFIG_BIOS) { + bios = config->bios; + + /* Go through the ROM's in the device configuration. */ + while (bios->files_no != 0) { + if (!strcmp(internal_name, bios->internal_name)) + return bios->size; + bios++; + } + } + config++; + } + } + } + + return 0; +} + const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 4cc283a25..c75cbfdcc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -137,8 +137,8 @@ typedef struct device_config_spinner_t { typedef struct device_config_bios_t { const char *name; const char *internal_name; - int bios_type; - int files_no; + uint8_t bios_type; + uint8_t files_no; uint32_t local; uint32_t size; void *dev1; @@ -211,6 +211,11 @@ extern void device_speed_changed(void); extern void device_force_redraw(void); extern void device_get_name(const device_t *dev, int bus, char *name); extern int device_has_config(const device_t *dev); + +extern uint8_t device_get_bios_type(const device_t *dev, const char *internal_name); +extern uint8_t device_get_bios_num_files(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_local(const device_t *dev, const char *internal_name); +extern uint32_t device_get_bios_file_size(const device_t *dev, const char *internal_name); extern const char *device_get_bios_file(const device_t *dev, const char *internal_name, int file_no); extern int device_is_valid(const device_t *, int mch); From 6740b62d23e8443d7a44ebaf2e88bbdf9e3c2f1b Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 01:29:55 -0500 Subject: [PATCH 0423/1190] Improve empty bios file entry support --- src/device.c | 73 +++++++++++++++++++------------------- src/qt/qt_deviceconfig.cpp | 8 +++-- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/device.c b/src/device.c index 814320c29..e1af3c5f3 100644 --- a/src/device.c +++ b/src/device.c @@ -390,22 +390,21 @@ device_get_priv(const device_t *dev) int device_available(const device_t *dev) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { int roms_present = 0; - - bios = (const device_config_bios_t *) config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { int i = 0; - for (int bf = 0; bf < bios->files_no; bf++) + for (uint8_t bf = 0; bf < bios->files_no; bf++) i += !!rom_present(bios->files[bf]); if (i == bios->files_no) roms_present++; @@ -432,16 +431,16 @@ device_available(const device_t *dev) uint8_t device_get_bios_type(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->bios_type; bios++; @@ -458,16 +457,16 @@ device_get_bios_type(const device_t *dev, const char *internal_name) uint8_t device_get_bios_num_files(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->files_no; bios++; @@ -484,16 +483,16 @@ device_get_bios_num_files(const device_t *dev, const char *internal_name) uint32_t device_get_bios_local(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; - while (bios->files_no != 0) { + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { printf("Internal name was: %s", internal_name); if (!strcmp(internal_name, bios->internal_name)) return bios->local; @@ -511,18 +510,18 @@ device_get_bios_local(const device_t *dev, const char *internal_name) uint32_t device_get_bios_file_size(const device_t *dev, const char *internal_name) { - const device_config_t *config = NULL; - const device_config_bios_t *bios = NULL; - if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) return bios->size; bios++; @@ -539,18 +538,20 @@ device_get_bios_file_size(const device_t *dev, const char *internal_name) const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { - const device_config_t *config = NULL; const device_config_bios_t *bios = NULL; if (dev != NULL) { - config = dev->config; + const device_config_t *config = dev->config; if (config != NULL) { while (config->type != CONFIG_END) { if (config->type == CONFIG_BIOS) { - bios = config->bios; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; /* Go through the ROM's in the device configuration. */ - while (bios->files_no != 0) { + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { if (!strcmp(internal_name, bios->internal_name)) { if (file_no < bios->files_no) return bios->files[file_no]; diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index e2d6759ad..fff085194 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -242,8 +242,12 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) int currentIndex = -1; q = 0; - for (auto *bios = config->bios; (bios != nullptr) && (bios->name != nullptr) && - (strlen(bios->name) > 0); ++bios) { + for (auto *bios = config->bios; (bios != nullptr) && + (bios->name != nullptr) && + (bios->internal_name != nullptr) && + (strlen(bios->name) > 0) && + (strlen(bios->internal_name) > 0) && + (bios->files_no > 0); ++bios) { p = 0; for (int d = 0; d < bios->files_no; d++) p += !!rom_present(const_cast(bios->files[d])); From 4504348fffc8fb3885347c124228fa25d19f6c86 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 01:49:22 -0500 Subject: [PATCH 0424/1190] Make config_bios_t dev's into an array --- src/include/86box/device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index c75cbfdcc..fb86d2adc 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -141,8 +141,7 @@ typedef struct device_config_bios_t { uint8_t files_no; uint32_t local; uint32_t size; - void *dev1; - void *dev2; + void *dev[2]; const char *files[9]; } device_config_bios_t; From 097ea4abf2d6220b2951be2996e72e9c528d2d34 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Mar 2025 04:54:42 -0400 Subject: [PATCH 0425/1190] Two missing CONFIG_END's in qt_deviceconfig.cpp --- src/qt/qt_deviceconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index fff085194..cda52e722 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -123,7 +123,7 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep) if (config == NULL) return; - while (config->type != -1) { + while (config->type != CONFIG_END) { const int config_type = config->type & CONFIG_TYPE_MASK; /* Ignore options of the wrong class. */ @@ -376,7 +376,7 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se return; config = device->config; - while (config->type != -1) { + while (config->type != CONFIG_END) { switch (config->type) { default: break; From e84bbcac0f9e72613bd9d2d10dbf387e4d91de95 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 21:24:55 +0500 Subject: [PATCH 0426/1190] Handle libslirp 4.9.0's deprecations --- src/network/net_slirp.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 203428b83..e86ea45fd 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -155,14 +155,22 @@ net_slirp_timer_mod(void *timer, int64_t expire_timer, UNUSED(void *opaque)) } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_register_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_register_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; } static void +#if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_unregister_poll_socket(slirp_os_socket fd, void *opaque) +#else net_slirp_unregister_poll_fd(int fd, void *opaque) +#endif { (void) fd; (void) opaque; @@ -198,7 +206,11 @@ net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque) #ifdef _WIN32 static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; long bitmask = 0; @@ -216,7 +228,11 @@ net_slirp_add_poll(int fd, int events, void *opaque) } #else static int +# if SLIRP_CHECK_VERSION(4, 9, 0) +net_slirp_add_poll(slirp_os_socket fd, int events, void *opaque) +# else net_slirp_add_poll(int fd, int events, void *opaque) +# endif { net_slirp_t *slirp = (net_slirp_t *) opaque; @@ -307,8 +323,13 @@ static const SlirpCb slirp_cb = { .timer_new = net_slirp_timer_new, .timer_free = net_slirp_timer_free, .timer_mod = net_slirp_timer_mod, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .register_poll_socket = net_slirp_register_poll_socket, + .unregister_poll_socket = net_slirp_unregister_poll_socket, +#else .register_poll_fd = net_slirp_register_poll_fd, .unregister_poll_fd = net_slirp_unregister_poll_fd, +#endif .notify = net_slirp_notify }; @@ -362,7 +383,11 @@ net_slirp_thread(void *priv) bool run = true; while (run) { uint32_t timeout = -1; +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif if (timeout < 0) timeout = INFINITE; @@ -409,7 +434,11 @@ net_slirp_thread(void *priv) net_slirp_add_poll(net_event_get_fd(&slirp->stop_event), SLIRP_POLL_IN, slirp); net_slirp_add_poll(net_event_get_fd(&slirp->tx_event), SLIRP_POLL_IN, slirp); +# if SLIRP_CHECK_VERSION(4, 9, 0) + slirp_pollfds_fill_socket(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# else slirp_pollfds_fill(slirp->slirp, &timeout, net_slirp_add_poll, slirp); +# endif int ret = poll(slirp->pfd, slirp->pfd_len, timeout); From a29613a88015a5d3648e17ee6b31a92f9af11801 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 7 Mar 2025 22:20:46 +0500 Subject: [PATCH 0427/1190] Switch to slirp_new --- src/network/net_slirp.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index e86ea45fd..92c4c4ddf 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -489,10 +489,47 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ - struct in6_addr ipv6_dummy = { 0 }; /* contents don't matter; we're not using IPv6 */ + + const SlirpConfig slirp_config = { +#if SLIRP_CHECK_VERSION(4, 9, 0) + .version = 6, +#else + .version = 1, +#endif + .restricted = 0, + .in_enabled = 1, + .vnetwork = net, + .vnetmask = mask, + .vhost = host, + .in6_enabled = 0, + .vprefix_addr6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, /* fec0:: - unused */ + .vprefix_len = 64, + .vhost6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02 } }, /* fec0::2 - unused */ + .vhostname = "86Box", + .tftp_server_name = NULL, + .tftp_path = NULL, + .bootfile = NULL, + .vdhcp_start = dhcp, + .vnameserver = dns, + .vnameserver6 = { .s6_addr = { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03 } }, /* fec0::3 - unused */ + .vdnssearch = NULL, + .vdomainname = NULL, + .if_mtu = 0, + .if_mru = 0, + .disable_host_loopback = 0, + .enable_emu = 0, +#if SLIRP_CHECK_VERSION(4, 9, 0) + .outbound_addr = NULL, + .outbound_addr6 = NULL, + .disable_dns = 0, + .disable_dhcp = 0, + .mfr_id = 0, + .oob_eth_addr = { 0, 0, 0, 0, 0, 0 } +#endif + }; /* Initialize SLiRP. */ - slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6_dummy, 0, ipv6_dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6_dummy, NULL, NULL, &slirp_cb, slirp); + slirp->slirp = slirp_new(&slirp_config, &slirp_cb, slirp); if (!slirp->slirp) { slirp_log("SLiRP: initialization failed\n"); snprintf(netdrv_errbuf, NET_DRV_ERRBUF_SIZE, "SLiRP initialization failed"); From 1005bdddd46125298461e1325dafa054fe7eeac1 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Mar 2025 02:27:02 -0400 Subject: [PATCH 0428/1190] Fix warning in device.c --- src/device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/device.c b/src/device.c index e1af3c5f3..25f0b55de 100644 --- a/src/device.c +++ b/src/device.c @@ -538,8 +538,6 @@ device_get_bios_file_size(const device_t *dev, const char *internal_name) const char * device_get_bios_file(const device_t *dev, const char *internal_name, int file_no) { - const device_config_bios_t *bios = NULL; - if (dev != NULL) { const device_config_t *config = dev->config; if (config != NULL) { From ba519fa6729fd1721308a77c1a0232c3f876bfb1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 12:37:50 +0600 Subject: [PATCH 0429/1190] Strip all whitespaces as well --- src/ini.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/ini.c b/src/ini.c index 8dca54754..7a54d5396 100644 --- a/src/ini.c +++ b/src/ini.c @@ -546,6 +546,55 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +wchar_t * +trim_w(wchar_t *str) +{ + size_t len = 0; + wchar_t *frontp = str; + wchar_t *endp = NULL; + + if (str == NULL) { + return NULL; + } + if (str[0] == L'\0') { + return str; + } + + len = wcslen(str); + endp = str + len; + + /* Move the front and back pointers to address the first non-whitespace + * characters from each end. + */ + while (iswspace((wint_t) *frontp)) { + ++frontp; + } + if (endp != frontp) { + while (iswspace((wint_t) *(--endp)) && endp != frontp) { } + } + + if (frontp != str && endp == frontp) + *str = L'\0'; + else if ((str + len - 1) != endp) + *(endp + 1) = L'\0'; + + /* Shift the string so that it starts at str so that if it's dynamically + * allocated, we can still free it on the returned pointer. Note the reuse + * of endp to mean the front of the string buffer now. + */ + endp = str; + if (frontp != str) { + while (*frontp) { + *endp++ = *frontp++; + } + *endp = L'\0'; + } + + return str; +} + +extern char* trim(char* str); + void ini_strip_quotes(ini_t ini) { @@ -582,8 +631,9 @@ ini_strip_quotes(ini_t ini) trailing_quote = strcspn(ent->data, "\""); ent->wdata[trailing_quote] = 0; ent->data[trailing_quote] = 0; - - pclog("Section %s, entry %s, value %ls\n", sec->name, ent->name, ent->wdata); + + trim_w(ent->wdata); + trim(ent->data); } ent = (entry_t *) ent->list.next; From 1626ee8760ac985680be80feecaa8aada416f81f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 12:38:21 +0600 Subject: [PATCH 0430/1190] Revert "Temp changes" This reverts commit cfe630e5239cd46207649028f2873223ae6224d2. --- src/qt/qt_openglrenderer_pcem.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 8ee4dff39..4644dc7be 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -132,7 +132,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - throw opengl_init_error_pcem(tr("Program not linked:\n%1").arg(log)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,9 +177,10 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - pclog("Could not compile shader: %s\n", log); - throw opengl_init_error_pcem(tr("Could not compile shader:\n%1").arg(log)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + + pclog("Could not compile shader: %s\n", log); // pclog("Shader: %s\n", program); free(log); @@ -579,7 +580,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - throw opengl_init_error_pcem(tr("Could not load texture: %s").arg(file)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -625,7 +626,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - throw opengl_init_error_pcem(tr("Could not load shader: %1").arg(shader->shader_fn)); + QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; From dceb13f859d41185597a1e87be24d4b48bf5c283 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 13:27:29 +0600 Subject: [PATCH 0431/1190] OpenGL error messages are now reported properly --- src/qt/qt_main.cpp | 4 ++++ src/qt/qt_mainwindow.cpp | 12 ++++++++++-- src/qt/qt_mainwindow.hpp | 3 +++ src/qt/qt_openglrenderer_pcem.cpp | 18 +++++++++++------- src/qt/qt_platform.cpp | 5 +++++ 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 9d965be31..b48d272c5 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -90,6 +90,8 @@ extern "C" { #include <86box/timer.h> #include <86box/nvr.h> extern int qt_nvr_save(void); + +bool cpu_thread_running = false; } void qt_set_sequence_auto_mnemonic(bool b); @@ -444,6 +446,7 @@ main_thread_fn() } } + cpu_thread_running = false; is_quit = 1; for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if (gfxcard[i]) { @@ -736,6 +739,7 @@ main(int argc, char *argv[]) #endif plat_pause(0); + cpu_thread_running = true; main_thread = new std::thread(main_thread_fn); }); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 7e0cecdeb..85bc0de55 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -62,6 +62,8 @@ extern int qt_nvr_save(void); #ifdef MTR_ENABLED # include #endif + +extern bool cpu_thread_running; }; #include @@ -1256,7 +1258,7 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) static auto curdopause = dopause; if (event->type() == QEvent::WindowBlocked) { curdopause = dopause; - plat_pause(1); + plat_pause(isShowMessage ? 2 : 1); emit setMouseCapture(false); } else if (event->type() == QEvent::WindowUnblocked) { plat_pause(curdopause); @@ -1279,7 +1281,11 @@ void MainWindow::showMessage(int flags, const QString &header, const QString &message) { if (QThread::currentThread() == this->thread()) { - showMessage_(flags, header, message); + if (!cpu_thread_running) { + showMessageForNonQtThread(flags, header, message, nullptr); + } + else + showMessage_(flags, header, message); } else { std::atomic_bool done = false; emit showMessageForNonQtThread(flags, header, message, &done); @@ -1295,6 +1301,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = false; } + isShowMessage = true; QMessageBox box(QMessageBox::Warning, header, message, QMessageBox::NoButton, this); if (flags & (MBX_FATAL)) { box.setIcon(QMessageBox::Critical); @@ -1306,6 +1313,7 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag if (done) { *done = true; } + isShowMessage = false; if (cpu_thread_run == 0) QApplication::exit(-1); } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index dced698bb..479ed38a4 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -182,6 +182,9 @@ private: friend class RendererCommon; friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. + + + bool isShowMessage = false; }; #endif // QT_MAINWINDOW_HPP diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 4644dc7be..c8f3d3eb9 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,6 +1,8 @@ #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" +extern MainWindow* main_window; + #include #include #include @@ -26,6 +28,7 @@ extern "C" { #include <86box/86box.h> #include <86box/plat.h> +#include <86box/ui.h> #include <86box/video.h> #include <86box/path.h> #include <86box/ini.h> @@ -33,6 +36,7 @@ extern "C" { #include <86box/qt-glslp-parser.h> char gl3_shader_file[MAX_USER_SHADERS][512]; +extern bool cpu_thread_running; } #define SCALE_SOURCE 0 @@ -132,7 +136,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Program not linked:\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -177,7 +181,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not compile shader:\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log)); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); @@ -580,7 +584,8 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; @@ -626,7 +631,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); pclog("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); pclog("Could not load shader %s\n", shader->shader_fn); failed = 1; @@ -764,8 +769,7 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) #else format.setVersion(3, 2); #endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - format.setOption(QSurfaceFormat::DebugContext); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) format.setRenderableType(QSurfaceFormat::OpenGLES); @@ -1031,7 +1035,7 @@ OpenGLRendererPCem::initialize() for (auto &flag : buf_usage) flag.test_and_set(); - QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); context->doneCurrent(); isFinalized = true; diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 561c94d8a..35dbc0081 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -385,6 +385,7 @@ plat_munmap(void *ptr, size_t size) #endif } +extern bool cpu_thread_running; void plat_pause(int p) { @@ -392,6 +393,10 @@ plat_pause(int p) wchar_t title[1024]; wchar_t paused_msg[512]; + if (!cpu_thread_running && p == 1) { + p = 2; + } + if ((!!p) == dopause) { #ifdef Q_OS_WINDOWS if (source_hwnd) From acf52f702793e610508b2e978c198a7db3f430e0 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 25 Aug 2024 17:55:41 -0400 Subject: [PATCH 0432/1190] XTIDE Changes --- src/disk/hdc_xtide.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index c18a24c4e..74abc1c4d 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -46,6 +46,7 @@ #include <86box/hdc_ide.h> #include <86box/plat_unused.h> +#define ROM_PATH_TINY "roms/hdd/xtide/ide_tiny.bin" #define ROM_PATH_XT "roms/hdd/xtide/ide_xt.bin" #define ROM_PATH_XTP "roms/hdd/xtide/ide_xtp.bin" #define ROM_PATH_AT "roms/hdd/xtide/ide_at.bin" From e257569e6763a6ba91763e089cd9c8fa64440042 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 9 Feb 2025 23:40:56 -0500 Subject: [PATCH 0433/1190] Single Channel XTIDE support --- src/disk/hdc.c | 2 ++ src/disk/hdc_xtide.c | 44 ++++++++++++++++++++++++++++++++++++----- src/include/86box/hdc.h | 10 ++++++---- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/disk/hdc.c b/src/disk/hdc.c index f09a9a430..582c33428 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -72,7 +72,9 @@ static const struct { { &ide_isa_device }, { &ide_isa_2ch_device }, { &xtide_at_device }, + { &xtide_at_2ch_device }, { &xtide_at_ps2_device }, + { &xtide_at_ps2_2ch_device }, { &xta_wdxt150_device }, { &xtide_acculogic_device }, { &xtide_device }, diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 74abc1c4d..09e41b9ea 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -157,7 +157,10 @@ xtide_at_init(const device_t *info) device_get_bios_file(info, device_get_config_bios("bios"), 0), 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -203,7 +206,10 @@ xtide_at_ps2_init(UNUSED(const device_t *info)) rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); - device_add(&ide_isa_2ch_device); + if (info->local == 1) + device_add(&ide_isa_2ch_device); + else + device_add(&ide_isa_device); return xtide; } @@ -311,10 +317,24 @@ const device_t xtide_device = { }; const device_t xtide_at_device = { + .name = "PC/AT XTIDE (Primary Only)", + .internal_name = "xtide_at_1ch", + .flags = DEVICE_ISA16, + .local = 0, + .init = xtide_at_init, + .close = xtide_at_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = xtide_at_config +}; + +const device_t xtide_at_2ch_device = { .name = "PC/AT XTIDE", .internal_name = "xtide_at", .flags = DEVICE_ISA16, - .local = 0, + .local = 1, .init = xtide_at_init, .close = xtide_at_close, .reset = NULL, @@ -339,8 +359,8 @@ const device_t xtide_acculogic_device = { }; const device_t xtide_at_ps2_device = { - .name = "PS/2 AT XTIDE (1.1.5)", - .internal_name = "xtide_at_ps2", + .name = "PS/2 AT XTIDE (1.1.5) (Primary Only)", + .internal_name = "xtide_at_ps2_1ch", .flags = DEVICE_ISA16, .local = 0, .init = xtide_at_ps2_init, @@ -351,3 +371,17 @@ const device_t xtide_at_ps2_device = { .force_redraw = NULL, .config = NULL }; + +const device_t xtide_at_ps2_2ch_device = { + .name = "PS/2 AT XTIDE (1.1.5)", + .internal_name = "xtide_at_ps2", + .flags = DEVICE_ISA16, + .local = 1, + .init = xtide_at_ps2_init, + .close = xtide_at_close, + .reset = NULL, + .available = xtide_at_ps2_available, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 7f91fd61b..71f83e5e6 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -99,10 +99,12 @@ extern const device_t mcide_device; extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ extern const device_t xta_hd20_device; /* EuroPC internal */ -extern const device_t xtide_device; /* xtide_xt */ -extern const device_t xtide_at_device; /* xtide_at */ -extern const device_t xtide_acculogic_device; /* xtide_ps2 */ -extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_device; /* xtide_xt */ +extern const device_t xtide_at_device; /* xtide_at */ +extern const device_t xtide_at_2ch_device; /* xtide_at_2ch */ +extern const device_t xtide_acculogic_device; /* xtide_ps2 */ +extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ +extern const device_t xtide_at_ps2_2ch_device; /* xtide_at_ps2_2ch */ /* Miscellaneous */ extern const device_t lba_enhancer_device; From b1d68b83e7af9a271440c45826790ed767848ff3 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 01:51:36 -0500 Subject: [PATCH 0434/1190] Allow Configuration of XTIDE base and bios addr --- src/disk/hdc_xtide.c | 95 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 09e41b9ea..fc18d79db 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -137,11 +137,11 @@ xtide_init(const device_t *info) rom_init(&xtide->bios_rom, device_get_bios_file(info, device_get_config_bios("bios"), 0), - 0xc8000, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + device_get_config_hex20("bios_addr"), 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); xtide->ide_board = ide_xtide_init(); - io_sethandler(0x0300, 16, + io_sethandler(device_get_config_hex16("base"), 16, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); @@ -228,8 +228,93 @@ xtide_at_close(void *priv) free(xtide); } +// clang-format off static const device_config_t xtide_config[] = { - // clang-format off + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x300, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "200H", .value = 0x200 }, + { .description = "210H", .value = 0x210 }, + { .description = "220H", .value = 0x220 }, + { .description = "230H", .value = 0x230 }, + { .description = "240H", .value = 0x240 }, + { .description = "250H", .value = 0x250 }, + { .description = "260H", .value = 0x260 }, + { .description = "270H", .value = 0x270 }, + { .description = "280H", .value = 0x280 }, + { .description = "290H", .value = 0x290 }, + { .description = "2A0H", .value = 0x2a0 }, + { .description = "2B0H", .value = 0x2b0 }, + { .description = "2C0H", .value = 0x2c0 }, + { .description = "2D0H", .value = 0x2d0 }, + { .description = "2E0H", .value = 0x2e0 }, + { .description = "2F0H", .value = 0x2f0 }, + { .description = "300H", .value = 0x300 }, + { .description = "310H", .value = 0x310 }, + { .description = "320H", .value = 0x320 }, + { .description = "330H", .value = 0x330 }, + { .description = "340H", .value = 0x340 }, + { .description = "350H", .value = 0x350 }, + { .description = "360H", .value = 0x360 }, + { .description = "370H", .value = 0x370 }, + { .description = "380H", .value = 0x380 }, + { .description = "390H", .value = 0x390 }, + { .description = "3A0H", .value = 0x3a0 }, + { .description = "3B0H", .value = 0x3b0 }, + { .description = "3C0H", .value = 0x3c0 }, + { .description = "3D0H", .value = 0x3d0 }, + { .description = "3E0H", .value = 0x3e0 }, + { .description = "3F0H", .value = 0x3f0 }, + { NULL } + }, + .bios = { { 0 } } + }, + { + .name = "bios_addr", + .description = "BIOS Address", + .type = CONFIG_HEX20, + .default_string = NULL, + .default_int = 0xd0000, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0x00000 }, +#if 0 + // Supported on XT IDE Deluxe By Monotech + { .description = "C000H", .value = 0xc0000 }, + { .description = "C200H", .value = 0xc2000 }, + { .description = "C400H", .value = 0xc4000 }, + { .description = "C600H", .value = 0xc6000 }, +#endif + { .description = "C800H", .value = 0xc8000 }, + { .description = "CA00H", .value = 0xca000 }, + { .description = "CC00H", .value = 0xcc000 }, + { .description = "CE00H", .value = 0xce000 }, + { .description = "D000H", .value = 0xd0000 }, + { .description = "D200H", .value = 0xd2000 }, + { .description = "D400H", .value = 0xd4000 }, + { .description = "D600H", .value = 0xd6000 }, + { .description = "D800H", .value = 0xd8000 }, + { .description = "DA00H", .value = 0xda000 }, + { .description = "DC00H", .value = 0xdc000 }, + { .description = "DE00H", .value = 0xde000 }, +#if 0 + // Supported on VCFed rev 2 + { .description = "E000H", .value = 0xe0000 }, + { .description = "E400H", .value = 0xe4000 }, + { .description = "E800H", .value = 0xe8000 }, + { .description = "EC00H", .value = 0xec000 }, +#endif + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "bios", .description = "BIOS Revision", @@ -262,11 +347,9 @@ static const device_config_t xtide_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; static const device_config_t xtide_at_config[] = { - // clang-format off { .name = "bios", .description = "BIOS Revision", @@ -299,8 +382,8 @@ static const device_config_t xtide_at_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on }; +// clang-format on const device_t xtide_device = { .name = "PC/XT XTIDE", From 9e95e1e4752dcb3c01335f02d596c9592ffd6af5 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 02:42:19 -0500 Subject: [PATCH 0435/1190] Move ROM write functions to rom.c --- src/floppy/fdc_monster.c | 51 ---------------------------------------- src/include/86box/rom.h | 5 ++++ src/mem/rom.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index 1b0e2fbac..b91d4db66 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -47,57 +47,6 @@ typedef struct monster_fdc_t { char nvr_path[64]; } monster_fdc_t; -static void -rom_write(uint32_t addr, uint8_t val, void *priv) -{ - const rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read byte from BIOS at %06lX\n", addr); -#endif - - if (addr < rom->mapping.base) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writew(uint32_t addr, uint16_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read word from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 1)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - -static void -rom_writel(uint32_t addr, uint32_t val, void *priv) -{ - rom_t *rom = (rom_t *) priv; - -#ifdef ROM_TRACE - if (rom->mapping.base == ROM_TRACE) - rom_log("ROM: read long from BIOS at %06lX\n", addr); -#endif - - if (addr < (rom->mapping.base - 3)) - return; - if (addr >= (rom->mapping.base + rom->sz)) - return; - *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; -} - static void monster_fdc_close(void *priv) { diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index 83fd7cf90..331d78526 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -52,7 +52,12 @@ extern uint8_t rom_read(uint32_t addr, void *priv); extern uint16_t rom_readw(uint32_t addr, void *priv); extern uint32_t rom_readl(uint32_t addr, void *priv); +extern void rom_write(uint32_t addr, uint8_t val, void *priv); +extern void rom_writew(uint32_t addr, uint16_t val, void *priv); +extern void rom_writel(uint32_t addr, uint32_t val, void *priv); + extern void rom_get_full_path(char *dest, const char *fn); + extern FILE *rom_fopen(const char *fn, char *mode); extern int rom_getfile(char *fn, char *s, int size); extern int rom_present(const char *fn); diff --git a/src/mem/rom.c b/src/mem/rom.c index 8b2308402..666652d53 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -244,6 +244,57 @@ rom_readl(uint32_t addr, void *priv) return (*(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask]); } +void +rom_write(uint32_t addr, uint8_t val, void *priv) +{ + const rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write byte from BIOS at %06lX\n", addr); +#endif + + if (addr < rom->mapping.base) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writew(uint32_t addr, uint16_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write word from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 1)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + +void +rom_writel(uint32_t addr, uint32_t val, void *priv) +{ + rom_t *rom = (rom_t *) priv; + +#ifdef ROM_TRACE + if (rom->mapping.base == ROM_TRACE) + rom_log("ROM: write long from BIOS at %06lX\n", addr); +#endif + + if (addr < (rom->mapping.base - 3)) + return; + if (addr >= (rom->mapping.base + rom->sz)) + return; + *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; +} + int rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { From f41f26a6e08d026429fd4c59f324a31557db2426 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 10 Feb 2025 02:43:32 -0500 Subject: [PATCH 0436/1190] The xtide (XT) ROM is now optionally writable --- src/disk/hdc_xtide.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index fc18d79db..154a28cec 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -41,6 +41,7 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/timer.h> +#include <86box/nvr.h> #include <86box/device.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> @@ -58,6 +59,7 @@ typedef struct xtide_t { void *ide_board; uint8_t data_high; rom_t bios_rom; + char nvr_path[64]; } xtide_t; static void @@ -145,6 +147,18 @@ xtide_init(const device_t *info) xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); + uint8_t rom_writes_enabled = device_get_config_int("rom_writes_enabled"); + + if (rom_writes_enabled) { + mem_mapping_set_write_handler(&xtide->bios_rom.mapping, rom_write, rom_writew, rom_writel); + sprintf(xtide->nvr_path, "xtide_%i.nvr", device_get_instance()); + FILE *fp = nvr_fopen(xtide->nvr_path, "rb"); + if (fp != NULL) { + fread(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + return xtide; } @@ -193,6 +207,14 @@ xtide_close(void *priv) { xtide_t *xtide = (xtide_t *) priv; + if (xtide->nvr_path[0] != 0x00) { + FILE *fp = nvr_fopen(xtide->nvr_path, "wb"); + if (fp != NULL) { + fwrite(xtide->bios_rom.rom, 1, 0x2000, fp); + fclose(fp); + } + } + free(xtide); ide_xtide_close(); @@ -275,6 +297,17 @@ static const device_config_t xtide_config[] = { }, .bios = { { 0 } } }, + { + .name = "rom_writes_enabled", + .description = "Enable BIOS extension ROM Writes", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "bios_addr", .description = "BIOS Address", From 837c0d369e4f6ea1613e3ad127b4e1271581cd32 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 13:43:07 -0500 Subject: [PATCH 0437/1190] A few cleanups in qt_settingssound.cpp --- src/qt/qt_settingssound.cpp | 88 +++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index e0572c3d8..cca903076 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -50,13 +50,15 @@ void SettingsSound::save() { for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - sound_card_current[i] = cbox->currentData().toInt(); + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + sound_card_current[i] = cbox->currentData().toInt(); } midi_output_device_current = ui->comboBoxMidiOut->currentData().toInt(); - midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); - mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; + + midi_input_device_current = ui->comboBoxMidiIn->currentData().toInt(); + + mpu401_standalone_enable = ui->checkBoxMPU401->isChecked() ? 1 : 0; sound_is_float = ui->checkBoxFloat32->isChecked() ? 1 : 0; @@ -74,12 +76,13 @@ SettingsSound::onCurrentMachineChanged(const int machineId) int c; int selectedRow; + // Sound Card for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - auto * cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - auto * model = cbox->model(); - const auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + c = 0; + auto model = cbox->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; while (true) { /* Skip "internal" if machine doesn't have it or this is not the primary card. */ @@ -88,17 +91,21 @@ SettingsSound::onCurrentMachineChanged(const int machineId) continue; } - auto name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); + const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } - if (sound_card_available(c) && device_is_valid(sound_card_getdevice(c), machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == sound_card_current[i]) { - selectedRow = row - removeRows; + if (sound_card_available(c)) { + const device_t *sound_dev = sound_card_getdevice(c); + if (device_is_valid(sound_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == sound_card_current[i]) { + selectedRow = row - removeRows; + } } } + c++; } @@ -108,12 +115,14 @@ SettingsSound::onCurrentMachineChanged(const int machineId) cbox->setCurrentIndex(selectedRow); } - auto model = ui->comboBoxMidiOut->model(); - auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + // Midi Out + c = 0; + auto model = ui->comboBoxMidiOut->model(); + auto removeRows = model->rowCount(); + selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_out_device_getdevice(c), midi_out_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -124,19 +133,23 @@ SettingsSound::onCurrentMachineChanged(const int machineId) selectedRow = row - removeRows; } } + c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiOut->setEnabled(model->rowCount() > 0); ui->comboBoxMidiOut->setCurrentIndex(-1); ui->comboBoxMidiOut->setCurrentIndex(selectedRow); + // Midi In + c = 0; model = ui->comboBoxMidiIn->model(); removeRows = model->rowCount(); - c = 0; selectedRow = 0; + while (true) { - QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); + const QString name = DeviceConfig::DeviceName(midi_in_device_getdevice(c), midi_in_device_get_internal_name(c), 0); if (name.isEmpty()) { break; } @@ -150,14 +163,19 @@ SettingsSound::onCurrentMachineChanged(const int machineId) c++; } + model->removeRows(0, removeRows); ui->comboBoxMidiIn->setEnabled(model->rowCount() > 0); ui->comboBoxMidiIn->setCurrentIndex(-1); ui->comboBoxMidiIn->setCurrentIndex(selectedRow); + // Standalone MPU401 ui->checkBoxMPU401->setChecked(mpu401_standalone_enable > 0); + + // Float32 Sound ui->checkBoxFloat32->setChecked(sound_is_float > 0); + // FM Driver switch (fm_driver) { case FM_DRV_YMFM: ui->radioButtonYMFM->setChecked(true); @@ -193,6 +211,7 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) return; } int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + if (sndCard == SOUND_INTERNAL) ui->pushButtonConfigureSoundCard1->setEnabled(machine_has_flags(machineId, MACHINE_SOUND) && device_has_config(machine_get_snd_device(machineId))); @@ -203,8 +222,9 @@ SettingsSound::on_comboBoxSoundCard1_currentIndexChanged(int index) void SettingsSound::on_pushButtonConfigureSoundCard1_clicked() { - int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard1->currentData().toInt(); + auto *device = sound_card_getdevice(sndCard); + if (sndCard == SOUND_INTERNAL) device = machine_get_snd_device(machineId); DeviceConfig::ConfigureDevice(device, 1, qobject_cast(Settings::settings)); @@ -216,15 +236,17 @@ SettingsSound::on_comboBoxSoundCard2_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + ui->pushButtonConfigureSoundCard2->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard2_clicked() { - int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); DeviceConfig::ConfigureDevice(device, 2, qobject_cast(Settings::settings)); } @@ -234,15 +256,18 @@ SettingsSound::on_comboBoxSoundCard3_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + ui->pushButtonConfigureSoundCard3->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard3_clicked() { - int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 3, qobject_cast(Settings::settings)); } @@ -252,15 +277,18 @@ SettingsSound::on_comboBoxSoundCard4_currentIndexChanged(int index) if (index < 0) { return; } + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + ui->pushButtonConfigureSoundCard4->setEnabled(sound_card_has_config(sndCard)); } void SettingsSound::on_pushButtonConfigureSoundCard4_clicked() { - int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); - auto *device = sound_card_getdevice(sndCard); + int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); + const device_t *device = sound_card_getdevice(sndCard); + DeviceConfig::ConfigureDevice(device, 4, qobject_cast(Settings::settings)); } @@ -270,6 +298,7 @@ SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiOut->setEnabled(midi_out_device_has_config(ui->comboBoxMidiOut->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); @@ -288,6 +317,7 @@ SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) if (index < 0) { return; } + ui->pushButtonConfigureMidiIn->setEnabled(midi_in_device_has_config(ui->comboBoxMidiIn->currentData().toInt())); ui->checkBoxMPU401->setEnabled(allowMpu401(ui) && (machine_has_bus(machineId, MACHINE_BUS_ISA) || machine_has_bus(machineId, MACHINE_BUS_MCA))); ui->pushButtonConfigureMPU401->setEnabled(allowMpu401(ui) && ui->checkBoxMPU401->isChecked()); From 727bfc0745d599ad32f04cb055070a929771cd27 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 19:25:03 -0500 Subject: [PATCH 0438/1190] A few cleanups in qt_settingsstoragecontrollers.cpp --- src/qt/qt_settingsstoragecontrollers.cpp | 47 +++++++++++++----------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index a86362909..4adfe1546 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -52,8 +52,8 @@ void SettingsStorageControllers::save() { /* Storage devices category */ - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); scsi_card_current[i] = cbox->currentData().toInt(); } hdc_current[0] = ui->comboBoxHD->currentData().toInt(); @@ -71,10 +71,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) this->machineId = machineId; /*HD controller config*/ + int c = 0; auto *model = ui->comboBoxHD->model(); auto removeRows = model->rowCount(); - int c = 0; int selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ if ((c == 1) && (machine_has_flags(machineId, MACHINE_HDC) == 0)) { @@ -88,7 +89,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (hdc_available(c)) { - auto *hdc_dev = hdc_get_device(c); + const device_t *hdc_dev = hdc_get_device(c); if (device_is_valid(hdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -124,7 +125,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (fdc_card_available(c)) { - auto *fdc_dev = fdc_card_getdevice(c); + const device_t *fdc_dev = fdc_card_getdevice(c); if (device_is_valid(fdc_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -141,10 +142,11 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxFD->setCurrentIndex(selectedRow); /*CD interface controller config*/ - model = ui->comboBoxCDInterface->model(); - removeRows = model->rowCount(); - c = 0; + c = 0; + model = ui->comboBoxCDInterface->model(); + removeRows = model->rowCount(); selectedRow = 0; + while (true) { /* Skip "internal" if machine doesn't have it. */ QString name = DeviceConfig::DeviceName(cdrom_interface_get_device(c), cdrom_interface_get_internal_name(c), 1); @@ -153,7 +155,7 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) } if (cdrom_interface_available(c)) { - auto *cdrom_interface_dev = cdrom_interface_get_device(c); + const device_t *cdrom_interface_dev = cdrom_interface_get_device(c); if (device_is_valid(cdrom_interface_dev, machineId)) { int row = Models::AddEntry(model, name, c); @@ -169,21 +171,21 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxCDInterface->setCurrentIndex(-1); ui->comboBoxCDInterface->setCurrentIndex(selectedRow); - for (int i = 0; i < SCSI_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); - model = cbox->model(); - removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + c = 0; + model = cbox->model(); + removeRows = model->rowCount(); + selectedRow = 0; while (true) { - auto name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); + QString name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); if (name.isEmpty()) { break; } if (scsi_card_available(c)) { - auto *scsi_dev = scsi_card_getdevice(c); + const device_t *scsi_dev = scsi_card_getdevice(c); if (device_is_valid(scsi_dev, machineId)) { int row = Models::AddEntry(model, name, c); if (c == scsi_card_current[i]) { @@ -236,7 +238,8 @@ SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0); } -void SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) +void +SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) { if (index < 0) { return; @@ -346,14 +349,14 @@ SettingsStorageControllers::on_pushButtonSCSI4_clicked() DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4, qobject_cast(Settings::settings)); } -void SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) +void +SettingsStorageControllers::on_checkBoxLbaEnhancer_stateChanged(int arg1) { ui->pushButtonConfigureLbaEnhancer->setEnabled(arg1 != 0); } - -void SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() +void +SettingsStorageControllers::on_pushButtonConfigureLbaEnhancer_clicked() { DeviceConfig::ConfigureDevice(&lba_enhancer_device); } - From fc639750ac91c48873219d167934f923bcd90b83 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 21 Feb 2025 20:02:28 -0500 Subject: [PATCH 0439/1190] Fix three warnings --- src/cdrom/cdrom.c | 2 +- src/scsi/scsi_cdrom.c | 2 +- src/video/vid_ps55da2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 8ebcfea1f..aea1afb94 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1159,7 +1159,7 @@ cdrom_get_from_name(const char *s) wchar_t tempmsg[2048]; sprintf(n, "WARNING: CD-ROM \"%s\" not found - contact 86Box support\n", s); swprintf(tempmsg, sizeof_w(tempmsg), L"%hs", n); - pclog(n); + pclog("%s", n); ui_msgbox_header(MBX_INFO, plat_get_string(STRING_HW_NOT_AVAILABLE_TITLE), tempmsg); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 04c6532df..cc9cc40c1 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -373,7 +373,7 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) if (fp) { if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, fp) != 0x10) log_fatal(dev->log, "scsi_cdrom_mode_sense_load(): Error reading data\n"); - (void) fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, + (void) !fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, fp); fclose(fp); } diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 823ef4d2f..db2035717 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3101,7 +3101,7 @@ da2_loadfont(char *fname, void *p) } uint32_t j = 0; while (ftell(mfile) < fsize) { - fread(&buf, sizeof(uint8_t), 1, mfile); + (void) !fread(&buf, sizeof(uint8_t), 1, mfile); da2->mmio.font[j] = buf; j++; } From 6b6e7b404b4b6400c3e1fef523a2c8a21e45dfc2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 5 Jul 2024 19:15:49 -0400 Subject: [PATCH 0440/1190] Less magic numbers in via_vt82c49x.c --- src/chipset/via_vt82c49x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_vt82c49x.c b/src/chipset/via_vt82c49x.c index 3aaef55a6..f8a5bb593 100644 --- a/src/chipset/via_vt82c49x.c +++ b/src/chipset/via_vt82c49x.c @@ -275,8 +275,8 @@ vt82c49x_write(uint16_t addr, uint8_t val, void *priv) case 0x71: if (dev->has_ide) { ide_pri_disable(); - ide_set_base(0, (val & 0x40) ? 0x170 : 0x1f0); - ide_set_side(0, (val & 0x40) ? 0x376 : 0x3f6); + ide_set_base(0, (val & 0x40) ? HDC_SECONDARY_BASE : HDC_PRIMARY_BASE); + ide_set_side(0, (val & 0x40) ? HDC_SECONDARY_SIDE : HDC_PRIMARY_SIDE); if (val & 0x01) ide_pri_enable(); vt82c49x_log("VT82C496 IDE now %sabled as %sary\n", (val & 0x01) ? "en" : "dis", From bb155ea9ef9c575e90f4708c43c9ad0c09005029 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 29 Dec 2023 23:00:13 -0500 Subject: [PATCH 0441/1190] Cleanups in vid_s3_virge.c --- src/video/vid_s3_virge.c | 1595 +++++++++++++++++++------------------- 1 file changed, 813 insertions(+), 782 deletions(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 904d4a4cf..cc0985c02 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -53,10 +53,10 @@ static uint64_t virge_time = 0; static int dither[4][4] = { - {0, 4, 1, 5}, - {6, 2, 7, 3}, - {1, 5, 0, 4}, - {7, 3, 6, 2} + { 0, 4, 1, 5 }, + { 6, 2, 7, 3 }, + { 1, 5, 0, 4 }, + { 7, 3, 6, 2 } }; #define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" @@ -112,80 +112,80 @@ enum { }; enum { - FIFO_INVALID = (0x00 << 24), - FIFO_WRITE_BYTE = (0x01 << 24), - FIFO_WRITE_WORD = (0x02 << 24), + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), FIFO_WRITE_DWORD = (0x03 << 24) }; typedef struct { - uint32_t addr_type; - uint32_t val; + uint32_t addr_type; + uint32_t val; } fifo_entry_t; typedef struct s3d_t { - uint32_t cmd_set; - int clip_l; - int clip_r; - int clip_t; - int clip_b; + uint32_t cmd_set; + int clip_l; + int clip_r; + int clip_t; + int clip_b; - uint32_t dest_base; - uint32_t dest_str; + uint32_t dest_base; + uint32_t dest_str; - uint32_t z_base; - uint32_t z_str; + uint32_t z_base; + uint32_t z_str; - uint32_t tex_base; - uint32_t tex_bdr_clr; - uint32_t tbv; - uint32_t tbu; - int32_t TdVdX; - int32_t TdUdX; - int32_t TdVdY; - int32_t TdUdY; - uint32_t tus; - uint32_t tvs; + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv; + uint32_t tbu; + int32_t TdVdX; + int32_t TdUdX; + int32_t TdVdY; + int32_t TdUdY; + uint32_t tus; + uint32_t tvs; - int32_t TdZdX; - int32_t TdZdY; - uint32_t tzs; + int32_t TdZdX; + int32_t TdZdY; + uint32_t tzs; - int32_t TdWdX; - int32_t TdWdY; - uint32_t tws; + int32_t TdWdX; + int32_t TdWdY; + uint32_t tws; - int32_t TdDdX; - int32_t TdDdY; - uint32_t tds; + int32_t TdDdX; + int32_t TdDdY; + uint32_t tds; - int16_t TdGdX; - int16_t TdBdX; - int16_t TdRdX; - int16_t TdAdX; - int16_t TdGdY; - int16_t TdBdY; - int16_t TdRdY; - int16_t TdAdY; - uint32_t tgs; - uint32_t tbs; - uint32_t trs; - uint32_t tas; + int16_t TdGdX; + int16_t TdBdX; + int16_t TdRdX; + int16_t TdAdX; + int16_t TdGdY; + int16_t TdBdY; + int16_t TdRdY; + int16_t TdAdY; + uint32_t tgs; + uint32_t tbs; + uint32_t trs; + uint32_t tas; - uint32_t TdXdY12; - uint32_t txend12; - uint32_t TdXdY01; - uint32_t txend01; - uint32_t TdXdY02; - uint32_t txs; - uint32_t tys; - int ty01; - int ty12; - int tlr; + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01; + int ty12; + int tlr; - uint8_t fog_r; - uint8_t fog_g; - uint8_t fog_b; + uint8_t fog_r; + uint8_t fog_g; + uint8_t fog_b; } s3d_t; typedef struct virge_t { @@ -193,41 +193,41 @@ typedef struct virge_t { mem_mapping_t mmio_mapping; mem_mapping_t new_mmio_mapping; - rom_t bios_rom; + rom_t bios_rom; - svga_t svga; + svga_t svga; - uint8_t bank; - uint8_t ma_ext; + uint8_t bank; + uint8_t ma_ext; - uint8_t virge_id; - uint8_t virge_id_high; - uint8_t virge_id_low; - uint8_t virge_rev; + uint8_t virge_id; + uint8_t virge_id_high; + uint8_t virge_id_low; + uint8_t virge_rev; - uint32_t linear_base; - uint32_t linear_size; + uint32_t linear_base; + uint32_t linear_size; - uint8_t pci_regs[256]; - uint8_t pci_slot; + uint8_t pci_regs[256]; + uint8_t pci_slot; - int chip; + int chip; - int bilinear_enabled; - int dithering_enabled; - int memory_size; + int bilinear_enabled; + int dithering_enabled; + int memory_size; - int pixel_count; - int tri_count; + int pixel_count; + int tri_count; - thread_t * render_thread; - event_t * wake_render_thread; - event_t * wake_main_thread; - event_t * not_full_event; + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; - uint32_t hwc_fg_col; - uint32_t hwc_bg_col; - int hwc_col_stack_pos; + uint32_t hwc_fg_col; + uint32_t hwc_bg_col; + int hwc_col_stack_pos; struct { uint32_t src_base; @@ -260,13 +260,13 @@ typedef struct virge_t { int lycnt; int line_dir; - int src_x; - int src_y; - int dest_x; - int dest_y; - int w; - int h; - uint8_t rop; + int src_x; + int src_y; + int dest_x; + int dest_y; + int w; + int h; + uint8_t rop; int data_left_count; uint32_t data_left; @@ -282,15 +282,16 @@ typedef struct virge_t { uint32_t plxstart; uint32_t pystart; uint32_t pycnt; - uint32_t dest_l, dest_r; + uint32_t dest_l; + uint32_t dest_r; } s3d; - s3d_t s3d_tri; + s3d_t s3d_tri; - s3d_t s3d_buffer[RB_SIZE]; - atomic_int s3d_read_idx; - atomic_int s3d_write_idx; - atomic_int s3d_busy; + s3d_t s3d_buffer[RB_SIZE]; + atomic_int s3d_read_idx; + atomic_int s3d_write_idx; + atomic_int s3d_busy; struct { uint32_t pri_ctrl; @@ -317,88 +318,89 @@ typedef struct virge_t { uint32_t sec_start; uint32_t sec_size; - int sdif; + int sdif; - int pri_x; - int pri_y; - int pri_w; - int pri_h; - int sec_x; - int sec_y; - int sec_w; - int sec_h; + int pri_x; + int pri_y; + int pri_w; + int pri_h; + int sec_x; + int sec_y; + int sec_w; + int sec_h; } streams; fifo_entry_t fifo[FIFO_SIZE]; atomic_int fifo_read_idx, fifo_write_idx; atomic_int fifo_thread_run, render_thread_run; - thread_t * fifo_thread; - event_t *wake_fifo_thread; - event_t * fifo_not_full_event; + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; - atomic_int virge_busy; - atomic_uint irq_pending; + atomic_int virge_busy; + atomic_uint irq_pending; - uint8_t subsys_stat; - uint8_t subsys_cntl; + uint8_t subsys_stat; + uint8_t subsys_cntl; - int local; + int local; - uint8_t serialport; + uint8_t serialport; - uint8_t irq_state; - uint8_t advfunc_cntl; + uint8_t irq_state; + uint8_t advfunc_cntl; - void *i2c, *ddc; + void *i2c, *ddc; - int onboard; - int fifo_slots_num; + int onboard; + int fifo_slots_num; - uint32_t vram_mask; + uint32_t vram_mask; - uint8_t reg6b; - uint8_t lfb_bios; - uint8_t int_line; - uint8_t cmd_dma; + uint8_t reg6b; + uint8_t lfb_bios; + uint8_t int_line; + uint8_t cmd_dma; - uint32_t cmd_dma_base; - uint32_t cmd_dma_buf_size; - uint32_t cmd_dma_buf_size_mask; - uint32_t cmd_base_addr; - uint32_t cmd_dma_write_ptr_reg; - uint32_t cmd_dma_write_ptr_update; - uint32_t cmd_dma_read_ptr_reg; - uint32_t dma_val; - uint32_t dma_dbl_words; - uint32_t dma_mmio_addr; - uint32_t dma_data_type; + uint32_t cmd_dma_base; + uint32_t cmd_dma_buf_size; + uint32_t cmd_dma_buf_size_mask; + uint32_t cmd_base_addr; + uint32_t cmd_dma_write_ptr_reg; + uint32_t cmd_dma_write_ptr_update; + uint32_t cmd_dma_read_ptr_reg; + uint32_t dma_val; + uint32_t dma_dbl_words; + uint32_t dma_mmio_addr; + uint32_t dma_data_type; - int pci; - int is_agp; + int pci; + int is_agp; - pc_timer_t irq_timer; + pc_timer_t irq_timer; } virge_t; static __inline void -wake_fifo_thread(virge_t *virge) { +wake_fifo_thread(virge_t *virge) +{ /* Wake up FIFO thread if moving from idle */ thread_set_event(virge->wake_fifo_thread); } -static virge_t *reset_state = NULL; +static virge_t *reset_state = NULL; static video_timings_t timing_diamond_stealth3d_2000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_diamond_stealth3d_3000_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 4, .read_b = 26, .read_w = 26, .read_l = 42 }; static video_timings_t timing_virge_dx_pci = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; static video_timings_t timing_virge_agp = { .type = VIDEO_AGP, .write_b = 2, .write_w = 2, .write_l = 3, .read_b = 28, .read_w = 28, .read_l = 45 }; -static void queue_triangle(virge_t *virge); +static void queue_triangle(virge_t *virge); -static void s3_virge_recalctimings(svga_t *svga); -static void s3_virge_updatemapping(virge_t *virge); +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); -static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv); static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *priv); @@ -407,33 +409,33 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv); static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv); static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv); -static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type); enum { - CMD_SET_AE = 1, - CMD_SET_HC = (1 << 1), + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), - CMD_SET_FORMAT_MASK = (7 << 2), - CMD_SET_FORMAT_8 = (0 << 2), - CMD_SET_FORMAT_16 = (1 << 2), - CMD_SET_FORMAT_24 = (2 << 2), + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), - CMD_SET_MS = (1 << 6), - CMD_SET_IDS = (1 << 7), - CMD_SET_MP = (1 << 8), - CMD_SET_TP = (1 << 9), + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), - CMD_SET_ITA_MASK = (3 << 10), - CMD_SET_ITA_BYTE = (0 << 10), - CMD_SET_ITA_WORD = (1 << 10), - CMD_SET_ITA_DWORD = (2 << 10), + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), - CMD_SET_ZUP = (1 << 23), + CMD_SET_ZUP = (1 << 23), - CMD_SET_ZB_MODE = (3 << 24), + CMD_SET_ZB_MODE = (3 << 24), - CMD_SET_XP = (1 << 25), - CMD_SET_YP = (1 << 26), + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), CMD_SET_COMMAND_MASK = (15 << 27) }; @@ -444,11 +446,11 @@ enum { #define CMD_SET_TWE (1 << 26) enum { - CMD_SET_COMMAND_BITBLT = (0 << 27), - CMD_SET_COMMAND_RECTFILL = (2 << 27), - CMD_SET_COMMAND_LINE = (3 << 27), - CMD_SET_COMMAND_POLY = (5 << 27), - CMD_SET_COMMAND_NOP = (15 << 27) + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) }; #define INT_VSY (1 << 0) @@ -475,7 +477,7 @@ s3_virge_update_irqs(virge_t *virge) } static void -s3_virge_update_irq_timer(void* priv) +s3_virge_update_irq_timer(void *priv) { virge_t *virge = (virge_t *) priv; @@ -491,7 +493,7 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *priv) { virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t old; uint32_t cursoraddr; @@ -538,7 +540,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) return; - old = svga->crtc[svga->crtcreg]; + old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; switch (svga->crtcreg) { @@ -622,7 +624,7 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) switch (virge->hwc_col_stack_pos) { case 0: virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; - break; + break; case 1: virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); break; @@ -705,9 +707,10 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) } static uint8_t -s3_virge_in(uint16_t addr, void *priv) { +s3_virge_in(uint16_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - svga_t * svga = &virge->svga; + svga_t *svga = &virge->svga; uint8_t ret; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -758,7 +761,7 @@ s3_virge_in(uint16_t addr, void *priv) { break; case 0x45: virge->hwc_col_stack_pos = 0; - ret = svga->crtc[0x45]; + ret = svga->crtc[0x45]; break; case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); @@ -812,8 +815,10 @@ s3_virge_in(uint16_t addr, void *priv) { static void s3_virge_recalctimings(svga_t *svga) { - int n, r, m; - double freq; + int n; + int r; + int m; + double freq; virge_t *virge = (virge_t *) svga->priv; svga->hdisp = svga->hdisp_old; @@ -857,7 +862,7 @@ s3_virge_recalctimings(svga_t *svga) else r = (svga->seqregs[0x12] >> 5) & 0x03; - m = svga->seqregs[0x13] & 0x7f; + m = svga->seqregs[0x13] & 0x7f; freq = (((double) m + 2) / (((double) n + 2) * (double) (1 << r))) * 14318184.0; svga->clock = (cpuclock * (float) (1ULL << 32)) / freq; @@ -876,7 +881,7 @@ s3_virge_recalctimings(svga_t *svga) svga->vblankstart = svga->dispend; video_force_resize_set_monitor(1, svga->monitor_index); } else { - svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; + svga->hblankstart = (((svga->crtc[0x5d] & 0x04) >> 2) << 8) + svga->crtc[2]; svga->hblank_end_val = (svga->crtc[3] & 0x1f) | (((svga->crtc[5] & 0x80) >> 7) << 5) | (((svga->crtc[0x5d] & 0x08) >> 3) << 6); @@ -894,39 +899,39 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = 256; svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); - if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) switch (svga->bpp) { - case 8: - svga->render = svga_render_8bpp_highres; - break; - case 15: - svga->render = svga_render_15bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 16: - svga->render = svga_render_16bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { - svga->hdisp >>= 1; - svga->dots_per_clock >>= 1; - } - break; - case 24: - svga->render = svga_render_24bpp_highres; - if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) - svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ - break; - case 32: - svga->render = svga_render_32bpp_highres; - break; + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 16: + svga->render = svga_render_16bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) { + svga->hdisp >>= 1; + svga->dots_per_clock >>= 1; + } + break; + case 24: + svga->render = svga_render_24bpp_highres; + if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) + svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; - default: - break; - } + default: + break; + } - svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && - (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; } else { /*Streams mode*/ if (virge->chip < S3_VIRGEGX2) { if (virge->streams.buffer_ctrl & 1) @@ -960,7 +965,7 @@ s3_virge_recalctimings(svga_t *svga) else svga->overlay.addr = virge->streams.sec_fb0; - svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.ena = (svga->overlay.x >= 0); svga->overlay.h_acc = virge->streams.dda_horiz_accumulator; svga->overlay.v_acc = virge->streams.dda_vert_accumulator; @@ -968,8 +973,7 @@ s3_virge_recalctimings(svga_t *svga) svga->rowoffset = virge->streams.pri_stride >> 3; if (virge->chip <= S3_VIRGEDX && svga->overlay.ena) { - svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || - (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); + svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); } else if (virge->chip >= S3_VIRGEGX2 && svga->overlay.ena) { /* 0x20 = Secondary Stream enabled */ /* 0x2000 = Primary Stream enabled */ @@ -1028,7 +1032,8 @@ s3_virge_recalctimings(svga_t *svga) } static void -s3_virge_updatemapping(virge_t *virge) { +s3_virge_updatemapping(virge_t *virge) +{ svga_t *svga = &virge->svga; if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { @@ -1040,7 +1045,7 @@ s3_virge_updatemapping(virge_t *virge) { } switch (svga->gdcreg[6] & 0xc) { /*Banked framebuffer*/ - case 0x0: /*128k at A0000*/ + case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; break; @@ -1114,7 +1119,8 @@ s3_virge_updatemapping(virge_t *virge) { } static void -s3_virge_vblank_start(svga_t *svga) { +s3_virge_vblank_start(svga_t *svga) +{ virge_t *virge = (virge_t *) svga->priv; if (virge->irq_pending) @@ -1124,7 +1130,8 @@ s3_virge_vblank_start(svga_t *svga) { } static void -s3_virge_wait_fifo_idle(virge_t *virge) { +s3_virge_wait_fifo_idle(virge_t *virge) +{ while (!FIFO_EMPTY) { wake_fifo_thread(virge); thread_wait_event(virge->fifo_not_full_event, 1); @@ -1135,7 +1142,7 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *priv) { virge_t *virge = (virge_t *) priv; - uint8_t ret; + uint8_t ret; switch (addr & 0xffff) { case 0x8504: @@ -1216,9 +1223,10 @@ s3_virge_mmio_read_w(uint32_t addr, void *priv) } static uint32_t -s3_virge_mmio_read_l(uint32_t addr, void *priv) { +s3_virge_mmio_read_l(uint32_t addr, void *priv) +{ virge_t *virge = (virge_t *) priv; - uint32_t ret = 0xffffffff; + uint32_t ret = 0xffffffff; switch (addr & 0xfffc) { case 0x8180: @@ -1447,7 +1455,7 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv) { break; } - //pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); + // pclog("MMIO ReadL=%04x, ret=%08x.\n", addr & 0xfffc, ret); return ret; } @@ -1461,15 +1469,15 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) int y = (addr >> 3) & 7; int color; int byte; - uint32_t newaddr = addr; - virge->s3d.pattern_8[y * 8 + x] = val & 0xff; + uint32_t newaddr = addr; + virge->s3d.pattern_8[y * 8 + x] = val & 0xff; virge->s3d.pattern_8[y * 8 + x + 1] = val >> 8; virge->s3d.pattern_8[y * 8 + x + 2] = val >> 16; virge->s3d.pattern_8[y * 8 + x + 3] = val >> 24; - x = (addr >> 1) & 6; - y = (addr >> 4) & 7; - virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y * 8 + x] = val & 0xffff; virge->s3d.pattern_16[y * 8 + x + 1] = val >> 16; newaddr &= 0x00ff; @@ -1482,22 +1490,21 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.pattern_24[y * 8 + x] |= ((val >> byte) & 0xff) << color; } - x = (addr >> 2) & 7; - y = (addr >> 5) & 7; + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; virge->s3d.pattern_32[y * 8 + x] = val & 0xffffff; - } break; + } + break; case 0xa4d4: case 0xa8d4: case 0xacd4: - virge->s3d.src_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.src_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4d8: case 0xa8d8: case 0xacd8: - virge->s3d.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xa4dc: case 0xa8dc: @@ -1515,7 +1522,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xa8e4: case 0xace4: virge->s3d.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xa4e8: case 0xace8: @@ -1548,7 +1555,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) s3_virge_bitblt(virge, -1, 0); break; case 0xa504: - virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_width = (val >> 16) & 0x7ff; virge->s3d.r_height = val & 0x7ff; break; case 0xa508: @@ -1566,7 +1573,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lxend1 = val & 0x7ff; break; case 0xa970: - virge->s3d.ldx = (int32_t)val; + virge->s3d.ldx = (int32_t) val; break; case 0xa974: virge->s3d.lxstart = val; @@ -1575,7 +1582,7 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) virge->s3d.lystart = val & 0x7ff; break; case 0xa97c: - virge->s3d.lycnt = val & 0x7ff; + virge->s3d.lycnt = val & 0x7ff; virge->s3d.line_dir = val >> 31; if (virge->s3d.cmd_set & CMD_SET_AE) s3_virge_bitblt(virge, -1, 0); @@ -1604,13 +1611,11 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0d4: case 0xb4d4: - virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.z_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0d8: case 0xb4d8: - virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.dest_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb0dc: case 0xb4dc: @@ -1625,15 +1630,14 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb0e4: case 0xb4e4: virge->s3d_tri.dest_str = (val >> 16) & 0xff8; - virge->s3d.src_str = val & 0xff8; + virge->s3d.src_str = val & 0xff8; break; case 0xb0e8: case 0xb4e8: virge->s3d_tri.z_str = val & 0xff8; break; case 0xb4ec: - virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? - (val & 0x7ffff8) : (val & 0x3ffff8)); + virge->s3d_tri.tex_base = val & ((virge->memory_size == 8) ? (val & 0x7ffff8) : (val & 0x3ffff8)); break; case 0xb4f0: virge->s3d_tri.tex_bdr_clr = val & 0xffffff; @@ -1750,17 +1754,17 @@ s3_virge_mmio_write_fifo_l(virge_t *virge, uint32_t addr, uint32_t val) case 0xb57c: virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; virge->s3d_tri.ty12 = val & 0x7ff; - virge->s3d_tri.tlr = val >> 31; + virge->s3d_tri.tlr = val >> 31; if (virge->s3d_tri.cmd_set & CMD_SET_AE) queue_triangle(virge); - break; + break; } } static void fifo_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->fifo_thread_run) { thread_set_event(virge->fifo_not_full_event); @@ -1768,10 +1772,10 @@ fifo_thread(void *param) thread_reset_event(virge->wake_fifo_thread); virge->virge_busy = 1; while (!FIFO_EMPTY) { - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; - uint32_t val = fifo->val; + uint32_t val = fifo->val; switch (fifo->addr_type & FIFO_TYPE) { case FIFO_WRITE_BYTE: @@ -1811,7 +1815,7 @@ fifo_thread(void *param) virge->virge_busy = 0; virge->subsys_stat |= (INT_FIFO_EMP | INT_3DF_EMP); if (virge->cmd_dma) - virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); + virge->subsys_stat |= (INT_HOST_DONE | INT_CMD_DONE); virge->irq_pending++; } @@ -1820,8 +1824,8 @@ fifo_thread(void *param) static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) { - fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; - int limit = 0; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int limit = 0; if (type == FIFO_WRITE_DWORD) { switch (addr & 0xfffc) { @@ -1848,7 +1852,7 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) } } - fifo->val = val; + fifo->val = val; fifo->addr_type = (addr & FIFO_ADDR) | type; virge->fifo_write_idx++; @@ -1924,7 +1928,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_ctrl = val; break; case 0x8190: - virge->streams.sec_ctrl = val; + virge->streams.sec_ctrl = val; virge->streams.dda_horiz_accumulator = val & 0xfff; if (val & 0x1000) virge->streams.dda_horiz_accumulator |= ~0xfff; @@ -1935,7 +1939,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) virge->streams.chroma_upper_bound = val; break; case 0x8198: - virge->streams.sec_filter = val; + virge->streams.sec_filter = val; virge->streams.k1_horiz_scale = val & 0x7ff; if (val & 0x800) virge->streams.k1_horiz_scale |= ~0x7ff; @@ -2015,29 +2019,29 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x81f0: virge->streams.pri_start = val; - virge->streams.pri_x = (val >> 16) & 0x7ff; - virge->streams.pri_y = val & 0x7ff; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f4: virge->streams.pri_size = val; - virge->streams.pri_w = (val >> 16) & 0x7ff; - virge->streams.pri_h = val & 0x7ff; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81f8: virge->streams.sec_start = val; - virge->streams.sec_x = (val >> 16) & 0x7ff; - virge->streams.sec_y = val & 0x7ff; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81fc: virge->streams.sec_size = val; - virge->streams.sec_w = (val >> 16) & 0x7ff; - virge->streams.sec_h = val & 0x7ff; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; svga_recalctimings(svga); svga->fullchange = changeframecount; break; @@ -2054,23 +2058,23 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x8590: - virge->cmd_dma_base = val; - virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; + virge->cmd_dma_base = val; + virge->cmd_dma_buf_size = (val & 2) ? 0x10000 : 0x1000; virge->cmd_dma_buf_size_mask = virge->cmd_dma_buf_size - 1; - virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); + virge->cmd_base_addr = (val & 2) ? (val & 0xffff0000) : (val & 0xfffff000); break; case 0x8594: virge->cmd_dma_write_ptr_update = val & (1 << 16); if (virge->cmd_dma_write_ptr_update) { virge->cmd_dma_write_ptr_reg = (virge->cmd_dma_buf_size == 0x10000) ? (val & 0xffff) : (val & 0xfff); - virge->dma_dbl_words = 0; - virge->dma_data_type = 0; - virge->dma_val = 0; + virge->dma_dbl_words = 0; + virge->dma_data_type = 0; + virge->dma_val = 0; if (virge->cmd_dma) { while (virge->cmd_dma_read_ptr_reg != virge->cmd_dma_write_ptr_reg) { virge->cmd_dma_write_ptr_update = 0; - dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *)&virge->dma_val, 4, 4); + dma_bm_read(virge->cmd_base_addr + virge->cmd_dma_read_ptr_reg, (uint8_t *) &virge->dma_val, 4, 4); if (!virge->dma_dbl_words) { virge->dma_dbl_words = (virge->dma_val & 0xffff); virge->dma_data_type = !!(virge->dma_val & (1 << 31)); @@ -2094,9 +2098,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; case 0x859c: - virge->cmd_dma = val & 1; + virge->cmd_dma = val & 1; virge->cmd_dma_write_ptr_reg = 0; - virge->cmd_dma_read_ptr_reg = 0; + virge->cmd_dma_read_ptr_reg = 0; break; case 0xff20: @@ -2106,26 +2110,26 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } } -#define READ(addr, val) \ - do { \ - switch (bpp) { \ - case 0: /*8 bpp*/ \ - val = vram[addr & virge->vram_mask]; \ - break; \ - case 1: /*16 bpp*/ \ - val = *(uint16_t *)&vram[addr & virge->vram_mask]; \ - break; \ - case 2: /*24 bpp*/ \ - val = (*(uint32_t *)&vram[addr & virge->vram_mask]) & 0xffffff; \ - break; \ - } \ +#define READ(addr, val) \ + do { \ + switch (bpp) { \ + case 0: /*8 bpp*/ \ + val = vram[addr & virge->vram_mask]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *) &vram[addr & virge->vram_mask]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *) &vram[addr & virge->vram_mask]) & 0xffffff; \ + break; \ + } \ } while (0) -#define Z_READ(addr) *(uint16_t *)&vram[addr & virge->vram_mask] +#define Z_READ(addr) *(uint16_t *) &vram[addr & virge->vram_mask] -#define Z_WRITE(addr, val) \ - if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ - *(uint16_t *)&vram[addr & virge->vram_mask] = val +#define Z_WRITE(addr, val) \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + *(uint16_t *) &vram[addr & virge->vram_mask] = val #define CLIP(x, y) \ do { \ @@ -2174,12 +2178,12 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) else \ Zzb = Zs; \ break; \ - case 5: \ + case 5: \ if (Zs == Zzb) \ update = 0; \ else \ Zzb = Zs; \ - break; \ + break; \ case 6: \ if (Zs > Zzb) \ update = 0; \ @@ -2188,10 +2192,10 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) break; \ case 7: \ update = 1; \ - Zzb = Zs; \ + Zzb = Zs; \ break; \ } \ - } while (0) + } while (0) #define ROPMIX(R, D, P, S, out) \ { \ @@ -2967,7 +2971,11 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) } \ } -#define MIX() do { ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); out &= 0xFFFFFF; } while (0) +#define MIX() \ + do { \ + ROPMIX(virge->s3d.rop & 0xFF, dest, pattern, source, out); \ + out &= 0xFFFFFF; \ + } while (0) #define WRITE(addr, val) \ do { \ @@ -2994,7 +3002,7 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { - uint8_t *vram = virge->svga.vram; + uint8_t *vram = virge->svga.vram; uint32_t mono_pattern[64]; int count_mask; int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; @@ -3008,33 +3016,33 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { case CMD_SET_FORMAT_8: - bpp = 0; - x_mul = 1; + bpp = 0; + x_mul = 1; cpu_dat_shift = 8; - pattern_data = virge->s3d.pattern_8; - src_fg_clr = virge->s3d.src_fg_clr & 0xff; - src_bg_clr = virge->s3d.src_bg_clr & 0xff; + pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; break; case CMD_SET_FORMAT_16: - bpp = 1; - x_mul = 2; + bpp = 1; + x_mul = 2; cpu_dat_shift = 16; - pattern_data = virge->s3d.pattern_16; - src_fg_clr = virge->s3d.src_fg_clr & 0xffff; - src_bg_clr = virge->s3d.src_bg_clr & 0xffff; + pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; break; case CMD_SET_FORMAT_24: default: - bpp = 2; - x_mul = 3; + bpp = 2; + x_mul = 3; cpu_dat_shift = 24; - pattern_data = virge->s3d.pattern_24; - src_fg_clr = virge->s3d.src_fg_clr; - src_bg_clr = virge->s3d.src_bg_clr; + pattern_data = virge->s3d.pattern_24; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; break; - } - if (virge->s3d.cmd_set & CMD_SET_MP) - pattern_data = mono_pattern; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) { case CMD_SET_ITA_BYTE: @@ -3052,16 +3060,16 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x; int y; for (y = 0; y < 4; y++) { - for (x = 0; x < 8; x++) { - if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; - else - mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; - } + for (x = 0; x < 8; x++) { + if (virge->s3d.mono_pat_0 & (1 << (x + y * 8))) + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[y * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y * 8))) + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y + 4) * 8 + (7 - x)] = virge->s3d.pat_bg_clr; + } } } switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) { @@ -3070,13 +3078,13 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_BITBLT: if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; - virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; virge->s3d.data_left_count = 0; if (virge->s3d.cmd_set & CMD_SET_IDS) @@ -3092,8 +3100,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) { case 0: @@ -3111,18 +3119,18 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) count -= (cpu_dat_shift - virge->s3d.data_left_count); virge->s3d.data_left_count = 0; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } else { source = cpu_dat; cpu_dat >>= cpu_dat_shift; count -= cpu_dat_shift; if (count < cpu_dat_shift) { - virge->s3d.data_left = cpu_dat; + virge->s3d.data_left = cpu_dat; virge->s3d.data_left_count = count; - count = 0; + count = 0; } } if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) @@ -3152,9 +3160,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3182,23 +3190,22 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case CMD_SET_COMMAND_RECTFILL: /*No source, pattern = pat_fg_clr*/ if (count == -1) { - virge->s3d.src_x = virge->s3d.rsrc_x; - virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; virge->s3d.dest_x = virge->s3d.rdest_x; virge->s3d.dest_y = virge->s3d.rdest_y; - virge->s3d.w = virge->s3d.r_width; - virge->s3d.h = virge->s3d.r_height; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (count && virge->s3d.h) { - uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + - (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); uint32_t source = 0; uint32_t dest = 0; uint32_t pattern = virge->s3d.pat_fg_clr; uint32_t out = 0; - int update = 1; + int update = 1; CLIP(virge->s3d.dest_x, virge->s3d.dest_y); @@ -3215,9 +3222,9 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) virge->s3d.dest_x += x_inc; virge->s3d.dest_x &= 0x7ff; if (!virge->s3d.w) { - virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_x = virge->s3d.rsrc_x; virge->s3d.dest_x = virge->s3d.rdest_x; - virge->s3d.w = virge->s3d.r_width; + virge->s3d.w = virge->s3d.r_width; virge->s3d.src_y += y_inc; virge->s3d.dest_y += y_inc; @@ -3225,7 +3232,7 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (!virge->s3d.h) return; } else - virge->s3d.w--; + virge->s3d.w--; count--; } break; @@ -3234,8 +3241,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) if (count == -1) { virge->s3d.dest_x = virge->s3d.lxstart; virge->s3d.dest_y = virge->s3d.lystart; - virge->s3d.h = virge->s3d.lycnt; - virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; } while (virge->s3d.h) { int x; @@ -3262,8 +3269,8 @@ s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) uint32_t source = 0; uint32_t dest = 0; uint32_t pattern; - uint32_t out = 0; - int update = 1; + uint32_t out = 0; + int update = 1; if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && ((virge->s3d.line_dir && x < virge->s3d.lxend0) || @@ -3306,39 +3313,39 @@ skip_line: virge->s3d.dest_r = virge->s3d.prxstart; if (virge->s3d.pycnt & (1 << 29)) virge->s3d.dest_l = virge->s3d.plxstart; - virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; while (virge->s3d.h) { - int x = virge->s3d.dest_l >> 20; - int xend = virge->s3d.dest_r >> 20; - int y = virge->s3d.pystart & 0x7ff; - int xdir = (x < xend) ? 1 : -1; - do { - uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); - uint32_t source = 0; - uint32_t dest = 0; - uint32_t pattern; - uint32_t out = 0; - int update = 1; + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + do { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0; + uint32_t dest = 0; + uint32_t pattern; + uint32_t out = 0; + int update = 1; - CLIP(x, y); + CLIP(x, y); - if (update) { - READ(dest_addr, dest); - pattern = pattern_data[(y & 7) * 8 + (x & 7)]; + if (update) { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7) * 8 + (x & 7)]; - MIX(); + MIX(); - WRITE(dest_addr, out); - } + WRITE(dest_addr, out); + } - x = (x + xdir) & 0x7ff; - } while (x != (xend + xdir)); + x = (x + xdir) & 0x7ff; + } while (x != (xend + xdir)); - virge->s3d.dest_l += virge->s3d.pldx; - virge->s3d.dest_r += virge->s3d.prdx; - virge->s3d.h--; - virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; } break; @@ -3375,54 +3382,57 @@ skip_line: #define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) typedef struct rgba_t { - int r, g, b, a; + int r; + int g; + int b; + int a; } rgba_t; typedef struct s3d_state_t { - int32_t r; - int32_t g; - int32_t b; - int32_t a; - int32_t u; - int32_t v; - int32_t d; - int32_t w; + int32_t r; + int32_t g; + int32_t b; + int32_t a; + int32_t u; + int32_t v; + int32_t d; + int32_t w; - int32_t base_r; - int32_t base_g; - int32_t base_b; - int32_t base_a; - int32_t base_u; - int32_t base_v; - int32_t base_d; - int32_t base_w; + int32_t base_r; + int32_t base_g; + int32_t base_b; + int32_t base_a; + int32_t base_u; + int32_t base_v; + int32_t base_d; + int32_t base_w; - uint32_t base_z; + uint32_t base_z; - uint32_t tbu; - uint32_t tbv; + uint32_t tbu; + uint32_t tbv; - uint32_t cmd_set; - int max_d; + uint32_t cmd_set; + int max_d; uint16_t *texture[10]; - uint32_t tex_bdr_clr; + uint32_t tex_bdr_clr; - int32_t x1; - int32_t x2; + int32_t x1; + int32_t x2; - int y; + int y; - rgba_t dest_rgba; + rgba_t dest_rgba; } s3d_state_t; typedef struct s3d_texture_state_t { - int level; - int texture_shift; + int level; + int texture_shift; - int32_t u; - int32_t v; + int32_t u; + int32_t v; } s3d_texture_state_t; static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); @@ -3436,7 +3446,8 @@ static int _x; static int _y; static void -tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3448,7 +3459,8 @@ tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3463,7 +3475,8 @@ tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3475,7 +3488,8 @@ tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint16_t val = state->texture[texture_state->level][offset]; @@ -3490,7 +3504,8 @@ tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3502,7 +3517,8 @@ tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out } static void -tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) { +tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; @@ -3517,19 +3533,21 @@ tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba } static void -tex_sample_normal(s3d_state_t *state) { +tex_sample_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_normal_filter(s3d_state_t *state) { +tex_sample_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3537,9 +3555,9 @@ tex_sample_normal_filter(s3d_state_t *state) { int dv; int d[4]; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3575,21 +3593,23 @@ tex_sample_normal_filter(s3d_state_t *state) { } static void -tex_sample_mipmap(s3d_state_t *state) { +tex_sample_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = state->u + state->tbu; - texture_state.v = state->v + state->tbv; + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_mipmap_filter(s3d_state_t *state) { +tex_sample_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; int tex_offset; rgba_t tex_samples[4]; @@ -3601,7 +3621,7 @@ tex_sample_mipmap_filter(s3d_state_t *state) { if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = state->u + state->tbu; texture_state.v = state->v + state->tbv; @@ -3637,25 +3657,27 @@ tex_sample_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal(s3d_state_t *state) { +tex_sample_persp_normal(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter(s3d_state_t *state) { +tex_sample_persp_normal_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3665,14 +3687,14 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3708,25 +3730,27 @@ tex_sample_persp_normal_filter(s3d_state_t *state) { } static void -tex_sample_persp_normal_375(s3d_state_t *state) { +tex_sample_persp_normal_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_normal_filter_375(s3d_state_t *state) { +tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3736,14 +3760,14 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; - texture_state.level = state->max_d; + texture_state.level = state->max_d; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3779,27 +3803,29 @@ tex_sample_persp_normal_filter_375(s3d_state_t *state) { } static void -tex_sample_persp_mipmap(s3d_state_t *state) { +tex_sample_persp_mipmap(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter(s3d_state_t *state) { +tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3809,16 +3835,16 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (12 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3854,27 +3880,29 @@ tex_sample_persp_mipmap_filter(s3d_state_t *state) { } static void -tex_sample_persp_mipmap_375(s3d_state_t *state) { +tex_sample_persp_mipmap_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + texture_state.u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; tex_read(state, &texture_state, &state->dest_rgba); } static void -tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { +tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ s3d_texture_state_t texture_state; - int32_t w = 0; + int32_t w = 0; int32_t u; int32_t v; int tex_offset; @@ -3884,16 +3912,16 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { int d[4]; if (state->w) - w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + w = (int32_t) (((1ULL << 27) << 19) / (int64_t) state->w); - u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; - v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + u = (int32_t) (((int64_t) state->u * (int64_t) w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t) (((int64_t) state->v * (int64_t) w) >> (8 + state->max_d)) + state->tbv; texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); if (texture_state.level < 0) texture_state.level = 0; texture_state.texture_shift = 18 + (9 - texture_state.level); - tex_offset = 1 << texture_state.texture_shift; + tex_offset = 1 << texture_state.texture_shift; texture_state.u = u; texture_state.v = v; @@ -3928,40 +3956,41 @@ tex_sample_persp_mipmap_filter_375(s3d_state_t *state) { tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; } -#define CLAMP(x) \ - do { \ - if ((x) & ~0xff) \ - x = ((x) < 0) ? 0 : 0xff; \ +#define CLAMP(x) \ + do { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ } while (0) -#define CLAMP_RGBA(r, g, b, a) \ - if ((r) & ~0xff) \ - r = ((r) < 0) ? 0 : 0xff; \ - if ((g) & ~0xff) \ - g = ((g) < 0) ? 0 : 0xff; \ - if ((b) & ~0xff) \ - b = ((b) < 0) ? 0 : 0xff; \ - if ((a) & ~0xff) \ - a = ((a) < 0) ? 0 : 0xff; +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; -#define CLAMP_RGB(r, g, b) \ - do { \ - if ((r) < 0) \ - r = 0; \ - if ((r) > 0xff) \ - r = 0xff; \ - if ((g) < 0) \ - g = 0; \ - if ((g) > 0xff) \ - g = 0xff; \ - if ((b) < 0) \ - b = 0; \ - if ((b) > 0xff) \ - b = 0xff; \ +#define CLAMP_RGB(r, g, b) \ + do { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ } while (0) static void -dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { +dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ state->dest_rgba.r = state->r >> 7; CLAMP(state->dest_rgba.r); @@ -3976,7 +4005,8 @@ dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) { } static void -dest_pixel_unlit_texture_triangle(s3d_state_t *state) { +dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3984,7 +4014,8 @@ dest_pixel_unlit_texture_triangle(s3d_state_t *state) { } static void -dest_pixel_lit_texture_decal(s3d_state_t *state) { +dest_pixel_lit_texture_decal(s3d_state_t *state) +{ tex_sample(state); if (state->cmd_set & CMD_SET_ABC_SRC) @@ -3992,7 +4023,8 @@ dest_pixel_lit_texture_decal(s3d_state_t *state) { } static void -dest_pixel_lit_texture_reflection(s3d_state_t *state) { +dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ tex_sample(state); state->dest_rgba.r += (state->r >> 7); @@ -4005,7 +4037,8 @@ dest_pixel_lit_texture_reflection(s3d_state_t *state) { } static void -dest_pixel_lit_texture_modulate(s3d_state_t *state) { +dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ int r = state->r >> 7; int g = state->g >> 7; int b = state->b >> 7; @@ -4024,17 +4057,18 @@ dest_pixel_lit_texture_modulate(s3d_state_t *state) { } static void -tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { - uint8_t *vram = virge->svga.vram; - int x_dir = s3d_tri->tlr ? 1 : -1; - int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); - int y_count = yc; - int bpp = (s3d_tri->cmd_set >> 2) & 7; - uint32_t dest_offset; - uint32_t z_offset; +tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + uint8_t *vram = virge->svga.vram; + int x_dir = s3d_tri->tlr ? 1 : -1; + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + int y_count = yc; + int bpp = (s3d_tri->cmd_set >> 2) & 7; + uint32_t dest_offset; + uint32_t z_offset; dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); - z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); if (s3d_tri->cmd_set & CMD_SET_HC) { if (state->y < s3d_tri->clip_t) @@ -4054,195 +4088,190 @@ tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int state->base_a += (s3d_tri->TdAdY * diff_y); state->base_d += (s3d_tri->TdDdY * diff_y); state->base_w += (s3d_tri->TdWdY * diff_y); - state->x1 += (dx1 * diff_y); - state->x2 += (dx2 * diff_y); - state->y -= diff_y; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; - y_count -= diff_y; + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) y_count = (state->y - s3d_tri->clip_t) + 1; } for (; y_count > 0; y_count--) { - int x = (state->x1 + ((1 << 20) - 1)) >> 20; - int xe = (state->x2 + ((1 << 20) - 1)) >> 20; - uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + int x = (state->x1 + ((1 << 20) - 1)) >> 20; + int xe = (state->x2 + ((1 << 20) - 1)) >> 20; + uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; - if (x_dir < 0) { - x--; - xe--; - } + if (x_dir < 0) { + x--; + xe--; + } - if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { - uint32_t dest_addr; - uint32_t z_addr; - int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : - (((state->x1 - 1) >> 15) & 0x1f); - int x_offset = x_dir * (bpp + 1); - int xz_offset = x_dir << 1; + if (x != xe && ((x_dir > 0 && x < xe) || (x_dir < 0 && x > xe))) { + uint32_t dest_addr; + uint32_t z_addr; + int dx = (x_dir > 0) ? ((31 - ((state->x1 - 1) >> 15)) & 0x1f) : (((state->x1 - 1) >> 15) & 0x1f); + int x_offset = x_dir * (bpp + 1); + int xz_offset = x_dir << 1; - if (x_dir > 0) - dx += 1; + if (x_dir > 0) + dx += 1; - state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); - state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); - state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); - state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); - state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); - state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); - state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); - state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); - z += ((s3d_tri->TdZdX * dx) >> 5); + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); - if (s3d_tri->cmd_set & CMD_SET_HC) { - if (x_dir > 0) { - if (x > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r + 1; - if (x < s3d_tri->clip_l) { - int diff_x = s3d_tri->clip_l - x; + if (s3d_tri->cmd_set & CMD_SET_HC) { + if (x_dir > 0) { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r + 1; + if (x < s3d_tri->clip_l) { + int diff_x = s3d_tri->clip_l - x; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_l; - } - } else { - if (x < s3d_tri->clip_l) - goto tri_skip_line; - if (xe > s3d_tri->clip_r) - goto tri_skip_line; - if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l - 1; - if (x > s3d_tri->clip_r) { - int diff_x = x - s3d_tri->clip_r; + x = s3d_tri->clip_l; + } + } else { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l - 1; + if (x > s3d_tri->clip_r) { + int diff_x = x - s3d_tri->clip_r; - z += (s3d_tri->TdZdX * diff_x); - state->u += (s3d_tri->TdUdX * diff_x); - state->v += (s3d_tri->TdVdX * diff_x); - state->r += (s3d_tri->TdRdX * diff_x); - state->g += (s3d_tri->TdGdX * diff_x); - state->b += (s3d_tri->TdBdX * diff_x); - state->a += (s3d_tri->TdAdX * diff_x); - state->d += (s3d_tri->TdDdX * diff_x); - state->w += (s3d_tri->TdWdX * diff_x); + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); - x = s3d_tri->clip_r; - } - } - } + x = s3d_tri->clip_r; + } + } + } - virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; + virge->svga.changedvram[(dest_offset & virge->vram_mask) >> 12] = changeframecount; - dest_addr = dest_offset + (x * (bpp + 1)); - z_addr = z_offset + (x << 1); + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); - x &= 0xfff; - xe &= 0xfff; + x &= 0xfff; + xe &= 0xfff; - for (; x != xe; x = (x + x_dir) & 0xfff) { - int update = 1; - uint16_t src_z = 0; + for (; x != xe; x = (x + x_dir) & 0xfff) { + int update = 1; + uint16_t src_z = 0; - _x = x; - _y = state->y; + _x = x; + _y = state->y; - if (use_z) { - src_z = Z_READ(z_addr); - Z_CLIP(src_z, z >> 16); - } + if (use_z) { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } - if (update) { - uint32_t dest_col; + if (update) { + uint32_t dest_col; - dest_pixel(state); + dest_pixel(state); - if (s3d_tri->cmd_set & CMD_SET_FE) { - int a = state->a >> 7; - state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; - } + if (s3d_tri->cmd_set & CMD_SET_FE) { + int a = state->a >> 7; + state->dest_rgba.r = ((state->dest_rgba.r * a) + (s3d_tri->fog_r * (255 - a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * a) + (s3d_tri->fog_g * (255 - a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * a) + (s3d_tri->fog_b * (255 - a))) / 255; + } - if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { - uint32_t src_col; - int src_r = 0; - uint32_t src_g = 0; - uint32_t src_b = 0; + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) { + uint32_t src_col; + int src_r = 0; + uint32_t src_g = 0; + uint32_t src_b = 0; + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *) &vram[dest_addr & virge->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *) &vram[dest_addr & virge->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - src_col = *(uint16_t *)&vram[dest_addr & virge->vram_mask]; - RGB15_TO_24(src_col, src_r, src_g, src_b); - break; - case 2: /*24 bpp*/ - src_col = (*(uint32_t *)&vram[dest_addr & virge->vram_mask]) & 0xffffff; - RGB24_TO_24(src_col, src_r, src_g, src_b); - break; - } + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } - state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + - (src_r * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + - (src_g * (255 - state->dest_rgba.a))) / 255; - state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + - (src_b * (255 - state->dest_rgba.a))) / 255; - } + switch (bpp) { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *) &vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *) &vram[dest_addr] = dest_col & 0xff; + *(uint8_t *) &vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *) &vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } - switch (bpp) { - case 0: /*8 bpp*/ - /*Not implemented yet*/ - break; - case 1: /*16 bpp*/ - RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); - *(uint16_t *)&vram[dest_addr] = dest_col; - break; - case 2: /*24 bpp*/ - dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); - *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; - *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; - *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; - break; - } + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } - if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) - Z_WRITE(z_addr, src_z); - } - - z += s3d_tri->TdZdX; - state->u += s3d_tri->TdUdX; - state->v += s3d_tri->TdVdX; - state->r += s3d_tri->TdRdX; - state->g += s3d_tri->TdGdX; - state->b += s3d_tri->TdBdX; - state->a += s3d_tri->TdAdX; - state->d += s3d_tri->TdDdX; - state->w += s3d_tri->TdWdX; - dest_addr += x_offset; - z_addr += xz_offset; - virge->pixel_count++; - } + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } } tri_skip_line: - state->x1 += dx1; - state->x2 += dx2; + state->x1 += dx1; + state->x2 += dx2; state->base_u += s3d_tri->TdUdY; state->base_v += s3d_tri->TdVdY; state->base_z += s3d_tri->TdZdY; @@ -4253,22 +4282,23 @@ tri_skip_line: state->base_d += s3d_tri->TdDdY; state->base_w += s3d_tri->TdWdY; state->y--; - dest_offset -= s3d_tri->dest_str; - z_offset -= s3d_tri->z_str; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; } } -static int tex_size[8] = {4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2}; +static int tex_size[8] = { 4 * 2, 2 * 2, 2 * 2, 1 * 2, 2 / 1, 2 / 1, 1 * 2, 1 * 2 }; static void -s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { +s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ s3d_state_t state; - uint32_t tex_base; - int c; + uint32_t tex_base; + int c; - uint64_t start_time = plat_timer_read(); - uint64_t end_time; + uint64_t start_time = plat_timer_read(); + uint64_t end_time; state.tbu = s3d_tri->tbu << 11; state.tbv = s3d_tri->tbv << 11; @@ -4282,18 +4312,18 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { state.base_u = s3d_tri->tus; state.base_v = s3d_tri->tvs; state.base_z = s3d_tri->tzs; - state.base_r = (int32_t)s3d_tri->trs; - state.base_g = (int32_t)s3d_tri->tgs; - state.base_b = (int32_t)s3d_tri->tbs; - state.base_a = (int32_t)s3d_tri->tas; + state.base_r = (int32_t) s3d_tri->trs; + state.base_g = (int32_t) s3d_tri->tgs; + state.base_b = (int32_t) s3d_tri->tbs; + state.base_a = (int32_t) s3d_tri->tas; state.base_d = s3d_tri->tds; state.base_w = s3d_tri->tws; tex_base = s3d_tri->tex_base; for (c = 9; c >= 0; c--) { - state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; - if (c <= state.max_d) - tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + state.texture[c] = (uint16_t *) &virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c * 2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; } switch ((s3d_tri->cmd_set >> 27) & 0xf) { @@ -4407,7 +4437,7 @@ s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) { static void render_thread(void *param) { - virge_t *virge = (virge_t *)param; + virge_t *virge = (virge_t *) param; while (virge->render_thread_run) { thread_wait_event(virge->wake_render_thread, -1); @@ -4443,14 +4473,14 @@ queue_triangle(virge_t *virge) static void s3_virge_hwcursor_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; - int x; - uint16_t dat[2] = { 0, 0 }; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - uint32_t fg; - uint32_t bg; - uint32_t vram_mask = virge->vram_mask; + virge_t *virge = (virge_t *) svga->priv; + int x; + uint16_t dat[2] = { 0, 0 }; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg; + uint32_t bg; + uint32_t vram_mask = virge->vram_mask; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; @@ -4568,22 +4598,22 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) CLAMP(b[x_write + 1]); \ \ x_write = (x_write + 2) & 7; \ - } \ + } \ } while (0) /*Both YUV formats are untested*/ #define DECODE_YUV211() \ do { \ uint8_t y1, y2, y3, y4; \ - int8_t U, V; \ - int dR; \ - int dG; \ - int dB; \ + int8_t U, V; \ + int dR; \ + int dG; \ + int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ y2 = (298 * (src[2] - 16)) >> 8; \ - V = src[3] - 0x80; \ + V = src[3] - 0x80; \ y3 = (298 * (src[4] - 16)) >> 8; \ y4 = (298 * (src[5] - 16)) >> 8; \ src += 6; \ @@ -4634,9 +4664,9 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) int dG; \ int dB; \ \ - U = src[0] - 0x80; \ + U = src[0] - 0x80; \ y1 = (298 * (src[1] - 16)) >> 8; \ - V = src[2] - 0x80; \ + V = src[2] - 0x80; \ y2 = (298 * (src[3] - 16)) >> 8; \ src += 4; \ \ @@ -4757,13 +4787,13 @@ s3_virge_hwcursor_draw(svga_t *svga, int displine) static void s3_virge_overlay_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *) svga->priv; + virge_t *virge = (virge_t *) svga->priv; int offset; int r[8]; int g[8]; int b[8]; int x_size; - int x_read = 4; + int x_read = 4; int x_write = 4; int x; uint32_t *p; @@ -4774,7 +4804,7 @@ s3_virge_overlay_draw(svga_t *svga, int displine) else offset = virge->streams.sec_x + 1; - p = &((uint32_t *)buffer32->line[displine])[offset + svga->x_add]; + p = &((uint32_t *) buffer32->line[displine])[offset + svga->x_add]; if (virge->chip < S3_VIRGEGX2) { if ((offset + virge->streams.sec_w) > virge->streams.pri_w) @@ -5078,9 +5108,9 @@ s3_virge_disable_handlers(virge_t *dev) reset_state->svga.mapping = dev->svga.mapping; reset_state->bios_rom.mapping = dev->bios_rom.mapping; - reset_state->svga.timer = dev->svga.timer; - reset_state->svga.timer8514 = dev->svga.timer8514; - reset_state->irq_timer = dev->irq_timer; + reset_state->svga.timer = dev->svga.timer; + reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->irq_timer = dev->irq_timer; } static void @@ -5090,12 +5120,12 @@ s3_virge_reset(void *priv) if (reset_state != NULL) { s3_virge_disable_handlers(dev); - dev->virge_busy = 0; - dev->fifo_write_idx = 0; - dev->fifo_read_idx = 0; - dev->s3d_busy = 0; - dev->s3d_write_idx = 0; - dev->s3d_read_idx = 0; + dev->virge_busy = 0; + dev->fifo_write_idx = 0; + dev->fifo_read_idx = 0; + dev->s3d_busy = 0; + dev->s3d_write_idx = 0; + dev->s3d_read_idx = 0; reset_state->pci_slot = dev->pci_slot; *dev = *reset_state; @@ -5106,8 +5136,8 @@ static void * s3_virge_init(const device_t *info) { const char *bios_fn = NULL; - virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); - reset_state = calloc(1, sizeof(virge_t)); + virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); + reset_state = calloc(1, sizeof(virge_t)); virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); @@ -5118,44 +5148,45 @@ s3_virge_init(const device_t *info) virge->onboard = !!(info->local & 0x100); - if (!virge->onboard) switch (info->local) { - case S3_VIRGE_325: - bios_fn = ROM_VIRGE_325; - break; - case S3_DIAMOND_STEALTH3D_2000: - bios_fn = ROM_DIAMOND_STEALTH3D_2000; - break; - case S3_MIROCRYSTAL_3D: - bios_fn = ROM_MIROCRYSTAL_3D; - break; - case S3_DIAMOND_STEALTH3D_3000: - bios_fn = ROM_DIAMOND_STEALTH3D_3000; - break; - case S3_STB_VELOCITY_3D: - bios_fn = ROM_STB_VELOCITY_3D; - break; - case S3_VIRGE_DX: - bios_fn = ROM_VIRGE_DX; - break; - case S3_DIAMOND_STEALTH3D_2000PRO: - bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; - break; - case S3_VIRGE_GX: - bios_fn = ROM_VIRGE_GX; - break; - case S3_VIRGE_GX2: - bios_fn = ROM_VIRGE_GX2; - break; - case S3_DIAMOND_STEALTH3D_4000: - bios_fn = ROM_DIAMOND_STEALTH3D_4000; - break; - case S3_TRIO_3D2X: - bios_fn = ROM_TRIO3D2X; - break; - default: - free(virge); - return NULL; - } + if (!virge->onboard) + switch (info->local) { + case S3_VIRGE_325: + bios_fn = ROM_VIRGE_325; + break; + case S3_DIAMOND_STEALTH3D_2000: + bios_fn = ROM_DIAMOND_STEALTH3D_2000; + break; + case S3_MIROCRYSTAL_3D: + bios_fn = ROM_MIROCRYSTAL_3D; + break; + case S3_DIAMOND_STEALTH3D_3000: + bios_fn = ROM_DIAMOND_STEALTH3D_3000; + break; + case S3_STB_VELOCITY_3D: + bios_fn = ROM_STB_VELOCITY_3D; + break; + case S3_VIRGE_DX: + bios_fn = ROM_VIRGE_DX; + break; + case S3_DIAMOND_STEALTH3D_2000PRO: + bios_fn = ROM_DIAMOND_STEALTH3D_2000PRO; + break; + case S3_VIRGE_GX: + bios_fn = ROM_VIRGE_GX; + break; + case S3_VIRGE_GX2: + bios_fn = ROM_VIRGE_GX2; + break; + case S3_DIAMOND_STEALTH3D_4000: + bios_fn = ROM_DIAMOND_STEALTH3D_4000; + break; + case S3_TRIO_3D2X: + bios_fn = ROM_TRIO3D2X; + break; + default: + free(virge); + return NULL; + } svga_init(info, &virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, @@ -5223,7 +5254,7 @@ s3_virge_init(const device_t *info) case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: case S3_MIROCRYSTAL_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x56; virge->virge_id_low = 0x31; @@ -5233,7 +5264,7 @@ s3_virge_init(const device_t *info) break; case S3_DIAMOND_STEALTH3D_3000: case S3_STB_VELOCITY_3D: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x88; virge->virge_id_low = 0x3d; @@ -5243,7 +5274,7 @@ s3_virge_init(const device_t *info) break; case S3_VIRGE_GX2: case S3_DIAMOND_STEALTH3D_4000: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x10; @@ -5255,7 +5286,7 @@ s3_virge_init(const device_t *info) break; case S3_TRIO_3D2X: - virge->fifo_slots_num = 16; + virge->fifo_slots_num = 16; virge->svga.decode_mask = (8 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x13; @@ -5272,7 +5303,7 @@ s3_virge_init(const device_t *info) fallthrough; default: - virge->fifo_slots_num = 8; + virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x8a; virge->virge_id_low = 0x01; @@ -5341,16 +5372,16 @@ s3_virge_init(const device_t *info) virge->svga.force_old_addr = 1; - virge->render_thread_run = 1; + virge->render_thread_run = 1; virge->wake_render_thread = thread_create_event(); - virge->wake_main_thread = thread_create_event(); - virge->not_full_event = thread_create_event(); - virge->render_thread = thread_create(render_thread, virge); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); - virge->fifo_thread_run = 1; - virge->wake_fifo_thread = thread_create_event(); + virge->fifo_thread_run = 1; + virge->wake_fifo_thread = thread_create_event(); virge->fifo_not_full_event = thread_create_event(); - virge->fifo_thread = thread_create(fifo_thread, virge); + virge->fifo_thread = thread_create(fifo_thread, virge); timer_add(&virge->irq_timer, s3_virge_update_irq_timer, virge, 1); @@ -5473,7 +5504,7 @@ s3_virge_force_redraw(void *priv) } static const device_config_t s3_virge_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5509,11 +5540,11 @@ static const device_config_t s3_virge_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_stb_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5550,11 +5581,11 @@ static const device_config_t s3_virge_stb_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_virge_357_config[] = { - // clang-format off + // clang-format off { .name = "bilinear", .description = "Bilinear filtering", @@ -5576,11 +5607,11 @@ static const device_config_t s3_virge_357_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; static const device_config_t s3_trio3d2x_config[] = { - // clang-format off + // clang-format off { .name = "memory", .description = "Memory size", @@ -5619,7 +5650,7 @@ static const device_config_t s3_trio3d2x_config[] = { .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on + // clang-format on }; const device_t s3_virge_325_pci_device = { From 6c32f3ec0c1cd5997bd1c2ed717403750ea29bff Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 19:06:05 +0600 Subject: [PATCH 0442/1190] Properly process line endings --- src/qt/qt_openglrenderer_pcem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index c8f3d3eb9..50583bf51 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -136,7 +136,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log).replace("\n", "
")); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -181,7 +181,7 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log).replace("\n", "
")); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); pclog("Could not compile shader: %s\n", log); From 1ed579a0fceaa86d5b4dc00cc76bd751040042cf Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 19:52:59 +0600 Subject: [PATCH 0443/1190] Reimplement other missing options from current OpenGL renderer --- src/qt/qt_openglrenderer_pcem.cpp | 11 +- src/qt/qt_openglshadermanagerdialog.cpp | 51 ++++ src/qt/qt_openglshadermanagerdialog.hpp | 8 + src/qt/qt_openglshadermanagerdialog.ui | 300 ++++++++++++++---------- 4 files changed, 247 insertions(+), 123 deletions(-) diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 50583bf51..79960323f 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -774,6 +774,8 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setSwapInterval(video_vsync ? 1 : 0); + setFormat(format); parentWidget = parent; @@ -822,6 +824,9 @@ OpenGLRendererPCem::initialize() glw.glEnable(GL_TEXTURE_2D); //renderTimer->start(75); + if (video_framerate != -1) { + renderTimer->start(ceilf(1000.f / (float)video_framerate)); + } scene_texture.data = NULL; scene_texture.width = 2048; @@ -1102,7 +1107,8 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) source.setRect(x, y, w, h); onResize(this->width(), this->height()); - render(); + if (video_framerate == -1) + render(); } std::vector> @@ -1314,6 +1320,9 @@ OpenGLRendererPCem::render() if (!context) return; + if (notReady()) + return; + int s, i, j; struct { diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 08cf94fd7..0bf083252 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -1,6 +1,9 @@ #include "qt_openglshadermanagerdialog.hpp" #include "ui_qt_openglshadermanagerdialog.h" +#include "qt_mainwindow.hpp" +extern MainWindow* main_window; + #include "qt_openglshaderconfig.hpp" #include @@ -25,6 +28,15 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) { ui->setupUi(this); + ui->checkBoxVSync->setChecked(!!video_vsync); + ui->radioButtonVideoSync->setChecked(video_framerate == -1); + ui->radioButtonTargetFramerate->setChecked(video_framerate != -1); + if (video_framerate != -1) { + ui->targetFrameRate->setValue(video_framerate); + } else { + ui->targetFrameRate->setDisabled(true); + } + for (int i = 0; i < MAX_USER_SHADERS; i++) { if (gl3_shader_file[i][0] != 0) { char* filename = path_get_filename(gl3_shader_file[i]); @@ -75,6 +87,9 @@ void OpenGLShaderManagerDialog::on_buttonBox_clicked(QAbstractButton *button) accept(); } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) { reject(); + } else if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) { + on_OpenGLShaderManagerDialog_accepted(); + main_window->reloadAllRenderers(); } } @@ -191,6 +206,12 @@ void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() strncpy(gl3_shader_file[i], ui->shaderListWidget->item(i)->data(Qt::UserRole + 1).toString().toUtf8(), 512); } startblit(); + video_vsync = ui->checkBoxVSync->isChecked(); + if (ui->radioButtonTargetFramerate->isChecked()) { + video_framerate = ui->horizontalSliderFramerate->value(); + } else { + video_framerate = -1; + } config_save(); endblit(); } @@ -207,3 +228,33 @@ void OpenGLShaderManagerDialog::on_buttonConfigure_clicked() } } + +void OpenGLShaderManagerDialog::on_radioButtonVideoSync_clicked() +{ + ui->targetFrameRate->setDisabled(true); +} + + +void OpenGLShaderManagerDialog::on_radioButtonTargetFramerate_clicked() +{ + ui->targetFrameRate->setDisabled(false); +} + + +void OpenGLShaderManagerDialog::on_horizontalSliderFramerate_sliderMoved(int position) +{ + (void)position; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->targetFrameRate->setValue(ui->horizontalSliderFramerate->value()); +} + + +void OpenGLShaderManagerDialog::on_targetFrameRate_valueChanged(int arg1) +{ + (void)arg1; + + if (ui->horizontalSliderFramerate->value() != ui->targetFrameRate->value()) + ui->horizontalSliderFramerate->setValue(ui->targetFrameRate->value()); +} + diff --git a/src/qt/qt_openglshadermanagerdialog.hpp b/src/qt/qt_openglshadermanagerdialog.hpp index b8885e3a3..a9f7ad3a9 100644 --- a/src/qt/qt_openglshadermanagerdialog.hpp +++ b/src/qt/qt_openglshadermanagerdialog.hpp @@ -35,6 +35,14 @@ private slots: void on_buttonConfigure_clicked(); + void on_radioButtonVideoSync_clicked(); + + void on_radioButtonTargetFramerate_clicked(); + + void on_horizontalSliderFramerate_sliderMoved(int position); + + void on_targetFrameRate_valueChanged(int arg1); + private: Ui::OpenGLShaderManagerDialog *ui; }; diff --git a/src/qt/qt_openglshadermanagerdialog.ui b/src/qt/qt_openglshadermanagerdialog.ui index f68827436..2a72c69ed 100644 --- a/src/qt/qt_openglshadermanagerdialog.ui +++ b/src/qt/qt_openglshadermanagerdialog.ui @@ -13,136 +13,192 @@ Shader Manager - + QLayout::SizeConstraint::SetFixedSize - - - - QAbstractItemView::DragDropMode::InternalMove - - - QAbstractItemView::SelectionBehavior::SelectItems + + + + Shaders + + + QLayout::SizeConstraint::SetFixedSize + + + + + QAbstractItemView::DragDropMode::InternalMove + + + QAbstractItemView::SelectionBehavior::SelectItems + + + + + + + QLayout::SizeConstraint::SetFixedSize + + + + + Add + + + + + + + Remove + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + true + + + Configure + + + + + + + Move up + + + + + + + Move down + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + Qt::Orientation::Vertical + + + QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + false + + + + + + - - - - - - Add - - - - - - - Remove - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - true - - - Configure - - - - - - - Move up - - - - - - - Move down - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - Qt::Orientation::Vertical - - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok - - - false - - - - + + + + Render behavior + + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + Use target framerate: + + + + + + + 15 + + + 240 + + + 60 + + + Qt::Orientation::Horizontal + + + false + + + false + + + + + + + Synchronize with video + + + true + + + + + + + VSync + + + + + + + fps + + + 15 + + + 240 + + + 60 + + + + +
- - - buttonBox - accepted() - OpenGLShaderManagerDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenGLShaderManagerDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + From 81461f677df712457f3c98214ca2390c4f135d14 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 20:54:25 +0600 Subject: [PATCH 0444/1190] Cleanups, copyright headers and name changing for PRing --- src/86box.c | 1 - src/config.c | 19 +- src/include/86box/86box.h | 1 - src/include/86box/ini.h | 30 -- src/ini.c | 3 +- src/qt/CMakeLists.txt | 12 +- src/qt/qt_glsl_parser.cpp | 37 +++ src/qt/qt_opengloptions.cpp | 196 ------------- src/qt/qt_opengloptions.hpp | 102 ------- src/qt/qt_opengloptionsdialog.cpp | 116 -------- src/qt/qt_opengloptionsdialog.hpp | 51 ---- src/qt/qt_opengloptionsdialog.ui | 280 ------------------ src/qt/qt_openglrenderer.cpp | 468 ------------------------------ src/qt/qt_openglrenderer.hpp | 125 -------- src/qt/qt_openglrenderer_pcem.cpp | 111 ++++--- src/qt/qt_openglrenderer_pcem.hpp | 20 +- src/qt/qt_rendererstack.cpp | 17 +- 17 files changed, 136 insertions(+), 1453 deletions(-) delete mode 100644 src/qt/qt_opengloptions.cpp delete mode 100644 src/qt/qt_opengloptions.hpp delete mode 100644 src/qt/qt_opengloptionsdialog.cpp delete mode 100644 src/qt/qt_opengloptionsdialog.hpp delete mode 100644 src/qt/qt_opengloptionsdialog.ui delete mode 100644 src/qt/qt_openglrenderer.cpp delete mode 100644 src/qt/qt_openglrenderer.hpp diff --git a/src/86box.c b/src/86box.c index 13167b1bd..24f6f0deb 100644 --- a/src/86box.c +++ b/src/86box.c @@ -172,7 +172,6 @@ int force_43 = 0; /* (C) video * int video_filter_method = 1; /* (C) video */ int video_vsync = 0; /* (C) video */ int video_framerate = -1; /* (C) video */ -char video_shader[512] = { '\0' }; /* (C) video */ bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ diff --git a/src/config.c b/src/config.c index 20981885a..5ad804df6 100644 --- a/src/config.c +++ b/src/config.c @@ -200,7 +200,6 @@ load_general(void) video_framerate = ini_section_get_int(cat, "video_gl_framerate", -1); video_vsync = ini_section_get_int(cat, "video_gl_vsync", 0); - strncpy(video_shader, ini_section_get_string(cat, "video_gl_shader", ""), sizeof(video_shader) - 1); window_remember = ini_section_get_int(cat, "window_remember", 0); if (window_remember) { @@ -1733,7 +1732,19 @@ load_gl3_shaders(void) if (shaders > MAX_USER_SHADERS) shaders = MAX_USER_SHADERS; - for (int i = 0; i < shaders; i++) { + if (shaders == 0) { + ini_section_t general = ini_find_section(config, "General"); + if (general) { + p = ini_section_get_string(general, "video_gl_shader", NULL); + if (p) { + strncpy(gl3_shader_file[0], p, 512); + ini_delete_var(config, general, "video_gl_shader"); + return; + } + } + } + + for (i = 0; i < shaders; i++) { temp[0] = 0; snprintf(temp, 512, "shader%d", i); p = ini_section_get_string(cat, temp, ""); @@ -2035,10 +2046,6 @@ save_general(void) ini_section_set_int(cat, "video_gl_vsync", video_vsync); else ini_section_delete_var(cat, "video_gl_vsync"); - if (strlen(video_shader) > 0) - ini_section_set_string(cat, "video_gl_shader", video_shader); - else - ini_section_delete_var(cat, "video_gl_shader"); if (do_auto_pause) ini_section_set_int(cat, "do_auto_pause", do_auto_pause); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 30905741c..768ca6267 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -126,7 +126,6 @@ extern int video_filter_method; /* (C) video */ extern int video_vsync; /* (C) video */ extern int video_framerate; /* (C) video */ extern int gfxcard[GFXCARD_MAX]; /* (C) graphics/video card */ -extern char video_shader[512]; /* (C) video */ extern int bugger_enabled; /* (C) enable ISAbugger */ extern int novell_keycard_enabled; /* (C) enable Novell NetWare 2.x key card emulation. */ extern int postcard_enabled; /* (C) enable POST card */ diff --git a/src/include/86box/ini.h b/src/include/86box/ini.h index 3139f410e..bb250e697 100644 --- a/src/include/86box/ini.h +++ b/src/include/86box/ini.h @@ -92,36 +92,6 @@ extern ini_section_t ini_find_or_create_section(ini_t ini, const char *name); extern void ini_rename_section(ini_section_t section, const char *name); extern void ini_delete_section_if_empty(ini_t ini, ini_section_t section); -static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } -static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); - if (size == 0) - return res; - if (str != NULL) - strncpy(dst, str, size - 1); - else - dst[0] = 0; - return res; -} -static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = ini_get_int((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = (float)ini_get_double((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { - int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); - *dst = !!ini_get_int((ini_t)config, "", name, defVal); - return res; -} -static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } -static inline void wx_config_free(void *config) { ini_close(config); }; - #ifdef __cplusplus } #endif diff --git a/src/ini.c b/src/ini.c index 7a54d5396..503b17ae3 100644 --- a/src/ini.c +++ b/src/ini.c @@ -162,7 +162,6 @@ ini_has_entry(ini_section_t self, const char *name) { section_t *section = (section_t *) self; const entry_t *entry; - int value = 0; if (section == NULL) return 0; @@ -546,6 +545,7 @@ ini_write(ini_t ini, const char *fn) (void) fclose(fp); } +/* Wide-character version of "trim" */ wchar_t * trim_w(wchar_t *str) { @@ -609,7 +609,6 @@ ini_strip_quotes(ini_t ini) ent = (entry_t *) sec->entry_head.next; while (ent != NULL) { if (ent->name[0] != '\0') { - int i = 0; int trailing_hash = strcspn(ent->data, "#"); int trailing_quote; ent->wdata[trailing_hash] = 0; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 574aae7b7..8137be98e 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -87,16 +87,9 @@ add_library(ui STATIC qt_softwarerenderer.hpp qt_hardwarerenderer.cpp qt_hardwarerenderer.hpp - qt_openglrenderer.cpp - qt_openglrenderer.hpp qt_openglrenderer_pcem.cpp qt_openglrenderer_pcem.hpp qt_glsl_parser.cpp - qt_opengloptions.cpp - qt_opengloptions.hpp - qt_opengloptionsdialog.cpp - qt_opengloptionsdialog.hpp - qt_opengloptionsdialog.ui qt_settings.cpp qt_settings.hpp @@ -197,7 +190,10 @@ add_library(ui STATIC qt_openglshadermanagerdialog.hpp qt_openglshadermanagerdialog.cpp qt_openglshadermanagerdialog.ui - qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui + + qt_openglshaderconfig.hpp + qt_openglshaderconfig.cpp + qt_openglshaderconfig.ui ) if(RTMIDI) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 2a4c4ddd1..bf02014db 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -28,6 +28,43 @@ extern void endblit(); (a)[(n)-1] = 0; \ } while (0) + + +static inline void *wx_config_load(const char *path) { ini_t ini = ini_read(path); if (ini) ini_strip_quotes(ini); return (void*)ini; } + +static inline int wx_config_get_string(void *config, const char *name, char *dst, int size, const char *defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + char* str = ini_get_string((ini_t)config, "", name, (char*)defVal); + if (size == 0) + return res; + if (str != NULL) + strncpy(dst, str, size - 1); + else + dst[0] = 0; + return res; +} + +static inline int wx_config_get_int(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_float(void *config, const char *name, float *dst, float defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = (float)ini_get_double((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_get_bool(void *config, const char *name, int *dst, int defVal) { + int res = ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); + *dst = !!ini_get_int((ini_t)config, "", name, defVal); + return res; +} + +static inline int wx_config_has_entry(void *config, const char *name) { return ini_has_entry(ini_find_or_create_section((ini_t)config, ""), name); } +static inline void wx_config_free(void *config) { ini_close(config); }; + static int endswith(const char *str, const char *ext) { int i; const char *p; diff --git a/src/qt/qt_opengloptions.cpp b/src/qt/qt_opengloptions.cpp deleted file mode 100644 index 58030b467..000000000 --- a/src/qt/qt_opengloptions.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * OpenGL renderer options for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include -#include - -#include - -#include "qt_opengloptions.hpp" - -extern "C" { -#include <86box/86box.h> -} - -/* Default vertex shader. */ -static const GLchar *vertex_shader = "\ -in vec2 VertexCoord;\n\ -in vec2 TexCoord;\n\ -out vec2 tex;\n\ -void main(){\n\ - gl_Position = vec4(VertexCoord, 0.0, 1.0);\n\ - tex = TexCoord;\n\ -}\n"; - -/* Default fragment shader. */ -static const GLchar *fragment_shader = "\ -in vec2 tex;\n\ -uniform sampler2D texsampler;\n\ -out vec4 color;\n\ -void main() {\n\ - color = texture(texsampler, tex);\n\ -}\n"; - -OpenGLOptions::OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion) - : QObject(parent) - , m_glslVersion(glslVersion) -{ - m_filter = video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; - - if (!loadConfig) - return; - - /* Initialize with config. */ - m_vsync = video_vsync != 0; - m_framerate = video_framerate; - - m_renderBehavior = video_framerate == -1 - ? RenderBehaviorType::SyncWithVideo - : RenderBehaviorType::TargetFramerate; - - QString shaderPath(video_shader); - - if (shaderPath.isEmpty()) { - addDefaultShader(); - } else { - try { - addShader(shaderPath); - } catch (const std::runtime_error &) { - /* Fallback to default shader */ - addDefaultShader(); - } - } -} - -void -OpenGLOptions::save() const -{ - video_vsync = m_vsync ? 1 : 0; - video_framerate = m_renderBehavior == RenderBehaviorType::SyncWithVideo ? -1 : m_framerate; - video_filter_method = m_filter == FilterType::Nearest ? 0 : 1; - - /* TODO: multiple shaders */ - auto path = m_shaders.first().path().toLocal8Bit(); - - if (!path.isEmpty()) - qstrncpy(video_shader, path.constData(), sizeof(video_shader)); - else - video_shader[0] = '\0'; -} - -OpenGLOptions::FilterType -OpenGLOptions::filter() const -{ - /* Filter method is controlled externally */ - return video_filter_method == 0 - ? FilterType::Nearest - : FilterType::Linear; -} - -void -OpenGLOptions::setRenderBehavior(RenderBehaviorType value) -{ - m_renderBehavior = value; -} - -void -OpenGLOptions::setFrameRate(int value) -{ - m_framerate = value; -} - -void -OpenGLOptions::setVSync(bool value) -{ - m_vsync = value; -} - -void -OpenGLOptions::setFilter(FilterType value) -{ - m_filter = value; -} - -void -OpenGLOptions::addShader(const QString &path) -{ - QFile shader_file(path); - - if (!shader_file.open(QIODevice::ReadOnly | QIODevice::Text)) { - throw std::runtime_error( - QString(tr("Error opening \"%1\": %2")) - .arg(path) - .arg(shader_file.errorString()) - .toStdString()); - } - - auto shader_text = QString(shader_file.readAll()); - - shader_file.close(); - - /* Remove parameter lines */ - shader_text.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); - - QRegularExpression version("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); - - auto match = version.match(shader_text); - - QString version_line(m_glslVersion); - - if (match.hasMatch()) { - /* Extract existing version and remove it. */ - version_line = match.captured(1); - shader_text.remove(version); - } - - auto shader = new QOpenGLShaderProgram(this); - - auto throw_shader_error = [path, shader](const QString &what) { - throw std::runtime_error( - QString(what % ":\n\n %2") - .arg(path) - .arg(shader->log()) - .toStdString()); - }; - - static const char *extension = "\n#extension GL_ARB_shading_language_420pack : enable\n"; - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Vertex, version_line % extension % "\n#define VERTEX\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling vertex shader in file \"%1\"")); - - if (!shader->addShaderFromSourceCode(QOpenGLShader::Fragment, version_line % extension % "\n#define FRAGMENT\n#line 1\n" % shader_text)) - throw_shader_error(tr("Error compiling fragment shader in file \"%1\"")); - - if (!shader->link()) - throw_shader_error(tr("Error linking shader program in file \"%1\"")); - - m_shaders << OpenGLShaderPass(shader, path); -} - -void -OpenGLOptions::addDefaultShader() -{ - auto shader = new QOpenGLShaderProgram(this); - shader->addShaderFromSourceCode(QOpenGLShader::Vertex, m_glslVersion % "\n" % vertex_shader); - shader->addShaderFromSourceCode(QOpenGLShader::Fragment, m_glslVersion % "\n" % fragment_shader); - shader->link(); - m_shaders << OpenGLShaderPass(shader, QString()); -} diff --git a/src/qt/qt_opengloptions.hpp b/src/qt/qt_opengloptions.hpp deleted file mode 100644 index 64f761670..000000000 --- a/src/qt/qt_opengloptions.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Header for OpenGL renderer options - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONS_HPP -#define QT_OPENGLOPTIONS_HPP - -#include -#include -#include -#include - -class OpenGLShaderPass { -public: - OpenGLShaderPass(QOpenGLShaderProgram *shader, const QString &path) - : m_shader(shader) - , m_path(path) - , m_vertex_coord(shader->attributeLocation("VertexCoord")) - , m_tex_coord(shader->attributeLocation("TexCoord")) - , m_color(shader->attributeLocation("Color")) - , m_mvp_matrix(shader->uniformLocation("MVPMatrix")) - , m_input_size(shader->uniformLocation("InputSize")) - , m_output_size(shader->uniformLocation("OutputSize")) - , m_texture_size(shader->uniformLocation("TextureSize")) - , m_frame_count(shader->uniformLocation("FrameCount")) - { - } - - bool bind() const { return m_shader->bind(); } - const QString &path() const { return m_path; } - const GLint &vertex_coord() const { return m_vertex_coord; } - const GLint &tex_coord() const { return m_tex_coord; } - const GLint &color() const { return m_color; } - const GLint &mvp_matrix() const { return m_mvp_matrix; } - const GLint &input_size() const { return m_input_size; } - const GLint &output_size() const { return m_output_size; } - const GLint &texture_size() const { return m_texture_size; } - const GLint &frame_count() const { return m_frame_count; } - -private: - QOpenGLShaderProgram *m_shader; - QString m_path; - GLint m_vertex_coord; - GLint m_tex_coord; - GLint m_color; - GLint m_mvp_matrix; - GLint m_input_size; - GLint m_output_size; - GLint m_texture_size; - GLint m_frame_count; -}; - -class OpenGLOptions : public QObject { - Q_OBJECT - -public: - enum RenderBehaviorType { SyncWithVideo, - TargetFramerate }; - - enum FilterType { Nearest, - Linear }; - - OpenGLOptions(QObject *parent, bool loadConfig, const QString &glslVersion); - - RenderBehaviorType renderBehavior() const { return m_renderBehavior; } - int framerate() const { return m_framerate; } - bool vSync() const { return m_vsync; } - FilterType filter() const; - - const QList &shaders() const { return m_shaders; } - - void setRenderBehavior(RenderBehaviorType value); - void setFrameRate(int value); - void setVSync(bool value); - void setFilter(FilterType value); - void addShader(const QString &path); - void addDefaultShader(); - void save() const; - -private: - RenderBehaviorType m_renderBehavior = SyncWithVideo; - int m_framerate = -1; - bool m_vsync = false; - FilterType m_filter = Nearest; - QList m_shaders; - QString m_glslVersion; -}; - -#endif diff --git a/src/qt/qt_opengloptionsdialog.cpp b/src/qt/qt_opengloptionsdialog.cpp deleted file mode 100644 index acb2ce9f2..000000000 --- a/src/qt/qt_opengloptionsdialog.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * OpenGL renderer options dialog for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include - -#include - -#include "qt_opengloptionsdialog.hpp" -#include "qt_util.hpp" -#include "ui_qt_opengloptionsdialog.h" - -OpenGLOptionsDialog::OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory) - : QDialog(parent) - , ui(new Ui::OpenGLOptionsDialog) - , createOptions(optionsFactory) -{ - ui->setupUi(this); - - if (options.renderBehavior() == OpenGLOptions::SyncWithVideo) - ui->syncWithVideo->setChecked(true); - else { - ui->syncToFramerate->setChecked(true); - ui->targetFps->setValue(options.framerate()); - } - - ui->vsync->setChecked(options.vSync()); - - if (!options.shaders().isEmpty()) { - auto path = options.shaders().first().path(); - if (!path.isEmpty()) - ui->shader->setPlainText(path); - } -} - -OpenGLOptionsDialog::~OpenGLOptionsDialog() -{ - delete ui; -} - -void -OpenGLOptionsDialog::accept() -{ - auto options = createOptions(); - - options->setRenderBehavior( - ui->syncWithVideo->isChecked() - ? OpenGLOptions::SyncWithVideo - : OpenGLOptions::TargetFramerate); - - options->setFrameRate(ui->targetFps->value()); - - options->setVSync(ui->vsync->isChecked()); - - auto shader = ui->shader->toPlainText(); - - try { - - if (!shader.isEmpty()) - options->addShader(shader); - else - options->addDefaultShader(); - - } catch (const std::runtime_error &e) { - delete options; - - QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Shader error")); - msgBox.setText(tr("Could not load shaders.")); - msgBox.setInformativeText(tr("More information in details.")); - msgBox.setDetailedText(e.what()); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Close); - msgBox.setDefaultButton(QMessageBox::Close); - msgBox.setStyleSheet("QTextEdit { min-width: 45em; }"); - msgBox.exec(); - - return; - } - - options->save(); - - emit optionsChanged(options); - - QDialog::accept(); -} - -void -OpenGLOptionsDialog::on_addShader_clicked() -{ - auto shader = QFileDialog::getOpenFileName( - this, - QString(), - QString(), - tr("OpenGL Shaders") % util::DlgFilter({ "glsl" }, true)); - - if (shader.isNull()) - return; - - ui->shader->setPlainText(shader); -} diff --git a/src/qt/qt_opengloptionsdialog.hpp b/src/qt/qt_opengloptionsdialog.hpp deleted file mode 100644 index f34d74d75..000000000 --- a/src/qt/qt_opengloptionsdialog.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Header for OpenGL renderer options dialog - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLOPTIONSDIALOG_H -#define QT_OPENGLOPTIONSDIALOG_H - -#include - -#include - -#include "qt_opengloptions.hpp" - -namespace Ui { -class OpenGLOptionsDialog; -} - -class OpenGLOptionsDialog : public QDialog { - Q_OBJECT - -public: - explicit OpenGLOptionsDialog(QWidget *parent, const OpenGLOptions &options, std::function optionsFactory); - ~OpenGLOptionsDialog(); - -signals: - void optionsChanged(OpenGLOptions *options); - -public slots: - void accept() override; - -private: - Ui::OpenGLOptionsDialog *ui; - - std::function createOptions; - -private slots: - void on_addShader_clicked(); -}; - -#endif // QT_OPENGLOPTIONSDIALOG_H diff --git a/src/qt/qt_opengloptionsdialog.ui b/src/qt/qt_opengloptionsdialog.ui deleted file mode 100644 index a6f86b6c2..000000000 --- a/src/qt/qt_opengloptionsdialog.ui +++ /dev/null @@ -1,280 +0,0 @@ - - - OpenGLOptionsDialog - - - - 0 - 0 - 400 - 320 - - - - OpenGL 3.0 renderer options - - - - - - Render behavior - - - - - - Use target framerate: - - - - - - - false - - - fps - - - 15 - - - 240 - - - 60 - - - - - - - VSync - - - - - - - <html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html> - - - Synchronize with video - - - true - - - - - - - false - - - 15 - - - 240 - - - 60 - - - Qt::Horizontal - - - false - - - QSlider::NoTicks - - - - - - - - - - Shaders - - - - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - true - - - No shader selected - - - - - - - Browse... - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - syncWithVideo - syncToFramerate - fpsSlider - targetFps - vsync - shader - addShader - removeShader - - - - - buttonBox - accepted() - OpenGLOptionsDialog - accept() - - - 257 - 310 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenGLOptionsDialog - reject() - - - 325 - 310 - - - 286 - 274 - - - - - syncToFramerate - toggled(bool) - targetFps - setEnabled(bool) - - - 140 - 71 - - - 380 - 98 - - - - - syncToFramerate - toggled(bool) - fpsSlider - setEnabled(bool) - - - 158 - 66 - - - 168 - 87 - - - - - fpsSlider - valueChanged(int) - targetFps - setValue(int) - - - 252 - 90 - - - 308 - 89 - - - - - targetFps - valueChanged(int) - fpsSlider - setValue(int) - - - 364 - 93 - - - 134 - 93 - - - - - removeShader - clicked() - shader - clear() - - - 333 - 201 - - - 235 - 208 - - - - - diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp deleted file mode 100644 index 60aa998a9..000000000 --- a/src/qt/qt_openglrenderer.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * OpenGL renderer for Qt - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "qt_opengloptionsdialog.hpp" -#include "qt_openglrenderer.hpp" - -#ifndef GL_MAP_PERSISTENT_BIT -# define GL_MAP_PERSISTENT_BIT 0x0040 -#endif - -#ifndef GL_MAP_COHERENT_BIT -# define GL_MAP_COHERENT_BIT 0x0080 -#endif - -OpenGLRenderer::OpenGLRenderer(QWidget *parent) - : QWindow(parent->windowHandle()) - , renderTimer(new QTimer(this)) - , options(nullptr) -{ - renderTimer->setTimerType(Qt::PreciseTimer); - /* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */ - connect(renderTimer, &QTimer::timeout, this, &OpenGLRenderer::render); - - buf_usage = std::vector(BUFFERCOUNT); - for (auto &flag : buf_usage) - flag.clear(); - - setSurfaceType(QWindow::OpenGLSurface); - - QSurfaceFormat format; - -#ifdef Q_OS_MACOS - format.setVersion(4, 1); -#else - format.setVersion(3, 2); -#endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - format.setRenderableType(QSurfaceFormat::OpenGLES); - - setFormat(format); - - parentWidget = parent; - - source.setRect(0, 0, INIT_WIDTH, INIT_HEIGHT); -} - -OpenGLRenderer::~OpenGLRenderer() -{ - finalize(); -} - -void -OpenGLRenderer::exposeEvent(QExposeEvent *event) -{ - Q_UNUSED(event); - - if (!isInitialized) - initialize(); - - onResize(size().width(), size().height()); -} - -void -OpenGLRenderer::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - - onResize(event->size().width(), event->size().height()); - - if (notReady()) - return; - - context->makeCurrent(this); - - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -} - -bool -OpenGLRenderer::event(QEvent *event) -{ - Q_UNUSED(event); - - bool res = false; - if (!eventDelegate(event, res)) - return QWindow::event(event); - return res; -} - -void -OpenGLRenderer::initialize() -{ - try { - context = new QOpenGLContext(this); - - context->setFormat(format()); - - if (!context->create()) - throw opengl_init_error(tr("Couldn't create OpenGL context.")); - - if (!context->makeCurrent(this)) - throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); - - auto version = context->format().version(); - - if (version.first < 3) - throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); - - initializeOpenGLFunctions(); - - /* Prepare the shader version string */ - glslVersion = reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); - glslVersion.truncate(4); - glslVersion.remove('.'); - glslVersion.prepend("#version "); - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) - glslVersion.append(" es"); - else if (context->format().profile() == QSurfaceFormat::CoreProfile) - glslVersion.append(" core"); - - initializeExtensions(); - - initializeBuffers(); - - /* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */ - const GLfloat surface[] = { - -1.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, - 1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, - -1.f, -1.f, 0.f, 1.f, 1.f, 1.f, 1.f, 1.f, - 1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f - }; - - glGenVertexArrays(1, &vertexArrayID); - - glBindVertexArray(vertexArrayID); - - glGenBuffers(1, &vertexBufferID); - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); - glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW); - - glGenTextures(1, &textureID); - glBindTexture(GL_TEXTURE_2D, textureID); - - const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f }; - - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - - reloadOptions(); - - glClearColor(0.f, 0.f, 0.f, 1.f); - - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); - - GLenum error = glGetError(); - if (error != GL_NO_ERROR) - throw opengl_init_error(tr("OpenGL initialization failed. Error %1.").arg(error)); - - isInitialized = true; - - emit initialized(); - - glClear(GL_COLOR_BUFFER_BIT); - - context->swapBuffers(this); - } catch (const opengl_init_error &e) { - /* Mark all buffers as in use */ - for (auto &flag : buf_usage) - flag.test_and_set(); - - QMessageBox::critical((QWidget *) qApp->findChild(), tr("Error initializing OpenGL"), e.what() % tr("\nFalling back to software rendering.")); - - context->doneCurrent(); - isFinalized = true; - isInitialized = true; - - emit errorInitializing(); - } -} - -void -OpenGLRenderer::finalize() -{ - if (isFinalized) - return; - - renderTimer->stop(); - - context->makeCurrent(this); - - if (hasBufferStorage) - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - - glDeleteBuffers(1, &unpackBufferID); - glDeleteTextures(1, &textureID); - glDeleteBuffers(1, &vertexBufferID); - glDeleteVertexArrays(1, &vertexArrayID); - - if (!hasBufferStorage && unpackBuffer) - free(unpackBuffer); - - context->doneCurrent(); - - isFinalized = true; -} - -QDialog * -OpenGLRenderer::getOptions(QWidget *parent) -{ - auto dialog = new OpenGLOptionsDialog(parent, *options, [this]() { return new OpenGLOptions(this, false, glslVersion); }); - - connect(dialog, &OpenGLOptionsDialog::optionsChanged, this, &OpenGLRenderer::updateOptions); - - return dialog; -} - -void -OpenGLRenderer::initializeExtensions() -{ -#ifndef NO_BUFFER_STORAGE - if (context->hasExtension("GL_ARB_buffer_storage") || context->hasExtension("GL_EXT_buffer_storage")) { - hasBufferStorage = true; - - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress(context->hasExtension("GL_EXT_buffer_storage") ? "glBufferStorageEXT" : "glBufferStorage"); - if (!glBufferStorage) - glBufferStorage = (PFNGLBUFFERSTORAGEEXTPROC_LOCAL) context->getProcAddress("glBufferStorage"); - } -#endif -} - -void -OpenGLRenderer::initializeBuffers() -{ - glGenBuffers(1, &unpackBufferID); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); - - if (hasBufferStorage) { -#ifndef NO_BUFFER_STORAGE - /* Create persistent buffer for pixel transfer. */ - glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); - - unpackBuffer = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); -#endif - } else { - /* Fallback; create our own buffer. */ - unpackBuffer = malloc(BUFFERBYTES * BUFFERCOUNT); - - if (unpackBuffer == nullptr) - throw opengl_init_error(tr("Allocating memory for unpack buffer failed.")); - - glBufferData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_STREAM_DRAW); - } -} - -void -OpenGLRenderer::applyOptions() -{ - /* TODO: change detection in options */ - - if (options->framerate() > 0) { - int interval = (int) ceilf(1000.f / (float) options->framerate()); - renderTimer->setInterval(std::chrono::milliseconds(interval)); - } - - if (options->renderBehavior() == OpenGLOptions::TargetFramerate) - renderTimer->start(); - else - renderTimer->stop(); - - auto format = this->format(); - int interval = options->vSync() ? 1 : 0; - - if (format.swapInterval() != interval) { - format.setSwapInterval(interval); - setFormat(format); - context->setFormat(format); - } - - GLint filter = options->filter() == OpenGLOptions::Linear ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - - currentFilter = options->filter(); -} - -void -OpenGLRenderer::reloadOptions() -{ - if (options) { - delete options; - options = nullptr; - } - options = new OpenGLOptions(this, true, glslVersion); - - applyOptions(); -} - -void -OpenGLRenderer::applyShader(const OpenGLShaderPass &shader) -{ - if (!shader.bind()) - return; - - if (shader.vertex_coord() != -1) { - glEnableVertexAttribArray(shader.vertex_coord()); - glVertexAttribPointer(shader.vertex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0); - } - - if (shader.tex_coord() != -1) { - glEnableVertexAttribArray(shader.tex_coord()); - glVertexAttribPointer(shader.tex_coord(), 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (2 * sizeof(GLfloat))); - } - - if (shader.color() != -1) { - glEnableVertexAttribArray(shader.color()); - glVertexAttribPointer(shader.color(), 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void *) (4 * sizeof(GLfloat))); - } - - if (shader.mvp_matrix() != -1) { - static const GLfloat mvp[] = { - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f - }; - glUniformMatrix4fv(shader.mvp_matrix(), 1, GL_FALSE, mvp); - } - - if (shader.output_size() != -1) - glUniform2f(shader.output_size(), destination.width(), destination.height()); - - if (shader.input_size() != -1) - glUniform2f(shader.input_size(), source.width(), source.height()); - - if (shader.texture_size() != -1) - glUniform2f(shader.texture_size(), source.width(), source.height()); - - if (shader.frame_count() != -1) - glUniform1i(shader.frame_count(), frameCounter); -} - -void -OpenGLRenderer::render() -{ - context->makeCurrent(this); - - if (options->filter() != currentFilter) - applyOptions(); - - /* TODO: multiple shader passes */ - applyShader(options->shaders().first()); - - glClear(GL_COLOR_BUFFER_BIT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - context->swapBuffers(this); - - frameCounter = (frameCounter + 1) & 1023; -} - -void -OpenGLRenderer::updateOptions(OpenGLOptions *newOptions) -{ - context->makeCurrent(this); - - glUseProgram(0); - - delete options; - - options = newOptions; - - options->setParent(this); - - applyOptions(); -} - -std::vector> -OpenGLRenderer::getBuffers() -{ - std::vector> buffers; - - if (notReady() || !unpackBuffer) - return buffers; - - /* Split the buffer area */ - for (int i = 0; i < BUFFERCOUNT; i++) { - buffers.push_back(std::make_tuple((uint8_t *) unpackBuffer + BUFFERBYTES * i, &buf_usage[i])); - } - - return buffers; -} - -void -OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) -{ - if (notReady()) - return; - - context->makeCurrent(this); - -#ifdef Q_OS_MACOS - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -#endif - - if (source.width() != w || source.height() != h) { - source.setRect(0, 0, w, h); - - /* Resize the texture */ - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, source.width(), source.height(), 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, unpackBufferID); - } - - if (!hasBufferStorage) - glBufferSubData(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * buf_idx, h * ROW_LENGTH * sizeof(uint32_t) + (y * ROW_LENGTH * sizeof(uint32_t)), (uint8_t *) unpackBuffer + BUFFERBYTES * buf_idx); - - glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * buf_idx + y * ROW_LENGTH + x); - glPixelStorei(GL_UNPACK_ROW_LENGTH, ROW_LENGTH); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - - /* TODO: check if fence sync is implementable here and still has any benefit. */ - glFinish(); - - buf_usage[buf_idx].clear(); - - if (options->renderBehavior() == OpenGLOptions::SyncWithVideo) - render(); -} diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp deleted file mode 100644 index 27822600c..000000000 --- a/src/qt/qt_openglrenderer.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Header file for OpenGL renderer - * - * - * - * Authors: Teemu Korhonen - * - * Copyright 2022 Teemu Korhonen - */ - -#ifndef QT_OPENGLRENDERER_HPP -#define QT_OPENGLRENDERER_HPP - -#if defined Q_OS_MACOS || __arm__ -# define NO_BUFFER_STORAGE -#endif - -#include -#include -#include -#include -#include -#include -#if !defined NO_BUFFER_STORAGE && !(QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) -# include -#endif - -#include -#include -#include -#include - -#include "qt_opengloptions.hpp" -#include "qt_renderercommon.hpp" - -typedef void(QOPENGLF_APIENTRYP PFNGLBUFFERSTORAGEEXTPROC_LOCAL)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); - -class OpenGLRenderer : public QWindow, protected QOpenGLExtraFunctions, public RendererCommon { - Q_OBJECT - -public: - QOpenGLContext *context; - - OpenGLRenderer(QWidget *parent = nullptr); - ~OpenGLRenderer(); - - std::vector> getBuffers() override; - - void finalize() override final; - bool hasOptions() const override { return true; } - QDialog *getOptions(QWidget *parent) override; - void reloadOptions() override; - -signals: - void initialized(); - void errorInitializing(); - -public slots: - void onBlit(int buf_idx, int x, int y, int w, int h); - -protected: - void exposeEvent(QExposeEvent *event) override; - void resizeEvent(QResizeEvent *event) override; - bool event(QEvent *event) override; - -private: - static constexpr int INIT_WIDTH = 640; - static constexpr int INIT_HEIGHT = 400; - static constexpr int ROW_LENGTH = 2048; - static constexpr int BUFFERPIXELS = 4194304; - static constexpr int BUFFERBYTES = 16777216; /* Pixel is 4 bytes. */ - static constexpr int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */ - - QTimer *renderTimer; - OpenGLOptions *options; - - QString glslVersion; - - bool isInitialized = false; - bool isFinalized = false; - - GLuint unpackBufferID = 0; - GLuint vertexArrayID = 0; - GLuint vertexBufferID = 0; - GLuint textureID = 0; - int frameCounter = 0; - - OpenGLOptions::FilterType currentFilter; - - void *unpackBuffer = nullptr; - - void initialize(); - void initializeExtensions(); - void initializeBuffers(); - void applyOptions(); - void applyShader(const OpenGLShaderPass &shader); - bool notReady() const { return !isInitialized || isFinalized; } - - /* GL_ARB_buffer_storage */ - bool hasBufferStorage = false; -#ifndef NO_BUFFER_STORAGE - PFNGLBUFFERSTORAGEEXTPROC_LOCAL glBufferStorage = nullptr; -#endif - -private slots: - void render(); - void updateOptions(OpenGLOptions *newOptions); -}; - -class opengl_init_error : public std::runtime_error { -public: - opengl_init_error(const QString &what) - : std::runtime_error(what.toStdString()) - { - } -}; - -#endif diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer_pcem.cpp index 79960323f..5b1c8518d 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer_pcem.cpp @@ -1,3 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * OpenGL renderer for Qt, mostly ported over from PCem. + * + * + * + * Authors: Teemu Korhonen + * Cacodemon345 + * bit + * Sarah Walker + * + * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 + * Copyright 2017 Bit + * Copyright 2017-2020 Sarah Walker + */ + #include "qt_renderercommon.hpp" #include "qt_mainwindow.hpp" @@ -114,7 +137,7 @@ next_pow2(unsigned int n) } int -OpenGLRendererPCem::create_program(struct shader_program *program) +OpenGLRenderer::create_program(struct shader_program *program) { GLint status; program->id = glw.glCreateProgram(); @@ -146,7 +169,7 @@ OpenGLRendererPCem::create_program(struct shader_program *program) } int -OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) +OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { const char *source[3]; char version[50]; @@ -197,19 +220,19 @@ OpenGLRendererPCem::compile_shader(GLenum shader_type, const char *prepend, cons } GLuint -OpenGLRendererPCem::get_uniform(GLuint program, const char *name) +OpenGLRenderer::get_uniform(GLuint program, const char *name) { return glw.glGetUniformLocation(program, name); } GLuint -OpenGLRendererPCem::get_attrib(GLuint program, const char *name) +OpenGLRenderer::get_attrib(GLuint program, const char *name) { return glw.glGetAttribLocation(program, name); } void -OpenGLRendererPCem::find_uniforms(struct glsl_shader *glsl, int num_pass) +OpenGLRenderer::find_uniforms(struct glsl_shader *glsl, int num_pass) { int i; char s[50]; @@ -294,7 +317,7 @@ setup_scale(struct shader *shader, struct shader_pass *pass) } void -OpenGLRendererPCem::create_texture(struct shader_texture *tex) +OpenGLRenderer::create_texture(struct shader_texture *tex) { if (tex->width > max_texture_size) tex->width = max_texture_size; @@ -314,7 +337,7 @@ OpenGLRendererPCem::create_texture(struct shader_texture *tex) } void -OpenGLRendererPCem::delete_texture(struct shader_texture *tex) +OpenGLRenderer::delete_texture(struct shader_texture *tex) { if (tex->id > 0) glw.glDeleteTextures(1, (GLuint *) &tex->id); @@ -322,7 +345,7 @@ OpenGLRendererPCem::delete_texture(struct shader_texture *tex) } void -OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) +OpenGLRenderer::delete_fbo(struct shader_fbo *fbo) { if (fbo->id >= 0) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -331,7 +354,7 @@ OpenGLRendererPCem::delete_fbo(struct shader_fbo *fbo) } void -OpenGLRendererPCem::delete_program(struct shader_program *program) +OpenGLRenderer::delete_program(struct shader_program *program) { if (program->vertex_shader) glw.glDeleteShader(program->vertex_shader); @@ -341,7 +364,7 @@ OpenGLRendererPCem::delete_program(struct shader_program *program) } void -OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) +OpenGLRenderer::delete_vbo(struct shader_vbo *vbo) { if (vbo->color >= 0) glw.glDeleteBuffers(1, (GLuint *) &vbo->color); @@ -350,7 +373,7 @@ OpenGLRendererPCem::delete_vbo(struct shader_vbo *vbo) } void -OpenGLRendererPCem::delete_pass(struct shader_pass *pass) +OpenGLRenderer::delete_pass(struct shader_pass *pass) { delete_fbo(&pass->fbo); delete_vbo(&pass->vbo); @@ -359,14 +382,14 @@ OpenGLRendererPCem::delete_pass(struct shader_pass *pass) } void -OpenGLRendererPCem::delete_prev(struct shader_prev *prev) +OpenGLRenderer::delete_prev(struct shader_prev *prev) { delete_fbo(&prev->fbo); delete_vbo(&prev->vbo); } void -OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) +OpenGLRenderer::delete_shader(struct glsl_shader *glsl) { int i; for (i = 0; i < glsl->num_passes; ++i) @@ -381,7 +404,7 @@ OpenGLRendererPCem::delete_shader(struct glsl_shader *glsl) } void -OpenGLRendererPCem::delete_glsl(glsl_t *glsl) +OpenGLRenderer::delete_glsl(glsl_t *glsl) { int i; for (i = 0; i < glsl->num_shaders; ++i) @@ -395,7 +418,7 @@ OpenGLRendererPCem::delete_glsl(glsl_t *glsl) } void -OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) +OpenGLRenderer::create_fbo(struct shader_fbo *fbo) { create_texture(&fbo->texture); @@ -410,7 +433,7 @@ OpenGLRendererPCem::create_fbo(struct shader_fbo *fbo) } void -OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) +OpenGLRenderer::setup_fbo(struct shader *shader, struct shader_fbo *fbo) { fbo->texture.internal_format = GL_RGBA8; fbo->texture.format = GL_RGBA; @@ -442,7 +465,7 @@ OpenGLRendererPCem::setup_fbo(struct shader *shader, struct shader_fbo *fbo) } void -OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) +OpenGLRenderer::recreate_fbo(struct shader_fbo *fbo, int width, int height) { if (width != fbo->texture.width || height != fbo->texture.height) { glw.glDeleteFramebuffers(1, (GLuint *) &fbo->id); @@ -454,7 +477,7 @@ OpenGLRendererPCem::recreate_fbo(struct shader_fbo *fbo, int width, int height) } int -OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) +OpenGLRenderer::create_default_shader_tex(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -474,7 +497,7 @@ OpenGLRendererPCem::create_default_shader_tex(struct shader_pass *pass) } int -OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) +OpenGLRenderer::create_default_shader_color(struct shader_pass *pass) { if (!compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || !create_program(&pass->program)) return 0; @@ -494,7 +517,7 @@ OpenGLRendererPCem::create_default_shader_color(struct shader_pass *pass) /* create the default scene shader */ void -OpenGLRendererPCem::create_scene_shader() +OpenGLRenderer::create_scene_shader() { struct shader scene_shader_conf; memset(&scene_shader_conf, 0, sizeof(struct shader)); @@ -554,7 +577,7 @@ load_texture(const char *f, struct shader_texture *tex) } glsl_t * -OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) +OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) { int i, j; glslp_t *p = glslp_parse(f); @@ -704,7 +727,7 @@ OpenGLRendererPCem::load_glslp(glsl_t *glsl, int num_shader, const char *f) } glsl_t * -OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +OpenGLRenderer::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) { int i; glsl_t *glsl; @@ -731,7 +754,7 @@ OpenGLRendererPCem::load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) } void -OpenGLRendererPCem::read_shader_config() +OpenGLRenderer::read_shader_config() { char s[512]; int i, j; @@ -747,10 +770,9 @@ OpenGLRendererPCem::read_shader_config() } } -OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) +OpenGLRenderer::OpenGLRenderer(QWidget *parent) : QWindow(parent->windowHandle()) , renderTimer(new QTimer(this)) - , options(nullptr) { connect(renderTimer, &QTimer::timeout, this, [this]() { this->render(); } ); imagebufs[0] = std::unique_ptr(new uint8_t[2048 * 2048 * 4]); @@ -785,10 +807,10 @@ OpenGLRendererPCem::OpenGLRendererPCem(QWidget *parent) isFinalized = false; } -OpenGLRendererPCem::~OpenGLRendererPCem() { finalize(); } +OpenGLRenderer::~OpenGLRenderer() { finalize(); } void -OpenGLRendererPCem::initialize() +OpenGLRenderer::initialize() { try { context = new QOpenGLContext(this); @@ -796,15 +818,15 @@ OpenGLRendererPCem::initialize() context->setFormat(format()); if (!context->create()) - throw opengl_init_error_pcem(tr("Couldn't create OpenGL context.")); + throw opengl_init_error(tr("Couldn't create OpenGL context.")); if (!context->makeCurrent(this)) - throw opengl_init_error_pcem(tr("Couldn't switch to OpenGL context.")); + throw opengl_init_error(tr("Couldn't switch to OpenGL context.")); auto version = context->format().version(); if (version.first < 3) - throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current version is %1.%2").arg(version.first).arg(version.second)); glw.initializeOpenGLFunctions(); @@ -813,7 +835,7 @@ OpenGLRendererPCem::initialize() glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); if (glsl_version[0] < 3) { - throw opengl_init_error_pcem(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); + throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); } pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); @@ -1035,7 +1057,7 @@ OpenGLRendererPCem::initialize() glw.glClear(GL_COLOR_BUFFER_BIT); context->swapBuffers(this); - } catch (const opengl_init_error_pcem &e) { + } catch (const opengl_init_error &e) { /* Mark all buffers as in use */ for (auto &flag : buf_usage) flag.test_and_set(); @@ -1051,7 +1073,7 @@ OpenGLRendererPCem::initialize() } void -OpenGLRendererPCem::finalize() +OpenGLRenderer::finalize() { if (isFinalized) return; @@ -1074,7 +1096,7 @@ OpenGLRendererPCem::finalize() } void -OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) +OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { if (notReady()) return; @@ -1112,7 +1134,7 @@ OpenGLRendererPCem::onBlit(int buf_idx, int x, int y, int w, int h) } std::vector> -OpenGLRendererPCem::getBuffers() +OpenGLRenderer::getBuffers() { std::vector> buffers; @@ -1123,7 +1145,7 @@ OpenGLRendererPCem::getBuffers() } void -OpenGLRendererPCem::exposeEvent(QExposeEvent *event) +OpenGLRenderer::exposeEvent(QExposeEvent *event) { Q_UNUSED(event); @@ -1134,7 +1156,7 @@ OpenGLRendererPCem::exposeEvent(QExposeEvent *event) } void -OpenGLRendererPCem::resizeEvent(QResizeEvent *event) +OpenGLRenderer::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); @@ -1153,7 +1175,7 @@ OpenGLRendererPCem::resizeEvent(QResizeEvent *event) } void -OpenGLRendererPCem::render_pass(struct render_data *data) +OpenGLRenderer::render_pass(struct render_data *data) { int i; GLuint texture_unit = 0; @@ -1298,7 +1320,7 @@ OpenGLRendererPCem::render_pass(struct render_data *data) } bool -OpenGLRendererPCem::event(QEvent *event) +OpenGLRenderer::event(QEvent *event) { Q_UNUSED(event); @@ -1309,13 +1331,13 @@ OpenGLRendererPCem::event(QEvent *event) } QDialog* -OpenGLRendererPCem::getOptions(QWidget *parent) +OpenGLRenderer::getOptions(QWidget *parent) { return new OpenGLShaderManagerDialog(parent); } void -OpenGLRendererPCem::render() +OpenGLRenderer::render() { if (!context) return; @@ -1353,17 +1375,12 @@ OpenGLRendererPCem::render() struct { uint32_t x, y, w, h; - } rect, video_rect; + } rect; rect.x = 0; rect.y = 0; rect.w = source.width(); rect.h = source.height(); - video_rect.x = source.x(); - video_rect.y = source.y(); - video_rect.w = source.width(); - video_rect.h = source.height(); - pass->state.input_size[0] = pass->state.output_size[0] = rect.w; pass->state.input_size[1] = pass->state.output_size[1] = rect.h; diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer_pcem.hpp index 706a744fa..9db1e7307 100644 --- a/src/qt/qt_openglrenderer_pcem.hpp +++ b/src/qt/qt_openglrenderer_pcem.hpp @@ -11,12 +11,14 @@ * * * Authors: Teemu Korhonen + * Cacodemon345 * * Copyright 2022 Teemu Korhonen + * Copyright 2025 Cacodemon345 */ -#ifndef QT_OpenGLRendererPCem_HPP -#define QT_OpenGLRendererPCem_HPP +#ifndef QT_OpenGLRenderer_HPP +#define QT_OpenGLRenderer_HPP #if defined Q_OS_MACOS || __arm__ # define NO_BUFFER_STORAGE @@ -37,7 +39,6 @@ #include #include -#include "qt_opengloptions.hpp" #include "qt_renderercommon.hpp" extern "C" @@ -55,14 +56,14 @@ struct render_data { int frame_count; }; -class OpenGLRendererPCem : public QWindow, public RendererCommon { +class OpenGLRenderer : public QWindow, public RendererCommon { Q_OBJECT public: QOpenGLContext *context; - OpenGLRendererPCem(QWidget *parent = nullptr); - ~OpenGLRendererPCem(); + OpenGLRenderer(QWidget *parent = nullptr); + ~OpenGLRenderer(); std::vector> getBuffers() override; @@ -88,7 +89,6 @@ private: std::array, 2> imagebufs; QTimer *renderTimer; - OpenGLOptions *options; QString glslVersion = ""; @@ -98,7 +98,6 @@ private: int max_texture_size = 65536; int frameCounter = 0; - OpenGLOptions::FilterType currentFilter; QOpenGLExtraFunctions glw; struct shader_texture scene_texture; glsl_t *active_shader; @@ -144,12 +143,11 @@ private: private slots: void render(); - //void updateOptions(OpenGLOptions *newOptions); }; -class opengl_init_error_pcem : public std::runtime_error { +class opengl_init_error : public std::runtime_error { public: - opengl_init_error_pcem(const QString &what) + opengl_init_error(const QString &what) : std::runtime_error(what.toStdString()) { } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 63d35e719..26ea2271f 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -22,7 +22,6 @@ #include "ui_qt_rendererstack.h" #include "qt_hardwarerenderer.hpp" -#include "qt_openglrenderer.hpp" #include "qt_openglrenderer_pcem.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" @@ -341,16 +340,16 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3PCem: { this->createWinId(); - auto hw = new OpenGLRendererPCem(this); + auto hw = new OpenGLRenderer(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRendererPCem::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); @@ -361,16 +360,16 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3: { this->createWinId(); - auto hw = new OpenGLRendererPCem(this); + auto hw = new OpenGLRenderer(this); rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRendererPCem::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRendererPCem::initialized, [=]() { + connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); + connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); }); - connect(hw, &OpenGLRendererPCem::errorInitializing, [=]() { + connect(hw, &OpenGLRenderer::errorInitializing, [=]() { /* Renderer not could initialize, fallback to software. */ imagebufs = {}; QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); From 3cad9024c843575792f3d062d73c350396183c1a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 21:14:10 +0600 Subject: [PATCH 0445/1190] Rename the files as well --- src/qt/CMakeLists.txt | 4 ++-- src/qt/{qt_openglrenderer_pcem.cpp => qt_openglrenderer.cpp} | 2 +- src/qt/{qt_openglrenderer_pcem.hpp => qt_openglrenderer.hpp} | 0 src/qt/qt_rendererstack.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/qt/{qt_openglrenderer_pcem.cpp => qt_openglrenderer.cpp} (99%) rename src/qt/{qt_openglrenderer_pcem.hpp => qt_openglrenderer.hpp} (100%) diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 8137be98e..90ea218af 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -87,8 +87,8 @@ add_library(ui STATIC qt_softwarerenderer.hpp qt_hardwarerenderer.cpp qt_hardwarerenderer.hpp - qt_openglrenderer_pcem.cpp - qt_openglrenderer_pcem.hpp + qt_openglrenderer.cpp + qt_openglrenderer.hpp qt_glsl_parser.cpp qt_settings.cpp diff --git a/src/qt/qt_openglrenderer_pcem.cpp b/src/qt/qt_openglrenderer.cpp similarity index 99% rename from src/qt/qt_openglrenderer_pcem.cpp rename to src/qt/qt_openglrenderer.cpp index 5b1c8518d..97a782f57 100644 --- a/src/qt/qt_openglrenderer_pcem.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -45,7 +45,7 @@ extern MainWindow* main_window; #include -#include "qt_openglrenderer_pcem.hpp" +#include "qt_openglrenderer.hpp" #include "qt_openglshadermanagerdialog.hpp" extern "C" { diff --git a/src/qt/qt_openglrenderer_pcem.hpp b/src/qt/qt_openglrenderer.hpp similarity index 100% rename from src/qt/qt_openglrenderer_pcem.hpp rename to src/qt/qt_openglrenderer.hpp diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 26ea2271f..ca16b680e 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -22,7 +22,7 @@ #include "ui_qt_rendererstack.h" #include "qt_hardwarerenderer.hpp" -#include "qt_openglrenderer_pcem.hpp" +#include "qt_openglrenderer.hpp" #include "qt_softwarerenderer.hpp" #include "qt_vulkanwindowrenderer.hpp" From 1ac02618b0fa9d6acc8f3f9f1d053706884dc313 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 21:22:52 +0600 Subject: [PATCH 0446/1190] Clean up secondary monitors properly on close --- src/qt/qt_mainwindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 85bc0de55..3af9c6f70 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -784,6 +784,14 @@ MainWindow::closeEvent(QCloseEvent *event) ui->stackedWidget->mouse_exit_func(); ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->isHidden()) { + renderers[i]->show(); + QApplication::processEvents(); + renderers[i]->switchRenderer(RendererStack::Renderer::Software); + QApplication::processEvents(); + } + } qt_nvr_save(); config_save(); From c832729ee565fdd54eadec896f2f9bb72b1cc99b Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 16:31:52 +0100 Subject: [PATCH 0447/1190] Config: Ignore the GL3 stuff on SDL builds. --- src/config.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/config.c b/src/config.c index 5ad804df6..e5fbe59b4 100644 --- a/src/config.c +++ b/src/config.c @@ -77,9 +77,11 @@ #include <86box/snd_opl.h> #include <86box/version.h> +#ifndef USE_SDL_UI /* Deliberate to not make the 86box.h header kitchen-sink. */ #include <86box/qt-glsl.h> extern char gl3_shader_file[MAX_USER_SHADERS][512]; +#endif static int cx; static int cy; @@ -1717,6 +1719,7 @@ load_other_peripherals(void) ini_section_delete_var(cat, temp); } +#ifndef USE_SDL_UI /* Load OpenGL 3.0 renderer options. */ static void load_gl3_shaders(void) @@ -1756,6 +1759,7 @@ load_gl3_shaders(void) } } } +#endif /* Load the specified or a default configuration file. */ void @@ -1853,7 +1857,9 @@ config_load(void) load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ load_other_removable_devices(); /* Other removable devices */ load_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI load_gl3_shaders(); /* GL3 Shaders */ +#endif /* Migrate renamed device configurations. */ c = ini_find_section(config, "MDA"); @@ -2672,6 +2678,7 @@ save_other_peripherals(void) ini_delete_section_if_empty(config, cat); } +#ifndef USE_SDL_UI /* Save "GL3 Shaders" section. */ static void save_gl3_shaders(void) @@ -2703,6 +2710,7 @@ save_gl3_shaders(void) ini_delete_section_if_empty(config, cat); } +#endif /* Save "Hard Disks" section. */ static void @@ -3059,7 +3067,9 @@ config_save(void) save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ save_other_peripherals(); /* Other peripherals */ +#ifndef USE_SDL_UI save_gl3_shaders(); /* GL3 Shaders */ +#endif ini_write(config, cfg_path); } From 48a5f3280fed8def764c6d8406a252155964eea1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:26:44 +0100 Subject: [PATCH 0448/1190] device_t: Increase the selection array to 64 elements. --- src/include/86box/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/86box/device.h b/src/include/86box/device.h index fb86d2adc..91ff2daa6 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -153,7 +153,7 @@ typedef struct _device_config_ { int default_int; const char *file_filter; const device_config_spinner_t spinner; - const device_config_selection_t selection[32]; + const device_config_selection_t selection[64]; const device_config_bios_t bios[32]; } device_config_t; From 8a2d841322c2af189acad170a678cad70cd11c24 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:29:42 +0100 Subject: [PATCH 0449/1190] OpenGL Renderer: Mark reloadRendererOption() as override, fixes compile on Mac. --- src/qt/qt_openglrenderer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp index 9db1e7307..4d1f68acb 100644 --- a/src/qt/qt_openglrenderer.hpp +++ b/src/qt/qt_openglrenderer.hpp @@ -70,7 +70,7 @@ public: void finalize() override final; bool hasOptions() const override { return true; } QDialog *getOptions(QWidget *parent) override; - bool reloadRendererOption() { return true; } + bool reloadRendererOption() override { return true; } signals: void initialized(); From c763c6db169c2b4f2ed9d1f8177d36d67166edfa Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:31:18 +0100 Subject: [PATCH 0450/1190] INI: Include so iswspace() is also found in Linux. --- src/ini.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ini.c b/src/ini.c index 503b17ae3..f5dfdef46 100644 --- a/src/ini.c +++ b/src/ini.c @@ -33,6 +33,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/ini.h> From 6fa39b3a67a0818f3d6a2535e5074d5901558cc1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:32:46 +0100 Subject: [PATCH 0451/1190] OpenGL Renderer: Explicitly cast const char * to char *. --- src/qt/qt_openglrenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 97a782f57..860b5d303 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -174,7 +174,7 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch const char *source[3]; char version[50]; int ver = 0; - char *version_loc = strstr(program, "#version"); + char *version_loc = (char *) strstr(program, "#version"); if (version_loc) ver = (int) strtol(version_loc + 8, (char **) &program, 10); else { From df85868e00cd3d8e71300f8d89323d8fd0be5631 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 17:34:33 +0100 Subject: [PATCH 0452/1190] Config: Brought the strncpy() in load_gl3_shaders() in line with the other stncpy()'s. --- src/config.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index e5fbe59b4..f68b23c37 100644 --- a/src/config.c +++ b/src/config.c @@ -1740,7 +1740,10 @@ load_gl3_shaders(void) if (general) { p = ini_section_get_string(general, "video_gl_shader", NULL); if (p) { - strncpy(gl3_shader_file[0], p, 512); + if (strlen(p) > 511) + fatal("Configuration: Length of video_gl_shadr is more than 511\n"); + else + strncpy(gl3_shader_file[0], p, 511); ini_delete_var(config, general, "video_gl_shader"); return; } From daf6e242efa3f244d05aa3f5ba6cf4b50b3c66a5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 18:00:28 +0100 Subject: [PATCH 0453/1190] QT GLSL Parser: More explicit const char * to char * casts. --- src/qt/qt_glsl_parser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index bf02014db..9a0a0fc03 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -101,11 +101,11 @@ static char *load_file(const char *fn) { static void strip_lines(const char *program, const char *starts_with) { /* strip parameters */ - char *ptr = strstr(program, starts_with); - while (ptr) { + char *ptr = (char *) strstr(program, starts_with); + while (ptr != nullptr) { while (*ptr != '\n' && *ptr != '\0') *ptr++ = ' '; - ptr = strstr(program, starts_with); + ptr = (char *) strstr(program, starts_with); } } From df1f739b90f53c1532492f6fa50c7585f0e95718 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 23:02:18 +0600 Subject: [PATCH 0454/1190] OpenGL 3.x screenshots are now processed --- src/qt/qt_openglrenderer.cpp | 114 +++++++++-------------------------- src/qt/qt_renderercommon.hpp | 2 + src/qt/qt_rendererstack.cpp | 7 ++- src/qt/qt_rendererstack.hpp | 4 ++ 4 files changed, 39 insertions(+), 88 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 860b5d303..37afd4810 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1612,95 +1612,35 @@ OpenGLRenderer::render() render_pass(&data); } - if (1) { - // if (video_focus_dim && !(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS)) { -#if 0 - if (0) { - struct shader_pass *pass = &active_shader->fs_color; - GLfloat r = 0; - GLfloat g = 0; - GLfloat b = 0; - GLfloat a = 0x80 / (float) 0xff; + if (monitors[r_monitor_index].mon_screenshots) { + int width = destination.width() * devicePixelRatio(), height = destination.height() * devicePixelRatio(); + char path[1024]; + char fn[256]; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + path_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (!plat_dir_check(path)) + plat_dir_create(path); + + path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", r_monitor_index + 1); + + plat_tempfile(fn, NULL, (char*)".png"); + strcat(path, fn); - GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a }; + unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); + + glw.glFinish(); + glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); - glw.glBindVertexArray(pass->vertex_array); - - glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); - glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); - glw.glBindBuffer(GL_ARRAY_BUFFER, 0); - - memset(&data, 0, sizeof(struct render_data)); - data.pass = -3; - data.shader_pass = pass; - data.texture = 0; - data.output_size = orig_output_size; - data.orig_pass = orig; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - render_pass(&data); - glDisable(GL_BLEND); - } - - if (flash.enabled) { - struct shader_pass *pass = &active_shader->fs_color; - GLfloat r = (flash.color[0] & 0xff) / (float)0xff; - GLfloat g = (flash.color[1] & 0xff) / (float)0xff; - GLfloat b = (flash.color[2] & 0xff) / (float)0xff; - GLfloat a = (flash.color[3] & 0xff) / (float)0xff; - - GLfloat colors[] = {r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a}; - - glw.glBindVertexArray(pass->vertex_array); - - glw.glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); - glw.glBufferSubData(GL_ARRAY_BUFFER, 0, 16 * sizeof(GLfloat), colors); - glw.glBindBuffer(GL_ARRAY_BUFFER, 0); - - memset(&data, 0, sizeof(struct render_data)); - data.pass = -3; - data.shader_pass = pass; - data.texture = 0; - data.output_size = orig_output_size; - data.orig_pass = orig; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - render_pass(&data); - glDisable(GL_BLEND); - } -#endif - } else { -#if 0 - take_screenshot = 0; - - int width = window_rect.w; - int height = window_rect.h; - - SDL_GetWindowSize(window, &width, &height); - - unsigned char *rgba = (unsigned char *)malloc(width * height * 4); - - glFinish(); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); - - int x, y; - unsigned char *rgb = (unsigned char *)malloc(width * height * 3); - - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - rgb[(y * width + x) * 3 + 0] = rgba[((height - y - 1) * width + x) * 4 + 0]; - rgb[(y * width + x) * 3 + 1] = rgba[((height - y - 1) * width + x) * 4 + 1]; - rgb[(y * width + x) * 3 + 2] = rgba[((height - y - 1) * width + x) * 4 + 2]; - } - } - - screenshot_taken(rgb, width, height); - - free(rgb); - free(rgba); -#endif + QImage image(rgba, width, height, QImage::Format_RGBA8888); + image.mirrored(false, true).save(path, "png"); + monitors[r_monitor_index].mon_screenshots--; + free(rgba); } glw.glDisable(GL_FRAMEBUFFER_SRGB); diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index f3f5d2223..bbda9516b 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -36,6 +36,8 @@ public: virtual void reloadOptions() { } /* Make the renderer reload itself */ virtual bool reloadRendererOption() { return false; } + /* Should the renderer take screenshots itself? */ + virtual bool rendererTakeScreenshot() { return false; } int r_monitor_index = 0; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index ca16b680e..38f087622 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -63,6 +63,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) { + rendererTakesScreenshots = false; #ifdef Q_OS_WINDOWS int raw = 1; #else @@ -305,6 +306,7 @@ RendererStack::switchRenderer(Renderer renderer) void RendererStack::createRenderer(Renderer renderer) { + rendererTakesScreenshots = false; switch (renderer) { default: case Renderer::Software: @@ -360,6 +362,7 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::OpenGL3: { this->createWinId(); + this->rendererTakesScreenshots = true; auto hw = new OpenGLRenderer(this); rendererWindow = hw; connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); @@ -424,6 +427,8 @@ RendererStack::createRenderer(Renderer renderer) this->setStyleSheet("background-color: black"); + rendererWindow->r_monitor_index = m_monitor_index; + currentBuf = 0; if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { @@ -454,7 +459,7 @@ RendererStack::blit(int x, int y, int w, int h) video_copy(scanline, &(monitors[m_monitor_index].target_buffer->line[y1][x]), w * 4); } - if (monitors[m_monitor_index].mon_screenshots) { + if (monitors[m_monitor_index].mon_screenshots && !rendererTakesScreenshots) { video_screenshot_monitor((uint32_t *) imagebits, x, y, 2048, m_monitor_index); } video_blit_complete_monitor(m_monitor_index); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 32ed5f7ca..a84773c72 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -15,6 +15,8 @@ #include "qt_renderercommon.hpp" +#include + namespace Ui { class RendererStack; } @@ -110,6 +112,8 @@ private: RendererCommon *rendererWindow { nullptr }; std::unique_ptr current; + + std::atomic_bool rendererTakesScreenshots; }; #endif // QT_RENDERERCONTAINER_HPP From c2eb7730296d53c39bcf230b0d8334499324e782 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 10 Mar 2025 23:27:19 +0600 Subject: [PATCH 0455/1190] Qt: Fix more compile errors --- src/qt/qt_openglshadermanagerdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 0bf083252..7f8a19414 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -46,7 +46,7 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); item->setText(filename); item->setData(Qt::UserRole + 1, QString(gl3_shader_file[i])); - item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); } } } @@ -174,7 +174,7 @@ void OpenGLShaderManagerDialog::on_buttonAdd_clicked() QListWidgetItem* item = new QListWidgetItem(ui->shaderListWidget); item->setText(filename); item->setData(Qt::UserRole + 1, res); - item->setData(Qt::UserRole + 2, (uintptr_t)shaderfile); + item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); } From 2e77b47f89ec960416bb362dc75551afedd77800 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 00:13:51 +0600 Subject: [PATCH 0456/1190] Call `glViewport` with correct function pointer --- src/qt/qt_openglrenderer.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 37afd4810..6f024f36f 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1103,14 +1103,6 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) context->makeCurrent(this); -#ifdef Q_OS_MACOS - glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); -#endif - if (source.width() != w || source.height() != h) { glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); glw.glTexImage2D(GL_TEXTURE_2D, 0, (GLenum) QOpenGLTexture::RGBA8_UNorm, w, h, 0, (GLenum) QOpenGLTexture::BGRA, (GLenum) QOpenGLTexture::UInt32_RGBA8_Rev, NULL); @@ -1129,6 +1121,14 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) source.setRect(x, y, w, h); onResize(this->width(), this->height()); +#ifdef Q_OS_MACOS + glw.glViewport( + destination.x() * devicePixelRatio(), + destination.y() * devicePixelRatio(), + destination.width() * devicePixelRatio(), + destination.height() * devicePixelRatio()); +#endif + if (video_framerate == -1) render(); } From f1720fdee481a226e4cc4269296a49be03269553 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 01:20:00 +0600 Subject: [PATCH 0457/1190] Attempt fixing crash on NetBSD --- src/qt/qt_platform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 35dbc0081..a1deb4137 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -368,6 +368,8 @@ plat_mmap(size_t size, uint8_t executable) void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), -1, 0); # elif defined(PROT_MPROTECT) void *ret = mmap(0, size, PROT_MPROTECT(PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0)), MAP_ANON | MAP_PRIVATE, -1, 0); + if (ret) + mprotect(ret, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0)); # else void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, -1, 0); # endif From df5cc9b03876ac34f296a8ad900e116182fee47f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Mar 2025 21:31:29 +0100 Subject: [PATCH 0458/1190] VIA PIPC: Restore old readout on the VT82C596/B southbridges, where it was correct, fixes the P6BAT. --- src/chipset/via_pipc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 11a192450..f7f5bf208 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -61,6 +61,7 @@ #define VIA_PIPC_586B 0x05864700 #define VIA_PIPC_596A 0x05960900 #define VIA_PIPC_596B 0x05962300 +#define VIA_PIPC_596 0x0596 #define VIA_PIPC_686A 0x06861400 #define VIA_PIPC_686B 0x06864000 #define VIA_PIPC_8231 0x82311000 @@ -413,7 +414,7 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; acpi_set_irq_line(dev->acpi, 0x00); dev->power_regs[0x48] = 0x01; @@ -1595,7 +1596,7 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); - dev->power_regs[0x42] = 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; acpi_set_irq_line(dev->acpi, 0x00); pipc_write(1, 0x04, 0x80, priv); From 9e5697126b08ffb6329a40151da6f9caf1ea7b67 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 11 Mar 2025 10:40:40 +0100 Subject: [PATCH 0459/1190] QT: Fix two strings. --- src/qt/qt_main.cpp | 2 +- src/qt/qt_platform.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index b48d272c5..f6ddddd32 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -665,7 +665,7 @@ main(int argc, char *argv[]) /* Force raw input if a debugger is present. */ if (IsDebuggerPresent()) { - pclog("WARNING: Debugged detected, forcing raw input\n"); + pclog("WARNING: Debugger detected, forcing raw input\n"); hook_enabled = 0; } diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a1deb4137..ee8d8842a 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -647,7 +647,7 @@ ProgSettings::reloadStrings() translatedstrings[STRING_NET_ERROR] = QCoreApplication::translate("", "Failed to initialize network driver").toStdWString(); translatedstrings[STRING_NET_ERROR_DESC] = QCoreApplication::translate("", "The network configuration will be switched to the null driver").toStdWString(); translatedstrings[STRING_ESCP_ERROR_TITLE] = QCoreApplication::translate("", "Unable to find Dot-Matrix fonts").toStdWString(); - translatedstrings[STRING_ESCP_ERROR_DESC] = QCoreApplication::translate("", "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulatio of the Generic ESC/P Dot-Matrix Printer.").toStdWString(); + translatedstrings[STRING_ESCP_ERROR_DESC] = QCoreApplication::translate("", "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer.").toStdWString(); } wchar_t * From 4d5adeae36d47085da9bcdd0014dbe1b2e12b391 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 11 Mar 2025 20:35:05 +0600 Subject: [PATCH 0460/1190] Restore older GLSL version code --- src/qt/qt_openglrenderer.cpp | 47 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 6f024f36f..b451c2245 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -34,6 +34,7 @@ extern MainWindow* main_window; #include #include #include +#include #include #include @@ -171,30 +172,33 @@ OpenGLRenderer::create_program(struct shader_program *program) int OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const char *program, int *dst) { - const char *source[3]; + QRegularExpression versionRegex("^\\s*(#version\\s+\\w+)", QRegularExpression::MultilineOption); + QString progSource = QString(program); + QByteArray finalSource = nullptr; + const char *source[5]; char version[50]; int ver = 0; char *version_loc = (char *) strstr(program, "#version"); - if (version_loc) - ver = (int) strtol(version_loc + 8, (char **) &program, 10); - else { - ver = glsl_version[0] * 100 + glsl_version[1] * 10; - if (ver == 300) - ver = 130; - else if (ver == 310) - ver = 140; - else if (ver == 320) - ver = 150; + if (version_loc) { + snprintf(version, 49, "%s\n", versionRegex.match(progSource).captured(1).toLatin1().data()); + progSource.remove(versionRegex); + } else { + snprintf(version, 49, "%s\n", this->glslVersion.toLatin1().data()); } - sprintf(version, "#version %d\n", ver); - source[0] = version; - source[1] = prepend ? prepend : ""; - source[2] = program; + + /* Remove parameter lines. */ + progSource.remove(QRegularExpression("^\\s*#pragma parameter.*?\\n", QRegularExpression::MultilineOption)); - pclog("GLSL version %d\n", ver); + finalSource = progSource.toLatin1(); + + source[0] = version; + source[1] = "\n#extension GL_ARB_shading_language_420pack : enable\n"; + source[2] = prepend ? prepend : ""; + source[3] = "\n#line 1\n"; + source[4] = finalSource.data(); GLuint shader = glw.glCreateShader(shader_type); - glw.glShaderSource(shader, 3, source, NULL); + glw.glShaderSource(shader, 5, source, NULL); glw.glCompileShader(shader); GLint status = 0; @@ -840,6 +844,15 @@ OpenGLRenderer::initialize() pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + glslVersion = reinterpret_cast(glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + glslVersion.truncate(4); + glslVersion.remove('.'); + glslVersion.prepend("#version "); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + glslVersion.append(" es"); + else if (context->format().profile() == QSurfaceFormat::CoreProfile) + glslVersion.append(" core"); + glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); From e2aa66a523d6b465b277c86a23e6a0e8cc9f8eb6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 19:55:09 +0600 Subject: [PATCH 0461/1190] Qt: Make tooltip displays consistent --- src/qt/qdarkstyle/dark/darkstyle.qss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/qt/qdarkstyle/dark/darkstyle.qss b/src/qt/qdarkstyle/dark/darkstyle.qss index 6e1ec4b06..134d6708e 100644 --- a/src/qt/qdarkstyle/dark/darkstyle.qss +++ b/src/qt/qdarkstyle/dark/darkstyle.qss @@ -130,16 +130,6 @@ QStatusBar::item { border: none; } -QStatusBar QToolTip { - background-color: #666666; - border: 1px solid #272727; - color: #272727; - /* Remove padding, for fix combo box tooltip */ - padding: 0px; - /* Reducing transparency to read better */ - opacity: 230; -} - QStatusBar QLabel { /* Fixes Spyder #9120, #9121 */ background: transparent; From 1c54261a1b1a3e813d5cb2940e959b493b55f26f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 21:16:53 +0600 Subject: [PATCH 0462/1190] Fix shader manager dialog crash when using multi-monitors --- src/qt/qt_openglrenderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index b451c2245..ef0332500 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -809,6 +809,7 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent) source.setRect(0, 0, 100, 100); isInitialized = false; isFinalized = false; + context = nullptr; } OpenGLRenderer::~OpenGLRenderer() { finalize(); } @@ -1088,7 +1089,7 @@ OpenGLRenderer::initialize() void OpenGLRenderer::finalize() { - if (isFinalized) + if (isFinalized || !context) return; context->makeCurrent(this); From 7261a0d74b11842370b2a326a96589f602f8133a Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 17:53:58 +0100 Subject: [PATCH 0463/1190] Hook input: Fix Pause scan code. --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index f6ddddd32..10900da0d 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -359,7 +359,7 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) } else if (!(lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000013)) { /* Pause - send E1 1D. */ win_keyboard_handle(0xe1, 0, 0, 0); - win_keyboard_handle(0x1d, LLKHF_UP, 0, 0); + win_keyboard_handle(0x1d, lpKdhs->flags & LLKHF_UP, 0, 0); } } else if (!last && (lpKdhs->scanCode == 0x00000036)) /* Non-fake right shift. */ From c73c7212f8baab1b25503a4f962d90e8c7a2330c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 18:02:01 +0100 Subject: [PATCH 0464/1190] QT OpenGL Renderer: Remove the unused variable "ver". --- src/qt/qt_openglrenderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index ef0332500..f654747eb 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -177,7 +177,6 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch QByteArray finalSource = nullptr; const char *source[5]; char version[50]; - int ver = 0; char *version_loc = (char *) strstr(program, "#version"); if (version_loc) { snprintf(version, 49, "%s\n", versionRegex.match(progSource).captured(1).toLatin1().data()); From f9572be8a5651437efe328e04516bd1666207caf Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 12 Mar 2025 23:54:57 +0600 Subject: [PATCH 0465/1190] Alter `#version` statements for macOS --- src/qt/qt_openglrenderer.cpp | 110 +++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index f654747eb..70c70527a 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -74,54 +74,74 @@ extern int video_vsync; extern int video_focus_dim; extern int video_refresh_rate; -const char *vertex_shader_default_tex_src = "#version 130\n" - "\n" - "in vec4 VertexCoord;\n" - "in vec2 TexCoord;\n" - "\n" - "out vec2 texCoord;\n" - "\n" - "void main()\n" - "{\n" - " gl_Position = VertexCoord;\n" - " texCoord = TexCoord;\n" - "}\n"; +const char* vertex_shader_default_tex_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; -const char *fragment_shader_default_tex_src = "#version 130\n" - "\n" - "in vec2 texCoord;\n" - "uniform sampler2D Texture;\n" - "\n" - "out vec4 color;" - "\n" - "void main()\n" - "{\n" - " color = texture(Texture, texCoord);\n" - "}\n"; +const char* fragment_shader_default_tex_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; -const char *vertex_shader_default_color_src = "#version 130\n" - "\n" - "in vec4 VertexCoord;\n" - "in vec4 Color;\n" - "\n" - "out vec4 color;\n" - "\n" - "void main()\n" - "{\n" - " gl_Position = VertexCoord;\n" - " color = Color;\n" - "}\n"; +const char* vertex_shader_default_color_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; -const char *fragment_shader_default_color_src = "#version 130\n" - "\n" - "in vec4 color;\n" - "\n" - "out vec4 outColor;" - "\n" - "void main()\n" - "{\n" - " outColor = color;\n" - "}\n"; +const char* fragment_shader_default_color_src = +#ifdef __APPLE__ + "#version 150\n" +#else + "#version 130\n" +#endif + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; static inline int next_pow2(unsigned int n) From 0d22e736767975d9f77da1295d404bc277a90bb1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 13 Mar 2025 00:50:16 +0600 Subject: [PATCH 0466/1190] Microtouch: Properly restore system cursor if "Show Crosshair" is enabled --- src/qt/qt_rendererstack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 38f087622..43e696085 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -270,7 +270,7 @@ RendererStack::leaveEvent(QEvent *event) { mousedata.mouse_tablet_in_proximity = 0; - if (mouse_input_mode == 1 && QApplication::overrideCursor()) { + if (mouse_input_mode >= 1 && QApplication::overrideCursor()) { while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); } From 6779a3c1bdef77a49832a03663fab16b7e96d99f Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 12 Mar 2025 23:16:16 +0100 Subject: [PATCH 0467/1190] Hook Keyboard Input: Ignore the extended flag for scan codes F1 and F2, fixes the passing of the Hanja and Han/Eng keys to the guest. --- src/qt/qt_main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 10900da0d..627455948 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -370,7 +370,11 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) else if (last && (lpKdhs->scanCode == 0x00000036)) last = 0; - win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, lpKdhs->flags & LLKHF_EXTENDED, 0); + if ((lpKdhs->scanCode == 0xf1) || (lpKdhs->scanCode == 0xf2)) + /* Hanja and Han/Eng keys, suppress the extended flag. */ + win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, 0, 0); + else + win_keyboard_handle(lpKdhs->scanCode, lpKdhs->flags & LLKHF_UP, lpKdhs->flags & LLKHF_EXTENDED, 0); return ret; } From 7c4df701cb37bb67b5decf625bcac81d64b9f967 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 13 Mar 2025 19:55:46 +0600 Subject: [PATCH 0468/1190] Add option to inhibit multimedia keys from host on Windows --- src/86box.c | 1 + src/config.c | 6 + src/include/86box/86box.h | 1 + src/qt/languages/86box.pot | 3 + src/qt/qt_main.cpp | 46 +++++++- src/qt/qt_progsettings.cpp | 9 +- src/qt/qt_progsettings.ui | 229 +++++++++++++++++++------------------ 7 files changed, 181 insertions(+), 114 deletions(-) diff --git a/src/86box.c b/src/86box.c index 24f6f0deb..5bf8177e8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -213,6 +213,7 @@ int hook_enabled = 1; /* (C) Keyboar int test_mode = 0; /* (C) Test mode */ char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */ int sound_muted = 0; /* (C) Is sound muted? */ +int inhibit_multimedia_keys; /* (C) Inhibit multimedia keys on Windows. */ int other_ide_present = 0; /* IDE controllers from non-IDE cards are present */ diff --git a/src/config.c b/src/config.c index f68b23c37..3bb9fb59a 100644 --- a/src/config.c +++ b/src/config.c @@ -131,6 +131,8 @@ load_general(void) video_filter_method = ini_section_get_int(cat, "video_filter_method", 1); + inhibit_multimedia_keys = ini_section_get_int(cat, "inhibit_multimedia_keys", 0); + force_43 = !!ini_section_get_int(cat, "force_43", 0); scale = ini_section_get_int(cat, "scale", 1); if (scale > 9) @@ -1900,6 +1902,10 @@ save_general(void) const char *va_name; + ini_section_set_int(cat, "inhibit_multimedia_keys", inhibit_multimedia_keys); + if (inhibit_multimedia_keys == 0) + ini_section_delete_var(cat, "inhibit_multimedia_keys"); + ini_section_set_int(cat, "sound_muted", sound_muted); if (sound_muted == 0) ini_section_delete_var(cat, "sound_muted"); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 768ca6267..40e1f7927 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -107,6 +107,7 @@ extern uint64_t instru_run_ms; #define window_y monitor_settings[0].mon_window_y #define window_w monitor_settings[0].mon_window_w #define window_h monitor_settings[0].mon_window_h +extern int inhibit_multimedia_keys; /* (C) Inhibit multimedia keys on Windows. */ extern int window_remember; extern int vid_resize; /* (C) allow resizing */ extern int invert_display; /* (C) invert the display */ diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 65cc32f85..93a47a1cb 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2141,3 +2141,6 @@ msgstr "" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "" + +msgid "Inhibit multimedia keys on Windows" +msgstr "" diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 627455948..2e0ce33e0 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -226,7 +226,30 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) detection; rest can't be reliably detected. */ DWORD vkCode = lpKdhs->vkCode; bool up = !!(lpKdhs->flags & LLKHF_UP); - ret = CallNextHookEx(NULL, nCode, wParam, lParam);; + + if (inhibit_multimedia_keys + && (lpKdhs->vkCode == VK_MEDIA_PLAY_PAUSE + || lpKdhs->vkCode == VK_MEDIA_NEXT_TRACK + || lpKdhs->vkCode == VK_MEDIA_PREV_TRACK + || lpKdhs->vkCode == VK_VOLUME_DOWN + || lpKdhs->vkCode == VK_VOLUME_UP + || lpKdhs->vkCode == VK_VOLUME_MUTE + || lpKdhs->vkCode == VK_MEDIA_STOP + || lpKdhs->vkCode == VK_LAUNCH_MEDIA_SELECT + || lpKdhs->vkCode == VK_LAUNCH_MAIL + || lpKdhs->vkCode == VK_LAUNCH_APP1 + || lpKdhs->vkCode == VK_LAUNCH_APP2 + || lpKdhs->vkCode == VK_HELP + || lpKdhs->vkCode == VK_BROWSER_BACK + || lpKdhs->vkCode == VK_BROWSER_FORWARD + || lpKdhs->vkCode == VK_BROWSER_FAVORITES + || lpKdhs->vkCode == VK_BROWSER_HOME + || lpKdhs->vkCode == VK_BROWSER_REFRESH + || lpKdhs->vkCode == VK_BROWSER_SEARCH + || lpKdhs->vkCode == VK_BROWSER_STOP)) + ret = TRUE; + else + ret = CallNextHookEx(NULL, nCode, wParam, lParam); switch (vkCode) { @@ -349,6 +372,27 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) ret = TRUE; else if ((lpKdhs->scanCode >= 0x5b) && (lpKdhs->scanCode <= 0x5d) && (lpKdhs->flags & LLKHF_EXTENDED)) ret = TRUE; + else if (inhibit_multimedia_keys + && (lpKdhs->vkCode == VK_MEDIA_PLAY_PAUSE + || lpKdhs->vkCode == VK_MEDIA_NEXT_TRACK + || lpKdhs->vkCode == VK_MEDIA_PREV_TRACK + || lpKdhs->vkCode == VK_VOLUME_DOWN + || lpKdhs->vkCode == VK_VOLUME_UP + || lpKdhs->vkCode == VK_VOLUME_MUTE + || lpKdhs->vkCode == VK_MEDIA_STOP + || lpKdhs->vkCode == VK_LAUNCH_MEDIA_SELECT + || lpKdhs->vkCode == VK_LAUNCH_MAIL + || lpKdhs->vkCode == VK_LAUNCH_APP1 + || lpKdhs->vkCode == VK_LAUNCH_APP2 + || lpKdhs->vkCode == VK_HELP + || lpKdhs->vkCode == VK_BROWSER_BACK + || lpKdhs->vkCode == VK_BROWSER_FORWARD + || lpKdhs->vkCode == VK_BROWSER_FAVORITES + || lpKdhs->vkCode == VK_BROWSER_HOME + || lpKdhs->vkCode == VK_BROWSER_REFRESH + || lpKdhs->vkCode == VK_BROWSER_SEARCH + || lpKdhs->vkCode == VK_BROWSER_STOP)) + ret = TRUE; else ret = CallNextHookEx(NULL, nCode, wParam, lParam); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 9e1f8c168..6ec76a290 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -115,14 +115,19 @@ ProgSettings::ProgSettings(QWidget *parent) mouseSensitivity = mouse_sensitivity; ui->horizontalSlider->setValue(mouseSensitivity * 100.); ui->openDirUsrPath->setChecked(open_dir_usr_path > 0); + ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); +#ifndef Q_OS_WINDOWS + ui->checkBoxMultimediaKeys->setHidden(true); +#endif } void ProgSettings::accept() { strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); - lang_id = ui->comboBoxLanguage->currentData().toUInt(); - open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + lang_id = ui->comboBoxLanguage->currentData().toUInt(); + open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); reloadStrings(); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index ac4327341..dc5674425 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -27,8 +27,122 @@
- QLayout::SetFixedSize + QLayout::SizeConstraint::SetFixedSize + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + Select media images from program working directory + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + 30 + + + + (System Default) + + + + + + + + Default + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + Icon set: + + + + + + + Language: + + + + + + + 10 + + + 200 + + + 10 + + + 20 + + + 100 + + + Qt::Orientation::Horizontal + + + @@ -51,13 +165,6 @@ - - - - Icon set: - - - @@ -65,77 +172,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - 10 - - - 200 - - - 10 - - - 20 - - - 100 - - - Qt::Horizontal - - - - - - - 30 - - - - (System Default) - - - - - - - - Language: - - - - - - - Default - - - @@ -143,39 +179,10 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> - + + - Select media images from program working directory + Inhibit multimedia keys on Windows From b1a02a6d137be594542741bde9f6c6b4571cd43b Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Mar 2025 20:59:59 +0100 Subject: [PATCH 0469/1190] Windows CD-ROM disc change notification: verify the correct bit of the unit mask. --- src/qt/qt_winrawinputfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 13e0ec9a7..cff9950b2 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -160,7 +160,7 @@ notify_drives(ULONG unitmask, int empty) char p[1024] = { 0 }; for (int i = 0; i < 26; ++i) { - if (unitmask & 0x1) { + if (unitmask & (1 << i)) { cdrom_t *dev = NULL; sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); From 8722fe0080d312c469e2750f60644fa67753facd Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 13 Mar 2025 21:17:25 +0100 Subject: [PATCH 0470/1190] CD-ROM: Optimize Windows IOCTL disc change checking. --- src/cdrom/cdrom.c | 4 ++++ src/include/86box/cdrom.h | 4 ++++ src/qt/qt_winrawinputfilter.cpp | 27 ++++++++------------------- src/qt/win_cdrom_ioctl.c | 16 ++++++++++++---- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index aea1afb94..c20e18db8 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -46,6 +46,7 @@ cdrom_t cdrom[CDROM_NUM] = { 0 }; int cdrom_interface_current; +int cdrom_assigned_letters = 0; #ifdef ENABLE_CDROM_LOG int cdrom_do_log = ENABLE_CDROM_LOG; @@ -2795,6 +2796,8 @@ cdrom_global_init(void) void cdrom_hard_reset(void) { + cdrom_assigned_letters = 0; + for (uint8_t i = 0; i < CDROM_NUM; i++) { cdrom_t *dev = &cdrom[i]; @@ -2825,6 +2828,7 @@ cdrom_hard_reset(void) } dev->cd_status = CD_STATUS_EMPTY; + dev->host_letter = 0xff; if (strlen(dev->image_path) > 0) { #ifdef _WIN32 diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 7c028d7d6..805f08b10 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -335,6 +335,8 @@ typedef struct cdrom { uint8_t subch_buffer[96]; int cdrom_sector_size; + /* Only used on Windows hosts for disc change notifications. */ + uint8_t host_letter; /* Needs some extra breathing space in case of overflows. */ uint8_t raw_buffer[4096]; @@ -437,6 +439,8 @@ extern int cdrom_is_empty(const uint8_t id); extern void cdrom_eject(const uint8_t id); extern void cdrom_reload(const uint8_t id); +extern int cdrom_assigned_letters; + #ifdef __cplusplus } #endif diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index cff9950b2..8a2841f97 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -157,27 +157,16 @@ WindowsRawInputFilter::~WindowsRawInputFilter() static void notify_drives(ULONG unitmask, int empty) { - char p[1024] = { 0 }; + if (unitmask & cdrom_assigned_letters) for (int i = 0; i < CDROM_NUM; i++) { + cdrom_t *dev = &(cdrom[i]); - for (int i = 0; i < 26; ++i) { - if (unitmask & (1 << i)) { - cdrom_t *dev = NULL; - - sprintf(p, "ioctl://\\\\.\\%c:", 'A' + i); - - for (int i = 0; i < CDROM_NUM; i++) - if (!stricmp(cdrom[i].image_path, p)) { - dev = &(cdrom[i]); - if (empty) - cdrom_set_empty(dev); - else - cdrom_update_status(dev); - // pclog("CD-ROM %i : Drive notified of media %s\n", - // dev->id, empty ? "removal" : "change"); - } + if ((dev->host_letter != 0xff) && + (unitmask & (1 << dev->host_letter))) { + if (empty) + cdrom_set_empty(dev); + else + cdrom_update_status(dev); } - - unitmask = unitmask >> 1; } } diff --git a/src/qt/win_cdrom_ioctl.c b/src/qt/win_cdrom_ioctl.c index 621cf0b76..309f861e0 100644 --- a/src/qt/win_cdrom_ioctl.c +++ b/src/qt/win_cdrom_ioctl.c @@ -748,6 +748,11 @@ ioctl_close(void *local) log_close(ioctl->log); ioctl->log = NULL; + + cdrom_assigned_letters &= ~(1 << ioctl->dev->host_letter); + ioctl->dev->host_letter = 0xff; + + free(ioctl); } static void @@ -788,19 +793,22 @@ ioctl_open(cdrom_t *dev, const char *drv) ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t)); if (ioctl != NULL) { - char n[1024] = { 0 }; + char n[1024] = { 0 }; sprintf(n, "CD-ROM %i IOCtl", dev->id + 1); - ioctl->log = log_open(n); + ioctl->log = log_open(n); memset(ioctl->path, 0x00, sizeof(ioctl->path)); wsprintf(ioctl->path, L"%S", &(drv[8])); ioctl_log(ioctl->log, "Path is %S\n", ioctl->path); - ioctl->dev = dev; + ioctl->dev = dev; - dev->ops = &ioctl_ops; + dev->ops = &ioctl_ops; + + dev->host_letter = (drv[12] & 0xdf) - 0x41; + cdrom_assigned_letters |= (1 << dev->host_letter); ioctl_load(ioctl); } From c23114ab8d7dc062d2acf39f0d6123857f9eb300 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 04:18:07 +0600 Subject: [PATCH 0471/1190] Attempt fixing OpenGL 3.x screenshot --- src/qt/qt_openglrenderer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 70c70527a..88fefa0c3 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1667,6 +1667,9 @@ OpenGLRenderer::render() unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); + glw.glFinish(); + glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); + glw.glReadBuffer(GL_BACK); glw.glFinish(); glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); From c166abbbc1242184dc0113b4e1a15ce93c7658f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 14:07:33 +0600 Subject: [PATCH 0472/1190] Always use an alpha value of 1.0 for drawing scene to texture Fixes invisible screenshots and blank screens on certain systems --- src/qt/qt_openglrenderer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 88fefa0c3..3b2ec58e0 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -107,6 +107,7 @@ const char* fragment_shader_default_tex_src = "void main()\n" "{\n" " color = texture(Texture, texCoord);\n" + " color.a = 1.0;\n" "}\n"; const char* vertex_shader_default_color_src = @@ -141,6 +142,7 @@ const char* fragment_shader_default_color_src = "void main()\n" "{\n" " outColor = color;\n" + " outColor.a = 1.0;\n" "}\n"; static inline int @@ -1667,9 +1669,6 @@ OpenGLRenderer::render() unsigned char *rgba = (unsigned char *)calloc(1, width * height * 4); - glw.glFinish(); - glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); - glw.glReadBuffer(GL_BACK); glw.glFinish(); glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); From 84112960c3f31df8455ea3c4b3d000f840cb5542 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 15:06:06 +0100 Subject: [PATCH 0473/1190] VIA PIPC: Also return 0x50 on power management register 0x42 for every other non-VT82c586-family southbridge, fixes CUV4X-LS. --- src/chipset/via_pipc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index f7f5bf208..6b855f5aa 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -59,6 +59,7 @@ listings on forums, as VIA's datasheets are not very helpful regarding those. */ #define VIA_PIPC_586A 0x05862500 #define VIA_PIPC_586B 0x05864700 +#define VIA_PIPC_586 0x0586 #define VIA_PIPC_596A 0x05960900 #define VIA_PIPC_596B 0x05962300 #define VIA_PIPC_596 0x0596 @@ -414,7 +415,7 @@ pipc_reset_hard(void *priv) dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; - dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_586) ? 0x00 : 0x50; acpi_set_irq_line(dev->acpi, 0x00); dev->power_regs[0x48] = 0x01; @@ -1596,7 +1597,7 @@ pipc_reset(void *priv) pipc_write(pm_func, 0x48, 0x01, priv); pipc_write(pm_func, 0x49, 0x00, priv); - dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_596) ? 0x50 : 0x00; + dev->power_regs[0x42] = ((dev->local >> 16) == VIA_PIPC_586) ? 0x00 : 0x50; acpi_set_irq_line(dev->acpi, 0x00); pipc_write(1, 0x04, 0x80, priv); From aef06552fb383320707d17a51fea174ddba94ff0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 15:34:37 +0100 Subject: [PATCH 0474/1190] Some missing breaks in the Cyrix register writes. --- src/cpu/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e6a22394a..c4d084947 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -3948,12 +3948,15 @@ pentium_invalid_wrmsr: /* Test Data */ case 0x03: msr.tr3 = EAX; + break; /* Test Address */ case 0x04: msr.tr4 = EAX; + break; /* Test Command/Status */ case 0x05: msr.tr5 = EAX & 0x008f0f3b; + break; /* Time Stamp Counter */ case 0x10: timer_set_new_tsc(EAX | ((uint64_t) EDX << 32)); From 0686045d2a7f3a2f7fc3ed4402874ca1e3406460 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 14 Mar 2025 21:24:36 +0600 Subject: [PATCH 0475/1190] Fix building on Haiku OS --- src/CMakeLists.txt | 4 ++++ src/qt/qt_platform.cpp | 7 +++++++ src/unix/unix.c | 11 +++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb3bf9f50..94dc6a61a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,10 @@ endif() target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd net print scsi sio snd vid voodoo plat ui) +if(HAIKU) + target_link_libraries(86Box be) +endif() + if(WIN32 AND ARCH STREQUAL "i386") if(MINGW) target_link_options(86Box PRIVATE "LINKER:--large-address-aware") diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index ee8d8842a..ebd6dc30c 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -18,6 +18,11 @@ * Copyright 2021-2022 Cacodemon345 * Copyright 2021-2022 Teemu Korhonen */ + +#ifdef __HAIKU__ +#include +#endif + #include #include @@ -828,6 +833,8 @@ plat_set_thread_name(void *thread, const char *name) pthread_setname_np(truncated); # elif defined(Q_OS_NETBSD) pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); +# elif defined(__HAIKU__) + rename_thread(find_thread(NULL), truncated); # elif defined(Q_OS_OPENBSD) pthread_set_name_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated); # else diff --git a/src/unix/unix.c b/src/unix/unix.c index 33b78ddb1..81312d25d 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -2,6 +2,9 @@ # define _FILE_OFFSET_BITS 64 # define _LARGEFILE64_SOURCE 1 #endif +#ifdef __HAIKU__ +#include +#endif #include #include #include @@ -1398,16 +1401,20 @@ plat_set_thread_name(void *thread, const char *name) if (thread) /* Apple pthread can only set self's name */ return; char truncated[64]; -#elif defined(Q_OS_NETBSD) +#elif defined(__NetBSD__) char truncated[64]; +#elif defined(__HAIKU__) + char truncated[32]; #else char truncated[16]; #endif strncpy(truncated, name, sizeof(truncated) - 1); #ifdef __APPLE__ pthread_setname_np(truncated); -#elif defined(Q_OS_NETBSD) +#elif defined(__NetBSD__) pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); +#elif defined(__HAIKU__) + rename_thread(find_thread(NULL), truncated); #else pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated); #endif From a1996e79553ee41df49c30551403f5fd19bbd534 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 15 Mar 2025 01:09:41 +0700 Subject: [PATCH 0476/1190] Readd XT and AT floppy controllers They got removed during the addition of CompatiCard --- src/floppy/fdc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 5de1a8ef4..51c3aa24a 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -105,6 +105,8 @@ static fdc_cards_t fdc_cards[] = { // clang-format off { &device_none }, { &device_internal }, + { &fdc_xt_device }, + { &fdc_at_device }, { &fdc_b215_device }, { &fdc_pii151b_device }, { &fdc_pii158b_device }, From a340f250f2f27f229d3aff30272d62a0b676d859 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 00:34:36 +0600 Subject: [PATCH 0477/1190] Attempt detecting BOM before parsing parameters --- src/qt/qt_glsl_parser.cpp | 36 ++++++++++++++++++++++--- src/qt/qt_openglshadermanagerdialog.cpp | 3 +++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index 9a0a0fc03..e5c7b77f2 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -17,6 +17,7 @@ extern "C" #include <86box/config.h> #include <86box/qt-glslp-parser.h> #include <86box/path.h> +#include <86box/plat.h> extern void startblit(); extern void endblit(); @@ -81,14 +82,38 @@ static int endswith(const char *str, const char *ext) { return 0; } +static int +glsl_detect_bom(const char *fn) +{ + FILE *fp; + unsigned char bom[4] = { 0, 0, 0, 0 }; + + fp = plat_fopen(fn, "rb"); + if (fp == NULL) + return 0; + (void) !fread(bom, 1, 3, fp); + if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) { + fclose(fp); + return 1; + } + fclose(fp); + return 0; +} + static char *load_file(const char *fn) { - FILE *f = fopen(fn, "rb"); + int bom = glsl_detect_bom(fn); + FILE *f = plat_fopen(fn, "rb"); if (!f) return 0; fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); + if (bom) { + fsize -= 3; + fseek(f, 3, SEEK_SET); + } + char *data = (char*)malloc(fsize + 1); fread(data, fsize, 1, f); @@ -131,12 +156,15 @@ static int get_parameters(glslp_t *glsl) { int i; struct parameter p; for (i = 0; i < glsl->num_shaders; ++i) { + char line[1024]; struct shader *shader = &glsl->shaders[i]; - FILE *f = fopen(shader->shader_fn, "rb"); + int bom = glsl_detect_bom(shader->shader_fn); + FILE *f = plat_fopen(shader->shader_fn, "rb"); if (!f) return 0; - - char line[1024]; + if (bom) { + fseek(f, 3, SEEK_SET); + } while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, &p.default_value, &p.min, &p.max, &p.step); diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 7f8a19414..72f58f9cb 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -63,6 +63,7 @@ OpenGLShaderManagerDialog::OpenGLShaderManagerDialog(QWidget *parent) } else { ui->buttonConfigure->setEnabled(false); } + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } else { ui->buttonRemove->setDisabled(true); ui->buttonMoveUp->setDisabled(true); @@ -177,6 +178,7 @@ void OpenGLShaderManagerDialog::on_buttonAdd_clicked() item->setData(Qt::UserRole + 2, (qulonglong)(uintptr_t)shaderfile); if (ui->shaderListWidget->count()) { ui->shaderListWidget->setCurrentRow(ui->shaderListWidget->count() - 1); + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } } else { QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); @@ -197,6 +199,7 @@ void OpenGLShaderManagerDialog::on_buttonRemove_clicked() on_shaderListWidget_currentRowChanged(ui->shaderListWidget->currentRow()); } + ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } void OpenGLShaderManagerDialog::on_OpenGLShaderManagerDialog_accepted() From b5c158ec98a02df1ea1ec559712601bd8ac4681a Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 14 Mar 2025 20:11:55 +0100 Subject: [PATCH 0478/1190] SCSI CD-ROM: Revert the performance-reducing changes to scsi_cdrom_command_common() introduced in build 6541. --- src/scsi/scsi_cdrom.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index cc9cc40c1..e16b16e7c 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -678,13 +678,8 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; scsi_cdrom_set_callback(dev); return; - case 0x43: - dev->drv->seek_diff = dev->drv->seek_pos + 150; - dev->drv->seek_pos = 0; - fallthrough; case 0x08: case 0x28: - case 0x42: case 0x44: case 0xa8: /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); @@ -698,7 +693,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += period; fallthrough; case 0x25: - // case 0x42 ... 0x44: + case 0x42 ... 0x44: case 0x51 ... 0x52: case 0xad: case 0xb8 ... 0xb9: @@ -707,11 +702,6 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) dev->callback += 40.0; /* Account for seek time. */ /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ - /* - TODO: This is a bit of a lie - the actual period is closer to - 75 * 2448 bytes per second, because the subchannel data - has to be read as well. - */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; @@ -740,19 +730,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); - switch (cmd) { - default: - period = period * (double) (dev->packet_len); - break; - case 0x42: case 0x44: - /* READ SUBCHANNEL or READ HEADER - period of 1 entire sector. */ - period = period * 2352.0; - break; - case 0x43: - /* READ TOC - period of 175 entire frames. */ - period = period * 150.0 * 2352.0; - break; - } + period = period * (double) (dev->packet_len); scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); dev->callback += period; From 9af19f850ea0374f3cbd07e0b23b0857aba581e0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 13:17:14 +0600 Subject: [PATCH 0479/1190] Parse shader parameter lines with an alternate method --- src/qt/qt_glsl_parser.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index e5c7b77f2..fa45267a7 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -21,6 +21,8 @@ extern "C" extern void startblit(); extern void endblit(); +extern ssize_t local_getline(char **buf, size_t *bufsiz, FILE *fp); +extern char* trim(char* str); } #define safe_strncpy(a, b, n) \ @@ -156,7 +158,8 @@ static int get_parameters(glslp_t *glsl) { int i; struct parameter p; for (i = 0; i < glsl->num_shaders; ++i) { - char line[1024]; + size_t size = 0; + char* line = NULL; struct shader *shader = &glsl->shaders[i]; int bom = glsl_detect_bom(shader->shader_fn); FILE *f = plat_fopen(shader->shader_fn, "rb"); @@ -165,7 +168,9 @@ static int get_parameters(glslp_t *glsl) { if (bom) { fseek(f, 3, SEEK_SET); } - while (fgets(line, sizeof(line) - 1, f) && glsl->num_parameters < MAX_PARAMETERS) { + while (local_getline(&line, &size, f) != -1 && glsl->num_parameters < MAX_PARAMETERS) { + line[strcspn(line, "\r\n")] = '\0'; + trim(line); int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, &p.default_value, &p.min, &p.max, &p.step); if (num < 5) From 4a9b0e0df8a94287bef72644111df5caa7a38397 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 13:17:41 +0600 Subject: [PATCH 0480/1190] Apply filter changes to the scene FBO texture as well --- src/qt/qt_openglrenderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 3b2ec58e0..b465bfddd 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1393,6 +1393,10 @@ OpenGLRenderer::render() glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + active_shader->scene.fbo.texture.min_filter = active_shader->scene.fbo.texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, active_shader->scene.fbo.texture.id); glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); glw.glBindTexture(GL_TEXTURE_2D, 0); From b8894fc9dfb403e0e723091c71aa21482321d52f Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:13:02 +0200 Subject: [PATCH 0481/1190] Add files via upload Fixes broken translation of "About 86Box" --- src/qt/qt_mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index cdb46cb29..41654ab25 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1754,7 +1754,7 @@ MainWindow::on_actionAbout_86Box_triggered() versioninfo.append(QString(" [%1, %2]").arg(QSysInfo::buildCpuArchitecture(), tr(DYNAREC_STR))); msgBox.setText(QString("%3%1%2").arg(EMU_VERSION_FULL, versioninfo, tr("86Box v"))); msgBox.setInformativeText(tr("An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information.")); - msgBox.setWindowTitle("About 86Box"); + msgBox.setWindowTitle(tr("About 86Box")); const auto closeButton = msgBox.addButton("OK", QMessageBox::ButtonRole::AcceptRole); msgBox.setEscapeButton(closeButton); const auto webSiteButton = msgBox.addButton(EMU_SITE, QMessageBox::ButtonRole::HelpRole); From dcce23a7d3c53ea1b544d58dab02065200ffb3e5 Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:13:55 +0200 Subject: [PATCH 0482/1190] Add files via upload Fixes broken translation of "Receive MIDI Input" for Ensoniq AudioPCI (ES1370) --- src/sound/snd_audiopci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 8d1de442b..1ca547650 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -2742,7 +2742,7 @@ static const device_config_t es1370_config[] = { // clang-format off { .name = "receive_input", - .description = "Receive input (MIDI)", + .description = "Receive MIDI input", .type = CONFIG_BINARY, .default_string = NULL, .default_int = 1, From 26e1852b5a22ff23e079f13619f8f8fd33b4f25f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 15 Mar 2025 23:47:10 +0600 Subject: [PATCH 0483/1190] Make renderer options item enabled/disabled instead Also a missed French translation --- src/qt/languages/fr-FR.po | 2 +- src/qt/qt.c | 5 ----- src/qt/qt_mainwindow.cpp | 5 +---- src/qt/qt_rendererstack.cpp | 22 +--------------------- src/qt/qt_rendererstack.hpp | 1 - 5 files changed, 3 insertions(+), 32 deletions(-) diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 3b283b3dd..590674a29 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -37,7 +37,7 @@ msgid "&Hide status bar" msgstr "&Masquer la barre de status" msgid "Hide &toolbar" -msgstr "Hide &toolbar" +msgstr "Masquer la &barre d'outils" msgid "&Resizeable window" msgstr "Fenètre &Retaillable" diff --git a/src/qt/qt.c b/src/qt/qt.c index 13ddbf498..a9a6460eb 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -54,8 +54,6 @@ plat_vidapi(const char *api) return 4; } else if (!strcasecmp(api, "vnc")) { return 5; - } else if (!strcasecmp(api, "qt_opengl3_pcem")) { - return 6; } return 0; @@ -85,9 +83,6 @@ plat_vidapi_name(int api) case 5: name = "vnc"; break; - case 6: - name = "qt_opengl3_pcem"; - break; default: fatal("Unknown renderer: %i\n", api); break; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index cdb46cb29..d2c4667cd 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -454,9 +454,6 @@ MainWindow::MainWindow(QWidget *parent) endblit(); } #endif - case 6: - newVidApi = RendererStack::Renderer::OpenGL3PCem; - break; } ui->stackedWidget->switchRenderer(newVidApi); if (!show_second_monitors) @@ -468,7 +465,7 @@ MainWindow::MainWindow(QWidget *parent) }); connect(ui->stackedWidget, &RendererStack::rendererChanged, [this]() { - ui->actionRenderer_options->setVisible(ui->stackedWidget->hasOptions()); + ui->actionRenderer_options->setEnabled(ui->stackedWidget->hasOptions()); }); /* Trigger initial renderer switch */ diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 43e696085..bd1fd2609 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -339,26 +339,6 @@ RendererStack::createRenderer(Renderer renderer) current.reset(this->createWindowContainer(hw, this)); break; } - case Renderer::OpenGL3PCem: - { - this->createWinId(); - auto hw = new OpenGLRenderer(this); - rendererWindow = hw; - connect(this, &RendererStack::blitToRenderer, hw, &OpenGLRenderer::onBlit, Qt::QueuedConnection); - connect(hw, &OpenGLRenderer::initialized, [=]() { - /* Buffers are available only after initialization. */ - imagebufs = rendererWindow->getBuffers(); - endblit(); - emit rendererChanged(); - }); - connect(hw, &OpenGLRenderer::errorInitializing, [=]() { - /* Renderer not could initialize, fallback to software. */ - imagebufs = {}; - QTimer::singleShot(0, this, [this]() { switchRenderer(Renderer::Software); }); - }); - current.reset(this->createWindowContainer(hw, this)); - break; - } case Renderer::OpenGL3: { this->createWinId(); @@ -431,7 +411,7 @@ RendererStack::createRenderer(Renderer renderer) currentBuf = 0; - if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan && renderer != Renderer::OpenGL3PCem) { + if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { imagebufs = rendererWindow->getBuffers(); endblit(); emit rendererChanged(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index a84773c72..309cae7f5 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -61,7 +61,6 @@ public: OpenGLES, OpenGL3, Vulkan, - OpenGL3PCem = 6, None = -1 }; void switchRenderer(Renderer renderer); From 000af483f3e0561fbb4c214496d20d0be358359b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 01:46:34 +0600 Subject: [PATCH 0484/1190] C&T 69000: All ROPs now implemented, also fixed transparency bitblts Several optimizations also implemented --- src/video/vid_chips_69000.c | 1342 ++++++++++++++++++++++------------- 1 file changed, 833 insertions(+), 509 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index a387e99fa..b0e8db35a 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -251,486 +251,797 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -void -chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFF; - break; +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ } -} - -void -chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFF; - break; - } -} - -void -chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFFFF; - break; - } -} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_8bpp(dst, src, rop); - } - - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_16bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src, uint8_t rop) { uint32_t orig_dst = *dst & 0xFF000000; - - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_24bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -895,20 +1206,22 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); + //dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; break; } case 2: /* 16 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; + //dest_pixel = *(uint16_t*)&chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; break; } case 3: /* 24 bits-per-pixel. */ { - dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; - dest_pixel |= chips_69000_readb_linear(dest_addr + 2, chips) << 16; + dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; + dest_pixel |= chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] << 16; break; } } @@ -921,7 +1234,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) if (chips->bitblt_running.bitblt.bitblt_control & (1 << 19)) pattern_data = 0; else - pattern_data = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); + pattern_data = chips->svga.vram[(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7)) & chips->svga.vram_mask]; //chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); is_true = !!(pattern_data & (1 << (7 - ((chips->bitblt_running.bitblt.destination_addr + chips->bitblt_running.x) & 7)))); @@ -937,32 +1250,30 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) pattern_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; } else { + uint32_t pattern_pixel_addr = 0; if (chips->bitblt_running.bytes_per_pixel == 1) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) - + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) + + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7); + + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; } if (chips->bitblt_running.bytes_per_pixel == 2) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; } if (chips->bitblt_running.bytes_per_pixel == 3) { - pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); + pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; - - pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 2, chips) << 16; + pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; + pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 2) & chips->svga.vram_mask] << 16; } } if (chips->bitblt_running.bytes_per_pixel == 2) { @@ -980,7 +1291,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1018,7 +1329,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1030,20 +1341,21 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + //chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); break; } case 2: /* 16 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; break; } case 3: /* 24 bits-per-pixel. */ { - chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); - chips_69000_writeb_linear(dest_addr + 2, (dest_pixel >> 16) & 0xFF, chips); + chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; + chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; + chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] = (dest_pixel >> 16) & 0xFF; break; } } @@ -1211,7 +1523,8 @@ chips_69000_setup_bitblt(chips_69000_t* chips) uint32_t orig_source_addr = chips->bitblt_running.bitblt.source_addr; while (orig_count_y == chips->bitblt_running.count_y) { int i = 0; - uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); + //uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); + uint8_t data = chips->svga.vram[orig_source_addr & chips->svga.vram_mask]; orig_source_addr++; for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(data & (1 << (7 - i)))); @@ -1230,14 +1543,15 @@ chips_69000_setup_bitblt(chips_69000_t* chips) case 1: /* Bit-aligned */ case 2: /* Byte-aligned */ { - uint32_t data = chips_69000_readb_linear(source_addr, chips); + //uint32_t data = chips_69000_readb_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask]; chips_69000_bitblt_write(chips, data & 0xFF); source_addr += 1; break; } case 3: /* Word-aligned*/ { - uint32_t data = chips_69000_readw_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); source_addr += 2; @@ -1245,7 +1559,8 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 4: /* Doubleword-aligned*/ { - uint32_t data = chips_69000_readl_linear(source_addr, chips); + uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) + | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1255,7 +1570,15 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 5: /* Quadword-aligned*/ { - uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); + uint64_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] + | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) + | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) + | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24) + | ((uint64_t)chips->svga.vram[(source_addr + 4) & chips->svga.vram_mask] << 32ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 5) & chips->svga.vram_mask] << 40ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 6) & chips->svga.vram_mask] << 48ULL) + | ((uint64_t)chips->svga.vram[(source_addr + 7) & chips->svga.vram_mask] << 56ULL); + //uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1280,20 +1603,21 @@ chips_69000_setup_bitblt(chips_69000_t* chips) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); + //pixel = chips_69000_readb_linear(source_addr, chips); + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; break; } case 2: /* 16 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); - pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; break; } case 3: /* 24 bits-per-pixel. */ { - pixel = chips_69000_readb_linear(source_addr, chips); - pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; - pixel |= chips_69000_readb_linear(source_addr + 2, chips) << 16; + pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; + pixel |= chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16; break; } } From 35125e70205ab59ed731059f67827dc472987eb5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 15:24:24 +0600 Subject: [PATCH 0485/1190] Don't use starblit/endblit for renderer switches --- src/qt/qt_mainwindow.cpp | 4 ++-- src/qt/qt_rendererstack.cpp | 11 ++++++----- src/qt/qt_rendererstack.hpp | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 497b791ca..fb265f34d 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2025,8 +2025,8 @@ MainWindow::on_actionRenderer_options_triggered() ui->stackedWidget->switchRenderer(static_cast(vid_api)); if (show_second_monitors) { for (int i = 1; i < MONITORS_NUM; i++) { - if (renderers[i] && renderers[i]->reloadRendererOption() && renderers[i]->hasOptions()) { - ui->stackedWidget->switchRenderer(static_cast(vid_api)); + if (renderers[i]) { + renderers[i]->switchRenderer(static_cast(vid_api)); } } } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index bd1fd2609..2b1cfdf26 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -288,7 +288,8 @@ RendererStack::leaveEvent(QEvent *event) void RendererStack::switchRenderer(Renderer renderer) { - startblit(); + //startblit(); + switchInProgress = true; if (current) { rendererWindow->finalize(); removeWidget(current.get()); @@ -349,7 +350,7 @@ RendererStack::createRenderer(Renderer renderer) connect(hw, &OpenGLRenderer::initialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); }); connect(hw, &OpenGLRenderer::errorInitializing, [=]() { @@ -381,7 +382,7 @@ RendererStack::createRenderer(Renderer renderer) connect(hw, &VulkanWindowRenderer::rendererInitialized, [=]() { /* Buffers are available only after initialization. */ imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); }); connect(hw, &VulkanWindowRenderer::errorInitializing, [=]() { @@ -413,7 +414,7 @@ RendererStack::createRenderer(Renderer renderer) if (renderer != Renderer::OpenGL3 && renderer != Renderer::Vulkan) { imagebufs = rendererWindow->getBuffers(); - endblit(); + switchInProgress = false; emit rendererChanged(); } } @@ -423,7 +424,7 @@ void RendererStack::blit(int x, int y, int w, int h) { if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || - (w > 2048) || (h > 2048) || + (w > 2048) || (h > 2048) || (switchInProgress) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get(imagebufs[currentBuf])->test_and_set()) { video_blit_complete_monitor(m_monitor_index); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 309cae7f5..54ea49bb9 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -113,6 +113,7 @@ private: std::unique_ptr current; std::atomic_bool rendererTakesScreenshots; + std::atomic_bool switchInProgress{false}; }; #endif // QT_RENDERERCONTAINER_HPP From c77cef6d80cdfc4c6b824ebcade534eee1bce2b7 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sun, 16 Mar 2025 16:55:29 +0500 Subject: [PATCH 0486/1190] Fix Qt menu roles for certain menu items --- src/qt/qt_mainwindow.cpp | 1 + src/qt/qt_mainwindow.ui | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 497b791ca..cfd6e08aa 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -181,6 +181,7 @@ MainWindow::MainWindow(QWidget *parent) main_window = this; ui->setupUi(this); status->setSoundGainAction(ui->actionSound_gain); + ui->menuEGA_S_VGA_settings->menuAction()->setMenuRole(QAction::NoRole); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); #ifdef Q_OS_WINDOWS diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index b1dc0ecf1..ef3cf16c6 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -353,6 +353,9 @@ Exit + + QAction::QuitRole + @@ -815,6 +818,9 @@ Renderer options... + + QAction::NoRole + From 271a125301342b588456dd026ea90ae809105029 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 16 Mar 2025 23:33:40 +0600 Subject: [PATCH 0487/1190] Use `fpclassify` for FXAM instead of manual comparison NaN detection for interpreter floating point compare on ARM64 --- src/cpu/x87_ops.h | 14 ++++++++++++-- src/cpu/x87_ops_misc.h | 22 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 97f5415b9..6a51a2c7f 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -420,11 +420,19 @@ x87_compare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ULL; + const uint64_t ib = 0x3fec1a6ff866a938ULL; + + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return FPU_SW_C3; if ((fpu_type < FPU_287XL) && !(cpu_state.npxc & 0x1000) && ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) eb = ea; - if (ea == eb) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (ea == eb) result |= FPU_SW_C3; else if (ea < eb) result |= FPU_SW_C0; @@ -473,7 +481,9 @@ x87_ucompare(double a, double b) * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; - if (a == b) + if ((isnan(a) || isnan(b))) + result |= FPU_SW_C3 | FPU_SW_C2 | FPU_SW_C0; + else if (a == b) result |= FPU_SW_C3; else if (a < b) result |= FPU_SW_C0; diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 5821a5cd5..4009eadd6 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -585,10 +585,24 @@ opFXAM(UNUSED(uint32_t fetchdat)) if (cpu_state.tag[cpu_state.TOP & 7] == 3) cpu_state.npxs |= (FPU_SW_C0 | FPU_SW_C3); #endif - else if (ST(0) == 0.0) - cpu_state.npxs |= FPU_SW_C3; - else - cpu_state.npxs |= FPU_SW_C2; + else switch (fpclassify(ST(0))) + { + case FP_SUBNORMAL: + cpu_state.npxs |= FPU_SW_C2 | FPU_SW_C3; + break; + case FP_NAN: + cpu_state.npxs |= FPU_SW_C0; + break; + case FP_INFINITE: + cpu_state.npxs |= FPU_SW_C0 | FPU_SW_C2; + break; + case FP_ZERO: + cpu_state.npxs |= FPU_SW_C3; + break; + case FP_NORMAL: + cpu_state.npxs |= FPU_SW_C2; + break; + } if (ST(0) < 0.0) cpu_state.npxs |= FPU_SW_C1; CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxam) : (x87_timings.fxam * cpu_multi)); From 1c5d432d3cf4332066ec48c0e572e11e95636ddb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 18:37:32 +0100 Subject: [PATCH 0488/1190] Disable special segment selector pushing behavior on Pentium onwards, fixes MSVC builds of ReactOS. --- src/cpu/cpu.c | 79 +++++++++++++++++++++++++----------------------- src/cpu/cpu.h | 1 + src/cpu/x86seg.c | 23 +++++++++----- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c4d084947..b821bc657 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -209,6 +209,7 @@ int is286; int is386; int is6117; int is486 = 1; +int is586 = 0; int cpu_isintel; int cpu_iscyrix; int hascache; @@ -552,6 +553,8 @@ cpu_set(void) cpu_16bitbus = (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_486SLC) || (cpu_s->cpu_type == CPU_IBM386SLC) || (cpu_s->cpu_type == CPU_IBM486SLC); cpu_64bitbus = (cpu_s->cpu_type >= CPU_WINCHIP); + is586 = cpu_64bitbus || (cpu_s->cpu_type == CPU_P24T); + if (cpu_s->multi) cpu_busspeed = cpu_s->rspeed / cpu_s->multi; else @@ -4303,47 +4306,47 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) static uint8_t cpu_read(uint16_t addr, UNUSED(void *priv)) { + uint8_t ret = 0xff; + if (addr == 0xf007) - return 0x7f; + ret = 0x7f; + else if ((addr < 0xf0) && (addr & 1)) switch (cyrix_addr) { + case 0xc0: + ret = ccr0; + break; + case 0xc1: + ret = ccr1; + break; + case 0xc2: + ret = ccr2; + break; + case 0xc3: + ret = ccr3; + break; + case 0xe8: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + break; + case 0xe9: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + break; + case 0xea: + ret = ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + break; + case 0xeb: + ret = ccr7; + break; + case 0xfe: + ret = cpu_s->cyrix_id & 0xff; + break; + case 0xff: + ret = cpu_s->cyrix_id >> 8; + break; - if (addr >= 0xf0) - return 0xff; /* FPU stuff */ - - if (addr & 1) { - switch (cyrix_addr) { - case 0xc0: - return ccr0; - case 0xc1: - return ccr1; - case 0xc2: - return ccr2; - case 0xc3: - return ccr3; - case 0xe8: - return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; - case 0xe9: - return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; - case 0xea: - return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; - case 0xeb: - return ccr7; - case 0xfe: - return cpu_s->cyrix_id & 0xff; - case 0xff: - return cpu_s->cyrix_id >> 8; - - default: - break; - } - - if ((cyrix_addr & 0xf0) == 0xc0) - return 0xff; - - if (cyrix_addr == 0x20 && (cpu_s->cpu_type == CPU_Cx5x86)) - return 0xff; + default: + break; } - - return 0xff; + + return ret; } void diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 8324c543e..d58da6998 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -513,6 +513,7 @@ extern int is286; extern int is386; extern int is6117; extern int is486; +extern int is586; extern int is_am486; extern int is_am486dxl; extern int is_pentium; diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 61c0edd9f..cd393812d 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -1113,7 +1113,7 @@ loadcscall(uint16_t seg) x86seg_log("Type %04X\n", type); if (type == 0x0c00) { - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp2); if (cpu_state.abrt) { SS = oldss; @@ -1678,10 +1678,17 @@ pmodeint(int num, int soft) cpl_override = 1; if (type >= 0x0800) { if (cpu_state.eflags & VM_FLAG) { - PUSHL_SEL(GS); - PUSHL_SEL(FS); - PUSHL_SEL(DS); - PUSHL_SEL(ES); + if (is586) { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); + } else { + PUSHL_SEL(GS); + PUSHL_SEL(FS); + PUSHL_SEL(DS); + PUSHL_SEL(ES); + } if (cpu_state.abrt) return; op_loadseg(0, &cpu_state.seg_ds); @@ -1689,10 +1696,10 @@ pmodeint(int num, int soft) op_loadseg(0, &cpu_state.seg_fs); op_loadseg(0, &cpu_state.seg_gs); } - PUSHL_SEL(oldss); + is586 ? PUSHL(oldss) : PUSHL_SEL(oldss); PUSHL(oldsp); PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; @@ -1728,7 +1735,7 @@ pmodeint(int num, int soft) } if (type > 0x0800) { PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL_SEL(CS); + is586 ? PUSHL(CS) : PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; From 9f200fe2e83c99c0e4b8076afe451bf0c3da8f98 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 21:20:15 +0100 Subject: [PATCH 0489/1190] 386 Interpreter: Check for debug breakpoint before segment limit and presence checking. --- src/cpu/386.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index caa5f84a2..c9a62fa6e 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -264,11 +264,7 @@ exec386_2386(int32_t cycs) ol = opcode_length[fetchdat & 0xff]; if ((ol == 3) && opcode_has_modrm[fetchdat & 0xff] && (((fetchdat >> 14) & 0x03) == 0x03)) ol = 2; - if (cpu_16bitbus) { - CHECK_READ_CS(MIN(ol, 2)); - } else { - CHECK_READ_CS(MIN(ol, 4)); - } + if (is386) ins_fetch_fault = cpu_386_check_instruction_fault(); @@ -276,6 +272,10 @@ exec386_2386(int32_t cycs) if (ins_fetch_fault) { ins_fetch_fault = 0; cpu_state.abrt = 1; + } else if (cpu_16bitbus) { + CHECK_READ_CS(MIN(ol, 2)); + } else { + CHECK_READ_CS(MIN(ol, 4)); } if (!cpu_state.abrt) { From 52a16529dcfd554c6e7e7a2c5c921388ee9bb9a4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 16 Mar 2025 23:54:55 +0100 Subject: [PATCH 0490/1190] 386 Interpreter: Fix execute breakpoints. --- src/cpu/386.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index c9a62fa6e..6abb7da18 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -269,9 +269,11 @@ exec386_2386(int32_t cycs) ins_fetch_fault = cpu_386_check_instruction_fault(); /* Breakpoint fault has priority over other faults. */ - if (ins_fetch_fault) { + if ((cpu_state.abrt == 0) & ins_fetch_fault) { + x86gen(); ins_fetch_fault = 0; - cpu_state.abrt = 1; + /* No instructions executed at this point. */ + goto block_ended; } else if (cpu_16bitbus) { CHECK_READ_CS(MIN(ol, 2)); } else { @@ -288,7 +290,6 @@ exec386_2386(int32_t cycs) trap |= !!(cpu_state.flags & T_FLAG); cpu_state.pc++; - cpu_state.eflags &= ~(RF_FLAG); if (opcode == 0xf0) in_lock = 1; x86_2386_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); @@ -316,6 +317,7 @@ exec386_2386(int32_t cycs) if (cpu_end_block_after_ins) cpu_end_block_after_ins--; +block_ended: if (cpu_state.abrt) { flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; @@ -338,6 +340,9 @@ exec386_2386(int32_t cycs) #endif } } + + if (!x86_was_reset && ins_fetch_fault) + x86gen(); } else if (new_ne) { flags_rebuild(); new_ne = 0; From dd4e493f646e316162c732b70ad86a3b81cc3b0f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 00:07:41 +0100 Subject: [PATCH 0491/1190] Applied the fix to the optional 486 implementation as well. --- src/cpu/386.c | 2 +- src/cpu/386_dynarec.c | 45 ++++++++++++++++++------------------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index 6abb7da18..ed4b40ab2 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -341,7 +341,7 @@ block_ended: } } - if (!x86_was_reset && ins_fetch_fault) + if (is386 && !x86_was_reset && ins_fetch_fault) x86gen(); } else if (new_ne) { flags_rebuild(); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 5f41c416a..fd6285057 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -276,11 +276,7 @@ exec386_dynarec_int(void) cpu_block_end = 0; x86_was_reset = 0; -# ifdef USE_DEBUG_REGS_486 - if (trap & 2) { -# else if (trap == 2) { -# endif /* Handle the T bit in the new TSS first. */ CPU_BLOCK_END(); goto block_ended; @@ -297,13 +293,6 @@ exec386_dynarec_int(void) cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; -# ifdef USE_DEBUG_REGS_486 - if (UNLIKELY(cpu_386_check_instruction_fault())) { - x86gen(); - goto block_ended; - } -# endif - fetchdat = fastreadl_fetch(cs + cpu_state.pc); # ifdef ENABLE_386_DYNAREC_LOG if (in_smm) @@ -370,13 +359,7 @@ exec386_dynarec_int(void) block_ended: if (!cpu_state.abrt && !new_ne && trap) { -# ifdef USE_DEBUG_REGS_486 - //pclog("Debug trap 0x%X\n", trap); - if (trap & 2) dr[6] |= 0x8000; - if (trap & 1) dr[6] |= 0x4000; -# else dr[6] |= (trap == 2) ? 0x8000 : 0x4000; -# endif trap = 0; # ifndef USE_NEW_DYNAREC @@ -902,6 +885,9 @@ exec386(int32_t cycs) cycdiff = 0; oldcyc = cycles; while (cycdiff < cycle_period) { +#ifdef USE_DEBUG_REGS_486 + int ins_fetch_fault = 0; +#endif ins_cycles = cycles; #ifndef USE_NEW_DYNAREC @@ -919,8 +905,14 @@ exec386(int32_t cycs) cpu_state.ssegs = 0; #ifdef USE_DEBUG_REGS_486 - if (UNLIKELY(cpu_386_check_instruction_fault())) { + if (is386) + ins_fetch_fault = cpu_386_check_instruction_fault(); + + /* Breakpoint fault has priority over other faults. */ + if ((cpu_state.abrt == 0) & ins_fetch_fault) { x86gen(); + ins_fetch_fault = 0; + /* No instructions executed at this point. */ goto block_ended; } #endif @@ -972,11 +964,13 @@ exec386(int32_t cycs) block_ended: #endif if (cpu_state.abrt) { + uint8_t oop = opcode; flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; cpu_state.abrt = 0; x86_doabrt(tempi); if (cpu_state.abrt) { + pclog("Double fault - %02X\n", oop); cpu_state.abrt = 0; #ifndef USE_NEW_DYNAREC CS = oldcs; @@ -993,6 +987,11 @@ block_ended: #endif } } + +#ifdef USE_DEBUG_REGS_486 + if (is386 && !x86_was_reset && ins_fetch_fault) + x86gen(); +#endif } else if (new_ne) { flags_rebuild(); @@ -1005,20 +1004,14 @@ block_ended: } else if (trap) { flags_rebuild(); #ifdef USE_DEBUG_REGS_486 - if (trap & 1) - dr[6] |= 0x4000; - if (trap & 2) - dr[6] |= 0x8000; + if (trap & 2) dr[6] |= 0x8000; + if (trap & 1) dr[6] |= 0x4000; #endif - trap = 0; #ifndef USE_NEW_DYNAREC oldcs = CS; #endif cpu_state.oldpc = cpu_state.pc; -#ifndef USE_DEBUG_REGS_486 - dr[6] |= 0x4000; -#endif x86_int(1); } From bb1b6660103b9b61cf1d7621a0aa75cae09c0721 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 00:43:18 +0100 Subject: [PATCH 0492/1190] Removed some commented out stuff. --- src/cdrom/cdrom.c | 8 +----- src/disk/hdc_ide.c | 61 ++----------------------------------------- src/scsi/scsi_cdrom.c | 16 ------------ 3 files changed, 3 insertions(+), 82 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 6805d42c6..b30d93812 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -1796,11 +1796,8 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) position), the rest are stuff like ISRC etc., which can be all zeroes. */ case 0x00: - if (dev->bus_type == CDROM_BUS_ATAPI) { - // pclog("Format 0 on ATAPI\n"); + if (dev->bus_type == CDROM_BUS_ATAPI) break; - } - // pclog("Format 0 on SCSI\n"); diff = 0; fallthrough; case 0x01: @@ -1847,9 +1844,6 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, const int msf) b[10] = (dat >> 8) & 0xff; b[11] = dat & 0xff; } - // pclog("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - // b[ 0], b[ 1], b[ 2], b[ 3], b[ 4], b[ 5], b[ 6], b[ 7], - // b[ 8], b[ 9], b[10], b[11]); if (b[0] != 0x00) break; base += 12; diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index eb160c41b..61211228a 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1091,7 +1091,6 @@ ide_atapi_callback(ide_t *ide) ide_irq_raise(ide); break; case PHASE_DATA_IN_DMA: - // pclog("Reading block %i (%i, %i)... ", ide->sc->sector_len + 1, ide->sc->block_len, ide->sc->packet_len); if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { @@ -1119,16 +1118,13 @@ ide_atapi_callback(ide_t *ide) default: break; case 0: - // pclog("ERROR\n"); if (ide->bus_master_error) ide->bus_master_error(ide->sc); break; case 2: - // pclog("WAIT\n"); ide_atapi_command_bus(ide); break; case 3: - // pclog("DONE\n"); /* Reached EOT - terminate the command as there's nothing more to transfer. */ ide->sc->packet_status = PHASE_COMPLETE; @@ -1138,7 +1134,6 @@ ide_atapi_callback(ide_t *ide) ide->command_stop(ide->sc); fallthrough; case 1: - // pclog("NEXT\n"); if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); @@ -1214,7 +1209,6 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->tf->pos = dev->request_pos = 0; if (dev->block_len == 0) { - // pclog("ide_atapi_pio_request(): Processing instant command...\n"); if (out && (ide->phase_data_out != NULL)) ide->phase_data_out(dev); else if (!out && (ide->command_stop != NULL)) @@ -1254,21 +1248,10 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) if (dev->block_len != 0) { if (out) { - if (ide->write != NULL) { -#if 0 - pclog("ide_atapi_pio_request(): Continuing write command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - + if (ide->write != NULL) ide->write(dev); - } if (dev->sector_len == 0) { -#if 0 - pclog("ide_atapi_pio_request(): Ending write command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - ide->sc->packet_status = PHASE_COMPLETE; ide->sc->callback = 0.0; @@ -1279,11 +1262,6 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) } } else { if (dev->sector_len == 0) { -#if 0 - pclog("ide_atapi_pio_request(): Ending read command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - if (ide->command_stop != NULL) ide->command_stop(dev); @@ -1291,14 +1269,8 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->sc->callback = 0.0; ide_atapi_callback(ide); - } else if (ide->read != NULL) { -#if 0 - pclog("ide_atapi_pio_request(): Continuing read command " - "(dev->sector_len = %i)...\n", dev->sector_len); -#endif - + } else if (ide->read != NULL) ide->read(dev); - } } } } @@ -1332,26 +1304,6 @@ ide_atapi_packet_read(ide_t *ide) /* Time for a DRQ. */ ide_atapi_pio_request(ide, 0); } -#if 0 - else if ((dev->block_len != 0) && - (dev->sector_len != 0) && - ((dev->request_pos % dev->block_len) == 0)) { - if (dev->sector_len == 0) { - // pclog("ide_atapi_packet_read(): Ending read command (dev->sector_len = %i)...\n", dev->sector_len); - - if (ide->command_stop != NULL) - ide->command_stop(ide->sc); - - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; - - ide_atapi_callback(ide); - } else if (ide->read != NULL) { - // pclog("ide_atapi_packet_read(): Continuing read command (dev->sector_len = %i)...\n", dev->sector_len); - ide->read(dev); - } - } -#endif } return ret; @@ -1386,15 +1338,6 @@ ide_atapi_packet_write(ide_t *ide, const uint16_t val) /* Time for a DRQ. */ ide_atapi_pio_request(ide, 1); } -#if 0 - else if ((dev->block_len != 0) && - ((dev->request_pos % dev->block_len) == 0) && - (ide->write != NULL)) { - // pclog("ide_atapi_packet_write(): Continuing write command (dev->sector_len = %i)...\n", dev->sector_len); - - ide->write(dev); - } -#endif } else if (dev->packet_status == PHASE_IDLE) { if (ide->tf->pos >= 12) { ide->tf->pos = 0; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index eed57c63b..292c54127 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -663,8 +663,6 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) static void scsi_cdrom_set_period(scsi_cdrom_t *dev) { - // const uint8_t cmd = dev->current_cdb[0]; - scsi_cdrom_log(dev->log, "Current speed: %ix\n", dev->drv->cur_speed); dev->callback = 0; @@ -689,7 +687,6 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; - // pclog("Current speed: %ix\n", dev->drv->cur_speed); } else { bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { @@ -711,7 +708,6 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) (dev->packet_len / dev->block_len)); period *= ((double) num) * 2352.0; - // pclog("[%02X] Calculated period for %i * 2352 bytes\n", cmd, num); } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); @@ -1082,7 +1078,6 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int dev->sector_len--; - // pclog("Sector read to buffer position %08X\n", dev->buffer_pos); dev->buffer_pos += temp_len; } } @@ -2470,7 +2465,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) break; case GPCMD_REZERO_UNIT: - // pclog("Rezero unit\n"); dev->was_cached = 0; scsi_cdrom_stop(sc); dev->requested_blocks = 0; @@ -2505,7 +2499,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: - // pclog("Audio scan\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; @@ -2552,7 +2545,6 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); toc_format = cdb[2] & 0xf; - // pclog("READ TOC format %1X\n", toc_format); if (toc_format == 0) toc_format = (cdb[9] >> 6) & 3; @@ -3170,20 +3162,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - // pclog("Play audio (10)\n"); break; case GPCMD_PLAY_AUDIO_12: msf = 0; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - // pclog("Play audio (12)\n"); break; case GPCMD_PLAY_AUDIO_MSF: msf = 1; pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - // pclog("Play audio MSF: %2i:%02i.%02i-%2i:%02i.%02i\n", - // cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8]); break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; @@ -3192,19 +3180,16 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) len = cdb[7]; } else ret = 0; - // pclog("Play audio track index\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[7] << 8) | cdb[8]; - // pclog("Play audio track relative (10)\n"); break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: msf = 0x100 | cdb[10]; pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - // pclog("Play audio track relative (12)\n"); break; default: @@ -3505,7 +3490,6 @@ atapi_out: case GPCMD_SEEK_6: case GPCMD_SEEK_10: - // pclog("Seek\n"); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->was_cached = 0; From 79134f3b21648d280f56303a2c43d92821565eb5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 03:40:52 +0100 Subject: [PATCH 0493/1190] Assorted Cyrix (and Codegen opcode Mod R/M passing table) fixes - fixes Windows 98 SE on Cyrix 6x86's with power management enabled. --- src/codegen/codegen_x86-64.c | 8 +++--- src/codegen/codegen_x86.c | 8 +++--- src/codegen_new/codegen.c | 8 +++--- src/cpu/386_common.c | 50 +++++++++++++++++++++++++++++++++++- src/cpu/x86.h | 6 +++++ src/cpu/x86_ops_cyrix.h | 11 ++++++-- src/cpu/x86_ops_rep.h | 2 ++ src/cpu/x86_ops_rep_2386.h | 2 ++ src/cpu/x86_ops_rep_dyn.h | 2 ++ src/cpu/x86seg.c | 10 +++----- src/io.c | 16 ++++++++++++ 11 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index 04c2136ff..00db630a3 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -499,14 +499,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index df0ed3bfd..935e2bab6 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1643,14 +1643,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 39ab69b3d..82f6cd037 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -359,14 +359,14 @@ static uint8_t opcode_modrm[256] = { static uint8_t opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 8a2bb4ab8..5b0e1a5c4 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -107,6 +107,12 @@ uint32_t backupregs[16]; x86seg _oldds; +uint8_t rep_op = 0x00; +uint8_t is_smint = 0; + +uint16_t io_port = 0x0000; +uint32_t io_val = 0x00000000; + int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ @@ -1215,7 +1221,7 @@ smram_restore_state_amd_k(uint32_t *saved_state) } static void -smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) +smram_save_state_cyrix(uint32_t *saved_state, int in_hlt) { saved_state[0] = dr[7]; saved_state[1] = cpu_state.flags | (cpu_state.eflags << 16); @@ -1224,6 +1230,35 @@ smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) saved_state[4] = cpu_state.pc; saved_state[5] = CS | (CPL << 21); saved_state[6] = 0x00000000; + saved_state[7] = 0x00010000; + + if (((opcode >= 0x6e) && (opcode <= 0x6f)) || ((opcode >= 0xe6) && (opcode <= 0xe7)) || + ((opcode >= 0xee) && (opcode <= 0xef))) { + saved_state[6] |= 0x00000002; + saved_state[7] = (opcode & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000006; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000004; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } + + if (is_smint) { + saved_state[6] |= 0x00000008; + is_smint = 0; + } + + if (in_hlt) + saved_state[6] |= 0x00000010; + + saved_state[7] |= io_port; + saved_state[8] = io_val; + + if (saved_state[6] & 0x00000002) + saved_state[9] = ESI; + else + saved_state[9] = EDI; } static void @@ -1234,6 +1269,13 @@ smram_restore_state_cyrix(uint32_t *saved_state) cpu_state.eflags = saved_state[1] >> 16; cr0 = saved_state[2]; cpu_state.pc = saved_state[4]; + /* Restore CPL. */ + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x9f) | (((saved_state[5] >> 21) & 0x03) << 5); + + if (saved_state[6] & 0x00000002) + ESI = saved_state[9]; + else + EDI = saved_state[9]; } void @@ -1368,6 +1410,9 @@ enter_smm(int in_hlt) writememl(0, smram_state - 0x14, saved_state[4]); writememl(0, smram_state - 0x18, saved_state[5]); writememl(0, smram_state - 0x24, saved_state[6]); + writememl(0, smram_state - 0x28, saved_state[7]); + writememl(0, smram_state - 0x2c, saved_state[8]); + writememl(0, smram_state - 0x30, saved_state[9]); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; @@ -1452,6 +1497,9 @@ leave_smm(void) else cyrix_load_seg_descriptor_2386(smram_state - 0x20, &cpu_state.seg_cs); saved_state[6] = readmeml(0, smram_state - 0x24); + saved_state[7] = readmeml(0, smram_state - 0x28); + saved_state[8] = readmeml(0, smram_state - 0x2c); + saved_state[9] = readmeml(0, smram_state - 0x30); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index 327af8964..ccfeadea0 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -103,4 +103,10 @@ extern int fpu_cycles; extern void x86illegal(void); +extern uint8_t rep_op; +extern uint8_t is_smint; + +extern uint16_t io_port; +extern uint32_t io_val; + #endif /*EMU_X86_H*/ diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index 8c3d6e155..ac864cd20 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -63,18 +63,23 @@ opRSDC_common(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*ES*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_es); + ES = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x18: /*DS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ds); + DS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x10: /*SS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ss); + SS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x20: /*FS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_fs); + FS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x28: /*GS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_gs); + GS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; default: x86illegal(); @@ -216,8 +221,10 @@ opSMINT(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opSMINT\n"); - else - x86illegal(); + else { + is_smint = 1; + enter_smm(0); + } return 1; } diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index c75684d31..6449912e9 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -855,6 +855,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -869,6 +870,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_2386.h b/src/cpu/x86_ops_rep_2386.h index aa1984f81..3b96d54e3 100644 --- a/src/cpu/x86_ops_rep_2386.h +++ b/src/cpu/x86_ops_rep_2386.h @@ -843,6 +843,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -857,6 +858,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h index bdb721ab0..1220c0da3 100644 --- a/src/cpu/x86_ops_rep_dyn.h +++ b/src/cpu/x86_ops_rep_dyn.h @@ -761,6 +761,7 @@ opREPNE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -774,6 +775,7 @@ opREPE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index cd393812d..2a0601661 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -2581,19 +2581,17 @@ cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; -#ifdef USE_DYNAREC - codegen_flat_ds = 0; -#endif } + + if (seg == &cpu_state.seg_cs) + set_use32(segdat[3] & 0x40); + if (seg == &cpu_state.seg_ss) { if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; else cpu_cur_status |= CPU_STATUS_NOTFLATSS; set_stack32((segdat[3] & 0x40) ? 1 : 0); -#ifdef USE_DYNAREC - codegen_flat_ss = 0; -#endif } } } diff --git a/src/io.c b/src/io.c index 27f8503b0..9554c971d 100644 --- a/src/io.c +++ b/src/io.c @@ -28,6 +28,7 @@ #include <86box/io.h> #include <86box/timer.h> #include "cpu.h" +#include "x86.h" #include <86box/m_amstrad.h> #include <86box/pci.h> @@ -344,6 +345,8 @@ inb(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -408,6 +411,9 @@ outb(uint16_t port, uint8_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -464,6 +470,8 @@ inw(uint16_t port) #endif uint8_t ret8[2]; + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -540,6 +548,9 @@ outw(uint16_t port, uint16_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -612,6 +623,8 @@ inl(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -720,6 +733,9 @@ outl(uint16_t port, uint32_t val) #endif int i = 0; + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif From 49463607c1b5825d7805fdc5abcdec9bb1ed4027 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 04:29:58 +0100 Subject: [PATCH 0494/1190] C&T 69000: Rewrite the PCI register handling and intialize the registers to sane default, fixes the card's detection by the Windows 98 driver installer. --- src/video/vid_chips_69000.c | 248 +++++++++++++++++++++--------------- 1 file changed, 144 insertions(+), 104 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index b0e8db35a..c17fe2004 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -107,6 +107,7 @@ typedef struct chips_69000_t { uint8_t mm_regs[256], mm_index; uint8_t flat_panel_regs[256], flat_panel_index; uint8_t ext_regs[256], ext_index; + uint8_t pci_regs[256]; union { uint32_t mem_regs[4]; @@ -2156,57 +2157,74 @@ static uint8_t chips_69000_pci_read(UNUSED(int func), int addr, void *priv) { chips_69000_t *chips = (chips_69000_t *) priv; + uint8_t ret = 0x00; - { - switch (addr) { - case 0x00: - return 0x2C; - case 0x01: - return 0x10; - case 0x02: - return 0xC0; - case 0x03: - return 0x00; - case 0x04: - return (chips->pci_conf_status & 0b11100011) | 0x80; - case 0x06: - return 0x80; - case 0x07: - return 0x02; - case 0x08: - case 0x09: - case 0x0a: - return 0x00; - case 0x0b: - return 0x03; - case 0x13: - return chips->linear_mapping.base >> 24; - case 0x30: - return chips->pci_rom_enable & 0x1; - case 0x31: - return 0x0; - case 0x32: - return chips->rom_addr & 0xFF; - case 0x33: - return (chips->rom_addr & 0xFF00) >> 8; - case 0x3c: - return chips->pci_line_interrupt; - case 0x3d: - return 0x01; - case 0x2C: - case 0x2D: - case 0x6C: - case 0x6D: - return (chips->subsys_vid >> ((addr & 1) * 8)) & 0xFF; - case 0x2E: - case 0x2F: - case 0x6E: - case 0x6F: - return (chips->subsys_pid >> ((addr & 1) * 8)) & 0xFF; - default: - return 0x00; - } + switch (addr) { + case 0x00: + ret = 0x2c; + break; + case 0x01: + ret = 0x10; + break; + case 0x02: + ret = 0xc0; + break; + case 0x03: + ret = 0x00; + break; + + case 0x04: + ret = (chips->pci_conf_status & 0x73) | 0x80; + break; + case 0x05: + ret = chips->pci_regs[addr] & 0x01; + break; + case 0x06: + ret = 0x80; + break; + case 0x07: + ret = chips->pci_regs[addr] | 0x02; + break; + + case 0x0b: + ret = 0x03; + break; + + case 0x13: + ret = chips->linear_mapping.base >> 24; + break; + + case 0x2c ... 0x2d: + case 0x6c ... 0x6d: + ret = chips->subsys_vid_b[addr & 1]; + break; + case 0x2e ... 0x2f: + case 0x6e ... 0x6f: + ret = chips->subsys_pid_b[addr & 1]; + break; + + case 0x30: + ret = chips->pci_rom_enable & 0x1; + break; + case 0x32: + ret = chips->rom_addr & 0xff; + break; + case 0x33: + ret = (chips->rom_addr & 0xff00) >> 8; + break; + + case 0x3c: + ret = chips->pci_line_interrupt; + break; + case 0x3d: + ret = 0x01; + break; + + default: + break; } + + return ret; } static void @@ -2214,67 +2232,77 @@ chips_69000_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) { chips_69000_t *chips = (chips_69000_t *) priv; - { - switch (addr) { - case 0x04: - { - chips->pci_conf_status = val; - io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); - mem_mapping_disable(&chips->linear_mapping); - mem_mapping_disable(&chips->svga.mapping); - if (chips->pci_conf_status & PCI_COMMAND_IO) { - io_sethandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); - } - if (chips->pci_conf_status & PCI_COMMAND_MEM) { - mem_mapping_enable(&chips->svga.mapping); - if (chips->linear_mapping.base) - mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); - } - break; - } - case 0x13: - { - chips->linear_mapping.base = val << 24; - if (chips->linear_mapping.base) - mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); - break; - } - case 0x3c: - chips->pci_line_interrupt = val; - break; - case 0x30: - if (chips->on_board) break; + switch (addr) { + case 0x04: + chips->pci_conf_status = val; + io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + mem_mapping_disable(&chips->linear_mapping); + mem_mapping_disable(&chips->svga.mapping); + if (!chips->on_board) + mem_mapping_disable(&chips->bios_rom.mapping); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + if (val & PCI_COMMAND_MEM) { + if (!chips->on_board && (chips->pci_rom_enable & 1)) + mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); + mem_mapping_enable(&chips->svga.mapping); + if (chips->linear_mapping.base > 0x00000000) + mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); + } + break; + case 0x05: + chips->pci_regs[addr] = val & 0x01; + break; + case 0x07: + chips->pci_regs[addr] &= ~(val & 0xc8); + break; + + case 0x13: + chips->linear_mapping.base = val << 24; + mem_mapping_disable(&chips->linear_mapping); + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->linear_mapping.base > 0x00000000)) + mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); + break; + + case 0x30: + if (!chips->on_board) { chips->pci_rom_enable = val & 0x1; mem_mapping_disable(&chips->bios_rom.mapping); - if (chips->pci_rom_enable & 1) { + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x32: - if (chips->on_board) break; - chips->rom_addr &= ~0xFF; - chips->rom_addr |= val & 0xFC; - if (chips->pci_rom_enable & 1) { + } + break; + case 0x32: + if (!chips->on_board) { + chips->rom_addr &= ~0xff; + chips->rom_addr |= val & 0xfc; + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x33: - if (chips->on_board) break; - chips->rom_addr &= ~0xFF00; + } + break; + case 0x33: + if (!chips->on_board) { + chips->rom_addr &= ~0xff00; chips->rom_addr |= (val << 8); - if (chips->pci_rom_enable & 1) { + if ((chips->pci_conf_status & PCI_COMMAND_MEM) && + (chips->pci_rom_enable & 1)) mem_mapping_set_addr(&chips->bios_rom.mapping, chips->rom_addr << 16, 0x10000); - } - break; - case 0x6C: - case 0x6D: - chips->subsys_vid_b[addr & 1] = val; - break; - case 0x6E: - case 0x6F: - chips->subsys_pid_b[addr & 1] = val; - break; - } + } + break; + + case 0x3c: + chips->pci_line_interrupt = val; + break; + + case 0x6c ... 0x6d: + chips->subsys_vid_b[addr & 1] = val; + break; + case 0x6e ... 0x6f: + chips->subsys_pid_b[addr & 1] = val; + break; } } @@ -2839,6 +2867,18 @@ chips_69000_init(const device_t *info) chips->flat_panel_regs[0x01] = 1; + chips->pci_conf_status = 0x00; + chips->pci_rom_enable = 0x00; + chips->rom_addr = 0x0000; + chips->subsys_vid = 0x102c; + chips->subsys_pid = 0x00c0; + + io_removehandler(0x03c0, 0x0020, chips_69000_in, NULL, NULL, chips_69000_out, NULL, NULL, chips); + mem_mapping_disable(&chips->linear_mapping); + mem_mapping_disable(&chips->svga.mapping); + if (!chips->on_board) + mem_mapping_disable(&chips->bios_rom.mapping); + *reset_state = *chips; return chips; From b1a77195abe7b513583010b383a7f9ae317a16d2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 21:23:32 +0600 Subject: [PATCH 0495/1190] C&T 69000: Fix bad refresh rate --- src/video/vid_chips_69000.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index c17fe2004..f7ed7ef14 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -1428,7 +1428,6 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.bytes_skip = 0; chips->bitblt_running.mono_bytes_pitch = 0; chips->bitblt_running.mono_bits_skip_left = 0; - int orig_cycles = cycles; if (chips->bitblt.bitblt_control & (1 << 23)) { chips->bitblt_running.bytes_per_pixel = 1 + ((chips->bitblt.bitblt_control >> 24) & 3); @@ -1632,7 +1631,6 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.count_x = 0; chips->bitblt_running.x = 0; } while ((++chips->bitblt_running.count_y) < chips->bitblt_running.actual_destination_height); - cycles = orig_cycles; chips_69000_bitblt_interrupt(chips); } @@ -1644,7 +1642,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } if (chips->bitblt_running.bitblt.bitblt_control & (1 << 12)) { - int orig_cycles = cycles; chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bitblt.monochrome_source_alignment == 1) { uint8_t val = chips->bitblt_running.bytes_port[0]; @@ -1662,7 +1659,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(chips->bitblt_running.bytes_port[j] & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1678,7 +1674,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y && chips->bitblt_running.bitblt.monochrome_source_alignment != 1) { - cycles = orig_cycles; return; } } @@ -1692,7 +1687,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 16; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (15 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1706,7 +1700,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 32; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (31 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } @@ -1729,12 +1722,10 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 64; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (63 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { - cycles = orig_cycles; return; } } } - cycles = orig_cycles; return; } @@ -1744,7 +1735,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bytes_written == chips->bitblt_running.bytes_per_pixel) { - int orig_cycles = cycles; uint32_t source_pixel = chips->bitblt_running.bytes_port[0]; chips->bitblt_running.bytes_written = 0; if (chips->bitblt_running.bytes_per_pixel >= 2) @@ -1755,7 +1745,6 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { chips->bitblt_running.bytes_in_line_written += chips->bitblt_running.bytes_per_pixel; chips_69000_process_pixel(chips, source_pixel); - cycles = orig_cycles; chips->bitblt_running.x += chips->bitblt_running.x_dir; if (chips->bitblt_running.bytes_in_line_written >= chips->bitblt_running.bitblt.destination_width) { @@ -2746,7 +2735,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (chips->ext_regs[0xcb] & 4) + if (!(chips->ext_regs[0xcb] & 4)) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2846,7 +2835,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vblank_start = chips_69000_vblank_start; + chips->svga.vsync_callback = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 1bf78aebfdc599d65c67e6ff28ebbb9382a79f68 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 21:45:50 +0600 Subject: [PATCH 0496/1190] C&T 69000: Adjust interrupt conditions --- src/video/vid_chips_69000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index f7ed7ef14..29521d1ae 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -240,7 +240,7 @@ chips_69000_write_flat_panel(chips_69000_t* chips, uint8_t val) void chips_69000_interrupt(chips_69000_t* chips) { - pci_irq(chips->slot, PCI_INTA, 0, !!((chips->mem_regs[0] & chips->mem_regs[1]) & 0x80004040), &chips->irq_state); + pci_irq(chips->slot, PCI_INTA, 0, !!(chips->mem_regs[0] & chips->mem_regs[1] & 0x80004040), &chips->irq_state); } void @@ -2416,7 +2416,7 @@ chips_69000_writeb_mmio(uint32_t addr, uint8_t val, chips_69000_t* chips) { chips->mem_regs_b[addr & 0xF] = val; chips->mem_regs[(addr >> 2) & 0x3] &= 0x80004040; - if (addr == 0x605 || addr == 0x607) + if (addr == 0x601 || addr == 0x603) chips_69000_interrupt(chips); break; } From 277273c05da8153dfe59a9ec0a8656d36b1d5939 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 16:54:41 +0100 Subject: [PATCH 0497/1190] ATAPI PIO: Do not prematurely terminate the command if bytes are left to be transferred but all sectors have already been read into the buffer, fixes FreeBSD CD-ROM boot on some machines. --- src/disk/hdc_ide.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 61211228a..bf0d4d286 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1197,7 +1197,8 @@ ide_atapi_callback(ide_t *ide) static void ide_atapi_pio_request(ide_t *ide, uint8_t out) { - scsi_common_t *dev = ide->sc; + scsi_common_t *dev = ide->sc; + int left = 0; ide_irq_lower(ide); @@ -1221,6 +1222,8 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_log("%i bytes %s, %i bytes are still left\n", ide->tf->pos, out ? "written" : "read", dev->packet_len - ide->tf->pos); + left = 1; + /* If less than (packet length) bytes are remaining, update packet length accordingly. @@ -1252,23 +1255,33 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->write(dev); if (dev->sector_len == 0) { - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; + if (left) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } else { + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - if (ide->phase_data_out != NULL) - (void) ide->phase_data_out(dev); + if (ide->phase_data_out != NULL) + (void) ide->phase_data_out(dev); - ide_atapi_callback(ide); + ide_atapi_callback(ide); + } } } else { if (dev->sector_len == 0) { - if (ide->command_stop != NULL) - ide->command_stop(dev); + if (left) { + ide_atapi_callback(ide); + ide_set_callback(ide, 0.0); + } else { + if (ide->command_stop != NULL) + ide->command_stop(dev); - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; + ide->sc->packet_status = PHASE_COMPLETE; + ide->sc->callback = 0.0; - ide_atapi_callback(ide); + ide_atapi_callback(ide); + } } else if (ide->read != NULL) ide->read(dev); } From 2019af174f9949bdc1017e95e02d206fb6ed0621 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 22:53:00 +0600 Subject: [PATCH 0498/1190] Revert "C&T 69000: Fix bad refresh rate" This reverts commit b1a77195abe7b513583010b383a7f9ae317a16d2. --- src/video/vid_chips_69000.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 29521d1ae..8963cb94b 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -1428,6 +1428,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.bytes_skip = 0; chips->bitblt_running.mono_bytes_pitch = 0; chips->bitblt_running.mono_bits_skip_left = 0; + int orig_cycles = cycles; if (chips->bitblt.bitblt_control & (1 << 23)) { chips->bitblt_running.bytes_per_pixel = 1 + ((chips->bitblt.bitblt_control >> 24) & 3); @@ -1631,6 +1632,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) chips->bitblt_running.count_x = 0; chips->bitblt_running.x = 0; } while ((++chips->bitblt_running.count_y) < chips->bitblt_running.actual_destination_height); + cycles = orig_cycles; chips_69000_bitblt_interrupt(chips); } @@ -1642,6 +1644,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } if (chips->bitblt_running.bitblt.bitblt_control & (1 << 12)) { + int orig_cycles = cycles; chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bitblt.monochrome_source_alignment == 1) { uint8_t val = chips->bitblt_running.bytes_port[0]; @@ -1659,6 +1662,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(chips->bitblt_running.bytes_port[j] & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1674,6 +1678,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (7 - i)))); if (orig_count_y != chips->bitblt_running.count_y && chips->bitblt_running.bitblt.monochrome_source_alignment != 1) { + cycles = orig_cycles; return; } } @@ -1687,6 +1692,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 16; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (15 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1700,6 +1706,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 32; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (31 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } @@ -1722,10 +1729,12 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { for (i = 0; i < 64; i++) { chips_69000_process_mono_bit(chips, !!(val & (1 << (63 - i)))); if (orig_count_y != chips->bitblt_running.count_y) { + cycles = orig_cycles; return; } } } + cycles = orig_cycles; return; } @@ -1735,6 +1744,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { } chips->bitblt_running.bytes_port[chips->bitblt_running.bytes_written++] = data; if (chips->bitblt_running.bytes_written == chips->bitblt_running.bytes_per_pixel) { + int orig_cycles = cycles; uint32_t source_pixel = chips->bitblt_running.bytes_port[0]; chips->bitblt_running.bytes_written = 0; if (chips->bitblt_running.bytes_per_pixel >= 2) @@ -1745,6 +1755,7 @@ chips_69000_bitblt_write(chips_69000_t* chips, uint8_t data) { chips->bitblt_running.bytes_in_line_written += chips->bitblt_running.bytes_per_pixel; chips_69000_process_pixel(chips, source_pixel); + cycles = orig_cycles; chips->bitblt_running.x += chips->bitblt_running.x_dir; if (chips->bitblt_running.bytes_in_line_written >= chips->bitblt_running.bitblt.destination_width) { @@ -2735,7 +2746,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (!(chips->ext_regs[0xcb] & 4)) + if (chips->ext_regs[0xcb] & 4) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2835,7 +2846,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vsync_callback = chips_69000_vblank_start; + chips->svga.vblank_start = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 65020a80c88801581d1400f23dfe515fa85b7195 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 22:53:36 +0600 Subject: [PATCH 0499/1190] Revert "C&T 69000: All ROPs now implemented, also fixed transparency bitblts" This reverts commit 000af483f3e0561fbb4c214496d20d0be358359b. --- src/video/vid_chips_69000.c | 1342 +++++++++++++---------------------- 1 file changed, 509 insertions(+), 833 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 8963cb94b..0347435fa 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -252,797 +252,486 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -#define ROPMIX(R, D, P, S, out) \ - { \ - switch (R) { \ - case 0x00: \ - out = 0; \ - break; \ - case 0x01: \ - out = ~(D | (P | S)); \ - break; \ - case 0x02: \ - out = D & ~(P | S); \ - break; \ - case 0x03: \ - out = ~(P | S); \ - break; \ - case 0x04: \ - out = S & ~(D | P); \ - break; \ - case 0x05: \ - out = ~(D | P); \ - break; \ - case 0x06: \ - out = ~(P | ~(D ^ S)); \ - break; \ - case 0x07: \ - out = ~(P | (D & S)); \ - break; \ - case 0x08: \ - out = S & (D & ~P); \ - break; \ - case 0x09: \ - out = ~(P | (D ^ S)); \ - break; \ - case 0x0a: \ - out = D & ~P; \ - break; \ - case 0x0b: \ - out = ~(P | (S & ~D)); \ - break; \ - case 0x0c: \ - out = S & ~P; \ - break; \ - case 0x0d: \ - out = ~(P | (D & ~S)); \ - break; \ - case 0x0e: \ - out = ~(P | ~(D | S)); \ - break; \ - case 0x0f: \ - out = ~P; \ - break; \ - case 0x10: \ - out = P & ~(D | S); \ - break; \ - case 0x11: \ - out = ~(D | S); \ - break; \ - case 0x12: \ - out = ~(S | ~(D ^ P)); \ - break; \ - case 0x13: \ - out = ~(S | (D & P)); \ - break; \ - case 0x14: \ - out = ~(D | ~(P ^ S)); \ - break; \ - case 0x15: \ - out = ~(D | (P & S)); \ - break; \ - case 0x16: \ - out = P ^ (S ^ (D & ~(P & S))); \ - break; \ - case 0x17: \ - out = ~(S ^ ((S ^ P) & (D ^ S))); \ - break; \ - case 0x18: \ - out = (S ^ P) & (P ^ D); \ - break; \ - case 0x19: \ - out = ~(S ^ (D & ~(P & S))); \ - break; \ - case 0x1a: \ - out = P ^ (D | (S & P)); \ - break; \ - case 0x1b: \ - out = ~(S ^ (D & (P ^ S))); \ - break; \ - case 0x1c: \ - out = P ^ (S | (D & P)); \ - break; \ - case 0x1d: \ - out = ~(D ^ (S & (P ^ D))); \ - break; \ - case 0x1e: \ - out = P ^ (D | S); \ - break; \ - case 0x1f: \ - out = ~(P & (D | S)); \ - break; \ - case 0x20: \ - out = D & (P & ~S); \ - break; \ - case 0x21: \ - out = ~(S | (D ^ P)); \ - break; \ - case 0x22: \ - out = D & ~S; \ - break; \ - case 0x23: \ - out = ~(S | (P & ~D)); \ - break; \ - case 0x24: \ - out = (S ^ P) & (D ^ S); \ - break; \ - case 0x25: \ - out = ~(P ^ (D & ~(S & P))); \ - break; \ - case 0x26: \ - out = S ^ (D | (P & S)); \ - break; \ - case 0x27: \ - out = S ^ (D | ~(P ^ S)); \ - break; \ - case 0x28: \ - out = D & (P ^ S); \ - break; \ - case 0x29: \ - out = ~(P ^ (S ^ (D | (P & S)))); \ - break; \ - case 0x2a: \ - out = D & ~(P & S); \ - break; \ - case 0x2b: \ - out = ~(S ^ ((S ^ P) & (P ^ D))); \ - break; \ - case 0x2c: \ - out = S ^ (P & (D | S)); \ - break; \ - case 0x2d: \ - out = P ^ (S | ~D); \ - break; \ - case 0x2e: \ - out = P ^ (S | (D ^ P)); \ - break; \ - case 0x2f: \ - out = ~(P & (S | ~D)); \ - break; \ - case 0x30: \ - out = P & ~S; \ - break; \ - case 0x31: \ - out = ~(S | (D & ~P)); \ - break; \ - case 0x32: \ - out = S ^ (D | (P | S)); \ - break; \ - case 0x33: \ - out = ~S; \ - break; \ - case 0x34: \ - out = S ^ (P | (D & S)); \ - break; \ - case 0x35: \ - out = S ^ (P | ~(D ^ S)); \ - break; \ - case 0x36: \ - out = S ^ (D | P); \ - break; \ - case 0x37: \ - out = ~(S & (D | P)); \ - break; \ - case 0x38: \ - out = P ^ (S & (D | P)); \ - break; \ - case 0x39: \ - out = S ^ (P | ~D); \ - break; \ - case 0x3a: \ - out = S ^ (P | (D ^ S)); \ - break; \ - case 0x3b: \ - out = ~(S & (P | ~D)); \ - break; \ - case 0x3c: \ - out = P ^ S; \ - break; \ - case 0x3d: \ - out = S ^ (P | ~(D | S)); \ - break; \ - case 0x3e: \ - out = S ^ (P | (D & ~S)); \ - break; \ - case 0x3f: \ - out = ~(P & S); \ - break; \ - case 0x40: \ - out = P & (S & ~D); \ - break; \ - case 0x41: \ - out = ~(D | (P ^ S)); \ - break; \ - case 0x42: \ - out = (S ^ D) & (P ^ D); \ - break; \ - case 0x43: \ - out = ~(S ^ (P & ~(D & S))); \ - break; \ - case 0x44: \ - out = S & ~D; \ - break; \ - case 0x45: \ - out = ~(D | (P & ~S)); \ - break; \ - case 0x46: \ - out = D ^ (S | (P & D)); \ - break; \ - case 0x47: \ - out = ~(P ^ (S & (D ^ P))); \ - break; \ - case 0x48: \ - out = S & (D ^ P); \ - break; \ - case 0x49: \ - out = ~(P ^ (D ^ (S | (P & D)))); \ - break; \ - case 0x4a: \ - out = D ^ (P & (S | D)); \ - break; \ - case 0x4b: \ - out = P ^ (D | ~S); \ - break; \ - case 0x4c: \ - out = S & ~(D & P); \ - break; \ - case 0x4d: \ - out = ~(S ^ ((S ^ P) | (D ^ S))); \ - break; \ - case 0x4e: \ - out = P ^ (D | (S ^ P)); \ - break; \ - case 0x4f: \ - out = ~(P & (D | ~S)); \ - break; \ - case 0x50: \ - out = P & ~D; \ - break; \ - case 0x51: \ - out = ~(D | (S & ~P)); \ - break; \ - case 0x52: \ - out = D ^ (P | (S & D)); \ - break; \ - case 0x53: \ - out = ~(S ^ (P & (D ^ S))); \ - break; \ - case 0x54: \ - out = ~(D | ~(P | S)); \ - break; \ - case 0x55: \ - out = ~D; \ - break; \ - case 0x56: \ - out = D ^ (P | S); \ - break; \ - case 0x57: \ - out = ~(D & (P | S)); \ - break; \ - case 0x58: \ - out = P ^ (D & (S | P)); \ - break; \ - case 0x59: \ - out = D ^ (P | ~S); \ - break; \ - case 0x5a: \ - out = D ^ P; \ - break; \ - case 0x5b: \ - out = D ^ (P | ~(S | D)); \ - break; \ - case 0x5c: \ - out = D ^ (P | (S ^ D)); \ - break; \ - case 0x5d: \ - out = ~(D & (P | ~S)); \ - break; \ - case 0x5e: \ - out = D ^ (P | (S & ~D)); \ - break; \ - case 0x5f: \ - out = ~(D & P); \ - break; \ - case 0x60: \ - out = P & (D ^ S); \ - break; \ - case 0x61: \ - out = ~(D ^ (S ^ (P | (D & S)))); \ - break; \ - case 0x62: \ - out = D ^ (S & (P | D)); \ - break; \ - case 0x63: \ - out = S ^ (D | ~P); \ - break; \ - case 0x64: \ - out = S ^ (D & (P | S)); \ - break; \ - case 0x65: \ - out = D ^ (S | ~P); \ - break; \ - case 0x66: \ - out = D ^ S; \ - break; \ - case 0x67: \ - out = S ^ (D | ~(P | S)); \ - break; \ - case 0x68: \ - out = ~(D ^ (S ^ (P | ~(D | S)))); \ - break; \ - case 0x69: \ - out = ~(P ^ (D ^ S)); \ - break; \ - case 0x6a: \ - out = D ^ (P & S); \ - break; \ - case 0x6b: \ - out = ~(P ^ (S ^ (D & (P | S)))); \ - break; \ - case 0x6c: \ - out = S ^ (D & P); \ - break; \ - case 0x6d: \ - out = ~(P ^ (D ^ (S & (P | D)))); \ - break; \ - case 0x6e: \ - out = S ^ (D & (P | ~S)); \ - break; \ - case 0x6f: \ - out = ~(P & ~(D ^ S)); \ - break; \ - case 0x70: \ - out = P & ~(D & S); \ - break; \ - case 0x71: \ - out = ~(S ^ ((S ^ D) & (P ^ D))); \ - break; \ - case 0x72: \ - out = S ^ (D | (P ^ S)); \ - break; \ - case 0x73: \ - out = ~(S & (D | ~P)); \ - break; \ - case 0x74: \ - out = D ^ (S | (P ^ D)); \ - break; \ - case 0x75: \ - out = ~(D & (S | ~P)); \ - break; \ - case 0x76: \ - out = S ^ (D | (P & ~S)); \ - break; \ - case 0x77: \ - out = ~(D & S); \ - break; \ - case 0x78: \ - out = P ^ (D & S); \ - break; \ - case 0x79: \ - out = ~(D ^ (S ^ (P & (D | S)))); \ - break; \ - case 0x7a: \ - out = D ^ (P & (S | ~D)); \ - break; \ - case 0x7b: \ - out = ~(S & ~(D ^ P)); \ - break; \ - case 0x7c: \ - out = S ^ (P & (D | ~S)); \ - break; \ - case 0x7d: \ - out = ~(D & ~(P ^ S)); \ - break; \ - case 0x7e: \ - out = (S ^ P) | (D ^ S); \ - break; \ - case 0x7f: \ - out = ~(D & (P & S)); \ - break; \ - case 0x80: \ - out = D & (P & S); \ - break; \ - case 0x81: \ - out = ~((S ^ P) | (D ^ S)); \ - break; \ - case 0x82: \ - out = D & ~(P ^ S); \ - break; \ - case 0x83: \ - out = ~(S ^ (P & (D | ~S))); \ - break; \ - case 0x84: \ - out = S & ~(D ^ P); \ - break; \ - case 0x85: \ - out = ~(P ^ (D & (S | ~P))); \ - break; \ - case 0x86: \ - out = D ^ (S ^ (P & (D | S))); \ - break; \ - case 0x87: \ - out = ~(P ^ (D & S)); \ - break; \ - case 0x88: \ - out = D & S; \ - break; \ - case 0x89: \ - out = ~(S ^ (D | (P & ~S))); \ - break; \ - case 0x8a: \ - out = D & (S | ~P); \ - break; \ - case 0x8b: \ - out = ~(D ^ (S | (P ^ D))); \ - break; \ - case 0x8c: \ - out = S & (D | ~P); \ - break; \ - case 0x8d: \ - out = ~(S ^ (D | (P ^ S))); \ - break; \ - case 0x8e: \ - out = S ^ ((S ^ D) & (P ^ D)); \ - break; \ - case 0x8f: \ - out = ~(P & ~(D & S)); \ - break; \ - case 0x90: \ - out = P & ~(D ^ S); \ - break; \ - case 0x91: \ - out = ~(S ^ (D & (P | ~S))); \ - break; \ - case 0x92: \ - out = D ^ (P ^ (S & (D | P))); \ - break; \ - case 0x93: \ - out = ~(S ^ (P & D)); \ - break; \ - case 0x94: \ - out = P ^ (S ^ (D & (P | S))); \ - break; \ - case 0x95: \ - out = ~(D ^ (P & S)); \ - break; \ - case 0x96: \ - out = D ^ (P ^ S); \ - break; \ - case 0x97: \ - out = P ^ (S ^ (D | ~(P | S))); \ - break; \ - case 0x98: \ - out = ~(S ^ (D | ~(P | S))); \ - break; \ - case 0x99: \ - out = ~(D ^ S); \ - break; \ - case 0x9a: \ - out = D ^ (P & ~S); \ - break; \ - case 0x9b: \ - out = ~(S ^ (D & (P | S))); \ - break; \ - case 0x9c: \ - out = S ^ (P & ~D); \ - break; \ - case 0x9d: \ - out = ~(D ^ (S & (P | D))); \ - break; \ - case 0x9e: \ - out = D ^ (S ^ (P | (D & S))); \ - break; \ - case 0x9f: \ - out = ~(P & (D ^ S)); \ - break; \ - case 0xa0: \ - out = D & P; \ - break; \ - case 0xa1: \ - out = ~(P ^ (D | (S & ~P))); \ - break; \ - case 0xa2: \ - out = D & (P | ~S); \ - break; \ - case 0xa3: \ - out = ~(D ^ (P | (S ^ D))); \ - break; \ - case 0xa4: \ - out = ~(P ^ (D | ~(S | P))); \ - break; \ - case 0xa5: \ - out = ~(P ^ D); \ - break; \ - case 0xa6: \ - out = D ^ (S & ~P); \ - break; \ - case 0xa7: \ - out = ~(P ^ (D & (S | P))); \ - break; \ - case 0xa8: \ - out = D & (P | S); \ - break; \ - case 0xa9: \ - out = ~(D ^ (P | S)); \ - break; \ - case 0xaa: \ - out = D; \ - break; \ - case 0xab: \ - out = D | ~(P | S); \ - break; \ - case 0xac: \ - out = S ^ (P & (D ^ S)); \ - break; \ - case 0xad: \ - out = ~(D ^ (P | (S & D))); \ - break; \ - case 0xae: \ - out = D | (S & ~P); \ - break; \ - case 0xaf: \ - out = D | ~P; \ - break; \ - case 0xb0: \ - out = P & (D | ~S); \ - break; \ - case 0xb1: \ - out = ~(P ^ (D | (S ^ P))); \ - break; \ - case 0xb2: \ - out = S ^ ((S ^ P) | (D ^ S)); \ - break; \ - case 0xb3: \ - out = ~(S & ~(D & P)); \ - break; \ - case 0xb4: \ - out = P ^ (S & ~D); \ - break; \ - case 0xb5: \ - out = ~(D ^ (P & (S | D))); \ - break; \ - case 0xb6: \ - out = D ^ (P ^ (S | (D & P))); \ - break; \ - case 0xb7: \ - out = ~(S & (D ^ P)); \ - break; \ - case 0xb8: \ - out = P ^ (S & (D ^ P)); \ - break; \ - case 0xb9: \ - out = ~(D ^ (S | (P & D))); \ - break; \ - case 0xba: \ - out = D | (P & ~S); \ - break; \ - case 0xbb: \ - out = D | ~S; \ - break; \ - case 0xbc: \ - out = S ^ (P & ~(D & S)); \ - break; \ - case 0xbd: \ - out = ~((S ^ D) & (P ^ D)); \ - break; \ - case 0xbe: \ - out = D | (P ^ S); \ - break; \ - case 0xbf: \ - out = D | ~(P & S); \ - break; \ - case 0xc0: \ - out = P & S; \ - break; \ - case 0xc1: \ - out = ~(S ^ (P | (D & ~S))); \ - break; \ - case 0xc2: \ - out = ~(S ^ (P | ~(D | S))); \ - break; \ - case 0xc3: \ - out = ~(P ^ S); \ - break; \ - case 0xc4: \ - out = S & (P | ~D); \ - break; \ - case 0xc5: \ - out = ~(S ^ (P | (D ^ S))); \ - break; \ - case 0xc6: \ - out = S ^ (D & ~P); \ - break; \ - case 0xc7: \ - out = ~(P ^ (S & (D | P))); \ - break; \ - case 0xc8: \ - out = S & (D | P); \ - break; \ - case 0xc9: \ - out = ~(S ^ (P | D)); \ - break; \ - case 0xca: \ - out = D ^ (P & (S ^ D)); \ - break; \ - case 0xcb: \ - out = ~(S ^ (P | (D & S))); \ - break; \ - case 0xcc: \ - out = S; \ - break; \ - case 0xcd: \ - out = S | ~(D | P); \ - break; \ - case 0xce: \ - out = S | (D & ~P); \ - break; \ - case 0xcf: \ - out = S | ~P; \ - break; \ - case 0xd0: \ - out = P & (S | ~D); \ - break; \ - case 0xd1: \ - out = ~(P ^ (S | (D ^ P))); \ - break; \ - case 0xd2: \ - out = P ^ (D & ~S); \ - break; \ - case 0xd3: \ - out = ~(S ^ (P & (D | S))); \ - break; \ - case 0xd4: \ - out = S ^ ((S ^ P) & (P ^ D)); \ - break; \ - case 0xd5: \ - out = ~(D & ~(P & S)); \ - break; \ - case 0xd6: \ - out = P ^ (S ^ (D | (P & S))); \ - break; \ - case 0xd7: \ - out = ~(D & (P ^ S)); \ - break; \ - case 0xd8: \ - out = P ^ (D & (S ^ P)); \ - break; \ - case 0xd9: \ - out = ~(S ^ (D | (P & S))); \ - break; \ - case 0xda: \ - out = D ^ (P & ~(S & D)); \ - break; \ - case 0xdb: \ - out = ~((S ^ P) & (D ^ S)); \ - break; \ - case 0xdc: \ - out = S | (P & ~D); \ - break; \ - case 0xdd: \ - out = S | ~D; \ - break; \ - case 0xde: \ - out = S | (D ^ P); \ - break; \ - case 0xdf: \ - out = S | ~(D & P); \ - break; \ - case 0xe0: \ - out = P & (D | S); \ - break; \ - case 0xe1: \ - out = ~(P ^ (D | S)); \ - break; \ - case 0xe2: \ - out = D ^ (S & (P ^ D)); \ - break; \ - case 0xe3: \ - out = ~(P ^ (S | (D & P))); \ - break; \ - case 0xe4: \ - out = S ^ (D & (P ^ S)); \ - break; \ - case 0xe5: \ - out = ~(P ^ (D | (S & P))); \ - break; \ - case 0xe6: \ - out = S ^ (D & ~(P & S)); \ - break; \ - case 0xe7: \ - out = ~((S ^ P) & (P ^ D)); \ - break; \ - case 0xe8: \ - out = S ^ ((S ^ P) & (D ^ S)); \ - break; \ - case 0xe9: \ - out = ~(D ^ (S ^ (P & ~(D & S)))); \ - break; \ - case 0xea: \ - out = D | (P & S); \ - break; \ - case 0xeb: \ - out = D | ~(P ^ S); \ - break; \ - case 0xec: \ - out = S | (D & P); \ - break; \ - case 0xed: \ - out = S | ~(D ^ P); \ - break; \ - case 0xee: \ - out = D | S; \ - break; \ - case 0xef: \ - out = S | (D | ~P); \ - break; \ - case 0xf0: \ - out = P; \ - break; \ - case 0xf1: \ - out = P | ~(D | S); \ - break; \ - case 0xf2: \ - out = P | (D & ~S); \ - break; \ - case 0xf3: \ - out = P | ~S; \ - break; \ - case 0xf4: \ - out = P | (S & ~D); \ - break; \ - case 0xf5: \ - out = P | ~D; \ - break; \ - case 0xf6: \ - out = P | (D ^ S); \ - break; \ - case 0xf7: \ - out = P | ~(D & S); \ - break; \ - case 0xf8: \ - out = P | (D & S); \ - break; \ - case 0xf9: \ - out = P | ~(D ^ S); \ - break; \ - case 0xfa: \ - out = D | P; \ - break; \ - case 0xfb: \ - out = D | (P | ~S); \ - break; \ - case 0xfc: \ - out = P | S; \ - break; \ - case 0xfd: \ - out = P | (S | ~D); \ - break; \ - case 0xfe: \ - out = D | (P | S); \ - break; \ - case 0xff: \ - out = ~0; \ - break; \ - } \ +void +chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFF; + break; } +} + +void +chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFFFF; + break; + } +} + +void +chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) +{ + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x11: + *dst = ~(*dst) & ~src; + break; + case 0x22: + *dst &= ~src; + break; + case 0x33: + *dst = ~src; + break; + case 0x44: + *dst = src & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x66: + *dst ^= src; + break; + case 0x77: + *dst = ~src | ~(*dst); + break; + case 0x88: + *dst &= src; + break; + case 0x99: + *dst ^= ~src; + break; + case 0xAA: + break; /* No-op. */ + case 0xBB: + *dst |= ~src; + break; + case 0xCC: + *dst = src; + break; + case 0xDD: + *dst = src | ~(*dst); + break; + case 0xEE: + *dst |= src; + break; + case 0xFF: + *dst = 0xFFFFFF; + break; + } +} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - ROPMIX(rop, *dst, pattern, src, *dst); + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_8bpp(dst, src, rop); + } + + switch (rop) { + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + } } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - ROPMIX(rop, *dst, pattern, src, *dst); + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_16bpp(dst, src, rop); + } + + switch (rop) { + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + } } void chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src, uint8_t rop) { uint32_t orig_dst = *dst & 0xFF000000; - ROPMIX(rop, *dst, pattern, src, *dst); + + if ((rop & 0xF) == ((rop >> 4) & 0xF)) { + return chips_69000_do_rop_24bpp(dst, src, rop); + } + + switch (rop) { + default: + pclog("Unknown ROP 0x%X\n", rop); + break; + case 0x00: + *dst = 0; + break; + case 0x05: + *dst = ~(*dst) & ~pattern; + break; + case 0x0A: + *dst &= ~pattern; + break; + case 0x0F: + *dst = ~pattern; + break; + case 0x1A: + *dst = pattern ^ (*dst | (pattern & src)); + break; + case 0x2A: + *dst = *dst & (~(src & pattern)); + break; + case 0x3A: + *dst = src ^ (pattern | (*dst ^ src)); + break; + case 0x4A: + *dst = *dst ^ (pattern & (src | *dst)); + break; + case 0x50: + *dst = pattern & ~(*dst); + break; + case 0x55: + *dst = ~*dst; + break; + case 0x5A: + *dst ^= pattern; + break; + case 0x5F: + *dst = ~pattern | ~(*dst); + break; + case 0x6A: + *dst = *dst ^ (pattern & src); + break; + case 0x7A: + *dst = *dst ^ (pattern & (src | (~*dst))); + break; + case 0x8A: + *dst = *dst & (src | (~pattern)); + break; + case 0x9A: + *dst = *dst ^ (pattern & (~src)); + break; + case 0xB8: + *dst = (((pattern ^ *dst) & src) ^ pattern); + break; + case 0xA0: + *dst &= pattern; + break; + case 0xA5: + *dst ^= ~pattern; + break; + case 0xAA: + break; /* No-op. */ + case 0xAC: + *dst = src ^ (pattern & (*dst ^ src)); + break; + case 0xAF: + *dst |= ~pattern; + break; + case 0xBA: + *dst |= (pattern & ~src); + break; + case 0xCA: + *dst ^= (pattern & (src ^ *dst)); + break; + case 0xDA: + *dst ^= pattern & (~(src & *dst)); + break; + case 0xE2: + *dst ^= (src & (pattern ^ *dst)); + break; + case 0xEA: + *dst |= pattern & src; + break; + case 0xF0: + *dst = pattern; + break; + case 0xF5: + *dst = pattern | ~(*dst); + break; + case 0xFA: + *dst |= pattern; + break; + case 0xFF: + *dst = 0xFF; + break; + } *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -1207,22 +896,20 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - //dest_pixel = chips_69000_readb_linear(dest_addr, chips); - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); break; } case 2: /* 16 bits-per-pixel. */ { - //dest_pixel = *(uint16_t*)&chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; break; } case 3: /* 24 bits-per-pixel. */ { - dest_pixel = chips->svga.vram[dest_addr & chips->svga.vram_mask]; - dest_pixel |= chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] << 8; - dest_pixel |= chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] << 16; + dest_pixel = chips_69000_readb_linear(dest_addr, chips); + dest_pixel |= chips_69000_readb_linear(dest_addr + 1, chips) << 8; + dest_pixel |= chips_69000_readb_linear(dest_addr + 2, chips) << 16; break; } } @@ -1235,7 +922,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) if (chips->bitblt_running.bitblt.bitblt_control & (1 << 19)) pattern_data = 0; else - pattern_data = chips->svga.vram[(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7)) & chips->svga.vram_mask]; //chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); + pattern_data = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + ((vert_pat_alignment + (chips->bitblt_running.y & 7)) & 7), chips); is_true = !!(pattern_data & (1 << (7 - ((chips->bitblt_running.bitblt.destination_addr + chips->bitblt_running.x) & 7)))); @@ -1251,30 +938,32 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) pattern_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; } else { - uint32_t pattern_pixel_addr = 0; if (chips->bitblt_running.bytes_per_pixel == 1) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) - + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7); - - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7) + + (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7), chips); } if (chips->bitblt_running.bytes_per_pixel == 2) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (2 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (2 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; } if (chips->bitblt_running.bytes_per_pixel == 3) { - pattern_pixel_addr = chips->bitblt_running.bitblt.pat_addr - + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) - + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)); + pattern_pixel = chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)), chips); - pattern_pixel = chips->svga.vram[pattern_pixel_addr & chips->svga.vram_mask]; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 1) & chips->svga.vram_mask] << 8; - pattern_pixel |= chips->svga.vram[(pattern_pixel_addr + 2) & chips->svga.vram_mask] << 16; + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 1, chips) << 8; + + pattern_pixel |= chips_69000_readb_linear(chips->bitblt_running.bitblt.pat_addr + + (4 * 8 * ((vert_pat_alignment + chips->bitblt_running.y) & 7)) + + (3 * (((chips->bitblt_running.bitblt.destination_addr & 7) + chips->bitblt_running.x) & 7)) + 2, chips) << 16; } } if (chips->bitblt_running.bytes_per_pixel == 2) { @@ -1292,7 +981,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1330,7 +1019,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1342,21 +1031,20 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - //chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); break; } case 2: /* 16 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); break; } case 3: /* 24 bits-per-pixel. */ { - chips->svga.vram[dest_addr & chips->svga.vram_mask] = dest_pixel & 0xFF; - chips->svga.vram[(dest_addr + 1) & chips->svga.vram_mask] = (dest_pixel >> 8) & 0xFF; - chips->svga.vram[(dest_addr + 2) & chips->svga.vram_mask] = (dest_pixel >> 16) & 0xFF; + chips_69000_writeb_linear(dest_addr, dest_pixel & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 1, (dest_pixel >> 8) & 0xFF, chips); + chips_69000_writeb_linear(dest_addr + 2, (dest_pixel >> 16) & 0xFF, chips); break; } } @@ -1524,8 +1212,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) uint32_t orig_source_addr = chips->bitblt_running.bitblt.source_addr; while (orig_count_y == chips->bitblt_running.count_y) { int i = 0; - //uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); - uint8_t data = chips->svga.vram[orig_source_addr & chips->svga.vram_mask]; + uint8_t data = chips_69000_readb_linear(orig_source_addr, chips); orig_source_addr++; for (i = 0; i < 8; i++) { chips_69000_process_mono_bit(chips, !!(data & (1 << (7 - i)))); @@ -1544,15 +1231,14 @@ chips_69000_setup_bitblt(chips_69000_t* chips) case 1: /* Bit-aligned */ case 2: /* Byte-aligned */ { - //uint32_t data = chips_69000_readb_linear(source_addr, chips); - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask]; + uint32_t data = chips_69000_readb_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); source_addr += 1; break; } case 3: /* Word-aligned*/ { - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8); + uint32_t data = chips_69000_readw_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); source_addr += 2; @@ -1560,8 +1246,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 4: /* Doubleword-aligned*/ { - uint32_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) - | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24); + uint32_t data = chips_69000_readl_linear(source_addr, chips); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1571,15 +1256,7 @@ chips_69000_setup_bitblt(chips_69000_t* chips) } case 5: /* Quadword-aligned*/ { - uint64_t data = chips->svga.vram[source_addr & chips->svga.vram_mask] - | (chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8) - | (chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16) - | (chips->svga.vram[(source_addr + 3) & chips->svga.vram_mask] << 24) - | ((uint64_t)chips->svga.vram[(source_addr + 4) & chips->svga.vram_mask] << 32ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 5) & chips->svga.vram_mask] << 40ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 6) & chips->svga.vram_mask] << 48ULL) - | ((uint64_t)chips->svga.vram[(source_addr + 7) & chips->svga.vram_mask] << 56ULL); - //uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); + uint64_t data = (uint64_t)chips_69000_readl_linear(source_addr, chips) | ((uint64_t)chips_69000_readl_linear(source_addr + 4, chips) << 32ull); chips_69000_bitblt_write(chips, data & 0xFF); chips_69000_bitblt_write(chips, (data >> 8) & 0xFF); chips_69000_bitblt_write(chips, (data >> 16) & 0xFF); @@ -1604,21 +1281,20 @@ chips_69000_setup_bitblt(chips_69000_t* chips) switch (chips->bitblt_running.bytes_per_pixel) { case 1: /* 8 bits-per-pixel. */ { - //pixel = chips_69000_readb_linear(source_addr, chips); - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; + pixel = chips_69000_readb_linear(source_addr, chips); break; } case 2: /* 16 bits-per-pixel. */ { - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; - pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; + pixel = chips_69000_readb_linear(source_addr, chips); + pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; break; } case 3: /* 24 bits-per-pixel. */ { - pixel = chips->svga.vram[source_addr & chips->svga.vram_mask]; - pixel |= chips->svga.vram[(source_addr + 1) & chips->svga.vram_mask] << 8; - pixel |= chips->svga.vram[(source_addr + 2) & chips->svga.vram_mask] << 16; + pixel = chips_69000_readb_linear(source_addr, chips); + pixel |= chips_69000_readb_linear(source_addr + 1, chips) << 8; + pixel |= chips_69000_readb_linear(source_addr + 2, chips) << 16; break; } } From 9182deaa2bf59c8d71b55a9a95ad551f557d9dc5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 17 Mar 2025 23:04:23 +0600 Subject: [PATCH 0500/1190] C&T B69000: Revert optimizations that made GUI acceleration slow --- src/video/vid_chips_69000.c | 1245 ++++++++++++++++++++++------------- 1 file changed, 779 insertions(+), 466 deletions(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 0347435fa..d06ab0484 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -252,378 +252,790 @@ chips_69000_bitblt_interrupt(chips_69000_t* chips) chips_69000_interrupt(chips); } -void -chips_69000_do_rop_8bpp(uint8_t *dst, uint8_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFF; - break; +#define ROPMIX(R, D, P, S, out) \ + { \ + switch (R) { \ + case 0x00: \ + out = 0; \ + break; \ + case 0x01: \ + out = ~(D | (P | S)); \ + break; \ + case 0x02: \ + out = D & ~(P | S); \ + break; \ + case 0x03: \ + out = ~(P | S); \ + break; \ + case 0x04: \ + out = S & ~(D | P); \ + break; \ + case 0x05: \ + out = ~(D | P); \ + break; \ + case 0x06: \ + out = ~(P | ~(D ^ S)); \ + break; \ + case 0x07: \ + out = ~(P | (D & S)); \ + break; \ + case 0x08: \ + out = S & (D & ~P); \ + break; \ + case 0x09: \ + out = ~(P | (D ^ S)); \ + break; \ + case 0x0a: \ + out = D & ~P; \ + break; \ + case 0x0b: \ + out = ~(P | (S & ~D)); \ + break; \ + case 0x0c: \ + out = S & ~P; \ + break; \ + case 0x0d: \ + out = ~(P | (D & ~S)); \ + break; \ + case 0x0e: \ + out = ~(P | ~(D | S)); \ + break; \ + case 0x0f: \ + out = ~P; \ + break; \ + case 0x10: \ + out = P & ~(D | S); \ + break; \ + case 0x11: \ + out = ~(D | S); \ + break; \ + case 0x12: \ + out = ~(S | ~(D ^ P)); \ + break; \ + case 0x13: \ + out = ~(S | (D & P)); \ + break; \ + case 0x14: \ + out = ~(D | ~(P ^ S)); \ + break; \ + case 0x15: \ + out = ~(D | (P & S)); \ + break; \ + case 0x16: \ + out = P ^ (S ^ (D & ~(P & S))); \ + break; \ + case 0x17: \ + out = ~(S ^ ((S ^ P) & (D ^ S))); \ + break; \ + case 0x18: \ + out = (S ^ P) & (P ^ D); \ + break; \ + case 0x19: \ + out = ~(S ^ (D & ~(P & S))); \ + break; \ + case 0x1a: \ + out = P ^ (D | (S & P)); \ + break; \ + case 0x1b: \ + out = ~(S ^ (D & (P ^ S))); \ + break; \ + case 0x1c: \ + out = P ^ (S | (D & P)); \ + break; \ + case 0x1d: \ + out = ~(D ^ (S & (P ^ D))); \ + break; \ + case 0x1e: \ + out = P ^ (D | S); \ + break; \ + case 0x1f: \ + out = ~(P & (D | S)); \ + break; \ + case 0x20: \ + out = D & (P & ~S); \ + break; \ + case 0x21: \ + out = ~(S | (D ^ P)); \ + break; \ + case 0x22: \ + out = D & ~S; \ + break; \ + case 0x23: \ + out = ~(S | (P & ~D)); \ + break; \ + case 0x24: \ + out = (S ^ P) & (D ^ S); \ + break; \ + case 0x25: \ + out = ~(P ^ (D & ~(S & P))); \ + break; \ + case 0x26: \ + out = S ^ (D | (P & S)); \ + break; \ + case 0x27: \ + out = S ^ (D | ~(P ^ S)); \ + break; \ + case 0x28: \ + out = D & (P ^ S); \ + break; \ + case 0x29: \ + out = ~(P ^ (S ^ (D | (P & S)))); \ + break; \ + case 0x2a: \ + out = D & ~(P & S); \ + break; \ + case 0x2b: \ + out = ~(S ^ ((S ^ P) & (P ^ D))); \ + break; \ + case 0x2c: \ + out = S ^ (P & (D | S)); \ + break; \ + case 0x2d: \ + out = P ^ (S | ~D); \ + break; \ + case 0x2e: \ + out = P ^ (S | (D ^ P)); \ + break; \ + case 0x2f: \ + out = ~(P & (S | ~D)); \ + break; \ + case 0x30: \ + out = P & ~S; \ + break; \ + case 0x31: \ + out = ~(S | (D & ~P)); \ + break; \ + case 0x32: \ + out = S ^ (D | (P | S)); \ + break; \ + case 0x33: \ + out = ~S; \ + break; \ + case 0x34: \ + out = S ^ (P | (D & S)); \ + break; \ + case 0x35: \ + out = S ^ (P | ~(D ^ S)); \ + break; \ + case 0x36: \ + out = S ^ (D | P); \ + break; \ + case 0x37: \ + out = ~(S & (D | P)); \ + break; \ + case 0x38: \ + out = P ^ (S & (D | P)); \ + break; \ + case 0x39: \ + out = S ^ (P | ~D); \ + break; \ + case 0x3a: \ + out = S ^ (P | (D ^ S)); \ + break; \ + case 0x3b: \ + out = ~(S & (P | ~D)); \ + break; \ + case 0x3c: \ + out = P ^ S; \ + break; \ + case 0x3d: \ + out = S ^ (P | ~(D | S)); \ + break; \ + case 0x3e: \ + out = S ^ (P | (D & ~S)); \ + break; \ + case 0x3f: \ + out = ~(P & S); \ + break; \ + case 0x40: \ + out = P & (S & ~D); \ + break; \ + case 0x41: \ + out = ~(D | (P ^ S)); \ + break; \ + case 0x42: \ + out = (S ^ D) & (P ^ D); \ + break; \ + case 0x43: \ + out = ~(S ^ (P & ~(D & S))); \ + break; \ + case 0x44: \ + out = S & ~D; \ + break; \ + case 0x45: \ + out = ~(D | (P & ~S)); \ + break; \ + case 0x46: \ + out = D ^ (S | (P & D)); \ + break; \ + case 0x47: \ + out = ~(P ^ (S & (D ^ P))); \ + break; \ + case 0x48: \ + out = S & (D ^ P); \ + break; \ + case 0x49: \ + out = ~(P ^ (D ^ (S | (P & D)))); \ + break; \ + case 0x4a: \ + out = D ^ (P & (S | D)); \ + break; \ + case 0x4b: \ + out = P ^ (D | ~S); \ + break; \ + case 0x4c: \ + out = S & ~(D & P); \ + break; \ + case 0x4d: \ + out = ~(S ^ ((S ^ P) | (D ^ S))); \ + break; \ + case 0x4e: \ + out = P ^ (D | (S ^ P)); \ + break; \ + case 0x4f: \ + out = ~(P & (D | ~S)); \ + break; \ + case 0x50: \ + out = P & ~D; \ + break; \ + case 0x51: \ + out = ~(D | (S & ~P)); \ + break; \ + case 0x52: \ + out = D ^ (P | (S & D)); \ + break; \ + case 0x53: \ + out = ~(S ^ (P & (D ^ S))); \ + break; \ + case 0x54: \ + out = ~(D | ~(P | S)); \ + break; \ + case 0x55: \ + out = ~D; \ + break; \ + case 0x56: \ + out = D ^ (P | S); \ + break; \ + case 0x57: \ + out = ~(D & (P | S)); \ + break; \ + case 0x58: \ + out = P ^ (D & (S | P)); \ + break; \ + case 0x59: \ + out = D ^ (P | ~S); \ + break; \ + case 0x5a: \ + out = D ^ P; \ + break; \ + case 0x5b: \ + out = D ^ (P | ~(S | D)); \ + break; \ + case 0x5c: \ + out = D ^ (P | (S ^ D)); \ + break; \ + case 0x5d: \ + out = ~(D & (P | ~S)); \ + break; \ + case 0x5e: \ + out = D ^ (P | (S & ~D)); \ + break; \ + case 0x5f: \ + out = ~(D & P); \ + break; \ + case 0x60: \ + out = P & (D ^ S); \ + break; \ + case 0x61: \ + out = ~(D ^ (S ^ (P | (D & S)))); \ + break; \ + case 0x62: \ + out = D ^ (S & (P | D)); \ + break; \ + case 0x63: \ + out = S ^ (D | ~P); \ + break; \ + case 0x64: \ + out = S ^ (D & (P | S)); \ + break; \ + case 0x65: \ + out = D ^ (S | ~P); \ + break; \ + case 0x66: \ + out = D ^ S; \ + break; \ + case 0x67: \ + out = S ^ (D | ~(P | S)); \ + break; \ + case 0x68: \ + out = ~(D ^ (S ^ (P | ~(D | S)))); \ + break; \ + case 0x69: \ + out = ~(P ^ (D ^ S)); \ + break; \ + case 0x6a: \ + out = D ^ (P & S); \ + break; \ + case 0x6b: \ + out = ~(P ^ (S ^ (D & (P | S)))); \ + break; \ + case 0x6c: \ + out = S ^ (D & P); \ + break; \ + case 0x6d: \ + out = ~(P ^ (D ^ (S & (P | D)))); \ + break; \ + case 0x6e: \ + out = S ^ (D & (P | ~S)); \ + break; \ + case 0x6f: \ + out = ~(P & ~(D ^ S)); \ + break; \ + case 0x70: \ + out = P & ~(D & S); \ + break; \ + case 0x71: \ + out = ~(S ^ ((S ^ D) & (P ^ D))); \ + break; \ + case 0x72: \ + out = S ^ (D | (P ^ S)); \ + break; \ + case 0x73: \ + out = ~(S & (D | ~P)); \ + break; \ + case 0x74: \ + out = D ^ (S | (P ^ D)); \ + break; \ + case 0x75: \ + out = ~(D & (S | ~P)); \ + break; \ + case 0x76: \ + out = S ^ (D | (P & ~S)); \ + break; \ + case 0x77: \ + out = ~(D & S); \ + break; \ + case 0x78: \ + out = P ^ (D & S); \ + break; \ + case 0x79: \ + out = ~(D ^ (S ^ (P & (D | S)))); \ + break; \ + case 0x7a: \ + out = D ^ (P & (S | ~D)); \ + break; \ + case 0x7b: \ + out = ~(S & ~(D ^ P)); \ + break; \ + case 0x7c: \ + out = S ^ (P & (D | ~S)); \ + break; \ + case 0x7d: \ + out = ~(D & ~(P ^ S)); \ + break; \ + case 0x7e: \ + out = (S ^ P) | (D ^ S); \ + break; \ + case 0x7f: \ + out = ~(D & (P & S)); \ + break; \ + case 0x80: \ + out = D & (P & S); \ + break; \ + case 0x81: \ + out = ~((S ^ P) | (D ^ S)); \ + break; \ + case 0x82: \ + out = D & ~(P ^ S); \ + break; \ + case 0x83: \ + out = ~(S ^ (P & (D | ~S))); \ + break; \ + case 0x84: \ + out = S & ~(D ^ P); \ + break; \ + case 0x85: \ + out = ~(P ^ (D & (S | ~P))); \ + break; \ + case 0x86: \ + out = D ^ (S ^ (P & (D | S))); \ + break; \ + case 0x87: \ + out = ~(P ^ (D & S)); \ + break; \ + case 0x88: \ + out = D & S; \ + break; \ + case 0x89: \ + out = ~(S ^ (D | (P & ~S))); \ + break; \ + case 0x8a: \ + out = D & (S | ~P); \ + break; \ + case 0x8b: \ + out = ~(D ^ (S | (P ^ D))); \ + break; \ + case 0x8c: \ + out = S & (D | ~P); \ + break; \ + case 0x8d: \ + out = ~(S ^ (D | (P ^ S))); \ + break; \ + case 0x8e: \ + out = S ^ ((S ^ D) & (P ^ D)); \ + break; \ + case 0x8f: \ + out = ~(P & ~(D & S)); \ + break; \ + case 0x90: \ + out = P & ~(D ^ S); \ + break; \ + case 0x91: \ + out = ~(S ^ (D & (P | ~S))); \ + break; \ + case 0x92: \ + out = D ^ (P ^ (S & (D | P))); \ + break; \ + case 0x93: \ + out = ~(S ^ (P & D)); \ + break; \ + case 0x94: \ + out = P ^ (S ^ (D & (P | S))); \ + break; \ + case 0x95: \ + out = ~(D ^ (P & S)); \ + break; \ + case 0x96: \ + out = D ^ (P ^ S); \ + break; \ + case 0x97: \ + out = P ^ (S ^ (D | ~(P | S))); \ + break; \ + case 0x98: \ + out = ~(S ^ (D | ~(P | S))); \ + break; \ + case 0x99: \ + out = ~(D ^ S); \ + break; \ + case 0x9a: \ + out = D ^ (P & ~S); \ + break; \ + case 0x9b: \ + out = ~(S ^ (D & (P | S))); \ + break; \ + case 0x9c: \ + out = S ^ (P & ~D); \ + break; \ + case 0x9d: \ + out = ~(D ^ (S & (P | D))); \ + break; \ + case 0x9e: \ + out = D ^ (S ^ (P | (D & S))); \ + break; \ + case 0x9f: \ + out = ~(P & (D ^ S)); \ + break; \ + case 0xa0: \ + out = D & P; \ + break; \ + case 0xa1: \ + out = ~(P ^ (D | (S & ~P))); \ + break; \ + case 0xa2: \ + out = D & (P | ~S); \ + break; \ + case 0xa3: \ + out = ~(D ^ (P | (S ^ D))); \ + break; \ + case 0xa4: \ + out = ~(P ^ (D | ~(S | P))); \ + break; \ + case 0xa5: \ + out = ~(P ^ D); \ + break; \ + case 0xa6: \ + out = D ^ (S & ~P); \ + break; \ + case 0xa7: \ + out = ~(P ^ (D & (S | P))); \ + break; \ + case 0xa8: \ + out = D & (P | S); \ + break; \ + case 0xa9: \ + out = ~(D ^ (P | S)); \ + break; \ + case 0xaa: \ + out = D; \ + break; \ + case 0xab: \ + out = D | ~(P | S); \ + break; \ + case 0xac: \ + out = S ^ (P & (D ^ S)); \ + break; \ + case 0xad: \ + out = ~(D ^ (P | (S & D))); \ + break; \ + case 0xae: \ + out = D | (S & ~P); \ + break; \ + case 0xaf: \ + out = D | ~P; \ + break; \ + case 0xb0: \ + out = P & (D | ~S); \ + break; \ + case 0xb1: \ + out = ~(P ^ (D | (S ^ P))); \ + break; \ + case 0xb2: \ + out = S ^ ((S ^ P) | (D ^ S)); \ + break; \ + case 0xb3: \ + out = ~(S & ~(D & P)); \ + break; \ + case 0xb4: \ + out = P ^ (S & ~D); \ + break; \ + case 0xb5: \ + out = ~(D ^ (P & (S | D))); \ + break; \ + case 0xb6: \ + out = D ^ (P ^ (S | (D & P))); \ + break; \ + case 0xb7: \ + out = ~(S & (D ^ P)); \ + break; \ + case 0xb8: \ + out = P ^ (S & (D ^ P)); \ + break; \ + case 0xb9: \ + out = ~(D ^ (S | (P & D))); \ + break; \ + case 0xba: \ + out = D | (P & ~S); \ + break; \ + case 0xbb: \ + out = D | ~S; \ + break; \ + case 0xbc: \ + out = S ^ (P & ~(D & S)); \ + break; \ + case 0xbd: \ + out = ~((S ^ D) & (P ^ D)); \ + break; \ + case 0xbe: \ + out = D | (P ^ S); \ + break; \ + case 0xbf: \ + out = D | ~(P & S); \ + break; \ + case 0xc0: \ + out = P & S; \ + break; \ + case 0xc1: \ + out = ~(S ^ (P | (D & ~S))); \ + break; \ + case 0xc2: \ + out = ~(S ^ (P | ~(D | S))); \ + break; \ + case 0xc3: \ + out = ~(P ^ S); \ + break; \ + case 0xc4: \ + out = S & (P | ~D); \ + break; \ + case 0xc5: \ + out = ~(S ^ (P | (D ^ S))); \ + break; \ + case 0xc6: \ + out = S ^ (D & ~P); \ + break; \ + case 0xc7: \ + out = ~(P ^ (S & (D | P))); \ + break; \ + case 0xc8: \ + out = S & (D | P); \ + break; \ + case 0xc9: \ + out = ~(S ^ (P | D)); \ + break; \ + case 0xca: \ + out = D ^ (P & (S ^ D)); \ + break; \ + case 0xcb: \ + out = ~(S ^ (P | (D & S))); \ + break; \ + case 0xcc: \ + out = S; \ + break; \ + case 0xcd: \ + out = S | ~(D | P); \ + break; \ + case 0xce: \ + out = S | (D & ~P); \ + break; \ + case 0xcf: \ + out = S | ~P; \ + break; \ + case 0xd0: \ + out = P & (S | ~D); \ + break; \ + case 0xd1: \ + out = ~(P ^ (S | (D ^ P))); \ + break; \ + case 0xd2: \ + out = P ^ (D & ~S); \ + break; \ + case 0xd3: \ + out = ~(S ^ (P & (D | S))); \ + break; \ + case 0xd4: \ + out = S ^ ((S ^ P) & (P ^ D)); \ + break; \ + case 0xd5: \ + out = ~(D & ~(P & S)); \ + break; \ + case 0xd6: \ + out = P ^ (S ^ (D | (P & S))); \ + break; \ + case 0xd7: \ + out = ~(D & (P ^ S)); \ + break; \ + case 0xd8: \ + out = P ^ (D & (S ^ P)); \ + break; \ + case 0xd9: \ + out = ~(S ^ (D | (P & S))); \ + break; \ + case 0xda: \ + out = D ^ (P & ~(S & D)); \ + break; \ + case 0xdb: \ + out = ~((S ^ P) & (D ^ S)); \ + break; \ + case 0xdc: \ + out = S | (P & ~D); \ + break; \ + case 0xdd: \ + out = S | ~D; \ + break; \ + case 0xde: \ + out = S | (D ^ P); \ + break; \ + case 0xdf: \ + out = S | ~(D & P); \ + break; \ + case 0xe0: \ + out = P & (D | S); \ + break; \ + case 0xe1: \ + out = ~(P ^ (D | S)); \ + break; \ + case 0xe2: \ + out = D ^ (S & (P ^ D)); \ + break; \ + case 0xe3: \ + out = ~(P ^ (S | (D & P))); \ + break; \ + case 0xe4: \ + out = S ^ (D & (P ^ S)); \ + break; \ + case 0xe5: \ + out = ~(P ^ (D | (S & P))); \ + break; \ + case 0xe6: \ + out = S ^ (D & ~(P & S)); \ + break; \ + case 0xe7: \ + out = ~((S ^ P) & (P ^ D)); \ + break; \ + case 0xe8: \ + out = S ^ ((S ^ P) & (D ^ S)); \ + break; \ + case 0xe9: \ + out = ~(D ^ (S ^ (P & ~(D & S)))); \ + break; \ + case 0xea: \ + out = D | (P & S); \ + break; \ + case 0xeb: \ + out = D | ~(P ^ S); \ + break; \ + case 0xec: \ + out = S | (D & P); \ + break; \ + case 0xed: \ + out = S | ~(D ^ P); \ + break; \ + case 0xee: \ + out = D | S; \ + break; \ + case 0xef: \ + out = S | (D | ~P); \ + break; \ + case 0xf0: \ + out = P; \ + break; \ + case 0xf1: \ + out = P | ~(D | S); \ + break; \ + case 0xf2: \ + out = P | (D & ~S); \ + break; \ + case 0xf3: \ + out = P | ~S; \ + break; \ + case 0xf4: \ + out = P | (S & ~D); \ + break; \ + case 0xf5: \ + out = P | ~D; \ + break; \ + case 0xf6: \ + out = P | (D ^ S); \ + break; \ + case 0xf7: \ + out = P | ~(D & S); \ + break; \ + case 0xf8: \ + out = P | (D & S); \ + break; \ + case 0xf9: \ + out = P | ~(D ^ S); \ + break; \ + case 0xfa: \ + out = D | P; \ + break; \ + case 0xfb: \ + out = D | (P | ~S); \ + break; \ + case 0xfc: \ + out = P | S; \ + break; \ + case 0xfd: \ + out = P | (S | ~D); \ + break; \ + case 0xfe: \ + out = D | (P | S); \ + break; \ + case 0xff: \ + out = ~0; \ + break; \ + } \ } -} - -void -chips_69000_do_rop_16bpp(uint16_t *dst, uint16_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFF; - break; - } -} - -void -chips_69000_do_rop_24bpp(uint32_t *dst, uint32_t src, uint8_t rop) -{ - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x11: - *dst = ~(*dst) & ~src; - break; - case 0x22: - *dst &= ~src; - break; - case 0x33: - *dst = ~src; - break; - case 0x44: - *dst = src & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x66: - *dst ^= src; - break; - case 0x77: - *dst = ~src | ~(*dst); - break; - case 0x88: - *dst &= src; - break; - case 0x99: - *dst ^= ~src; - break; - case 0xAA: - break; /* No-op. */ - case 0xBB: - *dst |= ~src; - break; - case 0xCC: - *dst = src; - break; - case 0xDD: - *dst = src | ~(*dst); - break; - case 0xEE: - *dst |= src; - break; - case 0xFF: - *dst = 0xFFFFFF; - break; - } -} void chips_69000_do_rop_8bpp_patterned(uint8_t *dst, uint8_t pattern, uint8_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_8bpp(dst, src, rop); - } - - switch (rop) { - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void chips_69000_do_rop_16bpp_patterned(uint16_t *dst, uint16_t pattern, uint16_t src, uint8_t rop) { - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_16bpp(dst, src, rop); - } - - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } + ROPMIX(rop, *dst, pattern, src, *dst); } void @@ -631,107 +1043,8 @@ chips_69000_do_rop_24bpp_patterned(uint32_t *dst, uint32_t pattern, uint32_t src { uint32_t orig_dst = *dst & 0xFF000000; - if ((rop & 0xF) == ((rop >> 4) & 0xF)) { - return chips_69000_do_rop_24bpp(dst, src, rop); - } + ROPMIX(rop, *dst, pattern, src, *dst); - switch (rop) { - default: - pclog("Unknown ROP 0x%X\n", rop); - break; - case 0x00: - *dst = 0; - break; - case 0x05: - *dst = ~(*dst) & ~pattern; - break; - case 0x0A: - *dst &= ~pattern; - break; - case 0x0F: - *dst = ~pattern; - break; - case 0x1A: - *dst = pattern ^ (*dst | (pattern & src)); - break; - case 0x2A: - *dst = *dst & (~(src & pattern)); - break; - case 0x3A: - *dst = src ^ (pattern | (*dst ^ src)); - break; - case 0x4A: - *dst = *dst ^ (pattern & (src | *dst)); - break; - case 0x50: - *dst = pattern & ~(*dst); - break; - case 0x55: - *dst = ~*dst; - break; - case 0x5A: - *dst ^= pattern; - break; - case 0x5F: - *dst = ~pattern | ~(*dst); - break; - case 0x6A: - *dst = *dst ^ (pattern & src); - break; - case 0x7A: - *dst = *dst ^ (pattern & (src | (~*dst))); - break; - case 0x8A: - *dst = *dst & (src | (~pattern)); - break; - case 0x9A: - *dst = *dst ^ (pattern & (~src)); - break; - case 0xB8: - *dst = (((pattern ^ *dst) & src) ^ pattern); - break; - case 0xA0: - *dst &= pattern; - break; - case 0xA5: - *dst ^= ~pattern; - break; - case 0xAA: - break; /* No-op. */ - case 0xAC: - *dst = src ^ (pattern & (*dst ^ src)); - break; - case 0xAF: - *dst |= ~pattern; - break; - case 0xBA: - *dst |= (pattern & ~src); - break; - case 0xCA: - *dst ^= (pattern & (src ^ *dst)); - break; - case 0xDA: - *dst ^= pattern & (~(src & *dst)); - break; - case 0xE2: - *dst ^= (src & (pattern ^ *dst)); - break; - case 0xEA: - *dst |= pattern & src; - break; - case 0xF0: - *dst = pattern; - break; - case 0xF5: - *dst = pattern | ~(*dst); - break; - case 0xFA: - *dst |= pattern; - break; - case 0xFF: - *dst = 0xFF; - break; - } *dst &= 0xFFFFFF; *dst |= orig_dst; } @@ -981,7 +1294,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) : chips->bitblt_running.bitblt.pattern_source_key_bg; color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -1019,7 +1332,7 @@ chips_69000_process_pixel(chips_69000_t* chips, uint32_t pixel) color_key &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; dest_pixel &= (1 << (8 * (chips->bitblt_running.bytes_per_pixel))) - 1; - if (!!(color_key == dest_pixel) == !!(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { + if (!!(color_key == dest_pixel) == !(chips->bitblt_running.bitblt.bitblt_control & (1 << 16))) { return; } @@ -2422,7 +2735,7 @@ chips_69000_getclock(int clock, void *priv) int pl = ((chips->ext_regs[0xcb] >> 4) & 7); float fvco = 14318181.0 * ((float)(m + 2) / (float)(n + 2)); - if (chips->ext_regs[0xcb] & 4) + if (!(chips->ext_regs[0xcb] & 4)) fvco *= 4.0; float fo = fvco / (float)(1 << pl); @@ -2522,7 +2835,7 @@ chips_69000_init(const device_t *info) chips->svga.bpp = 8; chips->svga.miscout = 1; - chips->svga.vblank_start = chips_69000_vblank_start; + chips->svga.vsync_callback = chips_69000_vblank_start; chips->svga.getclock = chips_69000_getclock; chips->svga.conv_16to32 = chips_69000_conv_16to32; chips->svga.line_compare = chips_69000_line_compare; From 556c74c1599e2c279a29cade4d7ef233dd48e0aa Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 20:58:15 +0100 Subject: [PATCH 0501/1190] IDE DMA: Properly handle partial transfers, fixes ATAPI DMA in Windows 98 SE. --- src/disk/hdc_ide.c | 17 ++++++++++------- src/disk/hdc_ide_cmd646.c | 8 ++++---- src/disk/hdc_ide_sff8038i.c | 16 +++++++++++----- src/include/86box/hdc_ide.h | 2 +- src/include/86box/hdc_ide_sff8038i.h | 2 +- src/scsi/scsi_cdrom.c | 4 +++- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index bf0d4d286..01690cd70 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -117,7 +117,7 @@ #define ROM_PATH_MCIDE "roms/hdd/xtide/ide_ps2 R1.1.bin" typedef struct ide_bm_t { - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv); + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv); void (*set_irq)(uint8_t status, void *priv); void *priv; } ide_bm_t; @@ -1094,7 +1094,7 @@ ide_atapi_callback(ide_t *ide) if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, bm->priv); + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 0, bm->priv); /* Underrun. */ if (ret == 1) @@ -1102,6 +1102,7 @@ ide_atapi_callback(ide_t *ide) } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos - ide->sc->block_len, ide->sc->block_len, + ide->sc->sector_len * ide->sc->block_len, 0, bm->priv); if (ret == 1) { @@ -1144,14 +1145,16 @@ ide_atapi_callback(ide_t *ide) if (!IDE_ATAPI_IS_EARLY && !ide_boards[ide->board]->force_ata3 && (bm != NULL) && bm->dma) { if (ide->sc->block_len == 0) { - ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 1, bm->priv); + ret = bm->dma(ide->sc->temp_buffer, ide->sc->packet_len, 0, 1, bm->priv); /* Underrun. */ if (ret == 1) ret = 3; } else { ret = bm->dma(ide->sc->temp_buffer + ide->sc->buffer_pos, - ide->sc->block_len, 1, bm->priv); + ide->sc->block_len, + ide->sc->sector_len * ide->sc->block_len, + 1, bm->priv); if (ret & 1) { if (ide->write != NULL) @@ -2392,7 +2395,7 @@ ide_callback(void *priv) err = UNC_ERR; } else if (!ide_boards[ide->board]->force_ata3 && bm->dma) { /* We should not abort - we should simply wait for the host to start DMA. */ - ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, bm->priv); + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 0, bm->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; @@ -2500,7 +2503,7 @@ ide_callback(void *priv) else ide->sector_pos = 256; - ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 1, bm->priv); + ret = bm->dma(ide->sector_buffer, ide->sector_pos * 512, 0, 1, bm->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ @@ -3127,7 +3130,7 @@ ide_xtide_close(void) void ide_set_bus_master(int board, - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv), + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv), void (*set_irq)(uint8_t status, void *priv), void *priv) { ide_bm_t *bm; diff --git a/src/disk/hdc_ide_cmd646.c b/src/disk/hdc_ide_cmd646.c index b548390fd..a60962ba8 100644 --- a/src/disk/hdc_ide_cmd646.c +++ b/src/disk/hdc_ide_cmd646.c @@ -95,19 +95,19 @@ cmd646_set_irq_1(uint8_t status, void *priv) } static int -cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int out, void *priv) +cmd646_bus_master_dma_0(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { const cmd646_t *dev = (cmd646_t *) priv; - return sff_bus_master_dma(data, transfer_length, out, dev->bm[0]); + return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[0]); } static int -cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int out, void *priv) +cmd646_bus_master_dma_1(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { const cmd646_t *dev = (cmd646_t *) priv; - return sff_bus_master_dma(data, transfer_length, out, dev->bm[1]); + return sff_bus_master_dma(data, transfer_length, total_length, out, dev->bm[1]); } static void diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c index 2cc1fe72e..7ded4372f 100644 --- a/src/disk/hdc_ide_sff8038i.c +++ b/src/disk/hdc_ide_sff8038i.c @@ -316,14 +316,14 @@ sff_bus_master_readl(uint16_t port, void *priv) } int -sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) +sff_bus_master_dma(uint8_t *data, int transfer_length, int total_length, int out, void *priv) { sff8038i_t *dev = (sff8038i_t *) priv; #ifdef ENABLE_SFF_LOG char *sop; #endif - int force_end = 0; + int force_end = 0; int buffer_pos = 0; #ifdef ENABLE_SFF_LOG @@ -365,9 +365,15 @@ sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv) return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ } else { if (!transfer_length && !dev->eot) { - sff_log("Total transfer length smaller than sum of all blocks, full block\n"); - dev->status &= ~2; - return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + if (total_length) { + sff_log("Total transfer length smaller than sum of all blocks, partial transfer\n"); + sff_bus_master_next_addr(dev); + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else { + sff_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } } else if (transfer_length && dev->eot) { sff_log("Total transfer length greater than sum of all blocks\n"); dev->status |= 2; diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 4e4ea4e5b..41fb7703e 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -201,7 +201,7 @@ extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); extern uint16_t ide_readw(uint16_t addr, void *priv); extern void ide_set_bus_master(int board, - int (*dma)(uint8_t *data, int transfer_length, int out, void *priv), + int (*dma)(uint8_t *data, int transfer_length, int total_length, int out, void *priv), void (*set_irq)(uint8_t status, void *priv), void *priv); extern void win_cdrom_eject(uint8_t id); diff --git a/src/include/86box/hdc_ide_sff8038i.h b/src/include/86box/hdc_ide_sff8038i.h index 3a69fdfac..79075b8b2 100644 --- a/src/include/86box/hdc_ide_sff8038i.h +++ b/src/include/86box/hdc_ide_sff8038i.h @@ -63,7 +63,7 @@ extern const device_t sff8038i_device; extern void sff_bus_master_handler(sff8038i_t *dev, int enabled, uint16_t base); extern void sff_bus_master_set_irq(uint8_t status, void *priv); -extern int sff_bus_master_dma(uint8_t *data, int transfer_length, int out, void *priv); +extern int sff_bus_master_dma(uint8_t *data, int transfer_length, int total_length, int out, void *priv); extern void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); extern uint8_t sff_bus_master_read(uint16_t port, void *priv); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 292c54127..a8bb1513b 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1096,6 +1096,8 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; + int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? + dev->requested_blocks : 1; switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: @@ -1128,7 +1130,7 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) } scsi_cdrom_log(dev->log, "Reading %i blocks starting from %i...\n", - dev->requested_blocks, dev->sector_pos); + num, dev->sector_pos); ret = scsi_cdrom_read_data(dev, msf, type, flags, dev->vendor_type); From 48c294a13bdd59abadd7f3271e49601c5a2ce39a Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 20:59:18 +0100 Subject: [PATCH 0502/1190] SCSI CD-ROM: Fix a warning. --- src/scsi/scsi_cdrom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index a8bb1513b..b35662eeb 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1096,8 +1096,10 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) int msf = 0; int type = dev->sector_type; int flags = dev->sector_flags; +#ifdef ENABLE_SCSI_CDROM_LOG int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? dev->requested_blocks : 1; +#endif switch (dev->current_cdb[0]) { case GPCMD_READ_CD_MSF_OLD: From be2a435e0510e939056a4334dfe5293d336f3cae Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 00:43:49 +0100 Subject: [PATCH 0503/1190] MO and ZIP: Fix reading, writing, and formatting, also fix > 2 GB MO images. --- src/disk/mo.c | 34 +++++++++++++++++++--------------- src/disk/zip.c | 17 +++++++++-------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index 7808e524e..b470b7761 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -63,7 +63,7 @@ const uint8_t mo_command_flags[0x100] = { [0x0a] = IMPLEMENTED | CHECK_READY, [0x0b] = IMPLEMENTED | CHECK_READY, [0x12] = IMPLEMENTED | ALLOW_UA, - [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x13] = IMPLEMENTED | CHECK_READY, [0x15] = IMPLEMENTED, [0x16] = IMPLEMENTED | SCSI_ONLY, [0x17] = IMPLEMENTED | SCSI_ONLY, @@ -74,8 +74,7 @@ const uint8_t mo_command_flags[0x100] = { [0x25] = IMPLEMENTED | CHECK_READY, [0x28] = IMPLEMENTED | CHECK_READY, [0x2a ... 0x2c] = IMPLEMENTED | CHECK_READY, - [0x2e] = IMPLEMENTED | CHECK_READY, - [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x2e ... 0x2f] = IMPLEMENTED | CHECK_READY, [0x41] = IMPLEMENTED | CHECK_READY, [0x55] = IMPLEMENTED, [0x5a] = IMPLEMENTED, @@ -172,9 +171,9 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } if (ret) { - fseek(dev->drv->fp, 0, SEEK_END); + fseeko64(dev->drv->fp, 0, SEEK_END); - uint32_t size = (uint32_t) ftell(dev->drv->fp); + uint64_t size = (uint64_t) ftello64(dev->drv->fp); unsigned int found = 0; if (is_mdi) { @@ -185,7 +184,7 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) dev->drv->base = 0; for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { - if (size == (mo_types[i].sectors * mo_types[i].bytes_per_sector)) { + if (size == ((uint64_t) mo_types[i].sectors * mo_types[i].bytes_per_sector)) { found = 1; dev->drv->medium_size = mo_types[i].sectors; dev->drv->sector_size = mo_types[i].bytes_per_sector; @@ -194,7 +193,7 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } if (found) { - if (fseek(dev->drv->fp, dev->drv->base, SEEK_SET) == -1) + if (fseeko64(dev->drv->fp, (uint64_t) dev->drv->base, SEEK_SET) == -1) log_fatal(dev->log, "mo_load(): Error seeking to the beginning of " "the file\n"); @@ -799,21 +798,21 @@ mo_blocks(mo_t *dev, int32_t *len, int out) *len = 0; - if (!dev->sector_len) - mo_command_complete(dev); - else { + if (dev->sector_len == 0) { mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); mo_lba_out_of_range(dev); + ret = 0; } else { *len = dev->requested_blocks * dev->drv->sector_size; ret = 1; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size) + (i * dev->drv->sector_size), SEEK_SET) == -1) { + if (fseeko64(dev->drv->fp, dev->drv->base + + ((uint64_t) dev->sector_pos * dev->drv->sector_size), SEEK_SET) == -1) { if (out) mo_write_error(dev); else @@ -854,6 +853,9 @@ mo_blocks(mo_t *dev, int32_t *len, int out) dev->sector_len -= dev->requested_blocks; } } + } else { + mo_command_complete(dev); + ret = 0; } return ret; @@ -888,7 +890,7 @@ mo_format(mo_t *dev) mo_log(dev->log, "Formatting media...\n"); - fseek(dev->drv->fp, 0, SEEK_END); + fseeko64(dev->drv->fp, 0, SEEK_END); long size = ftell(dev->drv->fp); #ifdef _WIN32 @@ -962,8 +964,9 @@ mo_erase(mo_t *dev) mo_buf_alloc(dev, dev->drv->sector_size); memset(dev->buffer, 0, dev->drv->sector_size); - fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos * dev->drv->sector_size), - SEEK_SET); + fseeko64(dev->drv->fp, dev->drv->base + + ((uint64_t) dev->sector_pos * dev->drv->sector_size), + SEEK_SET); for (i = 0; i < dev->requested_blocks; i++) { if (feof(dev->drv->fp)) @@ -1878,7 +1881,8 @@ mo_phase_data_out(scsi_common_t *sc) dev->buffer[6] = (s >> 8) & 0xff; dev->buffer[7] = s & 0xff; } - if (fseek(dev->drv->fp, (i * dev->drv->sector_size), SEEK_SET) == -1) + if (fseeko64(dev->drv->fp, + ((uint64_t) i * dev->drv->sector_size), SEEK_SET) == -1) mo_write_error(dev); if (feof(dev->drv->fp)) break; diff --git a/src/disk/zip.c b/src/disk/zip.c index f579f23ec..ae3319b40 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -53,7 +53,7 @@ const uint8_t zip_command_flags[0x100] = { [0x0c] = IMPLEMENTED, [0x0d] = IMPLEMENTED | ATAPI_ONLY, [0x12] = IMPLEMENTED | ALLOW_UA, - [0x13] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x13] = IMPLEMENTED | CHECK_READY, [0x15] = IMPLEMENTED, [0x16 ... 0x17] = IMPLEMENTED | SCSI_ONLY, [0x1a] = IMPLEMENTED, @@ -64,8 +64,7 @@ const uint8_t zip_command_flags[0x100] = { [0x25] = IMPLEMENTED | CHECK_READY, [0x28] = IMPLEMENTED | CHECK_READY, [0x2a ... 0x2b] = IMPLEMENTED | CHECK_READY, - [0x2e] = IMPLEMENTED | CHECK_READY, - [0x2f] = IMPLEMENTED | CHECK_READY | SCSI_ONLY, + [0x2e ... 0x2f] = IMPLEMENTED | CHECK_READY, [0x41] = IMPLEMENTED | CHECK_READY, [0x55] = IMPLEMENTED, [0x5a] = IMPLEMENTED, @@ -898,9 +897,7 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) int ret = 1; *len = 0; - if (!dev->sector_len) - zip_command_complete(dev); - else { + if (dev->sector_len > 0) { zip_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); @@ -908,12 +905,13 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) zip_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); zip_lba_out_of_range(dev); + ret = 0; } else { *len = dev->requested_blocks << 9; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9) + - (i << 9), SEEK_SET) == -1) { + if (fseek(dev->drv->fp, dev->drv->base + (dev->sector_pos << 9), + SEEK_SET) == -1) { if (out) zip_write_error(dev); else @@ -952,6 +950,9 @@ zip_blocks(zip_t *dev, int32_t *len, const int out) dev->sector_len -= dev->requested_blocks; } } + } else { + zip_command_complete(dev); + ret = 0; } return ret; From 6f8594f2b22504027d4471e146d296d7a32944f2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 01:38:59 +0100 Subject: [PATCH 0504/1190] MO: A few bug fixes. --- src/disk/mo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index b470b7761..3165a805e 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -798,7 +798,7 @@ mo_blocks(mo_t *dev, int32_t *len, int out) *len = 0; - if (dev->sector_len == 0) { + if (dev->sector_len > 0) { mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); @@ -891,7 +891,7 @@ mo_format(mo_t *dev) mo_log(dev->log, "Formatting media...\n"); fseeko64(dev->drv->fp, 0, SEEK_END); - long size = ftell(dev->drv->fp); + int64_t size = ftello64(dev->drv->fp); #ifdef _WIN32 LARGE_INTEGER liSize; From 1a6f84d455287b56232c3b7a0366616f531a3648 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:00:56 +0100 Subject: [PATCH 0505/1190] MO: More bug fixes. --- src/disk/mo.c | 56 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index 3165a805e..e2db4bda3 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -17,6 +17,7 @@ * Copyright 2020-2025 Miran Grca. * Copyright 2020-2025 Fred N. van Kempen */ +#define _GNU_SOURCE #ifdef ENABLE_MO_LOG #include #endif @@ -432,7 +433,8 @@ mo_update_request_length(mo_t *dev, int len, int block_len) case 0xa8: case 0xaa: /* Round it to the nearest 2048 bytes. */ - dev->max_transfer_len = (dev->max_transfer_len >> 9) << 9; + dev->max_transfer_len = (dev->max_transfer_len / dev->drv->sector_size) * + dev->drv->sector_size; /* Make sure total length is not bigger than sum of the lengths of @@ -792,10 +794,9 @@ mo_invalid_field_pl(mo_t *dev, const uint32_t field) } static int -mo_blocks(mo_t *dev, int32_t *len, int out) +mo_blocks(mo_t *dev, int32_t *len, const int out) { - int ret = 0; - + int ret = 1; *len = 0; if (dev->sector_len > 0) { @@ -803,41 +804,39 @@ mo_blocks(mo_t *dev, int32_t *len, int out) dev->requested_blocks, dev->sector_pos); if (dev->sector_pos >= dev->drv->medium_size) { - mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); + mo_log(dev->log, "Trying to %s beyond the end of disk\n", + out ? "write" : "read"); mo_lba_out_of_range(dev); - ret = 0; + ret = 0; } else { - *len = dev->requested_blocks * dev->drv->sector_size; - ret = 1; + *len = dev->requested_blocks * dev->drv->sector_size; for (int i = 0; i < dev->requested_blocks; i++) { - if (fseeko64(dev->drv->fp, dev->drv->base + - ((uint64_t) dev->sector_pos * dev->drv->sector_size), SEEK_SET) == -1) { + if (fseeko64(dev->drv->fp, (uint64_t) dev->drv->base + + (uint64_t) (dev->sector_pos * dev->drv->sector_size), + SEEK_SET) == -1) { if (out) mo_write_error(dev); else mo_read_error(dev); - ret = -1; } else { - if (!feof(dev->drv->fp)) + if (feof(dev->drv->fp)) break; if (out) { if (fwrite(dev->buffer + (i * dev->drv->sector_size), 1, - dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { mo_log(dev->log, "mo_blocks(): Error writing data\n"); mo_write_error(dev); ret = -1; } else fflush(dev->drv->fp); - } else { - if (fread(dev->buffer + (i * dev->drv->sector_size), 1, - dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { - mo_log(dev->log, "mo_blocks(): Error reading data\n"); - mo_read_error(dev); - ret = -1; - } + } else if (fread(dev->buffer + (i * dev->drv->sector_size), 1, + dev->drv->sector_size, dev->drv->fp) != dev->drv->sector_size) { + mo_log(dev->log, "mo_blocks(): Error reading data\n"); + mo_read_error(dev); + ret = -1; } } @@ -848,7 +847,8 @@ mo_blocks(mo_t *dev, int32_t *len, int out) } if (ret == 1) { - mo_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + mo_log(dev->log, "%s %i bytes of blocks...\n", out ? "Written" : + "Read", *len); dev->sector_len -= dev->requested_blocks; } @@ -1394,7 +1394,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_WRITE_12: case GPCMD_WRITE_AND_VERIFY_12: mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - alloc_length = 512; + alloc_length = dev->drv->sector_size; switch (cdb[0]) { case GPCMD_VERIFY_6: @@ -1444,11 +1444,11 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); dev->requested_blocks = max_len; - dev->packet_len = max_len << 9; + dev->packet_len = max_len * dev->drv->sector_size; mo_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - mo_data_command_finish(dev, dev->packet_len, 512, + mo_data_command_finish(dev, dev->packet_len, dev->drv->sector_size, dev->packet_len, 1); ui_sb_update_icon(SB_MO | dev->id, @@ -1465,7 +1465,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) case GPCMD_WRITE_SAME_10: mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - alloc_length = 512; + alloc_length = dev->drv->sector_size; if ((cdb[1] & 6) == 6) mo_invalid_field(dev, cdb[1]); @@ -1484,7 +1484,8 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_set_phase(dev, SCSI_PHASE_DATA_OUT); - mo_data_command_finish(dev, 512, 512, + mo_data_command_finish(dev, dev->drv->sector_size, + dev->drv->sector_size, alloc_length, 1); ui_sb_update_icon(SB_MO | dev->id, @@ -1916,6 +1917,9 @@ mo_phase_data_out(scsi_common_t *sc) block_desc_len = 0; pos = hdr_len + block_desc_len; + mo_log(dev->log, "Block descriptor: %08X %08X %08X %08X %08X %08X %08X %08X\n", + dev->buffer[hdr_len], dev->buffer[hdr_len + 1], dev->buffer[hdr_len + 2], dev->buffer[hdr_len + 3], + dev->buffer[hdr_len + 4], dev->buffer[hdr_len + 5], dev->buffer[hdr_len + 6], dev->buffer[hdr_len + 7]); while (1) { if (pos >= param_list_len) { From 39f65003dc999c2716bc9cfddde3b760b8d42ae6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:32:47 +0100 Subject: [PATCH 0506/1190] Acer 100T: Do not add a separate internal FDC because one is already provided by the Super I/O chip, fixes #5250. --- src/machine/m_at_286_386sx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 9086f7c8a..fd9cc3bcd 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -750,9 +750,6 @@ machine_at_acer100t_init(const machine_t *model) machine_at_ps2_ide_init(model); - if (fdc_current[0] == FDC_INTERNAL) - device_add(&fdc_at_device); - device_add(&ali1409_device); if (gfxcard[0] == VID_INTERNAL) device_add(&oti077_acer100t_device); From 8eb084d397aa8033494e69f4fcf18605fd64ae2f Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 03:34:49 +0100 Subject: [PATCH 0507/1190] XT KBC: Fix switches for 192k RAM, fixes #5262. --- src/device/keyboard_xt.c | 64 ++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index ddbcae61b..3c616a2ab 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -84,6 +84,7 @@ typedef struct xtkbd_t { uint8_t key_waiting; uint8_t type; uint8_t pravetz_flags; + uint8_t cpu_speed; pc_timer_t send_delay_timer; } xtkbd_t; @@ -799,6 +800,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd_adddata(0xaa); } } + kbd->pb = val; if (!(kbd->pb & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI)) kbd->clock = !!(kbd->pb & 0x40); @@ -846,6 +848,14 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } break; + case 0x1f0: + kbd_log("XTkbd: Port %04X out: %02X\n", port, val); + if (kbd->type == KBD_TYPE_VTECH) { + kbd->cpu_speed = val; + cpu_dynamic_switch(kbd->cpu_speed >> 7); + } + break; + default: break; } @@ -863,12 +873,14 @@ kbd_read(uint16_t port, void *priv) (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || - (kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI))) { + (kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH))) { if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_HYUNDAI)) ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00); - else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86)) + else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || + (kbd->type == KBD_TYPE_VTECH)) /* According to Ruud on the PCem forum, this is supposed to return 0xFF on the XT. */ ret = 0xff; @@ -926,16 +938,8 @@ kbd_read(uint16_t port, void *priv) } else { if (kbd->pb & 0x08) /* PB3 */ ret = kbd->pd >> 4; - else { - /* LaserXT = Always 512k RAM; - LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ -#ifdef USE_LASERXT - if (kbd->type == KBD_TYPE_VTECH) - ret = ((mem_size == 512) ? 0x0d : 0x0c) | (hasfpu ? 0x02 : 0x00); - else -#endif /* USE_LASERXT */ - ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); - } + else + ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); } ret |= (ppispeakon ? 0x20 : 0); @@ -956,7 +960,8 @@ kbd_read(uint16_t port, void *priv) case 0x63: /* Keyboard Configuration Register (aka Port D) */ if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || - (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI)) + (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH)) ret = kbd->pd; break; @@ -966,6 +971,12 @@ kbd_read(uint16_t port, void *priv) kbd_log("XTkbd: Port %02X in : %02X\n", port, ret); break; + case 0x1f0: + if (kbd->type == KBD_TYPE_VTECH) + ret = kbd->cpu_speed; + kbd_log("XTkbd: Port %04X in : %02X\n", port, ret); + break; + default: break; } @@ -984,7 +995,7 @@ kbd_reset(void *priv) kbd->pb = 0x00; kbd->pravetz_flags = 0x00; - keyboard_scan = 1; + keyboard_scan = 1; key_queue_start = 0; key_queue_end = 0; @@ -1006,12 +1017,16 @@ kbd_init(const device_t *info) io_sethandler(0x0060, 4, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); keyboard_send = kbd_adddata_ex; - kbd_reset(kbd); kbd->type = info->local; - if (kbd->type == KBD_TYPE_PRAVETZ) { + if (kbd->type == KBD_TYPE_VTECH) + kbd->cpu_speed = (!!cpu) << 2; + kbd_reset(kbd); + if (kbd->type == KBD_TYPE_PRAVETZ) io_sethandler(0x00c0, 16, kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); - } + if (kbd->type == KBD_TYPE_VTECH) + io_sethandler(0x01f0, 1, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); key_queue_start = key_queue_end = 0; @@ -1021,7 +1036,8 @@ kbd_init(const device_t *info) (kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) || (kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) || - (kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI)) { + (kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI) || + (kbd->type == KBD_TYPE_VTECH)) { /* DIP switch readout: bit set = OFF, clear = ON. */ if (kbd->type == KBD_TYPE_OLIVETTI) /* Olivetti M19 @@ -1035,7 +1051,7 @@ kbd_init(const device_t *info) /* Switches 7, 8 - floppy drives. */ kbd->pd = get_fdd_switch_settings(); - /* Siitches 5, 6 - video card type */ + /* Switches 5, 6 - video card type */ kbd->pd |= get_videomode_switch_settings(); /* Switches 3, 4 - memory size. */ @@ -1057,7 +1073,7 @@ kbd_init(const device_t *info) kbd->pd |= 0x0c; break; } - } else if (kbd->type == KBD_TYPE_XT82) { + } else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_VTECH)) { switch (mem_size) { case 64: /* 1x64k */ kbd->pd |= 0x00; @@ -1075,9 +1091,13 @@ kbd_init(const device_t *info) } } else if (kbd->type == KBD_TYPE_PC82) { switch (mem_size) { +#ifdef PC82_192K_3BANK case 192: /* 3x64k, not supported by stock BIOS due to bugs */ kbd->pd |= 0x08; break; +#else + case 192: /* 2x64k + 2x32k */ +#endif case 64: /* 4x16k */ case 96: /* 2x32k + 2x16k */ case 128: /* 4x32k */ @@ -1294,8 +1314,8 @@ const device_t keyboard_xt_t1x00_device = { #ifdef USE_LASERXT const device_t keyboard_xt_lxt3_device = { - .name = "VTech Laser XT3 Keyboard", - .internal_name = "keyboard_xt_lxt3", + .name = "VTech Laser Turbo XT Keyboard", + .internal_name = "keyboard_xt_lxt", .flags = 0, .local = KBD_TYPE_VTECH, .init = kbd_init, From 25bcd434a0936f96875126758f510c84bc53a541 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 18 Mar 2025 13:06:14 +0600 Subject: [PATCH 0508/1190] Qt: Add special handling for real touchscreen devices --- src/qt/qt_renderercommon.cpp | 4 +++ src/qt/qt_rendererstack.cpp | 65 ++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp index 178134c9d..2a20ff63c 100644 --- a/src/qt/qt_renderercommon.cpp +++ b/src/qt/qt_renderercommon.cpp @@ -144,6 +144,10 @@ RendererCommon::eventDelegate(QEvent *event, bool &result) case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: + case QEvent::TouchBegin: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + case QEvent::TouchUpdate: case QEvent::Wheel: case QEvent::Enter: case QEvent::Leave: diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 2b1cfdf26..8c0792be4 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -38,6 +38,7 @@ #include #include +#include #ifdef __APPLE__ # include @@ -63,6 +64,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) { + setAttribute(Qt::WA_AcceptTouchEvents, true); rendererTakesScreenshots = false; #ifdef Q_OS_WINDOWS int raw = 1; @@ -477,8 +479,8 @@ RendererStack::event(QEvent* event) if (m_monitor_index >= 1) { if (mouse_input_mode >= 1) { - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); if (!mouse_tablet_in_proximity) mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; } @@ -487,15 +489,66 @@ RendererStack::event(QEvent* event) #ifdef Q_OS_WINDOWS if (mouse_input_mode == 0) { - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); return QStackedWidget::event(event); } #endif - mouse_x_abs = (mouse_event->localPos().x()) / (long double)width(); - mouse_y_abs = (mouse_event->localPos().y()) / (long double)height(); + mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); + mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; + } else switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->touchPoints().count()) { + mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); + mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); + touchevent->accept(); + return true; +#else + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->pointCount()) { + mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); + mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); + touchevent->accept(); + return true; +#endif + } + case QEvent::TouchEnd: + case QEvent::TouchCancel: + { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->touchPoints().count()) { + mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); + mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); + touchevent->accept(); + return true; +#else + QTouchEvent* touchevent = (QTouchEvent*)event; + if (mouse_input_mode == 0) break; + if (touchevent->pointCount()) { + mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); + mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + } + mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); + touchevent->accept(); + return true; +#endif + } } return QStackedWidget::event(event); From 96644d137f785cec857b9a1c217dae65d563d50b Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:57:14 +0300 Subject: [PATCH 0509/1190] Add the Soyo SY-7SBB (SiS 600, Socket 370) --- src/include/86box/machine.h | 1 + src/machine/m_at_socket370.c | 28 ++++++++++++++++++++++++ src/machine/machine_table.c | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index b2e4c01f2..d1257d94c 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -855,6 +855,7 @@ extern int machine_at_s1857_init(const machine_t *); extern int machine_at_p6bap_init(const machine_t *); extern int machine_at_p6bat_init(const machine_t *); extern int machine_at_prosignias31x_bx_init(const machine_t *); +extern int machine_at_7sbb_init(const machine_t *); /* m_at_misc.c */ extern int machine_at_vpc2007_init(const machine_t *); diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 9be2d45b8..b2e311166 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -541,3 +541,31 @@ machine_at_6via90ap_init(const machine_t *model) return ret; } + +int +machine_at_7sbb_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/7sbb/sbb12aa2.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x02, PCI_CARD_AGPBRIDGE, 0, 0, 0, 0); + device_add(&sis_5600_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&it8661f_device); + device_add(&sst_flash_29ee020_device); /* assumed */ + + return ret; +} \ No newline at end of file diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3706126a3..bae9de29f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16227,6 +16227,48 @@ const machine_t machines[] = { .snd_device = &cmi8738_onboard_device, .net_device = NULL }, + /* SiS (5)600 */ + /* Has the SiS 600 chipset, which is a re-brand of the 5600, with + on-chip KBC. */ + { + .name = "[SiS 600] Soyo SY-7SBB", + .internal_name = "7sbb", + .type = MACHINE_TYPE_SOCKET370, + .chipset = MACHINE_CHIPSET_SIS_5600, + .init = machine_at_7sbb_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET370, + .block = CPU_BLOCK(CPU_CYRIX3S), + .min_bus = 60000000, + .max_bus = 100000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 1572864, + .step = 1024 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Miscellaneous/Fake/Hypervisor machines */ /* Has a Winbond W83977F Super I/O chip with on-chip KBC with AMIKey-2 KBC From aaaa96f785ca2ecdfa9b76561e074b6ea4815323 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 18:20:49 +0100 Subject: [PATCH 0510/1190] QT render stack: add a missing default entry. Also committing the missing MO image creation fixes. --- src/qt/qt_newfloppydialog.cpp | 18 +++++++++--------- src/qt/qt_rendererstack.cpp | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_newfloppydialog.cpp b/src/qt/qt_newfloppydialog.cpp index 48be09777..58a7a3df2 100644 --- a/src/qt/qt_newfloppydialog.cpp +++ b/src/qt/qt_newfloppydialog.cpp @@ -367,7 +367,7 @@ NewFloppyDialog::create86f(const QString &filename, const disk_size_t &disk_size bool NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &disk_size, FileType type) { - uint32_t total_size = 0; + uint64_t total_size = 0; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint32_t root_dir_bytes = 0; @@ -388,7 +388,7 @@ NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &d total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; if (total_sectors > ZIP_SECTORS) total_sectors = ZIP_250_SECTORS; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; root_dir_bytes = (disk_size.root_dir_entries << 5); fat_size = (disk_size.spfat * sector_bytes); fat1_offs = sector_bytes; @@ -465,11 +465,11 @@ NewFloppyDialog::createSectorImage(const QString &filename, const disk_size_t &d bool NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t &disk_size, FileType type, QProgressDialog &pbar) { - uint32_t total_size = 0; + uint64_t total_size = 0; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint16_t base = 0x1000; - uint32_t pbar_max = 0; + uint64_t pbar_max = 0; QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { @@ -482,7 +482,7 @@ NewFloppyDialog::createZipSectorImage(const QString &filename, const disk_size_t total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; if (total_sectors > ZIP_SECTORS) total_sectors = ZIP_250_SECTORS; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; pbar_max = total_size; if (type == FileType::Zdi) { @@ -649,12 +649,12 @@ bool NewFloppyDialog::createMoSectorImage(const QString &filename, int8_t disk_size, FileType type, QProgressDialog &pbar) { const mo_type_t *dp = &mo_types[disk_size]; - uint32_t total_size = 0; - uint32_t total_size2; + uint64_t total_size = 0; + uint64_t total_size2; uint32_t total_sectors = 0; uint32_t sector_bytes = 0; uint16_t base = 0x1000; - uint32_t pbar_max = 0; + uint64_t pbar_max = 0; uint32_t blocks_num; QFile file(filename); @@ -666,7 +666,7 @@ NewFloppyDialog::createMoSectorImage(const QString &filename, int8_t disk_size, sector_bytes = dp->bytes_per_sector; total_sectors = dp->sectors; - total_size = total_sectors * sector_bytes; + total_size = (uint64_t) total_sectors * sector_bytes; total_size2 = (total_size >> 20) << 20; total_size2 = total_size - total_size2; diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 8c0792be4..3e81a52c2 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -549,6 +549,9 @@ RendererStack::event(QEvent* event) return true; #endif } + + default: + return QStackedWidget::event(event); } return QStackedWidget::event(event); From 70dcdee72bbedc8fe138edaf4321e7145c22f2f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 19:21:00 +0100 Subject: [PATCH 0511/1190] Some Cyrix MII table/ID fixes and added some Cyrix CPU blocking for the NuPRO 592 and the P5MMS98. --- src/cpu/cpu.c | 8 ++++ src/cpu/cpu_table.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index b821bc657..0c621bf68 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -384,6 +384,14 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) if (cpu_override) return 1; + /* Cyrix 6x86MX on the NuPRO 592. */ + if (((cpu_s->cyrix_id & 0xff00) == 0x0400) && (strstr(machine_s->internal_name, "nupro") != NULL)) + return 0; + + /* Cyrix 6x86MX or MII on the P5MMS98. */ + if ((cpu_s->cpu_type == CPU_Cx6x86MX) && (strstr(machine_s->internal_name, "p5mms98") != NULL)) + return 0; + /* Check CPU blocklist. */ if (machine_s->cpu.block) { i = 0; diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 5a156853e..e5c91b1a8 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -6366,6 +6366,74 @@ const cpu_family_t cpu_families[] = { .name = "MII", .internal_name = "mii", .cpus = (const CPU[]) { + { + .name = "IBM 133 (PR166)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 133333333, + .multi = 2.0, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0851, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 12, + .mem_write_cycles = 12, + .cache_read_cycles = 6, + .cache_write_cycles = 6, + .atclk_div = 16 + }, + { + .name = "166 (PR200)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 166666666, + .multi = 2.5, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 15, + .mem_write_cycles = 15, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 20 + }, + { + .name = "187.5 (PR233)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 187500000, + .multi = 2.5, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 15, + .mem_write_cycles = 15, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 45/2 + }, + { + .name = "208.3 (PR266)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 208333333, + .multi = 2.5, + .voltage = 2700, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0852, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 17, + .mem_write_cycles = 17, + .cache_read_cycles = 7, + .cache_write_cycles = 7, + .atclk_div = 25 + }, { .name = "233 (PR300)", .cpu_type = CPU_Cx6x86MX, @@ -6375,7 +6443,7 @@ const cpu_family_t cpu_families[] = { .voltage = 2900, .edx_reset = 0x601, .cpuid_model = 0x601, - .cyrix_id = 0x0852, + .cyrix_id = 0x0854, .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, .mem_read_cycles = 21, .mem_write_cycles = 21, @@ -6409,7 +6477,7 @@ const cpu_family_t cpu_families[] = { .voltage = 2900, .edx_reset = 0x601, .cpuid_model = 0x601, - .cyrix_id = 0x0853, + .cyrix_id = 0x0852, .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, .mem_read_cycles = 23, .mem_write_cycles = 23, @@ -6417,6 +6485,23 @@ const cpu_family_t cpu_families[] = { .cache_write_cycles = 7, .atclk_div = 30 }, + { + .name = "270 (PR350)", + .cpu_type = CPU_Cx6x86MX, + .fpus = fpus_internal, + .rspeed = 270000000, + .multi = 3.0, + .voltage = 2900, + .edx_reset = 0x601, + .cpuid_model = 0x601, + .cyrix_id = 0x0853, + .cpu_flags = CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, + .mem_read_cycles = 25, + .mem_write_cycles = 25, + .cache_read_cycles = 8, + .cache_write_cycles = 8, + .atclk_div = 32 + }, { .name = "285 (PR400)", .cpu_type = CPU_Cx6x86MX, From 66b99cc2ff27dd9a9d962d4dc7ae1ad9a95efe09 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 22:49:03 +0100 Subject: [PATCH 0512/1190] QT render stack: ignore the wheel event on Windows and Apple. --- src/qt/qt_rendererstack.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 3e81a52c2..5b464f6a5 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -203,6 +203,9 @@ RendererStack::mousePressEvent(QMouseEvent *event) void RendererStack::wheelEvent(QWheelEvent *event) { +#if defined(Q_OS_WINDOWS) || defined(__APPLE__) + event->ignore(); +#else if (!mouse_capture) { event->ignore(); return; @@ -212,6 +215,7 @@ RendererStack::wheelEvent(QWheelEvent *event) mouse_set_z((int) numSteps); event->accept(); +#endif } void From 9bce2496be920bb3d2b260b53e17044d79205e0c Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 18 Mar 2025 22:51:19 +0100 Subject: [PATCH 0513/1190] Corrected the behavior of that. --- src/qt/qt_rendererstack.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 5b464f6a5..5dc61e03b 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -203,19 +203,17 @@ RendererStack::mousePressEvent(QMouseEvent *event) void RendererStack::wheelEvent(QWheelEvent *event) { -#if defined(Q_OS_WINDOWS) || defined(__APPLE__) - event->ignore(); -#else if (!mouse_capture) { event->ignore(); return; } +#if !defined(Q_OS_WINDOWS) && !defined(__APPLE__) double numSteps = (double) event->angleDelta().y() / 120.0; mouse_set_z((int) numSteps); - event->accept(); #endif + event->accept(); } void From 67f0e9574098eab70590cae94059bdf40878f3e0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 00:24:13 +0100 Subject: [PATCH 0514/1190] Fixed an off by 1 error in the new recompiler. --- src/codegen_new/codegen_backend_x86-64_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index 39173505b..c70112c86 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -533,7 +533,7 @@ host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addword(block, imm_data); } else if (offset < (1ULL << 32)) { - codegen_alloc_bytes(block, 8); + codegen_alloc_bytes(block, 9); codegen_addbyte3(block, 0x66, 0xc7, 0x85); /*MOV offset[RBP], imm_data*/ codegen_addlong(block, offset); codegen_addword(block, imm_data); From f05e2f34b615d879e7a60216ab8d24961087a023 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Mar 2025 08:51:52 +0900 Subject: [PATCH 0515/1190] added JEGA video emulation --- src/include/86box/vid_ega.h | 21 ++ src/video/CMakeLists.txt | 1 + src/video/vid_ega.c | 26 +- src/video/vid_jega.c | 724 ++++++++++++++++++++++++++++++++++++ src/video/vid_table.c | 1 + 5 files changed, 757 insertions(+), 16 deletions(-) create mode 100644 src/video/vid_jega.c diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 0bccd607e..082cb120a 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -140,6 +140,11 @@ typedef struct ega_t { uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr); void (*render)(struct ega_t *svga); + + /*If set then another device is driving the monitor output and the EGA + card should not attempt to display anything */ + void (*render_override)(void *priv); + void *priv_parent; } ega_t; #endif @@ -150,6 +155,7 @@ extern const device_t sega_device; extern const device_t atiega800p_device; extern const device_t iskra_ega_device; extern const device_t et2000_device; +extern const device_t jega_device; #endif extern int update_overscan; @@ -199,4 +205,19 @@ void ega_render_text(ega_t *ega); void ega_render_graphics(ega_t *ega); #endif +enum { + EGA_IBM = 0, + EGA_COMPAQ, + EGA_SUPEREGA, + EGA_ATI800P, + EGA_ISKRA, + EGA_TSENG +}; + +enum { + EGA_TYPE_IBM = 0, + EGA_TYPE_OTHER = 1, + EGA_TYPE_COMPAQ = 2 +}; + #endif /*VIDEO_EGA_H*/ diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index fdd94f6c6..062fc272a 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -78,6 +78,7 @@ add_library(vid OBJECT vid_xga.c vid_bochs_vbe.c vid_ps55da2.c + vid_jega.c nv/nv_rivatimer.c ) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 10df85c79..781e9a9dd 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -45,21 +45,6 @@ void ega_doblit(int wx, int wy, ega_t *ega); #define BIOS_ISKRA_PATH "roms/video/ega/143-02.bin", "roms/video/ega/143-03.bin" #define BIOS_TSENG_PATH "roms/video/ega/EGA ET2000.BIN" -enum { - EGA_IBM = 0, - EGA_COMPAQ, - EGA_SUPEREGA, - EGA_ATI800P, - EGA_ISKRA, - EGA_TSENG -}; - -enum { - EGA_TYPE_IBM = 0, - EGA_TYPE_OTHER = 1, - EGA_TYPE_COMPAQ = 2 -}; - static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; static uint8_t ega_rotate[8][256]; static int active = 0; @@ -107,6 +92,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) case 0x3c0: case 0x3c1: + if (ega->actual_type == EGA_SUPEREGA) + val &= 0x7f; /* Bit 7 indicates the flipflop status (read only) */ if (!ega->attrff) { ega->attraddr = val & 31; if ((val & 0x20) != ega->attr_palette_enable) { @@ -325,6 +312,8 @@ ega_in(uint16_t addr, void *priv) case 0x3c0: if (ega_type == EGA_TYPE_OTHER) ret = ega->attraddr | ega->attr_palette_enable; + if (ega->actual_type == EGA_SUPEREGA && ega->attrff) + ret |= 0x80; /* Bit 7 indicates the flipflop status (read only) */ break; case 0x3c1: if (ega_type == EGA_TYPE_OTHER) @@ -754,7 +743,10 @@ ega_poll(void *priv) ega->y_add *= ega->vres + 1; for (y = 0; y <= ega->vres; y++) { /* Render scanline */ - ega->render(ega); + if(ega->render_override) + ega->render_override(ega->priv_parent); + else + ega->render(ega); /* Render overscan */ ega->x_add = (overscan_x >> 1); @@ -1429,6 +1421,8 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) ega->crtc[0] = 63; ega->crtc[6] = 255; + ega->render_override = NULL; + timer_add(&ega->timer, ega_poll, ega, 1); if (ega_type == EGA_TYPE_COMPAQ) timer_add(&ega->dot_timer, ega_dot_poll, ega, 1); diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c new file mode 100644 index 000000000..ad312faff --- /dev/null +++ b/src/video/vid_jega.c @@ -0,0 +1,724 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the JEGA (Japanese EGA), a part of the AX architecture. + * + * It's an extension of the SuperEGA. Superimposing text (AX-2) is not available. + * + * Authors: Akamaki + * + * Copyright 2025 Akamaki + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_ega.h> + +/* JEGA internal registers */ +#define RPESL 0x09 /* End Scan Line */ +#define RCCSL 0x0A /* Cursor Start Line */ +#define RCCEL 0x0B /* Cursor End Line */ +#define RCCLH 0x0E /* Cursor Location High */ +#define RCCLL 0x0F /* Cursor Location Low */ +#define RPULP 0x14 /* Under Line Position */ +/* + 0xB8 - 0x20 */ +#define RMOD1 0x21 /* Display out, EGA through, Superimpose, Sync with EGA, Master EGA, Slave EGA, n/a, Test */ +#define RMOD2 0x22 /* 1st Attr, 2nd Attr, Blink/Int, n/a, Font access mode (b3-2), Font map sel (b1-0)*/ +#define RDAGS 0x23 /* ANK Group Select */ +#define RDFFB 0x24 /* Font Access First Byte */ +#define RDFSB 0x25 /* Font Access Second Byte */ +#define RDFAP 0x26 /* Font Access Pattern */ +#define RSTAT 0x27 /* Font Status Register */ +/* + 0xD0 - 0x20 */ +#define RPSSU 0x29 /* Start Scan Upper */ +#define RPSSL 0x2A /* Start Scan Lower */ +#define RPSSC 0x2B /* Start Scan Count */ +#define RPPAJ 0x2C /* Phase Adjust Count */ +#define RCMOD 0x2D /* Cursor Mode */ +#define RCSKW 0x2E /* Cursor Skew Control */ +#define ROMSL 0x2F /* ? */ +#define RINVALID_INDEX 0x30 + +#define JEGA_PATH_BIOS "roms/video/jega/OKI_IF386AX_VBIOS.bin" +#define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" +#define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ +#define DBCS16_CHARS 0x2c10 +#define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2) + +#define INVALIDACCESS8 0xffu +#define INVALIDACCESS16 0xffffu +#define INVALIDACCESS32 0xffffffffu + +#ifndef RELEASE_BUILD +// # define ENABLE_JEGA_LOG 1 +#endif + +#ifdef ENABLE_JEGA_LOG +int jega_do_log = ENABLE_JEGA_LOG; + +static void +jega_log(const char *fmt, ...) +{ + va_list ap; + + if (jega_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define jega_log(fmt, ...) +#endif + +static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + +typedef struct jega_t { + rom_t bios_rom; + ega_t ega; + uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */ + uint8_t regs[0x31]; + uint8_t egapal[16]; + uint8_t attrregs[32]; + uint8_t attraddr; + uint8_t attrff; + uint8_t attr_palette_enable; + uint32_t *pallook; + int con; + int cursoron; + int cursorblink_disable; + int ca; + int font_index; + int sbcsbank_inv; + int attr3_sbcsbank; + int start_scan_lower; + int start_scan_upper; + int start_scan_count; + uint8_t *vram; + uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */ + uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */ +} jega_t; + +static void jega_recalctimings(void *priv); + +#define FONTX_LEN_ID 6 +#define FONTX_LEN_FN 8 + +typedef struct { + char id[FONTX_LEN_ID]; + char name[FONTX_LEN_FN]; + unsigned char width; + unsigned char height; + unsigned char type; +} fontx_h; + +typedef struct { + uint16_t start; + uint16_t end; +} fontx_tbl; + +static uint32_t pallook64[256]; +static bool is_SJIS_1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } +static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } + +static uint16_t +SJIS_to_SEQ(uint16_t sjis) +{ + uint32_t chr1 = (sjis >> 8) & 0xff; + uint32_t chr2 = sjis & 0xff; + if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2)) return INVALIDACCESS16; + chr1 -= 0x81; + if (chr1 > 0x5E) chr1 -= 0x40; + chr2 -= 0x40; + if (chr2 > 0x3F) chr2--; + chr1 *= 0xBC; + return (chr1 + chr2); +} + +static uint8_t +dbcs_read(uint16_t sjis, int index, void *priv) { + jega_t *jega = (jega_t *) priv; + int seq = SJIS_to_SEQ(sjis); + if (seq >= DBCS16_CHARS || index >= 32) + return INVALIDACCESS8; + return jega->jfont_dbcs_16[seq * 32 + index]; +} + +static void +dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) { + jega_t *jega = (jega_t *) priv; + int seq = SJIS_to_SEQ(sjis); + if (seq >= DBCS16_CHARS || index >= 32) + return; + jega->jfont_dbcs_16[seq * 32 + index] = val; +} + +/* Display Adapter Mode 3 Drawing */ +void +jega_render_text(void *priv) +{ + jega_t *jega = (jega_t *) priv; + if (jega->ega.firstline_draw == 2000) + jega->ega.firstline_draw = jega->ega.displine; + jega->ega.lastline_draw = jega->ega.displine; + + if (jega->ega.fullchange) { + // const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0); + const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ + // const bool attrlinechars = (jega->ega.attrregs[0x10] & 4); + const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || (jega->regs[RMOD1] & 0x80 == 0); + const int charwidth = 8; + const bool blinked = jega->ega.blink & 0x10; + uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add]; + bool chr_wide = false; + int sc_wide = jega->ega.sc - jega->start_scan_count; + const bool cursoron = (blinked || jega->cursorblink_disable) + && (jega->ega.sc >= jega->regs[RCCSL]) && (jega->ega.sc <= jega->regs[RCCEL]); + uint32_t chr_first; + uint32_t attr_basic; + int fg; + int bg; + + for (int x = 0; x < (jega->ega.hdisp + jega->ega.scrollcache); x += charwidth) { + uint32_t addr = jega->ega.remap_func(&jega->ega, jega->ega.ma) & jega->ega.vrammask; + + int drawcursor = ((jega->ega.ma == jega->ca) && cursoron); + + uint32_t chr; + uint32_t attr; + if (!crtcreset) { + chr = jega->ega.vram[addr]; + attr = jega->ega.vram[addr + 1]; + } else + chr = attr = 0; + if (chr_wide) { + uint8_t attr_ext = 0; + /* the code may be in DBCS */ + if (jega->regs[RMOD2] & 0x40) { + /* Parse JEGA extended attribute */ + /* Bold | 2x width | 2x height | U/L select | R/L select | - | - | - */ + attr_ext = attr; + if ((attr_ext & 0x30) == 0x30) + sc_wide = jega->ega.sc - jega->start_scan_lower; /* Set top padding of lower 2x character */ + else if ((attr_ext & 0x30) == 0x20) + sc_wide = jega->ega.sc - jega->start_scan_upper; /* Set top padding of upper 2x character */ + else + sc_wide = jega->ega.sc - jega->start_scan_count; + } + if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && jega->ega.sc <= jega->regs[RPESL]) { + chr_first <<= 8; + chr |= chr_first; + /* Vertical wide font (Extended Attribute) */ + if (attr_ext & 0x20) { + if (attr_ext & 0x10) + sc_wide = (sc_wide >> 1) + 8; + else + sc_wide = sc_wide >> 1; + } + /* Horizontal wide font (Extended Attribute) */ + if (attr_ext & 0x40) { + uint32_t dat = dbcs_read(chr, sc_wide, jega); + if (!(attr_ext & 0x08)) { /* right half of character */ + dat = dbcs_read(chr, sc_wide + 16, jega); + } + for (int xx = 0; xx < charwidth; xx++) { + p[xx * 2] = (dat & (0x80 >> xx)) ? fg : bg; + p[xx * 2 + 1] = (dat & (0x80 >> xx)) ? fg : bg; + } + } else { + uint32_t dat = dbcs_read(chr, sc_wide, jega); + dat <<= 8; + dat |= dbcs_read(chr, sc_wide + 16, jega); + /* Bold (Extended Attribute) */ + if (attr_ext &= 0x80) { + uint32_t dat2 = dat; + dat2 >>= 1; + dat |= dat2; + } + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = (dat & (0x8000 >> xx)) ? fg : bg; + } + } else { + /* invalid DBCS code or line space then put blank */ + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = bg; + } + if (attr_basic & 0x20) { /* vertical line */ + p[0] = fg; + } + if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + for (int xx = 0; xx < charwidth * 2; xx++) + p[xx] = fg; + } + chr_wide = false; + p += (charwidth * 2); + } else { + /* SBCS or invalid second byte of DBCS */ + if (jega->regs[RMOD2] & 0x80) { + /* Parse attribute as JEGA */ + /* Blink | Reverse | V line | U line | (Bit 3-0 is the same as EGA) */ + /* The background color is always black (transparent in AX-2) */ + if (drawcursor || attr & 0x40) { + bg = jega->pallook[jega->egapal[attr & 0x0f]]; + fg = 0; + } else { + fg = jega->pallook[jega->egapal[attr & 0x0f]]; + bg = 0; + if (attr & 0x80) { + bg = 0; + if (blinked) + fg = bg; + } + } + attr_basic = attr; + } else { + /* Parse attribute as EGA */ + /* BInt/Blink | BR | BG | BB | Int/Group | R | G | B */ + if (drawcursor) { + bg = jega->pallook[jega->egapal[attr & 0x0f]]; + fg = jega->pallook[jega->egapal[attr >> 4]]; + } else { + fg = jega->pallook[jega->egapal[attr & 0x0f]]; + bg = jega->pallook[jega->egapal[attr >> 4]]; + if ((attr & 0x80) && attrblink) { + bg = jega->pallook[jega->egapal[(attr >> 4) & 7]]; + if (blinked) + fg = bg; + } + } + attr_basic = 0; + } + + if (is_SJIS_1(chr)) { + /* the char code maybe in DBCS */ + chr_first = chr; + chr_wide = true; + } else { + /* the char code is in SBCS */ + uint32_t charaddr = chr; + // if (jega->attr3_sbcsbank && (attr & 8)) + // charaddr |= 0x100; + // if (jega->sbcsbank_inv) + // charaddr ^= 0x100; + charaddr *= 19; + + uint32_t dat = jega->jfont_sbcs_19[charaddr + jega->ega.sc]; + for (int xx = 0; xx < charwidth; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + + if (attr_basic & 0x20) { /* vertical line */ + p[0] = fg; + } + if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + for (int xx = 0; xx < charwidth; xx++) + p[xx] = fg; + } + p += charwidth; + } + } + jega->ega.ma += 4; + } + jega->ega.ma &= 0x3ffff; + } +} + +static void +jega_out(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t o; + jega_t *jega = (jega_t *) priv; + // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); + switch (addr) { + case 0x3c0: + case 0x3c1: + jega_log("Palette %02X %02X(%d) %04X:%04X\n", jega->attraddr, val, val, cs >> 4, cpu_state.pc); + /* Palette (write only) */ + if (!jega->attrff) { + jega->attraddr = val & 31; + if ((val & 0x20) != jega->attr_palette_enable) { + jega->ega.fullchange = 3; + jega->attr_palette_enable = val & 0x20; + jega_recalctimings(jega); + } + } else { + o = jega->attrregs[jega->attraddr & 31]; + jega->attrregs[jega->attraddr & 31] = val; + if (jega->attraddr < 0x10) { + for (uint8_t c = 0; c < 16; c++) { + jega->egapal[c] = jega->attrregs[c] & 0x3f; + } + jega->ega.fullchange = changeframecount; + } + } + jega->attrff ^= 1; + break; + case 0x3b4: + case 0x3d4: + /* Index 0x00-0x1F (write only), 0xB8-0xDF (write and read) */ + if (val >= 0xB8 && val <= 0xBF) + jega->regs_index = val - 0xB8 + 0x20; + else if (val >= 0xD8 && val <= 0xDF) + jega->regs_index = val - 0xD0 + 0x20; + else if (val <= 0x1F) + jega->regs_index = val; + else + jega->regs_index = RINVALID_INDEX; + break; + case 0x3b5: + case 0x3d5: + /* Data */ + if (jega->regs_index != RINVALID_INDEX) { + jega->regs[jega->regs_index] = val; + jega_log("JEGA Out %04X(%02X) %02Xh(%d) %04X:%04X\n", addr, jega->regs_index, val, val, cs >> 4, cpu_state.pc); + switch (jega->regs_index) { + case RMOD1: + /* if the value is changed */ + // if (jega->regs[jega->regs_index] != val) { + if (val & 0x40) + jega->ega.render_override = NULL; + else + jega->ega.render_override = jega_render_text; + // } + break; + case RDAGS: + switch (val & 0x03) { + case 0x00: + jega->attr3_sbcsbank = false; + jega->sbcsbank_inv = false; + break; + case 0x01: + jega->attr3_sbcsbank = true; + jega->sbcsbank_inv = false; + break; + case 0x02: + jega->attr3_sbcsbank = true; + jega->sbcsbank_inv = true; + break; + case 0x03: + jega->attr3_sbcsbank = false; + jega->sbcsbank_inv = true; + break; + } + break; + case RCCLH: + case RCCLL: + jega->ca = jega->regs[RCCLH] << 10 | jega->regs[RCCLL] << 2; + break; + case RCMOD: + jega->cursoron = (val & 0x80); + jega->cursorblink_disable = (~val & 0x20); + break; + case RDFFB: + case RDFSB: + /* reset the line number */ + jega->font_index = 0; + break; + case RPSSC: + if (val <= 17) + jega->start_scan_count = val + 1; + else + jega->start_scan_count = (val - 32) + 1; + break; + case RPSSL: + jega->start_scan_lower = val - 15; + break; + case RPSSU: + if (val <= 33) + jega->start_scan_upper = val + 4; + else + jega->start_scan_upper = (val - 64) + 4; + break; + case RDFAP: + uint16_t chr = jega->regs[RDFFB]; + if (is_SJIS_1(chr) && chr >= 0xf0 && chr <= 0xf3) { + chr <<= 8; + chr |= jega->regs[RDFSB]; + if (jega->font_index < 32) + dbcs_write(chr, jega->font_index, val, jega); + } else { + if (jega->font_index <19) + jega->jfont_sbcs_19[chr * 19 + jega->font_index] = val; + } + jega_log("JEGA Font W %X %d %02Xh(%d) %04X:%04X\n", chr, jega->font_index, val, val, cs >> 4, cpu_state.pc); + jega->font_index++; + break; + } + } + break; + default: + break; + } + if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ + ega_out(addr, val, &jega->ega); +} + +static uint8_t +jega_in(uint16_t addr, void *priv) +{ + jega_t *jega = (jega_t *) priv; + uint8_t ret = INVALIDACCESS8; + switch (addr) { + case 0x3b5: + case 0x3d5: + if (jega->regs_index >= 0x20 && jega->regs_index <= 0x2F) { + switch (jega->regs_index) { + case RDFAP: + uint16_t chr = jega->regs[RDFFB]; + /* DBCS or SBCS */ + if (is_SJIS_1(chr)) { + chr <<= 8; + chr |= jega->regs[RDFSB]; + if (jega->font_index < 32) + ret = dbcs_read(chr, jega->font_index, jega); + } else { + if (jega->font_index < 19) + ret = jega->jfont_sbcs_19[chr * 19 + jega->font_index]; + } + jega_log("JEGA Font R %X %d %02Xh(%d) %04X:%04X\n", chr, jega->font_index, ret, ret, cs >> 4, cpu_state.pc); + jega->font_index++; + break; + case RSTAT: + ret = 0x03; + break; + default: + ret = jega->regs[jega->regs_index]; + break; + } + jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); + } else if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ + ret = ega_in(addr, &jega->ega); + break; + case 0x3ba: + case 0x3da: + jega->attrff = 0; + default: + if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave is redirected to Master in AX-1. */ + ret = ega_in(addr, &jega->ega); + break; + } + // jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); + return ret; +} + +static int +getfontx2header(FILE *fp, fontx_h *header) +{ + fread(header->id, FONTX_LEN_ID, 1, fp); + if (strncmp(header->id, "FONTX2", FONTX_LEN_ID) != 0) { + return 1; + } + fread(header->name, FONTX_LEN_FN, 1, fp); + header->width = (uint8_t) getc(fp); + header->height = (uint8_t) getc(fp); + header->type = (uint8_t) getc(fp); + return 0; +} + +static uint16_t +chrtosht(FILE *fp) +{ + uint16_t i, j; + i = (uint16_t) getc(fp); + j = (uint16_t) getc(fp) << 8; + return (i | j); +} + +static void +readfontxtbl(fontx_tbl *table, int size, FILE *fp) +{ + while (size > 0) { + table->start = chrtosht(fp); + table->end = chrtosht(fp); + ++table; + --size; + } +} + +static int +LoadFontxFile(const char *fn, void *priv) +{ + fontx_h fhead; + fontx_tbl *ftbl; + uint16_t code; + uint16_t scode; + uint8_t size; + uint8_t buf; + int line; + jega_t *jega = (jega_t *) priv; + FILE *fp = rom_fopen(fn, "rb"); + jega_log("JEGA: Loading font\n"); + if (fp == NULL) { + jega_log("JEGA: font file '%s' not found.\n", fn); + return 0; + } + if (getfontx2header(fp, &fhead) != 0) { + fclose(fp); + jega_log("JEGA: FONTX2 header is incorrect.\n"); + return 1; + } + /* DBCS or SBCS */ + if (fhead.type == 1) { + if (fhead.width == 16 && fhead.height == 16) { + size = getc(fp); + ftbl = (fontx_tbl *) calloc(size, sizeof(fontx_tbl)); + readfontxtbl(ftbl, size, fp); + for (int i = 0; i < size; i++) { + for (code = ftbl[i].start; code <= ftbl[i].end; code++) { + scode = SJIS_to_SEQ(code); + if (scode != INVALIDACCESS16) { + for (line = 0; line < 16; line++) { + fread(&buf, sizeof(uint8_t), 1, fp); + jega->jfont_dbcs_16[(int) (scode * 32) + line] = buf; + fread(&buf, sizeof(uint8_t), 1, fp); + jega->jfont_dbcs_16[(int) (scode * 32) + line + 16] = buf; + } + } else { + fseek(fp, 32, SEEK_CUR); + } + } + } + } else { + fclose(fp); + jega_log("JEGA: Width or height of DBCS font doesn't match.\n"); + return 1; + } + } else { + if (fhead.width == 8 && fhead.height == 19) { + fread(jega->jfont_sbcs_19, sizeof(uint8_t), SBCS19_FILESIZE, fp); + } else { + fclose(fp); + jega_log("JEGA: Width or height of SBCS font doesn't match.\n"); + return 1; + } + } + fclose(fp); + return 0; +} + +static void * +jega_init(const device_t *info) +{ + jega_t *jega = calloc(1, sizeof(jega_t)); + + rom_init(&jega->bios_rom, JEGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); + memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); + LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); + jega->pallook = pallook64; + ega_init(&jega->ega, 9, 0); + jega->ega.actual_type = EGA_SUPEREGA; + jega->ega.priv_parent = jega; + mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); + + io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + + jega->regs[RMOD1] = 0x48; +} + +static void +jega_close(void *priv) +{ + jega_t *jega = (jega_t *) priv; +#ifdef ENABLE_JEGA_LOG + FILE *f; + // f = fopen("jega_font16.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->jfont_dbcs_16, DBCS16_FILESIZE, 1, f); + // fclose(f); + // } + // f = fopen("jega_font19.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->jfont_sbcs_19, SBCS19_FILESIZE, 1, f); + // fclose(f); + // } + f = fopen("jega_regs.txt", "wb"); + if (f != NULL) { + for (int i = 0; i < 49; i++) + fprintf(f, "Regs %02X: %4X\n", i, jega->regs[i]); + for (int i = 0; i < 32; i++) + fprintf(f, "Attr %02X: %4X\n", i, jega->attrregs[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); + for (int i = 0; i < 64; i++) + fprintf(f, "RealPal %02X: %4X\n", i, jega->pallook[i]); + fclose(f); + } + // f = fopen("ega_vram.dmp", "wb"); + // if (f != NULL) { + // fwrite(jega->ega.vram, 256 * 1024, 1, f); + // fclose(f); + // } + f = fopen("ram_bda.dmp", "wb"); + if (f != NULL) { + fwrite(&ram[0x0], 0x500, 1, f); + fclose(f); + } + // jega_log("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); +#endif + if (jega->ega.eeprom) + free(jega->ega.eeprom); + free(jega->ega.vram); + free(jega); +} + +static void +jega_recalctimings(void *priv) +{ + jega_t *jega = (jega_t *) priv; + ega_recalctimings(&jega->ega); +} +static void +jega_speed_changed(void *priv) +{ + jega_t *jega = (jega_t *) priv; + + jega_recalctimings(jega); +} + +static int +jega_available(void) +{ + return (rom_present(JEGA_PATH_BIOS) && rom_present(JEGA_PATH_FONTDBCS)); +} + +const device_t jega_device = { + .name = "JEGA", + .internal_name = "jega", + .flags = DEVICE_ISA, + .local = 0, + .init = jega_init, + .close = jega_close, + .reset = NULL, + .available = jega_available, + .speed_changed = jega_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index d1df2ba20..be26d9e18 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -68,6 +68,7 @@ video_cards[] = { { .device = &ati18800_wonder_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &cga_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &sega_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &jega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5401_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5402_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5420_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, From 4d3e2a3be35606bce7d70275053ef18730c10e42 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:38:17 +0900 Subject: [PATCH 0516/1190] changed rom filename --- src/video/vid_jega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index ad312faff..b6695893c 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -59,7 +59,7 @@ #define ROMSL 0x2F /* ? */ #define RINVALID_INDEX 0x30 -#define JEGA_PATH_BIOS "roms/video/jega/OKI_IF386AX_VBIOS.bin" +#define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 From 395f23cf57d608b561f6cdde77d2976e602328b0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 03:12:36 +0100 Subject: [PATCH 0517/1190] More Cyrix fixes. --- src/cpu/386_common.c | 60 +++++++--- src/cpu/cpu.c | 236 ++++++++++++++++++++++++++-------------- src/cpu/cpu.h | 7 ++ src/cpu/x86_ops_cyrix.h | 208 ++++++++++++++++++++++++++++++----- 4 files changed, 383 insertions(+), 128 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 5b0e1a5c4..2853e3c9a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1449,26 +1449,44 @@ enter_smm(int in_hlt) void enter_smm_check(int in_hlt) { - if ((in_smm == 0) && smi_line) { -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while not in SMM\n"); -#endif - enter_smm(in_hlt); - } else if ((in_smm == 1) && smi_line) { - /* Mark this so that we don't latch more than one SMI. */ -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while in unlatched SMM\n"); -#endif - smi_latched = 1; - } else if ((in_smm == 2) && smi_line) { - /* Mark this so that we don't latch more than one SMI. */ -#ifdef ENABLE_386_COMMON_LOG - x386_common_log("SMI while in latched SMM\n"); -#endif - } + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && (cyrix.arr[3].size > 0); + + if (smi_line) { + if (!is_cxsmm || ccr1_check) switch (in_smm) { + default: +#ifdef ENABLE_386_COMMON_LOG + fatal("SMI while in_smm = %i\n", in_smm); + break; +#endif + case 0: +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while not in SMM\n"); +#endif + enter_smm(in_hlt); + break; + case 1: + /* Mark this so that we don't latch more than one SMI. */ +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while in unlatched SMM\n"); +#endif + smi_latched = 1; + break; + case 2: +#ifdef ENABLE_386_COMMON_LOG + x386_common_log("SMI while in latched SMM\n"); +#endif + break; + } +#ifdef ENABLE_386_COMMON_LOG + else { + x386_common_log("SMI while in Cyrix disabled mode\n"); + x386_common_log("lol\n"); + } +#endif - if (smi_line) smi_line = 0; + } } void @@ -2186,6 +2204,12 @@ cpu_fast_off_reset(void) void smi_raise(void) { + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && (cyrix.arr[3].size > 0); + + if (is_cxsmm && !ccr1_check) + return; + if (is486 && (cpu_fast_off_flags & 0x80000000)) cpu_fast_off_advance(); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 0c621bf68..41ca6932d 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -40,6 +40,7 @@ #include <86box/nmi.h> #include <86box/pic.h> #include <86box/pci.h> +#include <86box/smram.h> #include <86box/timer.h> #include <86box/gdbstub.h> #include <86box/plat_fallthrough.h> @@ -50,13 +51,6 @@ #endif /* USE_DYNAREC */ #include "x87_timings.h" -#define CCR1_USE_SMI (1 << 1) -#define CCR1_SMAC (1 << 2) -#define CCR1_SM3 (1 << 7) - -#define CCR3_SMI_LOCK (1 << 0) -#define CCR3_NMI_EN (1 << 1) - enum { CPUID_FPU = (1 << 0), /* On-chip Floating Point Unit */ CPUID_VME = (1 << 1), /* Virtual 8086 mode extensions */ @@ -289,6 +283,10 @@ uint8_t ccr5; uint8_t ccr6; uint8_t ccr7; +uint8_t reg_30 = 0x00; +uint8_t arr[24] = { 0 }; +uint8_t rcr[8] = { 0 }; + static int cyrix_addr; static void cpu_write(uint16_t addr, uint8_t val, void *priv); @@ -2627,6 +2625,23 @@ cpu_ven_reset(void) msr.amd_efer = (cpu_s->cpu_type >= CPU_K6_2C) ? 2ULL : 0ULL; break; + case CPU_Cx6x86MX: + ccr0 = 0x00; + ccr1 = 0x00; + ccr2 = 0x00; + ccr3 = 0x00; + ccr4 = 0x80; + ccr5 = 0x00; + ccr6 = 0x00; + memset(arr, 0x00, 24); + memset(rcr, 0x00, 3); + cyrix.arr[3].base = 0x00; + cyrix.arr[3].size = 0; /* Disabled */ + cyrix.smhr &= ~SMHR_VALID; + CPUID = cpu_s->cpuid_model; + reg_30 = 0xff; + break; + case CPU_PENTIUMPRO: case CPU_PENTIUM2: case CPU_PENTIUM2D: @@ -4237,78 +4252,105 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) picintc(1 << 13); else nmi = 0; - return; - } else if (addr >= 0xf1) - return; /* FPU stuff */ - - if (!(addr & 1)) + } else if ((addr < 0xf1) && !(addr & 1)) cyrix_addr = val; - else - switch (cyrix_addr) { - case 0xc0: /* CCR0 */ - ccr0 = val; - break; - case 0xc1: /* CCR1 */ - if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) - val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); - ccr1 = val; - break; - case 0xc2: /* CCR2 */ - ccr2 = val; - break; - case 0xc3: /* CCR3 */ - if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) - val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; - ccr3 = val; - break; - case 0xcd: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); - cyrix.smhr &= ~SMHR_VALID; - } - break; - case 0xce: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); - cyrix.smhr &= ~SMHR_VALID; - } - break; - case 0xcf: - if (!(ccr3 & CCR3_SMI_LOCK) || in_smm) { - cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); - if ((val & 0xf) == 0xf) - cyrix.arr[3].size = 1ULL << 32; /* 4 GB */ - else if (val & 0xf) - cyrix.arr[3].size = 2048 << (val & 0xf); - else - cyrix.arr[3].size = 0; /* Disabled */ - cyrix.smhr &= ~SMHR_VALID; - } - break; + else if (addr < 0xf1) switch (cyrix_addr) { + default: + if (cyrix_addr >= 0xc0) + fatal("Writing unimplemented Cyrix register %02X\n", cyrix_addr); + break; - case 0xe8: /* CCR4 */ - if ((ccr3 & 0xf0) == 0x10) { - ccr4 = val; - if (cpu_s->cpu_type >= CPU_Cx6x86) { - if (val & 0x80) - CPUID = cpu_s->cpuid_model; - else - CPUID = 0; - } + case 0x30: /* ???? */ + reg_30 = val; + break; + + case 0xc0: /* CCR0 */ + ccr0 = val; + break; + case 0xc1: { /* CCR1 */ + uint8_t old = ccr1; + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); + ccr1 = val; + if ((old ^ ccr1) & (CCR1_SMAC)) { + if (ccr1 & CCR1_SMAC) + smram_backup_all(); + smram_recalc_all(!(ccr1 & CCR1_SMAC)); + } + break; + } case 0xc2: /* CCR2 */ + ccr2 = val; + break; + case 0xc3: /* CCR3 */ + if ((ccr3 & CCR3_SMI_LOCK) && !in_smm) + val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; + ccr3 = val; + break; + + case 0xc4 ... 0xcc: + if (ccr5 & 0x20) + arr[cyrix_addr - 0xc4] = val; + break; + case 0xcd: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xce: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xcf: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) { + arr[cyrix_addr - 0xc4] = val; + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); + if ((val & 0xf) == 0xf) + cyrix.arr[3].size = 1ULL << 32; /* 4 GB */ + else if (val & 0xf) + cyrix.arr[3].size = 2048 << (val & 0xf); + else + cyrix.arr[3].size = 0; /* Disabled */ + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xd0 ... 0xdb: + if (((ccr3 & 0xf0) == 0x10) && (ccr5 & 0x20)) + arr[cyrix_addr - 0xc4] = val; + break; + + case 0xdc ... 0xe3: + if ((ccr3 & 0xf0) == 0x10) + rcr[cyrix_addr - 0xdc] = val; + break; + + case 0xe8: /* CCR4 */ + if ((ccr3 & 0xf0) == 0x10) { + ccr4 = val; + if (cpu_s->cpu_type >= CPU_Cx6x86) { + if (val & 0x80) + CPUID = cpu_s->cpuid_model; + else + CPUID = 0; } - break; - case 0xe9: /* CCR5 */ - if ((ccr3 & 0xf0) == 0x10) - ccr5 = val; - break; - case 0xea: /* CCR6 */ - if ((ccr3 & 0xf0) == 0x10) - ccr6 = val; - break; - case 0xeb: /* CCR7 */ - ccr7 = val & 5; - break; - } + } + break; + case 0xe9: /* CCR5 */ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /* CCR6 */ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + case 0xeb: /* CCR7 */ + ccr7 = val & 5; + break; + } } static uint8_t @@ -4319,6 +4361,15 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) if (addr == 0xf007) ret = 0x7f; else if ((addr < 0xf0) && (addr & 1)) switch (cyrix_addr) { + default: + if (cyrix_addr >= 0xc0) + fatal("Reading unimplemented Cyrix register %02X\n", cyrix_addr); + break; + + case 0x30: /* ???? */ + ret = reg_30; + break; + case 0xc0: ret = ccr0; break; @@ -4331,14 +4382,36 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) case 0xc3: ret = ccr3; break; + + case 0xc4 ... 0xcc: + if (ccr5 & 0x20) + ret = arr[cyrix_addr - 0xc4]; + break; + case 0xcd ... 0xcf: + if ((ccr5 & 0x20) || (!(ccr3 & CCR3_SMI_LOCK) || in_smm)) + ret = arr[cyrix_addr - 0xc4]; + break; + case 0xd0 ... 0xdb: + if (((ccr3 & 0xf0) == 0x10) && (ccr5 & 0x20)) + ret = arr[cyrix_addr - 0xc4]; + break; + + case 0xdc ... 0xe3: + if ((ccr3 & 0xf0) == 0x10) + ret = rcr[cyrix_addr - 0xdc]; + break; + case 0xe8: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr4; break; case 0xe9: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr5; break; case 0xea: - ret = ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + if ((ccr3 & 0xf0) == 0x10) + ret = ccr6; break; case 0xeb: ret = ccr7; @@ -4349,11 +4422,8 @@ cpu_read(uint16_t addr, UNUSED(void *priv)) case 0xff: ret = cpu_s->cyrix_id >> 8; break; - - default: - break; } - + return ret; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index d58da6998..80097294d 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -120,6 +120,13 @@ enum { #define CPU_ALTERNATE_XTAL 4 #define CPU_FIXED_MULTIPLIER 8 +#define CCR1_USE_SMI (1 << 1) +#define CCR1_SMAC (1 << 2) +#define CCR1_SM3 (1 << 7) + +#define CCR3_SMI_LOCK (1 << 0) +#define CCR3_NMI_EN (1 << 1) + #if (defined __amd64__ || defined _M_X64) # define LOOKUP_INV -1LL #else diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index ac864cd20..c95d4b038 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -35,7 +35,13 @@ opSVDC_common(uint32_t fetchdat) static int opSVDC_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); opSVDC_common(fetchdat); @@ -47,7 +53,13 @@ opSVDC_a16(uint32_t fetchdat) static int opSVDC_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); opSVDC_common(fetchdat); @@ -88,7 +100,13 @@ opRSDC_common(uint32_t fetchdat) static int opRSDC_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); opRSDC_common(fetchdat); @@ -100,7 +118,13 @@ opRSDC_a16(uint32_t fetchdat) static int opRSDC_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); opRSDC_common(fetchdat); @@ -113,7 +137,13 @@ opRSDC_a32(uint32_t fetchdat) static int opSVLDT_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -126,7 +156,13 @@ opSVLDT_a16(uint32_t fetchdat) static int opSVLDT_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -140,7 +176,13 @@ opSVLDT_a32(uint32_t fetchdat) static int opRSLDT_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -152,7 +194,13 @@ opRSLDT_a16(uint32_t fetchdat) static int opRSLDT_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_READ(cpu_state.ea_seg); cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &ldt); @@ -165,7 +213,13 @@ opRSLDT_a32(uint32_t fetchdat) static int opSVTS_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -178,7 +232,13 @@ opSVTS_a16(uint32_t fetchdat) static int opSVTS_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -192,7 +252,13 @@ opSVTS_a32(uint32_t fetchdat) static int opRSTS_a16(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_16(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -205,7 +271,13 @@ opRSTS_a16(uint32_t fetchdat) static int opRSTS_a32(uint32_t fetchdat) { - if (in_smm) { + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { fetch_ea_32(fetchdat); SEG_CHECK_WRITE(cpu_state.ea_seg); cyrix_write_seg_descriptor(easeg + cpu_state.eaaddr, &tr); @@ -219,9 +291,13 @@ opRSTS_a32(uint32_t fetchdat) static int opSMINT(UNUSED(uint32_t fetchdat)) { + uint8_t ccr1_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) && + (cyrix.arr[3].size > 0); + if (in_smm) fatal("opSMINT\n"); - else { + else if (ccr1_check) { is_smint = 1; enter_smm(0); } @@ -232,9 +308,26 @@ opSMINT(UNUSED(uint32_t fetchdat)) static int opRDSHR_a16(UNUSED(uint32_t fetchdat)) { - if (in_smm) - fatal("opRDSHR_a16\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_16(fetchdat); + if (cpu_mod == 3) { + cpu_state.regs[cpu_rm].l = cyrix.smhr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 0); + } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cyrix.smhr); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0, 0, 0, 1, 0); + } + return cpu_state.abrt; + } else x86illegal(); return 1; @@ -242,30 +335,91 @@ opRDSHR_a16(UNUSED(uint32_t fetchdat)) static int opRDSHR_a32(UNUSED(uint32_t fetchdat)) { - if (in_smm) - fatal("opRDSHR_a32\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_32(fetchdat); + if (cpu_mod == 3) { + cpu_state.regs[cpu_rm].l = cyrix.smhr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 1); + } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(cyrix.smhr); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0, 0, 0, 1, 1); + } + return cpu_state.abrt; + } else x86illegal(); return 1; } static int -opWRSHR_a16(UNUSED(uint32_t fetchdat)) +opWRSHR_a16(uint32_t fetchdat) { - if (in_smm) - fatal("opWRSHR_a16\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_16(fetchdat); + if (cpu_mod == 3) { + cyrix.smhr = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 0); + } else { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + temp = geteal(); + if (cpu_state.abrt) + return 1; + cyrix.smhr = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0, 1, 0, 0, 0); + } + return 0; + } else x86illegal(); return 1; } static int -opWRSHR_a32(UNUSED(uint32_t fetchdat)) +opWRSHR_a32(uint32_t fetchdat) { - if (in_smm) - fatal("opWRSHR_a32\n"); - else + uint8_t ins_check = ((ccr1 & (CCR1_USE_SMI | CCR1_SM3)) == + (CCR1_USE_SMI | CCR1_SM3)) && + ((ccr1 & CCR1_SMAC) || in_smm) && + (cyrix.arr[3].size > 0) && + (CPL == 0); + + if (ins_check) { + fetch_ea_32(fetchdat); + if (cpu_mod == 3) { + cyrix.smhr = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0, 0, 0, 0, 1); + } else { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + temp = geteal(); + if (cpu_state.abrt) + return 1; + cyrix.smhr = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0, 1, 0, 0, 1); + } + return 0; + } else x86illegal(); return 1; From 0fd97c8427a252e4994476663846a8eb30a05640 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 04:35:47 +0100 Subject: [PATCH 0518/1190] MO: Fix medium size in various conditions and fix handling of unsupported media. --- src/disk/mo.c | 30 +++++++++++++++++++++++++----- src/include/86box/mo.h | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index e2db4bda3..e5cbd9140 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -18,6 +18,7 @@ * Copyright 2020-2025 Fred N. van Kempen */ #define _GNU_SOURCE +#include #ifdef ENABLE_MO_LOG #include #endif @@ -184,11 +185,14 @@ mo_load(const mo_t *dev, const char *fn, const int skip_insert) } else dev->drv->base = 0; + dev->drv->supported = 0; + for (uint8_t i = 0; i < KNOWN_MO_TYPES; i++) { if (size == ((uint64_t) mo_types[i].sectors * mo_types[i].bytes_per_sector)) { found = 1; dev->drv->medium_size = mo_types[i].sectors; dev->drv->sector_size = mo_types[i].bytes_per_sector; + dev->drv->supported = mo_drive_types[dev->drv->type].supported_media[i]; break; } } @@ -803,7 +807,12 @@ mo_blocks(mo_t *dev, int32_t *len, const int out) mo_log(dev->log, "%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); - if (dev->sector_pos >= dev->drv->medium_size) { + if (!dev->drv->supported) { + mo_log(dev->log, "Trying to %s an unsupported medium\n", + out ? "write" : "read"); + out ? mo_write_error(dev) : mo_read_error(dev); + ret = 0; + } else if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to %s beyond the end of disk\n", out ? "write" : "read"); mo_lba_out_of_range(dev); @@ -955,7 +964,11 @@ mo_erase(mo_t *dev) mo_log(dev->log, "Erasing %i blocks starting from %i...\n", dev->sector_len, dev->sector_pos); - if (dev->sector_pos >= dev->drv->medium_size) { + if (!dev->drv->supported) { + mo_log(dev->log, "Trying to erase an unsupported medium\n"); + mo_write_error(dev); + return 0; + } else if (dev->sector_pos >= dev->drv->medium_size) { mo_log(dev->log, "Trying to erase beyond the end of disk\n"); mo_lba_out_of_range(dev); return 0; @@ -1386,6 +1399,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_set_phase(dev, SCSI_PHASE_STATUS); mo_command_complete(dev); break; + } else if (!dev->drv->supported) { + mo_read_error(dev); + break; } fallthrough; case GPCMD_WRITE_6: @@ -1433,7 +1449,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) break; } - if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) + if (!dev->drv->supported) + mo_write_error(dev); + else if (dev->sector_pos >= dev->drv->medium_size) mo_lba_out_of_range(dev); else { if (dev->sector_len) { @@ -1473,7 +1491,9 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if (dev->sector_pos > (mo_types[dev->drv->type].sectors - 1)) + if (!dev->drv->supported) + mo_write_error(dev); + else if (dev->sector_pos >= dev->drv->medium_size) mo_lba_out_of_range(dev); else if (dev->sector_len) { mo_buf_alloc(dev, alloc_length); @@ -1834,7 +1854,7 @@ static uint8_t mo_phase_data_out(scsi_common_t *sc) { mo_t * dev = (mo_t *) sc; - const uint32_t last_sector = mo_types[dev->drv->type].sectors - 1; + const uint32_t last_sector = dev->drv->medium_size - 1; int len = 0; uint8_t error = 0; uint32_t last_to_write; diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index e09515b10..f4e7e9809 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -122,6 +122,8 @@ typedef struct mo_drive_t { uint32_t medium_size; uint32_t base; uint16_t sector_size; + + int supported; } mo_drive_t; typedef struct mo_t { From 2cd99f0c705c9a40cbc4a11866c05c03b6704734 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 07:54:54 +0100 Subject: [PATCH 0519/1190] X86 segmentation: apparently, the CPU can execute a data segment in some cases, used by LINK and CodeView, fixes #5283. --- src/cpu/x86seg.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index 2a0601661..145752237 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -1334,6 +1334,12 @@ pmoderetf(int is32, uint16_t off) if (CPL == (seg & 0x0003)) { x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS LINK for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1384,6 +1390,12 @@ pmoderetf(int is32, uint16_t off) cycles -= timing_retf_pm; } else { switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS LINK for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1605,6 +1617,12 @@ pmodeint(int num, int soft) return; } switch (segdat2[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS CodeView for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: @@ -1983,6 +2001,12 @@ pmodeiret(int is32) } switch (segdat[2] & 0x1f00) { + case 0x1000: + case 0x1100: + case 0x1200: + case 0x1300: + /* Data segment, apparently valid when CPL is the same, used by MS CodeView for DOS. */ + fallthrough; case 0x1800: case 0x1900: case 0x1a00: From 21bafa37a5aae28aeb63f0e2f2ad4c5a0720d2b1 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:44:03 +0900 Subject: [PATCH 0520/1190] correct a compile error --- src/video/vid_jega.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index b6695893c..3ff13e85d 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -347,6 +347,7 @@ jega_out(uint16_t addr, uint8_t val, void *priv) { uint8_t o; jega_t *jega = (jega_t *) priv; + uint16_t chr; // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); switch (addr) { case 0x3c0: @@ -449,7 +450,7 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega->start_scan_upper = (val - 64) + 4; break; case RDFAP: - uint16_t chr = jega->regs[RDFFB]; + chr = jega->regs[RDFFB]; if (is_SJIS_1(chr) && chr >= 0xf0 && chr <= 0xf3) { chr <<= 8; chr |= jega->regs[RDFSB]; @@ -477,13 +478,14 @@ jega_in(uint16_t addr, void *priv) { jega_t *jega = (jega_t *) priv; uint8_t ret = INVALIDACCESS8; + uint16_t chr; switch (addr) { case 0x3b5: case 0x3d5: if (jega->regs_index >= 0x20 && jega->regs_index <= 0x2F) { switch (jega->regs_index) { case RDFAP: - uint16_t chr = jega->regs[RDFFB]; + chr = jega->regs[RDFFB]; /* DBCS or SBCS */ if (is_SJIS_1(chr)) { chr <<= 8; From e932bc940df7fcd0c0555f051f486d334e790aed Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 19 Mar 2025 17:48:08 +0100 Subject: [PATCH 0521/1190] JEGA: Fix warnings. --- src/video/vid_jega.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 3ff13e85d..c410a15da 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -186,7 +186,7 @@ jega_render_text(void *priv) // const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0); const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ // const bool attrlinechars = (jega->ega.attrregs[0x10] & 4); - const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || (jega->regs[RMOD1] & 0x80 == 0); + const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0); const int charwidth = 8; const bool blinked = jega->ega.blink & 0x10; uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add]; @@ -345,7 +345,6 @@ jega_render_text(void *priv) static void jega_out(uint16_t addr, uint8_t val, void *priv) { - uint8_t o; jega_t *jega = (jega_t *) priv; uint16_t chr; // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); @@ -362,7 +361,6 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega_recalctimings(jega); } } else { - o = jega->attrregs[jega->attraddr & 31]; jega->attrregs[jega->attraddr & 31] = val; if (jega->attraddr < 0x10) { for (uint8_t c = 0; c < 16; c++) { @@ -641,6 +639,8 @@ jega_init(const device_t *info) io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); jega->regs[RMOD1] = 0x48; + + return jega; } static void From 00c97dac1ccdd362a6781eedf8ba657ae5634019 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 20 Mar 2025 00:56:13 +0600 Subject: [PATCH 0522/1190] Add "Five + 2 Wheels" option for horizontal wheel reporting --- src/device/mouse.c | 45 +++++++++++++++++++++++- src/device/mouse_ps2.c | 61 ++++++++++++++++++++++++--------- src/include/86box/mouse.h | 3 ++ src/qt/macos_event_filter.mm | 1 + src/qt/qt_rendererstack.cpp | 2 ++ src/qt/qt_winrawinputfilter.cpp | 7 ++++ 6 files changed, 102 insertions(+), 17 deletions(-) diff --git a/src/device/mouse.c b/src/device/mouse.c index f0446d781..f7d8c9861 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -106,6 +106,7 @@ static mouse_t mouse_devices[] = { static _Atomic double mouse_x; static _Atomic double mouse_y; static atomic_int mouse_z; +static atomic_int mouse_w; static atomic_int mouse_buttons; static int mouse_delta_b; @@ -156,6 +157,7 @@ mouse_clear_coords(void) mouse_clear_y(); mouse_z = 0; + mouse_w = 0; } void @@ -355,6 +357,14 @@ mouse_wheel_moved(void) return ret; } +int +mouse_hwheel_moved(void) +{ + int ret = !!(atomic_load(&mouse_w)); + + return ret; +} + int mouse_moved(void) { @@ -373,13 +383,14 @@ mouse_state_changed(void) int b; int b_mask = (1 << mouse_nbut) - 1; int wheel = (mouse_nbut >= 4); + int hwheel = (mouse_nbut >= 6); int ret; b = atomic_load(&mouse_buttons); mouse_delta_b = (b ^ mouse_old_b); mouse_old_b = b; - ret = mouse_moved() || ((atomic_load(&mouse_z) != 0) && wheel) || (mouse_delta_b & b_mask); + ret = mouse_moved() || ((atomic_load(&mouse_z) != 0) && wheel) || ((atomic_load(&mouse_w) != 0) && hwheel) || (mouse_delta_b & b_mask); return ret; } @@ -475,6 +486,18 @@ mouse_clear_z(void) atomic_store(&mouse_z, 0); } +void +mouse_set_w(int w) +{ + atomic_fetch_add(&mouse_w, w); +} + +void +mouse_clear_w(void) +{ + atomic_store(&mouse_w, 0); +} + void mouse_subtract_z(int *delta_z, int min, int max, int invert) { @@ -495,6 +518,26 @@ mouse_subtract_z(int *delta_z, int min, int max, int invert) atomic_store(&mouse_z, invert ? -real_z : real_z); } +void +mouse_subtract_w(int *delta_w, int min, int max, int invert) +{ + int w = atomic_load(&mouse_w); + int real_w = invert ? -w : w; + + if (real_w > max) { + *delta_w = max; + real_w -= max; + } else if (real_w < min) { + *delta_w = min; + real_w += ABS(min); + } else { + *delta_w = real_w; + real_w = 0; + } + + atomic_store(&mouse_w, invert ? -real_w : real_w); +} + void mouse_set_buttons_ex(int b) { diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 79d7afc96..0d34235fe 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -34,13 +34,15 @@ enum { MODE_ECHO }; -#define FLAG_EXPLORER 0x200 /* Has 5 buttons */ -#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ -#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ -#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ -#define FLAG_SCALED 0x20 /* enable delta scaling */ -#define FLAG_ENABLED 0x10 /* dev is enabled for use */ -#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ +#define FLAG_HWHL 0x800 /* Report horizontal wheel movements. */ +#define FLAG_EXPLORER_HWHL 0x400 /* Has tilt-wheel/horizontal scroll wheel */ +#define FLAG_EXPLORER 0x200 /* Has 5 buttons */ +#define FLAG_5BTN 0x100 /* using Intellimouse Optical mode */ +#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ +#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ +#define FLAG_SCALED 0x20 /* enable delta scaling */ +#define FLAG_ENABLED 0x10 /* dev is enabled for use */ +#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ #define FIFO_SIZE 16 @@ -82,10 +84,16 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) int overflow_y; int b = mouse_get_buttons_ex(); int delta_z; + int delta_w; mouse_subtract_coords(&delta_x, &delta_y, &overflow_x, &overflow_y, -256, 255, 1, 0); - mouse_subtract_z(&delta_z, -8, 7, 1); + + if (dev->flags & FLAG_5BTN) + mouse_subtract_z(&delta_z, -32, 31, 1); + else + mouse_subtract_z(&delta_z, -8, 7, 1); + mouse_subtract_w(&delta_w, -1, 1, 0); buff[0] |= (overflow_y << 7) | (overflow_x << 6) | ((delta_y & 0x0100) >> 3) | ((delta_x & 0x0100) >> 4) | @@ -97,10 +105,21 @@ ps2_report_coordinates(atkbc_dev_t *dev, int main) kbc_at_dev_queue_add(dev, buff[1], main); kbc_at_dev_queue_add(dev, buff[2], main); if (dev->flags & FLAG_INTMODE) { - delta_z &= 0x0f; + delta_z &= (dev->flags & FLAG_HWHL) ? 0x3f : 0x0f; if (dev->flags & FLAG_5BTN) { - if (b & 8) + if ((dev->flags & FLAG_HWHL) && (delta_z || delta_w)) + { + if (delta_w) { + delta_z = delta_w; + delta_z &= 0x3f; + delta_z |= 0x40; + } else { + delta_z &= 0x3f; + delta_z |= 0x80; + } + } + else if (b & 8) delta_z |= 0x10; if (b & 16) delta_z |= 0x20; @@ -120,7 +139,7 @@ ps2_set_defaults(atkbc_dev_t *dev) dev->rate = 100; mouse_set_sample_rate(100.0); dev->resolution = 2; - dev->flags &= 0x188; + dev->flags &= 0x688; mouse_scan = 0; } @@ -298,6 +317,13 @@ ps2_write(void *priv) (last_data[2] == 0xf3) && (last_data[3] == 0xc8) && (last_data[4] == 0xf3) && (last_data[5] == 0x50)) dev->flags |= FLAG_5BTN; + + if ((dev->flags & FLAG_5BTN) && (dev->flags & FLAG_EXPLORER_HWHL) && + (last_data[0] == 0xf3) && (last_data[1] == 0xc8) && + (last_data[2] == 0xf3) && (last_data[3] == 0x50) && + (last_data[4] == 0xf3) && (last_data[5] == 0x28)) + dev->flags |= FLAG_HWHL; + } } @@ -336,6 +362,8 @@ mouse_ps2_init(const device_t *info) dev->flags |= FLAG_INTELLI; if (i > 4) dev->flags |= FLAG_EXPLORER; + if (i > 5) + dev->flags |= FLAG_EXPLORER_HWHL; mouse_ps2_log("%s: buttons=%d\n", dev->name, i); @@ -377,11 +405,12 @@ static const device_config_t ps2_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Two", .value = 2 }, - { .description = "Three", .value = 3 }, - { .description = "Wheel", .value = 4 }, - { .description = "Five + Wheel", .value = 5 }, - { .description = "" } + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "Wheel", .value = 4 }, + { .description = "Five + Wheel", .value = 5 }, + { .description = "Five + 2 Wheels", .value = 6 }, + { .description = "" } }, .bios = { { 0 } } }, diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index bbe78413b..333849846 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -100,6 +100,9 @@ extern void mouse_scale_axis(int axis, int val); extern void mouse_set_z(int z); extern void mouse_clear_z(void); extern void mouse_subtract_z(int *delta_z, int min, int max, int invert); +extern void mouse_set_w(int w); +extern void mouse_clear_w(void); +extern void mouse_subtract_w(int *delta_w, int min, int max, int invert); extern void mouse_set_buttons_ex(int b); extern int mouse_get_buttons_ex(void); extern void mouse_set_sample_rate(double new_rate); diff --git a/src/qt/macos_event_filter.mm b/src/qt/macos_event_filter.mm index ff4e7c4d2..45c8ecbe3 100644 --- a/src/qt/macos_event_filter.mm +++ b/src/qt/macos_event_filter.mm @@ -37,6 +37,7 @@ CocoaEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, return true; } if ([event type] == NSEventTypeScrollWheel) { + mouse_set_w(-[event deltaX]); mouse_set_z([event deltaY]); return true; } diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 5dc61e03b..aed932e92 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -210,8 +210,10 @@ RendererStack::wheelEvent(QWheelEvent *event) #if !defined(Q_OS_WINDOWS) && !defined(__APPLE__) double numSteps = (double) event->angleDelta().y() / 120.0; + double numStepsW = (double) event->angleDelta().x() / 120.0; mouse_set_z((int) numSteps); + mouse_set_w((int) numStepsW); #endif event->accept(); } diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 8a2841f97..306da575f 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -330,6 +330,7 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) static int x, delta_x; static int y, delta_y; static int b, delta_z; + static int delta_w; b = mouse_get_buttons_ex(); @@ -367,6 +368,12 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) } else delta_z = 0; + if (state.usButtonFlags & RI_MOUSE_HWHEEL) { + delta_w = (SHORT) state.usButtonData / 120; + mouse_set_w(delta_w); + } else + delta_w = 0; + if (state.usFlags & MOUSE_MOVE_ABSOLUTE) { /* absolute mouse, i.e. RDP or VNC * seems to work fine for RDP on Windows 10 From 46f7c7c46f14217f41572b5e77e9b8e328e8b922 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:20:22 +0100 Subject: [PATCH 0523/1190] MO and ZIP: Fix return length of READ 6/10/12 and actually save the image history into the configuration file. --- src/config.c | 26 ++++++++++++++++++++++++++ src/disk/mo.c | 1 + src/disk/zip.c | 6 ++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/config.c b/src/config.c index 3bb9fb59a..2e6a5460f 100644 --- a/src/config.c +++ b/src/config.c @@ -3011,6 +3011,19 @@ save_other_removable_devices(void) else ini_section_set_string(cat, temp, zip_drives[c].image_path); } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "zip_%02i_image_history_%02i", c + 1, i + 1); + if ((zip_drives[c].image_history[i] == 0) || strlen(zip_drives[c].image_history[i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(zip_drives[c].image_history[i]); + if (!strnicmp(zip_drives[c].image_history[i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &zip_drives[c].image_history[i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, zip_drives[c].image_history[i]); + } + } } for (c = 0; c < MO_NUM; c++) { @@ -3054,6 +3067,19 @@ save_other_removable_devices(void) else ini_section_set_string(cat, temp, mo_drives[c].image_path); } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "mo_%02i_image_history_%02i", c + 1, i + 1); + if ((mo_drives[c].image_history[i] == 0) || strlen(mo_drives[c].image_history[i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(mo_drives[c].image_history[i]); + if (!strnicmp(mo_drives[c].image_history[i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &mo_drives[c].image_history[i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, mo_drives[c].image_history[i]); + } + } } ini_delete_section_if_empty(config, cat); diff --git a/src/disk/mo.c b/src/disk/mo.c index e5cbd9140..d59343833 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1363,6 +1363,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); const int ret = mo_blocks(dev, &alloc_length, 0); + alloc_length = dev->requested_blocks * 512; if (ret > 0) { dev->requested_blocks = max_len; diff --git a/src/disk/zip.c b/src/disk/zip.c index ae3319b40..ed59154b0 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -1386,10 +1386,8 @@ zip_command(scsi_common_t *sc, const uint8_t *cdb) dev->packet_len = max_len * alloc_length; zip_buf_alloc(dev, dev->packet_len); - int ret = 0; - - if (dev->sector_len > 0) - ret = zip_blocks(dev, &alloc_length, 0); + const int ret = zip_blocks(dev, &alloc_length, 0); + alloc_length = dev->requested_blocks * 512; if (ret > 0) { dev->requested_blocks = max_len; From a886d8a9f0146907a2689795e2828023ab620300 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:20:55 +0100 Subject: [PATCH 0524/1190] Forgotten Cyrix-related fixes in mem.c. --- src/mem/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index d1c6de49d..d85b20581 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2370,7 +2370,7 @@ mem_mapping_recalc(uint64_t base, uint64_t size) for (i_c = i_s; i_c <= i_e; i_c += i_a) { for (c = (start + i_c); c < (end + i_c); c += MEM_GRANULARITY_SIZE) { /* CPU */ - n = !!in_smm; + n = (!!in_smm) || (is_cxsmm && (ccr1 & CCR1_SMAC)); wp = _mem_wp[c >> MEM_GRANULARITY_BITS]; if (map->exec && mem_mapping_access_allowed(map->flags, From f74db2660f2a7c2a7eeb1e08e1bf1284c38936b1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:25:49 +0100 Subject: [PATCH 0525/1190] Fix the exact same READ 10/12/16 bug in scsi_disk.c as well. --- src/scsi/scsi_disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 878259094..a1afca2e2 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -1095,7 +1095,9 @@ scsi_disk_command(scsi_common_t *sc, const uint8_t *cdb) dev->drv->seek_pos = dev->sector_pos; dev->drv->seek_len = dev->sector_len; - ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + ret = scsi_disk_blocks(dev, &alloc_length, 1, 0); + alloc_length = dev->requested_blocks * 512; + if (ret > 0) { dev->requested_blocks = max_len; dev->packet_len = alloc_length; From 7575bdc562268f1660cd8bbc35e8aeae383cc167 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 20 Mar 2025 06:30:58 +0100 Subject: [PATCH 0526/1190] Fixed the MO part of the fix - do NOT hardcode to 512! --- src/disk/mo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index d59343833..c039695b5 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -1363,7 +1363,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_buf_alloc(dev, dev->packet_len); const int ret = mo_blocks(dev, &alloc_length, 0); - alloc_length = dev->requested_blocks * 512; + alloc_length = dev->requested_blocks * dev->drv->sector_size; if (ret > 0) { dev->requested_blocks = max_len; From a9c97abfb6ac90aff1c0d9ea7cf594a519ff374b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 20 Mar 2025 21:52:48 +0600 Subject: [PATCH 0527/1190] Pre-calculate `pow` table for FXTRACT instruction --- src/86box.c | 8 ++++++++ src/cpu/cpu.c | 3 +++ src/cpu/x87_ops.h | 2 ++ src/cpu/x87_ops_misc.h | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/86box.c b/src/86box.c index 5bf8177e8..310d0b5d3 100644 --- a/src/86box.c +++ b/src/86box.c @@ -32,6 +32,7 @@ #include #include #include +#include #ifndef _WIN32 # include @@ -233,6 +234,8 @@ extern int CPUID; extern int output; int atfullspeed; +extern double exp_pow_table[0x800]; + char exe_path[2048]; /* path (dir) of executable */ char usr_path[1024]; /* path (dir) of user data */ char cfg_path[1024]; /* full path of config file */ @@ -1086,6 +1089,11 @@ pc_init_modules(void) machine_status_init(); + for (c = 0; c <= 0x7ff; c++) { + int64_t exp = c - 1023; /* 1023 = BIAS64 */ + exp_pow_table[c] = pow(2.0, (double) exp); + } + if (do_nothing) { do_nothing = 0; exit(-1); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 41ca6932d..910d40765 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -287,6 +287,9 @@ uint8_t reg_30 = 0x00; uint8_t arr[24] = { 0 }; uint8_t rcr[8] = { 0 }; +/* Table for FXTRACT. */ +double exp_pow_table[0x800]; + static int cyrix_addr; static void cpu_write(uint16_t addr, uint8_t val, void *priv); diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 6a51a2c7f..0bd8209e1 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -36,6 +36,8 @@ extern void fpu_log(const char *fmt, ...); # endif #endif +extern double exp_pow_table[0x800]; + static int rounding_modes[4] = { FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO }; #define ST(x) cpu_state.ST[((cpu_state.TOP + (x)) & 7)] diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 4009eadd6..9a01f7496 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -46,7 +46,7 @@ opFXTRACT(UNUSED(uint32_t fetchdat)) test.eind.d = ST(0); exp80 = test.eind.ll & 0x7ff0000000000000LL; exp80final = (exp80 >> 52) - BIAS64; - mant = test.eind.d / (pow(2.0, (double) exp80final)); + mant = test.eind.d / exp_pow_table[exp80 >> 52]; ST(0) = (double) exp80final; FP_TAG_VALID; x87_push(mant); From 0ebadfb942a3233622a75e85ae3ea34e05053911 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 21 Mar 2025 03:29:46 +0100 Subject: [PATCH 0528/1190] CD-ROM, ATAPI HDD, MO, and ZIP: correct bus speed arithmetic, makes especially MO and ZIP much faster. --- src/disk/mo.c | 37 +++++++++++++------------------------ src/disk/zip.c | 37 +++++++++++++------------------------ src/scsi/scsi_cdrom.c | 7 ++++--- src/scsi/scsi_disk.c | 7 ++++++- 4 files changed, 36 insertions(+), 52 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index c039695b5..f1cd3b983 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -486,19 +486,16 @@ mo_bus_speed(mo_t *dev) { double ret = -1.0; - if (dev && dev->drv && (dev->drv->bus_type == MO_BUS_SCSI)) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (dev && dev->drv) - ret = ide_atapi_get_period(dev->drv->ide_channel); - if (ret == -1.0) { - if (dev) - dev->callback = -1.0; - return 0.0; - } else - return ret * 1000000.0; + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + + if (ret == -1.0) { + if (dev) + dev->callback = -1.0; + ret = 0.0; } + + return ret; } static void @@ -509,18 +506,10 @@ mo_command_common(mo_t *dev) dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; - else { - double bytes_per_second; - - if (dev->drv->bus_type == MO_BUS_SCSI) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return; - } else - bytes_per_second = mo_bus_speed(dev); - - const double period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); - } + else if (dev->drv->bus_type == MO_BUS_SCSI) + dev->callback = -1.0; /* Speed depends on SCSI controller */ + else + dev->callback = mo_bus_speed(dev) * (double) (dev->packet_len); mo_set_callback(dev); } diff --git a/src/disk/zip.c b/src/disk/zip.c index ed59154b0..eecafb802 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -567,19 +567,16 @@ zip_bus_speed(zip_t *dev) { double ret = -1.0; - if (dev && dev->drv && (dev->drv->bus_type == ZIP_BUS_SCSI)) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return 0.0; - } else { - if (dev && dev->drv) - ret = ide_atapi_get_period(dev->drv->ide_channel); - if (ret == -1.0) { - if (dev) - dev->callback = -1.0; - return 0.0; - } else - return ret * 1000000.0; + if (dev && dev->drv) + ret = ide_atapi_get_period(dev->drv->ide_channel); + + if (ret == -1.0) { + if (dev) + dev->callback = -1.0; + ret = 0.0; } + + return ret; } static void @@ -590,18 +587,10 @@ zip_command_common(zip_t *dev) dev->tf->pos = 0; if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0.0; - else { - double bytes_per_second; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) { - dev->callback = -1.0; /* Speed depends on SCSI controller */ - return; - } else - bytes_per_second = zip_bus_speed(dev); - - double period = 1000000.0 / bytes_per_second; - dev->callback = period * (double) (dev->packet_len); - } + else if (dev->drv->bus_type == ZIP_BUS_SCSI) + dev->callback = -1.0; /* Speed depends on SCSI controller */ + else + dev->callback = zip_bus_speed(dev) * (double) (dev->packet_len); zip_set_callback(dev); } diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index b35662eeb..9ae65be74 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -656,7 +656,7 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) dev->callback = -1.0; return 0.0; } else - return ret * 1000000.0; + return 1000000.0 / ret; } } @@ -1069,8 +1069,9 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int dev->block_len = temp_len; if ((dev->drv->bus_type != CDROM_BUS_SCSI) && - (scsi_cdrom_current_mode(dev) != 2)) + (scsi_cdrom_current_mode(dev) != 2)) { num = (dev->packet_len / dev->block_len); + } } dev->sector_pos++; @@ -1126,7 +1127,7 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev) } if (ret) { - if (!dev->sector_len) { + if (dev->sector_len == 0) { scsi_cdrom_command_complete(dev); return -1; } diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index a1afca2e2..8528db1fb 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -400,7 +400,8 @@ scsi_disk_bus_speed(scsi_disk_t *dev) dev->callback = -1.0; return 0.0; } else - return ret * 1000000.0; + /* We get bytes per µs, so divide 1000000.0 by it. */ + return 1000000.0 / ret; } } @@ -484,6 +485,10 @@ scsi_disk_command_common(scsi_disk_t *dev) break; } + /* + For ATAPI, this will be 1000000.0 / µs_per_byte, and this will + convert it back to µs_per_byte. + */ period = 1000000.0 / bytes_per_second; scsi_disk_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); From 63f106a0fd888d994dfae60244e36ae718a01551 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 00:49:20 +0100 Subject: [PATCH 0529/1190] Added plat_break() for raising breakpoints and warning() and log_warning() to raise visible non-fatal warnings to the user. --- src/86box.c | 69 +++++++++++++++++++++++++++++++++++++++ src/include/86box/86box.h | 7 ++-- src/include/86box/log.h | 1 + src/include/86box/plat.h | 1 + src/qt/qt_platform.cpp | 10 ++++++ src/utils/log.c | 25 ++++++++++++++ 6 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/86box.c b/src/86box.c index 310d0b5d3..dbf58a70e 100644 --- a/src/86box.c +++ b/src/86box.c @@ -440,6 +440,75 @@ fatal_ex(const char *fmt, va_list ap) fflush(stdlog); } +/* Log a warning error, and display a UI message without exiting. */ +void +warning(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) + *sp = '\0'; + + do_pause(2); + + ui_msgbox(MBX_ERROR | MBX_ANSI, temp); + + fflush(stdlog); + + do_pause(0); +} + +void +warning_ex(const char *fmt, va_list ap) +{ + char temp[1024]; + char *sp; + + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) + *sp = '\0'; + + do_pause(2); + + ui_msgbox(MBX_ERROR | MBX_ANSI, temp); + + fflush(stdlog); + + do_pause(0); +} + #ifdef ENABLE_PC_LOG int pc_do_log = ENABLE_PC_LOG; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 40e1f7927..174685c34 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -194,15 +194,12 @@ extern __thread int is_cpu_thread; /* Is this the CPU thread? */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); extern void fatal_ex(const char *fmt, va_list ap); +extern void warning_ex(const char *fmt, va_list ap); #endif extern void pclog_toggle_suppr(void); -#ifdef _MSC_VER -extern void pclog(const char *fmt, ...); -extern void fatal(const char *fmt, ...); -#else extern void pclog(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void fatal(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -#endif +extern void warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void set_screen_size(int x, int y); extern void set_screen_size_monitor(int x, int y, int monitor_index); extern void reset_screen_size(void); diff --git a/src/include/86box/log.h b/src/include/86box/log.h index a37bdec4f..e247ef9c5 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -36,6 +36,7 @@ extern void log_out(void *priv, const char *fmt, va_list); extern void log_out_cyclic(void* priv, const char *fmt, va_list); #endif /*RELEASE_BUILD*/ extern void log_fatal(void *priv, const char *fmt, ...); +extern void log_warning(void *priv, const char *fmt, ...); extern void *log_open(const char *dev_name); extern void *log_open_cyclic(const char *dev_name); extern void log_close(void *priv); diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 81874685e..7ed6e80d4 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -164,6 +164,7 @@ extern uint32_t plat_language_code(char *langcode); extern void plat_language_code_r(uint32_t lcid, char *outbuf, int len); extern void plat_get_cpu_string(char *outbuf, uint8_t len); extern void plat_set_thread_name(void *thread, const char *name); +extern void plat_break(void); /* Resource management. */ extern wchar_t *plat_get_string(int id); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index ebd6dc30c..1364750b1 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -842,3 +842,13 @@ plat_set_thread_name(void *thread, const char *name) # endif #endif } + +void +plat_break(void) +{ +#ifdef Q_OS_WINDOWS + DebugBreak(); +#else + raise(SIGTRAP); +#endif +} diff --git a/src/utils/log.c b/src/utils/log.c index c8dddf62e..257029b51 100644 --- a/src/utils/log.c +++ b/src/utils/log.c @@ -294,6 +294,31 @@ log_fatal(void *priv, const char *fmt, ...) exit(-1); } +void +log_warning(void *priv, const char *fmt, ...) +{ + log_t *log = (log_t *) priv; + char temp[1024]; + char fmt2[1024]; + va_list ap; + + if (log == NULL) + return; + + if (log->cyclic_buff != NULL) { + for (int i = 0; i < LOG_SIZE_BUFFER_CYCLIC_LINES; i++) + if (log->cyclic_buff[i] != NULL) + free(log->cyclic_buff[i]); + free(log->cyclic_buff); + } + + va_start(ap, fmt); + log_copy(log, fmt2, fmt, 1024); + vsprintf(temp, fmt2, ap); + warning_ex(fmt2, ap); + va_end(ap); +} + static void * log_open_common(const char *dev_name, const int cyclic) { From 81141c574ceb25b20faf221ba0877d2becb24530 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 02:14:31 +0100 Subject: [PATCH 0530/1190] #include on non-Windows platforms. --- src/qt/qt_platform.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 1364750b1..0df64c4dc 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -54,6 +54,10 @@ #include "qt_progsettings.hpp" #include "qt_util.hpp" +#ifndef Q_OS_WINDOWS +# include +#endif + #ifdef Q_OS_UNIX # include # include From 50e77917d5309ea69a606a3c8af03be15a9447c8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 23 Mar 2025 00:42:51 +0900 Subject: [PATCH 0531/1190] Fix for NetBSD --- src/CMakeLists.txt | 4 ++++ src/include/86box/86box.h | 5 +++++ src/include/86box/bswap.h | 6 ++---- src/include/86box/log.h | 5 +++++ src/qt/qt_platform.cpp | 2 +- src/unix/unix_serial_passthrough.c | 4 ++++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aac413aae..8cf67043f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -263,3 +263,7 @@ else() add_compile_definitions(USE_SDL_UI) add_subdirectory(unix) endif() + +if(CMAKE_SYSTEM_NAME MATCHES "NetBSD") + add_custom_command(TARGET 86Box POST_BUILD COMMAND paxctl ARGS +m $ COMMENT "Disable PaX MPROTECT") +endif() diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 174685c34..e8c5fbac9 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -20,6 +20,11 @@ #ifndef EMU_86BOX_H #define EMU_86BOX_H +#ifdef __NetBSD__ +/* Doesn't compile on NetBSD without this include */ +#include +#endif + /* Configuration values. */ #define GFXCARD_MAX 2 #define SERIAL_MAX 7 diff --git a/src/include/86box/bswap.h b/src/include/86box/bswap.h index 37c846d59..61a6a46a2 100644 --- a/src/include/86box/bswap.h +++ b/src/include/86box/bswap.h @@ -35,13 +35,12 @@ * USA. */ -#ifndef __NetBSD__ - #ifndef BSWAP_H #define BSWAP_H #include +#ifndef __NetBSD__ #define bswap_16(x) \ ((uint16_t)((((x) & 0x00ffu) << 8) | \ (((x) & 0xff00u) >> 8))) @@ -91,6 +90,7 @@ bswap64(uint64_t x) return bswap_16(x); #endif } +#endif static __inline void bswap16s(uint16_t *s) @@ -241,5 +241,3 @@ cpu_to_be32wu(uint32_t *p, uint32_t v) #undef be_bswaps #endif /*BSWAP_H*/ - -#endif diff --git a/src/include/86box/log.h b/src/include/86box/log.h index e247ef9c5..80ed6d108 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -24,6 +24,11 @@ extern "C" { # endif +#ifdef __NetBSD__ +/* Doesn't compile on NetBSD without this include */ +#include +#endif + #define LOG_SIZE_BUFFER 1024 /* Log size buffer */ #define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ #define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 0df64c4dc..e8a02fc3b 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -836,7 +836,7 @@ plat_set_thread_name(void *thread, const char *name) # if defined(Q_OS_DARWIN) pthread_setname_np(truncated); # elif defined(Q_OS_NETBSD) - pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, "%s"); + pthread_setname_np(thread ? *((pthread_t *) thread) : pthread_self(), truncated, (void*)"%s"); # elif defined(__HAIKU__) rename_thread(find_thread(NULL), truncated); # elif defined(Q_OS_OPENBSD) diff --git a/src/unix/unix_serial_passthrough.c b/src/unix/unix_serial_passthrough.c index a12346013..9929f3298 100644 --- a/src/unix/unix_serial_passthrough.c +++ b/src/unix/unix_serial_passthrough.c @@ -26,6 +26,7 @@ #endif #ifdef __NetBSD__ # define _NETBSD_VISIBLE 1 +# define _NETBSD_SOURCE 1 #endif #include #include @@ -149,8 +150,11 @@ plat_serpt_set_params(void *priv) BAUDRATE_RANGE(dev->baudrate, 9600, 19200, B9600); BAUDRATE_RANGE(dev->baudrate, 19200, 38400, B19200); BAUDRATE_RANGE(dev->baudrate, 38400, 57600, B38400); +#ifndef __NetBSD__ + /* nonexistent on NetBSD */ BAUDRATE_RANGE(dev->baudrate, 57600, 115200, B57600); BAUDRATE_RANGE(dev->baudrate, 115200, 0xFFFFFFFF, B115200); +#endif term_attr.c_cflag &= ~CSIZE; switch (dev->data_bits) { From a19c99eb64c85a455ad81a693fc46e5919ff5db8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 23 Mar 2025 01:19:57 +0900 Subject: [PATCH 0532/1190] Fix JP translation --- src/qt/languages/ja-JP.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 9c6fa66e7..6132a8db1 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -868,7 +868,7 @@ msgid "Hardware not available" msgstr "ハードウェアが利用できません" msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." -msgstr "がインストールされてるか、%1に対応したネットワークに接続されてるか確認してください。" +msgstr "%1がインストールされていてかつ、%1に対応したネットワークに接続されてるか確認してください。" msgid "Invalid configuration" msgstr "不正な設定です" @@ -910,10 +910,10 @@ msgid "OpenGL options" msgstr "OpenGL設定" msgid "You are loading an unsupported configuration" -msgstr "読み込んでいる設定がサポートされません" +msgstr "サポートされていないコンフィグを読み込んでいます" msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." -msgstr "選択したマシンに基づくCPUタイプのフィルター機能は、使用中のマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。しかし、マシンのBIOSや他のソフトウェアと互換性がない場合があります。\n\nこの設定を有効にすることは公式にはサポートされておらず、バグレポートは無効として中止される可能性があります。" +msgstr "選択したマシンに基づくCPUタイプのフィルター機能は、使用中のマシンでは無効になっています。\n\nこれにより、選択したマシンと互換性のないCPUが選択できます。しかし、マシンのBIOSや他のソフトウェアと互換性がない場合があります。\n\nこの設定を有効にすることは公式にはサポートされておらず、バグレポートは無効としてクローズされる可能性があります。" msgid "Continue" msgstr "続行" @@ -1015,7 +1015,7 @@ msgid "The selected file will be overwritten. Are you sure you want to use it?" msgstr "選択したファイルは上書きされます。よろしいですか?" msgid "Unsupported disk image" -msgstr "非対応のディスクイメージジ" +msgstr "非対応のディスクイメージ" msgid "Overwrite" msgstr "上書き" @@ -1285,7 +1285,7 @@ msgid "Host CD/DVD Drive (%1)" msgstr "ホスト CD/DVD ドライブ (%1)" msgid "Unknown Bus" -msgstr "不明バス" +msgstr "不明なバス" msgid "Null Driver" msgstr "ヌル・ドライバー" @@ -1294,7 +1294,7 @@ msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" msgid "Error opening \"%1\": %2" -msgstr "エラー・オープニング\"%1\": %2" +msgstr "\"%1\"を開く際にエラーが発生しました: %2" msgid "Error compiling vertex shader in file \"%1\"" msgstr "ファイル\"%1\"の頂点シェーダのコンパイルエラー。" From c3d15ef36d183cb54df75466de5bb26fd38ce8d8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 19:45:32 +0100 Subject: [PATCH 0533/1190] EGA and JEGA: Implement some missing SuperEGA stuff and make the JEGA properly set the EGA type to SuperEGA, fixes #5370. --- src/include/86box/vid_ega.h | 1 + src/video/vid_ega.c | 69 +++++++++++++++++++++++++++++++++---- src/video/vid_jega.c | 2 +- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 082cb120a..5ff7d3871 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -178,6 +178,7 @@ extern uint8_t ega_in(uint16_t addr, void *priv); extern void ega_poll(void *priv); extern void ega_write(uint32_t addr, uint8_t val, void *priv); extern uint8_t ega_read(uint32_t addr, void *priv); +extern void ega_set_type(void *priv, uint32_t local); extern int firstline_draw; extern int lastline_draw; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 781e9a9dd..18a53a127 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -67,6 +67,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega_t *ega = (ega_t *) priv; uint8_t o; uint8_t old; + uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t crtcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x1f; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -200,8 +202,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->gdcaddr = val; break; case 0x3cf: - ega->gdcreg[ega->gdcaddr & 15] = val; - switch (ega->gdcaddr & 15) { + ega->gdcreg[ega->gdcaddr & gdcmask] = val; + switch (ega->gdcaddr & gdcmask) { case 2: ega->colourcompare = val; break; @@ -238,6 +240,19 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->colournocare = val; break; + case 0xf8: + ega->la = val; + break; + case 0xf9: + ega->lb = val; + break; + case 0xfa: + ega->lc = val; + break; + case 0xfb: + ega->ld = val; + break; + default: break; } @@ -247,7 +262,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if (ega->chipset) ega->crtcreg = val & 0x3f; else - ega->crtcreg = val & 0x1f; + ega->crtcreg = val & crtcmask; return; case 0x3d1: case 0x3d5: @@ -286,7 +301,8 @@ uint8_t ega_in(uint16_t addr, void *priv) { ega_t *ega = (ega_t *) priv; - uint8_t ret = 0xff; + uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t ret = 0xff; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -347,8 +363,25 @@ ega_in(uint16_t addr, void *priv) ret = ega->gdcaddr; break; case 0x3cf: - if (ega_type == EGA_TYPE_OTHER) - ret = ega->gdcreg[ega->gdcaddr & 0xf]; + if (ega_type == EGA_TYPE_OTHER) { + switch (ega->gdcaddr & gdcmask) { + default: + ret = ega->gdcreg[ega->gdcaddr & gdcmask]; + break; + case 0xf8: + ret = ega->la; + break; + case 0xf9: + ret = ega->lb; + break; + case 0xfa: + ret = ega->lc; + break; + case 0xfb: + ret = ega->ld; + break; + } + } break; case 0x3d0: case 0x3d4: @@ -1428,6 +1461,30 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) timer_add(&ega->dot_timer, ega_dot_poll, ega, 1); } +void +ega_set_type(void *priv, uint32_t local) +{ + ega_t *ega = (ega_t *) priv; + + if ((local == EGA_IBM) || (local == EGA_ISKRA) || (local == EGA_TSENG)) + ega_type = EGA_TYPE_IBM; + else if (local == EGA_COMPAQ) + ega_type = EGA_TYPE_COMPAQ; + else + ega_type = EGA_TYPE_OTHER; + + ega->actual_type = local; + ega->chipset = 0; + + switch (local) { + default: + break; + case EGA_ATI800P: + ega->chipset = 1; + break; + } +} + static void * ega_standalone_init(const device_t *info) { diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index c410a15da..145579cf5 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -632,7 +632,7 @@ jega_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); jega->pallook = pallook64; ega_init(&jega->ega, 9, 0); - jega->ega.actual_type = EGA_SUPEREGA; + ega_set_type(&jega->ega, EGA_SUPEREGA); jega->ega.priv_parent = jega; mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); From 5fe9cc76da31fdef1bf598967d7db565ed12d480 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 20:44:56 +0100 Subject: [PATCH 0534/1190] SuperEGA: Increase the GDC and CRTC register arrays to 256 elements to prevent overflows and correctly ignore the upper 3 bits of CRTC register 07h in ega_recalctimings(), fixes #4905. --- src/video/vid_ega.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 18a53a127..17fea7b81 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -486,19 +486,19 @@ ega_recalctimings(ega_t *ega) if (ega->crtc[7] & 1) ega->vtotal |= 0x100; - if (ega->crtc[7] & 32) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 32)) ega->vtotal |= 0x200; ega->vtotal += 2; if (ega->crtc[7] & 2) ega->dispend |= 0x100; - if (ega->crtc[7] & 64) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 64)) ega->dispend |= 0x200; ega->dispend++; if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; - if (ega->crtc[7] & 128) + if ((ega->actual_type != EGA_SUPEREGA) && (ega->crtc[7] & 128)) ega->vsyncstart |= 0x200; ega->vsyncstart++; From fb0704de993e36efce50ec731df13386a696c4d6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 21:23:07 +0100 Subject: [PATCH 0535/1190] Forgot vid_ega.h. --- src/include/86box/vid_ega.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 5ff7d3871..79375a2ae 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -47,8 +47,8 @@ typedef struct ega_t { uint8_t ctl_mode; uint8_t color_mux; uint8_t dot; - uint8_t crtc[32]; - uint8_t gdcreg[16]; + uint8_t crtc[256]; + uint8_t gdcreg[256]; uint8_t attrregs[32]; uint8_t seqregs[64]; uint8_t egapal[16]; From 2151a6064feaa9293889a5c014534ff1925b9e58 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 22 Mar 2025 23:57:05 +0100 Subject: [PATCH 0536/1190] SuperEGA: Implement row and vertical divide modes. --- src/include/86box/vid_ega.h | 1 + src/video/vid_ega.c | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 79375a2ae..4b7d32ea0 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -73,6 +73,7 @@ typedef struct ega_t { int oddeven_page; int oddeven_chain; int vc; + int real_vc; int sc; int dispon; int hdisp_on; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 17fea7b81..c7345cd00 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -620,11 +620,15 @@ ega_recalctimings(ega_t *ega) ega->y_add >>= 1; if (ega->seqregs[1] & 8) { - disptime = (double) ((ega->crtc[0] + 2) << 1); - _dispontime = (double) ((ega->crtc[1] + 1) << 1); + disptime = (double) ((ega->crtc[0] + 2) << 1); + _dispontime = (double) ((ega->crtc[1] + 1) << 1); } else { - disptime = (double) (ega->crtc[0] + 2); - _dispontime = (double) (ega->crtc[1] + 1); + disptime = (double) (ega->crtc[0] + 2); + _dispontime = (double) (ega->crtc[1] + 1); + } + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x01)) { + disptime *= 2.0; + _dispontime *= 2.0; } _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; @@ -852,7 +856,10 @@ ega_poll(void *priv) ega->cca = ega->maback; } } - ega->vc++; + ega->real_vc++; + if ((ega->actual_type != EGA_SUPEREGA) || !(ega->crtc[0xf9] & 0x02) || + !(ega->real_vc & 1)) + ega->vc++; if (ega->chipset) { if (ega->hdisp > 640) ega->vc &= 1023; @@ -905,9 +912,13 @@ ega_poll(void *priv) if (ega->vres) { wy = (ega->lastline - ega->firstline) << 1; + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x02)) + wy >>= 1; ega_doblit(wx, wy, ega); } else { wy = ega->lastline - ega->firstline; + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x02)) + wy >>= 1; ega_doblit(wx, wy, ega); } From 646e25f1bc524f21fc6a74045986142652c1cb21 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:22:10 +0100 Subject: [PATCH 0537/1190] EGA: Implement monochrome attributes for text mode. --- src/video/vid_ega.c | 20 ++++++++++++++++++++ src/video/vid_ega_render.c | 12 ++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index c7345cd00..438d5c98d 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1447,6 +1447,26 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) ega->pallook = pallook16; + for (uint16_t c = 0; c < 256; c++) { + ega->mdacols[c][0][0] = ega->mdacols[c][1][0] = ega->mdacols[c][1][1] = 16; + if (c & 8) + ega->mdacols[c][0][1] = 15 + 16; + else + ega->mdacols[c][0][1] = 7 + 16; + } + ega->mdacols[0x70][0][1] = 16; + ega->mdacols[0x70][0][0] = ega->mdacols[0x70][1][0] = ega->mdacols[0x70][1][1] = 16 + 15; + ega->mdacols[0xF0][0][1] = 16; + ega->mdacols[0xF0][0][0] = ega->mdacols[0xF0][1][0] = ega->mdacols[0xF0][1][1] = 16 + 15; + ega->mdacols[0x78][0][1] = 16 + 7; + ega->mdacols[0x78][0][0] = ega->mdacols[0x78][1][0] = ega->mdacols[0x78][1][1] = 16 + 15; + ega->mdacols[0xF8][0][1] = 16 + 7; + ega->mdacols[0xF8][0][0] = ega->mdacols[0xF8][1][0] = ega->mdacols[0xF8][1][1] = 16 + 15; + ega->mdacols[0x00][0][1] = ega->mdacols[0x00][1][1] = 16; + ega->mdacols[0x08][0][1] = ega->mdacols[0x08][1][1] = 16; + ega->mdacols[0x80][0][1] = ega->mdacols[0x80][1][1] = 16; + ega->mdacols[0x88][0][1] = ega->mdacols[0x88][1][1] = 16; + egaswitches = monitor_type & 0xf; ega->vram_limit = 256 * 1024; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index fe2632574..d499154e6 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -118,6 +118,7 @@ ega_render_text(ega_t *ega) const bool doublewidth = ((ega->seqregs[1] & 8) != 0); const bool attrblink = ((ega->attrregs[0x10] & 8) != 0); const bool attrlinechars = (ega->attrregs[0x10] & 4); + const bool monoattrs = (ega->attrregs[0x10] & 2); const bool crtcreset = ((ega->crtc[0x17] & 0x80) == 0); const bool seq9dot = ((ega->seqregs[1] & 1) == 0); const int dwshift = doublewidth ? 1 : 0; @@ -174,8 +175,15 @@ ega_render_text(ega_t *ega) if ((chr & ~0x1F) == 0xC0 && attrlinechars) dat |= (dat >> 1) & 1; - for (int xx = 0; xx < charwidth; xx++) - p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; + for (int xx = 0; xx < charwidth; xx++) { + if (monoattrs) { + if ((ega->sc == (ega->crtc[0x14] + 1)) && ((attr & 7) == 1)) + p[xx] = ega->mdacols[attr][attrblink][1]; + else + p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; + } else + p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; + } ega->ma += 4; p += charwidth; From ae60590133a28a873ef5d974ff6d52db34bdf0ea Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:26:03 +0100 Subject: [PATCH 0538/1190] EGA: Fix underline position. --- src/video/vid_ega_render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index d499154e6..af2402414 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -177,7 +177,7 @@ ega_render_text(ega_t *ega) for (int xx = 0; xx < charwidth; xx++) { if (monoattrs) { - if ((ega->sc == (ega->crtc[0x14] + 1)) && ((attr & 7) == 1)) + if ((ega->sc == ega->crtc[0x14]) && ((attr & 7) == 1)) p[xx] = ega->mdacols[attr][attrblink][1]; else p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; From 47aa4a1e1881bbe669f477399f3f2bc6d9d83c3b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 02:29:41 +0100 Subject: [PATCH 0539/1190] EGA: Process the results of the monochrome attributes into 32-bit RGB values. --- src/video/vid_ega_render.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index af2402414..dd393e4b6 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -189,6 +189,9 @@ ega_render_text(ega_t *ega) p += charwidth; } ega->ma &= 0x3ffff; + + if (monoattrs) + video_process_8(ega->hdisp + ega->scrollcache, ega->displine); } } From 2ff31188c2ae62475e5c04f1886c7b9c131ec5ab Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 06:57:40 +0100 Subject: [PATCH 0540/1190] CGA: Fix rounding in the interpolation calculation. --- src/video/vid_cga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index f439cb1d8..a24162019 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -442,7 +442,7 @@ cga_interpolate_linear(uint8_t co1, uint8_t co2, double fraction) r2 = pow((r1 >= 0.0) ? r1 : -r1, 1.0 / 2.19921875); if (r1 <= 0.0) r2 = -r2; - ret = (uint8_t) (r2 * 255.0); + ret = (uint8_t) round(r2 * 255.0); return ret; } From c5efce619f49b58a67ed45123c970bb43d4dd275 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 07:14:52 +0100 Subject: [PATCH 0541/1190] And the forgotten vid_ega.h. --- src/include/86box/vid_ega.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 4b7d32ea0..5ac5c24e3 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -53,7 +53,6 @@ typedef struct ega_t { uint8_t seqregs[64]; uint8_t egapal[16]; uint8_t regs[256]; - uint8_t *vram; uint16_t light_pen; @@ -114,6 +113,9 @@ typedef struct ega_t { int remap_required; int actual_type; int chipset; + int mono_display; + + int mdacols[256][2][2]; uint32_t charseta; uint32_t charsetb; From c65b7bda6621b4ba98cbf4bc24f3d4d477dcb3de Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Sun, 23 Mar 2025 14:26:07 +0100 Subject: [PATCH 0542/1190] IBM PS/2 Model 30-286 fixes the real machine supports 512 KB RAM configurations and ISA video cards --- src/machine/machine_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..c253bc029 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2756,11 +2756,11 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, + .flags = MACHINE_XTA | MACHINE_VIDEO, .ram = { - .min = 1024, + .min = 512, .max = 16384, - .step = 1024 + .step = 512 }, .nvrmask = 127, .kbc_device = NULL, From 609f34cc492ad670bcba59f11c3092a156b3d628 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 23 Mar 2025 15:36:05 +0100 Subject: [PATCH 0543/1190] Only flush write MMU cache on WP flag toggle as read and execute MMU cache is not affected by the flag. --- src/cpu/x86_ops_mov_ctrl.h | 10 ++++++---- src/cpu/x86_ops_mov_ctrl_2386.h | 10 ++++++---- src/include/86box/mem.h | 1 + src/mem/mem.c | 15 +++++++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index b4f0c498a..253dc059e 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -184,7 +184,7 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { if (is_p6 || cpu_use_dynarec) @@ -193,7 +193,8 @@ opMOV_CRx_r_a16(uint32_t fetchdat) flushmmucache_nopc(); cpu_flush_pending = 1; } - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; @@ -249,7 +250,7 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { if (is_p6 || cpu_use_dynarec) @@ -258,7 +259,8 @@ opMOV_CRx_r_a32(uint32_t fetchdat) flushmmucache_nopc(); cpu_flush_pending = 1; } - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; diff --git a/src/cpu/x86_ops_mov_ctrl_2386.h b/src/cpu/x86_ops_mov_ctrl_2386.h index 13e08a145..8827d29b2 100644 --- a/src/cpu/x86_ops_mov_ctrl_2386.h +++ b/src/cpu/x86_ops_mov_ctrl_2386.h @@ -180,12 +180,13 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { flushmmucache_nopc(); cpu_flush_pending = 1; - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; @@ -241,12 +242,13 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & (0x00000001 | WP_FLAG)) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { flushmmucache_nopc(); cpu_flush_pending = 1; - } + } else if ((cpu_state.regs[cpu_rm].l ^ cr0) & WP_FLAG) + flushmmucache_write(); /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 19a331925..81b46b2fa 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -448,6 +448,7 @@ extern void mem_flush_write_page(uint32_t addr, uint32_t virt); extern void mem_reset_page_blocks(void); extern void flushmmucache(void); +extern void flushmmucache_write(void); extern void flushmmucache_pc(void); extern void flushmmucache_nopc(void); diff --git a/src/mem/mem.c b/src/mem/mem.c index d85b20581..94c4ab788 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -225,6 +225,21 @@ flushmmucache(void) #endif } +void +flushmmucache_write(void) +{ + for (uint16_t c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + page_lookupp[writelookup[c]] = 4; + writelookup2[writelookup[c]] = LOOKUP_INV; + writelookupp[writelookup[c]] = 4; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; +} + void flushmmucache_pc(void) { From 8cc81683f7da568a4d7bad14889eb0370d887797 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Sun, 23 Mar 2025 15:48:47 +0100 Subject: [PATCH 0544/1190] Change back to fixed video, apparently 86Box had it set to fixed due to bugs in 86Box itself --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c253bc029..b38e42310 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2756,7 +2756,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_XTA | MACHINE_VIDEO, + .flags = MACHINE_XTA | MACHINE_VIDEO_FIXED, .ram = { .min = 512, .max = 16384, From 97707a9831d1b435b32d36a6cd24251dfefb4c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sun, 23 Mar 2025 16:18:48 +0100 Subject: [PATCH 0545/1190] net_modem: fix response to unrecognized will/wont telnet commands --- src/network/net_modem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/network/net_modem.c b/src/network/net_modem.c index a8eab4290..af97a16db 100644 --- a/src/network/net_modem.c +++ b/src/network/net_modem.c @@ -1177,9 +1177,15 @@ modem_process_telnet(modem_t *modem, uint8_t *data, uint32_t size) uint8_t c = data[i]; if (modem->telClient.inIAC) { if (modem->telClient.recCommand) { + modem_log("modem_process_telnet: received command %i, option %i\n", modem->telClient.command, c); + if ((c != 0) && (c != 1) && (c != 3)) { - if (modem->telClient.command > 250) { - /* Reject anything we don't recognize */ + /* Reject anything we don't recognize */ + if (modem->telClient.command == 251 || modem->telClient.command == 252) { + modem_data_mode_process_byte(modem, 0xff); + modem_data_mode_process_byte(modem, 254); + modem_data_mode_process_byte(modem, c); /* Don't do crap! */ + } else if (modem->telClient.command == 253 || modem->telClient.command == 254) { modem_data_mode_process_byte(modem, 0xff); modem_data_mode_process_byte(modem, 252); modem_data_mode_process_byte(modem, c); /* We won't do crap! */ From 512c04c9f4443f7a1c3b7147d13acb18819de04f Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 00:56:34 +0900 Subject: [PATCH 0546/1190] Add OKI if386AX emulation (#7) * add a machine oki if386ax * if386AX: still in debug * Revert "if386AX: still in debug" This reverts commit ade401beb0c72cee6fd1ec4728097a87e75bc09b. * if386ax: added I/O 6xh * if386ax: remove comment * formatting, sorting, change filename * change mono color palette --- src/include/86box/machine.h | 1 + src/include/86box/video.h | 3 + src/machine/m_at_286_386sx.c | 25 +++++ src/machine/machine_table.c | 38 ++++++++ src/video/vid_ega.c | 6 +- src/video/vid_jega.c | 171 ++++++++++++++++++++++++++++++----- 6 files changed, 216 insertions(+), 28 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index d1257d94c..21e4a89e2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -483,6 +483,7 @@ extern int machine_at_adi386sx_init(const machine_t *); extern int machine_at_cmdsl386sx16_init(const machine_t *); extern int machine_at_cmdsl386sx25_init(const machine_t *); extern int machine_at_dataexpert386sx_init(const machine_t *); +extern int machine_at_if386sx_init(const machine_t *); extern int machine_at_spc6033p_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); extern int machine_at_arb1374_init(const machine_t *); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 2985559e1..6cf9c8d59 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -456,6 +456,9 @@ extern const device_t millennium_ii_device; extern const device_t productiva_g100_device; #endif /* USE_G100 */ +/* JEGA */ +extern const device_t if386jega_device; + /* Oak OTI-0x7 */ extern const device_t oti037c_device; extern const device_t oti067_device; diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index fd9cc3bcd..2f35427be 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -641,6 +641,31 @@ machine_at_cmdsl386sx16_init(const machine_t *model) return ret; } +int +machine_at_if386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/if386sx/OKI_IF386SX_odd.bin", + "roms/machines/if386sx/OKI_IF386SX_even.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&keyboard_at_device); + + device_add(&neat_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(&if386jega_device); + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + static void machine_at_scamp_common_init(const machine_t *model, int is_ps2) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..ce95b5fc8 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4746,6 +4746,44 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { .name = "[NEAT] OKI if386AX30L", + .internal_name = "if386sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_NEAT, + .init = machine_at_if386sx_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 4096, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has IBM AT KBC firmware. */ { .name = "[OPTi 291] DTK PPM-3333P", diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 438d5c98d..16a3552ad 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -47,9 +47,9 @@ void ega_doblit(int wx, int wy, ega_t *ega); static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; static uint8_t ega_rotate[8][256]; -static int active = 0; -static uint32_t pallook16[256]; -static uint32_t pallook64[256]; +static int active = 0; +uint32_t pallook16[256]; +uint32_t pallook64[256]; static int ega_type = EGA_TYPE_IBM; static int old_overscan_color = 0; diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 145579cf5..edf7358a6 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -60,6 +60,7 @@ #define RINVALID_INDEX 0x30 #define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" +#define IF386_PATH_VBIOS "roms/video/jega/OKI_IF386SX_VBIOS.bin" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 @@ -137,7 +138,8 @@ typedef struct { uint16_t end; } fontx_tbl; -static uint32_t pallook64[256]; +extern uint32_t pallook16[256]; +extern uint32_t pallook64[256]; static bool is_SJIS_1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } @@ -615,8 +617,27 @@ LoadFontxFile(const char *fn, void *priv) return 0; } +static void +jega_commoninit(void *priv) +{ + jega_t *jega = (jega_t *) priv; + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); + jega->pallook = pallook64; + ega_init(&jega->ega, 9, 0); + ega_set_type(&jega->ega, EGA_SUPEREGA); + jega->ega.priv_parent = jega; + mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); + /* I/O 3DD and 3DE are used by Oki if386 */ + io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + jega->regs[RMOD1] = 0x48; +} + static void * -jega_init(const device_t *info) +jega_standalone_init(const device_t *info) { jega_t *jega = calloc(1, sizeof(jega_t)); @@ -624,21 +645,7 @@ jega_init(const device_t *info) memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); LoadFontxFile(JEGA_PATH_FONTDBCS, jega); - for (int c = 0; c < 256; c++) { - pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); - pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); - } - - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); - jega->pallook = pallook64; - ega_init(&jega->ega, 9, 0); - ega_set_type(&jega->ega, EGA_SUPEREGA); - jega->ega.priv_parent = jega; - mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); - - io_sethandler(0x03b0, 0x0030, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); - - jega->regs[RMOD1] = 0x48; + jega_commoninit(jega); return jega; } @@ -665,10 +672,10 @@ jega_close(void *priv) fprintf(f, "Regs %02X: %4X\n", i, jega->regs[i]); for (int i = 0; i < 32; i++) fprintf(f, "Attr %02X: %4X\n", i, jega->attrregs[i]); - for (int i = 0; i < 16; i++) - fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); - for (int i = 0; i < 16; i++) - fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "JEGAPal %02X: %4X\n", i, jega->egapal[i]); + for (int i = 0; i < 16; i++) + fprintf(f, "EGAPal %02X: %4X\n", i, jega->ega.egapal[i]); for (int i = 0; i < 64; i++) fprintf(f, "RealPal %02X: %4X\n", i, jega->pallook[i]); fclose(f); @@ -683,7 +690,7 @@ jega_close(void *priv) fwrite(&ram[0x0], 0x500, 1, f); fclose(f); } - // jega_log("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); + pclog("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); #endif if (jega->ega.eeprom) free(jega->ega.eeprom); @@ -706,7 +713,7 @@ jega_speed_changed(void *priv) } static int -jega_available(void) +jega_standalone_available(void) { return (rom_present(JEGA_PATH_BIOS) && rom_present(JEGA_PATH_FONTDBCS)); } @@ -716,10 +723,124 @@ const device_t jega_device = { .internal_name = "jega", .flags = DEVICE_ISA, .local = 0, - .init = jega_init, + .init = jega_standalone_init, .close = jega_close, .reset = NULL, - .available = jega_available, + .available = jega_standalone_available, + .speed_changed = jega_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + +static uint8_t p65idx = 0; +static uint8_t p3de_idx = 0; +static uint8_t p65[6]; +static uint8_t p3de[0x30]; + + +static uint8_t +if386_p6x_read(uint16_t port, void *priv) +{ + uint8_t ret = INVALIDACCESS8; + if (port == 0x63) { + ret = p65idx; + } else if (port == 0x65) { + ret = p65[p65idx]; + } + // pclog("p%x_r: [%04x:%04x] [%02x]%02x\n", port, cs >> 4, cpu_state.pc , p65idx, ret); + return ret; +} + +/* + OKi if386AX/SX Power management and Miscellaneous + I/O 63h: Index 0-5, I/O 65h: Data + Index 2: + Bit 3: Caps Lock enabled + Bit 2: Num Lock enabled + Bit 1: Scrl Lock enabled + Bit 0: Kana Lock enabled + Index 3 + Bit 2: External monitor output enabled + Bit 1: Floppy drive 1 active + Bit 0: Floppy drive 0 active + Index 5 + Bit 8: ? (1=Disabled, 0=Enabled) + Bit 7: Screen Off? (enabled by Ctrl + Alt + [1] and disabled by any key) + Bit 4: Shutdown? (caused by POST rebooting and POWER OFF command in DOS 3.21) + Bit 3: ? +*/ +static void +if386_p6x_write(uint16_t port, uint8_t val, void *priv) +{ + jega_t *jega = (jega_t *) priv; + // pclog("p%x_w: [%04x:%04x] val=%02x\n", port, cs >> 4, cpu_state.pc, val); + if (port == 0x63 && val < 6) + p65idx = val; + if (port == 0x65) { + // pclog("p65_w: [%04x:%04x] idx=%02x, val=%02x\n", cs >> 4, cpu_state.pc, p65idx, val); + p65[p65idx] = val; + if (p65idx == 0x03) { + if (val & 0x04) { /* Color monitor */ + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + } else { /* Monochrome LCD */ + for (int c = 0; c < 256; c++) { + int cval = 0; + if (c & 0x0f) + cval = ((c & 0x0e) * 0x10) + 0x1f; + pallook64[c] = makecol32(cval, cval, cval); + pallook16[c] = makecol32(cval, cval, cval); + } + } + jega_recalctimings(jega); + } else if (p65idx == 0x05) { + if (val & 0x10) { /* Power off (instead this call hardware reset here) */ + resetx86(); + } + } + } + return; +} + +static void * +if386jega_init(const device_t *info) +{ + jega_t *jega = calloc(1, sizeof(jega_t)); + + rom_init(&jega->bios_rom, IF386_PATH_VBIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); + memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); + LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + + jega_commoninit(jega); + + io_sethandler(0x0063, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + io_sethandler(0x0065, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + // io_sethandler(0x03dd, 2, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); + + return jega; +} + +static int +if386jega_available(void) +{ + return (rom_present(IF386_PATH_VBIOS) && rom_present(JEGA_PATH_FONTDBCS)); +} + +const device_t if386jega_device = { + .name = "JEGA (if386AX)", + .internal_name = "if386jega", + .flags = DEVICE_ISA, + .local = 0, + .init = if386jega_init, + .close = jega_close, + .reset = NULL, + .available = if386jega_available, .speed_changed = jega_speed_changed, .force_redraw = NULL, .config = NULL From fe0c246bd2e1bd97dce427e873b896cc8fbc6227 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:33:58 +0900 Subject: [PATCH 0547/1190] if386sx: change rom file path --- src/video/vid_jega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index edf7358a6..f9bcb6918 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -60,8 +60,8 @@ #define RINVALID_INDEX 0x30 #define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" -#define IF386_PATH_VBIOS "roms/video/jega/OKI_IF386SX_VBIOS.bin" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" +#define IF386_PATH_VBIOS "roms/machines/if386sx/OKI_IF386SX_VBIOS.bin" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 #define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2) From 861d942657dc5f8484f5ed2fad331c1687737346 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 11:03:04 +0900 Subject: [PATCH 0548/1190] Adding skeleton that at least compiles for audio4.c --- CMakeLists.txt | 4 ++++ src/sound/CMakeLists.txt | 5 +++- src/sound/audio4.c | 51 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/sound/audio4.c diff --git a/CMakeLists.txt b/CMakeLists.txt index fb71553e2..55cbec8b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,10 @@ else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) endif() +if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) + set(AUDIO4 ON) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index a381051ba..955e96f5a 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -53,7 +53,10 @@ add_library(snd OBJECT snd_opl_esfm.c ) -if(OPENAL) +# TODO: Should platform-specific audio driver be here? +if(AUDIO4) + target_sources(snd PRIVATE audio4.c) +elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) elseif(MINGW) diff --git a/src/sound/audio4.c b/src/sound/audio4.c new file mode 100644 index 000000000..3b3d4a429 --- /dev/null +++ b/src/sound/audio4.c @@ -0,0 +1,51 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Interface to audio(4). + * + * + * + * Authors: Nishi + * + * Copyright 2025 Nishi. + */ +#include + +#include <86box/sound.h> + +#define FREQ SOUND_FREQ +#define BUFLEN SOUNDBUFLEN + +static int midi_freq = 44100; +static int midi_buf_size = 4410; + +void closeal(void){ +} + +void inital(void){ +} + +void givealbuffer(const void *buf){ +} + +void givealbuffer_music(const void *buf){ +} + +void givealbuffer_wt(const void *buf){ +} + +void givealbuffer_cd(const void *buf){ +} + +void givealbuffer_midi(const void *buf, const uint32_t size){ +} + +void al_set_midi(const int freq, const int buf_size){ + midi_freq = freq; + midi_buf_size = buf_size; +} From 56d0cbb09336f3f426b5c72c945b39cf0fd4c393 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 06:32:02 +0100 Subject: [PATCH 0549/1190] Different CPU's for the two V-Tech machines. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bae9de29f..99f6e26a2 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1760,7 +1760,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8088, + .package = CPU_PKG_8088_VTECH, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, @@ -2623,7 +2623,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8086, + .package = CPU_PKG_8086_VTECH, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, From 7056c83bbb7c444fbdb55ea4a51382f77d7faa36 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 17:41:04 +0900 Subject: [PATCH 0550/1190] Add working NetBSD sound support --- src/sound/audio4.c | 104 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 3b3d4a429..e7b7dcf33 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -6,8 +6,8 @@ * * This file is part of the 86Box distribution. * - * Interface to audio(4). - * + * Interface to audio(4) for NetBSD/OpenBSD. + * TODO: Test on OpenBSD * * * Authors: Nishi @@ -15,37 +15,121 @@ * Copyright 2025 Nishi. */ #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <86box/86box.h> #include <86box/sound.h> +#include <86box/plat_unused.h> -#define FREQ SOUND_FREQ -#define BUFLEN SOUNDBUFLEN +#define I_NORMAL 0 +#define I_MUSIC 1 +#define I_WT 2 +#define I_CD 3 +#define I_MIDI 4 -static int midi_freq = 44100; -static int midi_buf_size = 4410; +static int audio[5] = {-1, -1, -1, -1, -1}; +static audio_offset_t offset[5]; +static audio_info_t info[5]; +static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; void closeal(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + if(audio[i] != -1){ + close(audio[i]); + } + audio[i] = -1; + } } void inital(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + audio[i] = open("/dev/audio", O_WRONLY); + if(audio[i] != -1){ + AUDIO_INITINFO(&info[i]); +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) + ioctl(audio[i], AUDIO_GETFORMAT, &info[i]); +#else + ioctl(audio[i], AUDIO_GETINFO, &info[i]); +#endif + info[i].play.channels = 2; + info[i].play.precision = 16; + info[i].play.encoding = AUDIO_ENCODING_SLINEAR; + info[i].hiwat = 5; + info[i].lowat = 3; + ioctl(audio[i], AUDIO_SETINFO, &info[i]); + } + } +} + +void givealbuffer_common(const void *buf, const uint8_t src, const int size){ + const int freq = freqs[src]; + int16_t* output; + int output_size; + int16_t* conv; + int conv_size; + int i; + double gain; + if(audio[src] == -1) return; + + gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + + if(sound_is_float){ + float* input = (float*)buf; + conv_size = sizeof(int16_t) * size; + conv = malloc(conv_size); + for(i = 0; i < conv_size / sizeof(int16_t); i++){ + conv[i] = 32767 * input[i]; + } + }else{ + conv_size = size * sizeof(int16_t); + conv = malloc(conv_size); + memcpy(conv, buf, conv_size); + } + + output_size = (double)conv_size * info[src].play.sample_rate / freq; + output = malloc(output_size); + + for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ + int ind = i * freq / info[src].play.sample_rate * 2; + output[i * 2 + 0] = conv[ind + 0] * gain; + output[i * 2 + 1] = conv[ind + 1] * gain; + } + + write(audio[src], output, output_size); + + free(conv); + free(output); } void givealbuffer(const void *buf){ + givealbuffer_common(buf, I_NORMAL, SOUNDBUFLEN << 1); } void givealbuffer_music(const void *buf){ + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1); } void givealbuffer_wt(const void *buf){ + givealbuffer_common(buf, I_WT, WTBUFLEN << 1); } void givealbuffer_cd(const void *buf){ + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1); } - void givealbuffer_midi(const void *buf, const uint32_t size){ + givealbuffer_common(buf, I_MIDI, (int) size); } -void al_set_midi(const int freq, const int buf_size){ - midi_freq = freq; - midi_buf_size = buf_size; +void al_set_midi(const int freq, UNUSED(const int buf_size)){ + freqs[I_MIDI] = freq; } From f287ee4fd0f96945c85feb0dd5085ef6129a223e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:20:05 +0900 Subject: [PATCH 0551/1190] Check OpenBSD version and use newer API if needed --- src/sound/audio4.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index e7b7dcf33..ebea8a08f 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -29,6 +29,10 @@ #include <86box/sound.h> #include <86box/plat_unused.h> +#if defined(OpenBSD) && OpenBSD >= 201709 +#define USE_NEW_API +#endif + #define I_NORMAL 0 #define I_MUSIC 1 #define I_WT 2 @@ -36,8 +40,11 @@ #define I_MIDI 4 static int audio[5] = {-1, -1, -1, -1, -1}; -static audio_offset_t offset[5]; +#ifdef USE_NEW_API +static struct audio_swpar info[5]; +#else static audio_info_t info[5]; +#endif static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; void closeal(void){ @@ -55,6 +62,14 @@ void inital(void){ for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); if(audio[i] != -1){ +#ifdef USE_NEW_API + AUDIO_INITPAR(&info[i]); + ioctl(audio[i], AUDIO_GETPAR, &info[i]); + info[i].pchan = 2; + info[i].bits = 16; + info[i].bps = 2; + ioctl(audio[i], AUDIO_SETPAR, &info[i]); +#else AUDIO_INITINFO(&info[i]); #if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) ioctl(audio[i], AUDIO_GETFORMAT, &info[i]); @@ -67,6 +82,7 @@ void inital(void){ info[i].hiwat = 5; info[i].lowat = 3; ioctl(audio[i], AUDIO_SETINFO, &info[i]); +#endif } } } From ad655ab40c3b3d7115ae719cb985fa9333831341 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:55:37 +0900 Subject: [PATCH 0552/1190] Forgot to add newer API support in conversion part --- src/sound/audio4.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index ebea8a08f..18606f9ce 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -112,11 +112,19 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ memcpy(conv, buf, conv_size); } +#ifdef USE_NEW_API + output_size = (double)conv_size * info[src].rate / freq; +#else output_size = (double)conv_size * info[src].play.sample_rate / freq; +#endif output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ +#ifdef USE_NEW_API + int ind = i * freq / info[src].rate * 2; +#else int ind = i * freq / info[src].play.sample_rate * 2; +#endif output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From 090b9d988a3efa0fa256a0c3b0bcb378dc9457f3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 18:57:36 +0900 Subject: [PATCH 0553/1190] Include string.h for memory operations --- src/sound/audio4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 18606f9ce..fe1b8192d 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 8daed4c70c4c8274d1bb06231443c2c23a994a2a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:03:36 +0900 Subject: [PATCH 0554/1190] OpenBSD needs stdarg.h --- src/include/86box/86box.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e8c5fbac9..c58d595c5 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -20,8 +20,8 @@ #ifndef EMU_86BOX_H #define EMU_86BOX_H -#ifdef __NetBSD__ -/* Doesn't compile on NetBSD without this include */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +/* Doesn't compile on NetBSD/OpenBSD without this include */ #include #endif From ef194e003e921edc2879317bbb22ecc662d0b3fc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:29:37 +0900 Subject: [PATCH 0555/1190] Check /dev/audio0 too --- src/sound/audio4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index fe1b8192d..2458f78c6 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -62,6 +62,7 @@ void inital(void){ int i; for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); + if(audio[i] != -1) audio[i] = open("/dev/audio0", O_WRONLY); if(audio[i] != -1){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); From e023a046bb597f292ab761df2191802474160182 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:37:15 +0900 Subject: [PATCH 0556/1190] Wrong comparison --- src/sound/audio4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 2458f78c6..fb98594e6 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -62,7 +62,7 @@ void inital(void){ int i; for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = open("/dev/audio", O_WRONLY); - if(audio[i] != -1) audio[i] = open("/dev/audio0", O_WRONLY); + if(audio[i] == -1) audio[i] = open("/dev/audio0", O_WRONLY); if(audio[i] != -1){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); From e4fb39d9441a127ae5fdcbdf571dcb31a06e91bc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:38:49 +0900 Subject: [PATCH 0557/1190] Remove TODO message --- src/sound/audio4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index fb98594e6..8428b3c93 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -7,7 +7,6 @@ * This file is part of the 86Box distribution. * * Interface to audio(4) for NetBSD/OpenBSD. - * TODO: Test on OpenBSD * * * Authors: Nishi From 3c4e8c9e4a017dbad54ed206c5eae1dafa1f5540 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:46:16 +0900 Subject: [PATCH 0558/1190] PS55DA2: Fix screen size calculation * Fix screen size calculation in recalctimings. * Set the position of underscore by CRTC reg value. * Optimize text drawing function --- src/video/vid_ps55da2.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index db2035717..81fb1601d 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -253,7 +253,7 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -// #define ENABLE_DA2_LOG 1 +#define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG @@ -1850,12 +1850,13 @@ da2_render_text(da2_t *da2) int fg, bg; uint32_t chr_dbcs; int chr_wide = 0; + int colormode = ((da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) == 0x80); // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { chr = da2->cram[(da2->ma) & DA2_MASK_CRAM]; attr = da2->cram[(da2->ma + 1) & DA2_MASK_CRAM]; // if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); - if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) /* IO 3E8h, Index 1Dh */ + if (colormode) /* IO 3E8h, Index 1Dh */ { /* --Parse attribute byte in color mode-- */ bg = 0; /* bg color is always black (the only way to change background color is programming PAL) */ fg = getPS55ForeColor(attr, da2); @@ -1932,24 +1933,24 @@ da2_render_text(da2_t *da2) chr_wide = 0; } /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ - if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) { /* Underscore only in monochrome mode */ + if (da2->sc == da2->crtc[LC_UNDERLINE_LOCATION] && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */ for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[fg]]; /* under line (white) */ } /* Column 1 (Vertical Line) */ if (attr & 0x10) { - p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */ + p[0] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */ } if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) { /* HGrid */ for (uint32_t n = 0; n < 13; n++) - p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */ + p[n] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */ } /* Drawing text cursor */ drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); - int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */ - fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); + int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */ + fg = (colormode) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); bg = 0; if (attr & 0x04) { /* Color 0 if reverse */ bg = fg; @@ -2048,8 +2049,8 @@ da2_render_textm3(da2_t *da2) drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { // int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); - // int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ - // fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; + // int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ + // fg = (colormode) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; // bg = 0; // if (attr & 0x04) {/* Color 0 if reverse */ // bg = fg; @@ -2217,10 +2218,10 @@ da2_recalctimings(da2_t *da2) da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; - if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) { - da2->hdisp--; - da2->dispend -= 29; - } + da2->hdisp -= da2->crtc[LC_START_H_DISPLAY_ENAB]; + /* In the J-DOS setup, you'll see the blank below the screen. It's NOT a bug. */ + da2->dispend -= da2->crtc[LC_START_V_DISPLAY_ENAB]; + da2->dispend++; da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; da2->htotal += 1; From c135dddfa998c66cb71d6fff004b0f6730e94921 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 19:51:45 +0900 Subject: [PATCH 0559/1190] Use option instead of set in CMake --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55cbec8b0..aafa46b1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,7 +145,9 @@ else() endif() if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) - set(AUDIO4 ON) + option(AUDIO4 "Use audio(4) as sound backend" ON) +else() + set(AUDIO4 OFF) endif() if(WIN32) From abb0670eb06538ee7f836473fc28ebb9e6705920 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 24 Mar 2025 20:22:38 +0900 Subject: [PATCH 0560/1190] PS55DA2: remove unused code, update comment --- src/video/vid_ps55da2.c | 56 ++++++----------------------------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 81fb1601d..af8beddb9 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -11,7 +11,6 @@ * Notes: There are some known issues that should be corrected. * - Incorrect foreground text color appears on an active window in OS/2 J1.3. * - Glitches some part of graphics on the Control Panel in OS/2 J2.1 beta. - * - The screen resolution and blanking interval time maybe not correct. * * The code should be tested with following cases. * - Execute MODE 0, 1, 3 and 4 commands in DOS K3.3 to test various video modes. @@ -253,7 +252,7 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 +// #define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG @@ -284,10 +283,8 @@ da2_log(const char *fmt, ...) #endif typedef struct da2_t { - // mem_mapping_t vmapping; mem_mapping_t cmapping; - // uint8_t crtcreg; uint8_t ioctl[16]; uint8_t fctl[32]; uint16_t crtc[128]; @@ -297,7 +294,6 @@ typedef struct da2_t { uint8_t attrc[0x40]; int attraddr, attrff; int attr_palette_enable; - // uint8_t seqregs[64]; int outflipflop; int inflipflop; int iolatch; @@ -312,7 +308,6 @@ typedef struct da2_t { uint32_t gdcla[8]; uint32_t gdcinput[8]; uint32_t gdcsrc[8]; - uint32_t debug_vramold[8]; uint8_t dac_mask, dac_status; int dac_read, dac_write, dac_pos; @@ -335,7 +330,7 @@ typedef struct da2_t { PALETTE vgapal; int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int hdisp, htotal, hdisp_time, rowoffset; int lowres, interlace; int rowcount; double clock; @@ -2190,13 +2185,14 @@ da2_updatevidselector(da2_t *da2) /* INT 10h video modes supported in DOS J4.0 (The DA-2 doesn't have a video BIOS on its card.) Mode Type Colors Text Base Address PELs Render - 3 A/N/K 16 80 x 25 B0000h/B8000h 1040 x 725 textm3 + 3 A/N/K 16 80 x 25 B0000h/B8000h 1040 x 754 textm3 8 A/N/K 2 80 x 25 E0000h 1040 x 725 text Ah APA 1 78 x 25 A0000h 1024 x 768 color_4bpp Dh APA 16 78 x 25 A0000h 1024 x 768 color_4bpp Eh A/N/K 16 80 x 25 E0000h 1040 x 725 text Fh APA 256 NA A0000h 1024 x 768 color_8bpp 45h(undoc) APA 16 NA A0000h 1040 x 768 color_4bpp + 46h(undoc) APA 16 ? A0000h 1040 x 768 color_4bpp */ void da2_recalctimings(da2_t *da2) @@ -2218,10 +2214,10 @@ da2_recalctimings(da2_t *da2) da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; + /* In the video mode 3, you'll see a blank below the screen. It's NOT a bug. */ da2->hdisp -= da2->crtc[LC_START_H_DISPLAY_ENAB]; - /* In the J-DOS setup, you'll see the blank below the screen. It's NOT a bug. */ da2->dispend -= da2->crtc[LC_START_V_DISPLAY_ENAB]; - da2->dispend++; + da2->dispend += 1; da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL]; da2->htotal += 1; @@ -2247,15 +2243,14 @@ da2_recalctimings(da2_t *da2) if (!(da2->ioctl[LS_MODE] & 0x01)) { da2->hdisp *= 16; da2->char_width = 13; - da2->hdisp_old = da2->hdisp; if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { da2_log("Set videomode to PS/55 8 bpp graphics.\n"); da2->render = da2_render_color_8bpp; da2->vram_display_mask = DA2_MASK_A000; } else { /* PS/55 8-color */ da2_log("Set videomode to PS/55 4 bpp graphics.\n"); - da2->vram_display_mask = DA2_MASK_A000; da2->render = da2_render_color_4bpp; + da2->vram_display_mask = DA2_MASK_A000; } } else { /* text mode */ @@ -2269,7 +2264,6 @@ da2_recalctimings(da2_t *da2) da2->vram_display_mask = DA2_MASK_CRAM; } da2->hdisp *= 13; - da2->hdisp_old = da2->hdisp; da2->char_width = 13; } // if (!da2->scrblank && da2->attr_palette_enable) @@ -2643,9 +2637,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2->mmdbg_vidaddr = addr; //} #endif - cycles -= video_timing_write_b; - da2->changedvram[addr >> 9] = changeframecount;/* 0x1FFFF -> 0x1F */ addr <<= 3; @@ -2686,27 +2678,13 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0; else da2->gdcinput[i] = val; - - // for (int i = 0; i < 8; i++) - // da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */ da2_gdcropB(addr, bitmask, da2); - // for (int i = 0; i < 8; i++) - // da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], bitmask, da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch - ////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); } break; case 1:/* equiv to vga write mode 2 */ - // if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { - // for (int i = 0; i < 8; i++) - // if (da2->planemask & (1 << i)) - // DA2_vram_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2); - // //fprintf(da2->mmdbg_fp, "m1-1"); - // } else { for (int i = 0; i < 8; i++) da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0); da2_gdcropB(addr, bitmask, da2); - //fprintf(da2->mmdbg_fp, "m1-2"); - // } break; case 3:/* equiv to vga write mode 3 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) @@ -2718,7 +2696,6 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2_gdcropB(addr, bitmask, da2); break; } - // da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]); } else { /* mode 3h text */ cycles -= video_timing_write_b; DA2_vram_w(addr, val, da2); @@ -2742,8 +2719,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) #ifdef ENABLE_DA2_DEBUGVRAM da2_log("da2_wW %x %d %d %02x\n", addr, addr % (da2->rowoffset * 2) * 8, addr / (da2->rowoffset * 2), val); - // if (!(da2->gdcreg[LG_COMMAND] & 0x08)) - //{ + if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) { fprintf(da2->mmdbg_fp, "\nW %x %x ", addr, val); for (int i = 0; i <= 0xb; i++) @@ -2756,7 +2732,6 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) fprintf(da2->mmdbg_fp, "%X", pixeldata); } da2->mmdbg_vidaddr = addr; - //} #endif cycles -= video_timing_write_w; @@ -2764,7 +2739,6 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) // da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); da2->changedvram[addr >> 9] = changeframecount; - // da2->changedvram[(addr + 1) >> 12] = changeframecount; addr <<= 3; for (int i = 0; i < 8; i++) @@ -3025,9 +2999,6 @@ da2_poll(void *priv) da2->cgastat |= 8; x = da2->hdisp; - // if (da2->interlace && !da2->oddeven) da2->lastline++; - // if (da2->interlace && da2->oddeven) da2->firstline--; - wx = x; wy = da2->lastline - da2->firstline; @@ -3044,17 +3015,9 @@ da2_poll(void *priv) changeframecount = da2->interlace ? 3 : 2; da2->vslines = 0; - // if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5); - // else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5); - // da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj; - /* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch; - else*/ da2->ma = da2->maback = da2->ma_latch; da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; - - // da2->ma <<= 1; - // da2->maback <<= 1; da2->ca <<= 1; // da2_log("Addr %08X vson %03X vsoff %01X\n",da2->ma,da2->vsyncstart,da2->crtc[0x11]&0xF); @@ -3071,9 +3034,6 @@ da2_poll(void *priv) if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) da2->con = 1; } - // printf("2 %i\n",da2_vsyncstart); - // da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc); - // da2_log("r"); } static void From 16a6ab3f95b187ca829dd21ffb17d698eaece1dc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:35:41 +0900 Subject: [PATCH 0561/1190] Fix music frequency conversion bug --- src/sound/audio4.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 8428b3c93..ad8b3ce82 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -96,6 +96,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ int conv_size; int i; double gain; + int target_rate; if(audio[src] == -1) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); @@ -114,18 +115,18 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ } #ifdef USE_NEW_API - output_size = (double)conv_size * info[src].rate / freq; + target_rate = info[src].rate; #else - output_size = (double)conv_size * info[src].play.sample_rate / freq; + target_rate = info[src].play.sample_rate; #endif + + output_size = (double)conv_size * target_rate / freq; + output_size -= output_size % 2; output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ -#ifdef USE_NEW_API - int ind = i * freq / info[src].rate * 2; -#else - int ind = i * freq / info[src].play.sample_rate * 2; -#endif + int ind = i * freq / target_rate * 2; + ind -= ind % 2; output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From fefcd530ab86dbb2143e01b8d0ae1117bccf6794 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:37:46 +0900 Subject: [PATCH 0562/1190] Remove the part that was not required --- src/sound/audio4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index ad8b3ce82..2bad30144 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -126,7 +126,6 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ int ind = i * freq / target_rate * 2; - ind -= ind % 2; output[i * 2 + 0] = conv[ind + 0] * gain; output[i * 2 + 1] = conv[ind + 1] * gain; } From c92d56261a38aed2e95c1445192763e540a7e244 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 20:44:29 +0900 Subject: [PATCH 0563/1190] Do mod4 instead of mod2, so it can keep the output channel correct --- src/sound/audio4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 2bad30144..32989eecf 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -121,7 +121,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ #endif output_size = (double)conv_size * target_rate / freq; - output_size -= output_size % 2; + output_size -= output_size % 4; output = malloc(output_size); for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ From b4fdb6dcdc1e4bfea8e91411112a869ced350ce6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 14:17:59 +0100 Subject: [PATCH 0564/1190] Vulkan renderer: Take the dpi_scale option into account when setting up the videwport, fixes #5374. --- src/qt/qt_vulkanrenderer.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp index 13728b82e..39830569c 100644 --- a/src/qt/qt_vulkanrenderer.cpp +++ b/src/qt/qt_vulkanrenderer.cpp @@ -970,10 +970,17 @@ VulkanRenderer2::startNextFrame() m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset); VkViewport viewport; - viewport.x = destination.x() * m_window->devicePixelRatio(); - viewport.y = destination.y() * m_window->devicePixelRatio(); - viewport.width = destination.width() * m_window->devicePixelRatio(); - viewport.height = destination.height() * m_window->devicePixelRatio(); + if (dpi_scale) { + viewport.x = destination.x() * m_window->devicePixelRatio(); + viewport.y = destination.y() * m_window->devicePixelRatio(); + viewport.width = destination.width() * m_window->devicePixelRatio(); + viewport.height = destination.height() * m_window->devicePixelRatio(); + } else { + viewport.x = destination.x(); + viewport.y = destination.y(); + viewport.width = destination.width(); + viewport.height = destination.height(); + } viewport.minDepth = 0; viewport.maxDepth = 1; m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport); From d361befe757f6dafd2408b0d1c47c6a57c06df0f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 14:23:38 +0100 Subject: [PATCH 0565/1190] JEGA: Commented out the two 3de arrays which are currently unused. --- src/video/vid_jega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index f9bcb6918..4d411c39c 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -733,9 +733,9 @@ const device_t jega_device = { }; static uint8_t p65idx = 0; -static uint8_t p3de_idx = 0; +// static uint8_t p3de_idx = 0; static uint8_t p65[6]; -static uint8_t p3de[0x30]; +// static uint8_t p3de[0x30]; static uint8_t From 9fed70679300260260440492c7f9ae5c92a3551a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:37:39 +0900 Subject: [PATCH 0566/1190] Add sndio.c that might compile --- CMakeLists.txt | 8 ++- src/sound/CMakeLists.txt | 2 + src/sound/sndio.c | 132 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/sound/sndio.c diff --git a/CMakeLists.txt b/CMakeLists.txt index aafa46b1c..a94321038 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,12 +144,18 @@ else() option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) endif() -if((CMAKE_SYSTEM_NAME STREQUAL "NetBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")) +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") option(AUDIO4 "Use audio(4) as sound backend" ON) else() set(AUDIO4 OFF) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + option(SNDIO "Use sndio as sound backend" ON) +else() + set(SNDIO OFF) +endif() + if(WIN32) set(QT ON) option(CPPTHREADS "C++11 threads" OFF) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 955e96f5a..0f96aa9a6 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -56,6 +56,8 @@ add_library(snd OBJECT # TODO: Should platform-specific audio driver be here? if(AUDIO4) target_sources(snd PRIVATE audio4.c) +elseif(SNDIO) + target_sources(snd PRIVATE sndio.c) elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) diff --git a/src/sound/sndio.c b/src/sound/sndio.c new file mode 100644 index 000000000..bb483d9fe --- /dev/null +++ b/src/sound/sndio.c @@ -0,0 +1,132 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Interface to audio(4) for NetBSD/OpenBSD. + * + * + * Authors: Nishi + * + * Copyright 2025 Nishi. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include <86box/86box.h> +#include <86box/sound.h> +#include <86box/plat_unused.h> + +#define I_NORMAL 0 +#define I_MUSIC 1 +#define I_WT 2 +#define I_CD 3 +#define I_MIDI 4 + +static struct sio_hdl* audio[5] = {NULL, NULL, NULL, NULL, NULL}; +static struct sio_par info[5]; +static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0}; + +void closeal(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + if(audio[i] != NULL){ + sio_close(audio[i]); + } + audio[i] = NULL; + } +} + +void inital(void){ + int i; + for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ + audio[i] = sio_open(SIO_DEVANY, SIO_PLAY, 0); + if(audio[i] != NULL){ + sio_initpar(&info[i]); + sio_getpar(audio[i], &info[i]); + info[i].sig = 1; + info[i].bits = 16; + info[i].pchan = 2; + sio_setpar(audio[i], &info[i]); + sio_start(audio[i]); + } + } +} + +void givealbuffer_common(const void *buf, const uint8_t src, const int size){ + const int freq = freqs[src]; + int16_t* output; + int output_size; + int16_t* conv; + int conv_size; + int i; + double gain; + int target_rate; + if(audio[src] == -1) return; + + gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + + if(sound_is_float){ + float* input = (float*)buf; + conv_size = sizeof(int16_t) * size; + conv = malloc(conv_size); + for(i = 0; i < conv_size / sizeof(int16_t); i++){ + conv[i] = 32767 * input[i]; + } + }else{ + conv_size = size * sizeof(int16_t); + conv = malloc(conv_size); + memcpy(conv, buf, conv_size); + } + + target_rate = info[src].rate; + + output_size = (double)conv_size * target_rate / freq; + output_size -= output_size % 4; + output = malloc(output_size); + + for(i = 0; i < output_size / sizeof(int16_t) / 2; i++){ + int ind = i * freq / target_rate * 2; + output[i * 2 + 0] = conv[ind + 0] * gain; + output[i * 2 + 1] = conv[ind + 1] * gain; + } + + sio_write(audio[src], output, output_size); + + free(conv); + free(output); +} + +void givealbuffer(const void *buf){ + givealbuffer_common(buf, I_NORMAL, SOUNDBUFLEN << 1); +} + +void givealbuffer_music(const void *buf){ + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1); +} + +void givealbuffer_wt(const void *buf){ + givealbuffer_common(buf, I_WT, WTBUFLEN << 1); +} + +void givealbuffer_cd(const void *buf){ + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1); +} +void givealbuffer_midi(const void *buf, const uint32_t size){ + givealbuffer_common(buf, I_MIDI, (int) size); +} + +void al_set_midi(const int freq, UNUSED(const int buf_size)){ + freqs[I_MIDI] = freq; +} From 277b422940fa953246cd28c054da73fce40cc596 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:41:43 +0900 Subject: [PATCH 0567/1190] Forgot to add linking/including stuff to CMake --- src/sound/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 0f96aa9a6..b2cbb57f0 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -58,6 +58,20 @@ if(AUDIO4) target_sources(snd PRIVATE audio4.c) elseif(SNDIO) target_sources(snd PRIVATE sndio.c) + find_package(PkgConfig REQUIRED) + + # Use FAudio, a reimplementation of XAudio2 + pkg_check_modules(SNDIO IMPORTED_TARGET sndio) + if(SNDIO_FOUND) + target_link_libraries(86Box PkgConfig::SNDIO) + else() + find_path(SNDIO_INCLUDE_DIR NAMES "sndio.h") + find_library(SNDIO_LIBRARY sndio) + + target_link_libraries(86Box ${SNDIO_LIBRARY}) + endif() + + include_directories(${SNDIO_INCLUDE_DIRS}) elseif(OPENAL) if(VCPKG_TOOLCHAIN) find_package(OpenAL CONFIG REQUIRED) From 251dcacaa162099027b7684d3ab57faaa598c9fc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:44:28 +0900 Subject: [PATCH 0568/1190] fix include --- src/sound/sndio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index bb483d9fe..2a454f5fc 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Interface to audio(4) for NetBSD/OpenBSD. + * Interface to sndio * * * Authors: Nishi @@ -14,15 +14,13 @@ * Copyright 2025 Nishi. */ #include -#include #include -#include #include #include #include #include -#include +#include #include <86box/86box.h> #include <86box/sound.h> From 5de2d6b86dcba49db57039f4ce2d10f68f4004e2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 22:45:11 +0900 Subject: [PATCH 0569/1190] Should be NULL not -1 --- src/sound/sndio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 2a454f5fc..56f8ec8cf 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -71,7 +71,7 @@ void givealbuffer_common(const void *buf, const uint8_t src, const int size){ int i; double gain; int target_rate; - if(audio[src] == -1) return; + if(audio[src] == NULL) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); From 6e83a7fc96ea44acf9dea93d2f4752043c4cadba Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 24 Mar 2025 23:30:13 +0900 Subject: [PATCH 0570/1190] Get sio_par for safety --- src/sound/audio4.c | 3 ++- src/sound/sndio.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 32989eecf..4e74d2c0c 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -66,8 +66,9 @@ void inital(void){ #ifdef USE_NEW_API AUDIO_INITPAR(&info[i]); ioctl(audio[i], AUDIO_GETPAR, &info[i]); - info[i].pchan = 2; + info[i].sig = 1; info[i].bits = 16; + info[i].pchan = 2; info[i].bps = 2; ioctl(audio[i], AUDIO_SETPAR, &info[i]); #else diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 56f8ec8cf..5c3adad49 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -57,6 +57,7 @@ void inital(void){ info[i].bits = 16; info[i].pchan = 2; sio_setpar(audio[i], &info[i]); + sio_getpar(audio[i], &info[i]); sio_start(audio[i]); } } From 1ef20bea361494e14960f3cb934c3b2e3f90b46b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 25 Mar 2025 00:01:15 +0900 Subject: [PATCH 0571/1190] Had to assign some values --- src/sound/sndio.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 5c3adad49..2fe1434df 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -51,14 +51,23 @@ void inital(void){ for(i = 0; i < sizeof(audio) / sizeof(audio[0]); i++){ audio[i] = sio_open(SIO_DEVANY, SIO_PLAY, 0); if(audio[i] != NULL){ - sio_initpar(&info[i]); + int rate; + int max_frames; sio_getpar(audio[i], &info[i]); + rate = info[i].rate; + max_frames = info[i].bufsz; + sio_initpar(&info[i]); info[i].sig = 1; info[i].bits = 16; info[i].pchan = 2; + info[i].rate = rate; + info[i].appbufsz = max_frames; sio_setpar(audio[i], &info[i]); sio_getpar(audio[i], &info[i]); - sio_start(audio[i]); + if(!sio_start(audio[i])){ + sio_close(audio[i]); + audio[i] = NULL; + } } } } From d68a56a3c92c40c279c89bcdc69c0e1ce00c2538 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 25 Mar 2025 00:52:27 +0900 Subject: [PATCH 0572/1190] Forgot to remove the comment --- src/sound/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index b2cbb57f0..0a04b0ff1 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -60,7 +60,6 @@ elseif(SNDIO) target_sources(snd PRIVATE sndio.c) find_package(PkgConfig REQUIRED) - # Use FAudio, a reimplementation of XAudio2 pkg_check_modules(SNDIO IMPORTED_TARGET sndio) if(SNDIO_FOUND) target_link_libraries(86Box PkgConfig::SNDIO) From c7b5aa8f0421f3d064b23b1b3d2c924a1a3747c7 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 24 Mar 2025 18:51:28 +0100 Subject: [PATCH 0573/1190] DEC 21x4 changes of the day (March 24th, 2025) 1. Change the block type of the extended format of the 21143 to 3 and do not issue an IRQ abuse. --- src/network/net_tulip.c | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index 7d988368c..685873c93 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -971,7 +971,8 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) case CSR(7): s->csr[7] = data; - tulip_update_int(s); + if (s->device_info->local) + tulip_update_int(s); break; case CSR(8): @@ -1006,7 +1007,7 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) case CSR(13): s->csr[13] = data; - if (s->device_info->local == 3 && (data & 0x4)) { + if ((s->device_info->local == 3) && (data & 0x4)) { s->csr[13] = 0x8f01; s->csr[14] = 0xfffd; s->csr[15] = 0; @@ -1407,7 +1408,7 @@ nic_init(const device_t *info) if (!s) return NULL; - if (info->local && info->local != 3) { + if (info->local && (info->local != 3)) { s->bios_addr = 0xD0000; s->has_bios = device_get_config_int("bios"); } else { @@ -1434,7 +1435,7 @@ nic_init(const device_t *info) s->eeprom_data[2] = 0x14; s->eeprom_data[3] = 0x21; } else { - /*Subsystem Vendor ID*/ + /*Subsystem Vendor ID*/ s->eeprom_data[0] = info->local ? 0x25 : 0x11; s->eeprom_data[1] = 0x10; @@ -1549,23 +1550,40 @@ nic_init(const device_t *info) /*Block Count*/ s->eeprom_data[32] = 0x01; - /*Extended Format - Block Type 2 for 21142/21143*/ + /*Extended Format - Block Type 3 for 21142/21143*/ /*Length (0:6) and Format Indicator (7)*/ - s->eeprom_data[33] = 0x86; + s->eeprom_data[33] = 0x8d; /*Block Type*/ - s->eeprom_data[34] = 0x02; + s->eeprom_data[34] = 0x03; - /*Media Code (0:5), EXT (6), Reserved (7)*/ - s->eeprom_data[35] = 0x01; + /*PHY Number*/ + s->eeprom_data[35] = 0x00; - /*General Purpose Control*/ - s->eeprom_data[36] = 0xff; - s->eeprom_data[37] = 0xff; + /*GPR Length*/ + s->eeprom_data[36] = 0x00; - /*General Purpose Data*/ + /*Reset Length*/ + s->eeprom_data[37] = 0x00; + + /*Media Capabilities*/ s->eeprom_data[38] = 0x00; - s->eeprom_data[39] = 0x00; + s->eeprom_data[39] = 0x78; + + /*Nway Advertisement*/ + s->eeprom_data[40] = 0xe0; + s->eeprom_data[41] = 0x01; + + /*FDX Bit Map*/ + s->eeprom_data[42] = 0x00; + s->eeprom_data[43] = 0x50; + + /*TTM Bit Map*/ + s->eeprom_data[44] = 0x00; + s->eeprom_data[45] = 0x18; + + /*MII PHY Insertion/removal Indication*/ + s->eeprom_data[46] = 0x00; } s->eeprom_data[126] = tulip_srom_crc(s->eeprom_data) & 0xff; @@ -1608,7 +1626,7 @@ nic_init(const device_t *info) checksum *= 2; if (checksum > 65535) checksum = checksum % 65535; - + /* 3rd pair. */ checksum += (s->eeprom_data[4] * 256) | s->eeprom_data[5]; if (checksum > 65535) @@ -1616,7 +1634,7 @@ nic_init(const device_t *info) if (checksum >= 65535) checksum = 0; - + s->eeprom_data[6] = (checksum >> 8) & 0xFF; s->eeprom_data[7] = checksum & 0xFF; } From d91cc459bf52fbc07fe864f67d234ed059ae45be Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 24 Mar 2025 19:02:46 +0100 Subject: [PATCH 0574/1190] OKI IF386AX: Implement the NEATsx chipset and give it the AT Phoenix keyboard controller. --- src/chipset/neat.c | 144 ++++++++++++++++++++++++----------- src/device/kbc_at.c | 40 ++++++++-- src/include/86box/chipset.h | 1 + src/include/86box/keyboard.h | 1 + src/include/86box/machine.h | 2 + src/machine/m_at_286_386sx.c | 4 +- src/machine/machine_table.c | 12 +-- 7 files changed, 146 insertions(+), 58 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index d4eb3ec7f..f6a7fafb2 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -53,6 +53,7 @@ #define REG_RA1 0x61 /* Command Delay */ #define RA1_MASK 0xff /* 1111 1111 */ +#define RA1_MASK_SX 0xbf /* 1X11 1111 */ #define RA1_BUSDLY 0x03 /* AT BUS command delay */ #define RA1_BUSDLY_SH 0 #define RA1_BUS8DLY 0x0c /* AT BUS 8bit command delay */ @@ -81,6 +82,7 @@ #define ATWS_3 1 /* 3 wait states */ #define ATWS_4 2 /* 4 wait states */ #define ATWS_5 4 /* 5 wait states */ +#define RA2_387SX 0x80 /* CS8221 82C212 controller registers. */ #define REG_RB0 0x64 /* Version ID */ @@ -103,6 +105,9 @@ #define REG_RB2 0x66 /* Memory Enable 1 */ #define RB2_MASK 0x80 /* 1XXX XXXX */ +#define RB2_MASK_SX 0xe0 /* 111X XXXX */ +#define RB2_BOT256 0x20 /* bottom 256K is on sysboard (1) */ +#define RB2_MID256 0x40 /* middle 256K is on sysboard (1) */ #define RB2_TOP128 0x80 /* top 128K is on sysboard (1) */ #define REG_RB3 0x67 /* Memory Enable 2 */ @@ -198,6 +203,7 @@ #define REG_RB12 0x6f /* Miscellaneous */ #define RB12_MASK 0xe6 /* 111R R11R */ +#define RB12_MASK_SX 0xf6 /* 1111 R11R */ #define RB12_GA20 0x02 /* gate for A20 */ #define RB12_RASTMO 0x04 /* enable RAS timeout counter */ #define RB12_EMSLEN 0xe0 /* EMS memory chunk size */ @@ -221,11 +227,10 @@ typedef struct ram_page_t { } ram_page_t; typedef struct neat_t { - uint8_t mem_flags[32]; + uint8_t mem_flags[64]; uint8_t regs[128]; /* all the CS8221 registers */ uint8_t indx; /* programmed index into registers */ - - char pad; + uint8_t sx; uint16_t ems_base; /* configured base address */ uint32_t ems_frame; /* configured frame address */ @@ -238,8 +243,19 @@ typedef struct neat_t { ram_page_t shadow[32]; /* Shadow RAM pages */ } neat_t; -static uint8_t defaults[16] = { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, - 0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 }; +static uint8_t defaults[2][16] = { { 0x0a, 0x45, 0xfc, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x10, 0x00, 0x00, 0x12 }, + { 0x0a, 0x45, 0x7c, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x00, 0x00, 0x00, 0x08 } }; + +static uint8_t reg_masks[2][16] = { { RA0_MASK, RA1_MASK, RA2_MASK, 0x00, + RB0_MASK, RB1_MASK, RB2_MASK, RB3_MASK, + RB4_MASK, RB4_MASK, RB4_MASK, RB4_MASK, + RB8_MASK, RB9_MASK, RB10_MASK, RB12_MASK }, + { RA0_MASK, RA1_MASK_SX, RA2_MASK, 0x00, + RB0_MASK, RB1_MASK, RB2_MASK_SX, RB3_MASK, + RB4_MASK, RB4_MASK, RB4_MASK, RB4_MASK, + RB8_MASK, RB9_MASK, RB10_MASK, RB12_MASK_SX } }; static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT }; static uint8_t shifts[4] = { RB10_P0EXT_SH, RB10_P1EXT_SH, RB10_P2EXT_SH, RB10_P3EXT_SH }; @@ -405,12 +421,12 @@ ems_writew(uint32_t addr, uint16_t val, void *priv) static void neat_mem_update_state(neat_t *dev, uint32_t addr, uint32_t size, uint8_t new_flags, uint8_t mask) { - if ((addr >= 0x00080000) && (addr < 0x00100000) && - ((new_flags ^ dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]) & mask)) { - dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] &= ~mask; - dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE] |= new_flags; + if ((addr < 0x00100000) && + ((new_flags ^ dev->mem_flags[addr / EMS_PGSIZE]) & mask)) { + dev->mem_flags[addr / EMS_PGSIZE] &= ~mask; + dev->mem_flags[addr / EMS_PGSIZE] |= new_flags; - new_flags = dev->mem_flags[(addr - 0x00080000) / EMS_PGSIZE]; + new_flags = dev->mem_flags[addr / EMS_PGSIZE]; if (new_flags & MEM_FLAG_ROMCS) { neat_log("neat_mem_update_state(): %08X-%08X: %02X (ROMCS)\n", addr, addr + size - 1, new_flags); @@ -691,6 +707,7 @@ neat_write(uint16_t port, uint8_t val, void *priv) uint8_t xval; uint8_t j; uint8_t *reg; + uint8_t mask; int i; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) @@ -705,10 +722,11 @@ neat_write(uint16_t port, uint8_t val, void *priv) case 0x23: reg = &dev->regs[dev->indx]; xval = *reg ^ val; + mask = reg_masks[dev->sx][dev->indx & REG_MASK]; switch (dev->indx) { case REG_RA0: - val &= RA0_MASK; - *reg = (*reg & ~RA0_MASK) | val | (RA0_REV_ID << RA0_REV_SH); + val &= mask; + *reg = (*reg & ~mask) | val | (RA0_REV_ID << RA0_REV_SH); if ((xval & 0x20) && (val & 0x20)) outb(0x64, 0xfe); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) @@ -717,32 +735,32 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RA1: - val &= RA1_MASK; - *reg = (*reg & ~RA1_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA1=%02x(%02x)\n", val, *reg); #endif break; case REG_RA2: - val &= RA2_MASK; - *reg = (*reg & ~RA2_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RA2=%02x(%02x)\n", val, *reg); #endif break; case REG_RB0: - val &= RB0_MASK; - *reg = (*reg & ~RB0_MASK) | val | (RB0_REV_ID << RB0_REV_SH); + val &= mask; + *reg = (*reg & ~mask) | val | (RB0_REV_ID << RB0_REV_SH); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB0=%02x(%02x)\n", val, *reg); #endif break; case REG_RB1: - val &= RB1_MASK; - *reg = (*reg & ~RB1_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB1=%02x(%02x)\n", val, *reg); @@ -750,20 +768,37 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB2: - val &= RB2_MASK; - *reg = (*reg & ~RB2_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; + if (dev->sx) { + if (val & RB2_BOT256) + neat_mem_update_state(dev, 0x00000000, 0x00040000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + else + neat_mem_update_state(dev, 0x00000000, 0x00040000, + 0x00, MEM_FMASK_SHADOW); + + if (val & RB2_MID256) + neat_mem_update_state(dev, 0x00040000, 0x00040000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + else + neat_mem_update_state(dev, 0x00040000, 0x00040000, + 0x00, MEM_FMASK_SHADOW); + } if (val & RB2_TOP128) - neat_mem_update_state(dev, 0x00080000, 0x00020000, MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, + MEM_FLAG_READ | MEM_FLAG_WRITE, MEM_FMASK_SHADOW); else - neat_mem_update_state(dev, 0x00080000, 0x00020000, 0x00, MEM_FMASK_SHADOW); + neat_mem_update_state(dev, 0x00080000, 0x00020000, + 0x00, MEM_FMASK_SHADOW); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB2=%02x(%02x)\n", val, *reg); #endif break; case REG_RB3: - val &= RB3_MASK; - *reg = (*reg & ~RB3_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB3=%02x(%02x)\n", val, *reg); @@ -771,8 +806,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB4: - val &= RB4_MASK; - *reg = (*reg & ~RB4_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB4=%02x(%02x)\n", val, *reg); @@ -780,8 +815,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB5: - val &= RB5_MASK; - *reg = (*reg & ~RB5_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; shadow_recalc(dev); #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB5=%02x(%02x)\n", val, *reg); @@ -789,20 +824,20 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB6: - val &= RB6_MASK; - *reg = (*reg & ~RB6_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB6=%02x(%02x)\n", val, *reg); #endif break; case REG_RB7: - val &= RB7_MASK; + val &= mask; if (xval & (RB7_EMSEN | RB7_UMAREL)) remap_update(dev, val); - dev->regs[REG_RB7] = val; + *reg = (*reg & ~mask) | val; if (xval & RB7_EMSEN) ems_remove_handlers(dev); @@ -816,16 +851,16 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB8: - val &= RB8_MASK; - *reg = (*reg & ~RB8_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB8=%02x(%02x)\n", val, *reg); #endif break; case REG_RB9: - val &= RB9_MASK; - *reg = (*reg & ~RB9_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg); #endif @@ -847,8 +882,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB10: - val &= RB10_MASK; - *reg = (*reg & ~RB10_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg); #endif @@ -882,8 +917,8 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; case REG_RB12: - val &= RB12_MASK; - *reg = (*reg & ~RB12_MASK) | val; + val &= mask; + *reg = (*reg & ~mask) | val; #if defined(ENABLE_NEAT_LOG) && (ENABLE_NEAT_LOG == 2) neat_log("NEAT: RB12=%02x(%02x)\n", val, *reg); #endif @@ -976,6 +1011,8 @@ neat_init(UNUSED(const device_t *info)) /* Create an instance. */ dev = (neat_t *) calloc(1, sizeof(neat_t)); + dev->sx = info->local; + if (mem_size > 1024) { mem_mapping_set_handler(&ram_high_mapping, neat_read_ram, neat_read_ramw, NULL, neat_write_ram, neat_write_ramw, NULL); @@ -1002,7 +1039,7 @@ neat_init(UNUSED(const device_t *info)) neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_SHADOW); else { /* This is needed to actually trigger an update. */ - dev->mem_flags[i + 8] = MEM_FLAG_ROMCS; + dev->mem_flags[i + 40] = MEM_FLAG_ROMCS; neat_mem_update_state(dev, 0x000a0000 + (i * EMS_PGSIZE), EMS_PGSIZE, 0x00, MEM_FMASK_SHADOW); } } @@ -1045,7 +1082,10 @@ neat_init(UNUSED(const device_t *info)) /* Initialize some of the registers to specific defaults. */ for (uint8_t i = REG_RA0; i <= REG_RB12; i++) { dev->indx = i; - neat_write(0x0023, defaults[i & REG_MASK], dev); + uint8_t def = defaults[dev->sx][i & REG_MASK]; + if ((i == REG_RA2) && (fpu_type == FPU_387)) + def |= RA2_387SX; + neat_write(0x0023, def, dev); } /* @@ -1190,7 +1230,7 @@ neat_init(UNUSED(const device_t *info)) } const device_t neat_device = { - .name = "C&T CS8121 (NEAT)", + .name = "C&T CS8221 (NEAT)", .internal_name = "neat", .flags = 0, .local = 0, @@ -1202,3 +1242,17 @@ const device_t neat_device = { .force_redraw = NULL, .config = NULL }; + +const device_t neat_sx_device = { + .name = "C&T CS8281 (NEATsx)", + .internal_name = "neat_sx", + .flags = 0, + .local = 1, + .init = neat_init, + .close = neat_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 09855a387..abb10d108 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1577,21 +1577,35 @@ write64_phoenix(void *priv, uint8_t val) revision level and proper CPU bits. */ case 0xd5: /* Read MultiKey code revision level */ kbc_at_log("ATkbc: Phoenix - Read MultiKey code revision level\n"); - kbc_at_queue_add(dev, 0x04); - kbc_at_queue_add(dev, 0x16); + if (dev->misc_flags & FLAG_PS2) { + kbc_at_queue_add(dev, 0x04); + kbc_at_queue_add(dev, 0x16); + } else { + kbc_at_queue_add(dev, 0x01); + kbc_at_queue_add(dev, 0x29); + } return 0; case 0xd6: /* Read Version Information */ kbc_at_log("ATkbc: Phoenix - Read Version Information\n"); kbc_at_queue_add(dev, 0x81); - kbc_at_queue_add(dev, 0xac); + if (dev->misc_flags & FLAG_PS2) + kbc_at_queue_add(dev, 0xac); + else + kbc_at_queue_add(dev, 0xaa); return 0; case 0xd7: /* Read MultiKey model numbers */ kbc_at_log("ATkbc: Phoenix - Read MultiKey model numbers\n"); - kbc_at_queue_add(dev, 0x02); - kbc_at_queue_add(dev, 0x87); - kbc_at_queue_add(dev, 0x02); + if (dev->misc_flags & FLAG_PS2) { + kbc_at_queue_add(dev, 0x02); + kbc_at_queue_add(dev, 0x87); + kbc_at_queue_add(dev, 0x02); + } else { + kbc_at_queue_add(dev, 0x90); + kbc_at_queue_add(dev, 0x88); + kbc_at_queue_add(dev, 0xd0); + } return 0; default: @@ -2510,6 +2524,20 @@ const device_t keyboard_at_compaq_device = { .config = NULL }; +const device_t keyboard_at_phoenix_device = { + .name = "PC/AT Keyboard (Phoenix)", + .internal_name = "keyboard_at_phoenix", + .flags = DEVICE_KBC, + .local = KBC_TYPE_ISA | KBC_VEN_PHOENIX, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2", diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index e47bb489f..3a65bbce9 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -48,6 +48,7 @@ extern const device_t contaq_82c597_device; /* C&T */ extern const device_t ct_82c100_device; extern const device_t neat_device; +extern const device_t neat_sx_device; extern const device_t scat_device; extern const device_t scat_4_device; extern const device_t scat_sx_device; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 3a7260c72..9142fbfe1 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -234,6 +234,7 @@ extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; extern const device_t keyboard_at_compaq_device; +extern const device_t keyboard_at_phoenix_device; extern const device_t keyboard_at_ncr_device; extern const device_t keyboard_at_olivetti_device; extern const device_t keyboard_at_siemens_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 21e4a89e2..16ccb2720 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -208,7 +208,9 @@ enum { MACHINE_CHIPSET_ALI_ALADDIN_V, MACHINE_CHIPSET_ALI_ALADDIN_PRO_II, MACHINE_CHIPSET_SCAT, + MACHINE_CHIPSET_SCAT_SX, MACHINE_CHIPSET_NEAT, + MACHINE_CHIPSET_NEAT_SX, MACHINE_CHIPSET_CT_386, MACHINE_CHIPSET_CT_CS4031, MACHINE_CHIPSET_CONTAQ_82C596, diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 2f35427be..136922a5c 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -654,9 +654,9 @@ machine_at_if386sx_init(const machine_t *model) return ret; machine_at_common_init(model); - device_add(&keyboard_at_device); + device_add(&keyboard_at_phoenix_device); - device_add(&neat_device); + device_add(&neat_sx_device); if (gfxcard[0] == VID_INTERNAL) device_add(&if386jega_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b78c11ec8..f3d39833e 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -115,7 +115,9 @@ const machine_filter_t machine_chipsets[] = { { "ALi ALADDiN V", MACHINE_CHIPSET_ALI_ALADDIN_V }, { "ALi ALADDiN-PRO II", MACHINE_CHIPSET_ALI_ALADDIN_PRO_II }, { "C&T 82C235 SCAT", MACHINE_CHIPSET_SCAT }, - { "C&T CS8121 NEAT", MACHINE_CHIPSET_NEAT }, + { "C&T 82C236 SCATsx", MACHINE_CHIPSET_SCAT_SX }, + { "C&T CS8221 NEAT", MACHINE_CHIPSET_NEAT }, + { "C&T CS8281 NEATsx", MACHINE_CHIPSET_NEAT_SX }, { "C&T 386", MACHINE_CHIPSET_CT_386 }, { "C&T CS4031", MACHINE_CHIPSET_CT_CS4031 }, { "Contaq 82C596", MACHINE_CHIPSET_CONTAQ_82C596 }, @@ -4746,10 +4748,10 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - { .name = "[NEAT] OKI if386AX30L", + { .name = "[NEATsx] OKI if386AX30L", .internal_name = "if386sx", .type = MACHINE_TYPE_386SX, - .chipset = MACHINE_CHIPSET_NEAT, + .chipset = MACHINE_CHIPSET_NEAT_SX, .init = machine_at_if386sx_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -4951,10 +4953,10 @@ const machine_t machines[] = { /* Has an unknown AMI KBC firmware, I'm going to assume 'F' until a photo or real hardware BIOS string is found. */ { - .name = "[SCAT] Kaimei KMX-C-02", + .name = "[SCATsx] Kaimei KMX-C-02", .internal_name = "kmxc02", .type = MACHINE_TYPE_386SX, - .chipset = MACHINE_CHIPSET_SCAT, + .chipset = MACHINE_CHIPSET_SCAT_SX, .init = machine_at_kmxc02_init, .p1_handler = NULL, .gpio_handler = NULL, From db6e74a3b9a94083fd47cada3b8a3325ad48dd06 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 01:47:34 +0100 Subject: [PATCH 0575/1190] NEAT/NEATsx: Fix the EMS enabled condition in the RAM remapping function, fixes 386 enhanced mode operations on the OKI IF386AX. --- src/chipset/neat.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index f6a7fafb2..ffc25d6d9 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -686,9 +686,10 @@ remap_update(neat_t *dev, uint8_t val) mem_mapping_set_addr(&ram_low_mapping, 0x00000000, dev->remap_base << 10); if (dev->remap_base > 1024) { - mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); - mem_mapping_set_exec(&ram_high_mapping, &(ram[(val & RB7_EMSEN) ? 0x00100000 : - (0x00100000 + (dev->ems_size << 10))])); + uint32_t base = (val & RB7_EMSEN) ? (0x00100000 + (dev->ems_size << 10)) : 0x00100000; + + mem_mapping_set_addr(&ram_high_mapping, base, (dev->remap_base << 10) - 0x00100000); + mem_mapping_set_exec(&ram_high_mapping, &(ram[base])); } else mem_mapping_disable(&ram_high_mapping); From 3f6593f314f47607771395064e23b8bd3f4c3ed5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 02:02:00 +0100 Subject: [PATCH 0576/1190] IF386AX: Set video card to fixed and make the power off function actually power off. --- src/machine/m_at_286_386sx.c | 4 ++-- src/machine/machine_table.c | 2 +- src/video/vid_jega.c | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 136922a5c..033233955 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -658,8 +658,8 @@ machine_at_if386sx_init(const machine_t *model) device_add(&neat_sx_device); - if (gfxcard[0] == VID_INTERNAL) - device_add(&if386jega_device); + device_add(&if386jega_device); + if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f3d39833e..9f2d0ce47 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4768,7 +4768,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_AT, - .flags = MACHINE_VIDEO, + .flags = MACHINE_VIDEO_FIXED, .ram = { .min = 1024, .max = 4096, diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4d411c39c..4730b5142 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -28,6 +28,7 @@ #include <86box/timer.h> #include <86box/pic.h> #include <86box/pit.h> +#include <86box/plat.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> @@ -800,9 +801,11 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv) } jega_recalctimings(jega); } else if (p65idx == 0x05) { - if (val & 0x10) { /* Power off (instead this call hardware reset here) */ - resetx86(); - } + if (val & 0x10) + /* Power off (instead this call hardware reset here) */ + // resetx86(); + /* Actually, power off - we have a function for that! */ + plat_power_off(); } } return; From 260f91313a574a0d1f1254cb6252b4d6d3c76daf Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 02:08:35 +0100 Subject: [PATCH 0577/1190] JEGA: Bring back the reset for time being, the BIOS needs it to reboot. --- src/video/vid_jega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4730b5142..36cf04077 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -803,9 +803,9 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv) } else if (p65idx == 0x05) { if (val & 0x10) /* Power off (instead this call hardware reset here) */ - // resetx86(); + resetx86(); /* Actually, power off - we have a function for that! */ - plat_power_off(); + // plat_power_off(); } } return; From e71c30ce8457fae5dd3910780e64cca56d8225b6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 04:03:21 +0100 Subject: [PATCH 0578/1190] MMU: Fix behavior of 64-bit memory reads (used by FPU and MMX), should no longer waste host cycles on extra unnecessary MMU translations and should also no longer MMU translate already translated addresses which was causing unpredictable results. --- src/mem/mem.c | 24 +++++++++++++++++++++--- src/mem/mmu_2386.c | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index 94c4ab788..074b44bda 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -1533,10 +1533,28 @@ readmemql(uint32_t addr) addr = addr64a[0] & rammask; map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - if (map && map->read_l) - return map->read_l(addr, map->priv) | ((uint64_t) map->read_l(addr + 4, map->priv) << 32); - return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); + if (map && map->read_l) + return map->read_l(addr, map->priv) | + ((uint64_t) map->read_l(addr + 4, map->priv) << 32); + + if (map && map->read_w) + return map->read_w(addr, map->priv) | + ((uint64_t) map->read_w(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_w(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_w(addr + 6, map->priv) << 48); + + if (map && map->read_b) + return map->read_b(addr, map->priv) | + ((uint64_t) map->read_b(addr + 1, map->priv) << 8) | + ((uint64_t) map->read_b(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_b(addr + 3, map->priv) << 24) | + ((uint64_t) map->read_b(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_b(addr + 5, map->priv) << 40) | + ((uint64_t) map->read_b(addr + 6, map->priv) << 48) | + ((uint64_t) map->read_b(addr + 7, map->priv) << 56); + + return 0xffffffffffffffffULL; } void diff --git a/src/mem/mmu_2386.c b/src/mem/mmu_2386.c index 7418a88d8..1a2782237 100644 --- a/src/mem/mmu_2386.c +++ b/src/mem/mmu_2386.c @@ -102,8 +102,8 @@ mem_readw_map(uint32_t addr) if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->read_w)) ret = map->read_w(addr, map->priv); else { - ret = mem_readb_phys(addr + 1) << 8; - ret |= mem_readb_phys(addr); + ret = mem_readb_map(addr); + ret |= ((uint16_t) mem_readb_map(addr + 1)) << 8; } return ret; @@ -120,8 +120,8 @@ mem_readl_map(uint32_t addr) if (!cpu_16bitbus && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->read_l)) ret = map->read_l(addr, map->priv); else { - ret = mem_readw_phys(addr + 2) << 16; - ret |= mem_readw_phys(addr); + ret = mem_readw_map(addr); + ret |= ((uint32_t) mem_readw_map(addr + 2)) << 16; } return ret; @@ -148,8 +148,8 @@ mem_writew_map(uint32_t addr, uint16_t val) if (((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_HBOUND) && (map && map->write_w)) map->write_w(addr, val, map->priv); else { - mem_writeb_phys(addr, val & 0xff); - mem_writeb_phys(addr + 1, val >> 8); + mem_writeb_map(addr, val & 0xff); + mem_writeb_map(addr + 1, val >> 8); } } @@ -161,10 +161,10 @@ mem_writel_map(uint32_t addr, uint32_t val) mem_logical_addr = 0xffffffff; if (!cpu_16bitbus && ((addr & MEM_GRANULARITY_MASK) <= MEM_GRANULARITY_QBOUND) && (map && map->write_l)) - map->write_l(addr, val, map->priv); + map->write_l(addr, val, map->priv); else { - mem_writew_phys(addr, val & 0xffff); - mem_writew_phys(addr + 2, val >> 16); + mem_writew_map(addr, val & 0xffff); + mem_writew_map(addr + 2, val >> 16); } } @@ -649,7 +649,7 @@ readmemll_2386(uint32_t addr) /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass their result as a parameter to be used if needed. */ return readmemwl_no_mmut_2386(addr, addr64a) | - (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16); + (((uint32_t) readmemwl_no_mmut_2386(addr + 2, &(addr64a[2]))) << 16); } } @@ -925,10 +925,28 @@ readmemql_2386(uint32_t addr) addr = addr64a[0] & rammask; map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - if (map && map->read_l) - return map->read_l(addr, map->priv) | ((uint64_t) map->read_l(addr + 4, map->priv) << 32); - return readmemll(addr) | ((uint64_t) readmemll(addr + 4) << 32); + if (map && map->read_l) + return map->read_l(addr, map->priv) | + ((uint64_t) map->read_l(addr + 4, map->priv) << 32); + + if (map && map->read_w) + return map->read_w(addr, map->priv) | + ((uint64_t) map->read_w(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_w(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_w(addr + 6, map->priv) << 48); + + if (map && map->read_b) + return map->read_b(addr, map->priv) | + ((uint64_t) map->read_b(addr + 1, map->priv) << 8) | + ((uint64_t) map->read_b(addr + 2, map->priv) << 16) | + ((uint64_t) map->read_b(addr + 3, map->priv) << 24) | + ((uint64_t) map->read_b(addr + 4, map->priv) << 32) | + ((uint64_t) map->read_b(addr + 5, map->priv) << 40) | + ((uint64_t) map->read_b(addr + 6, map->priv) << 48) | + ((uint64_t) map->read_b(addr + 7, map->priv) << 56); + + return 0xffffffffffffffffULL; } void From 8da843bb0acc529bb3791aa41fcde385f5e21ae6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 06:29:11 +0100 Subject: [PATCH 0579/1190] DMA: Fix a long-standing nasty bug in bus master transfers that was potentially causing memory corruption. --- src/dma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dma.c b/src/dma.c index 4edeb39f8..a730f1a1c 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1877,15 +1877,15 @@ dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int Tra n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n) { - for (uint32_t i = 0; i < n; i += TransferSize) + if (n2) { + for (uint32_t i = 0; i < n2; i += TransferSize) mem_read_phys((void *) &(DataRead[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n2) { - mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); - memcpy((void *) &(DataRead[n]), bytes, n2); + if (n) { + mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); + memcpy((void *) &(DataRead[n2]), bytes, n); } } @@ -1900,16 +1900,16 @@ dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n) { - for (uint32_t i = 0; i < n; i += TransferSize) + if (n2) { + for (uint32_t i = 0; i < n2; i += TransferSize) mem_write_phys((void *) &(DataWrite[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n2) { - mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); - memcpy(bytes, (void *) &(DataWrite[n]), n2); - mem_write_phys((void *) bytes, PhysAddress + n, TransferSize); + if (n) { + mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); + memcpy(bytes, (void *) &(DataWrite[n2]), n); + mem_write_phys((void *) bytes, PhysAddress + n2, TransferSize); } if (dma_at) From d7529d4f5eb2ae4c8cbdbb1280ed2e4942b43da7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 06:32:12 +0100 Subject: [PATCH 0580/1190] Reverted the fix because it turned out I had actually misread the code. --- src/dma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dma.c b/src/dma.c index a730f1a1c..4edeb39f8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1877,15 +1877,15 @@ dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int Tra n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n2) { - for (uint32_t i = 0; i < n2; i += TransferSize) + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) mem_read_phys((void *) &(DataRead[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n) { - mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); - memcpy((void *) &(DataRead[n2]), bytes, n); + if (n2) { + mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); + memcpy((void *) &(DataRead[n]), bytes, n2); } } @@ -1900,16 +1900,16 @@ dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, n2 = TotalSize - n; /* Do the divisible block, if there is one. */ - if (n2) { - for (uint32_t i = 0; i < n2; i += TransferSize) + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) mem_write_phys((void *) &(DataWrite[i]), PhysAddress + i, TransferSize); } /* Do the non-divisible block, if there is one. */ - if (n) { - mem_read_phys((void *) bytes, PhysAddress + n2, TransferSize); - memcpy(bytes, (void *) &(DataWrite[n2]), n); - mem_write_phys((void *) bytes, PhysAddress + n2, TransferSize); + if (n2) { + mem_read_phys((void *) bytes, PhysAddress + n, TransferSize); + memcpy(bytes, (void *) &(DataWrite[n]), n2); + mem_write_phys((void *) bytes, PhysAddress + n, TransferSize); } if (dma_at) From 556aca0b4edbc24412b3a6ae0cca5243f4673389 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 25 Mar 2025 07:13:50 +0100 Subject: [PATCH 0581/1190] NEAT/NEATsx: Fix the base of extended memory when EMS is enabled. --- src/chipset/neat.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index ffc25d6d9..1146ecbff 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -688,7 +688,7 @@ remap_update(neat_t *dev, uint8_t val) if (dev->remap_base > 1024) { uint32_t base = (val & RB7_EMSEN) ? (0x00100000 + (dev->ems_size << 10)) : 0x00100000; - mem_mapping_set_addr(&ram_high_mapping, base, (dev->remap_base << 10) - 0x00100000); + mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000); mem_mapping_set_exec(&ram_high_mapping, &(ram[base])); } else mem_mapping_disable(&ram_high_mapping); @@ -942,6 +942,13 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; } + if (mem_size < 1024) + /* No RAM left for EMS at all. */ + dev->ems_size = 0; + else if (mem_size < (dev->ems_size + 1024)) + /* Limit EMS size to the entirety of the remaining extended memory. */ + dev->ems_size = mem_size - 1024; + if (dev->regs[REG_RB7] & RB7_EMSEN) { remap_update(dev, dev->regs[REG_RB7]); From ce820df1d1df691780bd13e745322a127a670865 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 02:08:12 +0600 Subject: [PATCH 0582/1190] Always make sure emulator is not off-screen when resizing --- src/qt/qt_mainwindow.cpp | 24 ++++++++++++++++++++++++ src/qt/qt_mainwindow.hpp | 1 + src/qt/qt_rendererstack.hpp | 23 +++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ccaf6964f..b3d0d9fa9 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -798,6 +798,30 @@ MainWindow::closeEvent(QCloseEvent *event) event->accept(); } +void +MainWindow::resizeEvent(QResizeEvent *event) +{ + //qDebug() << pos().x() + event->size().width(); + //qDebug() << pos().y() + event->size().height(); + if (vid_resize == 1) + return; + + int newX = pos().x(); + int newY = pos().y(); + + if (((frameGeometry().x() + event->size().width() + 1) > util::screenOfWidget(this)->availableGeometry().right())) { + //move(util::screenOfWidget(this)->availableGeometry().right() - size().width() - 1, pos().y()); + newX = util::screenOfWidget(this)->availableGeometry().right() - frameGeometry().width() - 1; + if (newX < 1) newX = 1; + } + + if (((frameGeometry().y() + event->size().height() + 1) > util::screenOfWidget(this)->availableGeometry().bottom())) { + newY = util::screenOfWidget(this)->availableGeometry().bottom() - frameGeometry().height() - 1; + if (newY < 1) newY = 1; + } + move(newX, newY); +} + void MainWindow::initRendererMonitorSlot(int monitor_index) { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 479ed38a4..f1c6cadf6 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -137,6 +137,7 @@ protected: void showEvent(QShowEvent *event) override; void closeEvent(QCloseEvent *event) override; void changeEvent(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private slots: void on_actionPen_triggered(); diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 54ea49bb9..172dc2fe6 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ #include #include "qt_renderercommon.hpp" +#include "qt_util.hpp" #include @@ -21,6 +23,11 @@ namespace Ui { class RendererStack; } +extern "C" +{ + extern int vid_resize; +} + class RendererCommon; class RendererStack : public QStackedWidget { Q_OBJECT @@ -43,6 +50,22 @@ public: void changeEvent(QEvent *event) override; void resizeEvent(QResizeEvent *event) override { + if (this->m_monitor_index != 0 && vid_resize != 1) { + int newX = pos().x(); + int newY = pos().y(); + + if (((frameGeometry().x() + event->size().width() + 1) > util::screenOfWidget(this)->availableGeometry().right())) { + //move(util::screenOfWidget(this)->availableGeometry().right() - size().width() - 1, pos().y()); + newX = util::screenOfWidget(this)->availableGeometry().right() - frameGeometry().width() - 1; + if (newX < 1) newX = 1; + } + + if (((frameGeometry().y() + event->size().height() + 1) > util::screenOfWidget(this)->availableGeometry().bottom())) { + newY = util::screenOfWidget(this)->availableGeometry().bottom() - frameGeometry().height() - 1; + if (newY < 1) newY = 1; + } + move(newX, newY); + } onResize(event->size().width(), event->size().height()); } void keyPressEvent(QKeyEvent *event) override From 3380783876290bcb148f7e7573dabe428acd6697 Mon Sep 17 00:00:00 2001 From: flama12333 <143599905+flama12333@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:42:01 -0500 Subject: [PATCH 0583/1190] Replace MACHINE_PCI with MACHINE_PS2_PCI for pl4600c machine_table.c this will be solved the ps2 mouse not appear on the setting --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9f2d0ce47..62a0e1374 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8902,7 +8902,7 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM, .ram = { .min = 1024, From bd8bade3fbe7d48208d717768abca7536522f9c2 Mon Sep 17 00:00:00 2001 From: flama12333 <143599905+flama12333@users.noreply.github.com> Date: Wed, 26 Mar 2025 01:32:24 -0500 Subject: [PATCH 0584/1190] update machine_table.c --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 62a0e1374..aa9bae305 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -9358,7 +9358,7 @@ const machine_t machines[] = { .min_multi = MACHINE_MULTIPLIER_FIXED, .max_multi = MACHINE_MULTIPLIER_FIXED }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE | MACHINE_APM, .ram = { .min = 2048, From e5aed7f9e6e13302203e2ac88fd5ff5234392c88 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 16:37:59 +0600 Subject: [PATCH 0585/1190] Add confirmation dialog checkboxes in Preferences --- src/qt/qt_progsettings.cpp | 4 + src/qt/qt_progsettings.ui | 194 ++++++++++++++++++++----------------- 2 files changed, 108 insertions(+), 90 deletions(-) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 6ec76a290..059005ca4 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -116,6 +116,8 @@ ProgSettings::ProgSettings(QWidget *parent) ui->horizontalSlider->setValue(mouseSensitivity * 100.); ui->openDirUsrPath->setChecked(open_dir_usr_path > 0); ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); + ui->checkBoxConfirmExit->setChecked(confirm_exit); + ui->checkBoxConfirmSave->setChecked(confirm_save); #ifndef Q_OS_WINDOWS ui->checkBoxMultimediaKeys->setHidden(true); #endif @@ -127,6 +129,8 @@ ProgSettings::accept() strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); lang_id = ui->comboBoxLanguage->currentData().toUInt(); open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; + confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; + confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index dc5674425..2dbaa739d 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -29,56 +29,25 @@ QLayout::SizeConstraint::SetFixedSize - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + + Qt::Orientation::Horizontal + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + - Select media images from program working directory + Default - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - - - - 30 - - - - (System Default) - - - - - - + + Default @@ -97,13 +66,20 @@ - - - - Qt::Orientation::Horizontal + + + + Default - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + + + Select media images from program working directory @@ -121,6 +97,80 @@ + + + + Ask for confirmation before saving settings + + + + + + + 30 + + + + (System Default) + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Inhibit multimedia keys on Windows + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + false + + + 30 + + + + (Default) + + + + + + + + Mouse sensitivity: + + + @@ -143,46 +193,10 @@ - - - - false - - - 30 - - - - (Default) - - - - - - + + - Mouse sensitivity: - - - - - - - Default - - - - - - - Default - - - - - - - Inhibit multimedia keys on Windows + Ask for confirmation before quitting From 38de9b7a1b52a04f300b285bf0a7530d30a67d7d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 16:52:35 +0600 Subject: [PATCH 0586/1190] Add the other two confirmation dialog checkboxes in Preferences --- src/qt/qt_progsettings.cpp | 5 + src/qt/qt_progsettings.ui | 204 ++++++++++++++++++++----------------- 2 files changed, 114 insertions(+), 95 deletions(-) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 059005ca4..ce6c21dd6 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -118,6 +118,9 @@ ProgSettings::ProgSettings(QWidget *parent) ui->checkBoxMultimediaKeys->setChecked(inhibit_multimedia_keys); ui->checkBoxConfirmExit->setChecked(confirm_exit); ui->checkBoxConfirmSave->setChecked(confirm_save); + ui->checkBoxConfirmHardReset->setChecked(confirm_reset); + ui->checkBoxFullscreenFirst->setChecked(video_fullscreen_first); + #ifndef Q_OS_WINDOWS ui->checkBoxMultimediaKeys->setHidden(true); #endif @@ -131,6 +134,8 @@ ProgSettings::accept() open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; + confirm_reset = ui->checkBoxConfirmHardReset->isChecked() ? 1 : 0; + video_fullscreen_first = ui->checkBoxFullscreenFirst->isChecked() ? 1 : 0; inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); loadTranslators(QCoreApplication::instance()); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index 2dbaa739d..f7b32ce84 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -7,7 +7,7 @@ 0 0 458 - 374 + 391 @@ -29,43 +29,6 @@ QLayout::SizeConstraint::SetFixedSize - - - - Qt::Orientation::Horizontal - - - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok - - - - - - - Default - - - - - - - Default - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - @@ -73,16 +36,6 @@ - - - - <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> - - - Select media images from program working directory - - - @@ -90,32 +43,6 @@ - - - - Language: - - - - - - - Ask for confirmation before saving settings - - - - - - - 30 - - - - (System Default) - - - - @@ -129,10 +56,32 @@ - - + + + + 30 + + + + (System Default) + + + + + + + + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> + - Inhibit multimedia keys on Windows + Select media images from program working directory + + + + + + + Default @@ -149,25 +98,10 @@ - - - - false - - - 30 - - - - (Default) - - - - - - + + - Mouse sensitivity: + Default @@ -193,6 +127,79 @@ + + + + Language: + + + + + + + Ask for confirmation before saving settings + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + Inhibit multimedia keys on Windows + + + + + + + false + + + 30 + + + + (Default) + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Mouse sensitivity: + + + + + + + Ask for confirmation before hard resetting + + + @@ -200,6 +207,13 @@ + + + + Display hotkey message when entering full-screen mode + + + From 0a5fa0da39c12d3f438ea7197943bdf0e2df38e0 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 18 Jan 2025 15:47:41 +0500 Subject: [PATCH 0587/1190] Add variants of the CH Flightstick Pro and Thrustmaster FCS with rudder pedals (CH Pedals and Thrustmaster RCS respectively) attached --- src/game/gameport.c | 26 +++++++------- src/game/joystick_ch_flightstick_pro.c | 38 ++++++++++++++++++++ src/game/joystick_tm_fcs.c | 48 ++++++++++++++++++++++++++ src/include/86box/gameport.h | 2 ++ 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/game/gameport.c b/src/game/gameport.c index 90986a655..8ae1c7d25 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -88,18 +88,20 @@ static const joystick_if_t joystick_none = { static const struct { const joystick_if_t *joystick; } joysticks[] = { - { &joystick_none }, - { &joystick_2axis_2button }, - { &joystick_2axis_4button }, - { &joystick_2axis_6button }, - { &joystick_2axis_8button }, - { &joystick_3axis_2button }, - { &joystick_3axis_4button }, - { &joystick_4axis_4button }, - { &joystick_ch_flightstick_pro }, - { &joystick_sw_pad }, - { &joystick_tm_fcs }, - { NULL } + { &joystick_none }, + { &joystick_2axis_2button }, + { &joystick_2axis_4button }, + { &joystick_2axis_6button }, + { &joystick_2axis_8button }, + { &joystick_3axis_2button }, + { &joystick_3axis_4button }, + { &joystick_4axis_4button }, + { &joystick_ch_flightstick_pro }, + { &joystick_ch_flightstick_pro_ch_pedals }, + { &joystick_sw_pad }, + { &joystick_tm_fcs }, + { &joystick_tm_fcs_rcs }, + { NULL } }; static joystick_instance_t *joystick_instance[GAMEPORT_MAX] = { NULL, NULL }; diff --git a/src/game/joystick_ch_flightstick_pro.c b/src/game/joystick_ch_flightstick_pro.c index 6aaaa5dc5..5b240f3f4 100644 --- a/src/game/joystick_ch_flightstick_pro.c +++ b/src/game/joystick_ch_flightstick_pro.c @@ -112,6 +112,26 @@ ch_flightstick_pro_read_axis(UNUSED(void *priv), int axis) } } +static int +ch_flightstick_pro_ch_pedals_read_axis(UNUSED(void *priv), int axis) +{ + if (!JOYSTICK_PRESENT(0, 0)) + return AXIS_NOT_PRESENT; + + switch (axis) { + case 0: + return joystick_state[0][0].axis[0]; + case 1: + return joystick_state[0][0].axis[1]; + case 2: + return joystick_state[0][0].axis[3]; + case 3: + return joystick_state[0][0].axis[2]; + default: + return 0; + } +} + static void ch_flightstick_pro_a0_over(UNUSED(void *priv)) { @@ -135,3 +155,21 @@ const joystick_if_t joystick_ch_flightstick_pro = { .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, .pov_names = { "POV" } }; + +const joystick_if_t joystick_ch_flightstick_pro_ch_pedals = { + .name = "CH Flightstick Pro + CH Pedals", + .internal_name = "ch_flightstick_pro_ch_pedals", + .init = ch_flightstick_pro_init, + .close = ch_flightstick_pro_close, + .read = ch_flightstick_pro_read, + .write = ch_flightstick_pro_write, + .read_axis = ch_flightstick_pro_ch_pedals_read_axis, + .a0_over = ch_flightstick_pro_a0_over, + .axis_count = 4, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Throttle", "Rudder" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } +}; diff --git a/src/game/joystick_tm_fcs.c b/src/game/joystick_tm_fcs.c index 4440b039e..52d77d8fb 100644 --- a/src/game/joystick_tm_fcs.c +++ b/src/game/joystick_tm_fcs.c @@ -112,6 +112,36 @@ tm_fcs_read_axis(UNUSED(void *priv), int axis) } } +static int +tm_fcs_rcs_read_axis(UNUSED(void *priv), int axis) +{ + if (!JOYSTICK_PRESENT(0, 0)) + return AXIS_NOT_PRESENT; + + switch (axis) { + case 0: + return joystick_state[0][0].axis[0]; + case 1: + return joystick_state[0][0].axis[1]; + case 2: + return joystick_state[0][0].axis[2]; + case 3: + if (joystick_state[0][0].pov[0] == -1) + return 32767; + if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45) + return -32768; + if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135) + return -16384; + if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225) + return 0; + if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315) + return 16384; + return 0; + default: + return 0; + } +} + static void tm_fcs_a0_over(UNUSED(void *priv)) { @@ -135,3 +165,21 @@ const joystick_if_t joystick_tm_fcs = { .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, .pov_names = { "POV" } }; + +const joystick_if_t joystick_tm_fcs_rcs = { + .name = "Thrustmaster FCS + Rudder Control System", + .internal_name = "thrustmaster_fcs_rcs", + .init = tm_fcs_init, + .close = tm_fcs_close, + .read = tm_fcs_read, + .write = tm_fcs_write, + .read_axis = tm_fcs_rcs_read_axis, + .a0_over = tm_fcs_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 1, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis", "Rudder" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { "POV" } +}; diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index c5fc1d192..7928cdd30 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -179,10 +179,12 @@ extern const joystick_if_t joystick_2axis_6button; extern const joystick_if_t joystick_2axis_8button; extern const joystick_if_t joystick_ch_flightstick_pro; +extern const joystick_if_t joystick_ch_flightstick_pro_ch_pedals; extern const joystick_if_t joystick_sw_pad; extern const joystick_if_t joystick_tm_fcs; +extern const joystick_if_t joystick_tm_fcs_rcs; extern int gameport_available(int); extern int gameport_has_config(int); From 99e8d13afa047e3dc7d8aa7afae188e4748055a8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 30 Mar 2024 16:21:41 +0600 Subject: [PATCH 0588/1190] Implement NEC V20/V30's i8080 emulation mode --- src/cpu/8080.c | 290 ------------- src/cpu/808x.c | 168 +++++++- src/cpu/CMakeLists.txt | 2 +- src/cpu/i8080.c | 826 ++++++++++++++++++++++++++++++++++++++ src/cpu/i8080.h | 35 ++ src/include/86box/i8080.h | 69 ---- 6 files changed, 1025 insertions(+), 365 deletions(-) delete mode 100644 src/cpu/8080.c create mode 100644 src/cpu/i8080.c create mode 100644 src/cpu/i8080.h delete mode 100644 src/include/86box/i8080.h diff --git a/src/cpu/8080.c b/src/cpu/8080.c deleted file mode 100644 index 7a7e7b96c..000000000 --- a/src/cpu/8080.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * 8080 CPU emulation. - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345 - */ - -#include -#include -#include "cpu.h" -#include <86box/timer.h> -#include <86box/i8080.h> -#include <86box/mem.h> -#include <86box/plat_unused.h> - -static int completed = 1; -static int in_rep = 0; -static int repeating = 0; -static int rep_c_flag = 0; -static int oldc; -static int cycdiff; -#ifdef UNUSED_8080_VARS -static int prefetching = 1; -static int refresh = 0; -static int clear_lock = 0; - -static uint32_t cpu_src = 0; -static uint32_t cpu_dest = 0; -static uint32_t cpu_data = 0; -#endif - -static void -clock_start(void) -{ - cycdiff = cycles; -} - -static void -clock_end(void) -{ - int diff = cycdiff - cycles; - - /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ - tsc += (uint64_t) diff * (xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) - timer_process(); -} - -static void -i8080_wait(int c, int bus) -{ - cycles -= c; - if (bus < 2) { - clock_end(); - clock_start(); - } -} - -#ifdef UNUSED_8080_FUNCS -static uint8_t -readmemb(uint32_t a) -{ - uint8_t ret; - - i8080_wait(4, 1); - ret = read_mem_b(a); - - return ret; -} - -static uint8_t -ins_fetch(i8080 *cpu) -{ - uint8_t ret = cpu->readmembyte(cpu->pmembase + cpu->pc); - - cpu->pc++; - return ret; -} -#endif - -void -transfer_from_808x(i8080 *cpu) -{ - cpu->hl = BX; - cpu->bc = CX; - cpu->de = DX; - cpu->a = AL; - cpu->flags = cpu_state.flags & 0xFF; - cpu->sp = BP; - cpu->pc = cpu_state.pc; - cpu->oldpc = cpu_state.oldpc; - cpu->pmembase = cs; - cpu->dmembase = ds; -} - -void -transfer_to_808x(i8080 *cpu) -{ - BX = cpu->hl; - CX = cpu->bc; - DX = cpu->de; - AL = cpu->a; - cpu_state.flags &= 0xFF00; - cpu_state.flags |= cpu->flags & 0xFF; - BP = cpu->sp; - cpu_state.pc = cpu->pc; -} - -uint8_t -getreg_i8080(i8080 *cpu, uint8_t reg) -{ - uint8_t ret = 0xFF; - switch (reg) { - case 0x0: - ret = cpu->b; - break; - case 0x1: - ret = cpu->c; - break; - case 0x2: - ret = cpu->d; - break; - case 0x3: - ret = cpu->e; - break; - case 0x4: - ret = cpu->h; - break; - case 0x5: - ret = cpu->l; - break; - case 0x6: - ret = cpu->readmembyte(cpu->dmembase + cpu->sp); - break; - case 0x7: - ret = cpu->a; - break; - } - return ret; -} - -uint8_t -getreg_i8080_emu(i8080 *cpu, uint8_t reg) -{ - uint8_t ret = 0xFF; - switch (reg) { - case 0x0: - ret = CH; - break; - case 0x1: - ret = CL; - break; - case 0x2: - ret = DH; - break; - case 0x3: - ret = DL; - break; - case 0x4: - ret = BH; - break; - case 0x5: - ret = BL; - break; - case 0x6: - ret = cpu->readmembyte(cpu->dmembase + BP); - break; - case 0x7: - ret = AL; - break; - } - return ret; -} - -void -setreg_i8080_emu(i8080 *cpu, uint8_t reg, uint8_t val) -{ - switch (reg) { - case 0x0: - CH = val; - break; - case 0x1: - CL = val; - break; - case 0x2: - DH = val; - break; - case 0x3: - DL = val; - break; - case 0x4: - BH = val; - break; - case 0x5: - BL = val; - break; - case 0x6: - cpu->writemembyte(cpu->dmembase + BP, val); - break; - case 0x7: - AL = val; - break; - } -} - -void -setreg_i8080(i8080 *cpu, uint8_t reg, uint8_t val) -{ - switch (reg) { - case 0x0: - cpu->b = val; - break; - case 0x1: - cpu->c = val; - break; - case 0x2: - cpu->d = val; - break; - case 0x3: - cpu->e = val; - break; - case 0x4: - cpu->h = val; - break; - case 0x5: - cpu->l = val; - break; - case 0x6: - cpu->writemembyte(cpu->dmembase + cpu->sp, val); - break; - case 0x7: - cpu->a = val; - break; - } -} - -void -interpret_exec8080(UNUSED(i8080 *cpu), uint8_t opcode) -{ - switch (opcode) { - case 0x00: - { - break; - } - } -} - -/* Actually implement i8080 emulation. */ -void -exec8080(i8080 *cpu, int cycs) -{ -#ifdef UNUSED_8080_VARS - uint8_t temp = 0, temp2; - uint8_t old_af; - uint8_t handled = 0; - uint16_t addr, tempw; - uint16_t new_ip; - int bits; -#endif - - cycles += cycs; - - while (cycles > 0) { - cpu->startclock(); - - if (!repeating) { - cpu->oldpc = cpu->pc; - opcode = cpu->fetchinstruction(cpu); - oldc = cpu->flags & C_FLAG_I8080; - i8080_wait(1, 0); - } - completed = 1; - if (completed) { - repeating = 0; - in_rep = 0; - rep_c_flag = 0; - cpu->endclock(); - if (cpu->checkinterrupts) - cpu->checkinterrupts(); - } - } -} diff --git a/src/cpu/808x.c b/src/cpu/808x.c index e3a326503..4ce1fa3b9 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -18,10 +18,13 @@ #include #include #include +#include #include #include #include +#include "i8080.h" + #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" @@ -70,6 +73,9 @@ static int in_rep = 0, repeating = 0, rep_c_flag = 0; static int oldc, clear_lock = 0; static int refresh = 0, cycdiff; +static i8080 emulated_processor; +static bool cpu_md_write_disable = 1; + /* Various things needed for 8087. */ #define OP_TABLE(name) ops_##name @@ -195,6 +201,54 @@ prefetch_queue_get_size(void) { return pfq_size; } +static void set_if(int cond); + +void +sync_from_i8080(void) +{ + AL = emulated_processor.a; + BH = emulated_processor.h; + BL = emulated_processor.l; + CH = emulated_processor.b; + CL = emulated_processor.c; + DH = emulated_processor.d; + DL = emulated_processor.e; + BP = emulated_processor.sp; + + cpu_state.pc = emulated_processor.pc; + cpu_state.flags &= 0xFF00; + cpu_state.flags |= emulated_processor.sf << 7; + cpu_state.flags |= emulated_processor.zf << 6; + cpu_state.flags |= emulated_processor.hf << 4; + cpu_state.flags |= emulated_processor.pf << 2; + cpu_state.flags |= 1 << 1; + cpu_state.flags |= emulated_processor.cf << 0; + set_if(emulated_processor.iff); +} + +void +sync_to_i8080(void) +{ + emulated_processor.a = AL; + emulated_processor.h = BH; + emulated_processor.l = BL; + emulated_processor.b = CH; + emulated_processor.c = CL; + emulated_processor.d = DH; + emulated_processor.e = DL; + emulated_processor.sp = BP; + emulated_processor.pc = cpu_state.pc; + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); + + emulated_processor.sf = (cpu_state.flags >> 7) & 1; + emulated_processor.zf = (cpu_state.flags >> 6) & 1; + emulated_processor.hf = (cpu_state.flags >> 4) & 1; + emulated_processor.pf = (cpu_state.flags >> 2) & 1; + emulated_processor.cf = (cpu_state.flags >> 0) & 1; + + emulated_processor.interrupt_delay = noint; +} + uint16_t get_last_addr(void) @@ -582,6 +636,33 @@ load_seg(uint16_t seg, x86seg *s) s->seg = seg & 0xffff; } +uint8_t fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(cs + addr); +} + +uint8_t fetch_i8080_data(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(ds + addr); +} + +void put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val) +{ + writememb(ds, addr, val); +} + +static uint8_t i8080_port_in(UNUSED(void* priv), uint8_t port) +{ + cpu_io(8, 0, port); + return AL; +} + +static void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) +{ + AL = val; + cpu_io(8, 1, port); +} + void reset_808x(int hard) { @@ -619,6 +700,14 @@ reset_808x(int hard) use_custom_nmi_vector = 0x00; custom_nmi_vector = 0x00000000; + + cpu_md_write_disable = 1; + i8080_init(&emulated_processor); + emulated_processor.write_byte = put_i8080_data; + emulated_processor.read_byte = fetch_i8080_data; + emulated_processor.read_byte_seg = fetch_i8080_opcode; + emulated_processor.port_in = i8080_port_in; + emulated_processor.port_out = i8080_port_out; } static void @@ -994,6 +1083,11 @@ interrupt(uint16_t addr) uint16_t new_cs, new_ip; uint16_t tempf; + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + pclog("CALLN/INT#/NMI#\n"); + } + addr <<= 2; cpu_state.eaaddr = addr; old_cs = CS; @@ -1010,6 +1104,8 @@ interrupt(uint16_t addr) tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; access(40, 16); push(&old_cs); old_ip = cpu_state.pc; @@ -1020,6 +1116,56 @@ interrupt(uint16_t addr) push(&old_ip); } +/* Ditto, but for breaking into emulation mode. */ +static void +interrupt_brkem(uint16_t addr) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + addr <<= 2; + cpu_state.eaaddr = addr; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + new_cs = readmemw(0, cpu_state.eaaddr); + prefetching = 0; + pfq_clear(); + ovr_seg = NULL; + access(39, 16); + tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); + push(&tempf); + cpu_state.flags &= ~(MD_FLAG); + cpu_md_write_disable = 0; + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + load_cs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); + sync_to_i8080(); + pclog("BRKEM mode\n"); +} + +void +retem_i8080(void) +{ + sync_from_i8080(); + + cpu_state.pc = pop(); + CS = pop(); + cpu_state.flags = pop() | MD_FLAG; + + cpu_md_write_disable = 1; + pclog("RETEM mode\n"); +} + void interrupt_808x(uint16_t addr) { @@ -1771,6 +1917,15 @@ execx86(int cycs) while (cycles > 0) { clock_start(); + if (is_nec && !(cpu_state.flags & MD_FLAG)) { + i8080_step(&emulated_processor); + set_if(emulated_processor.iff); + cycles -= emulated_processor.cyc; + emulated_processor.cyc = 0; + completed = 1; + goto exec_completed; + } + if (!repeating) { cpu_state.oldpc = cpu_state.pc; opcode = pfq_fetchb(); @@ -2344,8 +2499,8 @@ execx86(int cycs) break; case 0xFF: /* BRKEM */ - /* Unimplemented for now. */ - fatal("808x: Unsupported 8080 emulation mode attempted to enter into!"); + interrupt_brkem(pfq_fetchb()); + handled = 1; break; default: @@ -2857,11 +3012,12 @@ execx86(int cycs) break; case 0x9D: /*POPF*/ access(25, 16); - if (is_nec) + if (is_nec && cpu_md_write_disable) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; wait(1, 0); + sync_to_i8080(); break; case 0x9E: /*SAHF*/ wait(1, 0); @@ -3127,13 +3283,15 @@ execx86(int cycs) access(62, 8); set_ip(new_ip); access(45, 8); - if (is_nec) + if (is_nec && cpu_md_write_disable) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; wait(5, 0); noint = 1; nmi_enable = 1; + if (is_nec && !(cpu_state.flags & MD_FLAG)) + sync_to_i8080(); break; case 0xD0: @@ -3659,7 +3817,7 @@ execx86(int cycs) break; } } - +exec_completed: if (completed) { repeating = 0; ovr_seg = NULL; diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index 9c1385d4f..dc7f5ac11 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -29,7 +29,7 @@ add_library(cpu OBJECT x86seg_2386.c x87.c x87_timings.c - 8080.c + i8080.c ) if(AMD_K5) diff --git a/src/cpu/i8080.c b/src/cpu/i8080.c new file mode 100644 index 000000000..688923997 --- /dev/null +++ b/src/cpu/i8080.c @@ -0,0 +1,826 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Intel 8080 CPU emulation + * + * Authors: Cacodemon345 + * Nicolas Allemand + * + * Copyright (c) 2018 Nicolas Allemand + * Copyright (c) 2024 Cacodemon345 + * + */ + +#include "i8080.h" +#include + +// Changes from upstream: +// Add CALLN and RETEM instructions. +// Add code for instruction fetches. + +// this array defines the number of cycles one opcode takes. +// note that there are some special cases: conditional RETs and CALLs +// add +6 cycles if the condition is met +// clang-format off +static const uint8_t OPCODES_CYCLES[256] = { +// 0 1 2 3 4 5 6 7 8 9 A B C D E F + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 0 + 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 1 + 4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4, // 2 + 4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4, // 3 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 4 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 5 + 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 6 + 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, // 7 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A + 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B + 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // C + 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // D + 5, 10, 10, 18, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11, // E + 5, 10, 10, 4, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11 // F +}; +// clang-format on + +static const char* DISASSEMBLE_TABLE[] = {"nop", "lxi b,#", "stax b", "inx b", + "inr b", "dcr b", "mvi b,#", "rlc", "ill", "dad b", "ldax b", "dcx b", + "inr c", "dcr c", "mvi c,#", "rrc", "ill", "lxi d,#", "stax d", "inx d", + "inr d", "dcr d", "mvi d,#", "ral", "ill", "dad d", "ldax d", "dcx d", + "inr e", "dcr e", "mvi e,#", "rar", "ill", "lxi h,#", "shld", "inx h", + "inr h", "dcr h", "mvi h,#", "daa", "ill", "dad h", "lhld", "dcx h", + "inr l", "dcr l", "mvi l,#", "cma", "ill", "lxi sp,#", "sta $", "inx sp", + "inr M", "dcr M", "mvi M,#", "stc", "ill", "dad sp", "lda $", "dcx sp", + "inr a", "dcr a", "mvi a,#", "cmc", "mov b,b", "mov b,c", "mov b,d", + "mov b,e", "mov b,h", "mov b,l", "mov b,M", "mov b,a", "mov c,b", "mov c,c", + "mov c,d", "mov c,e", "mov c,h", "mov c,l", "mov c,M", "mov c,a", "mov d,b", + "mov d,c", "mov d,d", "mov d,e", "mov d,h", "mov d,l", "mov d,M", "mov d,a", + "mov e,b", "mov e,c", "mov e,d", "mov e,e", "mov e,h", "mov e,l", "mov e,M", + "mov e,a", "mov h,b", "mov h,c", "mov h,d", "mov h,e", "mov h,h", "mov h,l", + "mov h,M", "mov h,a", "mov l,b", "mov l,c", "mov l,d", "mov l,e", "mov l,h", + "mov l,l", "mov l,M", "mov l,a", "mov M,b", "mov M,c", "mov M,d", "mov M,e", + "mov M,h", "mov M,l", "hlt", "mov M,a", "mov a,b", "mov a,c", "mov a,d", + "mov a,e", "mov a,h", "mov a,l", "mov a,M", "mov a,a", "add b", "add c", + "add d", "add e", "add h", "add l", "add M", "add a", "adc b", "adc c", + "adc d", "adc e", "adc h", "adc l", "adc M", "adc a", "sub b", "sub c", + "sub d", "sub e", "sub h", "sub l", "sub M", "sub a", "sbb b", "sbb c", + "sbb d", "sbb e", "sbb h", "sbb l", "sbb M", "sbb a", "ana b", "ana c", + "ana d", "ana e", "ana h", "ana l", "ana M", "ana a", "xra b", "xra c", + "xra d", "xra e", "xra h", "xra l", "xra M", "xra a", "ora b", "ora c", + "ora d", "ora e", "ora h", "ora l", "ora M", "ora a", "cmp b", "cmp c", + "cmp d", "cmp e", "cmp h", "cmp l", "cmp M", "cmp a", "rnz", "pop b", + "jnz $", "jmp $", "cnz $", "push b", "adi #", "rst 0", "rz", "ret", "jz $", + "ill", "cz $", "call $", "aci #", "rst 1", "rnc", "pop d", "jnc $", "out p", + "cnc $", "push d", "sui #", "rst 2", "rc", "ill", "jc $", "in p", "cc $", + "ill", "sbi #", "rst 3", "rpo", "pop h", "jpo $", "xthl", "cpo $", "push h", + "ani #", "rst 4", "rpe", "pchl", "jpe $", "xchg", "cpe $", "ill", "xri #", + "rst 5", "rp", "pop psw", "jp $", "di", "cp $", "push psw", "ori #", + "rst 6", "rm", "sphl", "jm $", "ei", "cm $", "ill", "cpi #", "rst 7"}; + +#define SET_ZSP(c, val) \ + do { \ + c->zf = (val) == 0; \ + c->sf = (val) >> 7; \ + c->pf = parity(val); \ + } while (0) + +// memory helpers (the only four to use `read_byte` and `write_byte` function +// pointers) + +// reads a byte from memory +static inline uint8_t i8080_rb(i8080* const c, uint16_t addr) { + return c->read_byte(c->userdata, addr); +} + +// writes a byte to memory +static inline void i8080_wb(i8080* const c, uint16_t addr, uint8_t val) { + c->write_byte(c->userdata, addr, val); +} + +// reads a word from memory +static inline uint16_t i8080_rw(i8080* const c, uint16_t addr) { + return c->read_byte(c->userdata, addr + 1) << 8 | + c->read_byte(c->userdata, addr); +} + +// writes a word to memory +static inline void i8080_ww(i8080* const c, uint16_t addr, uint16_t val) { + c->write_byte(c->userdata, addr, val & 0xFF); + c->write_byte(c->userdata, addr + 1, val >> 8); +} + +// returns the next byte in memory (and updates the program counter) +static inline uint8_t i8080_next_byte(i8080* const c) { + return c->read_byte_seg ? (c->read_byte_seg(c->userdata, c->pc++)) : i8080_rb(c, c->pc++); +} + +// returns the next word in memory (and updates the program counter) +static inline uint16_t i8080_next_word(i8080* const c) { + uint16_t result = 0; + if (c->read_byte_seg) + result = c->read_byte_seg(c, c->pc) | (c->read_byte_seg(c, c->pc + 1) << 8); + else + result = i8080_rw(c, c->pc); + c->pc += 2; + return result; +} + +// paired registers helpers (setters and getters) +static inline void i8080_set_bc(i8080* const c, uint16_t val) { + c->b = val >> 8; + c->c = val & 0xFF; +} + +static inline void i8080_set_de(i8080* const c, uint16_t val) { + c->d = val >> 8; + c->e = val & 0xFF; +} + +static inline void i8080_set_hl(i8080* const c, uint16_t val) { + c->h = val >> 8; + c->l = val & 0xFF; +} + +static inline uint16_t i8080_get_bc(i8080* const c) { + return (c->b << 8) | c->c; +} + +static inline uint16_t i8080_get_de(i8080* const c) { + return (c->d << 8) | c->e; +} + +static inline uint16_t i8080_get_hl(i8080* const c) { + return (c->h << 8) | c->l; +} + +// stack helpers + +// pushes a value into the stack and updates the stack pointer +static inline void i8080_push_stack(i8080* const c, uint16_t val) { + c->sp -= 2; + i8080_ww(c, c->sp, val); +} + +// pops a value from the stack and updates the stack pointer +static inline uint16_t i8080_pop_stack(i8080* const c) { + uint16_t val = i8080_rw(c, c->sp); + c->sp += 2; + return val; +} + +// opcodes + +// returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1 +static inline bool parity(uint8_t val) { + uint8_t nb_one_bits = 0; + for (int i = 0; i < 8; i++) { + nb_one_bits += ((val >> i) & 1); + } + + return (nb_one_bits & 1) == 0; +} + +// returns if there was a carry between bit "bit_no" and "bit_no - 1" when +// executing "a + b + cy" +static inline bool carry(int bit_no, uint8_t a, uint8_t b, bool cy) { + int16_t result = a + b + cy; + int16_t carry = result ^ a ^ b; + return carry & (1 << bit_no); +} + +// adds a value (+ an optional carry flag) to a register +static inline void i8080_add( + i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { + uint8_t result = *reg + val + cy; + c->cf = carry(8, *reg, val, cy); + c->hf = carry(4, *reg, val, cy); + SET_ZSP(c, result); + *reg = result; +} + +// substracts a byte (+ an optional carry flag) from a register +// see https://stackoverflow.com/a/8037485 +static inline void i8080_sub( + i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { + i8080_add(c, reg, ~val, !cy); + c->cf = !c->cf; +} + +// adds a word to HL +static inline void i8080_dad(i8080* const c, uint16_t val) { + c->cf = ((i8080_get_hl(c) + val) >> 16) & 1; + i8080_set_hl(c, i8080_get_hl(c) + val); +} + +// increments a byte +static inline uint8_t i8080_inr(i8080* const c, uint8_t val) { + uint8_t result = val + 1; + c->hf = (result & 0xF) == 0; + SET_ZSP(c, result); + return result; +} + +// decrements a byte +static inline uint8_t i8080_dcr(i8080* const c, uint8_t val) { + uint8_t result = val - 1; + c->hf = !((result & 0xF) == 0xF); + SET_ZSP(c, result); + return result; +} + +// executes a logic "and" between register A and a byte, then stores the +// result in register A +static inline void i8080_ana(i8080* const c, uint8_t val) { + uint8_t result = c->a & val; + c->cf = 0; + c->hf = ((c->a | val) & 0x08) != 0; + SET_ZSP(c, result); + c->a = result; +} + +// executes a logic "xor" between register A and a byte, then stores the +// result in register A +static inline void i8080_xra(i8080* const c, uint8_t val) { + c->a ^= val; + c->cf = 0; + c->hf = 0; + SET_ZSP(c, c->a); +} + +// executes a logic "or" between register A and a byte, then stores the +// result in register A +static inline void i8080_ora(i8080* const c, uint8_t val) { + c->a |= val; + c->cf = 0; + c->hf = 0; + SET_ZSP(c, c->a); +} + +// compares the register A to another byte +static inline void i8080_cmp(i8080* const c, uint8_t val) { + int16_t result = c->a - val; + c->cf = result >> 8; + c->hf = ~(c->a ^ result ^ val) & 0x10; + SET_ZSP(c, result & 0xFF); +} + +// sets the program counter to a given address +static inline void i8080_jmp(i8080* const c, uint16_t addr) { + c->pc = addr; +} + +// jumps to next address pointed by the next word in memory if a condition +// is met +static inline void i8080_cond_jmp(i8080* const c, bool condition) { + uint16_t addr = i8080_next_word(c); + if (condition) { + c->pc = addr; + } +} + +// pushes the current pc to the stack, then jumps to an address +static inline void i8080_call(i8080* const c, uint16_t addr) { + i8080_push_stack(c, c->pc); + i8080_jmp(c, addr); +} + +// calls to next word in memory if a condition is met +static inline void i8080_cond_call(i8080* const c, bool condition) { + uint16_t addr = i8080_next_word(c); + if (condition) { + i8080_call(c, addr); + c->cyc += 6; + } +} + +// returns from subroutine +static inline void i8080_ret(i8080* const c) { + c->pc = i8080_pop_stack(c); +} + +// returns from subroutine if a condition is met +static inline void i8080_cond_ret(i8080* const c, bool condition) { + if (condition) { + i8080_ret(c); + c->cyc += 6; + } +} + +// pushes register A and the flags into the stack +static inline void i8080_push_psw(i8080* const c) { + // note: bit 3 and 5 are always 0 + uint8_t psw = 0; + psw |= c->sf << 7; + psw |= c->zf << 6; + psw |= c->hf << 4; + psw |= c->pf << 2; + psw |= 1 << 1; // bit 1 is always 1 + psw |= c->cf << 0; + i8080_push_stack(c, c->a << 8 | psw); +} + +// pops register A and the flags from the stack +static inline void i8080_pop_psw(i8080* const c) { + uint16_t af = i8080_pop_stack(c); + c->a = af >> 8; + uint8_t psw = af & 0xFF; + + c->sf = (psw >> 7) & 1; + c->zf = (psw >> 6) & 1; + c->hf = (psw >> 4) & 1; + c->pf = (psw >> 2) & 1; + c->cf = (psw >> 0) & 1; +} + +// rotate register A left +static inline void i8080_rlc(i8080* const c) { + c->cf = c->a >> 7; + c->a = (c->a << 1) | c->cf; +} + +// rotate register A right +static inline void i8080_rrc(i8080* const c) { + c->cf = c->a & 1; + c->a = (c->a >> 1) | (c->cf << 7); +} + +// rotate register A left with the carry flag +static inline void i8080_ral(i8080* const c) { + bool cy = c->cf; + c->cf = c->a >> 7; + c->a = (c->a << 1) | cy; +} + +// rotate register A right with the carry flag +static inline void i8080_rar(i8080* const c) { + bool cy = c->cf; + c->cf = c->a & 1; + c->a = (c->a >> 1) | (cy << 7); +} + +// Decimal Adjust Accumulator: the eight-bit number in register A is adjusted +// to form two four-bit binary-coded-decimal digits. +// For example, if A=$2B and DAA is executed, A becomes $31. +static inline void i8080_daa(i8080* const c) { + bool cy = c->cf; + uint8_t correction = 0; + + uint8_t lsb = c->a & 0x0F; + uint8_t msb = c->a >> 4; + + if (c->hf || lsb > 9) { + correction += 0x06; + } + + if (c->cf || msb > 9 || (msb >= 9 && lsb > 9)) { + correction += 0x60; + cy = 1; + } + + i8080_add(c, &c->a, correction, 0); + c->cf = cy; +} + +// switches the value of registers DE and HL +static inline void i8080_xchg(i8080* const c) { + uint16_t de = i8080_get_de(c); + i8080_set_de(c, i8080_get_hl(c)); + i8080_set_hl(c, de); +} + +// switches the value of a word at (sp) and HL +static inline void i8080_xthl(i8080* const c) { + uint16_t val = i8080_rw(c, c->sp); + i8080_ww(c, c->sp, i8080_get_hl(c)); + i8080_set_hl(c, val); +} + +extern void interrupt_808x(uint16_t addr); +extern void retem_i8080(void); +// executes one opcode +static inline void i8080_execute(i8080* const c, uint8_t opcode) { + c->cyc += OPCODES_CYCLES[opcode]; + + // when DI is executed, interrupts won't be serviced + // until the end of next instruction: + if (c->interrupt_delay > 0) { + c->interrupt_delay -= 1; + } + + switch (opcode) { + case 0x7F: c->a = c->a; break; // MOV A,A + case 0x78: c->a = c->b; break; // MOV A,B + case 0x79: c->a = c->c; break; // MOV A,C + case 0x7A: c->a = c->d; break; // MOV A,D + case 0x7B: c->a = c->e; break; // MOV A,E + case 0x7C: c->a = c->h; break; // MOV A,H + case 0x7D: c->a = c->l; break; // MOV A,L + case 0x7E: c->a = i8080_rb(c, i8080_get_hl(c)); break; // MOV A,M + + case 0x0A: c->a = i8080_rb(c, i8080_get_bc(c)); break; // LDAX B + case 0x1A: c->a = i8080_rb(c, i8080_get_de(c)); break; // LDAX D + case 0x3A: c->a = i8080_rb(c, i8080_next_word(c)); break; // LDA word + + case 0x47: c->b = c->a; break; // MOV B,A + case 0x40: c->b = c->b; break; // MOV B,B + case 0x41: c->b = c->c; break; // MOV B,C + case 0x42: c->b = c->d; break; // MOV B,D + case 0x43: c->b = c->e; break; // MOV B,E + case 0x44: c->b = c->h; break; // MOV B,H + case 0x45: c->b = c->l; break; // MOV B,L + case 0x46: c->b = i8080_rb(c, i8080_get_hl(c)); break; // MOV B,M + + case 0x4F: c->c = c->a; break; // MOV C,A + case 0x48: c->c = c->b; break; // MOV C,B + case 0x49: c->c = c->c; break; // MOV C,C + case 0x4A: c->c = c->d; break; // MOV C,D + case 0x4B: c->c = c->e; break; // MOV C,E + case 0x4C: c->c = c->h; break; // MOV C,H + case 0x4D: c->c = c->l; break; // MOV C,L + case 0x4E: c->c = i8080_rb(c, i8080_get_hl(c)); break; // MOV C,M + + case 0x57: c->d = c->a; break; // MOV D,A + case 0x50: c->d = c->b; break; // MOV D,B + case 0x51: c->d = c->c; break; // MOV D,C + case 0x52: c->d = c->d; break; // MOV D,D + case 0x53: c->d = c->e; break; // MOV D,E + case 0x54: c->d = c->h; break; // MOV D,H + case 0x55: c->d = c->l; break; // MOV D,L + case 0x56: c->d = i8080_rb(c, i8080_get_hl(c)); break; // MOV D,M + + case 0x5F: c->e = c->a; break; // MOV E,A + case 0x58: c->e = c->b; break; // MOV E,B + case 0x59: c->e = c->c; break; // MOV E,C + case 0x5A: c->e = c->d; break; // MOV E,D + case 0x5B: c->e = c->e; break; // MOV E,E + case 0x5C: c->e = c->h; break; // MOV E,H + case 0x5D: c->e = c->l; break; // MOV E,L + case 0x5E: c->e = i8080_rb(c, i8080_get_hl(c)); break; // MOV E,M + + case 0x67: c->h = c->a; break; // MOV H,A + case 0x60: c->h = c->b; break; // MOV H,B + case 0x61: c->h = c->c; break; // MOV H,C + case 0x62: c->h = c->d; break; // MOV H,D + case 0x63: c->h = c->e; break; // MOV H,E + case 0x64: c->h = c->h; break; // MOV H,H + case 0x65: c->h = c->l; break; // MOV H,L + case 0x66: c->h = i8080_rb(c, i8080_get_hl(c)); break; // MOV H,M + + case 0x6F: c->l = c->a; break; // MOV L,A + case 0x68: c->l = c->b; break; // MOV L,B + case 0x69: c->l = c->c; break; // MOV L,C + case 0x6A: c->l = c->d; break; // MOV L,D + case 0x6B: c->l = c->e; break; // MOV L,E + case 0x6C: c->l = c->h; break; // MOV L,H + case 0x6D: c->l = c->l; break; // MOV L,L + case 0x6E: c->l = i8080_rb(c, i8080_get_hl(c)); break; // MOV L,M + + case 0x77: i8080_wb(c, i8080_get_hl(c), c->a); break; // MOV M,A + case 0x70: i8080_wb(c, i8080_get_hl(c), c->b); break; // MOV M,B + case 0x71: i8080_wb(c, i8080_get_hl(c), c->c); break; // MOV M,C + case 0x72: i8080_wb(c, i8080_get_hl(c), c->d); break; // MOV M,D + case 0x73: i8080_wb(c, i8080_get_hl(c), c->e); break; // MOV M,E + case 0x74: i8080_wb(c, i8080_get_hl(c), c->h); break; // MOV M,H + case 0x75: i8080_wb(c, i8080_get_hl(c), c->l); break; // MOV M,L + + case 0x3E: c->a = i8080_next_byte(c); break; // MVI A,byte + case 0x06: c->b = i8080_next_byte(c); break; // MVI B,byte + case 0x0E: c->c = i8080_next_byte(c); break; // MVI C,byte + case 0x16: c->d = i8080_next_byte(c); break; // MVI D,byte + case 0x1E: c->e = i8080_next_byte(c); break; // MVI E,byte + case 0x26: c->h = i8080_next_byte(c); break; // MVI H,byte + case 0x2E: c->l = i8080_next_byte(c); break; // MVI L,byte + case 0x36: + i8080_wb(c, i8080_get_hl(c), i8080_next_byte(c)); + break; // MVI M,byte + + case 0x02: i8080_wb(c, i8080_get_bc(c), c->a); break; // STAX B + case 0x12: i8080_wb(c, i8080_get_de(c), c->a); break; // STAX D + case 0x32: i8080_wb(c, i8080_next_word(c), c->a); break; // STA word + + case 0x01: i8080_set_bc(c, i8080_next_word(c)); break; // LXI B,word + case 0x11: i8080_set_de(c, i8080_next_word(c)); break; // LXI D,word + case 0x21: i8080_set_hl(c, i8080_next_word(c)); break; // LXI H,word + case 0x31: c->sp = i8080_next_word(c); break; // LXI SP,word + case 0x2A: i8080_set_hl(c, i8080_rw(c, i8080_next_word(c))); break; // LHLD + case 0x22: i8080_ww(c, i8080_next_word(c), i8080_get_hl(c)); break; // SHLD + case 0xF9: c->sp = i8080_get_hl(c); break; // SPHL + + case 0xEB: i8080_xchg(c); break; // XCHG + case 0xE3: i8080_xthl(c); break; // XTHL + + case 0x87: i8080_add(c, &c->a, c->a, 0); break; // ADD A + case 0x80: i8080_add(c, &c->a, c->b, 0); break; // ADD B + case 0x81: i8080_add(c, &c->a, c->c, 0); break; // ADD C + case 0x82: i8080_add(c, &c->a, c->d, 0); break; // ADD D + case 0x83: i8080_add(c, &c->a, c->e, 0); break; // ADD E + case 0x84: i8080_add(c, &c->a, c->h, 0); break; // ADD H + case 0x85: i8080_add(c, &c->a, c->l, 0); break; // ADD L + case 0x86: + i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); + break; // ADD M + case 0xC6: i8080_add(c, &c->a, i8080_next_byte(c), 0); break; // ADI byte + + case 0x8F: i8080_add(c, &c->a, c->a, c->cf); break; // ADC A + case 0x88: i8080_add(c, &c->a, c->b, c->cf); break; // ADC B + case 0x89: i8080_add(c, &c->a, c->c, c->cf); break; // ADC C + case 0x8A: i8080_add(c, &c->a, c->d, c->cf); break; // ADC D + case 0x8B: i8080_add(c, &c->a, c->e, c->cf); break; // ADC E + case 0x8C: i8080_add(c, &c->a, c->h, c->cf); break; // ADC H + case 0x8D: i8080_add(c, &c->a, c->l, c->cf); break; // ADC L + case 0x8E: + i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); + break; // ADC M + case 0xCE: i8080_add(c, &c->a, i8080_next_byte(c), c->cf); break; // ACI byte + + case 0x97: i8080_sub(c, &c->a, c->a, 0); break; // SUB A + case 0x90: i8080_sub(c, &c->a, c->b, 0); break; // SUB B + case 0x91: i8080_sub(c, &c->a, c->c, 0); break; // SUB C + case 0x92: i8080_sub(c, &c->a, c->d, 0); break; // SUB D + case 0x93: i8080_sub(c, &c->a, c->e, 0); break; // SUB E + case 0x94: i8080_sub(c, &c->a, c->h, 0); break; // SUB H + case 0x95: i8080_sub(c, &c->a, c->l, 0); break; // SUB L + case 0x96: + i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); + break; // SUB M + case 0xD6: i8080_sub(c, &c->a, i8080_next_byte(c), 0); break; // SUI byte + + case 0x9F: i8080_sub(c, &c->a, c->a, c->cf); break; // SBB A + case 0x98: i8080_sub(c, &c->a, c->b, c->cf); break; // SBB B + case 0x99: i8080_sub(c, &c->a, c->c, c->cf); break; // SBB C + case 0x9A: i8080_sub(c, &c->a, c->d, c->cf); break; // SBB D + case 0x9B: i8080_sub(c, &c->a, c->e, c->cf); break; // SBB E + case 0x9C: i8080_sub(c, &c->a, c->h, c->cf); break; // SBB H + case 0x9D: i8080_sub(c, &c->a, c->l, c->cf); break; // SBB L + case 0x9E: + i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); + break; // SBB M + case 0xDE: i8080_sub(c, &c->a, i8080_next_byte(c), c->cf); break; // SBI byte + + case 0x09: i8080_dad(c, i8080_get_bc(c)); break; // DAD B + case 0x19: i8080_dad(c, i8080_get_de(c)); break; // DAD D + case 0x29: i8080_dad(c, i8080_get_hl(c)); break; // DAD H + case 0x39: i8080_dad(c, c->sp); break; // DAD SP + + case 0xF3: c->iff = 0; break; // DI + case 0xFB: + c->iff = 1; + c->interrupt_delay = 1; + break; // EI + case 0x00: break; // NOP + case 0x76: c->halted = 1; break; // HLT + + case 0x3C: c->a = i8080_inr(c, c->a); break; // INR A + case 0x04: c->b = i8080_inr(c, c->b); break; // INR B + case 0x0C: c->c = i8080_inr(c, c->c); break; // INR C + case 0x14: c->d = i8080_inr(c, c->d); break; // INR D + case 0x1C: c->e = i8080_inr(c, c->e); break; // INR E + case 0x24: c->h = i8080_inr(c, c->h); break; // INR H + case 0x2C: c->l = i8080_inr(c, c->l); break; // INR L + case 0x34: + i8080_wb(c, i8080_get_hl(c), i8080_inr(c, i8080_rb(c, i8080_get_hl(c)))); + break; // INR M + + case 0x3D: c->a = i8080_dcr(c, c->a); break; // DCR A + case 0x05: c->b = i8080_dcr(c, c->b); break; // DCR B + case 0x0D: c->c = i8080_dcr(c, c->c); break; // DCR C + case 0x15: c->d = i8080_dcr(c, c->d); break; // DCR D + case 0x1D: c->e = i8080_dcr(c, c->e); break; // DCR E + case 0x25: c->h = i8080_dcr(c, c->h); break; // DCR H + case 0x2D: c->l = i8080_dcr(c, c->l); break; // DCR L + case 0x35: + i8080_wb(c, i8080_get_hl(c), i8080_dcr(c, i8080_rb(c, i8080_get_hl(c)))); + break; // DCR M + + case 0x03: i8080_set_bc(c, i8080_get_bc(c) + 1); break; // INX B + case 0x13: i8080_set_de(c, i8080_get_de(c) + 1); break; // INX D + case 0x23: i8080_set_hl(c, i8080_get_hl(c) + 1); break; // INX H + case 0x33: c->sp += 1; break; // INX SP + + case 0x0B: i8080_set_bc(c, i8080_get_bc(c) - 1); break; // DCX B + case 0x1B: i8080_set_de(c, i8080_get_de(c) - 1); break; // DCX D + case 0x2B: i8080_set_hl(c, i8080_get_hl(c) - 1); break; // DCX H + case 0x3B: c->sp -= 1; break; // DCX SP + + case 0x27: i8080_daa(c); break; // DAA + case 0x2F: c->a = ~c->a; break; // CMA + case 0x37: c->cf = 1; break; // STC + case 0x3F: c->cf = !c->cf; break; // CMC + + case 0x07: i8080_rlc(c); break; // RLC (rotate left) + case 0x0F: i8080_rrc(c); break; // RRC (rotate right) + case 0x17: i8080_ral(c); break; // RAL + case 0x1F: i8080_rar(c); break; // RAR + + case 0xA7: i8080_ana(c, c->a); break; // ANA A + case 0xA0: i8080_ana(c, c->b); break; // ANA B + case 0xA1: i8080_ana(c, c->c); break; // ANA C + case 0xA2: i8080_ana(c, c->d); break; // ANA D + case 0xA3: i8080_ana(c, c->e); break; // ANA E + case 0xA4: i8080_ana(c, c->h); break; // ANA H + case 0xA5: i8080_ana(c, c->l); break; // ANA L + case 0xA6: i8080_ana(c, i8080_rb(c, i8080_get_hl(c))); break; // ANA M + case 0xE6: i8080_ana(c, i8080_next_byte(c)); break; // ANI byte + + case 0xAF: i8080_xra(c, c->a); break; // XRA A + case 0xA8: i8080_xra(c, c->b); break; // XRA B + case 0xA9: i8080_xra(c, c->c); break; // XRA C + case 0xAA: i8080_xra(c, c->d); break; // XRA D + case 0xAB: i8080_xra(c, c->e); break; // XRA E + case 0xAC: i8080_xra(c, c->h); break; // XRA H + case 0xAD: i8080_xra(c, c->l); break; // XRA L + case 0xAE: i8080_xra(c, i8080_rb(c, i8080_get_hl(c))); break; // XRA M + case 0xEE: i8080_xra(c, i8080_next_byte(c)); break; // XRI byte + + case 0xB7: i8080_ora(c, c->a); break; // ORA A + case 0xB0: i8080_ora(c, c->b); break; // ORA B + case 0xB1: i8080_ora(c, c->c); break; // ORA C + case 0xB2: i8080_ora(c, c->d); break; // ORA D + case 0xB3: i8080_ora(c, c->e); break; // ORA E + case 0xB4: i8080_ora(c, c->h); break; // ORA H + case 0xB5: i8080_ora(c, c->l); break; // ORA L + case 0xB6: i8080_ora(c, i8080_rb(c, i8080_get_hl(c))); break; // ORA M + case 0xF6: i8080_ora(c, i8080_next_byte(c)); break; // ORI byte + + case 0xBF: i8080_cmp(c, c->a); break; // CMP A + case 0xB8: i8080_cmp(c, c->b); break; // CMP B + case 0xB9: i8080_cmp(c, c->c); break; // CMP C + case 0xBA: i8080_cmp(c, c->d); break; // CMP D + case 0xBB: i8080_cmp(c, c->e); break; // CMP E + case 0xBC: i8080_cmp(c, c->h); break; // CMP H + case 0xBD: i8080_cmp(c, c->l); break; // CMP L + case 0xBE: i8080_cmp(c, i8080_rb(c, i8080_get_hl(c))); break; // CMP M + case 0xFE: i8080_cmp(c, i8080_next_byte(c)); break; // CPI byte + + case 0xC3: i8080_jmp(c, i8080_next_word(c)); break; // JMP + case 0xC2: i8080_cond_jmp(c, c->zf == 0); break; // JNZ + case 0xCA: i8080_cond_jmp(c, c->zf == 1); break; // JZ + case 0xD2: i8080_cond_jmp(c, c->cf == 0); break; // JNC + case 0xDA: i8080_cond_jmp(c, c->cf == 1); break; // JC + case 0xE2: i8080_cond_jmp(c, c->pf == 0); break; // JPO + case 0xEA: i8080_cond_jmp(c, c->pf == 1); break; // JPE + case 0xF2: i8080_cond_jmp(c, c->sf == 0); break; // JP + case 0xFA: i8080_cond_jmp(c, c->sf == 1); break; // JM + + case 0xE9: c->pc = i8080_get_hl(c); break; // PCHL + case 0xCD: i8080_call(c, i8080_next_word(c)); break; // CALL + + case 0xC4: i8080_cond_call(c, c->zf == 0); break; // CNZ + case 0xCC: i8080_cond_call(c, c->zf == 1); break; // CZ + case 0xD4: i8080_cond_call(c, c->cf == 0); break; // CNC + case 0xDC: i8080_cond_call(c, c->cf == 1); break; // CC + case 0xE4: i8080_cond_call(c, c->pf == 0); break; // CPO + case 0xEC: i8080_cond_call(c, c->pf == 1); break; // CPE + case 0xF4: i8080_cond_call(c, c->sf == 0); break; // CP + case 0xFC: i8080_cond_call(c, c->sf == 1); break; // CM + + case 0xC9: i8080_ret(c); break; // RET + case 0xC0: i8080_cond_ret(c, c->zf == 0); break; // RNZ + case 0xC8: i8080_cond_ret(c, c->zf == 1); break; // RZ + case 0xD0: i8080_cond_ret(c, c->cf == 0); break; // RNC + case 0xD8: i8080_cond_ret(c, c->cf == 1); break; // RC + case 0xE0: i8080_cond_ret(c, c->pf == 0); break; // RPO + case 0xE8: i8080_cond_ret(c, c->pf == 1); break; // RPE + case 0xF0: i8080_cond_ret(c, c->sf == 0); break; // RP + case 0xF8: i8080_cond_ret(c, c->sf == 1); break; // RM + + case 0xC7: i8080_call(c, 0x00); break; // RST 0 + case 0xCF: i8080_call(c, 0x08); break; // RST 1 + case 0xD7: i8080_call(c, 0x10); break; // RST 2 + case 0xDF: i8080_call(c, 0x18); break; // RST 3 + case 0xE7: i8080_call(c, 0x20); break; // RST 4 + case 0xEF: i8080_call(c, 0x28); break; // RST 5 + case 0xF7: i8080_call(c, 0x30); break; // RST 6 + case 0xFF: i8080_call(c, 0x38); break; // RST 7 + + case 0xC5: i8080_push_stack(c, i8080_get_bc(c)); break; // PUSH B + case 0xD5: i8080_push_stack(c, i8080_get_de(c)); break; // PUSH D + case 0xE5: i8080_push_stack(c, i8080_get_hl(c)); break; // PUSH H + case 0xF5: i8080_push_psw(c); break; // PUSH PSW + case 0xC1: i8080_set_bc(c, i8080_pop_stack(c)); break; // POP B + case 0xD1: i8080_set_de(c, i8080_pop_stack(c)); break; // POP D + case 0xE1: i8080_set_hl(c, i8080_pop_stack(c)); break; // POP H + case 0xF1: i8080_pop_psw(c); break; // POP PSW + + case 0xDB: c->a = c->port_in(c->userdata, i8080_next_byte(c)); break; // IN + case 0xD3: c->port_out(c->userdata, i8080_next_byte(c), c->a); break; // OUT + + case 0x08: + case 0x10: + case 0x18: + case 0x20: + case 0x28: + case 0x30: + case 0x38: break; // undocumented NOPs + + case 0xD9: i8080_ret(c); break; // undocumented RET + + case 0xDD: + case 0xED: + { + if (opcode == 0xED) { + uint8_t data = i8080_next_byte(c); + if (data == 0xED) { + interrupt_808x(i8080_next_byte(c)); + break; + } else if (data == 0xFD) { + retem_i8080(); + break; + } + else { + i8080_call(c, (i8080_next_byte(c) << 8) | data); break; + } + } + } + case 0xFD: i8080_call(c, i8080_next_word(c)); break; // undocumented CALLs + + case 0xCB: i8080_jmp(c, i8080_next_word(c)); break; // undocumented JMP + } +} + +// initialises the emulator with default values +void i8080_init(i8080* const c) { + c->read_byte = NULL; + c->write_byte = NULL; + c->port_in = NULL; + c->port_out = NULL; + c->userdata = NULL; + + c->cyc = 0; + + c->pc = 0; + c->sp = 0; + + c->a = 0; + c->b = 0; + c->c = 0; + c->d = 0; + c->e = 0; + c->h = 0; + c->l = 0; + + c->sf = 0; + c->zf = 0; + c->hf = 0; + c->pf = 0; + c->cf = 0; + c->iff = 0; + + c->halted = 0; + c->interrupt_pending = 0; + c->interrupt_vector = 0; + c->interrupt_delay = 0; +} + +// executes one instruction +void i8080_step(i8080* const c) { + // interrupt processing: if an interrupt is pending and IFF is set, + // we execute the interrupt vector passed by the user. + if (c->interrupt_pending && c->iff && c->interrupt_delay == 0) { + c->interrupt_pending = 0; + c->iff = 0; + c->halted = 0; + + i8080_execute(c, c->interrupt_vector); + } else if (!c->halted) { + i8080_execute(c, i8080_next_byte(c)); + } +} + +// asks for an interrupt to be serviced +void i8080_interrupt(i8080* const c, uint8_t opcode) { + c->interrupt_pending = 1; + c->interrupt_vector = opcode; +} + +// outputs a debug trace of the emulator state to the standard output, +// including registers and flags +void i8080_debug_output(i8080* const c, bool print_disassembly) { + uint8_t f = 0; + f |= c->sf << 7; + f |= c->zf << 6; + f |= c->hf << 4; + f |= c->pf << 2; + f |= 1 << 1; // bit 1 is always 1 + f |= c->cf << 0; + + printf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, CYC: %lu", + c->pc, c->a << 8 | f, i8080_get_bc(c), i8080_get_de(c), i8080_get_hl(c), + c->sp, c->cyc); + + printf("\t(%02X %02X %02X %02X)", i8080_rb(c, c->pc), i8080_rb(c, c->pc + 1), + i8080_rb(c, c->pc + 2), i8080_rb(c, c->pc + 3)); + + if (print_disassembly) { + printf(" - %s", DISASSEMBLE_TABLE[i8080_rb(c, c->pc)]); + } + + printf("\n"); +} + +#undef SET_ZSP diff --git a/src/cpu/i8080.h b/src/cpu/i8080.h new file mode 100644 index 000000000..43406e43e --- /dev/null +++ b/src/cpu/i8080.h @@ -0,0 +1,35 @@ +#ifndef I8080_I8080_H_ +#define I8080_I8080_H_ + +#include +#include +#include + +typedef struct i8080 { + // memory + io interface + uint8_t (*read_byte)(void*, uint16_t); // user function to read from memory + void (*write_byte)(void*, uint16_t, uint8_t); // same for writing to memory + uint8_t (*read_byte_seg)(void*, uint16_t); // user function to read from memory (Code segment) + uint8_t (*port_in)(void*, uint8_t); // user function to read from port + void (*port_out)(void*, uint8_t, uint8_t); // same for writing to port + void* userdata; // user custom pointer + + unsigned long cyc; // cycle count + + uint16_t pc, sp; // program counter, stack pointer + uint8_t a, b, c, d, e, h, l; // registers + // flags: sign, zero, half-carry, parity, carry, interrupt flip-flop + bool sf : 1, zf : 1, hf : 1, pf : 1, cf : 1, iff : 1; + bool halted : 1; + + bool interrupt_pending : 1; + uint8_t interrupt_vector; + uint8_t interrupt_delay; +} i8080; + +void i8080_init(i8080* const c); +void i8080_step(i8080* const c); +void i8080_interrupt(i8080* const c, uint8_t opcode); +void i8080_debug_output(i8080* const c, bool print_disassembly); + +#endif // I8080_I8080_H_ diff --git a/src/include/86box/i8080.h b/src/include/86box/i8080.h deleted file mode 100644 index 9a25b5d1b..000000000 --- a/src/include/86box/i8080.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * 8080 CPU emulation (header). - * - * - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345 - */ - -#include - -typedef struct i8080 { - union { - uint16_t af; /* Intended in case we also go for μPD9002 emulation, which also has a Z80 emulation mode. */ - struct { - uint8_t a; - uint8_t flags; - }; - }; - union { - uint16_t bc; - struct { - uint8_t b; - uint8_t c; - }; - }; - union { - uint16_t de; - struct { - uint8_t d; - uint8_t e; - }; - }; - union { - uint16_t hl; - struct { - uint8_t h; - uint8_t l; - }; - }; - uint16_t pc; - uint16_t sp; - uint16_t oldpc; - uint16_t ei; - uint32_t pmembase; - uint32_t dmembase; /* Base from where i8080 starts. */ - uint8_t emulated; /* 0 = not emulated, use separate registers, 1 = emulated, use x86 registers. */ - uint16_t *cpu_flags; - void (*writemembyte)(uint32_t, uint8_t); - uint8_t (*readmembyte)(uint32_t); - void (*startclock)(void); - void (*endclock)(void); - void (*checkinterrupts)(void); - uint8_t (*fetchinstruction)(void *); -} i8080; - -#define C_FLAG_I8080 (1 << 0) -#define P_FLAG_I8080 (1 << 2) -#define AC_FLAG_I8080 (1 << 4) -#define Z_FLAG_I8080 (1 << 6) -#define S_FLAG_I8080 (1 << 7) From 2b107725bdc9a30f94d4af0b55483c37047744aa Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 20:17:13 +0600 Subject: [PATCH 0589/1190] Custom NMI handling for i8080 emulation --- src/cpu/808x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 4ce1fa3b9..c07e583ae 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1179,6 +1179,11 @@ custom_nmi(void) uint16_t new_cs, new_ip; uint16_t tempf; + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + pclog("NMI# (CUTSOM)\n"); + } + cpu_state.eaaddr = 0x0002; old_cs = CS; access(5, 16); @@ -1196,6 +1201,8 @@ custom_nmi(void) tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; access(40, 16); push(&old_cs); old_ip = cpu_state.pc; From 929a9fb25e4a6ce86dfa81305e63e4267545d444 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 26 Mar 2025 19:30:21 +0500 Subject: [PATCH 0590/1190] Network settings page redesign Co-Authored-By: cold-brewed <47337035+cold-brewed@users.noreply.github.com> --- src/qt/qt_settingsnetwork.cpp | 61 +++- src/qt/qt_settingsnetwork.ui | 606 ++++++++++++++++++---------------- 2 files changed, 369 insertions(+), 298 deletions(-) diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 2aa3705fd..a0acd7a3f 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -35,25 +35,58 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) for (int i = 0; i < NET_CARD_MAX; ++i) { auto *nic_cbox = findChild(QString("comboBoxNIC%1").arg(i + 1)); auto *net_type_cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); + + auto *intf_label = findChild(QString("interfaceLabel%1").arg(i + 1)); auto *intf_cbox = findChild(QString("comboBoxIntf%1").arg(i + 1)); + auto *conf_btn = findChild(QString("pushButtonConf%1").arg(i + 1)); +// auto *net_type_conf_btn = findChild(QString("pushButtonNetTypeConf%1").arg(i + 1)); + + auto *vde_socket_label = findChild(QString("socketVDELabel%1").arg(i + 1)); auto *socket_line = findChild(QString("socketVDENIC%1").arg(i + 1)); - int netType = net_type_cbox->currentData().toInt(); - bool adaptersEnabled = netType == NET_TYPE_NONE - || netType == NET_TYPE_SLIRP - || netType == NET_TYPE_VDE - || (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0); + auto *option_list_label = findChild(QString("optionListLabel%1").arg(i + 1)); + auto *option_list_line = findChild(QString("optionListLine%1").arg(i + 1)); intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP); - nic_cbox->setEnabled(adaptersEnabled); - int netCard = nic_cbox->currentData().toInt(); - if ((i == 0) && (netCard == NET_INTERNAL)) - conf_btn->setEnabled(adaptersEnabled && machine_has_flags(machineId, MACHINE_NIC) && - device_has_config(machine_get_net_device(machineId))); - else - conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt())); - socket_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_VDE); + conf_btn->setEnabled(network_card_has_config(nic_cbox->currentData().toInt())); +// net_type_conf_btn->setEnabled(network_type_has_config(netType)); + + // Option list label and line + option_list_label->setVisible(false); + option_list_line->setVisible(false); + + + // VDE + vde_socket_label->setVisible(false); + socket_line->setVisible(false); + + // PCAP + intf_cbox->setVisible(false); + intf_label->setVisible(false); + + // Don't enable anything unless there's a nic selected + if(nic_cbox->currentData().toInt() != 0) { + // Then only enable as needed based on network type + switch (net_type_cbox->currentData().toInt()) { + case NET_TYPE_VDE: + // option_list_label->setText("VDE Options"); + option_list_label->setVisible(true); + option_list_line->setVisible(true); + + vde_socket_label->setVisible(true); + socket_line->setVisible(true); + break; + case NET_TYPE_PCAP: + // option_list_label->setText("PCAP Options"); + option_list_label->setVisible(true); + option_list_line->setVisible(true); + + intf_cbox->setVisible(true); + intf_label->setVisible(true); + break; + } + } } } @@ -154,7 +187,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) } model->removeRows(0, removeRows); - cbox->setCurrentIndex(net_cards_conf[i].net_type); + cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type)); selectedRow = 0; diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui index 8f1eb5a79..741b60648 100644 --- a/src/qt/qt_settingsnetwork.ui +++ b/src/qt/qt_settingsnetwork.ui @@ -36,20 +36,7 @@ Network Card #1 - - - - - 0 - 0 - - - - Mode - - - - + 30 @@ -63,32 +50,6 @@ - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - @@ -101,23 +62,40 @@ - - - - 30 + + + + Qt::Vertical + + + 20 + 40 + + + + + + - + 0 0 - - QComboBox::AdjustToContents + + Mode - + + + + Qt::Horizontal + + + + @@ -130,21 +108,74 @@ + + + + Options + + + - + + + + 0 + 0 + + + + Interface + + + + + VDE Socket - + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + 127 - + + + + + 0 + 0 + + + + + + + + + Network Card #2 + + + Qt::Vertical @@ -157,13 +188,26 @@ - - - - - Network Card #2 - - + + + + + 0 + 0 + + + + Interface + + + + + + + Options + + + @@ -177,7 +221,7 @@ - + 30 @@ -190,33 +234,21 @@ - - - - - 0 - 0 - - + + - Interface + VDE Socket - - - - 30 - - - - 0 - 0 - + + + + Qt::Horizontal - + @@ -229,7 +261,20 @@ - + + + + + 0 + 0 + + + + Configure + + + + 30 @@ -245,40 +290,19 @@ - - - - Configure + + + + + + + + 0 + 0 + - - - - VDE Socket - - - - - - - 127 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -286,6 +310,69 @@ Network Card #3 + + + + 30 + + + + 0 + 0 + + + + + + + + VDE Socket + + + + + + + Options + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + + + + + 0 + 0 + + + + Interface + + + + + + + Qt::Horizontal + + + @@ -299,75 +386,7 @@ - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Adapter - - - - - - - 30 - - - - 0 - 0 - - - - QComboBox::AdjustToContents - - - - + @@ -380,21 +399,33 @@ - - + + + + + 0 + 0 + + - VDE Socket + Adapter - - - - 127 + + + + + + + + 0 + 0 + - + Qt::Vertical @@ -414,6 +445,13 @@ Network Card #4 + + + + Options + + + @@ -427,102 +465,7 @@ - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Interface - - - - - - - 30 - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Adapter - - - - - - - 30 - - - - 0 - 0 - - - - QComboBox::AdjustToContents - - - - - - - - 0 - 0 - - - - Configure - - - - - - - 127 - - - - - - - VDE Socket - - - - + Qt::Vertical @@ -535,6 +478,101 @@ + + + + VDE Socket + + + + + + + + 0 + 0 + + + + Adapter + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + Interface + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 30 + + + + + + + 30 + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Configure + + + + + + + + + + + 0 + 0 + + + + From ad4e90e345308cdd186e3e5ce368aa11f1d41d0c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 23:01:09 +0600 Subject: [PATCH 0591/1190] Finally fix RETEM --- src/cpu/808x.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index c07e583ae..ac23cd99a 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1158,11 +1158,20 @@ retem_i8080(void) { sync_from_i8080(); - cpu_state.pc = pop(); - CS = pop(); - cpu_state.flags = pop() | MD_FLAG; + prefetching = 0; + pfq_clear(); + + set_ip(pop()); + load_cs(pop()); + cpu_state.flags = pop(); + + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); cpu_md_write_disable = 1; + + noint = 1; + nmi_enable = 1; + pclog("RETEM mode\n"); } @@ -3298,7 +3307,7 @@ execx86(int cycs) noint = 1; nmi_enable = 1; if (is_nec && !(cpu_state.flags & MD_FLAG)) - sync_to_i8080(); + sync_to_i8080(); break; case 0xD0: From abbae5efd2b1732ceefb7af11effa757bfe5f034 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 26 Mar 2025 23:18:36 +0600 Subject: [PATCH 0592/1190] Cleanups --- src/cpu/808x.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index ac23cd99a..e98b7de3d 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -229,6 +229,8 @@ sync_from_i8080(void) void sync_to_i8080(void) { + if (!is_nec) + return; emulated_processor.a = AL; emulated_processor.h = BH; emulated_processor.l = BL; @@ -1085,7 +1087,7 @@ interrupt(uint16_t addr) if (!(cpu_state.flags & MD_FLAG) && is_nec) { sync_from_i8080(); - pclog("CALLN/INT#/NMI#\n"); + x808x_log("CALLN/INT#/NMI#\n"); } addr <<= 2; @@ -1150,7 +1152,7 @@ interrupt_brkem(uint16_t addr) access(41, 16); push(&old_ip); sync_to_i8080(); - pclog("BRKEM mode\n"); + x808x_log("BRKEM mode\n"); } void @@ -1172,7 +1174,7 @@ retem_i8080(void) noint = 1; nmi_enable = 1; - pclog("RETEM mode\n"); + x808x_log("RETEM mode\n"); } void From 209b29a2390e343a31fe2890fa9b4ef3616e3ad2 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 28 Mar 2025 00:55:33 +0900 Subject: [PATCH 0593/1190] PS55DA2: cleanup, change func scope remove unused variables, change funcs declaration scope, reformat debug code --- src/video/vid_ps55da2.c | 172 +++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 91 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index af8beddb9..158629226 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -29,7 +29,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> @@ -40,7 +39,6 @@ #include <86box/mca.h> #include <86box/rom.h> #include <86box/plat.h> -#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_ps55da2.h> #include <86box/vid_svga.h> @@ -256,8 +254,9 @@ #endif #ifdef ENABLE_DA2_LOG +// # define ENABLE_DA2_DEBUGIO 1 // # define ENABLE_DA2_DEBUGBLT 1 -# define ENABLE_DA2_DEBUGVRAM 1 +// # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 int da2_do_log = ENABLE_DA2_LOG; @@ -276,6 +275,11 @@ da2_log(const char *fmt, ...) #else # define da2_log(fmt, ...) #endif +#ifdef ENABLE_DA2_DEBUGIO +# define da2_iolog da2_log +#else +# define da2_iolog(fmt, ...) +#endif #ifdef ENABLE_DA2_DEBUGBLT # define da2_bltlog da2_log #else @@ -302,9 +306,6 @@ typedef struct da2_t { int fctladdr; int crtcaddr; - uint32_t decode_mask; - uint32_t vram_max; - uint32_t gdcla[8]; uint32_t gdcinput[8]; uint32_t gdcsrc[8]; @@ -317,13 +318,8 @@ typedef struct da2_t { uint8_t plane_mask; - int fb_only; - - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; + int writemode, readplane; uint8_t planemask; - uint32_t charseta, charsetb; uint8_t egapal[16]; uint32_t pallook[512]; @@ -357,13 +353,9 @@ typedef struct da2_t { /* Attribute Buffer E0000-E0FFFh (4 KB) */ uint8_t *cram; - /* (cram size - 1) >> 3 = 0xFFF */ - // uint32_t cram_display_mask; /* APA Buffer A0000-BFFFFh (128 KB) */ uint8_t *vram; - /* xxh */ uint8_t *changedvram; - /* (vram size - 1) >> 3 = 0x1FFFF */ uint32_t vram_display_mask; int fullchange; @@ -374,7 +366,6 @@ typedef struct da2_t { card should not attempt to display anything */ int override; - /* end VGA compatible regs*/ struct { int enable; @@ -431,13 +422,13 @@ typedef struct da2_t { int old_pos2; } da2_t; -void da2_recalctimings(da2_t *da2); -static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p); -void da2_bitblt_exec(void *p); -void da2_updatevidselector(da2_t *da2); -void da2_reset_ioctl(da2_t *da2); -static void da2_reset(void *priv); -uint16_t rightRotate(uint16_t data, uint8_t count); +static void da2_recalctimings(da2_t *da2); +static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p); +static void da2_bitblt_exec(void *p); +static void da2_updatevidselector(da2_t *da2); +static void da2_reset_ioctl(da2_t *da2); +static void da2_reset(void *priv); +static uint16_t rightRotate(uint16_t data, uint8_t count); typedef union { uint32_t d; @@ -449,7 +440,7 @@ typedef struct { } pixel32; /* safety read for internal functions */ -uint32_t +static uint32_t DA2_vram_r(uint32_t addr, da2_t *da2) { if (addr & ~DA2_MASK_VRAM) @@ -457,7 +448,7 @@ DA2_vram_r(uint32_t addr, da2_t *da2) return da2->vram[addr]; } /* safety write for internal functions */ -void +static void DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) { if (addr & ~DA2_MASK_VRAM) @@ -466,7 +457,7 @@ DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) return; } /* write pixel data with rop (Note: bitmask must be in big endian) */ -void +static void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) { uint32_t writepx[8]; @@ -516,7 +507,7 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s } } -void +static void DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t *da2) { pixel32 srcpx; @@ -554,7 +545,7 @@ Param Desc 33 Size W 35 Size H */ -void +static void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) { pixel32 srcpx; @@ -568,7 +559,7 @@ DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } -void +static void DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) { pixel32 srcpx; @@ -655,7 +646,7 @@ IBMJtoSJIS(uint16_t knj) return knj; } #endif -void +static void da2_bitblt_load(da2_t *da2) { uint32_t value32; @@ -892,7 +883,7 @@ da2_bitblt_load(da2_t *da2) } } } -void +static void da2_bitblt_exec(void *p) { da2_t *da2 = (da2_t *) p; @@ -1099,7 +1090,7 @@ da2_bitblt_exec(void *p) break; } } -void +static void da2_bitblt_dopayload(void *priv) { da2_t *da2 = (da2_t *) priv; @@ -1116,7 +1107,7 @@ da2_bitblt_dopayload(void *priv) } } -void +static void da2_out(uint16_t addr, uint16_t val, void *p) { da2_t *da2 = (da2_t *) p; @@ -1142,7 +1133,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->dac_pos = 0; break; case 0x3C9: /* Data */ - // da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); + // da2_iolog("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI); da2->dac_status = 0; da2->fullchange = changeframecount; switch (da2->dac_pos) { @@ -1171,11 +1162,11 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->ioctladdr = val; break; case LS_DATA: - // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc); if (da2->ioctladdr > 0xf) return; if (da2->ioctl[da2->ioctladdr & 15] != val) - da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); + da2_iolog("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc); oldval = da2->ioctl[da2->ioctladdr]; da2->ioctl[da2->ioctladdr] = val; if (oldval != val) { @@ -1192,15 +1183,15 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->fctladdr = val; break; case LF_DATA: - // da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); if (da2->fctladdr > 0x1f) return; if (da2->fctl[da2->fctladdr & 0x1f] != val) - da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); + da2_iolog("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc); oldval = da2->fctl[da2->fctladdr]; da2->fctl[da2->fctladdr] = val; if (da2->fctladdr == 0 && oldval != val) { - da2_log("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + da2_iolog("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); } break; case LC_INDEX: @@ -1210,7 +1201,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) if (da2->crtcaddr > 0x1f) return; if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ)) - da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); + da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc); if (!(da2->crtc[da2->crtcaddr] ^ val)) return; switch (da2->crtcaddr) { @@ -1261,7 +1252,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) } break; case LV_PORT: - // da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); + // da2_iolog("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); if (!da2->attrff) { // da2->attraddr = val & 31; da2->attraddr = val & 0x3f; @@ -1270,14 +1261,14 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->attr_palette_enable = val & 0x20; da2_recalctimings(da2); } - // da2_log("set attraddr: %X\n", da2->attraddr); + // da2_iolog("set attraddr: %X\n", da2->attraddr); } else { if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val)) da2->fullchange = changeframecount; if (da2->attrc[da2->attraddr & 0x3f] != val) - da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); + da2_iolog("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val); da2->attrc[da2->attraddr & 0x3f] = val; - // da2_log("set attrc %x: %x\n", da2->attraddr & 31, val); + // da2_iolog("set attrc %x: %x\n", da2->attraddr & 31, val); if (da2->attraddr < 16) da2->fullchange = changeframecount; if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) { @@ -1325,12 +1316,12 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->attrc[da2->attraddr & 0x3f] = val; break; case LG_INDEX: - da2_log("DA2 Out addr %03X val %02X\n", addr, val); + da2_iolog("DA2 Out addr %03X val %02X\n", addr, val); da2->gdcaddr = val; break; case LG_DATA: - // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); - da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); + // if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_iolog("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI); + da2_iolog("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val); da2->gdcreg[da2->gdcaddr & 0x0f] = val & 0xff; switch (da2->gdcaddr & 0x1f) { case LG_READ_MAP_SELECT: @@ -1350,7 +1341,7 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LG_COMMAND: break; case LG_SET_RESET_2: - da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); + da2_iolog("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val); return; } break; @@ -1358,12 +1349,12 @@ da2_out(uint16_t addr, uint16_t val, void *p) // da2->gdcreg[5] = val & 0xff; // break; default: - da2_log("DA2? Out addr %03X val %02X\n", addr, val); + da2_iolog("DA2? Out addr %03X val %02X\n", addr, val); break; } } -uint16_t +static uint16_t da2_in(uint16_t addr, void *p) { da2_t *da2 = (da2_t *) p; @@ -1431,17 +1422,17 @@ da2_in(uint16_t addr, void *p) // if (da2->bitblt.indata) /* for OS/2 J1.3 command prompt scrolling */ // da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { - // da2_log("exec:%x\n", da2->bitblt.exec); + // da2_iolog("exec:%x\n", da2->bitblt.exec); temp |= 0x01; /* wait (bit 3 + bit 0) ? need verify */ // if (!da2->bitblt.timer.enabled) //{ - // da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); + // da2_iolog("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); // } } if (da2->bitblt.indata) temp |= 0x08; #ifdef ENABLE_DA2_DEBUGMONWAIT - da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); + da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); #endif } break; @@ -1474,7 +1465,7 @@ da2_in(uint16_t addr, void *p) temp = da2->cgastat; } else temp = da2->attrc[da2->attraddr]; - // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc); da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ break; case LG_INDEX: @@ -1482,10 +1473,10 @@ da2_in(uint16_t addr, void *p) break; case LG_DATA: temp = da2->gdcreg[da2->gdcaddr & 0x1f]; - // da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc); break; } - // da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); return temp; } /* @@ -1499,11 +1490,11 @@ da2_in(uint16_t addr, void *p) * out b(idx), in b, in b(data) * out b(idx), in w(data) */ -void +static void da2_outb(uint16_t addr, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; - // da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + // da2_iolog("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); da2->inflipflop = 0; switch (addr) { case LS_DATA: @@ -1533,7 +1524,7 @@ da2_outb(uint16_t addr, uint8_t val, void *p) void da2_outw(uint16_t addr, uint16_t val, void *p) { - da2_log("DA2 Outw addr %03X val %04X\n", addr, val); + da2_iolog("DA2 Outw addr %03X val %04X\n", addr, val); da2_t *da2 = (da2_t *) p; da2->inflipflop = 0; switch (addr) { @@ -1553,8 +1544,8 @@ da2_outw(uint16_t addr, uint16_t val, void *p) da2->outflipflop = 0; break; case 0x3EC: - // da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_log(" "); + // da2_iolog("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_iolog(" "); // val = rightRotate(val, 8); // da2_out(LG_DATA, val, da2); da2_out(LG_DATA, val >> 8, da2); @@ -1580,12 +1571,12 @@ da2_outw(uint16_t addr, uint16_t val, void *p) break; case AC_REG: /* no register is revealed */ - da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_iolog("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); da2->reg3ee[val & 0x0f] = val >> 8; break; } } -uint8_t +static uint8_t da2_inb(uint16_t addr, void *p) { uint8_t temp; @@ -1615,10 +1606,10 @@ da2_inb(uint16_t addr, void *p) da2->inflipflop = 0; break; } - // da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + // da2_iolog("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); return temp; } -uint16_t +static uint16_t da2_inw(uint16_t addr, void *p) { uint16_t temp; @@ -1626,11 +1617,11 @@ da2_inw(uint16_t addr, void *p) da2->inflipflop = 0; da2->outflipflop = 0; temp = da2_in(addr, da2); - da2_log("DA2 Inw addr %03X val %04X\n", addr, temp); + da2_iolog("DA2 Inw addr %03X val %04X\n", addr, temp); return temp; } /* IO 03DAh : Input Status Register 2 for DOSSHELL used by DOS J4.0 */ -uint8_t +static uint8_t da2_in_ISR(uint16_t addr, void *p) { da2_t *da2 = (da2_t *) p; @@ -1642,15 +1633,15 @@ da2_in_ISR(uint16_t addr, void *p) da2->cgastat ^= 0x30; temp = da2->cgastat; } - // da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + // da2_iolog("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); return temp; } -void +static void da2_out_ISR(uint16_t addr, uint8_t val, void *p) { // da2_t* da2 = (da2_t*)p; - da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); + da2_iolog("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); } /* @@ -1754,7 +1745,7 @@ The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh. */ /* Get character line pattern from jfont rom or gaiji volatile memory */ -uint32_t +static uint32_t getfont_ps55dbcs(int32_t code, int32_t line, void *p) { da2_t *da2 = (da2_t *) p; @@ -1792,14 +1783,14 @@ getfont_ps55dbcs(int32_t code, int32_t line, void *p) } /* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */ -uint8_t +static int8_t IRGBtoBGRI(uint8_t attr) { attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1); return attr >>= 4; } /* Get the foreground color from the attribute byte */ -uint8_t +static uint8_t getPS55ForeColor(uint8_t attr, da2_t *da2) { uint8_t foreground = ~attr & 0x08; /* 0000 1000 */ @@ -1811,7 +1802,7 @@ getPS55ForeColor(uint8_t attr, da2_t *da2) return foreground; } -void +static void da2_render_blank(da2_t *da2) { int x, xx; @@ -2062,7 +2053,7 @@ da2_render_textm3(da2_t *da2) } } -void +static void da2_render_color_4bpp(da2_t *da2) { int changed_offset = da2->ma >> 9; @@ -2111,7 +2102,7 @@ da2_render_color_4bpp(da2_t *da2) } } -void +static void da2_render_color_8bpp(da2_t *da2) { int changed_offset = da2->ma >> 9; @@ -2160,7 +2151,7 @@ da2_render_color_8bpp(da2_t *da2) } } -void +static void da2_updatevidselector_tick(void *priv) { da2_t *da2 = (da2_t *) priv; @@ -2176,7 +2167,7 @@ da2_updatevidselector_tick(void *priv) } } -void +static void da2_updatevidselector(da2_t *da2) { timer_set_delay_u64(&da2->timer_vidupd, 100000ull * TIMER_USEC); @@ -2194,7 +2185,7 @@ da2_updatevidselector(da2_t *da2) 45h(undoc) APA 16 NA A0000h 1040 x 768 color_4bpp 46h(undoc) APA 16 ? A0000h 1040 x 768 color_4bpp */ -void +static void da2_recalctimings(da2_t *da2) { double crtcconst; @@ -2298,8 +2289,7 @@ da2_recalctimings(da2_t *da2) da2->dispofftime = TIMER_USEC; da2_log("da2 horiz total %i display end %i vidclock %f\n", da2->crtc[0], da2->crtc[1], da2->clock); da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); - da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70); - + da2_log("da2 dispon %lu dispoff %lu on(us) %f off(us) %f\n",da2->dispontime, da2->dispofftime, (double)da2->dispontime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0, (double)da2->dispofftime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0); // da2_log("da2->render %08X\n", da2->render); } @@ -2334,14 +2324,14 @@ da2_mapping_update(da2_t *da2) } } -uint8_t +static uint8_t da2_mca_read(int port, void *p) { da2_t *da2 = (da2_t *) p; return da2->pos_regs[port & 7]; } -void +static void da2_mca_write(int port, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; @@ -2702,7 +2692,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) da2->fullchange = 2; } } -uint16_t +static uint16_t rightRotate(uint16_t data, uint8_t count) { return (data >> count) | (data << (sizeof(data) * 8 - count)); @@ -2875,7 +2865,7 @@ da2_code_readw(uint32_t addr, void *p) return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8); } -void +static void da2_doblit(int y1, int y2, int wx, int wy, da2_t *da2) { if (wx != xsize || wy != ysize) { @@ -2894,7 +2884,7 @@ da2_doblit(int y1, int y2, int wx, int wy, da2_t *da2) video_bpp = 8; } -void +static void da2_poll(void *priv) { da2_t *da2 = (da2_t *) priv; @@ -3090,7 +3080,7 @@ static uint8_t ps55_palette_color[64][3] = { { 0x3F, 0x15, 0x15 }, { 0x3F, 0x15, 0x3F }, { 0x3F, 0x3F, 0x15 }, { 0x3F, 0x3F, 0x3F } }; -void +static void da2_reset_ioctl(da2_t *da2) { da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */ @@ -3204,7 +3194,7 @@ da2_available(void) return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN)); } -void +static void da2_close(void *p) { da2_t *da2 = (da2_t *) p; @@ -3292,7 +3282,7 @@ da2_close(void *p) free(da2); } -void +static void da2_speed_changed(void *p) { da2_t *da2 = (da2_t *) p; @@ -3300,7 +3290,7 @@ da2_speed_changed(void *p) da2_recalctimings(da2); } -void +static void da2_force_redraw(void *p) { da2_t *da2 = (da2_t *) p; From da855e02b4219bdda33325c0caa557ffc4ee2c99 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 28 Mar 2025 01:30:00 +0900 Subject: [PATCH 0594/1190] PS55DA2: Fix video switcher Fix an issue that the screen is resized repeatedly when booting OS/2. --- src/video/vid_ps55da2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 158629226..98db5f9fa 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -1242,7 +1242,8 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LC_VERTICAL_SYNC_START: case LC_V_DISPLAY_ENABLE_END: case LC_START_VERTICAL_BLANK: - case LC_END_VERTICAL_BLANK: + case LC_START_H_DISPLAY_ENAB: + case LC_START_V_DISPLAY_ENAB: case LC_VIEWPORT_PRIORITY: da2->fullchange = changeframecount; da2_recalctimings(da2); @@ -2158,10 +2159,12 @@ da2_updatevidselector_tick(void *priv) if (da2->ioctl[LS_MODE] & 0x02) { /* VGA passthrough mode */ da2->override = 1; + timer_disable(&da2->timer); svga_set_override(da2->mb_vga, 0); da2_log("DA2 selector: VGA\n"); } else { svga_set_override(da2->mb_vga, 1); + timer_enable(&da2->timer); da2->override = 0; da2_log("DA2 selector: DA2\n"); } @@ -2310,12 +2313,10 @@ da2_mapping_update(da2_t *da2) io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2); mem_mapping_enable(&da2->cmapping); mem_mapping_enable(&da2->mmio.mapping); - timer_enable(&da2->timer); timer_enable(&da2->bitblt.timer); } else { da2_log("DA2 disable registers\n"); timer_disable(&da2->bitblt.timer); - timer_disable(&da2->timer); mem_mapping_disable(&da2->cmapping); mem_mapping_disable(&da2->mmio.mapping); io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2); From 93f3e9f339361dbdecc2fbc0a87c9b7c31e9dd97 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 27 Mar 2025 19:10:20 +0100 Subject: [PATCH 0595/1190] Keyboard: Actually reset everything in keyboard_init() and call it in pc_reset_hard_init() as well. --- src/device/keyboard.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 58d5a4724..a00968cf7 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -113,7 +113,17 @@ static scconvtbl scconv55_8a[18 + 1] = void keyboard_init(void) { + num_lock = 0; + caps_lock = 0; + scroll_lock = 0; + shift = 0; + memset(recv_key, 0x00, sizeof(recv_key)); + memset(recv_key_ui, 0x00, sizeof(recv_key)); + memset(oldkey, 0x00, sizeof(recv_key)); +#if 0 + memset(key_delay, 0x00, sizeof(recv_key)); +#endif keyboard_scan = 1; scan_table = NULL; From ffd00e4527f56f429b8c826343c0de08f166ef6b Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 27 Mar 2025 19:14:01 +0100 Subject: [PATCH 0596/1190] Forgot 86box.c. --- src/86box.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/86box.c b/src/86box.c index dbf58a70e..2b6e1ba9f 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1293,6 +1293,8 @@ pc_reset_hard_init(void) * modules that are. */ + keyboard_init(); + /* Reset the IDE and SCSI presences */ other_ide_present = other_scsi_present = 0; From cec630fa756874bdf2ccc4a6fb3b733df2b4ad52 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 03:26:28 +0100 Subject: [PATCH 0597/1190] JEGA: Use colors based on a photo of the real OKI IF386AX when the LCD is in use to tell it apart more easily, and reset all devices on port 65h reset, fixes Trantor SCSI BIOS not finding any devices after such a reset. --- src/video/vid_jega.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 36cf04077..d8994916f 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -770,6 +770,8 @@ if386_p6x_read(uint16_t port, void *priv) Bit 4: Shutdown? (caused by POST rebooting and POWER OFF command in DOS 3.21) Bit 3: ? */ +static uint32_t lcd_cols[8] = { 0x001024, 0x747d8a, 0x8c96a4, 0xa0abbb, + 0xb1bece, 0xc0cee0, 0xceddf0, 0xdbebff }; static void if386_p6x_write(uint16_t port, uint8_t val, void *priv) { @@ -793,19 +795,31 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv) } else { /* Monochrome LCD */ for (int c = 0; c < 256; c++) { int cval = 0; +#ifdef SIMPLE_BW if (c & 0x0f) cval = ((c & 0x0e) * 0x10) + 0x1f; pallook64[c] = makecol32(cval, cval, cval); pallook16[c] = makecol32(cval, cval, cval); +#else + if (c & 0x3f) { + cval = (c & 0x10) >> 2; + cval |= (c & 0x06) >> 1; + } + pallook64[c] = lcd_cols[cval]; + cval = 0; + if (c & 0x0f) + cval = (c & 0x0e) >> 1; + pallook16[c] = lcd_cols[cval]; +#endif } } jega_recalctimings(jega); } else if (p65idx == 0x05) { - if (val & 0x10) + if (val & 0x10) { /* Power off (instead this call hardware reset here) */ + device_reset_all(DEVICE_ALL); resetx86(); - /* Actually, power off - we have a function for that! */ - // plat_power_off(); + } } } return; From 8a8ed6004383dbe271f6b7db01c0d29baeaeec11 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 03:29:11 +0100 Subject: [PATCH 0598/1190] EGA: Send monochrome attributes through the EGA palette lookup like the real hardware also does. --- src/video/vid_ega_render.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index dd393e4b6..261474742 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -181,6 +181,7 @@ ega_render_text(ega_t *ega) p[xx] = ega->mdacols[attr][attrblink][1]; else p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; + p[xx] = ega->pallook[ega->egapal[p[xx] & 0x0f]]; } else p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; } @@ -189,9 +190,6 @@ ega_render_text(ega_t *ega) p += charwidth; } ega->ma &= 0x3ffff; - - if (monoattrs) - video_process_8(ega->hdisp + ega->scrollcache, ega->displine); } } From 63222b70db1e8ad5f1d651d6dce8e6c3a511d50b Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 06:16:05 +0100 Subject: [PATCH 0599/1190] Added the OKIVGA/H-2 (JVGA/H). --- src/include/86box/vid_ega.h | 9 +- src/include/86box/vid_svga.h | 5 + src/include/86box/vid_vga.h | 15 +- src/video/vid_ega.c | 2 +- src/video/vid_jega.c | 354 ++++++++++++++++++++++++----------- src/video/vid_svga.c | 5 +- src/video/vid_table.c | 1 + src/video/vid_vga.c | 45 +++-- 8 files changed, 293 insertions(+), 143 deletions(-) diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index 5ac5c24e3..0e28820ff 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -144,10 +144,10 @@ typedef struct ega_t { uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr); void (*render)(struct ega_t *svga); - /*If set then another device is driving the monitor output and the EGA - card should not attempt to display anything */ - void (*render_override)(void *priv); - void *priv_parent; + /* If set then another device is driving the monitor output and the EGA + card should not attempt to display anything. */ + void (*render_override)(void *priv); + void * priv_parent; } ega_t; #endif @@ -159,6 +159,7 @@ extern const device_t atiega800p_device; extern const device_t iskra_ega_device; extern const device_t et2000_device; extern const device_t jega_device; +extern const device_t jvga_device; #endif extern int update_overscan; diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index afff6e211..068774eac 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -310,6 +310,11 @@ typedef struct svga_t { void * ext8514; void * clock_gen8514; void * xga; + + /* If set then another device is driving the monitor output and the EGA + card should not attempt to display anything. */ + void (*render_override)(void *priv); + void * priv_parent; } svga_t; extern void ibm8514_set_poll(svga_t *svga); diff --git a/src/include/86box/vid_vga.h b/src/include/86box/vid_vga.h index 26b5a7f71..54a1d0690 100644 --- a/src/include/86box/vid_vga.h +++ b/src/include/86box/vid_vga.h @@ -25,14 +25,19 @@ typedef struct vga_t { svga_t svga; - rom_t bios_rom; + rom_t bios_rom; } vga_t; -extern void vga_out(uint16_t addr, uint8_t val, void *priv); +extern void vga_out(uint16_t addr, uint8_t val, void *priv); extern uint8_t vga_in(uint16_t addr, void *priv); -void vga_disable(void* p); -void vga_enable(void* p); -int vga_isenabled(void* p); +extern void vga_init(const device_t *info, vga_t *vga, int enabled); + +extern void vga_disable(void* p); +extern void vga_enable(void* p); + +extern int vga_isenabled(void* p); + +extern video_timings_t timing_vga; #endif /*VIDEO_VGA_H*/ diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 16a3552ad..17b3fb593 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -780,7 +780,7 @@ ega_poll(void *priv) ega->y_add *= ega->vres + 1; for (y = 0; y <= ega->vres; y++) { /* Render scanline */ - if(ega->render_override) + if (ega->render_override) ega->render_override(ega->priv_parent); else ega->render(ega); diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index d8994916f..af20444dd 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -34,6 +34,8 @@ #include <86box/device.h> #include <86box/video.h> #include <86box/vid_ega.h> +#include <86box/vid_svga.h> +#include <86box/vid_vga.h> /* JEGA internal registers */ #define RPESL 0x09 /* End Scan Line */ @@ -63,6 +65,8 @@ #define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN" #define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT" #define IF386_PATH_VBIOS "roms/machines/if386sx/OKI_IF386SX_VBIOS.bin" +#define JVGA_PATH_BIOS "roms/video/jega/OKI_JVGT(AXVGAH)_BIOS_011993.BIN" +#define JVGA_PATH_FONTDBCS "roms/video/jega/JWPCE.FNT" #define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */ #define DBCS16_CHARS 0x2c10 #define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2) @@ -96,29 +100,31 @@ jega_log(const char *fmt, ...) static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; typedef struct jega_t { - rom_t bios_rom; - ega_t ega; - uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */ - uint8_t regs[0x31]; - uint8_t egapal[16]; - uint8_t attrregs[32]; - uint8_t attraddr; - uint8_t attrff; - uint8_t attr_palette_enable; + rom_t bios_rom; + ega_t ega; + vga_t vga; + uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */ + uint8_t regs[0x31]; + uint8_t egapal[16]; + uint8_t attrregs[32]; + uint8_t attraddr; + uint8_t attrff; + uint8_t attr_palette_enable; uint32_t *pallook; - int con; - int cursoron; - int cursorblink_disable; - int ca; - int font_index; - int sbcsbank_inv; - int attr3_sbcsbank; - int start_scan_lower; - int start_scan_upper; - int start_scan_count; - uint8_t *vram; - uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */ - uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */ + int is_vga; + int con; + int cursoron; + int cursorblink_disable; + int ca; + int font_index; + int sbcsbank_inv; + int attr3_sbcsbank; + int start_scan_lower; + int start_scan_upper; + int start_scan_count; + uint8_t * vram; + uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */ + uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */ } jega_t; static void jega_recalctimings(void *priv); @@ -127,16 +133,16 @@ static void jega_recalctimings(void *priv); #define FONTX_LEN_FN 8 typedef struct { - char id[FONTX_LEN_ID]; - char name[FONTX_LEN_FN]; - unsigned char width; - unsigned char height; - unsigned char type; + char id[FONTX_LEN_ID]; + char name[FONTX_LEN_FN]; + uint8_t width; + uint8_t height; + uint8_t type; } fontx_h; typedef struct { - uint16_t start; - uint16_t end; + uint16_t start; + uint16_t end; } fontx_tbl; extern uint32_t pallook16[256]; @@ -147,22 +153,32 @@ static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr static uint16_t SJIS_to_SEQ(uint16_t sjis) { - uint32_t chr1 = (sjis >> 8) & 0xff; - uint32_t chr2 = sjis & 0xff; - if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2)) return INVALIDACCESS16; - chr1 -= 0x81; - if (chr1 > 0x5E) chr1 -= 0x40; - chr2 -= 0x40; - if (chr2 > 0x3F) chr2--; - chr1 *= 0xBC; - return (chr1 + chr2); + uint32_t chr1 = (sjis >> 8) & 0xff; + uint32_t chr2 = sjis & 0xff; + + if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2)) + return INVALIDACCESS16; + + chr1 -= 0x81; + + if (chr1 > 0x5e) + chr1 -= 0x40; + + chr2 -= 0x40; + + if (chr2 > 0x3f) + chr2--; + + chr1 *= 0xbc; + + return (chr1 + chr2); } static uint8_t dbcs_read(uint16_t sjis, int index, void *priv) { jega_t *jega = (jega_t *) priv; int seq = SJIS_to_SEQ(sjis); - if (seq >= DBCS16_CHARS || index >= 32) + if ((seq >= DBCS16_CHARS) || (index >= 32)) return INVALIDACCESS8; return jega->jfont_dbcs_16[seq * 32 + index]; } @@ -171,7 +187,7 @@ static void dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) { jega_t *jega = (jega_t *) priv; int seq = SJIS_to_SEQ(sjis); - if (seq >= DBCS16_CHARS || index >= 32) + if ((seq >= DBCS16_CHARS) || (index >= 32)) return; jega->jfont_dbcs_16[seq * 32 + index] = val; } @@ -180,38 +196,81 @@ dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) { void jega_render_text(void *priv) { - jega_t *jega = (jega_t *) priv; - if (jega->ega.firstline_draw == 2000) - jega->ega.firstline_draw = jega->ega.displine; - jega->ega.lastline_draw = jega->ega.displine; + jega_t * jega = (jega_t *) priv; +#ifdef USE_DOUBLE_WIDTH_AND_LINE_CHARS + uint8_t * seqregs = jega->is_vga ? jega->vga.svga.seqregs : + jega->ega.seqregs; + uint8_t * attrregs = jega->is_vga ? jega->vga.svga.attrregs : + jega->ega.attrregs; +#endif + uint8_t * crtc = jega->is_vga ? jega->vga.svga.crtc : + jega->ega.crtc; + uint8_t * vram = jega->is_vga ? jega->vga.svga.vram : + jega->ega.vram; + int * firstline_draw = jega->is_vga ? &jega->vga.svga.firstline_draw : + &jega->ega.firstline_draw; + int * lastline_draw = jega->is_vga ? &jega->vga.svga.lastline_draw : + &jega->ega.lastline_draw; + int * displine = jega->is_vga ? &jega->vga.svga.displine : + &jega->ega.displine; + int * fullchange = jega->is_vga ? &jega->vga.svga.fullchange : + &jega->ega.fullchange; + int * blink = jega->is_vga ? &jega->vga.svga.blink : + &jega->ega.blink; + int * x_add = jega->is_vga ? &jega->vga.svga.x_add : + &jega->ega.x_add; + int * y_add = jega->is_vga ? &jega->vga.svga.y_add : + &jega->ega.y_add; + int * sc = jega->is_vga ? &jega->vga.svga.sc : + &jega->ega.sc; + int * hdisp = jega->is_vga ? &jega->vga.svga.hdisp : + &jega->ega.hdisp; + int * scrollcache = jega->is_vga ? &jega->vga.svga.scrollcache : + &jega->ega.scrollcache; + uint32_t *ma = jega->is_vga ? &jega->vga.svga.ma : + &jega->ega.ma; + uint8_t mask = jega->is_vga ? jega->vga.svga.dac_mask : 0xff; - if (jega->ega.fullchange) { - // const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0); - const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ - // const bool attrlinechars = (jega->ega.attrregs[0x10] & 4); - const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0); - const int charwidth = 8; - const bool blinked = jega->ega.blink & 0x10; - uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add]; - bool chr_wide = false; - int sc_wide = jega->ega.sc - jega->start_scan_count; - const bool cursoron = (blinked || jega->cursorblink_disable) - && (jega->ega.sc >= jega->regs[RCCSL]) && (jega->ega.sc <= jega->regs[RCCEL]); - uint32_t chr_first; - uint32_t attr_basic; - int fg; - int bg; + if (*firstline_draw == 2000) + *firstline_draw = *displine; + *lastline_draw = *displine; - for (int x = 0; x < (jega->ega.hdisp + jega->ega.scrollcache); x += charwidth) { - uint32_t addr = jega->ega.remap_func(&jega->ega, jega->ega.ma) & jega->ega.vrammask; + if (*fullchange) { +#ifdef USE_DOUBLE_WIDTH_AND_LINE_CHARS + const bool doublewidth = ((seqregs[1] & 8) != 0); + const bool attrlinechars = (attrregs[0x10] & 4); +#endif + const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */ + const bool crtcreset = ((crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0); + const int charwidth = 8; + const bool blinked = *blink & 0x10; + uint32_t *p = &buffer32->line[*displine + *y_add][*x_add]; + bool chr_wide = false; + int sc_wide = *sc - jega->start_scan_count; + const bool cursoron = (blinked || jega->cursorblink_disable) && + (*sc >= jega->regs[RCCSL]) && (*sc <= jega->regs[RCCEL]); + uint32_t chr_first; + uint32_t attr_basic; + int fg; + int bg; - int drawcursor = ((jega->ega.ma == jega->ca) && cursoron); + for (int x = 0; x < (*hdisp + *scrollcache); x += charwidth) { + uint32_t addr = 0; + + if (jega->is_vga) { + if (!jega->vga.svga.force_old_addr) + addr = jega->vga.svga.remap_func(&jega->vga.svga, jega->vga.svga.ma) & + jega->vga.svga.vram_display_mask; + } else + addr = jega->ega.remap_func(&jega->ega, *ma) & jega->ega.vrammask; + + int drawcursor = ((*ma == jega->ca) && cursoron); uint32_t chr; uint32_t attr; if (!crtcreset) { - chr = jega->ega.vram[addr]; - attr = jega->ega.vram[addr + 1]; + chr = vram[addr]; + attr = vram[addr + 1]; } else chr = attr = 0; if (chr_wide) { @@ -222,13 +281,13 @@ jega_render_text(void *priv) /* Bold | 2x width | 2x height | U/L select | R/L select | - | - | - */ attr_ext = attr; if ((attr_ext & 0x30) == 0x30) - sc_wide = jega->ega.sc - jega->start_scan_lower; /* Set top padding of lower 2x character */ + sc_wide = *sc - jega->start_scan_lower; /* Set top padding of lower 2x character */ else if ((attr_ext & 0x30) == 0x20) - sc_wide = jega->ega.sc - jega->start_scan_upper; /* Set top padding of upper 2x character */ + sc_wide = *sc - jega->start_scan_upper; /* Set top padding of upper 2x character */ else - sc_wide = jega->ega.sc - jega->start_scan_count; + sc_wide = *sc - jega->start_scan_count; } - if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && jega->ega.sc <= jega->regs[RPESL]) { + if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && *sc <= jega->regs[RPESL]) { chr_first <<= 8; chr |= chr_first; /* Vertical wide font (Extended Attribute) */ @@ -269,7 +328,7 @@ jega_render_text(void *priv) if (attr_basic & 0x20) { /* vertical line */ p[0] = fg; } - if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + if ((*sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ for (int xx = 0; xx < charwidth * 2; xx++) p[xx] = fg; } @@ -298,13 +357,13 @@ jega_render_text(void *priv) /* Parse attribute as EGA */ /* BInt/Blink | BR | BG | BB | Int/Group | R | G | B */ if (drawcursor) { - bg = jega->pallook[jega->egapal[attr & 0x0f]]; - fg = jega->pallook[jega->egapal[attr >> 4]]; + bg = jega->pallook[jega->egapal[attr & 0x0f] & mask]; + fg = jega->pallook[jega->egapal[attr >> 4] & mask]; } else { - fg = jega->pallook[jega->egapal[attr & 0x0f]]; - bg = jega->pallook[jega->egapal[attr >> 4]]; + fg = jega->pallook[jega->egapal[attr & 0x0f] & mask]; + bg = jega->pallook[jega->egapal[attr >> 4] & mask]; if ((attr & 0x80) && attrblink) { - bg = jega->pallook[jega->egapal[(attr >> 4) & 7]]; + bg = jega->pallook[jega->egapal[(attr >> 4) & 7] & mask]; if (blinked) fg = bg; } @@ -325,32 +384,35 @@ jega_render_text(void *priv) // charaddr ^= 0x100; charaddr *= 19; - uint32_t dat = jega->jfont_sbcs_19[charaddr + jega->ega.sc]; + uint32_t dat = jega->jfont_sbcs_19[charaddr + *sc]; for (int xx = 0; xx < charwidth; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; if (attr_basic & 0x20) { /* vertical line */ p[0] = fg; } - if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ + if ((*sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */ for (int xx = 0; xx < charwidth; xx++) p[xx] = fg; } p += charwidth; } } - jega->ega.ma += 4; + *ma += 4; } - jega->ega.ma &= 0x3ffff; + *ma &= 0x3ffff; } } static void jega_out(uint16_t addr, uint8_t val, void *priv) { - jega_t *jega = (jega_t *) priv; - uint16_t chr; + jega_t *jega = (jega_t *) priv; + uint8_t pal4to16[16] = { 0, 7, 0x38, 0x3f, 0, 3, 4, 0x3f, 0, 2, 4, 0x3e, 0, 3, 5, 0x3f }; + uint16_t chr; + // jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc); + switch (addr) { case 0x3c0: case 0x3c1: @@ -367,9 +429,19 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega->attrregs[jega->attraddr & 31] = val; if (jega->attraddr < 0x10) { for (uint8_t c = 0; c < 16; c++) { + if (!jega->is_vga) jega->egapal[c] = jega->attrregs[c] & 0x3f; + else if (jega->attrregs[0x10] & 0x80) + jega->egapal[c] = (jega->attrregs[c] & 0xf) | ((jega->attrregs[0x14] & 0xf) << 4); + else if (jega->vga.svga.ati_4color) + jega->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)]; + else + jega->egapal[c] = (jega->attrregs[c] & 0x3f) | ((jega->attrregs[0x14] & 0xc) << 4); } - jega->ega.fullchange = changeframecount; + if (jega->is_vga) + jega->vga.svga.fullchange = changeframecount; + else + jega->ega.fullchange = changeframecount; } } jega->attrff ^= 1; @@ -395,12 +467,17 @@ jega_out(uint16_t addr, uint8_t val, void *priv) switch (jega->regs_index) { case RMOD1: /* if the value is changed */ - // if (jega->regs[jega->regs_index] != val) { - if (val & 0x40) - jega->ega.render_override = NULL; - else - jega->ega.render_override = jega_render_text; - // } + if (jega->is_vga) { + if (val & 0x40) + jega->vga.svga.render_override = NULL; + else + jega->vga.svga.render_override = jega_render_text; + } else { + if (val & 0x40) + jega->ega.render_override = NULL; + else + jega->ega.render_override = jega_render_text; + } break; case RDAGS: switch (val & 0x03) { @@ -470,8 +547,14 @@ jega_out(uint16_t addr, uint8_t val, void *priv) default: break; } - if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ - ega_out(addr, val, &jega->ega); + + /* Accessing to Slave EGA is redirected to Master in AX-1. */ + if (jega->regs[RMOD1] & 0x0c) { + if (jega->is_vga) + vga_out(addr, val, &jega->vga); + else + ega_out(addr, val, &jega->ega); + } } static uint8_t @@ -480,6 +563,7 @@ jega_in(uint16_t addr, void *priv) jega_t *jega = (jega_t *) priv; uint8_t ret = INVALIDACCESS8; uint16_t chr; + switch (addr) { case 0x3b5: case 0x3d5: @@ -515,8 +599,13 @@ jega_in(uint16_t addr, void *priv) case 0x3da: jega->attrff = 0; default: - if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave is redirected to Master in AX-1. */ - ret = ega_in(addr, &jega->ega); + /* Accessing to Slave is redirected to Master in AX-1. */ + if (jega->regs[RMOD1] & 0x0c) { + if (jega->is_vga) + ret = vga_in(addr, &jega->vga); + else + ret = ega_in(addr, &jega->ega); + } break; } // jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); @@ -619,19 +708,29 @@ LoadFontxFile(const char *fn, void *priv) } static void -jega_commoninit(void *priv) +jega_commoninit(const device_t *info, void *priv, int vga) { jega_t *jega = (jega_t *) priv; - for (int c = 0; c < 256; c++) { - pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); - pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + jega->is_vga = vga; + if (vga) { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga); + vga_init(info, &jega->vga, 1); + jega->vga.svga.priv_parent = jega; + jega->pallook = jega->vga.svga.pallook; + } else { + for (int c = 0; c < 256; c++) { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); + jega->pallook = pallook64; + ega_init(&jega->ega, 9, 0); + ega_set_type(&jega->ega, EGA_SUPEREGA); + jega->ega.priv_parent = jega; + mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, + ega_read, NULL, NULL, ega_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, &jega->ega); } - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega); - jega->pallook = pallook64; - ega_init(&jega->ega, 9, 0); - ega_set_type(&jega->ega, EGA_SUPEREGA); - jega->ega.priv_parent = jega; - mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); /* I/O 3DD and 3DE are used by Oki if386 */ io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); jega->regs[RMOD1] = 0x48; @@ -646,7 +745,21 @@ jega_standalone_init(const device_t *info) memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); LoadFontxFile(JEGA_PATH_FONTDBCS, jega); - jega_commoninit(jega); + jega_commoninit(info, jega, 0); + + return jega; +} + +static void * +jvga_standalone_init(const device_t *info) +{ + jega_t *jega = calloc(1, sizeof(jega_t)); + + rom_init(&jega->bios_rom, JVGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); + memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); + LoadFontxFile(JVGA_PATH_FONTDBCS, jega); + + jega_commoninit(info, jega, 1); return jega; } @@ -693,9 +806,15 @@ jega_close(void *priv) } pclog("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); #endif - if (jega->ega.eeprom) - free(jega->ega.eeprom); - free(jega->ega.vram); + + if (jega->is_vga) + svga_close(&jega->vga.svga); + else { + if (jega->ega.eeprom) + free(jega->ega.eeprom); + free(jega->ega.vram); + } + free(jega); } @@ -703,8 +822,13 @@ static void jega_recalctimings(void *priv) { jega_t *jega = (jega_t *) priv; - ega_recalctimings(&jega->ega); + + if (jega->is_vga) + svga_recalctimings(&jega->vga.svga); + else + ega_recalctimings(&jega->ega); } + static void jega_speed_changed(void *priv) { @@ -733,6 +857,20 @@ const device_t jega_device = { .config = NULL }; +const device_t jvga_device = { + .name = "OKIVGA/H-2 (JVGA/H)", + .internal_name = "jvga", + .flags = DEVICE_ISA, + .local = 0, + .init = jvga_standalone_init, + .close = jega_close, + .reset = NULL, + .available = jega_standalone_available, + .speed_changed = jega_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + static uint8_t p65idx = 0; // static uint8_t p3de_idx = 0; static uint8_t p65[6]; @@ -834,7 +972,7 @@ if386jega_init(const device_t *info) memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); LoadFontxFile(JEGA_PATH_FONTDBCS, jega); - jega_commoninit(jega); + jega_commoninit(info, jega, 0); io_sethandler(0x0063, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); io_sethandler(0x0065, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 1fd2460bd..c7a65120f 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1174,7 +1174,10 @@ svga_do_render(svga_t *svga) } if (!svga->override) { - svga->render(svga); + if (svga->render_override) + svga->render_override(svga->priv_parent); + else + svga->render(svga); svga->x_add = (svga->monitor->mon_overscan_x >> 1); svga_render_overscan_left(svga); diff --git a/src/video/vid_table.c b/src/video/vid_table.c index be26d9e18..b90d7c3e4 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -96,6 +96,7 @@ video_cards[] = { { .device = &genius_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &nga_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &ogc_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &jvga_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &oti037c_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &oti067_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &oti077_device, .flags = VIDEO_FLAG_TYPE_NONE }, diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 97889e007..0a0fbd8e1 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -31,7 +31,8 @@ #include <86box/vid_svga.h> #include <86box/vid_vga.h> -static video_timings_t timing_vga = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; +video_timings_t timing_vga = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + static video_timings_t timing_ps1_svga_isa = { .type = VIDEO_ISA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 }; static video_timings_t timing_ps1_svga_mca = { .type = VIDEO_MCA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 }; @@ -135,8 +136,23 @@ int vga_isenabled(void* p) return svga->vga_enabled; } +void +vga_init(const device_t *info, vga_t *vga, int enabled) +{ + svga_init(info, &vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + vga->svga.vga_enabled = enabled; +} + static void * -vga_init(const device_t *info) +vga_standalone_init(const device_t *info) { vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); @@ -145,16 +161,7 @@ vga_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga); - svga_init(info, &vga->svga, vga, 1 << 18, /*256kb*/ - NULL, - vga_in, vga_out, - NULL, - NULL); - - io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); - - vga->svga.bpp = 8; - vga->svga.miscout = 1; + vga_init(info, vga, 0); return vga; } @@ -171,17 +178,7 @@ ps1vga_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_isa); - svga_init(info, &vga->svga, vga, 1 << 18, /*256kb*/ - NULL, - vga_in, vga_out, - NULL, - NULL); - - io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); - - vga->svga.bpp = 8; - vga->svga.miscout = 1; - vga->svga.vga_enabled = 1; + vga_init(info, vga, 1); return vga; } @@ -223,7 +220,7 @@ const device_t vga_device = { .internal_name = "vga", .flags = DEVICE_ISA, .local = 0, - .init = vga_init, + .init = vga_standalone_init, .close = vga_close, .reset = NULL, .available = vga_available, From 47febdf1969b5532ee6be6c321b802e5ff19fd02 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 06:42:11 +0100 Subject: [PATCH 0600/1190] JVGA: Read CRTC registers from VGA rather than EGA, fixes Wolfenstein 3D. --- src/video/vid_jega.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index af20444dd..745c76e24 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -29,6 +29,7 @@ #include <86box/pic.h> #include <86box/pit.h> #include <86box/plat.h> +#include <86box/plat_fallthrough.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/device.h> @@ -592,12 +593,18 @@ jega_in(uint16_t addr, void *priv) break; } jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc); - } else if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */ - ret = ega_in(addr, &jega->ega); + } else if (jega->regs[RMOD1] & 0x0c) { + /* Accessing to Slave EGA is redirected to Master in AX-1. */ + if (jega->is_vga) + ret = vga_in(addr, &jega->vga); + else + ret = ega_in(addr, &jega->ega); + } break; case 0x3ba: case 0x3da: jega->attrff = 0; + fallthrough; default: /* Accessing to Slave is redirected to Master in AX-1. */ if (jega->regs[RMOD1] & 0x0c) { From 8f6f21b57e14b370a7e8cae4cb5930d2efe6ea11 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 06:54:45 +0100 Subject: [PATCH 0601/1190] IBM VGA: Re-add the forgotten (S)VGA I/O handlers. --- src/video/vid_vga.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 0a0fbd8e1..8289fd4cb 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -154,8 +154,7 @@ vga_init(const device_t *info, vga_t *vga, int enabled) static void * vga_standalone_init(const device_t *info) { - vga_t *vga = malloc(sizeof(vga_t)); - memset(vga, 0, sizeof(vga_t)); + vga_t *vga = calloc(1, sizeof(vga_t)); rom_init(&vga->bios_rom, "roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); @@ -163,6 +162,8 @@ vga_standalone_init(const device_t *info) vga_init(info, vga, 0); + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + return vga; } @@ -170,8 +171,7 @@ vga_standalone_init(const device_t *info) void * ps1vga_init(const device_t *info) { - vga_t *vga = malloc(sizeof(vga_t)); - memset(vga, 0, sizeof(vga_t)); + vga_t *vga = calloc(1, sizeof(vga_t)); if (info->flags & DEVICE_MCA) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_mca); @@ -180,6 +180,8 @@ ps1vga_init(const device_t *info) vga_init(info, vga, 1); + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + return vga; } From 6366ff758082d16430bbbf5e81d9845ba8270985 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 28 Mar 2025 08:09:51 +0100 Subject: [PATCH 0602/1190] JEGA: Fix two uninitialized variables. --- src/video/vid_jega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 745c76e24..3d1cfe476 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -250,9 +250,9 @@ jega_render_text(void *priv) int sc_wide = *sc - jega->start_scan_count; const bool cursoron = (blinked || jega->cursorblink_disable) && (*sc >= jega->regs[RCCSL]) && (*sc <= jega->regs[RCCEL]); + uint32_t attr_basic = 0; uint32_t chr_first; - uint32_t attr_basic; - int fg; + int fg = 0; int bg; for (int x = 0; x < (*hdisp + *scrollcache); x += charwidth) { From 94cf5d59a2b919cfb5e916e8d715708ff138f54e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Mar 2025 22:35:56 +0600 Subject: [PATCH 0603/1190] host_x86_MOV8_REG_ABS: Avoid more fatals --- src/codegen_new/codegen_backend_x86-64_ops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index c70112c86..fc6c1b492 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -723,7 +723,11 @@ host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) codegen_addbyte4(block, 0x41, 0x8a, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ codegen_addlong(block, ram_offset); } else { - fatal("host_x86_MOV8_REG_ABS - out of range\n"); + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t) p); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x41, 0x8a, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [R9]*/ } } void From dd0e6261337df4384df3bb94ffe691bcd67307be Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 29 Mar 2025 01:18:37 +0600 Subject: [PATCH 0604/1190] Set LC_NUMERIC to "C" in program startup For whatever fucking reason, glibc's functions dealing with decimal numbers apparently can only accept either commas or dots in strings, but not both. Meanwhile, both Windows and macOS have no apparent issues accepting both. I will never understand why they decided to even consider such behaviour acceptable, especially since those ARE used for parsing decimal numbers in many programs, but I guess it's their own version of Not Invented Here syndrome that they (or anyone else) can't be bothered to deal with. This is not how good C standard libraries are written, at all. --- src/qt/qt_main.cpp | 3 +++ src/utils/ini.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 2e0ce33e0..2ef797bd1 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -94,6 +94,8 @@ extern int qt_nvr_save(void); bool cpu_thread_running = false; } +#include + void qt_set_sequence_auto_mnemonic(bool b); #ifdef Q_OS_WINDOWS @@ -525,6 +527,7 @@ main(int argc, char *argv[]) QApplication app(argc, argv); QLocale::setDefault(QLocale::C); + setlocale(LC_NUMERIC, "C"); #ifdef Q_OS_WINDOWS Q_INIT_RESOURCE(darkstyle); diff --git a/src/utils/ini.c b/src/utils/ini.c index f5dfdef46..e23f83670 100644 --- a/src/utils/ini.c +++ b/src/utils/ini.c @@ -756,8 +756,9 @@ double ini_section_get_double(ini_section_t self, const char *name, double def) { section_t *section = (section_t *) self; - const entry_t *entry; - double value = 0; + entry_t *entry; + double value = 0; + int res = 0; if (section == NULL) return def; @@ -766,7 +767,17 @@ ini_section_get_double(ini_section_t self, const char *name, double def) if (entry == NULL) return def; - sscanf(entry->data, "%lg", &value); + res = sscanf(entry->data, "%lg", &value); + if (res == EOF || res <= 0) { + int i = 0; + for (i = 0; i < strlen(entry->data); i++) { + if (entry->data[i] == ',') { + entry->data[i] = '.'; + entry->wdata[i] = L'.'; + } + } + (void)sscanf(entry->data, "%lg", &value); + } return value; } From f422a9ce3dc14edf75b6c12d793c829a82db3f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Fri, 28 Mar 2025 22:11:26 +0100 Subject: [PATCH 0605/1190] qt: implement authentic icon grayscaling --- src/qt/qt_styleoverride.cpp | 40 +++++++++++++++++++++++++++++++++++++ src/qt/qt_styleoverride.hpp | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/src/qt/qt_styleoverride.cpp b/src/qt/qt_styleoverride.cpp index 60a7162a5..0bade8fa6 100644 --- a/src/qt/qt_styleoverride.cpp +++ b/src/qt/qt_styleoverride.cpp @@ -18,6 +18,9 @@ #include #include +#include +#include +#include #ifdef Q_OS_WINDOWS #include @@ -66,3 +69,40 @@ StyleOverride::polish(QWidget *widget) qobject_cast(widget)->view()->setMinimumWidth(widget->minimumSizeHint().width()); } } + +QPixmap +StyleOverride::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +{ + if (iconMode != QIcon::Disabled) { + return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); + } + + auto image = pixmap.toImage(); + + for (int y = 0; y < image.height(); y++) { + for (int x = 0; x < image.width(); x++) { + // checkerboard transparency + if (((x ^ y) & 1) == 0) { + image.setPixelColor(x, y, Qt::transparent); + continue; + } + + auto color = image.pixelColor(x, y); + + // convert to grayscale using the NTSC formula + auto avg = 0.0; + avg += color.blueF() * 0.114; + avg += color.greenF() * 0.587; + avg += color.redF() * 0.299; + + color.setRedF(avg); + color.setGreenF(avg); + color.setBlueF(avg); + + image.setPixelColor(x, y, color); + + } + } + + return QPixmap::fromImage(image); +} diff --git a/src/qt/qt_styleoverride.hpp b/src/qt/qt_styleoverride.hpp index c04d01a12..840aa6ad6 100644 --- a/src/qt/qt_styleoverride.hpp +++ b/src/qt/qt_styleoverride.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include class StyleOverride : public QProxyStyle { public: @@ -14,6 +17,7 @@ public: QStyleHintReturn *returnData = nullptr) const override; void polish(QWidget *widget) override; + QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const override; }; #endif From c00c432398dd2d1a7f0c2bfe20a5f9756867e894 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 00:10:39 +0100 Subject: [PATCH 0606/1190] EGA: Fix colors in mono mode and attribute registers, fixes #5395. --- src/video/vid_ega.c | 11 +++++++---- src/video/vid_ega_render.c | 10 +++++++--- src/video/vid_jega.c | 15 ++++++++------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 17b3fb593..f002ef999 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -112,10 +112,13 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->fullchange = changeframecount; if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) { for (uint8_t c = 0; c < 16; c++) { - if (ega->attrregs[0x10] & 0x80) - ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); - else - ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + if (ega->chipset) { + if (ega->attrregs[0x10] & 0x80) + ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else + ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + } else + ega->egapal[c] = ega->attrregs[c] & 0x3f; } ega->fullchange = changeframecount; } diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 261474742..10667084a 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -172,15 +172,19 @@ ega_render_text(ega_t *ega) uint32_t dat = ega->vram[charaddr + (ega->sc << 2)]; dat <<= 1; - if ((chr & ~0x1F) == 0xC0 && attrlinechars) + if (((chr & ~0x1f) == 0xc0) && attrlinechars) dat |= (dat >> 1) & 1; for (int xx = 0; xx < charwidth; xx++) { if (monoattrs) { + int bit = (dat & (0x100 >> (xx >> dwshift))) ? 1 : 0; + int blink = (!drawcursor && (attr & 0x80) && attrblink && blinked); if ((ega->sc == ega->crtc[0x14]) && ((attr & 7) == 1)) - p[xx] = ega->mdacols[attr][attrblink][1]; + p[xx] = ega->mdacols[attr][blink][1]; else - p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))]; + p[xx] = ega->mdacols[attr][blink][bit]; + if (drawcursor) + p[xx] ^= ega->mdacols[attr][0][1]; p[xx] = ega->pallook[ega->egapal[p[xx] & 0x0f]]; } else p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 3d1cfe476..11c9cbf8d 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -430,14 +430,15 @@ jega_out(uint16_t addr, uint8_t val, void *priv) jega->attrregs[jega->attraddr & 31] = val; if (jega->attraddr < 0x10) { for (uint8_t c = 0; c < 16; c++) { - if (!jega->is_vga) + if (jega->is_vga) { + if (jega->attrregs[0x10] & 0x80) + jega->egapal[c] = (jega->attrregs[c] & 0xf) | ((jega->attrregs[0x14] & 0xf) << 4); + else if (jega->vga.svga.ati_4color) + jega->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)]; + else + jega->egapal[c] = (jega->attrregs[c] & 0x3f) | ((jega->attrregs[0x14] & 0xc) << 4); + } else jega->egapal[c] = jega->attrregs[c] & 0x3f; - else if (jega->attrregs[0x10] & 0x80) - jega->egapal[c] = (jega->attrregs[c] & 0xf) | ((jega->attrregs[0x14] & 0xf) << 4); - else if (jega->vga.svga.ati_4color) - jega->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)]; - else - jega->egapal[c] = (jega->attrregs[c] & 0x3f) | ((jega->attrregs[0x14] & 0xc) << 4); } if (jega->is_vga) jega->vga.svga.fullchange = changeframecount; From ed4a312f4f6dec174a848dfa13bee8d9cc551976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Fri, 28 Mar 2025 23:13:23 +0100 Subject: [PATCH 0607/1190] Remove support for icon sets --- src/config.c | 11 ----- src/include/86box/86box.h | 1 - src/qt/qt.c | 2 - src/qt/qt_machinestatus.cpp | 44 ++++++++--------- src/qt/qt_mediamenu.cpp | 18 +++---- src/qt/qt_progsettings.cpp | 62 ------------------------ src/qt/qt_progsettings.hpp | 3 -- src/qt/qt_progsettings.ui | 72 ++++++---------------------- src/qt/qt_settings.cpp | 2 +- src/qt/qt_settingsfloppycdrom.cpp | 10 ++-- src/qt/qt_settingsharddisks.cpp | 2 +- src/qt/qt_settingsotherremovable.cpp | 8 ++-- src/unix/unix.c | 1 - 13 files changed, 57 insertions(+), 179 deletions(-) diff --git a/src/config.c b/src/config.c index 2e6a5460f..8ff7d548c 100644 --- a/src/config.c +++ b/src/config.c @@ -192,12 +192,6 @@ load_general(void) else if (mouse_sensitivity > 2.0) mouse_sensitivity = 2.0; - p = ini_section_get_string(cat, "iconset", NULL); - if (p != NULL) - strcpy(icon_set, p); - else - strcpy(icon_set, ""); - enable_discord = !!ini_section_get_int(cat, "enable_discord", 0); open_dir_usr_path = ini_section_get_int(cat, "open_dir_usr_path", 0); @@ -2038,11 +2032,6 @@ save_general(void) ini_section_set_string(cat, "language", buffer); } - if (!strcmp(icon_set, "")) - ini_section_delete_var(cat, "iconset"); - else - ini_section_set_string(cat, "iconset", icon_set); - if (enable_discord) ini_section_set_int(cat, "enable_discord", enable_discord); else diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index c58d595c5..61de69cf3 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -118,7 +118,6 @@ extern int vid_resize; /* (C) allow resizing */ extern int invert_display; /* (C) invert the display */ extern int suppress_overscan; /* (C) suppress overscans */ extern uint32_t lang_id; /* (C) language code identifier */ -extern char icon_set[256]; /* (C) iconset identifier */ extern int scale; /* (C) screen scale factor */ extern int dpi_scale; /* (C) DPI scaling of the emulated screen */ extern int vid_api; /* (C) video renderer */ diff --git a/src/qt/qt.c b/src/qt/qt.c index a9a6460eb..ecf4b964b 100644 --- a/src/qt/qt.c +++ b/src/qt/qt.c @@ -35,8 +35,6 @@ qt_nvr_save(void) return nvr_save(); } -char icon_set[256] = ""; /* name of the iconset to be used */ - int plat_vidapi(const char *api) { diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index a00cc032b..eff29a232 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -176,24 +176,24 @@ static const QString pixmap_empty_active = QStringLiteral("_empty_active"); void PixmapSetEmpty::load(const QString &basePath) { - normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); + normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + empty = QIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); } void PixmapSetActive::load(const QString &basePath) { - normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); + normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + active = QIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); } void PixmapSetEmptyActive::load(QString basePath) { - normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); - empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); - empty_active = ProgSettings::loadIcon(basePath.arg(pixmap_empty_active)).pixmap(pixmap_size); + normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); + active = QIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); + empty = QIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); + empty_active = QIcon(basePath.arg(pixmap_empty_active)).pixmap(pixmap_size); } } @@ -202,21 +202,21 @@ struct MachineStatus::States { States(QObject *parent) { - pixmaps.cartridge.load("/cartridge%1.ico"); - pixmaps.cassette.load("/cassette%1.ico"); - pixmaps.floppy_disabled.normal = ProgSettings::loadIcon(QStringLiteral("/floppy_disabled.ico")).pixmap(pixmap_size); + pixmaps.cartridge.load(":/settings/qt/icons/cartridge%1.ico"); + pixmaps.cassette.load(":/settings/qt/icons/cassette%1.ico"); + pixmaps.floppy_disabled.normal = QIcon(":/settings/qt/icons/floppy_disabled.ico").pixmap(pixmap_size); pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal; pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal; pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal; - pixmaps.floppy_525.load("/floppy_525%1.ico"); - pixmaps.floppy_35.load("/floppy_35%1.ico"); - pixmaps.cdrom.load("/cdrom%1.ico"); - pixmaps.zip.load("/zip%1.ico"); - pixmaps.mo.load("/mo%1.ico"); - pixmaps.hd.load("/hard_disk%1.ico"); - pixmaps.net.load("/network%1.ico"); - pixmaps.sound = ProgSettings::loadIcon("/sound.ico").pixmap(pixmap_size); - pixmaps.soundMuted = ProgSettings::loadIcon("/sound_mute.ico").pixmap(pixmap_size); + pixmaps.floppy_525.load(":/settings/qt/icons/floppy_525%1.ico"); + pixmaps.floppy_35.load(":/settings/qt/icons/floppy_35%1.ico"); + pixmaps.cdrom.load(":/settings/qt/icons/cdrom%1.ico"); + pixmaps.zip.load(":/settings/qt/icons/zip%1.ico"); + pixmaps.mo.load(":/settings/qt/icons/mo%1.ico"); + pixmaps.hd.load(":/settings/qt/icons/hard_disk%1.ico"); + pixmaps.net.load(":/settings/qt/icons/network%1.ico"); + pixmaps.sound = QIcon(":/settings/qt/icons/sound.ico").pixmap(pixmap_size); + pixmaps.soundMuted = QIcon(":/settings/qt/icons/sound_mute.ico").pixmap(pixmap_size); cartridge[0].pixmaps = &pixmaps.cartridge; cartridge[1].pixmaps = &pixmaps.cartridge; @@ -511,7 +511,7 @@ MachineStatus::refresh(QStatusBar *sbar) config_save(); if (d->sound) d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); - + muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); }); } @@ -697,7 +697,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); if (muteUnmuteAction) muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); - + connect(d->sound.get(), &ClickableLabel::clicked, this, [this](QPoint pos) { this->soundMenu->popup(pos - QPoint(0, this->soundMenu->sizeHint().height())); }); diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index fdea16c2a..f7abebdf1 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -154,10 +154,10 @@ MediaMenu::refresh(QMenu *parentMenu) MachineStatus::iterateCDROM([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); cdromMutePos = menu->children().count(); - menu->addAction(ProgSettings::loadIcon("/cdrom_mute.ico"), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); + menu->addAction(QIcon(":/settings/qt/icons/cdrom_mute.ico"), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); menu->addSeparator(); - menu->addAction(ProgSettings::loadIcon("/cdrom_image.ico"), tr("&Image..."), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false); - menu->addAction(ProgSettings::loadIcon("/cdrom_folder.ico"), tr("&Folder..."), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false); + menu->addAction(QIcon(":/settings/qt/icons/cdrom_image.ico"), tr("&Image..."), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false); + menu->addAction(QIcon(":/settings/qt/icons/cdrom_folder.ico"), tr("&Folder..."), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cdromImageHistoryPos[slot] = menu->children().count(); @@ -170,7 +170,7 @@ MediaMenu::refresh(QMenu *parentMenu) for (const auto &letter : driveLetters) { auto drive = QString("%1:\\").arg(letter); if (GetDriveType(drive.toUtf8().constData()) == DRIVE_CDROM) - menu->addAction(ProgSettings::loadIcon("/cdrom_host.ico"), tr("Host CD/DVD Drive (%1:)").arg(letter), [this, i, letter] { cdromMount(i, 2, QString(R"(\\.\%1:)").arg(letter)); })->setCheckable(false); + menu->addAction(QIcon(":/settings/qt/icons/cdrom_host.ico"), tr("Host CD/DVD Drive (%1:)").arg(letter), [this, i, letter] { cdromMount(i, 2, QString(R"(\\.\%1:)").arg(letter)); })->setCheckable(false); } menu->addSeparator(); #endif // Q_OS_WINDOWS @@ -666,7 +666,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cdromImageHistoryPos[slot]]); if (fn.left(8) == "ioctl://") { - menu_icon = ProgSettings::loadIcon("/cdrom_host.ico"); + menu_icon = QIcon(":/settings/qt/icons/cdrom_host.ico"); #ifdef Q_OS_WINDOWS menu_item_name = tr("Host CD/DVD Drive (%1)").arg(fn.right(2)).toUtf8().constData(); #else @@ -674,7 +674,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) #endif } else { fi.setFile(fn); - menu_icon = fi.isDir() ? ProgSettings::loadIcon("/cdrom_folder.ico") : ProgSettings::loadIcon("/cdrom_image.ico"); + menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); menu_item_name = fn.isEmpty() ? tr("previous image").toUtf8().constData() : fn.toUtf8().constData(); } imageHistoryUpdatePos->setIcon(menu_icon); @@ -727,7 +727,7 @@ MediaMenu::cdromUpdateMenu(int i) auto childs = menu->children(); auto *muteMenu = dynamic_cast(childs[cdromMutePos]); - muteMenu->setIcon(ProgSettings::loadIcon((cdrom[i].sound_on == 0) ? "/cdrom_unmute.ico" : "/cdrom_mute.ico")); + muteMenu->setIcon(QIcon((cdrom[i].sound_on == 0) ? ":/settings/qt/icons/cdrom_unmute.ico" : ":/settings/qt/icons/cdrom_mute.ico")); muteMenu->setText((cdrom[i].sound_on == 0) ? tr("&Unmute") : tr("&Mute")); auto *imageMenu = dynamic_cast(childs[cdromImagePos]); @@ -740,13 +740,13 @@ MediaMenu::cdromUpdateMenu(int i) menu_item_name = tr("Host CD/DVD Drive (%1)").arg(name.right(name.length() - 8)); #endif name2 = menu_item_name; - menu_icon = ProgSettings::loadIcon("/cdrom_host.ico"); + menu_icon = QIcon(":/settings/qt/icons/cdrom_host.ico"); } else { QFileInfo fi(cdrom[i].image_path); menu_item_name = name.isEmpty() ? QString().toUtf8().constData() : name.toUtf8().constData(); name2 = name; - menu_icon = fi.isDir() ? ProgSettings::loadIcon("/cdrom_folder.ico") : ProgSettings::loadIcon("/cdrom_image.ico"); + menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); } imageMenu->setIcon(menu_icon); imageMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), menu_item_name.toUtf8().constData())); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index ce6c21dd6..2fd108186 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -36,71 +36,16 @@ extern "C" { #include <86box/rom.h> } -static QMap iconset_to_qt; extern MainWindow *main_window; ProgSettings::CustomTranslator *ProgSettings::translator = nullptr; QTranslator *ProgSettings::qtTranslator = nullptr; -QString -ProgSettings::getIconSetPath() -{ - if (iconset_to_qt.isEmpty()) { - // Always include default bundled icons - iconset_to_qt.insert("", ":/settings/qt/icons"); - // Walk rom_paths to get the candidates - for (rom_path_t *emu_rom_path = &rom_paths; emu_rom_path != nullptr; emu_rom_path = emu_rom_path->next) { - // Check for icons subdir in each candidate - QDir roms_icons_dir(QString(emu_rom_path->path) + "/icons"); - if (roms_icons_dir.isReadable()) { - auto dirList = roms_icons_dir.entryList(QDir::AllDirs | QDir::Executable | QDir::Readable); - for (auto &curIconSet : dirList) { - if (curIconSet == "." || curIconSet == "..") { - continue; - } - iconset_to_qt.insert(curIconSet, (roms_icons_dir.canonicalPath() + '/') + curIconSet); - } - } - } - } - return iconset_to_qt[icon_set]; -} - -QIcon -ProgSettings::loadIcon(QString file) -{ - (void) getIconSetPath(); - if (!QFile::exists(iconset_to_qt[icon_set] + file)) - return QIcon(iconset_to_qt[""] + file); - return QIcon(iconset_to_qt[icon_set] + file); -} ProgSettings::ProgSettings(QWidget *parent) : QDialog(parent) , ui(new Ui::ProgSettings) { ui->setupUi(this); - (void) getIconSetPath(); - ui->comboBox->setItemData(0, ""); - ui->comboBox->setCurrentIndex(0); - for (auto i = iconset_to_qt.begin(); i != iconset_to_qt.end(); i++) { - if (i.key() == "") - continue; - QFile iconfile(i.value() + "/iconinfo.txt"); - iconfile.open(QFile::ReadOnly); - QString friendlyName; - QString iconsetinfo(iconfile.readAll()); - iconfile.close(); - if (iconsetinfo.isEmpty()) - friendlyName = i.key(); - else - friendlyName = iconsetinfo.split('\n')[0]; - ui->comboBox->addItem(friendlyName, i.key()); - if (strcmp(icon_set, i.key().toUtf8().data()) == 0) { - ui->comboBox->setCurrentIndex(ui->comboBox->findData(i.key())); - } - } - ui->comboBox->setItemData(0, '(' + tr("Default") + ')', Qt::DisplayRole); - ui->comboBoxLanguage->setItemData(0, 0xFFFF); for (auto i = lcid_langcode.begin(); i != lcid_langcode.end(); i++) { if (i.key() == 0xFFFF) @@ -129,7 +74,6 @@ ProgSettings::ProgSettings(QWidget *parent) void ProgSettings::accept() { - strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data()); lang_id = ui->comboBoxLanguage->currentData().toUInt(); open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; @@ -161,12 +105,6 @@ ProgSettings::~ProgSettings() delete ui; } -void -ProgSettings::on_pushButton_released() -{ - ui->comboBox->setCurrentIndex(0); -} - #ifdef Q_OS_WINDOWS /* Return the standard font name on Windows, which is overridden per-language to prevent CJK fonts with embedded bitmaps being chosen as a fallback. */ diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 642b2002d..b4e59e02d 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -14,8 +14,6 @@ class ProgSettings : public QDialog { public: explicit ProgSettings(QWidget *parent = nullptr); ~ProgSettings(); - static QString getIconSetPath(); - static QIcon loadIcon(QString file); #ifdef Q_OS_WINDOWS static QString getFontName(uint32_t lcid); #endif @@ -56,7 +54,6 @@ public: protected slots: void accept() override; private slots: - void on_pushButton_released(); void on_pushButtonLanguage_released(); void on_horizontalSlider_valueChanged(int value); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index f7b32ce84..d3ebf8c85 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -29,21 +29,14 @@ QLayout::SizeConstraint::SetFixedSize - + Default - - - - Icon set: - - - - + Qt::Orientation::Horizontal @@ -56,7 +49,7 @@ - + 30 @@ -68,7 +61,7 @@ - + <html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html> @@ -78,14 +71,7 @@ - - - - Default - - - - + Qt::Orientation::Horizontal @@ -98,14 +84,14 @@ - + Default - + 10 @@ -127,21 +113,21 @@ - + Language: - + Ask for confirmation before saving settings - + Qt::Orientation::Horizontal @@ -151,63 +137,35 @@ - + Inhibit multimedia keys on Windows - - - - false - - - 30 - - - - (Default) - - - - - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - - + Mouse sensitivity: - + Ask for confirmation before hard resetting - + Ask for confirmation before quitting - + Display hotkey message when entering full-screen mode diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp index 471558e22..19a537652 100644 --- a/src/qt/qt_settings.cpp +++ b/src/qt/qt_settings.cpp @@ -95,7 +95,7 @@ SettingsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return tr(pages.at(index.row()).toUtf8().data()); case Qt::DecorationRole: - return QIcon(QString("%1/%2.ico").arg(ProgSettings::getIconSetPath(), page_icons[index.row()])); + return QIcon(QString(":/settings/qt/icons/%1.ico").arg(page_icons[index.row()])); case Qt::SizeHintRole: return QSize(-1, fontHeight * 2); default: diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index cc58d3cde..52d737ae6 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -46,11 +46,11 @@ setFloppyType(QAbstractItemModel *model, const QModelIndex &idx, int type) { QIcon icon; if (type == 0) - icon = ProgSettings::loadIcon("/floppy_disabled.ico"); + icon = QIcon(":/settings/qt/icons/floppy_disabled.ico"); else if (type >= 1 && type <= 6) - icon = ProgSettings::loadIcon("/floppy_525.ico"); + icon = QIcon(":/settings/qt/icons/floppy_525.ico"); else - icon = ProgSettings::loadIcon("/floppy_35.ico"); + icon = QIcon(":/settings/qt/icons/floppy_35.ico"); model->setData(idx, QObject::tr(fdd_getname(type))); model->setData(idx, type, Qt::UserRole); @@ -64,12 +64,12 @@ setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint switch (bus) { case CDROM_BUS_DISABLED: - icon = ProgSettings::loadIcon("/cdrom_disabled.ico"); + icon = QIcon(":/settings/qt/icons/cdrom_disabled.ico"); break; case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: case CDROM_BUS_MITSUMI: - icon = ProgSettings::loadIcon("/cdrom.ico"); + icon = QIcon(":/settings/qt/icons/cdrom.ico"); break; } diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp index e679dafa5..ded50ac34 100644 --- a/src/qt/qt_settingsharddisks.cpp +++ b/src/qt/qt_settingsharddisks.cpp @@ -81,7 +81,7 @@ addRow(QAbstractItemModel *model, hard_disk_t *hd) QString busName = Harddrives::BusChannelName(hd->bus_type, hd->channel); model->setData(model->index(row, ColumnBus), busName); - model->setData(model->index(row, ColumnBus), ProgSettings::loadIcon("/hard_disk.ico"), Qt::DecorationRole); + model->setData(model->index(row, ColumnBus), QIcon(":/settings/qt/icons/hard_disk.ico"), Qt::DecorationRole); model->setData(model->index(row, ColumnBus), hd->bus_type, DataBus); model->setData(model->index(row, ColumnBus), hd->bus_type, DataBusPrevious); model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel); diff --git a/src/qt/qt_settingsotherremovable.cpp b/src/qt/qt_settingsotherremovable.cpp index 1a6dceacb..8a810a4fb 100644 --- a/src/qt/qt_settingsotherremovable.cpp +++ b/src/qt/qt_settingsotherremovable.cpp @@ -46,11 +46,11 @@ setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t QIcon icon; switch (bus) { case MO_BUS_DISABLED: - icon = ProgSettings::loadIcon("/mo_disabled.ico"); + icon = QIcon(":/settings/qt/icons/mo_disabled.ico"); break; case MO_BUS_ATAPI: case MO_BUS_SCSI: - icon = ProgSettings::loadIcon("/mo.ico"); + icon = QIcon(":/settings/qt/icons/mo.ico"); break; default: @@ -81,11 +81,11 @@ setZIPBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_ QIcon icon; switch (bus) { case ZIP_BUS_DISABLED: - icon = ProgSettings::loadIcon("/zip_disabled.ico"); + icon = QIcon(":/settings/qt/icons/zip_disabled.ico"); break; case ZIP_BUS_ATAPI: case ZIP_BUS_SCSI: - icon = ProgSettings::loadIcon("/zip.ico"); + icon = QIcon(":/settings/qt/icons/zip.ico"); break; default: diff --git a/src/unix/unix.c b/src/unix/unix.c index 81312d25d..c41aee2a4 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -73,7 +73,6 @@ static int exit_event = 0; static int fullscreen_pending = 0; uint32_t lang_id = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US uint32_t lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US -char icon_set[256] = ""; /* name of the iconset to be used */ static const uint16_t sdl_to_xt[0x200] = { [SDL_SCANCODE_ESCAPE] = 0x01, From 8b72c84c028effa55f4751f25da0c51ec1603ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Sat, 29 Mar 2025 00:13:10 +0100 Subject: [PATCH 0608/1190] Use indicator overlays for status bar icons --- src/qt/CMakeLists.txt | 3 + src/qt/icons/active.ico | Bin 0 -> 9622 bytes src/qt/icons/cartridge_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/cassette_active.ico | Bin 9622 -> 0 bytes src/qt/icons/cassette_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/cassette_empty_active.ico | Bin 9622 -> 0 bytes src/qt/icons/cdrom_active.ico | Bin 9622 -> 0 bytes src/qt/icons/cdrom_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/cdrom_empty_active.ico | Bin 9622 -> 0 bytes src/qt/icons/disabled.ico | Bin 0 -> 9622 bytes src/qt/icons/floppy_35_active.ico | Bin 9622 -> 0 bytes src/qt/icons/floppy_35_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/floppy_35_empty_active.ico | Bin 9622 -> 0 bytes src/qt/icons/floppy_525_active.ico | Bin 9622 -> 0 bytes src/qt/icons/floppy_525_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/floppy_525_empty_active.ico | Bin 9622 -> 0 bytes src/qt/icons/hard_disk_active.ico | Bin 9622 -> 0 bytes src/qt/icons/mo_active.ico | Bin 9622 -> 0 bytes src/qt/icons/mo_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/mo_empty_active.ico | Bin 9622 -> 0 bytes src/qt/icons/network_active.ico | Bin 9622 -> 0 bytes src/qt/icons/network_empty.ico | Bin 6950 -> 0 bytes src/qt/icons/sound_mute.ico | Bin 9622 -> 0 bytes src/qt/icons/zip_active.ico | Bin 9622 -> 0 bytes src/qt/icons/zip_empty.ico | Bin 9622 -> 0 bytes src/qt/icons/zip_empty_active.ico | Bin 9622 -> 0 bytes src/qt/qt_iconindicators.cpp | 33 +++++++++++ src/qt/qt_iconindicators.hpp | 15 +++++ src/qt/qt_machinestatus.cpp | 72 +++++++++++++---------- src/qt_resources.qrc | 25 +------- 30 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 src/qt/icons/active.ico delete mode 100644 src/qt/icons/cartridge_empty.ico delete mode 100644 src/qt/icons/cassette_active.ico delete mode 100644 src/qt/icons/cassette_empty.ico delete mode 100644 src/qt/icons/cassette_empty_active.ico delete mode 100644 src/qt/icons/cdrom_active.ico delete mode 100644 src/qt/icons/cdrom_empty.ico delete mode 100644 src/qt/icons/cdrom_empty_active.ico create mode 100644 src/qt/icons/disabled.ico delete mode 100644 src/qt/icons/floppy_35_active.ico delete mode 100644 src/qt/icons/floppy_35_empty.ico delete mode 100644 src/qt/icons/floppy_35_empty_active.ico delete mode 100644 src/qt/icons/floppy_525_active.ico delete mode 100644 src/qt/icons/floppy_525_empty.ico delete mode 100644 src/qt/icons/floppy_525_empty_active.ico delete mode 100644 src/qt/icons/hard_disk_active.ico delete mode 100644 src/qt/icons/mo_active.ico delete mode 100644 src/qt/icons/mo_empty.ico delete mode 100644 src/qt/icons/mo_empty_active.ico delete mode 100644 src/qt/icons/network_active.ico delete mode 100644 src/qt/icons/network_empty.ico delete mode 100644 src/qt/icons/sound_mute.ico delete mode 100644 src/qt/icons/zip_active.ico delete mode 100644 src/qt/icons/zip_empty.ico delete mode 100644 src/qt/icons/zip_empty_active.ico create mode 100644 src/qt/qt_iconindicators.cpp create mode 100644 src/qt/qt_iconindicators.hpp diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 90ea218af..e6e45fc25 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -194,6 +194,9 @@ add_library(ui STATIC qt_openglshaderconfig.hpp qt_openglshaderconfig.cpp qt_openglshaderconfig.ui + + qt_iconindicators.hpp + qt_iconindicators.cpp ) if(RTMIDI) diff --git a/src/qt/icons/active.ico b/src/qt/icons/active.ico new file mode 100644 index 0000000000000000000000000000000000000000..9569a3962ba1d76f735492b689bfd8fd1cd95839 GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkM6D4I{X;VPKfRhQl(_g<)k4GEKTE5FLoJ2bPCGG_hp}#0&@t&C5uo z5u#)w$IMalC<{MOtU$vMJ-L!q&VtMXVNhJ6W03eL9u0xf5TI)a{QqJ9|NjU1|NkHG zV`7jvNFF`&4O}Ltr!nhG7W&|Ihya|3Bvc|Nk)l|Nnyl6NAJ-@*s7{g)ot9P&*7XM(Kdm4r>4n zT+%NrVQn&GnjW@8>_e|xKzvBs3M5Y}cOcr0u=W-*4RQkrL)<}KH$dxbylp?2TWH~i zfwZ3#yJ-;yqxOSKC8E;aa14J?P9`M{47dCT@;?Ye!vK^Ru%!i%I0#d<9|5u#8H2(W z$sHj3U>IyKNFG@|t=J%Y&@rv-8Z~z`1V%$(Gz3ONU^E0qLtr!nNC<)d|NqGU|Nnvg f|NjTf|NkFggkVqu3LV4bKM6D4I{X;VPKfRhHL{)HaLAFg(o3CPJ?jylaM%0 z0~r_?2*m>|PGK~XKQN4ixdWz_5Din0VGxo4y8B>!bQ)$CDei;iIdmFkHYx6dsYN#n z#vd&1gO#)B^r-ug5*-o~JuSfE6P+F`;fL-n7@r*X!O}E34KoWSjuc!NOj!8A^bn#+ z$-jim8YuU{>?M{)4z#bK|Np;Q_5c6Z(0Z!Spn6M!fq}sQsePQliEJZIHlccokUUO< zi47M*>Tp^>M!klfmZ+Hy(anbWixl_6@)02#W)~^$hm{e8XqerkxF4pLkl8T#k?4N( zx)>LKB!@q)FhLg|iRlNHcL>oVIsFg{8<;#f=?7NE5u#yc!_<*d{=@VVOOsOm6Kf_+ z-C%J)%pK&?$l?DrH2(jqRqOwM4GpIW4Qhvh#wZ<-+F=c#flFjZ;AazRZ;>jG-!>#! za>JL9J|rs$GGS#GEDcgh&A0J&WsdmHEkNSVK z{D-D9SbqV^#ZAG=D_Gir@kyo8_2ae?QwEm)VP;TDQ&Rp>YBwz0Fnx(zWYqtVx|7nd ghv_FL{$cS(EgD;F{|ybT|Fvq>{=cE2@dH5v00wK(i2wiq diff --git a/src/qt/icons/cassette_active.ico b/src/qt/icons/cassette_active.ico deleted file mode 100644 index 32fca20b4bb41aefbd3a03a22c94f0098882b7fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pk03A0!7>`yb*?5FZ`G%!G-9 z_~5XF`VA%yqG4ts(;#uM9%R2l?MD^|sYA!uyE8I`u1c+o8$UdSmSo6>({y+Zz z|Np`N|3T3JN&F- zu>Su?E{zaukogERvAG{pj2QDk=8}LxF@#cH!CVM31LQuKoeT{B!TAeXc7gRkc?u$vk8`z-plW2kF6P9jsU?*L=|wjW8@|6%|C{|EX1{~z%GZ(!j6&p-lhV35a15}k|Ds*#^`KWea3q#yuq?iw~hYSo# zP~h?m+0DpokeQ$`g1Lo=dKOmxfyy9K&4=j)(ICAb8tgu({V+b5hKhmZk==~UMtA>z zL|G3q17rt2jL#1sec-YiDSSX?g4{zA4fO}eJY)>A8;p_62bqnc2I?PVF>GwGIiRpW z!eBRo_{ipi_)rWp2V^H$KeXNkwFN+WK{N=1)PeY5HRyUle01|cjdM`D6Y6icUOeU_ zy8&b$$SxQSjsvJ!AaO7s*-lV;fVl%Cj)p7Q1n|39C3MVSvSctY(txCa4=g;RT8}bPN&)VNh6sF%JKO)F5M$+y?R+k~@&i z0ow^1TLY;>vL9v#SPe)ViedV}@;J!k~T+2!reZ@nQY|@j>lkWExo>qz)v9A_lbsqz{Ba^2qK3*#p8LJunR7gD|>U zkbaOjhz4N{c{2PDG6xq1nGbRk$X_5eAU-;cEDur#QUe!*hA~JF7=!q*d;nq-gJE$6 zQVWV>7>1=im^?@v$^R&B0O5Hyz z7;OGWtN&>k9`JOH6#k$*Ku-*he^4tJ6c+=5L3WSg(GVEHA@KkIANl|PKd}G*|A6`b V{{xI5+(6~oz2J>=3L`(gI|{PqbPXMetZ1=HWZdi_>x0yIb+NIeXL${7&`NO{8uE^QbX zCa?|F(4e}z!RZYtosr8YyNtt?u0cKp#UY4BFJoYOVB+X}m^iY(aH)aWfs2Nj1*2i+ zfZPSs1Ct|{2DuYvF3b#cvtfJ~jjj$R4l@VYeK0YY8kk;?z1Y;Ds|TrriNR=?Suh$V z4x?dq!1(Aivb`YlL424Rm|mDTx*h1^AU?WYTzo>}FnN%BVD`e?Ln;k&7swnC4Ko*J zCb=}s9FVy%Hl;MktWiu^2!P@fhF7iH|35S|{{N~~>xrcI!?eO_P`xF=z`$UD)ILt& zq|A+@x@j5$p^ijQTg_Re`YkDQisj`Ffo`}Fufpm zfcy!QhtV)~Fg}ciiG%dP#9%Z`4o1VoVKmH6bUw%|Y;FLF!OTKe12YRIj!wh$!R&&` z!^A;+m>kS3Tzr@~I*qOmT^`x}Ftya8k=+ksgY2S~*)V^A%!Gv(wP~1}L3Y6Gqc#mP zdlV1f5CEk~WPCL=^#7_=tNw?QNQ3ktn*(Em+F_tEN(ZENSOaL_a`*=6sLzIO2oP#Z z(n_9YZB%0G15lKK@+^qPRR_Y%!X=L`PRKl@`U~ecJ-V5M+(1Ykmw6z6<8m)9ahO?z zg#s3DvH diff --git a/src/qt/icons/cassette_empty_active.ico b/src/qt/icons/cassette_empty_active.ico deleted file mode 100644 index e1bf61f612a9628a4416efa842d21d04911c7f65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 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 H5B&cD+B(Tp diff --git a/src/qt/icons/cdrom_empty.ico b/src/qt/icons/cdrom_empty.ico deleted file mode 100644 index 45580999cc66d4d9a75aed03ff9fc268592a28d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkFP+?4}p`ih+_P~JyVEX_6|6qE_ zf(2ljfq?-=V`xU#3o`?z7siLFLpA^=22%s0VfMrL=<0|u17<%Ky>P$4gs4pR#ghtb&d!pwl#3!~A^z^50N88EY8^2qex`2YW3t^fc3YWV;Et5*O2e>L>~ z|5dC0{|^oQ|9>@zzKY<(fkrXEJa<1_tY$nVMbQ+`vT@1zt*$0wG$1uBK>R>cTJuW$zIJ#LNJs>fd8R#@NIV7{d zegmmN#xQww8e|tt3}z2HAEX9q7T9cwp)k?S zgqZ=ONihp%Fw9JJ8YYj8{tv2eK=n>&{r^|1_W!>cTK|6)n2!IyYSsGxpf+(*U#MaQd1_lG9_HhCyHk*kS1E+hW@PP4&HUM2AEPP;L z4U11$+M&cQn3?D_%nq11%ne9(p*s_U57UcI!_0=cA7(a;CdLkQGtv3D%!aAMX9r9T zE*j>3m^{qgFg}dNW(O{{Fg@rrA@#_1z|_KMbhBW5m^_SziQ}S?BNnCyM#J>L_(<*n zr+b(fXU;cVdjC%hGCc(Ob@wc!}P<rUW}(|b z4YOf(!R&z1FtcGaEDX?Tn0{htnAtEIm)Xeagcx(Nse##nPGeJxF82TG|NsA1?f?Hb zH2(juRqOwM4GsVQYSrrhS3^VpuY%G0R{amH5B11bE_`J|gjKnHsGqNfj79K+HslG_NFOjsIbH@clL zKDym7H^B5!;ue@4glKd(!0d+6pv0J9TDqwB}#2AEke8eK0gKCyPg^kZ`a%)KzXVKht+E*f1O%p6?m zVdBU+4_yz;Oc)K*Lx@H}gsFdAJRW*0h*t_~L;ISycEpsR)14WnW5 zF!e}gfc*j!hp8h(gFH@156o^DjbtZCJ2EEQ4TRhYvm54CWJ}T5U^fsl4<--t3(QQI z7%m#74$VGnTvFYDv!8(O7La?fS%@wMb1S-jbUw&DV%5Ubq1%OpPj&wz*$p-ui=8M! zF!kvEMduUae{{1zdQdDw+!B7)@+_2eTVS!}P;wP}svT%uW~$Q-e;! z?8ap#x_X#87!8w0_CLBCU~155nB6cpqMM1X9>#~MgVFS~8;=`c-iFgKf5G&?XqdlY zG)x`LKQMKKXqbAqg;*Fcvteez?1a%Ud6-!+b;QzGti%w4*#WZ?M#IEmcEf0D+6{9I z%r11hVdAv3n~)n|cEe~~{>PTiVP=y`!~6}SaoLSzC%9ZB)gEHh!`y(2CdLeyn*U$p zAqx~jL+k&oTDAXgXlVSeRjby24Gj%{wQAMstD&Lct5&UAc{MaNbk(X=t3$)DhOS!w sYE@|b*U(k#eWDjIP#IN=L0e$dllmGw# diff --git a/src/qt/icons/cdrom_empty_active.ico b/src/qt/icons/cdrom_empty_active.ico deleted file mode 100644 index a48371bd7b0e0775308bacc103eb0cfb7bb16f8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkT;lP0dVEX_6 z|6qE_f(0P@KSKip0y8jx#Ne9I^}@^m>uq2F8TFq58G_7$nt@9%NE6rs0{TH}aG61h z{pe=E_+T3929TRT7#tQ14FAD$3=9moXa=Ys!Qlb&GZcgQAcy1E3snILYnUBKdg1oN z#9(S*_QDK+iNn;vXplUNjjje}22336Zw3Z<`T)tp?fob zrWU3bMuYUiFiZ`MhM5Ud3loR&L2ifXh0!oIFt@|h!o*=THoY)2VD`djbTjbj#bpM} zESNkp{nz>b|5uIw|6gVJ|9@2jf(~{3|9|zW|Nld;{{O!UM2G(WziRdW|5ro*|9`dm z|NpPy|NsBm|NlRzoDpGwlsAmv(uRRy0voaoM6+S#0Wu9@qhp)~!u$yfXBZ6)LqypF z%|oy}h|NH}WKPi^WV*+=t>0P-2DF0WiD3G?DIunFXU^?gN_v30zRx0I|Sv3zA32Ah&~@ z0n-CB3r54lL584Vu$f@}pg4eHm_CqN7#p1i*$0wG$1uCFsmCP;6Gt}-W(T@iFg{2< zj18la%z}j*NEsZ%lNqMHdb14ff#7R+Fnndmf39vl5X!2bWQ1@iyDI`IF0wSfQsRR{k6tB~l>5Ay$4 z{aXJ&^lLnX4vqi6YSsS#S3~3fzXH?s|6i^8|Nn33|NsBiL+ULF1_lNLr1o(FCpMdj z76Yeyr0_uIgV@NJC_`c40}E?de8SQW*e+g(f%k7d@6Hb@-^!{lIUVKlhB!IFky^5`_o9GDwOF&h>Z=w_nxk?a5& z55_Ptm|Apq6Kgh1KiE(-0%ixg*)VZp?LadYg$pwa-41G)4YLSl2aJZ94WnUUfKJ2o z6GOwyhS9jpMouThn2Svf%no!Kn_6_S|5w@n|69fU|8EH6|6eN@{(lW%`2T7J!~d%R z4F6Yw=n%&LtM)Pd53OhYzv|zr|DpAv5V|(>|Eg81|6dJ-(c%AJty=&8YiRucU#s^2 z{~KEW|Nm-8I}9{N>44M@YXA*gqC13iK1yCk3P+eY%tR0$9mC{EqS3<_J$=C97@Bq= zb|Tj+FgB!a1j!R^Kg@1)J7IhbyJ2?Ws{29m5O)xC1I!LWG}sN$IveZQ3A$T|a04Mb zVe(+RK|Z0P{V=nMr9o{8ushKGiI0yX48Z0fwL=KG0j!=Bzr);w#eT3^pbP~a+aY8( zOr9G4hoy5;-2hfkq5ola!~6p_lZ0@fhW}x9!)QWofVmk)ljH`pxQCemvl~X^asx~~ zD2PB=4@{F12T1nA%!1j8PNTa4Y!}p0GzvVf2T~8h*vcW0I0%En3T6+;3>X_14c3Fy z76j?Rfx&J7nGe!~jzQue46_I17efArsfDS-VK1^Uq<#T~F*?Rlu7EVc>>xyg+zV1q z2*cb;jCsVWg{dQCH_VNM?1ssM%!9FU(MWbf!WN_n4~D77Wgbi% zZv>@1kUE%MxM+N8(Cvotak&8|53?Ia7EByQL)&?9eYn)a?1s@W{V*C7_Am@H14hHtpwlqBahZv(9;OaP!{m|ukM0JT z8gv?FH_VObW}>Ty@nPy3|~VT7+$SvV7MB}z_1ETJ20+V)xa1Uet>b+`Ugy*@n1w&t^c(uH2!NSm=6CM zx@z^SRaZkpLszX@wHidfg3#fwR;^n9H8eE-*Q!JR74#*6U01+5w21p+WgZM;fLs0_K1H&j1qnyzYAS(p^ zKmPy!|H1$N|M&d=|9{H=|Nmz|`5^KCgaN3W5n+IoH;mxYhJj%M8(B`lrU{h4&@nc3 z#E2o4A)x#R!^D;$$X0;zAY4C^1Y8W{W+ZV!Oqh8fbs#f9Gz^3J6qpAx2W$q2L1MWF z)xv=6KA0HHOfXHR`@ni(214Bi79-I-kP$F9g7hO}kT^)591PNnj>$1+RL^J#jD`Ru zA@Ki){r~?T z0GR>8AT|tx_#jM)*&y>l7-S~MEOZPK2gy?dgUmw5)G&9{jL{Gn4S~@R7~CQ7|3CZx z|Nof(|Nq1I|Njqz|NnnT{Qv)>Yj`2yzv~4WMwKrv1ovqq0$50J0tAe-Ngo8!+ue^DEpLXyTys2$v(DfoVU; zEHt}7LJVkPG_@aOA)0-3w;$aNXzrns|3S83j{}el2qWyJcG?4(4#LRx!|VX1abye< z2VsyHHS-_Heh`MZ0oAV{`yd!34#L>V29R#*V36Ms?f}^b!w`Ex^3<^jzbPPl&@p}; zqq3tRFd71*Aut*OqaiRF0;3^7j}Z9(|Bw9t{~y@@|9`;z|NjBT|Njp@{QtkF7W?Lqo%VTo`PA1H*p? z7>3#h()<6>#{d71W&g(oKzcxO4F8cJ$Q%ZU-5~uS^A8+2@E;o{Mn9$YgY;vw8zu&G z1IQmB4B~^_OpO0Q>OmN+2juSth`-VG!|WnNgWL+T7hOL{9Apn(42q{?+2AN0;$D^Nih$U9;oR)ka_sr29g`>?n8DXh>eUvZU@CZD80k-8KLll$%FNR z;u8sj%t1E~**=okILc9&{iM>MxWwu{P?hBWCjT1F%Mk$gWQFVL3#*bWIbSm7#J8D807ymFz{0W z%l~g+u>TLLwKQYw2lCof!BN_bs)9m-~lxsRKJmm(fo|d{UC8zc!1Iuu^6Qc!_%%p zHXpgH$HxY_fm-H+&4Pvn%ucWvC_JI!Ape8h2@(g<$aaJIP<1f<$TUa~NIwX}#KB^t z=7Yx_Kw$yHM1&8xp#lnXY#64W7#dwa*kEwGi;)`b94uxq{%>Gl2DigNW0Vd^?XU*W zz$MH9s5BOH$QrjK)f|j=8YsMo30GWdU~!CIw}AObZ7YyHAhjSGIiG>@54m*=$ULw; zpgJC43K)5{U92ILH1*>;)--+Jwz^gc#Hf$o7NSAPlmf9RE{l zKgeD<26==8Op@KOP=JO3ILy(?NK*YzZTm^^I#?;S?H~0&_W2Hc;X+azK+_&5zhO&% z;7BErpr-x!{E1Hv<_3_{v6Vw0aS#Tn1Nobp{s);0!XUFj7{o@$AaM`|l{5J4$LB|4 zE%p)#b>3=ItpU_Ev9^lsb^qd z_zz<*S+D@C_y7O@MA0yPAU7X4Z~&}lKaAeLAHv6=A?jduQQQ7~`ylr2+qVyFKPC;4 zr=9%}{~_D~u@AwA$WvlJOfR|@-(ip22C95512Wi*co*n0|RCmjTUaOvYhVW2T6a3c!s1qoP20{#TLJ?G=rYL z2=QV1KzS2pE=-JE8fFf1`h%GTOOJ$Tn0gqE&wU^{kX?jmm|57|2NQ#-sjEY8=RoR$ zy1F`W*#>hzOg+eMbTeRbu=)ii4^j(qFH9btkE9Nx-ht_XnF*uO#i`*wn7d#!%noGt z!Pw|DdVK_QC%QOHA1FMohQ|M2wQBwUP^!@T!S$8|0|SErQu{c86J!%k431lvf2l~r z>oJ&rVf7Pwy+w!*(+4vL>PXb3e>pm|Bn;P#H*whPef%4`vQXFS;B|4Q4w7*6x6`H(>Pv z%x;)I7!4AK*#i?p=fmn=m^ere$W1WyFnM%0BB_VBLtuJfG)yl{EsPJBhxSX+?S#pL z#9?}2V(5IBnJ{sXp5fqrm_K0t!WaH9HRv?1_7r-U;Zg?*$E%^C|5vSA^*@v*^lETB z3^YdRfYc6a01aG%EXR&%)ea+MF4fv;uzZV7qqpB+@d-)`Fg7e7z-U;T31d70-ll@I zNr;z6t%G3pf}#SJ24P}^>Kbz8VSabhL2iM`k>6Ip)wY9#7tDN^UqN=l{11~O z*MEfc!OVxzAV0(00TYAKqyC4)7t!N57;Sd+bO13A7QV1>AB}$ojC!6>Iwn^h7WOcD zH2q`FlflAfH2*{DD?~Uz@-O*(h;+69!-F#n>{r1&4C7F1V}O2gcaZa2R8hsnY8;O?)Y_gjhUzrxG~`32oBm>fEd z-nW721DOE|7npjOI#?T=8vciw39}PM!^B~B!)Ta1y4zs#Fd8HeQwtNrMZ@fZsfW=Z zGe-T-zyJ$3SU8Qe_=lwfSh^s^|1dqcXk6n6F!hKqhva{_ICLBc#z&_?>Go=9Xy~d{ Lt5$^$480lv5h+$P diff --git a/src/qt/icons/floppy_35_empty_active.ico b/src/qt/icons/floppy_35_empty_active.ico deleted file mode 100644 index 4f0c928d6287dae876ac3ce3d9f4b26115005af0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkE%p)&YrkQ_1wYiVd`0Escw)z^dRdhGOn zh6V-%W?%rR{SVW-WWfRupW*-i|Cn?GSol8!G6b0gF@xd2fdgPY`(gC{{SZEs2H6WX z7mI#s+P`lf#NK`T_JQq3p`m^NxdVhjZen0yAkP0Fg`jW&`5B5~?gm8w%>VoLLBavy z4w!pjG(;X2)*xeH=D@_jZUaex?88FC)WP&2+Ygf?mIfIQGY6&z<`-NvOdU)gvi(S6 z;P3~T50Zz`Ff(ChfW%>XU}7-3p`j6MMtwabZG+T;%tFY+#o_4>W>!;E6Id@y4@{gC z`x_e}X29%&nFZs+%mld!#)i?2Q2Sx-sE6iHm^_RI>AmXs|Np9n|Nlc7&}fkOs{j8( zL;wF@g^OPO|39dl5n+IoH;mxYhJj%M8^~mw7$t0A{=z|n)MCS6!(sj)Q0_25%OgbD z1I`b_wR?~mHp5%1cip?Wt8#=RWmZ*g@k2#74%Tu*DX?c*Bo@fdO20gTfvS!{Pyy0AcwVWFLr6Dh*3(*xd(7 ze+YNN%5WSsG`(VTAIu(Vx({Y1sWd+K!NQXejczBl@PnxV$${dA5Din0&3!O2n3}pe z^mY!UE~u-k1C>?q`T(XLWH-7QFgaNL0+R=+1-Ta{kIqL@2e$_%2GavG6Go$p!@?IP z4zdH?4453u446DfEy#W7G)z5`ItCaUokp*ZV0NI3!}NjdyBZ+>f7Js1|Dg{2*lCdb zs`dXvL*xIiB1rEC*IN<{3=9TH?c)SakWDx-IBwDXO(Y+r7a4;r0r5dJMmP~!pMmt^ ztJA>purP$h53ywcxZDJleaLkYj13Zp)^Q+9(9;v%x)Y=UT2^DNpU~_e%l#yn4{{E= z`w?X>mbw+BfdunMr27ek5i||L(?6-<53ZY$>;RdEjKOIaBu{Gp3Y3}A`aNK?KfysgV3$mM38m1p+F31dY_rugsO5<}srDo%E zKg>U*(&%o&=6;yHFts2xpfDsv!`uSX2Qvqx7hMjf2D6<3Yj;4}8_<3Y$Ov#=g6V_N zAUDD6fr+8>VRbJ|9Ha+iAWS_>9^H*d>f!AWm>w7n(+g7zw~%RAU58YE zf&v1T24QX?weA6{C#LNLa|_5Fkai|YSb*FD^FN`s8mz4Vqe1mK*c~uC@X-kSK~`dv zb6|5ok%QJ|z$H$S-7t4S-2e-7n7?5(N&Y7#?9uE81pqAmVRqy4Cob_(|6`fQfQ2(I znws$sibPV<0Mu@fHV~#X{=w;jJp1AKAC~rDG)d_nXI%yYa<8Ob(_8cYhVV-%4En6=p8T zFX(o`V5zK diff --git a/src/qt/icons/floppy_525_active.ico b/src/qt/icons/floppy_525_active.ico deleted file mode 100644 index e19baa8a2094ca6d155472f1efa9c38a706e80a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pk%)yfdj9|a|DORFg3N)K!9d6ieEJFL1-Xk{{UEbp7-j~@A0Q0kgTe$PkInxe zIpmlEsRQc)`MZGu9OfW3AaP>#gZu)+Abqsd53&bjJ`98S$e57*$ZD~%iPeuSY(VA_ zqaUQEp`qbFHZwqSAisfVZ1ONW$kh)r7ldK@L2QtjFbv|u><6*YF(~aIi=p#jatsXr z|HE(t5}WbB|Nk%ylSikS6#oAQl`|p?kn)BRT-q=&Oke}qhJnd0V?h2y$1wL3OM~@8 z^A2)80*f<1@)NFjgoQbb2I&XqVdU}%#s=9z1M@(k3Gyp3ZX5{r5$iTk7*fl9AUk0g zW+o_JkTFOc6vrTS_`(jP1{B6H3{nr)3yM!93>GIMezBPc@;f>nDDyz>fVvT!FF|~4 zm{|8=(~C`vRP*q~8OVH6%mb-~m8T%R*f2;9C|p1^F?Npx^FUz%3M&u|^Dl@E5<|xz zaaj0)*w`>AkD-fW6GK+Rz`*|>88@Ku84CFS!!f!X8lRDaA6#!qFfcF}AhnMZI6ftAPl3Mht4O}e2{ujnGVAsd(h29 z=7ZFO!V^RjQVY@tQU@~|L=(~jQa@@w?lCJ;!Uv=lISyc94-*H;p<|F7Ec`)id>E8n zvB~2SM^+26106R&%1dxQ1tJG)C!w)DCL^4P1g8hl&yQ zVKa-yV#r}aDI1i(z~KgRGg{pOs=HuvAax)N;)Cpjr3>`5Kq?<(9@rj`-JrG>ItGb@ zFcsR7=xzhq3#zX1w*6r4fw}?YUTXP&Anhl~ZnQ9WOUUgTfaXgUT(Ky~s4! zOpxD@+ySx=hC%j%Fvu*hS~Bd%WjD+nAagqDiTLKzd+yVWUCj z!R)|CgVce{0?|XsevqF)?xw`=ATvPz2AKn*N%22OF9?J5qPYQYzYU}Z8H4NvnE|57 zu^(g>NIwjN_@rQvy&%0Hnq2!yu@7A>$X;sLPp;dkVL!-jP&*Ptqx+8#pHlll`ayQX zFsW_;>8B+8LHc2KgXmHFararVr3FyMko_PU z#s|^FV2~bI{Dat}U{Jk-O+7AgY-(X*AU(Kn12zf90}Kqz4;UEOKOiuO4-&_w9-kPC G00RJ^PxtQt diff --git a/src/qt/icons/floppy_525_empty.ico b/src/qt/icons/floppy_525_empty.ico deleted file mode 100644 index 8fa6c6b87c333dee1e85e39c68e15470471d3305..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkqvVdlZ?fzdE`!DyH`jK*g_NDkyT7)Cb( z#s|scvL7UejA8b|XpkK+b6{dH8YG9T7hN5U4^o52esFlh%z~K>qe0>@b6{e`(lCAa z>?dRvG4{jkK{pE~j?aFW8hqgcQ-jNVm^_Szse|!B_QTlZ(4nFK|F2s0|33zO_5c6X zum1lJy^2E~st;7oh%i9P8%A(x!@w|s4df~ejFJ{WVGmV7t~lA{4th9&+yWDWg)bo* z7N_Vm%p8#4U~+`ag2}_mHgp=~K9G4JOsttOb?7v$+y^rk<`;5lm^sAw6{Z$OR@4u$6k;!IL4!nU_A)(1Kc1626);>Hr4G=6CdPgo%T~55`8PL2@9BE{=~M z8XEt9)vERXVf0lrerRd@|5d-%{|D1Z>R{@T>D8;&{|D7u5)2Fs21xDW1Wu5vFfd9U z0mUU$1+~QCc^RMoL3WZV4{|F^4|+Ti%SW$^V0@UlAa@Z;|G4ae>BB|S%l$CF;BqG} zaa`_(iPOvdF#B-1lU#9f+)r#+!qkzHen4uGF(H4E;(lavk=eNHAjSP4cOaVyW5dkA zWd}$fAvG|)Ff-95HtFrbG!j897V!}P$y6~@O! z!_gwe&3`Jthq|5vSA^&c<2Z`J?M`q2NYkZEG{y20bz9YATba|7stmB r4Gj%lwQAKW;_0iQt5&~S6&n6Ebk+J_5E{e}y-K1vp`okR?OFu@5+_;a diff --git a/src/qt/icons/floppy_525_empty_active.ico b/src/qt/icons/floppy_525_empty_active.ico deleted file mode 100644 index 703d2a64f6d3a3a3ac6726d3411e84959eccd8e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkufGU_f97 z29TcrFg;5aECBHtu+j|-|3QG^KN19)1u+9|FIK%E7vj-R4f_uqIDpmdFtfol)D0ki zfG{{L7#MK+p8@JOkn=$pW(HVa141824wwBPIb@6;J|H{5<}xr~ggZzMSueUe7$2kt zkNx0qftf{${pf1Z`NY_dt_PhDau>`TbU7Fwmpn`ypZ{TM@P!Xd4a`0m4HHMF(d9w* zqpKl>AL{u3|Eh-n|3ewj=!5_NuYUFaf9Tc!|5vU0|35SoI}IvlL>M6D4I{X;VPKfR z267b!Mo9~xu!pL^Ck~RshQV4%@h8|mP?>>_A^8kvK7@rg3JuN6NTm^?WCEEFF_QsT zyrY-}@(GdVfs_(uCXwb5WfsU%BFuxu1-jp`@`*4HWGx~0!R!RnP%}YgD>4R`mw3uq znESx#17s-_!^{Nh2gNBAgTjt=77`^ z;XY8_0x1R4FuTxckliqI(d9_x!^{C$O2~c0noWxPVD{rO8zxVT`(SDb`C~Y`59W9D zaD<72!Vktqr$KTcj4qCk9~vP4f7Js1|Dg{2VEQVQhVerS+W< z<|BtI%zcFD!RCHKnr!Uyueu;Sb7(Aa&>%7FOu-1LK4A5mJMs7TtI-A104Z!^{OKBIJIUUXWU33=_vi zlj44u86Z6%J79cVG&%0aWfm@RkXvB(;8KGwPHb4h%mw+CR6Q`g=ys#?NpU~SOc+hb zO)zz%?#CQEfyDzU;SbXT3s)E)7Y$Pf3V#?I7Y$Ma!szlKF%U)VIf`D1;6T{l99}s{f(*=+~>j?J&?7r2|qs ztN}D|333=JhP9VyL4(Xh#vq$Pd}NyJb{cYcf((T6LFOaILy_wkNZkmpyU0mLxY7+& z9APi4y@gD}+=A3^2DzJ1nE*8#V=NIx99n1NZJWW|0&)jhSfH4NW!#dGJg98|YAcXv zKgjzew{y|mLXzERVE|1t_`{Y^c#snIX!e5wfKoRMb^lYE{s-Lu;7G(Wmja7xbQ+QW zKsw1z|FCoerb$VI2>an>A$p!7#0T36c0Ggu^Pz6QRStl}K^PQYVD%8KB>Nv!ZbP-A zP+&7benWBx$UYbb*$cujzk$pF>miiCk>o*oP%K5`z{~^LgMpFEfvaO+Ajkh`wxV)j z{v$+#`~q_aA+<1hkRDXqPqO=|wfQ+!3!rVcwS>)=6>7&H|Ff(8@seYiu z|1djYG^uGArf<~$q?iA&c!q@`jE0F5OOM7sV!a2kVTP`b+^~n~1Eqf$n^+p82ZYhp zgTz1>T^t`jG&DqX)v5(dp`i|pt5!8IAZP{#2p>kn{2I+&bLFz&J7^-%{!x&vZNFJmg zhC%v47{mw3sjm9}Kl|AK{~$9!=3&zhQU_9xj6q^B3^D_x55x!2$nFQ3Nh${E2PI&T zS>#}l-hsydAOHXV|KR`spe)9~@c%zCxPcKAvk(j_XG9nvF zH5`)XK;;H9CZ!yLs0Et?@;y>%geaLnW<&Eev1tO7r-?BSls-Xe7luK6Y?vJLK<0q* z8^|3X3}S=w5lEa=^FaDwW`N9ru|Z~m_@tNzG7F>!M1#zMVGti?9!LykCWwuULE@l% z3W^JmdXPR4MmG~A2NDD61<8Z>V7;LDM8Y6*(9Hws1L=X$AT~%p%q);Nh!2W4kbV$G zW@9rCqz8mSW`Oj9Xpp%eF%S(BgP8%ML41(8AdJgAkQpEh(htHgHponnevmmJ{U92| z2eCmI**uUOOfN`3NG~!5iGlQj)Pc%s5Dmg0F_2jxjBXxC9%Lr6IWRUz93&4ayJ6)& zh)>8okQ$I)bPN)QVUU?1_kb`+3`B!4vim^xP=aCRfeI}U8)Ofq800>Xc_0ijlTr*a zXRzb{KkWbi{~-Urfr0-&0~r{k?*M~5D0zZ0sNRxbU|=vnY9A+X(j*k9S%;xJ5L_2w zlv9v;3SBK}d{~)>sM!!KkQ}NV*!+lF4Aj^FwSf^PVzQuikdwAS;Q@+dto1X@CaC$K zya>wQAQ~Bi#E>zv93|$%$|I2bKp4h{*#)wPT=PL@fyzygxiA_e2Ergdhz8k1iTTK8 zgV-Q5VP=EaAoD?de0G5JLCY|Be*mNxqz^=cfz1G=6EqAG2Vq?1gY<(i%xn-F-E5G%KxQD* zAT|ht#6cLF`5?1E801cn`7k!fd=MKX24cg^0ns1~G7p52*~sRD#6fyt=7QKD^FVwU z4H82)8&t=GFi1ZLgXBT>fG{@mL1w@(%v_KiATbaP(ho8Rq#sm2gX(+`hS>p<2g!jj zy7?e|Aag(%WHtzc%miVOJ`e_}0qF(NAPlktgh6Z&2B`tbgD^JpL25u4WCt<^i6LW< zery<|1}2VdKFD5bVPx|`Y>=JQ#vpS+?gv#WAU3tl2bl*mA7%&09%^EcxuY0=2>k!g z{{R0!=KufyF#d0V)cLsUbprAr{RbG31`q!K{|{=1fyO8uklJAlpn*&L&Z4F)Hvdr5 zd|YNh>_w|vKy?>1-Gk(D>7`U0(QbsbhmdKQn;`LtY!}E)lwo4pelWLy+yQk1wemeE zd_naB-nJnQ`$6S1s9eH@LGsuzOg%|`oqCtFQ z46_$TQ))lVY>;^%HjIYZ4RRwghN%Im17Q#!<_3@+Y~=t*9E3sYK=}?-9)oC*xgh;8 zbI@s!JScpSF-Q!i2c{loHpqMs8y$nhK^SBw2xGG!WEL_8*#WW(*=`UUBnFZLsRhv> zyFfHZ9E3skpkt6e5C+)|!ql`MW;e(^Ap2qVAk!c=2!refVQSb9vKNFwc7kYZ_9NSg z%qC<%C`>`-fy@P&kBmWLAbAiC5(m-9YGL+(Xk-jh3-UV%Bij#B12Y3;E(pWS1F=DJ z$QUFC!Z0xy8)QDnERgvi8Xbe=L2@9B&3=$wAPh1OghA$m_#h18W5XahkUEeY$b68U zVDq8#f*?K&gXBSSAdGH5NDa&!kXax$$ZQY>@$q4h8j#r_GeBm8`hLj$OOQASgVccJ zK^U9;AT=O+VHjjC2$N$s$bJxp^>IOF6JtL}9kTuS>;}n!%mnEH`3dH4ki8%_2!rHc z7^D`Y4uo;}AEp-O29O=tFvu(r2B`;`2ckh3WG4uN*ytFf9;6n83E2n_ zATtSJkXo1;Wcxwxq8CQCAJhm3@j>pQCkELG@;}Ia5C-w-X+Ov=Wcy)m0J(!+7-Z)t q9@r50|NoEt|NkG@|Nno$+yGkA1i@5yR09J8!vO{ch6fC&0~G*-+SvmD diff --git a/src/qt/icons/mo_active.ico b/src/qt/icons/mo_active.ico deleted file mode 100644 index 06b788b4d533b13cbf947d59592360fc02d4c612..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 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 E02N}4RsaA1 diff --git a/src/qt/icons/mo_empty.ico b/src/qt/icons/mo_empty.ico deleted file mode 100644 index 30481522a601d51748c1e99c19b1c16f3dce95d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 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 diff --git a/src/qt/icons/mo_empty_active.ico b/src/qt/icons/mo_empty_active.ico deleted file mode 100644 index 29c82845b9f4bba7e17f493a3f11aadce637928e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkE%p)&YrkQ_1wYiVd`0EvOvU>e3pqyIBB zFd#4k14!+En3{9v&Vl$0FnY;?1z zFb%R7pMH>Dusj0;+IZenAtFSkTGEYAej&IH%u+MU$EH^Qv)*# z7Y);k&3<(IK;a8=AB={X39}0%4l@Tv!_0vBp}xKzl7^sZ4W<{S9%Md@4U>b>FugDu zWu7~DJ7>zCuGViM6|NpBR{{IhUfY4W=bSOxC z)&KvYq5uD{LZ??l#aI9T4=QIw7$D^hBe=9-V3@!LG8rdE2~U{6aL^#N*f7{|n15h; zVSF4kqU?d@Ay^&+>4)iog)ce{OLt%znwODEBSgsrG8>v!(Bm6sCVCnJxdW^gVG4qU zWFE-VV0B1&4Q3{c2B%vJ-G^cp$WkKALk~ZgA7N&}XiD6NZYByJ>PArbAY)M2BF8UG z4=x%Uzp%0s6!vHs=1)+tfb0R$Ffnv9VSa|03FE_Pm^e1~!PLNLm|7SgW*3Z)?iP@{ zU}7*eFn1D5!|X(MAIvOpJR+q-n0sI}x;)G*nBBSF#RC4F!#XhK{vCmt`1Z-F~Dea^)P)PJ7MO+XqX(#OjsQOlLzSmxdEmQMkC3? z%YB#}It?=uMx(nAn^`b1TxP-KNpT-c4>}F2mtZuyJd6(thpPed|5q*G{~zkW52mj| zX&65gB)@9?|IpC*|EqA)`=Rpt!S$8|0|SErQu{c86J!%k432A!pSa}CF7^!^+i%*!@Fg}cij2hxvj zHcUNC9;60l2TTq|!~B76HjIx;A2zdL?t+;OqjA{*GXtg$od(I{G80`b%)K!6Fg`B# z!_f%}Lqq?s zT7{dwiXy)n+ztbcQ92;C!x}&XmmtfrV_3aGO&VktG6vZU;v>`WG9MOBp!fwTfbmJB zLFN-RCIPYsW;S}d!NrH=DI7GyUTm!wL_G%|p9J|6JuRZU36@V_G`icsWeqWH8v@*$>hQZuEf|Ff-Bp4->~lgW3_`FogM!7#a}j@0I(r~lFIg2gx3Ur263_cx3WR!1fO!|aB+32ZhIZlEOo zVRpg%1EXPf!)TZ|jE1=tMw8?Qq__tqK3M$2%!0WIW;cvRw;QDlA|(zG_QUf(%x;(+ zFdAkzjE30>lZVk@ai|->{(+@)BpM_R!l1B%`4QRwFtcECFh0y~TyBJ^gSi1@KFA() z3=#)nusV>%Nd0(1W)qS}aRbO~P#B|Qq_hn4BSJz#D){hPx$-~ zGaF_%%xqk4z$Fed2S&rxA^RUDhfc%nhKZxQ0cI9V9Ht&d!}P&un0jpfhnWFO59HD? zyJ0lUZgd)(|6%UJr5EN#kX}&S;i6&sVKmHceEx^2LDvHlhuMwZUxoE)VB)ZFgP8-P zVRpmJ1GydMUziv=A0`g78)g>FPMCTa4KfoHE--yC^)MPHj-(!=?FF+7rWVGB(YWk} ziNpL4(~oX9OdRA^m^)x%Fh0yKbQ)$B%r2OE7!5KL+5a$e(PlRSTFxLme1bt!iL^ i(N{wm7$AHYjVupR57M`4RcL5v=&Du3(^pZ|uLb}{LsU%w diff --git a/src/qt/icons/network_active.ico b/src/qt/icons/network_active.ico deleted file mode 100644 index 25caaadfa92778dfc1db8b61e63765746c2895a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 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 diff --git a/src/qt/icons/sound_mute.ico b/src/qt/icons/sound_mute.ico deleted file mode 100644 index 89a8407354ce0ef805689d75763cd17fd58ce52b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkV}|7)cl>6Qq^_YQ}#ChW|*I z0W610CsYqqFUSory)YdhK6W!u^@7yH^n=)7eGCw{VCskI1t|cjK5*c`e+CAGeuzBC z3=oFv2m1vg$H1^;!2%RMsu>`CAPh1SWCO$u{CXLX!U3eO;Xh10$b@Ilo`LOy*$ZagjB$-(r%)WGz@#L;P(K4coE24)5lA6Xe*HcStU#;X{&Bsg8*mS$l1pZx#- zzsCRn|ML9*|7*(s|6c|E|6kSk|9`0C|NpC2|NkEv3Zbut{{R1K_y7N2L;wH(wg3PB zzxDtB|NH;{Kd77$VSto3jNsCSfnfq0J{w7r1Gyg^lVkvrVx+PMl>cBDkr$BE;$%YN z1C$5h`jOPa#XxRG635Aes)LyaQU@{vM8hzc4^;;f!=xeZg5_~!^FV6BW`G!=BndJL zgrR&)3e_x-Ji2)xF_@WP8mDum{~9yW(JIg zsmDcw%!HN8Fg-A{VD5s^FnJgsq!)_8VFhJ_DVTjQv(e3jnFUjaWG2ik7!5WLnLsxa zW(LemB(q@JaGC{D0MZXL6Q&nt7Dx`J1{)0$!-ZjH!pwk~iA6nL_aUoCHxpS7jZL(f zFh9fGiDnLnONv<_^&m`+9*{nY@c$q7|NnoG|NsAR|Ns9>&;S4LcK-jr<^KQwI`aSj zwLt#=)c|>DeHH(I)$0BKuZG6||FwGm|DU1p|NpJu|Nnpd{r~?#^!@)}0IIhn7#J7~ zklM!yoD?|`T{9@0&@s9ia`;d)5oHpjeG1}(%NLM5Ip%`&AeDKbvJ)MH>;Pe~Js|bO zVz9ZOfQPiZK`cxRlY{t&Xgi?(Z2%jHW(JD;Knfu8MEe1Y*~s>Q%^}wgsM#QYVw#EO zR%rVlOzDJbJnC62tpxc2(4B31b8%!h2#_oQY8_?}Qn0GWe~LE<0`5(9-RtUZTl^PsyQ#)sGiu>;kuAoCy?Bo4wLzasq2z(Ab)85kgT zf!v0$2V@=$gUp3saFBrsm_4vCftZ2t4@fUqAp^v}FnNeM5W5g;uu5=zf>}@kW(T@I zAYlSl1l9vH8>Svz9-WV*4jPA;@d49=#cZ&}SO~CNu!zHjVD`eo4917q0au8dL9`vX z+z+#p5RKajh_Hg$0W%Aq9;h5a_e0fT#0yNE2%2a+VD2ZvOqddw*)SR=KIG{Cf8_uF z|G@tL{{!a#{~H+p|95=&|6jw0|9@Em{{Lz-_#j6ty=Z}YWVm6zt;c$|2H)B|G)LW|NoEw`~Uy`U!ZIc#-Mf>XpGVUsU6k; z8n~oiNP*%A9n-^hsGaC#9EcAt3qkU(Zpe9g5~fKFm+%WR$n39fN4L-EHt}7LJVkPVDrEdxCyWt{B>2b><3|FHz2cN=7H2;!FcT^E9_xz zfVdqw4q$eG>_NsLaS#THVdQ_Xov<*0*$Jaz;xId5G|Ybxd59ZO{R*-Vf;m##%u>co} z1z>Yv>R@)E(jaA+7`=TBvlE?0w+rS5OcRM0ftd-j3uY#a52IoJf~kk8gYjWBx;mIR zE*j)gV*L+_N054$9WXaQ#mJ&y?t=LfW+sdeqhWT!)Wg)l_(+zcr31JOOdKu%W5CQH z6b>*qpxX`852In~(D~@%Nb(r%eVD&tG)yndZWxVh2FyP=Xqf+DG!A8mJO;BHM#Joa z*$ty{8bpBv%r2PSg!~UvPl$$@15=03i7+*|+yIluX9lHmFgsvwfbl5^dszI#Xo60J z*$E3fnB7R?1kFHGK(yU3eMokJ^&;_MN@z~Q?1a%Yw-CDpVE<#68WkOCA@Cn%AmRYy z|L+GM{(s%@;s4c^g8!@94E~3<3;bKv-tafn(ec-+1B_Qg9hg_GTEG+<8X~`H6=)qp zXefj(y}xSJs#RA*>#zS>^&d1Y5&Cb{|Ns9(|9}0z>i_TmSO5S2|N8&`|KCBiI06Fz D@pane diff --git a/src/qt/icons/zip_active.ico b/src/qt/icons/zip_active.ico deleted file mode 100644 index 40b3a593000cbced7fb6bcd25fb15421382e7eb7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pk-n#`>OVRLo7cebp8P5()0iS|Njig5M&P246xoSAO8ObVURu$jf9ET57G;A`~Uy{4;(lE z$N2Qa?MBlJaxXSBK;j?_G7}Ug==wo=K=Q~mhz-JEJs^KKFo44sn|^e?Fg{2>2*blj zbrmA6Kw$-SKUfXa|1iBU8Z3vT7MuMbH6RSrgF)ld4|M}LOhEB~4TIExFgEvt#EHeY z^n=`o55vsIrXS>9s5~fauwg>s4@>tA4GsU%F~~f0{h$nlExge6!uZH)L3)2M|NsAh z@&Eq=4FCUwk`)LuF#P{d3~pfj{~uJ&h%i9P8%A(x!@w|s4P-J&7@QVC{v!h8GZ<_R zvL9h=u({B@gPf1R;%Fwq^uTFooWkM;q#u;7QOYA&*#xo!S}uW%1)Bj&PiW>)WFE3v zF!P}_vF?Mr4cRQ!Rq%2Tl#fA}Z1bRIfx-%84h$1x9){b{%)(_RNE{i1>;lCxHuFI0 zKyE^(L1G{b)(eVHBn&bKmw6yP=w`wAAUPO@=V4H|V=G6X;&AnN%43ikQq2SF!DA*l z=HWAwDD$9x28Ay{3{nfjxWW%6Pb!ViJZSy``v)Hz*-l*M5m8rw(isSY?Sq*~gn6*C z9vh9zJe0BuWEYbAu$coB!(krCI55T*moUA!Xkgc%t4{}YQF807ySV6X?*TM`Tm3}t z93IGQuw6)H6TG}as(-Lqf@}tu4T^6x3^xl_uOZVQJ8{?nHV>3H(9DC?bs!pKHmF?0 zT7Saq!D0t7W|M0^Ub8{|LBgcEAFtWadJR;5!Z6j$2jyXCIS(@%L{r6lB(p(r2{IQM zFw72+95M!r<0>aX_JHh!h6_v|$V?C$ zL?dI6S?Cy)#z1ijaz2PgDW9R{gUo=L2ckh3Sq#KR#@NgtWIjkgvbo4?kQ_25*L;u} z$mSxmL2@umiTNNikj+JAgXBP%QuD!P;E8jR%!kG?IPO7di5LvhgN*T|Ph@rEvIp9H zP@X0Qqx%z|`$6H2q#l${2w{@q7tMTJ?G%_e$ZlNbgX&*!Ist_R%+1s@A7nfjgY5vB ziv`2niH}Ct4>lC!u}1d)e;Anm|6pMJ|AB$w{{sew{|6Wt{x`reBfOmgQcf&xU|{@z zfPop@4g-x*Iv};f8bAY=Fb9xN6LJ^KWNhkSa-`C5v(Up6oevKuP&)@5L)um#vxv1H zq!v6T2)758*09iEyJ2?1+FQspOb+4>yl#No2TFHX>;l)7NaCQn6jZ+BZTrF80&)i) zH-PO%&R0nGpxX=MQ_Fsu+l?m-h_V|LE@+q}zvHl*tmIRj)Dj0UlhF}e2Rvm0bS z$UbBY69duc80H3$dTiwoNF0R0>hQHgK;;e8?;txsdXO z%p$^mkl7%;FdD>$VVD?*#)d)mpkuJTAiseyk@kbk2H6RtL2MX?iGgT*7^4kEqWvJV zL3YAu5F3VJVjvn9riT3>vq5&kXb>BQVPYT}8>W{1AhSVs!e|g1hGAkL8XZ&9evsK9 zJ7F}44Z|=o5RHtfZ9m9tkex6Z#D-y*7>I^pTG$UV8)PSp2C-onCI+HGm{#_K%|@yl zVD^J(6gg1c4a#%Km{9%)sRfmR)W9IK&@nOgqwAq2e<;`wiZ^OtY~e=8|DbqB(+BQf zK-%r#ehIOBa??LbebsjbW8NHJzZWJ4a^qmOAJhrM+6KZB{xCn0LKE;m$a*jay8&b; z9!!e8$ZD~f4Ym~IxDPz?{~H+C|1mHy|6yQY{K3G$_<@0e;Q<2!!vQF6U|?WqU|?Vb PVVFKjX^>e57#NrV^S1*l diff --git a/src/qt/icons/zip_empty.ico b/src/qt/icons/zip_empty.ico deleted file mode 100644 index 4123c7cc24a511cb40688e047ec1ad29dda6be96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkFP+_bTSZ#fMJ(#Yms{_+8J_7>- zn2${-Of8H)aNqz~?f(7y!8D8ylSeiKCiegTf3R9yG|ViRdSo+TdSG%ewfpw%1Dgq> zVdBVsAyzNU447X)W}w>#GasfForc+k6s8O?F?6%g^}_ftJMh^LQ-e;U+XV_kbTOD7 zn0@FpOdgy4FhAg;VR~Wm$o9kJVD`cIxM*biVR~SG!9~N=VY445h8({j_krv|rjg}g zdeGen6Gx|E?t+Pf%!RShX;>OTr(xc zf|&)gk60R}57|s~zoPRAnGN#~vY%o05Yme-57P%T6Xa)f_n`C9%|PeF%!26yMKa7D zm|B<`LNrVtOdY-42Xi|i8s;t-jm>>9Ia2)&virk_58!eH77j2oV0=O}Og+pE*xU!Q z2NXxhYCwFDT5L2-9ZVlc4a^-dIT#I7gNuggL(U%{^FSCT2h$5P6PE5_bVEY}IE-NK zg{gz-1DOTGFfnpzkU9Uu|NsBB`v3p0q4ob?t=j+pYH0ocRbV>)|Eg8%|A&U+qWw|i zuZG5h^@Hjy2?hoR1EltG0w>5OvN1|{z`})W(;ynbX2QZ6okp?)tPY}uI1=3~SXw}* zVd{|VB4`0D4WXMwh);|iBE+O(AAR5$LD@>&4lSA#{IBxCYFYo4WmhMKS(Vo zEOF5=H^9us=YE(Rx>}exIt{ZErXEJa#6j*tw;!ekMx&dF&PUe|lLwg%!!R*w(I9jG zU;Y38->Uup|Axl@|FvrU|F5C$|6i?I{r_rc=>Ju4de#3>FrRoDq#tAss2v6xqjW%O zhc$o(E$i%>iurw{DLkt7PX8)hdgUE!i(>R>b_Zh@JB%PvCV zF#Y7X0X<(3vWt*BDQ=*)-7vQi;|4-@!{l+%FuQQk_}l<96PI2>@-Tgb)M0Z2EUm!I zpp?et2ADm_IS?jBsh#NhNpS-%wYbF5?ZU;!r5`yCaQPo5j>`;Ob`lbYnG1>o7#m#= zOdMu6j7C>SE+1w-$PKv6hKZxoq}mD7kFF0C2QYV_%fZB9deLcg^`!D)=Hv4}%uIB< zVSJc8AsUx@V*C#?8)gPN4U;F8CdL0Sv(fE_@nQ0~Xk6+@@juLLm|5sFOrBVp9RI`2 zMzNoHTyDVUe_VQ~B@XiwG36h%>_j(*82`iKlTsSpZgTt&axW;nNTp$JM|T6r9GE-M zHD10cHm-b3k^(Fw9PR(I9*O ze~pJMPzVjJ|F>$@{=cE2@xNBBTK_dPH2l@7RjaRthK8?#(4inYG&B@MucDN`8X6i3 GG9LgwFRm&8 diff --git a/src/qt/icons/zip_empty_active.ico b/src/qt/icons/zip_empty_active.ico deleted file mode 100644 index d57860b1050ffb2520c1c04c337435f1fc4a50fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pkm)0|yR(<@fL357zVl|Ns9C$Pi=})C`y&uo?yi26P%^FIWtR zevli$@(c_NFtfn+GB7ag+qaLP{do1FnE_G@!XP(+oQiHAioGzsFdF1%D29e9$mwwZ zqMHSFJ4`PU4YLEE{V+A?G}!G(;RJF3x)@9kIrhW+fQyEi4U)Wh6> z&3zzyKyieu2E+%c#YV%_!SsRDz}x|ogV8WGxM-L@Seb@oC%9k(nGMqmGZU8XVRS=7 z12~LedSU8d`aovDFiebG8f4D@0Q>*H7Rdkq>cId1)dK$iR~`8OuR@|j1LXg&TDAUv zXlOhd?T^C08XEuq)vEpAdP{>Na0HfjNA!;H73uGrAJJ8b?%uE;!G8?Q0VIn3AhaF&j3=9k~ zv#`?8x&WoWfNld8^KqFC6Nk~{xF4n$-Mz4QKoKX={aDRlV1TC^6th8zfkg8`TF~8( z%TAbG_`(Qk7C3F=GaIT7XI#VV0I5U9AaRhnp!|W$ognofH82|HZgd)K7AUPCW2CUf zW(LeonAtEI-E2a9eC~(og_#YbVdCgCx;)H{_}mXO1Ev>7!^8>E#JC@32Fz?24HJja z=;EZfAKeUevtaV*G(Pvk>?f8+Hyfr8Tlk}^C6|xS{p6Yn(?^W^Vc|?H4Ko`?lj44m zT2NTxqG4`;nT^l=FgbL!FmZGmW+zNNjE0GW+=XsGObv`iHxr$Yt{)~3G8=|rV$`BR z=KjCR{{P=9=Kp^~82|rT!SMfU0K@-RD;WM?4Pf}c3Pgu6{$I6<>3?V_>;F}&R{akR z4JC@c8XEfl)vDFtb{J@k(gCR*)&Lr~1X)fQhSe{)Xqf3Bd2|euBb5f31JVPg3B&_P z4R~x3qmF^Jtw8c1vxvoD^)NeO=?Vvpuot~u1meT$I*2<6+E1jNkb0b$wg<=!APjN` z0XLxM3mpE1*bVXt744^~-5~#iFpe-FWH(G6g(k)CAiF^ri~TS&afLN5c~CkB%Yn=# z7NgluQd&drCs62ritHve?ZLta&Hv!=L-!Y`qJfV8;ffQOI7xAUW;ZVX!^Cm94Q4l( zCM6D#?1$L_HUr83FmagOFdAJQ3LokQuv%C+Bhesn5C(-6%zRMvfyI#QhM5TyN2g)( zSZR>oklX>%3&S9LK^UeF6umHaz{FrQOdO;a*^MwhOdT#7WDf>L@*~WAWV3OZ1+x>K z#-$!z9HtLloEZPZ^uWwOr(yD>(xmtwW;VLrFg{Ek7mZ6DDgK9<4KoX!hRG94ljDDw z+30q|_%L~N8kamd{)d?jGZUSL$rGX}@juLLbh}}Em^_TeB~FR|(anb00i$8^xM*Vh z4^u-ajmr)A{EtfywZvh5BBuPKmYwM45aWMXd{RoI+f9!DLGA^G7pXMN?dWa*nFDhN zx*Q>Km^>jGWCzI2xXcI1;c_1?J%sE;m&av3%x&1*05gM9H^A(`We&)07>3zNFB)X; z|F1Ff|5q(w{~zkW{BKnQy6htpz c3JnbrUA1b}s?gBTP;%(2p`oF#R;^kM0M6~z)&Kwi diff --git a/src/qt/qt_iconindicators.cpp b/src/qt/qt_iconindicators.cpp new file mode 100644 index 000000000..dc8e3ceb2 --- /dev/null +++ b/src/qt/qt_iconindicators.cpp @@ -0,0 +1,33 @@ +#include +#include +#include "qt_iconindicators.hpp" + +QIcon +getIndicatorIcon(IconIndicator indicator) +{ + switch (indicator) { + case Active: + return QIcon(":/settings/qt/icons/active.ico"); + case Disabled: + return QIcon(":/settings/qt/icons/disabled.ico"); + default: + return QIcon(); + } +} + +QPixmap +getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator) +{ + auto iconPixmap = icon.pixmap(size, iconMode); + + if (indicator == None) + return iconPixmap; + + auto painter = QPainter(&iconPixmap); + auto indicatorPixmap = getIndicatorIcon(indicator).pixmap(size); + + painter.drawPixmap(0, 0, indicatorPixmap); + painter.end(); + + return iconPixmap; +} \ No newline at end of file diff --git a/src/qt/qt_iconindicators.hpp b/src/qt/qt_iconindicators.hpp new file mode 100644 index 000000000..553520063 --- /dev/null +++ b/src/qt/qt_iconindicators.hpp @@ -0,0 +1,15 @@ +#ifndef QT_ICONINDICATORS_HPP +# define QT_INDICATORS_HPP + +#include +#include + +enum IconIndicator { + None, + Active, + Disabled, +}; + +QPixmap getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator); + +#endif \ No newline at end of file diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index eff29a232..d555be360 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -54,6 +54,7 @@ extern "C" { #include "qt_mainwindow.hpp" #include "qt_soundgain.hpp" #include "qt_progsettings.hpp" +#include "qt_iconindicators.hpp" #include @@ -65,19 +66,24 @@ namespace { struct PixmapSetActive { QPixmap normal; QPixmap active; - void load(const QString &basePath); + void load(const QIcon &icon); +}; +struct PixmapSetDisabled { + QPixmap normal; + QPixmap disabled; + void load(const QIcon &icon); }; struct PixmapSetEmpty { QPixmap normal; QPixmap empty; - void load(const QString &basePath); + void load(const QIcon &icon); }; struct PixmapSetEmptyActive { QPixmap normal; QPixmap active; QPixmap empty; QPixmap empty_active; - void load(QString basePath); + void load(const QIcon &icon); }; struct Pixmaps { PixmapSetEmpty cartridge; @@ -90,7 +96,7 @@ struct Pixmaps { PixmapSetEmptyActive mo; PixmapSetActive hd; PixmapSetEmptyActive net; - QPixmap sound, soundMuted; + PixmapSetDisabled sound; }; struct StateActive { @@ -170,30 +176,35 @@ struct StateEmptyActive { }; static QSize pixmap_size(16, 16); -static const QString pixmap_empty = QStringLiteral("_empty"); -static const QString pixmap_active = QStringLiteral("_active"); -static const QString pixmap_empty_active = QStringLiteral("_empty_active"); + void -PixmapSetEmpty::load(const QString &basePath) +PixmapSetEmpty::load(const QIcon &icon) { - normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - empty = QIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); + normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None); } void -PixmapSetActive::load(const QString &basePath) +PixmapSetActive::load(const QIcon &icon) { - normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - active = QIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); + normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); } void -PixmapSetEmptyActive::load(QString basePath) +PixmapSetDisabled::load(const QIcon &icon) { - normal = QIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size); - active = QIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size); - empty = QIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size); - empty_active = QIcon(basePath.arg(pixmap_empty_active)).pixmap(pixmap_size); + normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + disabled = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Disabled); +} + +void +PixmapSetEmptyActive::load(const QIcon &icon) +{ + normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); + empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None); + empty_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Active); } } @@ -202,21 +213,20 @@ struct MachineStatus::States { States(QObject *parent) { - pixmaps.cartridge.load(":/settings/qt/icons/cartridge%1.ico"); - pixmaps.cassette.load(":/settings/qt/icons/cassette%1.ico"); + pixmaps.cartridge.load(QIcon(":/settings/qt/icons/cartridge.ico")); + pixmaps.cassette.load(QIcon(":/settings/qt/icons/cassette.ico")); pixmaps.floppy_disabled.normal = QIcon(":/settings/qt/icons/floppy_disabled.ico").pixmap(pixmap_size); pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal; pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal; pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal; - pixmaps.floppy_525.load(":/settings/qt/icons/floppy_525%1.ico"); - pixmaps.floppy_35.load(":/settings/qt/icons/floppy_35%1.ico"); - pixmaps.cdrom.load(":/settings/qt/icons/cdrom%1.ico"); - pixmaps.zip.load(":/settings/qt/icons/zip%1.ico"); - pixmaps.mo.load(":/settings/qt/icons/mo%1.ico"); - pixmaps.hd.load(":/settings/qt/icons/hard_disk%1.ico"); - pixmaps.net.load(":/settings/qt/icons/network%1.ico"); - pixmaps.sound = QIcon(":/settings/qt/icons/sound.ico").pixmap(pixmap_size); - pixmaps.soundMuted = QIcon(":/settings/qt/icons/sound_mute.ico").pixmap(pixmap_size); + pixmaps.floppy_525.load(QIcon(":/settings/qt/icons/floppy_525.ico")); + pixmaps.floppy_35.load(QIcon(":/settings/qt/icons/floppy_35.ico")); + pixmaps.cdrom.load(QIcon(":/settings/qt/icons/cdrom.ico")); + pixmaps.zip.load(QIcon(":/settings/qt/icons/zip.ico")); + pixmaps.mo.load(QIcon(":/settings/qt/icons/mo.ico")); + pixmaps.hd.load(QIcon(":/settings/qt/icons/hard_disk.ico")); + pixmaps.net.load(QIcon(":/settings/qt/icons/network.ico")); + pixmaps.sound.load(QIcon(":/settings/qt/icons/sound.ico")); cartridge[0].pixmaps = &pixmaps.cartridge; cartridge[1].pixmaps = &pixmaps.cartridge; @@ -510,7 +520,7 @@ MachineStatus::refresh(QStatusBar *sbar) sound_muted ^= 1; config_save(); if (d->sound) - d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); + d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal); muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); }); @@ -694,7 +704,7 @@ MachineStatus::refresh(QStatusBar *sbar) } d->sound = std::make_unique(); - d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound); + d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal); if (muteUnmuteAction) muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index 6ca323b89..dc8db2c06 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -1,16 +1,9 @@ qt/icons/cartridge.ico - qt/icons/cartridge_empty.ico qt/icons/cassette.ico - qt/icons/cassette_active.ico - qt/icons/cassette_empty.ico - qt/icons/cassette_empty_active.ico qt/icons/cdrom.ico - qt/icons/cdrom_active.ico qt/icons/cdrom_disabled.ico - qt/icons/cdrom_empty.ico - qt/icons/cdrom_empty_active.ico qt/icons/cdrom_mute.ico qt/icons/cdrom_unmute.ico qt/icons/cdrom_image.ico @@ -18,38 +11,24 @@ qt/icons/cdrom_host.ico qt/icons/display.ico qt/icons/floppy_35.ico - qt/icons/floppy_35_active.ico - qt/icons/floppy_35_empty.ico - qt/icons/floppy_35_empty_active.ico qt/icons/floppy_525.ico - qt/icons/floppy_525_active.ico - qt/icons/floppy_525_empty.ico - qt/icons/floppy_525_empty_active.ico qt/icons/floppy_and_cdrom_drives.ico qt/icons/floppy_disabled.ico qt/icons/hard_disk.ico - qt/icons/hard_disk_active.ico qt/icons/input_devices.ico qt/icons/machine.ico qt/icons/mo.ico - qt/icons/mo_active.ico qt/icons/mo_disabled.ico - qt/icons/mo_empty.ico - qt/icons/mo_empty_active.ico qt/icons/network.ico - qt/icons/network_active.ico - qt/icons/network_empty.ico qt/icons/other_peripherals.ico qt/icons/other_removable_devices.ico qt/icons/ports.ico qt/icons/sound.ico - qt/icons/sound_mute.ico qt/icons/storage_controllers.ico qt/icons/zip.ico - qt/icons/zip_active.ico qt/icons/zip_disabled.ico - qt/icons/zip_empty.ico - qt/icons/zip_empty_active.ico + qt/icons/active.ico + qt/icons/disabled.ico qt/icons/86Box-gray.ico qt/icons/86Box-green.ico qt/icons/86Box-red.ico From fcd6bd9c664564eb2e0d03086cafb46e6163d585 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 01:22:35 +0100 Subject: [PATCH 0609/1190] Serial: Give the OKI IF386AX 16450 serial ports instead of 8250. --- src/device/serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/serial.c b/src/device/serial.c index deb97225a..8483f7fe3 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -999,7 +999,8 @@ void serial_standalone_init(void) { while (next_inst < SERIAL_MAX) - device_add_inst(&ns8250_device, next_inst + 1); + device_add_inst(!strcmp(machine_get_internal_name(), "if386sx") ? &ns16450_device : + &ns8250_device, next_inst + 1); }; const device_t ns8250_device = { From 2ed64c83996e762eb10c296666d759068c8ec69f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 08:11:04 +0100 Subject: [PATCH 0610/1190] Machine settings: Reduce the two loops to determine present machine types to a single loop, reduces the number of iterations from (number of machine types * number of machines) to just (number of machines), speeding things up. --- src/qt/qt_settingsmachine.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp index 9b1f9849e..34968b288 100644 --- a/src/qt/qt_settingsmachine.cpp +++ b/src/qt/qt_settingsmachine.cpp @@ -88,20 +88,31 @@ SettingsMachine::SettingsMachine(QWidget *parent) ui->comboBoxPitMode->setCurrentIndex(-1); ui->comboBoxPitMode->setCurrentIndex(pit_mode + 1); - int selectedMachineType = 0; - auto *machineTypesModel = ui->comboBoxMachineType->model(); - for (int i = 1; i < MACHINE_TYPE_MAX; ++i) { - int j = 0; - while (machine_get_internal_name_ex(j) != nullptr) { - if (machine_available(j) && (machine_get_type(j) == i)) { + int selectedMachineType = 0; + auto * machineTypesModel = ui->comboBoxMachineType->model(); + int i = -1; + int j = 0; + int cur_j = 0; + const void *miname; + do { + miname = machine_get_internal_name_ex(j); + + if ((miname == nullptr) || (machine_get_type(j) != i)) { + if ((i != -1) && (cur_j != 0)) { int row = Models::AddEntry(machineTypesModel, machine_types[i].name, machine_types[i].id); if (machine_types[i].id == machine_get_type(machine)) selectedMachineType = row; - break; } - j++; + + i = machine_get_type(j); + cur_j = 0; } - } + + if (machine_available(j)) + cur_j++; + + j++; + } while (miname != nullptr); ui->comboBoxMachineType->setCurrentIndex(-1); ui->comboBoxMachineType->setCurrentIndex(selectedMachineType); From bb22e1dccb39b0ce1af9bfbb3202c5a78da3bdb3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 08:14:30 +0100 Subject: [PATCH 0611/1190] Moved the Packard Bell PB450 to the correct place on the machines list. --- src/machine/machine_table.c | 80 ++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index aa9bae305..fa383139b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6981,46 +6981,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* has a Phoenix PLCC Multikey copyrighted 1993, version unknown. */ - { - .name = "[OPTi 895] Packard Bell PB450", - .internal_name = "pb450", - .type = MACHINE_TYPE_486_S3_PCI, - .chipset = MACHINE_CHIPSET_OPTI_895_802G, - .init = machine_at_pb450_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET3, - .block = CPU_BLOCK_NONE, - .min_bus = 0, - .max_bus = 0, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_SUPER_IO | MACHINE_IDE_DUAL | MACHINE_VIDEO, - .ram = { - .min = 1024, - .max = 65536, - .step = 1024 - }, - .nvrmask = 255, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = &pb450_device, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = &gd5428_vlb_onboard_device, - .snd_device = NULL, - .net_device = NULL - }, /* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */ { .name = "[SiS 461] Acer V10", @@ -7915,6 +7875,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* has a Phoenix PLCC Multikey copyrighted 1993, version unknown. */ + { + .name = "[OPTi 895] Packard Bell PB450", + .internal_name = "pb450", + .type = MACHINE_TYPE_486_S3_PCI, + .chipset = MACHINE_CHIPSET_OPTI_895_802G, + .init = machine_at_pb450_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_SUPER_IO | MACHINE_IDE_DUAL | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &pb450_device, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5428_vlb_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ { .name = "[i420EX] ASUS PVI-486AP4", From 85a94516f75f7c898d6c2cfd456c2aee97668175 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Mar 2025 16:31:32 +0600 Subject: [PATCH 0612/1190] Caps/Num/Scroll LED states are now displayed --- src/device/keyboard.c | 15 +++++++++------ src/device/keyboard_at.c | 3 +++ src/qt/qt_mainwindow.cpp | 33 +++++++++++++++++++++++++++++++++ src/qt/qt_mainwindow.hpp | 3 +++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index a00968cf7..aa9aba3c6 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -72,9 +72,9 @@ static int keydelay[512]; #endif static scancode *scan_table; /* scancode table for keyboard */ -static uint8_t caps_lock = 0; -static uint8_t num_lock = 0; -static uint8_t scroll_lock = 0; +static volatile uint8_t caps_lock = 0; +static volatile uint8_t num_lock = 0; +static volatile uint8_t scroll_lock = 0; static uint8_t shift = 0; static int key5576mode = 0; @@ -318,13 +318,16 @@ keyboard_input(int down, uint16_t scan) shift &= ~0x80; break; case 0x03a: /* Caps Lock */ - caps_lock ^= 1; + if (!(machine_has_bus(machine, MACHINE_AT) > 0)) + caps_lock ^= 1; break; case 0x045: - num_lock ^= 1; + if (!(machine_has_bus(machine, MACHINE_AT) > 0)) + num_lock ^= 1; break; case 0x046: - scroll_lock ^= 1; + if (!(machine_has_bus(machine, MACHINE_AT) > 0)) + scroll_lock ^= 1; break; default: diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index e61b8547a..c5f73459b 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -3476,6 +3476,7 @@ keyboard_at_bat(void *priv) keyboard_scan = 1; + keyboard_update_states(0, 0, 0); kbc_at_dev_queue_add(dev, 0xaa, 0); } else { bat_counter--; @@ -3510,6 +3511,7 @@ keyboard_at_write(void *priv) switch (dev->command) { case 0xed: /* Set/reset LEDs */ kbc_at_dev_queue_add(dev, 0xfa, 0); + keyboard_update_states(!!(val & 0x4), !!(val & 0x2), val & 0x1); keyboard_at_log("%s: Set/reset LEDs [%02X]\n", dev->name, val); break; @@ -3762,6 +3764,7 @@ keyboard_at_init(const device_t *info) if (dev->port != NULL) { kbc_at_dev_reset(dev, 0); + keyboard_update_states(0, 0, 0); bat_counter = 0x0000; } diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index b3d0d9fa9..9f63bf297 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -184,6 +184,32 @@ MainWindow::MainWindow(QWidget *parent) ui->menuEGA_S_VGA_settings->menuAction()->setMenuRole(QAction::NoRole); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); + + num_label = new QLabel; + num_label->setText(" NUM "); + statusBar()->addPermanentWidget(num_label); + + scroll_label = new QLabel; + scroll_label->setText(" SCRL "); + statusBar()->addPermanentWidget(scroll_label); + + caps_label = new QLabel; + caps_label->setText(" CAPS "); + statusBar()->addPermanentWidget(caps_label); + + QTimer* ledKeyboardTimer = new QTimer(this); + ledKeyboardTimer->setTimerType(Qt::CoarseTimer); + ledKeyboardTimer->setInterval(1); + connect(ledKeyboardTimer, &QTimer::timeout, this, [this] () { + uint8_t caps, num, scroll; + keyboard_get_states(&caps, &num, &scroll); + + num_label->setStyleSheet(num ? "QLabel { background: green; }" : ""); + caps_label->setStyleSheet(caps ? "QLabel { background: green; }" : ""); + scroll_label->setStyleSheet(scroll ? "QLabel { background: green; }" : ""); + }); + ledKeyboardTimer->start(); + #ifdef Q_OS_WINDOWS util::setWin11RoundedCorners(this->winId(), (hide_status_bar ? false : true)); #endif @@ -211,6 +237,9 @@ MainWindow::MainWindow(QWidget *parent) connect(this, &MainWindow::hardResetCompleted, this, [this]() { ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); + num_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + scroll_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + caps_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); #ifdef USE_WACOM @@ -1306,6 +1335,10 @@ MainWindow::refreshMediaMenu() status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); + + num_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + scroll_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + caps_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); } void diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index f1c6cadf6..06a739dd8 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -184,6 +185,8 @@ private: friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. + QLabel *caps_label, *scroll_label, *num_label; + bool isShowMessage = false; }; From 81e6b2a40a292474a03a2e1df38f774f53277f5d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 27 Mar 2025 16:58:42 +0600 Subject: [PATCH 0613/1190] Correct the order --- src/qt/qt_mainwindow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 9f63bf297..3ee8d61b4 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -189,14 +189,14 @@ MainWindow::MainWindow(QWidget *parent) num_label->setText(" NUM "); statusBar()->addPermanentWidget(num_label); - scroll_label = new QLabel; - scroll_label->setText(" SCRL "); - statusBar()->addPermanentWidget(scroll_label); - caps_label = new QLabel; caps_label->setText(" CAPS "); statusBar()->addPermanentWidget(caps_label); + scroll_label = new QLabel; + scroll_label->setText(" SCRL "); + statusBar()->addPermanentWidget(scroll_label); + QTimer* ledKeyboardTimer = new QTimer(this); ledKeyboardTimer->setTimerType(Qt::CoarseTimer); ledKeyboardTimer->setInterval(1); From 8861741945404350589613bbe2ab4157c0f30c8c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Mar 2025 00:10:16 +0600 Subject: [PATCH 0614/1190] Some needed changes for hard resets --- src/86box.c | 3 +++ src/device/keyboard.c | 2 +- src/device/keyboard_at.c | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/86box.c b/src/86box.c index 2b6e1ba9f..57faa89c1 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1301,6 +1301,9 @@ pc_reset_hard_init(void) /* Mark ACPI as unavailable */ acpi_enabled = 0; + /* Reset all keyboard indicators */ + keyboard_update_states(0, 0, 0); + /* Reset the general machine support modules. */ io_init(); diff --git a/src/device/keyboard.c b/src/device/keyboard.c index aa9aba3c6..7666b0e70 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -75,7 +75,7 @@ static scancode *scan_table; /* scancode table for keyboard */ static volatile uint8_t caps_lock = 0; static volatile uint8_t num_lock = 0; static volatile uint8_t scroll_lock = 0; -static uint8_t shift = 0; +static uint8_t shift = 0; static int key5576mode = 0; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index c5f73459b..605f51e90 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -3764,12 +3764,12 @@ keyboard_at_init(const device_t *info) if (dev->port != NULL) { kbc_at_dev_reset(dev, 0); - keyboard_update_states(0, 0, 0); bat_counter = 0x0000; } keyboard_send = add_data_kbd; SavedKbd = dev; + keyboard_update_states(0, 0, 0); inv_cmd_response = (dev->type & FLAG_PS2) ? 0xfe : 0xfa; @@ -3788,6 +3788,8 @@ keyboard_at_close(void *priv) /* Disable the scancode maps. */ keyboard_set_table(NULL); + keyboard_update_states(0, 0, 0); + SavedKbd = NULL; free(dev); From 7e3cf32dcacc9b6af1b709c78323cbb3e6fd9cf0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 28 Mar 2025 00:15:06 +0600 Subject: [PATCH 0615/1190] Remove some no-more-needed changes --- src/86box.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/86box.c b/src/86box.c index 57faa89c1..2b6e1ba9f 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1301,9 +1301,6 @@ pc_reset_hard_init(void) /* Mark ACPI as unavailable */ acpi_enabled = 0; - /* Reset all keyboard indicators */ - keyboard_update_states(0, 0, 0); - /* Reset the general machine support modules. */ io_init(); From 94a928978e20fcb2b0b9edd86b430ce818f4255d Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Sat, 29 Mar 2025 20:46:30 +0900 Subject: [PATCH 0616/1190] PS55DA2: update compatibility table --- src/video/vid_ps55da2.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 98db5f9fa..1f00b7cc5 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -112,17 +112,18 @@ EFD8h * Display Adapter/J [Atlas-SP2] [Japanese DOS and Display Adapter compatibility] - | POS ID | Adapter Name | K3.31 | J4.04 | J4.08 | OS2 J1.3 | Win3 | - |------------|-----------------------------|:-----:|:-----:|:-----:|:--------:|:----:| - | EFFFh | Display Adapter | X | | | | | - | FFEDh | ? [Atlas EVT] | X | | | | | - | FFFDh | ? [LDT EVT] | X | | | | | - | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | - | E013h | ? [LDT] | X | X | X | X | | - | ECCEh | Display Adapter IV | | X | X | X | | - | ECECh | Display Adapter IV,B1 | | X | X | X | X | - | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | - | EFD8h | Display Adapter /J | | | X | X | X | + | | | K3.31 | J4.04 | J4.08 | OS2J1.3 | Win3.02 | DOSVExt | + | POS ID | Adapter Name | 5605JBK | 5605PAA | 5605PCA | 5605PDE | 5605PAW | 5605PXA | + |------------|-----------------------------|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| + | EFFFh | Display Adapter | X | | | | | | + | FFEDh | ? [Atlas EVT] | X | | | | | | + | FFFDh | ? [LDT EVT] | X | | | | | | + | EFFEh | Display Adapter II,III,V,B2 | X | X | X | X | X | X | + | E013h | ? [LDT] | X | X | X | X | | X | + | ECCEh | Display Adapter IV | | X | X | X | | X | + | ECECh | Display Adapter IV,B1 | | X | X | X | X | X | + | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | X | + | EFD8h | Display Adapter /J | | | X | X | X | X | */ /* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ #define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ From 6d43f7e2df212fd7d9bf662a0fcf6caa18c75541 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 29 Mar 2025 14:24:20 +0100 Subject: [PATCH 0617/1190] More fixes for 5380-based SCSI chips of the day (March 29th, 2025) 1. Avoid audio stops when they don't need to be. 2. And improved the MMIO-based NCR 53c400 timings to be similar to the port I/O-based one (T130B). 3. Minor timing fixes to the T128/PAS as well (especially for the hdd, when entering Windows 1.x using a SCSI HDD). --- src/scsi/scsi_ncr5380.c | 3 -- src/scsi/scsi_ncr53c400.c | 94 ++++++++++++++++++++++++++++----------- src/scsi/scsi_t128.c | 15 ++++--- 3 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 048194a96..132fade37 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -95,9 +95,6 @@ ncr5380_reset(ncr_t *ncr) ncr->timer(ncr->priv, 0.0); - for (int i = 0; i < 8; i++) - scsi_device_reset(&scsi_devices[ncr->bus][i]); - scsi_bus->state = STATE_IDLE; scsi_bus->clear_req = 0; scsi_bus->wait_complete = 0; diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index fc62a1cab..f91dc83a9 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -29,11 +29,11 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> -#include <86box/timer.h> #include <86box/dma.h> #include <86box/pic.h> #include <86box/mca.h> #include <86box/mem.h> +#include <86box/timer.h> #include <86box/rom.h> #include <86box/device.h> #include <86box/nvr.h> @@ -41,6 +41,7 @@ #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/scsi_ncr5380.h> +#include "cpu.h" #define LCS6821N_ROM "roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" #define COREL_LS2000_ROM "roms/scsi/ncr5380/Corel LS2000 - BIOS ROM - Ver 1.65.bin" @@ -80,6 +81,7 @@ typedef struct ncr53c400_t { int buffer_host_pos; int busy; + int reset; uint8_t pos_regs[8]; pc_timer_t timer; @@ -126,6 +128,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) addr &= 0x3fff; + if (addr >= 0x3880) + ncr53c400_log("%04X:%08X: memio_write(%04x)=%02x\n", CS, cpu_state.pc, addr, val); + if (addr >= 0x3a00) ncr400->ext_ram[addr - 0x3a00] = val; else { @@ -147,6 +152,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->busy = 1; + if (ncr400->type != ROM_T130B) + timer_on_auto(&ncr400->timer, 1.0); } } else ncr53c400_log("No Write.\n"); @@ -155,6 +162,19 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) case 0x3980: switch (addr) { case 0x3980: /* Control */ + /*Parity bits*/ + /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ + /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ + /*Required by RTASPI10.SYS otherwise it won't initialize.*/ + if (val & 0x80) { + if (ncr->mode & 0x30) { + if (!(ncr->mode & MODE_DMA)) { + ncr->mode = 0x00; + ncr400->reset = 1; + } + } + } + ncr53c400_log("NCR 53c400 control=%02x, mode=%02x.\n", val, ncr->mode); if ((val & CTRL_DATA_DIR) && !(ncr400->status_ctrl & CTRL_DATA_DIR)) { ncr400->buffer_host_pos = MIN(128, dev->buffer_length); @@ -180,10 +200,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) } if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); - if (ncr400->type == ROM_T130B) - timer_on_auto(&ncr400->timer, 10.0); - else - timer_on_auto(&ncr400->timer, scsi_bus->period); + timer_on_auto(&ncr400->timer, 10.0); ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer)); } else @@ -241,6 +258,20 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; + if (ncr400->type != ROM_T130B) { + if (!ncr400->block_count_loaded) { + scsi_bus->tx_mode = PIO_TX_BUS; + ncr53c400_log("IO End of read transfer\n"); + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr53c400_log("NCR read irq\n"); + ncr5380_irq(ncr, 1); + } + } else if (!timer_is_enabled(&ncr400->timer)) { + ncr53c400_log("Timer re-enabled.\n"); + timer_on_auto(&ncr400->timer, 1.0); + } + } } } break; @@ -252,11 +283,10 @@ ncr53c400_read(uint32_t addr, void *priv) ncr53c400_log("NCR status ctrl read=%02x.\n", ncr400->status_ctrl & STATUS_BUFFER_NOT_READY); if (!ncr400->busy) ret |= STATUS_5380_ACCESSIBLE; - if (ncr->mode & 0x30) { /*Parity bits*/ - if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ - ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ - ncr->mode = 0x00; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ - } + + if (ncr400->reset) { + ncr400->reset = 0; + ret |= 0x01; } ncr53c400_log("NCR 53c400 status=%02x.\n", ret); break; @@ -267,7 +297,10 @@ ncr53c400_read(uint32_t addr, void *priv) break; case 0x3982: /* switch register read */ - ret = 0xff; + if (ncr->irq != -1) { + ret = 0xf8; + ret += ncr->irq; + } ncr53c400_log("Switches read=%02x.\n", ret); break; @@ -282,7 +315,7 @@ ncr53c400_read(uint32_t addr, void *priv) } if (addr >= 0x3880) - ncr53c400_log("memio_read(%08x)=%02x\n", addr, ret); + ncr53c400_log("%04X:%08X: memio_read(%04x)=%02x\n", CS, cpu_state.pc, addr, ret); return ret; } @@ -424,11 +457,8 @@ ncr53c400_callback(void *priv) uint8_t status; if (scsi_bus->tx_mode != PIO_TX_BUS) { - if (ncr400->type == ROM_T130B) { - ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0); - timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0); - } else - timer_on_auto(&ncr400->timer, 1.0); + ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0); + timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0); } if (scsi_bus->data_wait & 1) { @@ -538,14 +568,17 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); if (!ncr400->block_count) { - scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; - ncr53c400_log("IO End of read transfer\n"); - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) { - ncr53c400_log("NCR read irq\n"); - ncr5380_irq(ncr, 1); - } + if (ncr400->type == ROM_T130B) { + scsi_bus->tx_mode = PIO_TX_BUS; + ncr53c400_log("IO End of read transfer\n"); + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) { + ncr53c400_log("NCR read irq\n"); + ncr5380_irq(ncr, 1); + } + } else + timer_on_auto(&ncr400->timer, 1.0); } break; } @@ -732,8 +765,17 @@ ncr53c400_init(const device_t *info) scsi_bus_set_speed(ncr->bus, 5000000.0); scsi_bus->speed = 0.2; - scsi_bus->divider = 2.0; - scsi_bus->multi = 1.750; + if (ncr400->type == ROM_T130B) { + scsi_bus->divider = 2.0; + scsi_bus->multi = 1.750; + } else { + scsi_bus->divider = 1.0; + scsi_bus->multi = 1.0; + } + + for (int i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[ncr->bus][i]); + return ncr400; } diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index eada27246..3f273d1bb 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -95,9 +95,10 @@ t128_write(uint32_t addr, uint8_t val, void *priv) t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded); t128->status &= ~0x04; - timer_on_auto(&t128->timer, 10.0); + timer_on_auto(&t128->timer, 1.0); } - } + } else + t128_log("Write not allowed.\n"); } } @@ -136,20 +137,18 @@ t128_read(uint32_t addr, void *priv) t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d.\n", t128->status, scsi_bus->period, timer_is_enabled(&t128->timer)); + t128->status &= ~0x04; if (!t128->block_loaded) { ncr->isr |= STATUS_END_OF_DMA; if (ncr->mode & MODE_ENA_EOP_INT) { t128_log("T128 read irq\n"); ncr5380_irq(ncr, 1); } - t128->status &= ~0x04; scsi_bus->bus_out |= BUS_CD; scsi_bus->tx_mode = PIO_TX_BUS; timer_stop(&t128->timer); } else if (!timer_is_enabled(&t128->timer)) - timer_on_auto(&t128->timer, 10.0); - else - t128->status &= ~0x04; + timer_on_auto(&t128->timer, 1.0); } } else { /*According to the WinNT DDK sources, just get the status timeout bit from here.*/ @@ -522,6 +521,10 @@ t128_init(const device_t *info) scsi_bus->speed = 0.2; scsi_bus->divider = 1.0; scsi_bus->multi = 1.0; + + for (int i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[ncr->bus][i]); + return t128; } From c91f2255ad7795573ab2383e2a3205df69d308ad Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 29 Mar 2025 14:42:25 +0100 Subject: [PATCH 0618/1190] Vast overhaul for the Mach8/32/8514/A (March 29th, 2025) 1. Implemented the FIFO test data to pass some tests of the Mach8 POST ROM and tests (not complete yet). 2. Overhauled the mode switches again, but this time with way less hacks and more on manual instructions. 3. Use a function pointer to determine if the Mach8 type used is a VGA combo or add-on. 4. Mach32 mode tests are no longer incorrectly green (was caused by improper pixtrans parts). 5. Implemented overscan color to the Mach32 as well as the CRT offset. 6. And fixed a PCI LFB GPF issue with the Mach32 2.3 drivers on Win3.1x. 7. Implemented memory boundary for both the Mach32 SVGA and its accelerator. 8. Added undocumented ports used by the FIFO (such as ports 0x8AEE and 0xEAEE). 9. Plus resetting the device right a la s3. 10. Temporarily switched the bus type of the Mach8 to 8-bit in both MCA and ISA variants. --- src/include/86box/vid_8514a.h | 21 +- src/include/86box/vid_ati_mach8.h | 14 +- src/video/vid_8514a.c | 696 +++++---- src/video/vid_ati_mach8.c | 2381 +++++++++++++++++++---------- 4 files changed, 1939 insertions(+), 1173 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index bfde22d5e..153bface4 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -18,6 +18,12 @@ #ifndef VIDEO_8514A_H #define VIDEO_8514A_H +#define INT_VSY (1 << 0) +#define INT_GE_BSY (1 << 1) +#define INT_FIFO_OVR (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_MASK 0xf + typedef struct hwcursor8514_t { int ena; int x; @@ -61,6 +67,7 @@ typedef struct ibm8514_t { uint32_t vram_mask; uint32_t pallook[512]; uint32_t bios_addr; + uint32_t ma_latch; PALETTE vgapal; uint8_t hwcursor_oddeven; @@ -85,8 +92,8 @@ typedef struct ibm8514_t { uint16_t advfunc_cntl; uint16_t cur_y; uint16_t cur_x; - int16_t destx; - int16_t desty; + uint16_t destx; + uint16_t desty; int16_t desty_axstp; int16_t destx_distp; int16_t err_term; @@ -117,6 +124,8 @@ typedef struct ibm8514_t { int y1; int y2; int temp_cnt; + int16_t dx_ibm; + int16_t dy_ibm; int16_t cx; int16_t cx_back; int16_t cy; @@ -216,10 +225,9 @@ typedef struct ibm8514_t { uint16_t subsys_cntl; uint8_t subsys_stat; - atomic_int fifo_idx; - atomic_int ext_fifo_idx; atomic_int force_busy; atomic_int force_busy2; + atomic_int fifo_idx; int blitter_busy; uint64_t blitter_time; @@ -235,6 +243,11 @@ typedef struct ibm8514_t { PALETTE _8514pal; latch8514_t latch; + + void (*vblank_start)(void *priv); + void (*accel_out_fifo)(void *priv, uint16_t port, uint16_t val, int len); + void (*update_irqs)(void *priv); + } ibm8514_t; #endif /*VIDEO_8514A_H*/ diff --git a/src/include/86box/vid_ati_mach8.h b/src/include/86box/vid_ati_mach8.h index 849446def..4a5d3deb5 100644 --- a/src/include/86box/vid_ati_mach8.h +++ b/src/include/86box/vid_ati_mach8.h @@ -25,6 +25,7 @@ typedef struct mach_t { rom_t bios_rom; rom_t bios_rom2; mem_mapping_t mmio_linear_mapping; + mem_mapping_t banked_mapping; int mca_bus; int pci_bus; @@ -71,7 +72,12 @@ typedef struct mach_t { uint8_t bank_r; uint16_t shadow_set; uint16_t shadow_cntl; - int override_resolution; + uint8_t overscan_col_8; + uint8_t overscan_b_col_24; + uint8_t overscan_g_col_24; + uint8_t overscan_r_col_24; + uint16_t fifo_test_data[17]; + int resolution_crt; struct { uint8_t line_idx; @@ -79,9 +85,9 @@ typedef struct mach_t { uint8_t patt_idx; uint8_t patt_len; uint8_t pix_trans[2]; - uint8_t eeprom_control; uint8_t alu_bg_fn; uint8_t alu_fg_fn; + uint16_t eeprom_control; uint16_t clip_left; uint16_t clip_right; uint16_t clip_top; @@ -92,6 +98,7 @@ typedef struct mach_t { uint16_t src_x_end; uint16_t src_x_start; uint16_t src_x; + uint16_t r_src_x; uint16_t src_y; int16_t bres_count; uint16_t clock_sel; @@ -100,6 +107,8 @@ typedef struct mach_t { uint16_t dest_cmp_fn; uint16_t dp_config; uint16_t ext_ge_config; + uint16_t crt_offset_lo; + uint16_t crt_offset_hi; uint16_t ge_offset_lo; uint16_t ge_offset_hi; uint16_t linedraw_opt; @@ -159,6 +168,7 @@ typedef struct mach_t { } accel; atomic_int force_busy; + atomic_int fifo_test_idx; } mach_t; #endif /*VIDEO_ATI_MACH8_H*/ diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 765258237..efb05a307 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -15,6 +15,7 @@ * * Copyright 2022-2024 TheCollector1995. */ +#include #include #include #include @@ -32,7 +33,6 @@ #include <86box/mca.h> #include <86box/rom.h> #include <86box/plat.h> -#include <86box/thread.h> #include <86box/video.h> #include <86box/vid_8514a.h> #include <86box/vid_8514a_device.h> @@ -153,12 +153,15 @@ CLAMP(int16_t in, int16_t min, int16_t max) dest_dat = ~(src_dat & dest_dat); \ break; \ case 0x09: \ + case 0x11: \ dest_dat = ~src_dat | dest_dat; \ break; \ case 0x0a: \ + case 0x12: \ dest_dat = src_dat | ~dest_dat; \ break; \ case 0x0b: \ + case 0x13: \ dest_dat = src_dat | dest_dat; \ break; \ case 0x0c: \ @@ -176,56 +179,43 @@ CLAMP(int16_t in, int16_t min, int16_t max) case 0x10: \ dest_dat = MIN(src_dat, dest_dat); \ break; \ - case 0x11: \ - dest_dat = dest_dat - src_dat; \ - break; \ - case 0x12: \ - dest_dat = src_dat - dest_dat; \ - break; \ - case 0x13: \ - dest_dat = src_dat + dest_dat; \ - break; \ case 0x14: \ dest_dat = MAX(src_dat, dest_dat); \ break; \ case 0x15: \ - dest_dat = (dest_dat - src_dat) >> 1; \ + dest_dat = (src_dat | ~dest_dat) >> 1; \ break; \ case 0x16: \ - dest_dat = (src_dat - dest_dat) >> 1; \ + dest_dat = (~src_dat | dest_dat) >> 1; \ break; \ case 0x17: \ - dest_dat = (dest_dat + src_dat) >> 1; \ + dest_dat = (src_dat | dest_dat) >> 1; \ break; \ case 0x18: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ case 0x19: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ + dest_dat = MAX(0, ~src_dat | dest_dat); \ break; \ case 0x1a: \ - dest_dat = MAX(0, (src_dat - dest_dat)); \ + dest_dat = MAX(0, src_dat | ~dest_dat); \ break; \ case 0x1b: \ if (dev->bpp) \ - dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ + dest_dat = MIN(0xffff, src_dat | dest_dat); \ else \ - dest_dat = MIN(0xff, (dest_dat + src_dat)); \ + dest_dat = MIN(0xff, src_dat | dest_dat); \ break; \ case 0x1c: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ case 0x1d: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + dest_dat = MAX(0, ~src_dat | dest_dat) >> 1; \ break; \ case 0x1e: \ - dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ + dest_dat = MAX(0, src_dat | ~dest_dat) >> 1; \ break; \ case 0x1f: \ if (dev->bpp) \ - dest_dat = (0xffff < (src_dat + dest_dat)) ? 0xffff : ((src_dat + dest_dat) / 2); \ + dest_dat = (0xffff < (src_dat | dest_dat)) ? 0xffff : ((src_dat | dest_dat) >> 1); \ else \ - dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ + dest_dat = (0xff < (src_dat | dest_dat)) ? 0xff : ((src_dat | dest_dat) >> 1); \ break; \ } \ } @@ -233,10 +223,10 @@ CLAMP(int16_t in, int16_t min, int16_t max) #define WRITE(addr, dat) \ if (dev->bpp) { \ vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = changeframecount; \ + dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ } else { \ dev->vram[((addr)) & (dev->vram_mask)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; \ } int ibm8514_active = 0; @@ -246,7 +236,7 @@ ibm8514_cpu_src(svga_t *svga) { const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (!(dev->accel.cmd & 0x100)) + if (dev->accel.cmd_back) return 0; if (dev->accel.cmd & 1) @@ -260,7 +250,7 @@ ibm8514_cpu_dest(svga_t *svga) { const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (!(dev->accel.cmd & 0x100)) + if (dev->accel.cmd_back) return 0; if (dev->accel.cmd & 1) @@ -282,7 +272,7 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in int bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; int cmd = dev->accel.cmd >> 13; - if (dev->accel.cmd & 0x100) { + if (!dev->accel.cmd_back) { if (len == 2) { /*Bus size*/ if (dev->accel.cmd & 0x200) /*16-bit*/ @@ -344,27 +334,184 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port != 0x9ae8 && port != 0xe2e8) - ibm8514_log("Port OUT FIFO=%04x, val=%04x, len=%d.\n", port, val, len); - switch (port) { + case 0x2e8: + WRITE8(port, dev->htotal, val); + ibm8514_log("IBM 8514/A compatible: (0x%04x): htotal=0x%02x.\n", port, val); + svga_recalctimings(svga); + break; + + case 0x6e8: + /*In preparation to switch from VGA to 8514/A mode*/ + WRITE8(port, dev->hdisped, val); + dev->hdisp = (dev->hdisped + 1) << 3; + ibm8514_log("[%04X:%08X]: IBM 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); + svga_recalctimings(svga); + break; + + case 0x6e9: + WRITE8(port, dev->htotal, val); + ibm8514_log("IBM 8514/A compatible: (0x%04x): htotal=0x%02x.\n", port, val); + svga_recalctimings(svga); + break; + + case 0xae8: + WRITE8(port, dev->hsync_start, val); + pclog("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_start=%d.\n", port, val, (val + 1) << 3); + svga_recalctimings(svga); + break; + + case 0xee8: + WRITE8(port, dev->hsync_width, val); + pclog("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_width=%d, hsyncpol=%02x.\n", port, val & 0x1f, ((val & 0x1f) + 1) << 3, val & 0x20); + svga_recalctimings(svga); + break; + + case 0x12e8: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 2) { + dev->v_total_reg = val; + dev->v_total_reg &= 0x1fff; + dev->v_total = dev->v_total_reg + 1; + if (dev->interlace) + dev->v_total >>= 1; + + ibm8514_log("IBM 8514/A compatible: (0x%04x): vtotal=0x%02x.\n", port, val); + svga_recalctimings(svga); + } else { + WRITE8(port, dev->v_total_reg, val); + } + break; + case 0x12e9: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 1) { + WRITE8(port, dev->v_total_reg, val); + dev->v_total_reg &= 0x1fff; + dev->v_total = dev->v_total_reg + 1; + if (dev->interlace) + dev->v_total >>= 1; + + ibm8514_log("IBM 8514/A compatible: (0x%04x): vtotal=0x%02x.\n", port, val); + svga_recalctimings(svga); + } + break; + + case 0x16e8: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 2) { + dev->v_disp = val; + dev->v_disp &= 0x1fff; + dev->vdisp = (dev->v_disp + 1) >> 1; + ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp); + ibm8514_log("IBM 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); + svga_recalctimings(svga); + } else { + WRITE8(port, dev->v_disp, val); + } + break; + case 0x16e9: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 1) { + WRITE8(port, dev->v_disp, val); + dev->v_disp &= 0x1fff; + dev->vdisp = (dev->v_disp + 1) >> 1; + ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp); + ibm8514_log("IBM 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); + svga_recalctimings(svga); + } + break; + + case 0x1ae8: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 2) { + dev->v_sync_start = val; + dev->v_sync_start &= 0x1fff; + dev->v_syncstart = dev->v_sync_start + 1; + if (dev->interlace) + dev->v_syncstart >>= 1; + + ibm8514_log("IBM 8514/A compatible: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); + ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncstart=0x%02x.\n", port, val); + svga_recalctimings(svga); + } else { + WRITE8(port, dev->v_sync_start, val); + } + break; + case 0x1ae9: + /*In preparation to switch from VGA to 8514/A mode*/ + if (len == 1) { + WRITE8(port, dev->v_sync_start, val); + dev->v_sync_start &= 0x1fff; + dev->v_syncstart = dev->v_sync_start + 1; + if (dev->interlace) + dev->v_syncstart >>= 1; + + ibm8514_log("IBM 8514/A compatible: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); + ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncstart=0x%02x.\n", port, val); + svga_recalctimings(svga); + } + break; + + case 0x22e8: + dev->disp_cntl = val; + dev->interlace = !!(dev->disp_cntl & 0x10); + ibm8514_log("IBM 8514/A compatible: DISP_CNTL write %04x=%02x, interlace=%d.\n", port, dev->disp_cntl, dev->interlace); + svga_recalctimings(svga); + break; + + case 0x1ee8: + case 0x1ee9: + ibm8514_log("IBM 8514/A compatible: V_SYNC_WID write 1EE8 = %02x\n", val); + ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncwidth=0x%02x.\n", port, val); + svga_recalctimings(svga); + break; + + case 0x42e8: + ibm8514_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); + if (len == 2) { + dev->subsys_cntl = val; + dev->subsys_stat &= ~val; + if ((val & 0xc000) == 0x8000) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } + } else { + WRITE8(port, dev->subsys_cntl, val); + dev->subsys_stat &= ~val; + } + break; + case 0x42e9: + if (len == 1) { + WRITE8(port, dev->subsys_cntl, val); + if ((val & 0xc0) == 0x80) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } + } + break; + + case 0x4ae8: + WRITE8(port, dev->accel.advfunc_cntl, val); + dev->on = dev->accel.advfunc_cntl & 0x01; + ibm8514_log("[%04X:%08X]: IBM 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", CS, cpu_state.pc, port, dev->on, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + ibm8514_log("IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); + svga_recalctimings(svga); + break; + case 0x82e8: case 0xc2e8: - dev->fifo_idx++; if (len == 2) dev->accel.cur_y = val & 0x7ff; break; case 0x86e8: case 0xc6e8: - dev->fifo_idx++; if (len == 2) dev->accel.cur_x = val & 0x7ff; break; case 0x8ae8: case 0xcae8: - dev->fifo_idx++; if (len == 2) { dev->accel.desty = val & 0x7ff; dev->accel.desty_axstp = val & 0x3fff; @@ -375,7 +522,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x8ee8: case 0xcee8: - dev->fifo_idx++; if (len == 2) { dev->accel.destx = val & 0x7ff; dev->accel.destx_distp = val & 0x3fff; @@ -385,7 +531,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x92e8: - dev->fifo_idx++; if (len == 2) dev->test = val; fallthrough; @@ -400,7 +545,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x96e8: case 0xd6e8: - dev->fifo_idx++; if (len == 2) { dev->accel.maj_axis_pcnt = val & 0x7ff; dev->accel.maj_axis_pcnt_no_limit = val; @@ -409,7 +553,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x9ae8: case 0xdae8: - dev->fifo_idx++; dev->accel.ssv_state = 0; if (len == 2) { dev->data_available = 0; @@ -419,14 +562,13 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (dev->accel.cmd & 0x100) dev->accel.cmd_back = 0; - ibm8514_log("8514/A CMD=%04x, back=%d.\n", dev->accel.cmd, dev->accel.cmd_back); + ibm8514_log("8514/A CMD=%04x, back=%d, frgd color=%04x, frgdmix=%02x, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.cmd_back, dev->accel.frgd_color, dev->accel.frgd_mix, dev->accel.multifunc[0x0a]); ibm8514_accel_start(-1, 0, -1, 0, svga, len); } break; case 0x9ee8: case 0xdee8: - dev->fifo_idx++; dev->accel.ssv_state = 1; if (len == 2) { dev->accel.short_stroke = val; @@ -451,7 +593,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0xa2e8: case 0xe2e8: - dev->fifo_idx++; if (port == 0xe2e8) { if (len == 2) { if (dev->accel.cmd_back) @@ -470,7 +611,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0xa6e8: case 0xe6e8: - dev->fifo_idx++; if (port == 0xe6e8) { if (len == 2) { if (dev->accel.cmd_back) @@ -489,40 +629,34 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0xaae8: case 0xeae8: - dev->fifo_idx++; if (len == 2) dev->accel.wrt_mask = val; break; case 0xaee8: case 0xeee8: - dev->fifo_idx++; if (len == 2) dev->accel.rd_mask = val; break; case 0xb2e8: case 0xf2e8: - dev->fifo_idx++; if (len == 2) dev->accel.color_cmp = val; break; case 0xb6e8: case 0xf6e8: - dev->fifo_idx++; dev->accel.bkgd_mix = val & 0xff; break; case 0xbae8: case 0xfae8: - dev->fifo_idx++; dev->accel.frgd_mix = val & 0xff; break; case 0xbee8: case 0xfee8: - dev->fifo_idx++; if (len == 2) { dev->accel.multifunc_cntl = val; dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; @@ -631,115 +765,13 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) - ibm8514_accel_out_fifo(svga, port, val, len); - else { - switch (port) { - case 0x2e8: - case 0x6e9: - WRITE8(port, dev->htotal, val); - ibm8514_log("IBM 8514/A compatible: (0x%04x): htotal=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x6e8: - /*In preparation to switch from VGA to 8514/A mode*/ - dev->hdisped = val; - dev->hdisp = (dev->hdisped + 1) << 3; - ibm8514_log("[%04X:%08X]: IBM 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); - svga_recalctimings(svga); - break; - - case 0xae8: - dev->hsync_start = val; - ibm8514_log("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_start=%d.\n", port, val, (val + 1) << 3); - svga_recalctimings(svga); - break; - - case 0xee8: - dev->hsync_width = val; - ibm8514_log("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_width=%d, hsyncpol=%02x.\n", port, val & 0x1f, ((val & 0x1f) + 1) << 3, val & 0x20); - svga_recalctimings(svga); - break; - - case 0x12e8: - case 0x12e9: - /*In preparation to switch from VGA to 8514/A mode*/ - WRITE8(port, dev->v_total_reg, val); - dev->v_total_reg &= 0x1fff; - dev->v_total = dev->v_total_reg + 1; - if (dev->interlace) - dev->v_total >>= 1; - - ibm8514_log("IBM 8514/A compatible: (0x%04x): vtotal=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x16e8: - case 0x16e9: - /*In preparation to switch from VGA to 8514/A mode*/ - WRITE8(port, dev->v_disp, val); - dev->v_disp &= 0x1fff; - dev->vdisp = (dev->v_disp + 1) >> 1; - ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp); - ibm8514_log("IBM 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x1ae8: - case 0x1ae9: - /*In preparation to switch from VGA to 8514/A mode*/ - WRITE8(port, dev->v_sync_start, val); - dev->v_sync_start &= 0x1fff; - dev->v_syncstart = dev->v_sync_start + 1; - if (dev->interlace) - dev->v_syncstart >>= 1; - - ibm8514_log("IBM 8514/A compatible: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); - ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncstart=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x1ee8: - case 0x1ee9: - ibm8514_log("IBM 8514/A compatible: V_SYNC_WID write 1EE8 = %02x\n", val); - ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncwidth=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x22e8: - dev->disp_cntl = val; - dev->interlace = !!(dev->disp_cntl & 0x10); - ibm8514_log("IBM 8514/A compatible: DISP_CNTL write %04x=%02x, interlace=%d.\n", port, dev->disp_cntl, dev->interlace); - svga_recalctimings(svga); - break; - - case 0x42e8: - ibm8514_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); - dev->subsys_cntl = (dev->subsys_cntl & 0xff00) | val; - dev->subsys_stat &= ~val; - break; - case 0x42e9: - dev->subsys_cntl = (dev->subsys_cntl & 0xff) | (val << 8); - if ((val & 0xc0) == 0x80) { - dev->fifo_idx = 0; - dev->force_busy = 0; - dev->force_busy2 = 0; - } - break; - - case 0x4ae8: - WRITE8(port, dev->accel.advfunc_cntl, val); - dev->on = dev->accel.advfunc_cntl & 0x01; - ibm8514_log("[%04X:%08X]: IBM 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", CS, cpu_state.pc, port, dev->on, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); - ibm8514_log("IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); - svga_recalctimings(svga); - break; - - default: - break; - } + if (dev->accel.cmd_back) { + dev->fifo_idx++; + if (dev->fifo_idx > 8) + dev->fifo_idx = 8; } + + ibm8514_accel_out_fifo(svga, port, val, len); } static void @@ -790,28 +822,21 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) case 0x9ae8: case 0xdae8: - if ((dev->fifo_idx >= 1) && (dev->fifo_idx <= 8)) { - temp |= (1 << (dev->fifo_idx - 1)); - switch (dev->accel.cmd >> 13) { - case 2: - case 3: - case 4: - case 6: - if (dev->accel.sy < 0) - dev->fifo_idx = 0; - break; - default: - if (!dev->accel.sy) - dev->fifo_idx = 0; - break; - } - } if (len == 2) { + if (dev->fifo_idx <= 8) { + for (int i = 1; i <= dev->fifo_idx; i++) + temp |= (1 << (7 - (i - 1))); + } else + temp = 0x00ff; + + if (dev->fifo_idx > 0) + dev->fifo_idx--; + if (dev->force_busy) - temp |= 0x200; /*Hardware busy*/ + temp |= 0x0200; /*Hardware busy*/ dev->force_busy = 0; if (dev->data_available) { - temp |= 0x100; /*Read Data available*/ + temp |= 0x0100; /*Read Data available*/ dev->data_available = 0; } } @@ -819,8 +844,11 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) case 0x9ae9: case 0xdae9: if (len == 1) { + dev->fifo_idx = 0; + if (dev->force_busy2) temp |= 0x02; /*Hardware busy*/ + dev->force_busy2 = 0; if (dev->data_available2) { temp |= 0x01; /*Read Data available*/ @@ -868,7 +896,7 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) switch (port) { case 0x2e8: - if (dev->vc == dev->dispend) + if (dev->vc == dev->v_syncstart) temp |= 0x02; ibm8514_log("Read: Display Status1=%02x.\n", temp); @@ -896,36 +924,35 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) case 0x42e8: case 0x42e9: - if ((dev->subsys_cntl & 0x01) && !(dev->subsys_stat & 0x01) && (dev->vc == dev->dispend)) - temp |= 0x01; + if (!(port & 1)) { + if ((dev->subsys_cntl & INT_VSY) && !(dev->subsys_stat & INT_VSY) && (dev->vc == dev->dispend)) + temp |= INT_VSY; - if (cmd == 6) { - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && - (dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r_ibm) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b_ibm)) - temp |= 0x02; - } else { - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && - (dev->accel.cx >= clip_l) && - (dev->accel.cx <= clip_r_ibm) && - (dev->accel.cy >= clip_t) && - (dev->accel.cy <= clip_b_ibm)) - temp |= 0x02; - } + if (cmd == 6) { + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && + (dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r_ibm) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b_ibm)) + temp |= INT_GE_BSY; + } else { + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && + (dev->accel.cx >= clip_l) && + (dev->accel.cx <= clip_r_ibm) && + (dev->accel.cy >= clip_t) && + (dev->accel.cy <= clip_b_ibm)) + temp |= INT_GE_BSY; + } - if (!dev->fifo_idx) { - if (!dev->force_busy && !dev->force_busy2) - temp |= 0x08; - } - - if (port & 1) { - temp = dev->vram_512k_8514 ? 0x00 : 0x80; - temp |= (dev->subsys_cntl >> 8); - } else { + if (dev->accel.cmd_back) { + dev->force_busy = 0; + dev->force_busy2 = 0; + dev->data_available = 0; + dev->data_available2 = 0; + temp |= INT_FIFO_EMP; + } temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); temp |= 0x20; } @@ -1024,7 +1051,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat rd_mask_polygon &= 0xff; } - if (dev->accel.cmd & 0x100) { + if (!dev->accel.cmd_back) { dev->force_busy = 1; dev->force_busy2 = 1; } @@ -1129,8 +1156,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat old_mix_dat = mix_dat; - if (cmd == 5 || cmd == 1 || (cmd == 2 && (dev->accel.multifunc[0x0a] & 0x06))) - ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06); + if (cmd != 0) + ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw); /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on @@ -1146,7 +1173,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1197,6 +1224,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!dev->accel.ssv_len) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1242,7 +1270,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1293,6 +1321,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!dev->accel.ssv_len) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1378,7 +1407,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -1468,6 +1497,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!dev->accel.sy) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; if (!cpu_input) { dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; @@ -1537,7 +1567,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; if (ibm8514_cpu_dest(svga)) { READ((dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); } else @@ -1588,6 +1618,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!dev->accel.sy) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1629,7 +1660,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -1691,6 +1722,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!dev->accel.sy) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; if (!cpu_input) { dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; @@ -1828,7 +1860,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1970,8 +2002,10 @@ skip_vector_rect_write: dev->accel.sy--; dev->accel.x_count = 0; - if (dev->accel.sy < 0) + if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + } return; } } @@ -1986,7 +2020,7 @@ skip_vector_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { mix_dat = mix_mask; /* Mix data = forced to foreground register. */ } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { @@ -2129,8 +2163,10 @@ skip_nibble_rect_write: dev->accel.sy--; dev->accel.x_count = 0; - if (dev->accel.sy < 0) + if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + } return; } } @@ -2148,7 +2184,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2215,8 +2251,10 @@ skip_nibble_rect_write: dev->accel.sy--; - if (dev->accel.sy < 0) + if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + } return; } } @@ -2231,7 +2269,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2301,6 +2339,7 @@ skip_nibble_rect_write: dev->accel.cur_y = dev->accel.cy; } dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -2313,7 +2352,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2412,6 +2451,7 @@ skip_nibble_rect_write: if (dev->accel.sy < 0) { ibm8514_log(".\n"); dev->accel.cmd_back = 1; + dev->fifo_idx = 0; dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; return; @@ -2419,13 +2459,13 @@ skip_nibble_rect_write: } } } else { - ibm8514_log("Polygon Draw Type=%02x, CX=%d, CY=%d, SY=%d, CL=%d, CR=%d.\n", dev->accel.multifunc[0x0a] & 0x06, dev->accel.cx, dev->accel.cy, dev->accel.sy, clip_l, clip_r); + ibm8514_log("Polygon Draw Type=%02x, CX=%d, CY=%d, SY=%d, CL=%d, CR=%d, frgdmix=%d, bkgdmix=%d, cmpmode=%02x, pitch=%d.\n", dev->accel.multifunc[0x0a] & 0x06, dev->accel.cx, dev->accel.cy, dev->accel.sy, clip_l, clip_r, frgd_mix, bkgd_mix, compare_mode, dev->pitch); while (count-- && (dev->accel.sy >= 0)) { if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2501,6 +2541,7 @@ skip_nibble_rect_write: dev->accel.cur_y = dev->accel.cy; } dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -2548,7 +2589,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2603,6 +2644,7 @@ skip_nibble_rect_write: if (!dev->accel.sy) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -2656,7 +2698,7 @@ skip_nibble_rect_write: (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -2707,6 +2749,7 @@ skip_nibble_rect_write: if (!dev->accel.sy) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -2753,13 +2796,8 @@ skip_nibble_rect_write: { dev->accel.x_count = 0; - dev->accel.dx = dev->accel.destx; - if (dev->accel.destx >= 0x600) - dev->accel.dx |= ~0x5ff; - - dev->accel.dy = dev->accel.desty; - if (dev->accel.desty >= 0x600) - dev->accel.dy |= ~0x5ff; + dev->accel.dx_ibm = dev->accel.destx; + dev->accel.dy_ibm = dev->accel.desty; dev->accel.cx = dev->accel.cur_x; if (dev->accel.cur_x >= 0x600) @@ -2774,13 +2812,13 @@ skip_nibble_rect_write: if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } dev->accel.fill_state = 0; @@ -2805,17 +2843,16 @@ skip_nibble_rect_write: dev->data_available = 1; dev->data_available2 = 1; return; /*Wait for data from CPU*/ - } + } else + ibm8514_log("BitBLT normal: Parameters: DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, dstheight=%d, clipl=%d, clipr=%d, clipt=%d, clipb=%d.\n", dev->accel.dx_ibm, dev->accel.dy_ibm, dev->accel.cx, dev->accel.cy, dev->accel.sx, dev->accel.sy, clip_l, clip_r, clip_t, clip_b); } - ibm8514_log("BitBLT: full=%04x, odd=%d, c(%d,%d), d(%d,%d), xcount=%d, and3=%d, len(%d,%d), CURX=%d, Width=%d, pixcntl=%d, mix_dat=%08x, count=%d, cpu_data=%08x, cpu_input=%d.\n", dev->accel.cmd, dev->accel.input, dev->accel.cx, dev->accel.cy, dev->accel.dx, dev->accel.dy, dev->accel.x_count, and3, dev->accel.sx, dev->accel.sy, dev->accel.cur_x, dev->accel.maj_axis_pcnt, pixcntl, mix_dat, count, cpu_dat, cpu_input); if (cpu_input) { while (count-- && (dev->accel.sy >= 0)) { - if ((dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + if ((dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b)) { if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -2879,7 +2916,7 @@ skip_nibble_rect_write: } } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -2895,20 +2932,20 @@ skip_nibble_rect_write: goto skip_nibble_bitblt_write; dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); } else { MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); } } } if (dev->accel.cmd & 0x20) { - dev->accel.dx++; + dev->accel.dx_ibm++; dev->accel.cx++; } else { - dev->accel.dx--; + dev->accel.dx_ibm--; dev->accel.cx--; } @@ -2935,37 +2972,39 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx -= (dev->accel.sx + 1); + dev->accel.dx_ibm -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx += (dev->accel.sx + 1); + dev->accel.dx_ibm += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy++; + dev->accel.dy_ibm++; dev->accel.cy++; } else { - dev->accel.dy--; + dev->accel.dy_ibm--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } dev->accel.sy--; dev->accel.x_count = 0; - if (dev->accel.sy < 0) + if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + } return; } } @@ -2979,11 +3018,10 @@ skip_nibble_bitblt_write: mix_dat >>= 8; dev->accel.temp_cnt = 8; } - if ((dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + if ((dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b)) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3002,7 +3040,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3014,7 +3052,7 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); } } @@ -3025,10 +3063,10 @@ skip_nibble_bitblt_write: } if (dev->accel.cmd & 0x20) { - dev->accel.dx++; + dev->accel.dx_ibm++; dev->accel.cx++; } else { - dev->accel.dx--; + dev->accel.dx_ibm--; dev->accel.cx--; } @@ -3037,36 +3075,38 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx -= (dev->accel.sx + 1); + dev->accel.dx_ibm -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx += (dev->accel.sx + 1); + dev->accel.dx_ibm += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy++; + dev->accel.dy_ibm++; dev->accel.cy++; } else { - dev->accel.dy--; + dev->accel.dy_ibm--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } dev->accel.sy--; - if (dev->accel.sy < 0) + if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + } return; } } @@ -3077,11 +3117,10 @@ skip_nibble_bitblt_write: dev->accel.temp_cnt = 8; mix_dat = old_mix_dat; } - if ((dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + if ((dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b)) { switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3100,7 +3139,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3112,7 +3151,7 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & 0x01, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); } } @@ -3120,10 +3159,10 @@ skip_nibble_bitblt_write: mix_dat >>= 1; if (dev->accel.cmd & 0x20) { - dev->accel.dx++; + dev->accel.dx_ibm++; dev->accel.cx++; } else { - dev->accel.dx--; + dev->accel.dx_ibm--; dev->accel.cx--; } @@ -3132,37 +3171,38 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx -= (dev->accel.sx + 1); + dev->accel.dx_ibm -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx += (dev->accel.sx + 1); + dev->accel.dx_ibm += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy++; + dev->accel.dy_ibm++; dev->accel.cy++; } else { - dev->accel.dy--; + dev->accel.dy_ibm--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } dev->accel.sy--; if (dev->accel.sy < 0) { - dev->accel.destx = dev->accel.dx; - dev->accel.desty = dev->accel.dy; + dev->accel.destx = dev->accel.dx_ibm; + dev->accel.desty = dev->accel.dy_ibm; dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -3174,15 +3214,13 @@ skip_nibble_bitblt_write: int64_t dx; cx = (int64_t) dev->accel.cx; - dx = (int64_t) dev->accel.dx; + dx = (int64_t) dev->accel.dx_ibm; while (1) { if ((dx >= (((int64_t)clip_l) * 3)) && (dx <= (((uint64_t)clip_r) * 3)) && - (dev->accel.dy >= (clip_t << 1)) && - (dev->accel.dy <= (clip_b << 1))) { - dev->subsys_stat |= 0x02; - + (dev->accel.dy_ibm >= (clip_t << 1)) && + (dev->accel.dy_ibm <= (clip_b << 1))) { READ(dev->accel.src + cx, src_dat); READ(dev->accel.dest + dx, dest_dat); dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); @@ -3195,16 +3233,16 @@ skip_nibble_bitblt_write: dev->accel.sx--; if (dev->accel.sx < 0) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } } else { while (count-- && dev->accel.sy >= 0) { - if ((dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + if ((dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b)) { if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -3238,7 +3276,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3250,12 +3288,14 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (dev->accel.cmd & 0x04) { if (dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); } } else { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx_ibm, dev->accel.dy_ibm, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); } } } @@ -3264,10 +3304,10 @@ skip_nibble_bitblt_write: mix_dat |= 1; if (dev->accel.cmd & 0x20) { - dev->accel.dx++; + dev->accel.dx_ibm++; dev->accel.cx++; } else { - dev->accel.dx--; + dev->accel.dx_ibm--; dev->accel.cx--; } @@ -3277,37 +3317,38 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx -= (dev->accel.sx + 1); + dev->accel.dx_ibm -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx += (dev->accel.sx + 1); + dev->accel.dx_ibm += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy++; + dev->accel.dy_ibm++; dev->accel.cy++; } else { - dev->accel.dy--; + dev->accel.dy_ibm--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); } dev->accel.sy--; if (dev->accel.sy < 0) { - dev->accel.destx = dev->accel.dx; - dev->accel.desty = dev->accel.dy; + dev->accel.destx = dev->accel.dx_ibm; + dev->accel.desty = dev->accel.dy_ibm; dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -3334,7 +3375,7 @@ ibm8514_render_blank(svga_t *svga) dev->firstline_draw = dev->displine; dev->lastline_draw = dev->displine; - uint32_t *line_ptr = &svga->monitor->target_buffer->line[dev->displine + svga->y_add][svga->x_add]; + uint32_t *line_ptr = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; uint32_t line_width = (uint32_t)(dev->h_disp) * sizeof(uint32_t); if (dev->h_disp > 0) @@ -3628,7 +3669,7 @@ ibm8514_poll(void *priv) int wx; int wy; - ibm8514_log("IBM 8514/A poll=%x.\n", dev->on); + ibm8514_log("IBM 8514/A poll=%x offtime=%" PRIu64 ", ontime=%" PRIu64 ".\n", dev->on, dev->dispofftime, dev->dispontime); if (dev->on) { ibm8514_log("ON!\n"); if (!dev->linepos) { @@ -3713,7 +3754,7 @@ ibm8514_poll(void *priv) dev->vc &= 0xfff; if (dev->vc == dev->dispend) { - dev->subsys_stat |= 0x01; + dev->vblank_start(svga); ibm8514_log("VBLANK irq.\n"); dev->dispon = 0; @@ -3751,16 +3792,16 @@ ibm8514_poll(void *priv) svga->vslines = 0; if (dev->interlace && dev->oddeven) - dev->ma = dev->maback = (dev->rowoffset << 1); + dev->ma = dev->maback = dev->ma_latch + (dev->rowoffset << 1); else - dev->ma = dev->maback = 0; + dev->ma = dev->maback = dev->ma_latch; dev->ma = (dev->ma << 2); dev->maback = (dev->maback << 2); } if (dev->vc == dev->v_total) { dev->vc = 0; - dev->sc = 0; + dev->sc = (svga->crtc[0x8] & 0x1f); dev->dispon = 1; dev->displine = (dev->interlace && dev->oddeven) ? 1 : 0; @@ -3876,6 +3917,15 @@ ibm8514_mca_reset(void *priv) svga_set_poll(svga); } +static void +ibm8514_vblank_start(void *priv) +{ + svga_t *svga = (svga_t *) priv; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + dev->subsys_stat |= INT_VSY; +} + static void * ibm8514_init(const device_t *info) { @@ -3938,6 +3988,7 @@ ibm8514_init(const device_t *info) fallthrough; default: + dev->extensions = 0; ibm8514_io_set(svga); if (dev->type & DEVICE_MCA) { @@ -3945,8 +3996,11 @@ ibm8514_init(const device_t *info) dev->pos_regs[1] = 0xef; mca_add(ibm8514_mca_read, ibm8514_mca_write, ibm8514_mca_feedb, ibm8514_mca_reset, svga); } + + dev->vblank_start = ibm8514_vblank_start; break; } + return svga; } @@ -3981,7 +4035,7 @@ ibm8514_force_redraw(void *priv) { svga_t *svga = (svga_t *) priv; - svga->fullchange = changeframecount; + svga->fullchange = svga->monitor->mon_changeframecount; } // clang-format off diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index d35257ea7..9f1bb99d6 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -70,6 +70,10 @@ static uint16_t ati8514_accel_inw(uint16_t port, void *priv); static uint32_t ati8514_accel_inl(uint16_t port, void *priv); static void mach32_updatemapping(mach_t *mach, svga_t *svga); +static __inline void mach32_writew_linear(uint32_t addr, uint16_t val, mach_t *mach); +static __inline void mach32_write_common(uint32_t addr, uint8_t val, int linear, mach_t *mach, svga_t *svga); + +static mach_t *reset_state = NULL; #ifdef ENABLE_MACH_LOG int mach_do_log = ENABLE_MACH_LOG; @@ -121,14 +125,14 @@ mach_log(const char *fmt, ...) } #define READ_PIXTRANS_WORD(cx, n) \ - if ((cmd == 0) || (cmd == 1) || (cmd == 5) || (mach->accel.cmd_type == -1)) { \ + if ((cmd == 0) || (cmd == 1) || (cmd == 5) || ((mach->accel.cmd_type == -1) && (cmd != 2))) { \ if (dev->bpp) \ temp = vram_w[((dev->accel.cy * dev->pitch) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ else { \ temp = dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n)) & dev->vram_mask]; \ temp |= (dev->vram[((dev->accel.cy * dev->pitch) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ } \ - } else if ((mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ + } else if (((cmd == 2) && (mach->accel.cmd_type == -1)) || (mach->accel.cmd_type == 2) || (mach->accel.cmd_type == 5)) { \ if (dev->bpp) \ temp = vram_w[((dev->accel.dest) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ else { \ @@ -184,12 +188,15 @@ mach_log(const char *fmt, ...) dest_dat = ~(src_dat & dest_dat); \ break; \ case 0x09: \ + case 0x11: \ dest_dat = ~src_dat | dest_dat; \ break; \ case 0x0a: \ + case 0x12: \ dest_dat = src_dat | ~dest_dat; \ break; \ case 0x0b: \ + case 0x13: \ dest_dat = src_dat | dest_dat; \ break; \ case 0x0c: \ @@ -207,56 +214,43 @@ mach_log(const char *fmt, ...) case 0x10: \ dest_dat = MIN(src_dat, dest_dat); \ break; \ - case 0x11: \ - dest_dat = dest_dat - src_dat; \ - break; \ - case 0x12: \ - dest_dat = src_dat - dest_dat; \ - break; \ - case 0x13: \ - dest_dat = src_dat + dest_dat; \ - break; \ case 0x14: \ dest_dat = MAX(src_dat, dest_dat); \ break; \ case 0x15: \ - dest_dat = (dest_dat - src_dat) / 2; \ + dest_dat = (src_dat | ~dest_dat) >> 1; \ break; \ case 0x16: \ - dest_dat = (src_dat - dest_dat) / 2; \ + dest_dat = (~src_dat | dest_dat) >> 1; \ break; \ case 0x17: \ - dest_dat = (dest_dat + src_dat) / 2; \ + dest_dat = (src_dat | dest_dat) >> 1; \ break; \ case 0x18: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ - break; \ case 0x19: \ - dest_dat = MAX(0, (dest_dat - src_dat)); \ + dest_dat = MAX(0, ~src_dat | dest_dat); \ break; \ case 0x1a: \ - dest_dat = MAX(0, (src_dat - dest_dat)); \ + dest_dat = MAX(0, src_dat | ~dest_dat); \ break; \ case 0x1b: \ if (dev->bpp) \ - dest_dat = MIN(0xffff, (dest_dat + src_dat)); \ + dest_dat = MIN(0xffff, src_dat | dest_dat); \ else \ - dest_dat = MIN(0xff, (dest_dat + src_dat)); \ + dest_dat = MIN(0xff, src_dat | dest_dat); \ break; \ case 0x1c: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ - break; \ case 0x1d: \ - dest_dat = MAX(0, (dest_dat - src_dat)) / 2; \ + dest_dat = MAX(0, ~src_dat | dest_dat) >> 1; \ break; \ case 0x1e: \ - dest_dat = MAX(0, (src_dat - dest_dat)) / 2; \ + dest_dat = MAX(0, src_dat | ~dest_dat) >> 1; \ break; \ case 0x1f: \ if (dev->bpp) \ - dest_dat = (0xffff < (src_dat + dest_dat)) ? 0xffff : ((src_dat + dest_dat) / 2); \ + dest_dat = (0xffff < (src_dat | dest_dat)) ? 0xffff : ((src_dat | dest_dat) >> 1); \ else \ - dest_dat = (0xff < (src_dat + dest_dat)) ? 0xff : ((src_dat + dest_dat) / 2); \ + dest_dat = (0xff < (src_dat | dest_dat)) ? 0xff : ((src_dat | dest_dat) >> 1); \ break; \ } \ } @@ -265,10 +259,10 @@ mach_log(const char *fmt, ...) #define WRITE(addr, dat) \ if (dev->bpp) { \ vram_w[((addr)) & (dev->vram_mask >> 1)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = changeframecount; \ + dev->changedvram[(((addr)) & (dev->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ } else { \ dev->vram[((addr)) & (dev->vram_mask)] = dat; \ - dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = changeframecount; \ + dev->changedvram[(((addr)) & (dev->vram_mask)) >> 12] = svga->monitor->mon_changeframecount; \ } static int @@ -297,6 +291,8 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 uint16_t rd_mask = dev->accel.rd_mask; uint16_t wrt_mask = dev->accel.wrt_mask; uint16_t dest_cmp_clr = dev->accel.color_cmp; + uint16_t frgd_color = dev->accel.frgd_color; + uint16_t bkgd_color = dev->accel.bkgd_color; int frgd_sel; int bkgd_sel; int mono_src; @@ -313,9 +309,16 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 int16_t clip_b = dev->accel.clip_bottom; int16_t clip_r = dev->accel.clip_right; + if (clip_l < 0) + clip_l = 0; + if (clip_t < 0) + clip_t = 0; + if (!dev->bpp) { rd_mask &= 0xff; dest_cmp_clr &= 0xff; + frgd_color &= 0xff; + bkgd_color &= 0xff; } compare_mode = (mach->accel.dest_cmp_fn >> 3) & 7; @@ -341,6 +344,8 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i.\n", cmd_type, frgd_sel, bkgd_sel, mono_src); + switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ if (!cpu_input) { @@ -438,13 +443,12 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -547,9 +551,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mono_src == 1) && !count) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -662,13 +668,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -772,9 +778,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mono_src == 1) && !count) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -997,6 +1005,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dy_end == mach->accel.dy_start) { mach_log("No DEST.\n"); dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } @@ -1004,6 +1013,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.sx_end == mach->accel.sx_start) { mach_log("No SRC.\n"); dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -1015,6 +1025,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.sy == mach->accel.height) { mach_log("No Blit on DPCONFIG=3251.\n"); dev->accel.cmd_back = 1; + dev->fifo_idx = 0; return; } } @@ -1069,7 +1080,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; if (mach->accel.dp_config & 0x02) { READ(dev->accel.src + dev->accel.cx, poly_src); poly_src = ((poly_src & rd_mask) == rd_mask); @@ -1080,10 +1091,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -1232,6 +1243,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.sy >= mach->accel.height) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; if ((mono_src == 2) || (mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) return; if ((mono_src == 1) && (frgd_sel == 5) && (dev->accel_bpp == 24)) @@ -1311,14 +1323,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -1391,6 +1403,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (!count) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1445,7 +1458,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; if (mach->accel.linedraw_opt & 0x02) { if (dev->bpp) { @@ -1459,10 +1472,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -1561,6 +1574,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.sx >= mach->accel.width) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1604,14 +1618,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -1685,6 +1699,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (!count) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1739,14 +1754,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cx <= clip_r) && (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -1843,6 +1858,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.sx >= mach->accel.width) { dev->accel.cmd_back = 1; + dev->fifo_idx = 0; break; } @@ -1873,8 +1889,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.poly_fill = 0; mach->accel.line_array[(cmd_type == 4) ? 4 : 0] = dev->accel.cx; mach->accel.line_array[(cmd_type == 4) ? 5 : 1] = dev->accel.cy; - dev->accel.cur_x = mach->accel.line_array[(cmd_type == 4) ? 4 : 0]; - dev->accel.cur_y = mach->accel.line_array[(cmd_type == 4) ? 5 : 1]; + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + mach_log("Done: %i, %i\n", dev->accel.cur_x, dev->accel.cur_y); break; case 5: /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ @@ -1920,12 +1937,16 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dest_y_end >= 0x600) mach->accel.dy_end |= ~0x5ff; - if (mach->accel.dy_end > mach->accel.dy_start) + if (mach->accel.dy_end > mach->accel.dy_start) { + dev->accel.sy = (mach->accel.dy_end - mach->accel.dy_start); mach->accel.stepy = 1; - else if (mach->accel.dy_end < mach->accel.dy_start) + } else if (mach->accel.dy_end < mach->accel.dy_start) { + dev->accel.sy = (mach->accel.dy_start - mach->accel.dy_end); mach->accel.stepy = -1; - else + } else { mach->accel.stepy = 0; + dev->accel.sy = 0; + } if (dev->bpp) dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); @@ -1969,9 +1990,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); - mach_log("ScanToX=%04x, MonoSRC=%d, FrgdSel=%d, BkgdSel=%d, Pitch=%d, C(%d,%d), SRCWidth=%d, WH(%d,%d), colorpattidx=%d, pattlen=%d.\n", - mach->accel.dp_config, mono_src, frgd_sel, bkgd_sel, dev->ext_pitch, dev->accel.cx, dev->accel.cy, mach->accel.src_width, - mach->accel.width, mach->accel.height, mach->accel.color_pattern_idx, mach->accel.patt_len); + mach_log("ScanToX: Parameters=%04x: DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, srcwidth=%d, height=%d, clipl=%d, clipr=%d, clipt=%d, clipb=%d, frmix=%02x.\n", mach->accel.dp_config, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.src_width, dev->accel.sy, clip_l, clip_r, clip_t, clip_b, dev->accel.frgd_mix & 0x1f); if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { if (mach_pixel_write(mach)) { @@ -2035,13 +2054,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { - dev->subsys_stat |= 0x02; + dev->subsys_stat |= INT_GE_BSY; switch (mix ? frgd_sel : bkgd_sel) { case 0: - src_dat = dev->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = dev->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -2104,6 +2123,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config & 0x10) { WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + mach_log("ScanToX: DXS=%d, DYS=%d, dest data=%02x, lineidx=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, mach->accel.line_idx); } } @@ -2148,7 +2168,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.line_array[0] = dev->accel.dx; mach->accel.line_array[4] = dev->accel.dx; } + if (dev->accel.sy >= 0) + dev->accel.sy--; + dev->accel.cmd_back = 1; + dev->fifo_idx = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; return; } } @@ -2278,16 +2305,14 @@ mach_out(uint16_t addr, uint8_t val, void *priv) mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2); mach->bank_w |= ((mach->regs[0xae] & 3) << 4); } - if (dev->on) - mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); + mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); } else { /* Single bank mode */ mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); if ((dev->local & 0xff) >= 0x02) mach->bank_w |= ((mach->regs[0xae] & 3) << 4); mach->bank_r = mach->bank_w; - if (dev->on) - mach_log("Single B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); + mach_log("Single B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); } svga->read_bank = mach->bank_r << 16; svga->write_bank = mach->bank_w << 16; @@ -2420,7 +2445,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga->fullchange = 3; svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { - svga->fullchange = changeframecount; + svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); } } @@ -2490,6 +2515,7 @@ mach_in(uint16_t addr, void *priv) temp = mach->regs[mach->index]; break; } + mach_log("ATI VGA read reg=%02x, val=%02x.\n", mach->index, temp); break; case 0x2ea: @@ -2637,6 +2663,40 @@ ati_render_32bpp(svga_t *svga) } } +static void +mach_set_resolution(mach_t *mach, svga_t *svga) +{ + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + dev->hdisp = (dev->hdisped + 1) << 3; + dev->h_total = dev->htotal + 1; + + dev->vdisp = (dev->v_disp + 1) >> 1; + if ((dev->vdisp == 478) || (dev->vdisp == 598) || (dev->vdisp == 766) || (dev->vdisp == 1022)) + dev->vdisp += 2; + + dev->v_total = dev->v_total_reg + 1; + if (dev->interlace) + dev->v_total >>= 1; + + dev->v_syncstart = dev->v_sync_start + 1; + if (dev->interlace) + dev->v_syncstart >>= 1; + + mach_log("Shadow set ATI=%x, shadow set 8514/A=%x, resolution h=%d, v=%d.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + if ((mach->accel.clock_sel & 0x01) || dev->bpp || ((mach->accel.ext_ge_config & 0x30) == 0x30)) /*ATI and 15bpp+ mode*/ + svga_recalctimings(svga); + else { /*8514/A mode*/ + if (mach->resolution_crt == 0x02) { + if (!(dev->accel.advfunc_cntl & 0x04)) { + dev->hdisp = 640; + dev->vdisp = 480; + svga_recalctimings(svga); + } + } + } +} + void ati8514_recalctimings(svga_t *svga) { @@ -2648,7 +2708,6 @@ ati8514_recalctimings(svga_t *svga) mach_log("8514/A ON.\n"); dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; - dev->h_total = dev->htotal + 1; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; @@ -2656,23 +2715,8 @@ ati8514_recalctimings(svga_t *svga) mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); - if (mach->accel.clock_sel & 0x01) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } else { - if (dev->accel.advfunc_cntl & 0x04) { - if (dev->hdisp == 640) { - dev->h_disp = 1024; - dev->dispend = 768; - } else { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } - } else { - dev->h_disp = 640; - dev->dispend = 480; - } - } + dev->h_disp = dev->hdisp; + dev->dispend = dev->vdisp; if (dev->accel.advfunc_cntl & 0x04) svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; @@ -2695,6 +2739,7 @@ ati8514_recalctimings(svga_t *svga) } } dev->accel_bpp = 8; + mach->resolution_crt = 0; svga->render8514 = ibm8514_render_8bpp; } } @@ -2753,9 +2798,9 @@ mach_recalctimings(svga_t *svga) mach_log("ON?=%d, override=%d.\n", dev->on, svga->override); if (dev->on) { mach_log("8514/A ON, extpitch=%d, devma=%x, vgamalatch=%x.\n", dev->ext_pitch, dev->ma, svga->ma_latch); + dev->ma_latch = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2; dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; - dev->h_total = dev->htotal + 1; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; @@ -2763,42 +2808,12 @@ mach_recalctimings(svga_t *svga) mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x, interlace=%x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0xfe, dev->interlace); - if ((dev->local & 0xff) >= 0x02) { - if (dev->bpp || ((mach->accel.ext_ge_config & 0x30) == 0x30) || (mach->accel.clock_sel & 0x01)) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } else { - if (dev->interlace) { /*Interlaced displays are only for 800x600 and up.*/ - if (dev->accel.advfunc_cntl & 0x04) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } else { - dev->h_disp = 640; - dev->dispend = 480; - } - } else { - if (((mach->shadow_set & 0x03) == 0x00) && ((dev->hdisp2 == 640) || (dev->hdisp2 == 1280)) && (dev->hdisp != 800)) { - dev->h_disp = dev->hdisp2; - dev->dispend = dev->vdisp2; - } else { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } - } - } - } else { - if (mach->accel.clock_sel & 0x01) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } else { - if (dev->accel.advfunc_cntl & 0x04) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; - } else { - dev->h_disp = 640; - dev->dispend = 480; - } - } + + dev->h_disp = dev->hdisp; + dev->dispend = dev->vdisp; + if (dev->dispend == 959) { /*FIXME: vertical resolution mess on EEPROM tests on Mach8*/ + dev->dispend >>= 1; + dev->dispend++; } svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen); @@ -2809,21 +2824,29 @@ mach_recalctimings(svga_t *svga) dev->dispend >>= 1; if ((dev->local & 0xff) >= 0x02) { - mach_log("HDISP=%d, mask=%02x.\n", dev->h_disp, dev->dac_mask); + mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", + dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, + mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace, svga->hdisp); if ((mach->accel.ext_ge_config & 0x800) || (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800))) { if ((mach->accel.ext_ge_config & 0x30) == 0x20) { - if ((mach->accel.ext_ge_config & 0xc0) == 0x40) + if ((mach->accel.ext_ge_config & 0xc0) == 0x40) { dev->accel_bpp = 16; - else + svga->overscan_color = video_16to32[((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24) & 0xffff]; + } else { dev->accel_bpp = 15; + svga->overscan_color = video_15to32[((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24) & 0xffff]; + } } else if ((mach->accel.ext_ge_config & 0x30) == 0x30) { if (mach->accel.ext_ge_config & 0x200) dev->accel_bpp = 32; else dev->accel_bpp = 24; - } else if ((mach->accel.ext_ge_config & 0x30) == 0x10) + + svga->overscan_color = ((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24); + } else if ((mach->accel.ext_ge_config & 0x30) == 0x10) { dev->accel_bpp = 8; - else { + svga->overscan_color = dev->pallook[mach->overscan_col_8]; + } else { if (dev->vram_512k_8514) { if (dev->h_disp == 640) { dev->ext_pitch = 640; @@ -2834,12 +2857,14 @@ mach_recalctimings(svga_t *svga) } } dev->accel_bpp = 8; + svga->overscan_color = dev->pallook[mach->overscan_col_8]; } - svga->render8514 = ibm8514_render_blank; mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, dev->accel_bpp, mach->shadow_set & 3, svga->hdisp); + + mach->resolution_crt = 0; switch (dev->accel_bpp) { case 8: svga->render8514 = ibm8514_render_8bpp; @@ -2864,10 +2889,9 @@ mach_recalctimings(svga_t *svga) } } } else { - svga->render8514 = ibm8514_render_blank; - mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", - dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, - mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); + mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", + dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, + mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace, svga->hdisp); if (dev->vram_512k_8514) { if (dev->h_disp == 640) { dev->ext_pitch = 640; @@ -2878,6 +2902,7 @@ mach_recalctimings(svga_t *svga) } } dev->accel_bpp = 8; + mach->resolution_crt = 0; svga->render8514 = ibm8514_render_8bpp; } } else { @@ -2934,22 +2959,248 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("[%04X:%08X]: Port FIFO OUT=%04x, val=%04x, len=%d.\n", CS, cpu_state.pc, port, val, len); switch (port) { + case 0x2e8: + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) + dev->htotal = val; + + mach_set_resolution(mach, svga); + } + break; + + case 0xae8: + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) { + WRITE8(port, dev->hsync_start, val); + } + svga_recalctimings(svga); + } + break; + + case 0xee8: + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) { + WRITE8(port, dev->hsync_width, val); + } + svga_recalctimings(svga); + } + break; + + case 0x1ee8: + case 0x1ee9: + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) /*For 8514/A mode, take the shadow sets into account.*/ + svga_recalctimings(svga); + break; + + case 0x6e8: + if (len == 2) { + mach_log("HDISP and HTOTAL=%04x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x08)) { + WRITE8(port, dev->hdisped, val); + } + + if (!(mach->shadow_cntl & 0x04)) + dev->htotal = (val >> 8) & 0xff; + + mach_set_resolution(mach, svga); + } + } else { + mach_log("HDISP and HTOTAL=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x08)) { + WRITE8(port, dev->hdisped, val); + } + mach_set_resolution(mach, svga); + } else if (!(mach->accel.clock_sel & 0x01) && ((mach->shadow_set & 0x03) == 0x00) && dev->on) { /*Still write the parameter even after going to 8514/A mode if needed*/ + if (!(mach->shadow_cntl & 0x08)) { + WRITE8(port, dev->hdisped, val); + } + if (mach->resolution_crt == 0x00) + mach->resolution_crt = 0x02; + + mach_set_resolution(mach, svga); + } + } + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x, shadowcntl=%02x, shadowset=%02x.\n", + CS, cpu_state.pc, port, val, mach->shadow_cntl & 0x08, mach->shadow_set & 0x03); + break; + + case 0x6e9: + if (len == 1) { + mach_log("HDISP and HTOTAL+1=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) { + dev->htotal = val; + } + mach_set_resolution(mach, svga); + } + } + break; + + case 0x12e8: + if (len == 2) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x10)) { + dev->v_total_reg = val; + dev->v_total_reg &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + } else { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x10)) { + WRITE8(port, dev->v_total_reg, val); + dev->v_total_reg &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + } + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); + break; + + case 0x12e9: + if (len == 1) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + WRITE8(port, dev->v_total_reg, val); + dev->v_total_reg &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); + } + break; + + case 0x16e8: + if (len == 2) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + dev->v_disp = val; + dev->v_disp &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); + mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); + } else { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + WRITE8(port, dev->v_disp, val); + dev->v_disp &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + } + break; + case 0x16e9: + if (len == 1) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + WRITE8(port, dev->v_disp, val); + dev->v_disp &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); + mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); + } + break; + + case 0x1ae8: + if (len == 2) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + dev->v_sync_start = val; + dev->v_sync_start &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); + mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); + } else { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + WRITE8(port, dev->v_sync_start, val); + dev->v_sync_start &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + } + break; + case 0x1ae9: + if (len == 1) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + WRITE8(port, dev->v_sync_start, val); + dev->v_sync_start &= 0x1fff; + } + mach_set_resolution(mach, svga); + } + mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); + mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); + } + break; + + case 0x22e8: + if ((mach->shadow_cntl & 0x03) == 0x00) { + dev->disp_cntl = val; + dev->interlace = !!(dev->disp_cntl & 0x10); + } + mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n", + port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace); + svga_recalctimings(svga); + break; + + + case 0x42e8: + case 0x42e9: + mach_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); + if (len == 2) + dev->subsys_cntl = val; + else { + WRITE8(port, dev->subsys_cntl, val); + } + dev->subsys_stat &= ~val; + if ((dev->subsys_cntl & 0xc000) == 0x8000) { + mach->force_busy = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + } + break; + + case 0x46e8: + case 0x46e9: + mach_log("0x%04x write: VGA subsystem enable add-on=%02x.\n", port, val); + break; + + case 0x4ae8: + dev->accel.advfunc_cntl = val; + dev->on = dev->accel.advfunc_cntl & 0x01; + dev->vendor_mode = 0; + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", + CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + + if ((dev->local & 0xff) < 0x02) { + dev->ext_crt_pitch = 128; + mach_set_resolution(mach, svga); + } else { + mach_set_resolution(mach, svga); + mach32_updatemapping(mach, svga); + } + mach_log("Vendor IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); + break; + case 0x82e8: case 0x86e8: case 0xc2e8: case 0xc6e8: - dev->ext_fifo_idx++; - ibm8514_accel_out_fifo(svga, port, val, len); - break; case 0xf6ee: - dev->ext_fifo_idx++; - if (len == 2) - dev->accel.cur_y = val & 0x7ff; + ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x8ae8: case 0xcae8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { mach_log("SRCY=%d.\n", val & 0x07ff); @@ -2959,7 +3210,6 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x8ee8: case 0xcee8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { mach_log("SRCX=%d.\n", val & 0x07ff); @@ -2969,13 +3219,11 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x92e8: case 0xd2e8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x96e8: case 0xd6e8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) mach->accel.test = val & 0x1fff; @@ -2983,34 +3231,42 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x9ae8: case 0xdae8: - dev->ext_fifo_idx++; mach->accel.cmd_type = -1; ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x9ee8: case 0xdee8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); break; case 0xa2e8: case 0xe2e8: - dev->ext_fifo_idx++; - dev->fifo_idx++; if (port == 0xe2e8) { if (len == 2) { if (dev->accel.cmd_back) { - dev->accel.bkgd_color = val; - mach_log("CMDBack BKGDCOLOR, sy=%d, height=%d, val=%04x.\n", dev->accel.sy, mach->accel.height, val); + if (mach->accel.cmd_type == 5) { + if (dev->accel.sy >= 0) { + if (mach_pixel_read(mach)) + break; + + mach_accel_out_pixtrans(svga, mach, dev, val); + } else + dev->accel.bkgd_color = val; + } else + dev->accel.bkgd_color = val; + + mach_log("%04X: CMDBack BKGDCOLOR, sy=%d, height=%d, val=%04x.\n", port, dev->accel.sy, mach->accel.height, val); } else { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach_accel_out_pixtrans(svga, mach, dev, val); } else { if (ibm8514_cpu_dest(svga)) break; + ibm8514_accel_out_pixtrans(svga, port, val, len); } } @@ -3018,31 +3274,43 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach->accel.pix_trans[1] = val; } } } else { if (len == 2) dev->accel.bkgd_color = val; + + mach_log("%04X: Background Color=%04x.\n", port, val); } break; case 0xa6e8: case 0xe6e8: - dev->ext_fifo_idx++; - dev->fifo_idx++; if (port == 0xe6e8) { if (len == 2) { - if (dev->accel.cmd_back) - dev->accel.frgd_color = val; - else { + if (dev->accel.cmd_back) { + if (mach->accel.cmd_type == 5) { + if (dev->accel.sy >= 0) { + if (mach_pixel_read(mach)) + break; + + mach_accel_out_pixtrans(svga, mach, dev, val); + } else + dev->accel.frgd_color = val; + } else + dev->accel.frgd_color = val; + } else { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach_accel_out_pixtrans(svga, mach, dev, val); } else { if (ibm8514_cpu_dest(svga)) break; + ibm8514_accel_out_pixtrans(svga, port, val, len); } } @@ -3050,6 +3318,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach->accel.pix_trans[1] = val; } } @@ -3061,13 +3330,12 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xe2e9: case 0xe6e9: - dev->ext_fifo_idx++; - dev->fifo_idx++; mach_log("Write PORT=%04x, 8514/A=%x, val=%04x, len=%d.\n", port, dev->accel.cmd_back, val, len); if (len == 1) { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach->accel.pix_trans[0] = val; frgd_sel = (mach->accel.dp_config >> 13) & 7; bkgd_sel = (mach->accel.dp_config >> 7) & 3; @@ -3114,13 +3382,11 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xf2e8: case 0xf6e8: case 0xfae8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); break; case 0xbee8: case 0xfee8: - dev->ext_fifo_idx++; ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { if ((dev->accel.multifunc_cntl >> 12) == 5) { @@ -3131,485 +3397,95 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; /*ATI Mach8/32 specific registers*/ - case 0x82ee: - dev->ext_fifo_idx++; - mach->accel.patt_data_idx_reg = val & 0x1f; - mach->accel.patt_data_idx = mach->accel.patt_data_idx_reg; - - if (mach->accel.patt_data_idx_reg < 0x10) - mach->accel.color_pattern_idx = mach->accel.patt_idx; - else - mach->accel.color_pattern_idx = 0; - - mach_log("Write Port 82ee: Pattern Data Index=%d.\n", val & 0x1f); - break; - - case 0x8eee: - dev->ext_fifo_idx++; - if (len == 2) { - if (mach->accel.patt_data_idx_reg < 0x10) { - mach->accel.color_pattern[mach->accel.patt_data_idx] = val & 0xff; - mach->accel.color_pattern[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; - mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); - } else { - mach->accel.mono_pattern_normal[mach->accel.patt_data_idx - 0x10] = val & 0xff; - mach->accel.mono_pattern_normal[(mach->accel.patt_data_idx + 1) - 0x10] = (val >> 8) & 0xff; - mach_log("Write Port 8eee: Mono Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx - 0x10, val); - } - mach->accel.patt_data_idx += 2; - } - break; - - case 0x96ee: - dev->ext_fifo_idx++; - if (len == 2) { - mach->accel.bres_count = val & 0x7ff; - mach_log("BresenhamDraw=%04x.\n", mach->accel.dp_config); - dev->data_available = 0; - dev->data_available2 = 0; - mach->accel.cmd_type = 1; - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; - - dev->accel.cmd_back = 1; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) - dev->accel.cmd_back = 0; - - mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); - } - break; - - case 0x9aee: - dev->ext_fifo_idx++; - mach->accel.line_idx = val & 0x07; - break; - - case 0xa2ee: - dev->ext_fifo_idx++; - mach_log("Line OPT=%04x.\n", val); - if (len == 2) { - mach->accel.linedraw_opt = val; - mach->accel.bbottom = dev->accel.clip_bottom; - mach->accel.btop = dev->accel.clip_top; - mach->accel.bleft = dev->accel.clip_left; - mach->accel.bright = dev->accel.clip_right; - if (mach->accel.linedraw_opt & 0x100) { - mach->accel.bbottom = 2047; - mach->accel.btop = 0; - mach->accel.bleft = 0; - mach->accel.bright = 2047; - } - } - break; - - case 0xa6ee: - dev->ext_fifo_idx++; - if (len == 2) - mach->accel.dest_x_start = val & 0x7ff; - break; - - case 0xaaee: - dev->ext_fifo_idx++; - if (len == 2) - mach->accel.dest_x_end = val & 0x7ff; - break; - - case 0xaeee: - dev->ext_fifo_idx++; - if (len == 2) { - mach->accel.dest_y_end = val & 0x7ff; - if ((val + 1) == 0x10000) { - mach_log("Dest_Y_end overflow val=%04x, DPCONFIG=%04x\n", val, mach->accel.dp_config); - mach->accel.dest_y_end = 0; - } - dev->data_available = 0; - dev->data_available2 = 0; - mach_log("BitBLT=%04x.\n", mach->accel.dp_config); - mach_log(".\n"); - mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ - - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; - - dev->accel.cmd_back = 1; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) - dev->accel.cmd_back = 0; - - mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); - } - break; - - case 0xb2ee: - dev->ext_fifo_idx++; - if (len == 2) - mach->accel.src_x_start = val & 0x7ff; - break; - - case 0xb6ee: - dev->ext_fifo_idx++; - dev->accel.bkgd_mix = val & 0xff; - break; - - case 0xbaee: - dev->ext_fifo_idx++; - dev->accel.frgd_mix = val & 0xff; - break; - - case 0xbeee: - dev->ext_fifo_idx++; - if (len == 2) - mach->accel.src_x_end = val & 0x7ff; - break; - - case 0xc2ee: - dev->ext_fifo_idx++; - mach->accel.src_y_dir = val & 1; - break; - - case 0xc6ee: - dev->ext_fifo_idx++; - if (len == 2) { - mach->accel.cmd_type = 0; - mach_log("TODO: Short Stroke.\n"); - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; - - dev->accel.cmd_back = 1; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) - dev->accel.cmd_back = 0; - } - break; - - case 0xcaee: - dev->ext_fifo_idx++; - if (len == 2) { - mach->accel.scan_to_x = (val & 0x7ff); - if ((val + 1) == 0x10000) { - mach_log("Scan_to_X overflow val = %04x\n", val); - mach->accel.scan_to_x = 0; - } - dev->data_available = 0; - dev->data_available2 = 0; - mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ - mach_log("ScanToX=%04x.\n", mach->accel.dp_config); - mach_log(".\n"); - - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; - - dev->accel.cmd_back = 1; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) - dev->accel.cmd_back = 0; - - mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); - } - break; - - case 0xceee: - dev->ext_fifo_idx++; - mach_log("CEEE write val = %04x.\n", val); - if (len == 2) { - dev->data_available = 0; - dev->data_available2 = 0; - mach->accel.dp_config = val; - } - break; - - case 0xd2ee: - dev->ext_fifo_idx++; - mach->accel.patt_len = val & 0x1f; - mach_log("Write Port d2ee: Pattern Length=%d, val=%04x.\n", val & 0x1f, val); - mach->accel.mono_pattern_enable = !!(val & 0x80); - if (len == 2) { - mach->accel.block_write_mono_pattern_enable = !!(val & 0x8000); - mach->accel.patt_len_reg = val; - } - break; - - case 0xd6ee: - dev->ext_fifo_idx++; - mach->accel.patt_idx = val & 0x1f; - mach_log("Write Port d6ee: Pattern Index=%d.\n", val & 0x1f); - break; - - case 0xdaee: - dev->ext_fifo_idx++; - if (len == 2) { - dev->accel.multifunc[2] = val & 0x7ff; - dev->accel.clip_left = dev->accel.multifunc[2]; - if (val & 0x800) - dev->accel.clip_left |= ~0x7ff; - } - mach_log("DAEE (extclipl) write val=%d, left=%d.\n", val, dev->accel.clip_left); - break; - - case 0xdeee: - dev->ext_fifo_idx++; - if (len == 2) { - dev->accel.multifunc[1] = val & 0x7ff; - dev->accel.clip_top = dev->accel.multifunc[1]; - if (val & 0x800) { - dev->accel.clip_top |= ~0x7ff; - } - } - mach_log("DEEE (extclipt) write val = %d\n", val); - break; - - case 0xe2ee: - dev->ext_fifo_idx++; - if (len == 2) { - dev->accel.multifunc[4] = val & 0x7ff; - dev->accel.clip_right = dev->accel.multifunc[4]; - if (val & 0x800) - dev->accel.clip_right |= ~0x7ff; - } - mach_log("E2EE (extclipr) write val = %d\n", val); - break; - - case 0xe6ee: - dev->ext_fifo_idx++; - if (len == 2) { - dev->accel.multifunc[3] = val & 0x7ff; - dev->accel.clip_bottom = dev->accel.multifunc[3]; - if (val & 0x800) - dev->accel.clip_bottom |= ~0x7ff; - } - mach_log("E6EE (extclipb) write val = %d\n", val); - break; - - case 0xeeee: - dev->ext_fifo_idx++; - if (len == 2) - mach->accel.dest_cmp_fn = val; - break; - - case 0xf2ee: - dev->ext_fifo_idx++; - mach_log("F2EE.\n"); - if (len == 2) - mach->accel.dst_clr_cmp_mask = val; - break; - - case 0xfeee: - dev->ext_fifo_idx++; - mach_log("LineDraw=%04x.\n", mach->accel.dp_config); - if (len == 2) { - mach->accel.line_array[mach->accel.line_idx] = val; - dev->accel.cur_x = mach->accel.line_array[(mach->accel.line_idx == 4) ? 4 : 0]; - dev->accel.cur_y = mach->accel.line_array[(mach->accel.line_idx == 5) ? 5 : 1]; - mach->accel.cx_end_line = mach->accel.line_array[2]; - mach->accel.cy_end_line = mach->accel.line_array[3]; - if ((mach->accel.line_idx == 3) || (mach->accel.line_idx == 5)) { - mach->accel.cmd_type = (mach->accel.line_idx == 5) ? 4 : 3; - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; - - dev->accel.cmd_back = 1; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) - dev->accel.cmd_back = 0; - - mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); - mach->accel.line_idx = (mach->accel.line_idx == 5) ? 4 : 2; - break; - } - mach->accel.line_idx++; - } - break; - - default: - break; - } -} - -static void -mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8514_t *dev) -{ - if (port == 0x42e8 || port == 0x42e9) - mach_log("[%04X:%08X]: Port CALL OUT=%04x, val=%02x.\n", CS, cpu_state.pc, port, val); - - switch (port) { - case 0x2e8: - case 0x6e9: - case 0xae8: - case 0xee8: - case 0x1ee8: - case 0x1ee9: - case 0x42e8: - ibm8514_accel_out(port, val, svga, 2); - break; - case 0x42e9: - ibm8514_accel_out(port, val, svga, 2); - if ((val & 0xc0) == 0x80) { - dev->ext_fifo_idx = 0; - mach->force_busy = 0; - } - break; - - case 0x6e8: - /*In preparation to switch from VGA to 8514/A mode*/ - if (!(mach->shadow_cntl & 0x08)) { - if ((mach->shadow_set & 0x03) || (mach->accel.clock_sel & 0x01)) { - dev->hdisped = val; - dev->hdisp = (val + 1) << 3; - } else if (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01)) - dev->hdisp2 = (val + 1) << 3; - } - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x, shadowcntl=%02x, shadowset=%02x.\n", - CS, cpu_state.pc, port, val, mach->shadow_cntl & 0x08, mach->shadow_set & 0x03); - svga_recalctimings(svga); - break; - - case 0x12e8: - case 0x12e9: - /*In preparation to switch from VGA to 8514/A mode*/ - if (!(mach->shadow_cntl & 0x10)) { - if ((mach->shadow_set & 0x03) || (mach->accel.clock_sel & 0x01) || - (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01))) { - WRITE8(port, dev->v_total_reg, val); - dev->v_total_reg &= 0x1fff; - dev->v_total = dev->v_total_reg + 1; - if (dev->interlace) - dev->v_total >>= 1; - } - } - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); - svga_recalctimings(svga); - break; - - case 0x16e8: - case 0x16e9: - /*In preparation to switch from VGA to 8514/A mode*/ - if (!(mach->shadow_cntl & 0x20)) { - if ((mach->shadow_set & 0x03) || (mach->accel.clock_sel & 0x01)) { - WRITE8(port, dev->v_disp, val); - dev->v_disp &= 0x1fff; - dev->vdisp = (dev->v_disp + 1) >> 1; - if ((dev->vdisp == 478) || (dev->vdisp == 598) || (dev->vdisp == 766) || (dev->vdisp == 1022)) - dev->vdisp += 2; - } else if (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01)) { - WRITE8(port, dev->v_disp2, val); - dev->v_disp2 &= 0x1fff; - dev->vdisp2 = (dev->v_disp2 + 1) >> 1; - if ((dev->vdisp2 == 478) || (dev->vdisp2 == 598) || (dev->vdisp2 == 766) || (dev->vdisp2 == 1022)) - dev->vdisp2 += 2; - } - } - mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); - mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x1ae8: - case 0x1ae9: - /*In preparation to switch from VGA to 8514/A mode*/ - if (!(mach->shadow_cntl & 0x10)) { - if ((mach->shadow_set & 0x03) || (mach->accel.clock_sel & 0x01) || - (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01))) { - WRITE8(port, dev->v_sync_start, val); - dev->v_sync_start &= 0x1fff; - dev->v_syncstart = dev->v_sync_start + 1; - if (dev->interlace) - dev->v_syncstart >>= 1; - } - } - mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); - mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); - svga_recalctimings(svga); - break; - - case 0x22e8: - if (!(mach->shadow_cntl & 0x03)) { - if ((mach->shadow_set & 0x03) || (mach->accel.clock_sel & 0x01) || - (((mach->shadow_set & 0x03) == 0x00) && !(mach->accel.clock_sel & 0x01))) { - dev->disp_cntl = val; - dev->interlace = !!(dev->disp_cntl & 0x10); - } - } - mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n", - port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace); - svga_recalctimings(svga); - break; - - case 0x46e8: - case 0x46e9: - mach_log("0x%04x write: VGA subsystem enable add-on=%02x.\n", port, val); - break; - - case 0x4ae8: - dev->accel.advfunc_cntl = val; - dev->on = dev->accel.advfunc_cntl & 0x01; - dev->vendor_mode = 0; - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", - CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); - - if ((dev->local & 0xff) < 0x02) { - dev->ext_crt_pitch = 128; - svga_recalctimings(svga); - } else { - svga_recalctimings(svga); - mach32_updatemapping(mach, svga); - } - mach_log("Vendor IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); - break; - - /*ATI Mach8/32 specific registers*/ case 0x2ee: - mach_log("2EE write val = %02x.\n", val); - break; case 0x2ef: - mach_log("2EF write val = %02x.\n", val); + if (len == 2) { + mach->overscan_col_8 = val & 0xff; + mach->overscan_b_col_24 = (val >> 8) & 0xff; + } else { + if (port & 1) + mach->overscan_b_col_24 = val; + else + mach->overscan_col_8 = val; + } + svga_recalctimings(svga); break; - case 0x6ee: - mach_log("6EE write val = %02x.\n", val); - break; case 0x6ef: - mach_log("6EF write val = %02x.\n", val); + if (len == 2) { + mach->overscan_g_col_24 = val & 0xff; + mach->overscan_r_col_24 = (val >> 8) & 0xff; + } else { + if (port & 1) + mach->overscan_r_col_24 = val; + else + mach->overscan_g_col_24 = val; + } + svga_recalctimings(svga); break; case 0xaee: case 0xaef: - WRITE8(port, mach->cursor_offset_lo_reg, val); + if (len == 2) + mach->cursor_offset_lo_reg = val; + else { + WRITE8(port, mach->cursor_offset_lo_reg, val); + } mach->cursor_offset_lo = mach->cursor_offset_lo_reg; dev->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16)) << 2); break; case 0xeee: case 0xeef: - WRITE8(port, mach->cursor_offset_hi_reg, val); + if (len == 2) + mach->cursor_offset_hi_reg = val; + else { + WRITE8(port, mach->cursor_offset_hi_reg, val); + } + dev->hwcursor.ena = !!(mach->cursor_offset_hi_reg & 0x8000); mach->cursor_offset_hi = mach->cursor_offset_hi_reg & 0x0f; dev->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16)) << 2); - dev->hwcursor.ena = !!(mach->cursor_offset_hi_reg & 0x8000); mach_log("HWCursorEnabled=%x.\n", dev->hwcursor.ena); break; case 0x12ee: case 0x12ef: - WRITE8(port, mach->cursor_x, val); + if (len == 2) + mach->cursor_x = val; + else { + WRITE8(port, mach->cursor_x, val); + } dev->hwcursor.x = mach->cursor_x & 0x7ff; break; case 0x16ee: case 0x16ef: - WRITE8(port, mach->cursor_y, val); + if (len == 2) + mach->cursor_y = val; + else { + WRITE8(port, mach->cursor_y, val); + } dev->hwcursor.y = mach->cursor_y & 0xfff; break; case 0x1aee: case 0x1aef: - WRITE8(port, mach->cursor_col_b, val); + if (len == 2) + mach->cursor_col_b = val; + else { + WRITE8(port, mach->cursor_col_b, val); + } mach->cursor_col_0 = mach->cursor_col_b & 0xff; mach->cursor_col_1 = (mach->cursor_col_b >> 8) & 0xff; break; case 0x1eee: case 0x1eef: - WRITE8(port, mach->cursor_vh_offset, val); + if (len == 2) + mach->cursor_vh_offset = val; + else { + WRITE8(port, mach->cursor_vh_offset, val); + } dev->hwcursor.xoff = mach->cursor_vh_offset & 0x3f; dev->hwcursor.yoff = (mach->cursor_vh_offset >> 8) & 0x3f; break; @@ -3624,7 +3500,11 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 case 0x26ee: case 0x26ef: - WRITE8(port, mach->accel.crt_pitch, val); + if (len == 2) + mach->accel.crt_pitch = val; + else { + WRITE8(port, mach->accel.crt_pitch, val); + } dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; if (dev->accel_bpp > 8) { if (dev->accel_bpp == 24) @@ -3642,54 +3522,98 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 if ((dev->local & 0xff) >= 0x01) mach32_updatemapping(mach, svga); - mach_log("ATI 8514/A: (0x%04x) val=0x%02x, extended 8514/A mode=%02x.\n", port, val, mach->regs[0xb0] & 0x20); + mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode=%02x.\n", port, val, dev->ext_crt_pitch, len, mach->regs[0xb0] & 0x20); + break; + + case 0x2aee: + case 0x2aef: + if (len == 2) { + mach->accel.crt_offset_lo = val; + } else { + WRITE8(port, mach->accel.crt_offset_lo, val); + } + svga_recalctimings(svga); + break; + + case 0x2eee: + case 0x2eef: + mach->accel.crt_offset_hi = val & 0x0f; + svga_recalctimings(svga); break; case 0x32ee: case 0x32ef: - WRITE8(port, mach->local_cntl, val); + if (len == 2) + mach->local_cntl = val; + else { + WRITE8(port, mach->local_cntl, val); + } if ((dev->local & 0xff) >= 0x01) mach32_updatemapping(mach, svga); break; case 0x36ee: case 0x36ef: - mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); - if ((dev->local & 0xff) >= 0x02) { - WRITE8(port, mach->misc, val); - mach->misc &= 0xfff0; + if (len == 2) { + if ((dev->local & 0xff) >= 0x02) + mach->misc = val; + } else { + if ((dev->local & 0xff) >= 0x02) + WRITE8(port, mach->misc, val); } + mach->misc &= 0xfff0; break; case 0x3aee: case 0x3aef: - WRITE8(port, mach->cursor_col_0_rg, val); + if (len == 2) + mach->cursor_col_0_rg = val; + else { + WRITE8(port, mach->cursor_col_0_rg, val); + } mach->ext_cur_col_0_g = mach->cursor_col_0_rg & 0xff; mach->ext_cur_col_0_r = (mach->cursor_col_0_rg >> 8) & 0xff; break; case 0x3eee: case 0x3eef: - WRITE8(port, mach->cursor_col_1_rg, val); + if (len == 2) + mach->cursor_col_1_rg = val; + else { + WRITE8(port, mach->cursor_col_1_rg, val); + } mach->ext_cur_col_1_g = mach->cursor_col_1_rg & 0xff; mach->ext_cur_col_1_r = (mach->cursor_col_1_rg >> 8) & 0xff; break; case 0x42ee: case 0x42ef: - mach_log("ATI 8514/A: (0x%04x) val=%04x.\n", port, val); - WRITE8(port, mach->accel.test2, val); + if (len == 2) + mach->accel.test2 = val; + else { + WRITE8(port, mach->accel.test2, val); + } + mach_log("ATI 8514/A: (0x%04x) MEM_BNDRY val=%04x, memory part=%06x, gdcreg6=%02x.\n", port, val, (mach->accel.test2 & 0x0f) << 18, svga->gdcreg[6] & 0x0c); + mach32_updatemapping(mach, svga); break; case 0x46ee: case 0x46ef: - WRITE8(port, mach->shadow_cntl, val); + if (len == 2) + mach->shadow_cntl = val; + else { + WRITE8(port, mach->shadow_cntl, val); + } mach_log("ATI 8514/A: (0x%04x) val=%02x.\n", port, val); break; case 0x4aee: case 0x4aef: - WRITE8(port, mach->accel.clock_sel, val); + if (len == 2) + mach->accel.clock_sel = val; + else { + WRITE8(port, mach->accel.clock_sel, val); + } dev->on = mach->accel.clock_sel & 0x01; dev->vendor_mode = 1; mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d.\n", @@ -3703,31 +3627,50 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 case 0x52ee: case 0x52ef: - mach_log("ATI 8514/A: (0x%04x) val=%04x.\n", port, val); - WRITE8(port, mach->accel.scratch0, val); + mach_log("ATI 8514/A: (0x%04x) ScratchPad0 val=%04x.\n", port, val); + if (len == 2) + mach->accel.scratch0 = val; + else { + WRITE8(port, mach->accel.scratch0, val); + } break; case 0x56ee: case 0x56ef: - mach_log("ATI 8514/A: (0x%04x) val=%04x.\n", port, val); - WRITE8(port, mach->accel.scratch1, val); + mach_log("ATI 8514/A: (0x%04x) ScratchPad1 val=%04x.\n", port, val); + if (len == 2) + mach->accel.scratch1 = val; + else { + WRITE8(port, mach->accel.scratch1, val); + } break; case 0x5aee: case 0x5aef: - WRITE8(port, mach->shadow_set, val); + if (len == 2) + mach->shadow_set = val; + else { + WRITE8(port, mach->shadow_set, val); + } mach_log("ATI 8514/A: (0x%04x) val=0x%02x.\n", port, val); if ((mach->shadow_set & 0x03) == 0x00) mach_log("Primary CRT register set.\n"); - else if ((mach->shadow_set & 0x03) == 0x01) + else if ((mach->shadow_set & 0x03) == 0x01) { mach_log("CRT Shadow Set 1: 640x480.\n"); - else if ((mach->shadow_set & 0x03) == 0x02) + mach->resolution_crt = 0x01; + } else if ((mach->shadow_set & 0x03) == 0x02) { mach_log("CRT Shadow Set 2: 1024x768.\n"); + mach->resolution_crt = 0x02; + } break; case 0x5eee: case 0x5eef: - WRITE8(port, mach->memory_aperture, val); + if (len == 2) + mach->memory_aperture = val; + else { + WRITE8(port, mach->memory_aperture, val); + } mach_log("Memory Aperture = %04x.\n", mach->memory_aperture); if (!mach->pci_bus) mach->linear_base = (mach->memory_aperture & 0xff00) << 12; @@ -3736,36 +3679,44 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 mach32_updatemapping(mach, svga); break; - case 0x62ee: - mach_log("62EE write val = %04x, len = %d.\n", val, len); - break; - - case 0x66ee: - mach_log("66EE write val = %04x, len = %d.\n", val, len); - break; - case 0x6aee: case 0x6aef: - WRITE8(port, mach->accel.max_waitstates, val); + if (len == 2) + mach->accel.max_waitstates = val; + else { + WRITE8(port, mach->accel.max_waitstates, val); + } break; case 0x6eee: case 0x6eef: - WRITE8(port, mach->accel.ge_offset_lo, val); + if (len == 2) + mach->accel.ge_offset_lo = val; + else { + WRITE8(port, mach->accel.ge_offset_lo, val); + } svga_recalctimings(svga); mach_log("ATI 8514/A: (0x%04x) val=0x%02x, geoffset=%04x.\n", port, val, dev->accel.ge_offset); break; case 0x72ee: case 0x72ef: - WRITE8(port, mach->accel.ge_offset_hi, val); + if (len == 2) + mach->accel.ge_offset_hi = val; + else { + WRITE8(port, mach->accel.ge_offset_hi, val); + } svga_recalctimings(svga); mach_log("ATI 8514/A: (0x%04x) val=0x%02x, geoffset=%04x.\n", port, val, dev->accel.ge_offset); break; case 0x76ee: case 0x76ef: - WRITE8(port, mach->accel.ge_pitch, val); + if (len == 2) + mach->accel.ge_pitch = val; + else { + WRITE8(port, mach->accel.ge_pitch, val); + } dev->ext_pitch = ((mach->accel.ge_pitch & 0xff) << 3); mach_log("ATI 8514/A: (0x%04x) val=0x%02x, extpitch=%d.\n", port, val, dev->ext_pitch); svga_recalctimings(svga); @@ -3773,7 +3724,11 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 case 0x7aee: case 0x7aef: - WRITE8(port, mach->accel.ext_ge_config, val); + if (len == 2) + mach->accel.ext_ge_config = val; + else { + WRITE8(port, mach->accel.ext_ge_config, val); + } if ((dev->local & 0xff) >= 0x02) { if (mach->accel.crt_pitch & 0xff) dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; @@ -3802,24 +3757,295 @@ mach_accel_out_call(uint16_t port, uint8_t val, mach_t *mach, svga_t *svga, ibm8 mach_log("ATI 8514/A: (0x%04x) val=%02x.\n", port, val); svga_recalctimings(svga); } else - ati_eeprom_write(&mach->eeprom, !!(mach->accel.ext_ge_config & 0x4000), !!(mach->accel.ext_ge_config & 0x2000), !!(mach->accel.ext_ge_config & 0x1000)); + ati_eeprom_write(&mach->eeprom, !!(mach->accel.ext_ge_config & 0x04), !!(mach->accel.ext_ge_config & 0x02), !!(mach->accel.ext_ge_config & 0x01)); + break; + + case 0x7eee: + case 0x7eef: + if (len == 2) + mach->accel.eeprom_control = val; + else { + WRITE8(port, mach->accel.eeprom_control, val); + } + mach_log("%04X write val=%04x, actual=%04x, len=%d.\n", port, mach->accel.eeprom_control, val, len); + break; + + case 0x82ee: + mach->accel.patt_data_idx_reg = val & 0x1f; + mach->accel.patt_data_idx = mach->accel.patt_data_idx_reg; + + if (mach->accel.patt_data_idx_reg < 0x10) + mach->accel.color_pattern_idx = mach->accel.patt_idx; + else + mach->accel.color_pattern_idx = 0; + + mach_log("Write Port 82ee: Pattern Data Index=%d.\n", val & 0x1f); + break; + + case 0x8eee: + if (len == 2) { + if (mach->accel.patt_data_idx_reg < 0x10) { + mach->accel.color_pattern[mach->accel.patt_data_idx] = val & 0xff; + mach->accel.color_pattern[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; + mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); + } else { + mach->accel.mono_pattern_normal[mach->accel.patt_data_idx - 0x10] = val & 0xff; + mach->accel.mono_pattern_normal[(mach->accel.patt_data_idx + 1) - 0x10] = (val >> 8) & 0xff; + mach_log("Write Port 8eee: Mono Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx - 0x10, val); + } + mach->accel.patt_data_idx += 2; + } + break; + + case 0x92ee: + mach_log("Write port 92ee, malatch=%08x.\n", svga->ma_latch); + break; + + case 0x96ee: + if (len == 2) { + mach->accel.bres_count = val & 0x7ff; + mach_log("BresenhamDraw=%04x.\n", mach->accel.dp_config); + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 1; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + dev->accel.cmd_back = 1; + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) + dev->accel.cmd_back = 0; + + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); + } + break; + + case 0x9aee: + mach->accel.line_idx = val & 0x07; + break; + + case 0xa2ee: + mach_log("Line OPT=%04x.\n", val); + if (len == 2) { + mach->accel.linedraw_opt = val; + mach->accel.bbottom = dev->accel.clip_bottom; + mach->accel.btop = dev->accel.clip_top; + mach->accel.bleft = dev->accel.clip_left; + mach->accel.bright = dev->accel.clip_right; + if (mach->accel.linedraw_opt & 0x100) { + mach->accel.bbottom = 2047; + mach->accel.btop = 0; + mach->accel.bleft = 0; + mach->accel.bright = 2047; + } + } + break; + + case 0xa6ee: + if (len == 2) + mach->accel.dest_x_start = val & 0x7ff; + break; + + case 0xaaee: + if (len == 2) + mach->accel.dest_x_end = val & 0x7ff; + break; + + case 0xaeee: + if (len == 2) { + mach->accel.dest_y_end = val & 0x7ff; + if ((val + 1) == 0x10000) { + mach_log("Dest_Y_end overflow val=%04x, DPCONFIG=%04x\n", val, mach->accel.dp_config); + mach->accel.dest_y_end = 0; + } + dev->data_available = 0; + dev->data_available2 = 0; + mach_log("BitBLT=%04x.\n", mach->accel.dp_config); + mach_log(".\n"); + mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ + + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + dev->accel.cmd_back = 1; + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) + dev->accel.cmd_back = 0; + + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); + } + break; + + case 0xb2ee: + if (len == 2) + mach->accel.src_x_start = val & 0x7ff; + break; + + case 0xb6ee: + dev->accel.bkgd_mix = val & 0xff; + break; + + case 0xbaee: + dev->accel.frgd_mix = val & 0xff; + break; + + case 0xbeee: + if (len == 2) + mach->accel.src_x_end = val & 0x7ff; + break; + + case 0xc2ee: + mach->accel.src_y_dir = val & 1; + break; + + case 0xc6ee: + if (len == 2) { + mach->accel.cmd_type = 0; + mach_log("TODO: Short Stroke.\n"); + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + dev->accel.cmd_back = 1; + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) + dev->accel.cmd_back = 0; + } + break; + + case 0xcaee: + if (len == 2) { + mach->accel.scan_to_x = (val & 0x7ff); + if ((val + 1) == 0x10000) { + mach_log("Scan_to_X overflow val = %04x\n", val); + mach->accel.scan_to_x = 0; + } + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ + mach_log(".\n"); + + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + dev->accel.cmd_back = 1; + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) + dev->accel.cmd_back = 0; + + mach_log("ScanToX=%04x, mono_src=%d, bkgd_sel=%d, frgd_sel=%d, pixread=%x.\n", mach->accel.dp_config, mono_src, bkgd_sel, frgd_sel, mach_pixel_read(mach)); + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); + } + break; + + case 0xceee: + mach_log("Data Path Configuration (%04x) write val=%04x.\n", port, val); + if (len == 2) { + dev->data_available = 0; + dev->data_available2 = 0; + mach->accel.dp_config = val; + } + break; + + case 0xd2ee: + mach->accel.patt_len = val & 0x1f; + mach_log("Write Port d2ee: Pattern Length=%d, val=%04x.\n", val & 0x1f, val); + mach->accel.mono_pattern_enable = !!(val & 0x80); + if (len == 2) { + mach->accel.block_write_mono_pattern_enable = !!(val & 0x8000); + mach->accel.patt_len_reg = val; + } + break; + + case 0xd6ee: + mach->accel.patt_idx = val & 0x1f; + mach_log("Write Port d6ee: Pattern Index=%d.\n", val & 0x1f); + break; + + case 0xdaee: + if (len == 2) { + dev->accel.multifunc[2] = val & 0x7ff; + dev->accel.clip_left = dev->accel.multifunc[2]; + if (val & 0x800) + dev->accel.clip_left |= ~0x7ff; + } + mach_log("DAEE (extclipl) write val=%d, left=%d.\n", val, dev->accel.clip_left); + break; + + case 0xdeee: + if (len == 2) { + dev->accel.multifunc[1] = val & 0x7ff; + dev->accel.clip_top = dev->accel.multifunc[1]; + if (val & 0x800) { + dev->accel.clip_top |= ~0x7ff; + } + } + mach_log("DEEE (extclipt) write val = %d\n", val); + break; + + case 0xe2ee: + if (len == 2) { + dev->accel.multifunc[4] = val & 0x7ff; + dev->accel.clip_right = dev->accel.multifunc[4]; + if (val & 0x800) + dev->accel.clip_right |= ~0x7ff; + } + mach_log("E2EE (extclipr) write val = %d\n", val); + break; + + case 0xe6ee: + if (len == 2) { + dev->accel.multifunc[3] = val & 0x7ff; + dev->accel.clip_bottom = dev->accel.multifunc[3]; + if (val & 0x800) + dev->accel.clip_bottom |= ~0x7ff; + } + mach_log("E6EE (extclipb) write val = %d\n", val); + break; + + case 0xeeee: + if (len == 2) + mach->accel.dest_cmp_fn = val; + break; + + case 0xf2ee: + mach_log("F2EE.\n"); + if (len == 2) + mach->accel.dst_clr_cmp_mask = val; + break; + + case 0xfeee: + if (len == 2) { + mach->accel.line_array[mach->accel.line_idx] = val; + mach_log("mach->accel.line_array[%02X] = %04X\n", mach->accel.line_idx, val); + dev->accel.cur_x = mach->accel.line_array[(mach->accel.line_idx == 4) ? 4 : 0]; + dev->accel.cur_y = mach->accel.line_array[(mach->accel.line_idx == 5) ? 5 : 1]; + mach->accel.cx_end_line = mach->accel.line_array[2]; + mach->accel.cy_end_line = mach->accel.line_array[3]; + if ((mach->accel.line_idx == 3) || (mach->accel.line_idx == 5)) { + mach->accel.cmd_type = (mach->accel.line_idx == 5) ? 4 : 3; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; + + dev->accel.cmd_back = 1; + if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) + dev->accel.cmd_back = 0; + + mach_log("LineDraw type=%x, dpconfig=%04x.\n", mach->accel.cmd_type, mach->accel.dp_config); + mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); + mach->accel.line_idx = (mach->accel.line_idx == 5) ? 4 : 2; + break; + } + mach->accel.line_idx++; + } break; default: + mach_log("Unknown or reserved write to %04x, val=%04x, len=%d, latch=%08x.\n", port, val, len, svga->ma_latch); break; } } -static void -mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) -{ - svga_t *svga = &mach->svga; - - mach_log("[%04X:%08X]: Port NORMAL OUT=%04x, val=%04x.\n", CS, cpu_state.pc, port, val); - - mach_accel_out_call(port, val, mach, svga, (ibm8514_t *) svga->dev8514); -} - static uint16_t mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, int len) { @@ -3832,7 +4058,19 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in switch (port) { case 0x82e8: + if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) + temp = mach->accel.cy_end_line; + else + temp = ibm8514_accel_in_fifo(svga, port, len); + break; + case 0x86e8: + if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) + temp = mach->accel.cx_end_line; + else + temp = ibm8514_accel_in_fifo(svga, port, len); + break; + case 0x92e8: case 0x96e8: case 0xc2e8: @@ -3842,18 +4080,24 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0x9ae8: case 0xdae8: - if ((dev->fifo_idx >= 1) && (dev->fifo_idx <= 8)) { - temp |= (1 << (dev->fifo_idx - 1)); - dev->fifo_idx = 0; - } - if (len == 2) { - if (dev->force_busy) - temp |= 0x200; /*Hardware busy*/ + if (dev->fifo_idx <= 8) { + for (int i = 1; i <= dev->fifo_idx; i++) + temp |= (1 << (7 - (i - 1))); + } else + temp = 0x00ff; + + if (dev->fifo_idx > 0) + dev->fifo_idx--; + + if (dev->force_busy) + temp |= 0x0200; /*Hardware busy*/ + + if (dev->accel.cmd_back) + dev->force_busy = 0; - dev->force_busy = 0; if (dev->data_available) { - temp |= 0x100; /*Read Data available*/ + temp |= 0x0100; /*Read Data available*/ if (mach->accel.cmd_type >= 0) { switch (mach->accel.cmd_type) { case 2: @@ -3891,10 +4135,13 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0x9ae9: case 0xdae9: if (len == 1) { + dev->fifo_idx = 0; + if (dev->force_busy2) temp |= 0x02; /*Hardware busy*/ dev->force_busy2 = 0; + if (dev->data_available2) { temp |= 0x01; /*Read Data available*/ if (mach->accel.cmd_type >= 0) { @@ -3913,8 +4160,19 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; } } else { - if (dev->accel.sy < 0) - dev->data_available2 = 0; + switch (dev->accel.cmd >> 13) { + case 2: + case 3: + case 4: + case 6: + if (dev->accel.sy < 0) + dev->data_available = 0; + break; + default: + if (!dev->accel.sy) + dev->data_available = 0; + break; + } } } } @@ -3930,7 +4188,7 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in READ_PIXTRANS_BYTE_IO(dev->accel.dx, 1) temp = mach->accel.pix_trans[1]; } else { - if (mach->accel.cmd_type == 3) { + if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { READ_PIXTRANS_WORD(dev->accel.cx, 0) } else { READ_PIXTRANS_WORD(dev->accel.dx, 0) @@ -3943,7 +4201,7 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in cmd = (dev->accel.cmd >> 13); if (len == 2) { READ_PIXTRANS_WORD(dev->accel.cx, 0) - if (dev->subsys_stat & 0x01) { + if (dev->subsys_stat & INT_VSY) { dev->force_busy = 1; dev->data_available = 1; } @@ -4017,10 +4275,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0x8eee: - if (len == 1) - temp = mach->accel.ext_ge_config & 0xff; - else + if (len == 2) temp = mach->accel.ext_ge_config; + else + temp = mach->accel.ext_ge_config & 0xff; mach_log("ExtGE Read = %04x, len=%d.\n", temp, len); break; @@ -4030,10 +4288,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0x92ee: - if (len == 1) - temp = mach->accel.eeprom_control & 0xff; - else + if (len == 2) temp = mach->accel.eeprom_control; + else + temp = mach->accel.eeprom_control & 0xff; mach_log("EEPROM cntl read=%04x, len=%d.\n", temp, len); break; @@ -4045,10 +4303,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0x96ee: - if (len == 1) - temp = mach->accel.test & 0xff; - else + if (len == 2) temp = mach->accel.test; + else + temp = mach->accel.test & 0xff; break; case 0x96ef: if (len == 1) @@ -4057,18 +4315,22 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0x9aee: if (len == 2) { - if ((dev->ext_fifo_idx >= 1) && (dev->ext_fifo_idx <= 16)) { - temp |= (1 << (dev->ext_fifo_idx - 1)); - dev->ext_fifo_idx = 0; - } + if (dev->fifo_idx <= 16) { + for (int i = 1; i <= dev->fifo_idx; i++) + temp |= (1 << (15 - (i - 1))); + } else + temp = 0xffff; + + if (dev->fifo_idx > 0) + dev->fifo_idx--; } break; case 0xa2ee: - if (len == 1) - temp = mach->accel.linedraw_opt & 0xff; - else + if (len == 2) temp = mach->accel.linedraw_opt; + else + temp = mach->accel.linedraw_opt & 0xff; break; case 0xa2ef: if (len == 1) @@ -4076,11 +4338,11 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0xb2ee: - if (len == 1) - temp = dev->hdisped; - else { + if (len == 2) { temp = dev->hdisped & 0xff; temp |= (dev->htotal << 8); + } else { + temp = dev->hdisped; } mach_log("B2EE read=%02x.\n", temp & 0xff); break; @@ -4098,12 +4360,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0xc2ee: - if (len == 1) - temp = dev->v_total_reg & 0xff; - else { + if (len == 2) temp = dev->v_total_reg; - mach_log("VTOTAL read=%d.\n", temp); - } + else + temp = dev->v_total_reg & 0xff; break; case 0xc2ef: if (len == 1) @@ -4111,12 +4371,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0xc6ee: - if (len == 1) - temp = dev->v_disp & 0xff; - else { + if (len == 2) temp = dev->v_disp; - mach_log("VDISP read=%d.\n", temp); - } + else + temp = dev->v_disp & 0xff; break; case 0xc6ef: if (len == 1) @@ -4124,10 +4382,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0xcaee: - if (len == 1) - temp = dev->v_sync_start & 0xff; - else + if (len == 2) temp = dev->v_sync_start; + else + temp = dev->v_sync_start & 0xff; break; case 0xcaef: if (len == 1) @@ -4136,10 +4394,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0xceee: mach_log("CEEE read=%d.\n", len); - if (len == 1) - temp = dev->vc & 0xff; - else + if (len == 2) temp = dev->vc & 0x7ff; + else + temp = dev->vc & 0xff; break; case 0xceef: mach_log("CEEF read=%d.\n", len); @@ -4167,8 +4425,10 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in if (len == 2) { if ((dev->local & 0xff) >= 0x02) temp = mach->accel.src_y; - } else - temp = mach->accel.src_y & 0xff; + } else { + if ((dev->local & 0xff) >= 0x02) + temp = mach->accel.src_y & 0xff; + } break; case 0xdeef: if (len == 1) { @@ -4218,6 +4478,7 @@ static uint8_t mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) { uint8_t temp = 0; + uint8_t fifo_test_tag[16] = { 0x7c, 0x64, 0x60, 0x5c, 0x58, 0x54, 0x50, 0x68, 0x38, 0x24, 0x10, 0x0c, 0x08, 0x04, 0x00, 0x4c}; int16_t clip_t = dev->accel.clip_top; int16_t clip_l = dev->accel.clip_left; int16_t clip_b = dev->accel.clip_bottom; @@ -4240,63 +4501,64 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x42e8: case 0x42e9: - if ((dev->subsys_cntl & 0x01) && !(dev->subsys_stat & 0x01) && (dev->vc == dev->dispend)) - temp |= 0x01; + if (!(port & 1)) { + if ((dev->subsys_cntl & INT_VSY) && !(dev->subsys_stat & INT_VSY) && (dev->vc == dev->dispend)) + temp |= INT_VSY; - if (mach->accel.cmd_type == -1) { - if (cmd == 6) { - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && - (dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r_ibm) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b_ibm)) - temp |= 0x02; - } else { - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && - (dev->accel.cx >= clip_l) && - (dev->accel.cx <= clip_r_ibm) && - (dev->accel.cy >= clip_t) && - (dev->accel.cy <= clip_b_ibm)) - temp |= 0x02; - } - } else { - switch (mach->accel.cmd_type) { - case 1: - case 2: - case 5: - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && - (dev->accel.dx >= clip_l) && - (dev->accel.dx <= clip_r) && - (dev->accel.dy >= clip_t) && - (dev->accel.dy <= clip_b)) - temp |= 0x02; - break; - case 3: - case 4: - if ((dev->subsys_cntl & 0x02) && - !(dev->subsys_stat & 0x02) && + if (mach->accel.cmd_type == -1) { + if (cmd == 6) { + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && + (dev->accel.dx_ibm >= clip_l) && + (dev->accel.dx_ibm <= clip_r_ibm) && + (dev->accel.dy_ibm >= clip_t) && + (dev->accel.dy_ibm <= clip_b_ibm)) + temp |= INT_GE_BSY; + } else { + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && (dev->accel.cx >= clip_l) && - (dev->accel.cx <= clip_r) && + (dev->accel.cx <= clip_r_ibm) && (dev->accel.cy >= clip_t) && - (dev->accel.cy <= clip_b)) - temp |= 0x02; - break; - default: - break; + (dev->accel.cy <= clip_b_ibm)) + temp |= INT_GE_BSY; + } + } else { + switch (mach->accel.cmd_type) { + case 1: + case 2: + case 5: + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && + (dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) + temp |= INT_GE_BSY; + break; + case 3: + case 4: + if ((dev->subsys_cntl & INT_GE_BSY) && + !(dev->subsys_stat & INT_GE_BSY) && + (dev->accel.cx >= clip_l) && + (dev->accel.cx <= clip_r) && + (dev->accel.cy >= clip_t) && + (dev->accel.cy <= clip_b)) + temp |= INT_GE_BSY; + break; + default: + break; + } } - } - if ((!dev->fifo_idx || !dev->ext_fifo_idx)) { - if ((!dev->force_busy && !dev->force_busy2) || !mach->force_busy) - temp |= 0x08; - } - if (port & 1) { - temp = dev->vram_512k_8514 ? 0x00 : 0x80; - temp |= (dev->subsys_cntl >> 8); - } else { + if (dev->accel.cmd_back) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + dev->data_available = 0; + dev->data_available2 = 0; + temp |= INT_FIFO_EMP; + } temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); if (mach->accel.ext_ge_config & 0x08) temp |= ((mach->accel.ext_ge_config & 0x07) << 4); @@ -4318,8 +4580,16 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) break; case 0x1aee: + if (dev->fifo_idx > 0) + dev->fifo_idx--; + if (mach->fifo_test_idx > 0) + mach->fifo_test_idx--; + fallthrough; case 0x1aef: - temp = 0x00; + mach_log("FIFO Test IDX=%d, Data=%04x.\n", mach->fifo_test_idx, mach->fifo_test_data[mach->fifo_test_idx]); + READ8(port, mach->fifo_test_data[mach->fifo_test_idx]); + if (!mach->fifo_test_idx && ((mach->accel.dp_config == 0xaaaa) || (mach->accel.dp_config == 0x5555))) + mach->accel.dp_config = 0x2211; break; case 0x22ee: @@ -4336,7 +4606,6 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x36ef: if ((dev->local & 0xff) >= 0x02) { READ8(port, mach->misc); - if (!(port & 1)) { temp &= ~0x0c; switch (dev->vram_amount) { @@ -4357,6 +4626,14 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) } break; + case 0x3aee: + case 0x3aef: + if (port & 1) + temp = 0x01; + else + temp = fifo_test_tag[dev->fifo_idx]; + break; + case 0x42ee: case 0x42ef: READ8(port, mach->accel.test2); @@ -4380,7 +4657,13 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) temp = (((dev->bios_rom.mapping.base >> 7) - 0x1000) >> 4); if (port & 1) temp |= 0x01; + } else { + if (mach->accel.scratch0 == 0x1234) + temp = 0x0000; } + } else { + if (mach->accel.scratch0 == 0x1234) + temp = 0x0000; } break; @@ -4440,30 +4723,30 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) default: break; } - if (port == 0x2ee8 || port == 0x2ee9 || port == 0x42e8 || port == 0x42e9) - mach_log("[%04X:%08X]: Port NORMAL IN=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); + mach_log("[%04X:%08X]: Port NORMAL IN=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); return temp; } -static void -ati8514_accel_out(uint16_t port, uint8_t val, svga_t *svga) -{ - mach_log("[%04X:%08X]: Port NORMAL OUT=%04x, val=%04x.\n", CS, cpu_state.pc, port, val); - - mach_accel_out_call(port, val, (mach_t *)svga->ext8514, svga, (ibm8514_t *) svga->dev8514); -} - static void ati8514_accel_outb(uint16_t port, uint8_t val, void *priv) { svga_t *svga = (svga_t *)priv; mach_t *mach = (mach_t *)svga->ext8514; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 1); - else - ati8514_accel_out(port, val, svga); + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } + } + dev->accel_out_fifo(svga, port, val, 1); + mach_log("%04X:%08X: OUTB port=%04x, val=%02x, fifo idx=%d.\n", CS, cpu_state.pc, port, val, dev->fifo_idx); } static void @@ -4471,13 +4754,23 @@ ati8514_accel_outw(uint16_t port, uint16_t val, void *priv) { svga_t *svga = (svga_t *)priv; mach_t *mach = (mach_t *)svga->ext8514; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 2); - else { - ati8514_accel_out(port, val, svga); - ati8514_accel_out(port + 1, (val >> 8), svga); + if (port == 0xf6ee) + port = 0x82e8; + + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } } + dev->accel_out_fifo(svga, port, val, 2); + mach_log("%04X:%08X: OUTW port=%04x, val=%04x, fifo idx=%d.\n", CS, cpu_state.pc, port, val, dev->fifo_idx); } static void @@ -4485,16 +4778,23 @@ ati8514_accel_outl(uint16_t port, uint32_t val, void *priv) { svga_t *svga = (svga_t *)priv; mach_t *mach = (mach_t *)svga->ext8514; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) { - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val & 0xffff, 2); - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, val >> 16, 2); - } else { - ati8514_accel_out(port, val, svga); - ati8514_accel_out(port + 1, (val >> 8), svga); - ati8514_accel_out(port + 2, (val >> 16), svga); - ati8514_accel_out(port + 3, (val >> 24), svga); + if (port == 0xf6ee) + port = 0x82e8; + + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } } + dev->accel_out_fifo(svga, port, val, 2); + mach_log("OUTL port=%04x, val=%08x, fifo idx=%d.\n", port, val, dev->fifo_idx); } static void @@ -4502,11 +4802,20 @@ mach_accel_outb(uint16_t port, uint8_t val, void *priv) { mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 1); - else - mach_accel_out(port, val, mach); + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } + } + dev->accel_out_fifo(mach, port, val, 1); + mach_log("%04X:%08X: OUTB port=%04x, val=%02x, fifo idx=%d.\n", CS, cpu_state.pc, port, val, dev->fifo_idx); } static void @@ -4514,13 +4823,23 @@ mach_accel_outw(uint16_t port, uint16_t val, void *priv) { mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val, 2); - else { - mach_accel_out(port, val, mach); - mach_accel_out(port + 1, (val >> 8), mach); + if (port == 0xf6ee) + port = 0x82e8; + + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } } + dev->accel_out_fifo(mach, port, val, 2); + mach_log("%04X:%08X: OUTW port=%04x, val=%04x, fifo idx=%d.\n", CS, cpu_state.pc, port, val, dev->fifo_idx); } static void @@ -4528,16 +4847,23 @@ mach_accel_outl(uint16_t port, uint32_t val, void *priv) { mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (port & 0x8000) { - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, val & 0xffff, 2); - mach_accel_out_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, val >> 16, 2); - } else { - mach_accel_out(port, val, mach); - mach_accel_out(port + 1, (val >> 8), mach); - mach_accel_out(port + 2, (val >> 16), mach); - mach_accel_out(port + 3, (val >> 24), mach); + if (port == 0xf6ee) + port = 0x82e8; + + if (port & 0x8000) { /*Command FIFO*/ + if (dev->accel.cmd_back) { + mach->fifo_test_data[dev->fifo_idx] = val; + dev->fifo_idx++; + if (dev->fifo_idx > 16) + dev->fifo_idx = 16; + + mach->fifo_test_idx = dev->fifo_idx; + } } + dev->accel_out_fifo(mach, port, val, 2); + mach_log("OUTL port=%04x, val=%08x, fifo idx=%d.\n", port, val, dev->fifo_idx); } static uint8_t @@ -4558,6 +4884,7 @@ ati8514_accel_inb(uint16_t port, void *priv) else temp = ati8514_accel_in(port, svga); + mach_log("%04X:%08X: INB port=%04x, temp=%02x.\n", CS, cpu_state.pc, port, temp); return temp; } @@ -4574,6 +4901,8 @@ ati8514_accel_inw(uint16_t port, void *priv) temp = ati8514_accel_in(port, svga); temp |= (ati8514_accel_in(port + 1, svga) << 8); } + + mach_log("%04X:%08X: INW port=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); return temp; } @@ -4584,14 +4913,11 @@ ati8514_accel_inl(uint16_t port, void *priv) mach_t *mach = (mach_t *)svga->ext8514; uint32_t temp; - if (port & 0x8000) { + if (port & 0x8000) temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2); - temp = (mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, 2) << 16); - } else { + else { temp = ati8514_accel_in(port, svga); temp |= (ati8514_accel_in(port + 1, svga) << 8); - temp |= (ati8514_accel_in(port + 2, svga) << 16); - temp |= (ati8514_accel_in(port + 3, svga) << 24); } return temp; } @@ -4615,6 +4941,7 @@ mach_accel_inb(uint16_t port, void *priv) else temp = mach_accel_in(port, mach); + mach_log("%04X:%08X: INB port=%04x, temp=%02x.\n", CS, cpu_state.pc, port, temp); return temp; } @@ -4631,6 +4958,8 @@ mach_accel_inw(uint16_t port, void *priv) temp = mach_accel_in(port, mach); temp |= (mach_accel_in(port + 1, mach) << 8); } + + mach_log("%04X:%08X: INW port=%04x, temp=%04x.\n", CS, cpu_state.pc, port, temp); return temp; } @@ -4641,14 +4970,11 @@ mach_accel_inl(uint16_t port, void *priv) svga_t *svga = &mach->svga; uint32_t temp; - if (port & 0x8000) { + if (port & 0x8000) temp = mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port, 2); - temp = (mach_accel_in_fifo(mach, svga, (ibm8514_t *) svga->dev8514, port + 2, 2) << 16); - } else { + else { temp = mach_accel_in(port, mach); temp |= (mach_accel_in(port + 1, mach) << 8); - temp |= (mach_accel_in(port + 2, mach) << 16); - temp |= (mach_accel_in(port + 3, mach) << 24); } return temp; } @@ -4817,6 +5143,11 @@ mach32_write(uint32_t addr, uint8_t val, void *priv) xga_write_test(addr, val, svga); addr = (addr & svga->banked_mask) + svga->write_bank; + if (mach->accel.test2 & 0x10) { + if (addr < ((mach->accel.test2 & 0x0f) << 18)) + return; + } + if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; switch (addr & 0x06) { @@ -4838,6 +5169,8 @@ mach32_write(uint32_t addr, uint8_t val, void *priv) } } else mach32_write_common(addr, val, 0, mach, svga); + + mach_log("Writeb banked=%08x.\n", addr); } static void @@ -4850,6 +5183,11 @@ mach32_writew(uint32_t addr, uint16_t val, void *priv) xga_write_test(addr, val, svga); addr = (addr & svga->banked_mask) + svga->write_bank; + if (mach->accel.test2 & 0x10) { + if (addr < ((mach->accel.test2 & 0x0f) << 18)) + return; + } + if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; if (addr & 0x04) { @@ -4867,6 +5205,7 @@ mach32_writew(uint32_t addr, uint16_t val, void *priv) mach32_write_common(addr, val & 0xff, 0, mach, svga); mach32_write_common(addr + 1, val >> 8, 0, mach, svga); } + mach_log("Writew banked=%08x.\n", addr); } static void @@ -4879,6 +5218,11 @@ mach32_writel(uint32_t addr, uint32_t val, void *priv) xga_write_test(addr, val, svga); addr = (addr & svga->banked_mask) + svga->write_bank; + if (mach->accel.test2 & 0x10) { + if (addr < ((mach->accel.test2 & 0x0f) << 18)) + return; + } + if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; mach32_write_common(addr, val & 0x0f, 0, mach, svga); @@ -4895,6 +5239,223 @@ mach32_writel(uint32_t addr, uint32_t val, void *priv) mach32_write_common(addr + 2, val >> 16, 0, mach, svga); mach32_write_common(addr + 3, val >> 24, 0, mach, svga); } + + mach_log("Writel banked=%08x.\n", addr); +} + +static __inline void +mach32_svga_write(uint32_t addr, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->priv; + int writemask2 = svga->writemask; + int reset_wm = 0; + latch_t vall; + uint8_t wm = svga->writemask; + uint8_t count; + uint8_t i; + + cycles -= svga->monitor->mon_video_timing_write_b; + + xga_write_test(addr, val, svga); + addr = svga_decode_addr(svga, addr, 1); + if (addr == 0xffffffff) { + mach_log("WriteCommon Over.\n"); + return; + } + + if (mach->accel.test2 & 0x10) { + if (addr >= ((mach->accel.test2 & 0x0f) << 18)) + return; + } + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if (((svga->chain4 && (svga->packed_chain4 || svga->force_old_addr)) || svga->fb_only) && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } else if (svga->chain4 && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) { + mach_log("WriteBankedOver=%08x, val=%02x.\n", addr & svga->vram_mask, val); + return; + } + + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + + count = 4; + + switch (svga->writemode) { + case 0: + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); + if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = val; + } + return; + } else { + for (i = 0; i < count; i++) { + if (svga->gdcreg[1] & (1 << i)) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + else + vall.b[i] = val; + } + } + break; + case 1: + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = svga->latch.b[i]; + } + return; + case 2: + for (i = 0; i < count; i++) + vall.b[i] = !!(val & (1 << i)) * 0xff; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } + return; + } + break; + case 3: + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + for (i = 0; i < count; i++) + vall.b[i] = !!(svga->gdcreg[0] & (1 << i)) * 0xff; + + reset_wm = 1; + break; + default: + return; + } + + switch (svga->gdcreg[3] & 0x18) { + case 0x00: /* Set */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } + break; + case 0x08: /* AND */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } + break; + case 0x10: /* OR */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } + break; + case 0x18: /* XOR */ + for (i = 0; i < count; i++) { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } + break; + + default: + break; + } + + if (reset_wm) + svga->gdcreg[8] = wm; +} + +static __inline void +mach32_svga_writew(uint32_t addr, uint16_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->priv; + + if (!svga->fast) { + mach32_svga_write(addr, val, priv); + mach32_svga_write(addr + 1, val >> 8, priv); + return; + } + + cycles -= svga->monitor->mon_video_timing_write_w; + + xga_write_test(addr, val & 0xff, svga); + xga_write_test(addr + 1, val >> 8, svga); + addr = svga_decode_addr(svga, addr, 1); + + if (addr == 0xffffffff) + return; + + if (mach->accel.test2 & 0x10) { + if (addr >= ((mach->accel.test2 & 0x0f) << 18)) + return; + } + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + *(uint16_t *) &svga->vram[addr] = val; +} + +static __inline void +mach32_svga_writel(uint32_t addr, uint32_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->priv; + + if (!svga->fast) { + mach32_svga_write(addr, val, priv); + mach32_svga_write(addr + 1, val >> 8, priv); + mach32_svga_write(addr + 2, val >> 16, priv); + mach32_svga_write(addr + 3, val >> 24, priv); + return; + } + + cycles -= svga->monitor->mon_video_timing_write_l; + + xga_write_test(addr, val & 0xff, svga); + xga_write_test(addr + 1, (val >> 8) & 0xff, svga); + xga_write_test(addr + 2, (val >> 16) & 0xff, svga); + xga_write_test(addr + 3, (val >> 24) & 0xff, svga); + addr = svga_decode_addr(svga, addr, 1); + + if (addr == 0xffffffff) + return; + + if (mach->accel.test2 & 0x10) { + if (addr >= ((mach->accel.test2 & 0x0f) << 18)) + return; + } + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + *(uint32_t *) &svga->vram[addr] = val; } static __inline void @@ -5100,6 +5661,7 @@ mach32_read(uint32_t addr, void *priv) } else ret = mach32_read_common(addr, 0, mach, svga); + mach_log("Readb banked=%08x.\n", addr); return ret; } @@ -5131,6 +5693,7 @@ mach32_readw(uint32_t addr, void *priv) ret = mach32_read_common(addr, 0, mach, svga); ret |= (mach32_read_common(addr + 1, 0, mach, svga) << 8); } + mach_log("Readw banked=%08x.\n", addr); return ret; } @@ -5161,6 +5724,7 @@ mach32_readl(uint32_t addr, void *priv) ret |= (mach32_read_common(addr + 2, 0, mach, svga) << 16); ret |= (mach32_read_common(addr + 3, 0, mach, svga) << 24); } + mach_log("Readl banked=%08x.\n", addr); return ret; } @@ -5224,19 +5788,22 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (addr & 1) + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (addr & 1) + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { - mach_log("Port WORDB Write=%04x.\n", 0x02ee + (port_dword << 8)); - mach_accel_outb(0x02ee + (addr & 1) + (port_dword << 8), val, mach); + mach_log("Port WORDB Write=%04x.\n", actual_port_ext); + mach_accel_outb(actual_port_ext, val, mach); } else { - mach_log("Port WORDB Write=%04x.\n", 0x02e8 + (port_dword << 8)); - mach_accel_outb(0x02e8 + (addr & 1) + (port_dword << 8), val, mach); + mach_log("Port WORDB Write=%04x.\n", actual_port); + mach_accel_outb(actual_port, val, mach); } } else { mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + if (dev->on) mach32_write_common(addr, val, 1, mach, svga); else @@ -5251,19 +5818,21 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { - mach_log("Port WORDW Write=%04x.\n", 0x02ee + (port_dword << 8)); - mach_accel_outw(0x02ee + (port_dword << 8), val, mach); + mach_log("Port WORDW Write=%04x, localcntl=%02x, pcicntl=%02x, actual addr=%08x, val=%04x.\n", actual_port_ext, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80, addr, val); + mach_accel_outw(actual_port_ext, val, mach); } else { - mach_log("Port WORDW Write=%04x.\n", 0x02e8 + (port_dword << 8)); - mach_accel_outw(0x02e8 + (port_dword << 8), val, mach); + mach_log("Port WORDW Write=%04x, localcntl=%02x, pcicntl=%02x, actual addr=%08x.\n", actual_port, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80, addr); + mach_accel_outw(actual_port, val, mach); } } else { - mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x, base=%08x, 8514/A port=%04x, ATI port=%04x, switch=%03x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20, mach->linear_base, actual_port, actual_port_ext, addr & 0x100); if (dev->on) mach32_writew_linear(addr, val, mach); else @@ -5278,6 +5847,8 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (port_dword << 8); mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); @@ -5285,13 +5856,11 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { - mach_log("Port WORDL Write=%04x.\n", 0x02ee + (port_dword << 8)); - mach_accel_outw(0x02ee + (port_dword << 8), val & 0xffff, mach); - mach_accel_outw(0x02ee + (port_dword << 8) + 4, val >> 16, mach); + mach_log("Port WORDL Write=%04x, localcntl=%02x, pcicntl=%02x.\n", actual_port_ext, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80); + mach_accel_outl(actual_port_ext, val, mach); } else { - mach_log("Port WORDL Write=%04x.\n", 0x02e8 + (port_dword << 8)); - mach_accel_outw(0x02e8 + (port_dword << 8), val & 0xffff, mach); - mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); + mach_log("Port WORDL Write=%04x, localcntl=%02x, pcicntl=%02x.\n", actual_port, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80); + mach_accel_outl(actual_port, val, mach); } } else { if (dev->on) @@ -5309,13 +5878,15 @@ mach32_ap_readb(uint32_t addr, void *priv) const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp; uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (addr & 1) + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (addr & 1) + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) - temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); + temp = mach_accel_inb(actual_port_ext, mach); else - temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); + temp = mach_accel_inb(actual_port, mach); } else { if (dev->on) temp = mach32_read_common(addr, 1, mach, svga); @@ -5335,14 +5906,19 @@ mach32_ap_readw(uint32_t addr, void *priv) svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint16_t temp; - uint8_t port_dword = (addr - mach->linear_base) & 0xfc; + uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { - if (addr & 0x100) - temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); - else - temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); + if (addr & 0x100) { + temp = mach_accel_inw(actual_port_ext, mach); + mach_log("Port WORDW Read=%04x.\n", actual_port_ext); + } else { + temp = mach_accel_inw(actual_port, mach); + mach_log("Port WORDW Read=%04x.\n", actual_port); + } } else { if (dev->on) temp = mach32_readw_linear(addr, mach); @@ -5363,15 +5939,17 @@ mach32_ap_readl(uint32_t addr, void *priv) const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t temp; uint8_t port_dword = addr & 0xfc; + uint16_t actual_port = 0x02e8 + (port_dword << 8); + uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { if (addr & 0x100) { - temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); - temp |= (mach_accel_inw(0x02ee + (port_dword << 8) + 4, mach) << 8); + temp = mach_accel_inl(actual_port_ext, mach); + mach_log("Port WORDL Read=%04x.\n", actual_port_ext); } else { - temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); - temp |= (mach_accel_inw(0x02e8 + (port_dword << 8) + 4, mach) << 8); + temp = mach_accel_inl(actual_port, mach); + mach_log("Port WORDL Read=%04x.\n", actual_port); } } else { if (dev->on) @@ -5405,14 +5983,17 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; + mem_mapping_set_addr(&mach->banked_mapping, 0xa0000, 0x20000); break; case 0x4: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; + mem_mapping_set_addr(&mach->banked_mapping, 0xa0000, 0x10000); break; case 0x8: /*32k at B0000*/ mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; + mem_mapping_set_addr(&mach->banked_mapping, 0xb0000, 0x08000); break; case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); @@ -5426,6 +6007,7 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) } } } + mem_mapping_set_addr(&mach->banked_mapping, 0xb8000, 0x08000); break; default: @@ -5433,7 +6015,7 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) } } - mach_log("Linear base = %08x, aperture = %04x, localcntl = %02x svgagdc = %x.\n", + mach_log("Linear base=%08x, aperture=%04x, localcntl=%02x, svgagdc=%x.\n", mach->linear_base, mach->memory_aperture, mach->local_cntl, svga->gdcreg[6] & 0x0c); if (mach->linear_base) { if (((mach->memory_aperture & 3) == 1) && !mach->pci_bus) { @@ -5452,24 +6034,20 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) mach_log("Linear Disabled APSIZE=4.\n"); mem_mapping_disable(&mach->mmio_linear_mapping); } + if ((dev->local & 0xff) >= 0x02) { if (dev->on && dev->vendor_mode) { mach_log("Mach32 banked mapping.\n"); - mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel); - mem_mapping_set_p(&svga->mapping, mach); + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&mach->banked_mapping); } else { - if (!dev->on) { - memset(dev->vram, 0, dev->vram_size); - memset(dev->changedvram, 0, (dev->vram_size >> 12) + 1); - } mach_log("IBM compatible banked mapping.\n"); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); - mem_mapping_set_p(&svga->mapping, svga); + mem_mapping_enable(&svga->mapping); + mem_mapping_disable(&mach->banked_mapping); } } else { - mach_log("IBM compatible banked mapping.\n"); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); - mem_mapping_set_p(&svga->mapping, svga); + mem_mapping_enable(&svga->mapping); + mem_mapping_disable(&mach->banked_mapping); } } @@ -5869,6 +6447,7 @@ mach_io_set(mach_t *mach) io_sethandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0x86ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); + io_sethandler(0x8aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); @@ -5891,6 +6470,7 @@ mach_io_set(mach_t *mach) io_sethandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); + io_sethandler(0xeaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_sethandler(0xf6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); @@ -6122,6 +6702,95 @@ mach32_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) } } +static void +mach_vblank_start(mach_t *mach, svga_t *svga) +{ + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + dev->subsys_stat |= INT_VSY; +} + +static void +mach_combo_vblank_start(void *priv) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->priv; + + mach_vblank_start(mach, svga); +} + +static void +ati8514_vblank_start(void *priv) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->ext8514; + + mach_vblank_start(mach, svga); +} + +static void +mach_combo_accel_out_fifo(void *priv, uint16_t port, uint16_t val, int len) +{ + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + mach_log("Accel OUT Combo=%04x, val=%04x, len=%d.\n", port, val, len); + mach_accel_out_fifo(mach, svga, dev, port, val, len); +} + +static void +ati8514_accel_out_fifo(void *priv, uint16_t port, uint16_t val, int len) +{ + svga_t *svga = (svga_t *) priv; + mach_t *mach = (mach_t *) svga->ext8514; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + mach_accel_out_fifo(mach, svga, dev, port, val, len); +} + +static void +mach_disable_handlers(mach_t *mach) +{ + io_removehandler(0x01ce, 2, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_removehandler(0x02ea, 4, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + mach_io_remove(mach); + + mem_mapping_disable(&mach->mmio_linear_mapping); + mem_mapping_disable(&mach->banked_mapping); + mem_mapping_disable(&mach->svga.mapping); + if (mach->pci_bus && mach->has_bios) + mem_mapping_disable(&mach->bios_rom.mapping); + + /* Save all the mappings and the timers because they are part of linked lists. */ + reset_state->mmio_linear_mapping = mach->mmio_linear_mapping; + reset_state->banked_mapping = mach->banked_mapping; + reset_state->svga.mapping = mach->svga.mapping; + reset_state->bios_rom.mapping = mach->bios_rom.mapping; + + reset_state->svga.timer = mach->svga.timer; +} + +static void +mach_reset(void *priv) +{ + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + + if (reset_state != NULL) { + mach_disable_handlers(mach); + mach->force_busy = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + if (mach->pci_bus) + reset_state->pci_slot = mach->pci_slot; + + *mach = *reset_state; + } +} + static void * mach8_init(const device_t *info) { @@ -6130,6 +6799,7 @@ mach8_init(const device_t *info) ibm8514_t *dev; mach = calloc(1, sizeof(mach_t)); + reset_state = calloc(1, sizeof(mach_t)); svga = &mach->svga; dev = (ibm8514_t *) calloc(1, sizeof(ibm8514_t)); @@ -6145,6 +6815,7 @@ mach8_init(const device_t *info) mach->ramdac_type = mach->pci_bus ? device_get_config_int("ramdac") : 1; dev->vram_amount = device_get_config_int("memory"); dev->vram_512k_8514 = dev->vram_amount == 512; + dev->accel.cmd_back = 1; if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus) { @@ -6227,8 +6898,12 @@ mach8_init(const device_t *info) mach->config1 |= 0x0400; svga->clock_gen = device_add(&ati18811_1_device); } + mem_mapping_add(&mach->banked_mapping, 0, 0, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel, NULL, MEM_MAPPING_EXTERNAL, mach); mem_mapping_add(&mach->mmio_linear_mapping, 0, 0, mach32_ap_readb, mach32_ap_readw, mach32_ap_readl, mach32_ap_writeb, mach32_ap_writew, mach32_ap_writel, NULL, MEM_MAPPING_EXTERNAL, mach); + mem_mapping_disable(&mach->banked_mapping); mem_mapping_disable(&mach->mmio_linear_mapping); + + mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, mach32_svga_write, mach32_svga_writew, mach32_svga_writel); } else { svga_init(info, svga, mach, (512 << 10), /*default: 512kB VGA for 28800-6 + 1MB for Mach8*/ mach_recalctimings, @@ -6240,7 +6915,7 @@ mach8_init(const device_t *info) dev->changedvram = calloc((dev->vram_size >> 12) + 1, 1); dev->vram_mask = dev->vram_size - 1; video_inform(VIDEO_FLAG_TYPE_8514, &timing_gfxultra_isa); - mach->config1 = 0x01 | 0x02 | 0x08 | 0x80; + mach->config1 = 0x01 | 0x08 | 0x80; if (dev->vram_amount >= 1024) mach->config1 |= 0x20; @@ -6296,6 +6971,11 @@ mach8_init(const device_t *info) } else ati_eeprom_load_mach8_vga(&mach->eeprom, "mach8.nvr"); + dev->accel_out_fifo = mach_combo_accel_out_fifo; + dev->vblank_start = mach_combo_vblank_start; + + *reset_state = *mach; + return mach; } @@ -6315,9 +6995,11 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); ati8514_io_set(svga); + mach->accel.cmd_type = -2; mach->mca_bus = !!(dev->type & DEVICE_MCA); + dev->accel.cmd_back = 1; - mach->config1 = 0x02 | 0x08 | 0x80; + mach->config1 = 0x08 | 0x80; if (mach->mca_bus) mach->config1 |= 0x04; @@ -6326,6 +7008,9 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) mach->config1 |= 0x20; mach->config2 = 0x01 | 0x02; + + dev->accel_out_fifo = ati8514_accel_out_fifo; + dev->vblank_start = ati8514_vblank_start; } static int @@ -6373,6 +7058,10 @@ mach_close(void *priv) } svga_close(svga); + + free(reset_state); + reset_state = NULL; + free(mach); } @@ -6479,7 +7168,7 @@ const device_t mach8_vga_isa_device = { .local = 1, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = mach8_vga_available, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, @@ -6493,7 +7182,7 @@ const device_t mach32_isa_device = { .local = 2, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = mach32_isa_available, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, @@ -6507,7 +7196,7 @@ const device_t mach32_vlb_device = { .local = 2, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = mach32_vlb_available, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, @@ -6521,7 +7210,7 @@ const device_t mach32_mca_device = { .local = 2, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = mach32_mca_available, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, @@ -6535,7 +7224,7 @@ const device_t mach32_pci_device = { .local = 2, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = mach32_pci_available, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, @@ -6549,7 +7238,7 @@ const device_t mach32_onboard_pci_device = { .local = 2 | 0x100, .init = mach8_init, .close = mach_close, - .reset = NULL, + .reset = mach_reset, .available = NULL, .speed_changed = mach_speed_changed, .force_redraw = mach_force_redraw, From 1c98437e664918c05e66e4d664ae061fc0374bb0 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 29 Mar 2025 14:49:13 +0100 Subject: [PATCH 0619/1190] More display changes. SVGA related: If CRTC1/HDISP is odd (if bit 0 is set), then make it even accordingly, else leave it as is. Should fix some display skews. S3 related: Remove old code references (can still be accessed through history if one needs it). 8514/A compatible related: Proper use of the htotal and hdisp timings. --- src/video/vid_s3.c | 177 +------------------------------------------ src/video/vid_svga.c | 10 ++- 2 files changed, 8 insertions(+), 179 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 769cd0001..ef21b18df 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -3519,34 +3519,6 @@ s3_recalctimings(svga_t *svga) } } -#ifdef OLD_CODE_REFERENCE - if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_MIROCRYSTAL8S_805 || s3->card_type == S3_NUMBER9_9FX_531 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { - if (!(svga->crtc[0x5e] & 0x04)) - svga->vblankstart = svga->dispend; - if (svga->bpp != 32) { - if (svga->crtc[0x31] & 2) - s3->width = 2048; - else { - if (s3->card_type == S3_MIROCRYSTAL10SD_805) { - if (svga->hdisp == 1280 && s3->width == 1024) { - s3->width = 1280; - } - } - } - } else { - if (s3->card_type == S3_NUMBER9_9FX_531) { - if ((svga->hdisp == 1600) && (s3->width == 1600)) - s3->width = 800; - } - } - } else if (s3->chip == S3_86C928) { - if (svga->bpp == 15) { - if (s3->width == 800) - s3->width = 1024; - } - } -#endif - if ((svga->crtc[0x3a] & 0x10) && !svga->lowres) { s3_log("BPP=%d, pitch=%d, width=%02x, double?=%x, 16bit?=%d, highres?=%d, " "attr=%02x, hdisp=%d.\n", svga->bpp, s3->width, svga->crtc[0x50], @@ -3665,29 +3637,6 @@ s3_recalctimings(svga_t *svga) default: break; } -#ifdef OLD_CODE_REFERENCE - if (s3->chip != S3_VISION868) { - if (s3->chip == S3_86C928) { - if (s3->width == 2048 || s3->width == 1280 || s3->width == 1600) { - if ((s3->width != 1600) && (svga->dispend == 1024) && (svga->hdisp != 1280)) - svga->hdisp <<= 2; - else - svga->hdisp <<= 1; - } - } else if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968)) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - } else if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - } else if (s3->card_type == S3_SPEA_MERCURY_P64V) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - } - } else if (s3->card_type == S3_NUMBER9_9FX_771) - svga->hdisp <<= 1; - } -#endif break; case 15: svga->render = svga_render_15bpp_highres; @@ -3856,29 +3805,6 @@ s3_recalctimings(svga_t *svga) default: break; } -#ifdef OLD_CODE_REFERENCE - if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && (s3->card_type != S3_SPEA_MIRAGE_86C805)) { - if (s3->chip == S3_86C928) - svga->hdisp <<= 1; - else if (s3->chip != S3_VISION968) - svga->hdisp >>= 1; - } - if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - else if (s3->card_type == S3_NUMBER9_9FX_771) - svga->hdisp <<= 1; - } - if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { - if (svga->hdisp == (1408 * 2)) - svga->hdisp >>= 1; - else - svga->hdisp = s3->width; - } - - if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) - svga->hdisp = s3->width; -#endif break; case 16: svga->render = svga_render_16bpp_highres; @@ -4044,35 +3970,6 @@ s3_recalctimings(svga_t *svga) default: break; } - -#ifdef OLD_CODE_REFERENCE - if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - } - if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && (s3->card_type != S3_SPEA_MIRAGE_86C805)) { - if (s3->chip == S3_86C928) - svga->hdisp <<= 1; - else if (s3->chip != S3_VISION968) - svga->hdisp >>= 1; - } else if ((s3->card_type == S3_SPEA_MIRAGE_86C801) || (s3->card_type == S3_SPEA_MIRAGE_86C805)) - svga->hdisp >>= 1; - if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) { - if (s3->width == 1280 || s3->width == 1600) - svga->hdisp <<= 1; - else if (s3->card_type == S3_NUMBER9_9FX_771) - svga->hdisp <<= 1; - } - if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { - if (svga->hdisp == (1408 << 1)) - svga->hdisp >>= 1; - else - svga->hdisp = s3->width; - } - - if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) - svga->hdisp = s3->width; -#endif break; case 24: svga->render = svga_render_24bpp_highres; @@ -4150,34 +4047,6 @@ s3_recalctimings(svga_t *svga) default: break; } -#ifdef OLD_CODE_REFERENCE - if (s3->chip != S3_VISION968) { - if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805) - svga->hdisp /= 3; - else - svga->hdisp = (svga->hdisp * 2) / 3; - - if (s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { - if (s3->width == 2048) { - switch (svga->dispend) { - case 480: - svga->hdisp = 640; - break; - - default: - break; - } - } - } else if (s3->chip == S3_86C924) { - if (svga->dispend == 480) - svga->hdisp = 640; - } - } else { - if ((s3->card_type == S3_MIROVIDEO40SV_ERGO_968) || - (s3->card_type == S3_PHOENIX_VISION968) || (s3->card_type == S3_SPEA_MERCURY_P64V)) - svga->hdisp = s3->width; - } -#endif break; case 32: svga->render = svga_render_32bpp_highres; @@ -4262,48 +4131,6 @@ s3_recalctimings(svga_t *svga) default: break; } -#ifdef OLD_CODE_REFERENCE - if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968) && (s3->chip != S3_86C928)) { - if (s3->chip == S3_VISION868) - svga->hdisp >>= 1; - else - svga->hdisp >>= 2; - } - if (s3->width == 1280 || s3->width == 1600 || (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_NUMBER9_9FX_771)) - svga->hdisp <<= 1; - if (s3->card_type == S3_NUMBER9_9FX_771) { - if (svga->hdisp == 832) - svga->hdisp -= 32; - } - if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { - svga->hdisp = s3->width; - if (s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964) { - if (s3->width == 800 || s3->width == 1024 || s3->width == 1600) { - switch (svga->dispend) { - case 400: - case 480: - svga->hdisp = 640; - break; - - case 576: - if (s3->width == 1600) - s3->width = 800; - svga->hdisp = 768; - break; - - case 600: - if (s3->width == 1600) - s3->width = 800; - svga->hdisp = 800; - break; - - default: - break; - } - } - } - } -#endif break; default: @@ -4362,7 +4189,7 @@ s3_trio64v_recalctimings(svga_t *svga) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * svga->dots_per_clock; + svga->hdisp |= (0x100 * svga->dots_per_clock); } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; @@ -4681,6 +4508,7 @@ s3_trio64_getclock(int clock, void *priv) return 25175000.0; if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; n1 = (svga->seqregs[0x12] & 0x1f) + 2; n2 = ((svga->seqregs[0x12] >> 5) & 0x07); @@ -9523,7 +9351,6 @@ s3_disable_handlers(s3_t *s3) reset_state->bios_rom.mapping = s3->bios_rom.mapping; reset_state->svga.timer = s3->svga.timer; - reset_state->svga.timer8514 = s3->svga.timer8514; memset(s3->svga.vram, 0x00, s3->svga.vram_max + 8); memset(s3->svga.changedvram, 0x00, (s3->svga.vram_max >> 12) + 1); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index c7a65120f..a44838d68 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -739,7 +739,8 @@ svga_recalctimings(svga_t *svga) svga->vblankstart++; svga->hdisp = svga->crtc[1]; - svga->hdisp++; + if (svga->crtc[1] & 1) + svga->hdisp++; svga->htotal = svga->crtc[0]; /* +5 has been verified by Sergi to be correct - +6 must have been an off by one error. */ @@ -944,7 +945,7 @@ svga_recalctimings(svga_t *svga) if (dev->on) { uint32_t dot8514 = dev->h_blankstart; uint32_t adj_dot8514 = dev->h_blankstart; - uint32_t eff_mask8514 = 0x0000003f; + uint32_t eff_mask8514 = 0x0000001f; dev->hblank_sub = 0; while (adj_dot8514 < (dev->h_total << 1)) { @@ -1029,8 +1030,9 @@ svga_recalctimings(svga_t *svga) if (ibm8514_active && (svga->dev8514 != NULL)) { if (dev->on) { - disptime8514 = dev->h_total ? dev->h_total : TIMER_USEC; - _dispontime8514 = dev->hdisped; + disptime8514 = dev->h_total; + _dispontime8514 = (dev->hdisped + 1) * 8; + svga_log("HDISPED 8514=%d, htotal=%02x.\n", (dev->hdisped + 1) << 3, dev->h_total); } } From 8cc6f215362436aa72be5b1002ab830058a0602f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 18:32:41 +0100 Subject: [PATCH 0620/1190] PB450: Fix the default BIOS selection, fixes segmentation fault. --- src/machine/m_at_386dx_486.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 19c4b535e..639233e10 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -691,12 +691,12 @@ static const device_config_t pb450_config[] = { .name = "bios", .description = "BIOS Version", .type = CONFIG_BIOS, - .default_string = "pci10a", + .default_string = "pb450a", .default_int = 0, .file_filter = "", .spinner = { 0 }, .bios = { - { .name = "PCI 1.0A", .internal_name = "pb450" /*"pci10a"*/, .bios_type = BIOS_NORMAL, + { .name = "PCI 1.0A", .internal_name = "pb450a" /*"pci10a"*/, .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/OPTI802.bin", "" } }, { .name = "PNP 1.1A", .internal_name = "pnp11a", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/PNP11A.bin", "" } }, @@ -732,7 +732,7 @@ machine_at_pb450_init(const machine_t *model) return ret; device_context(model->device); - fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); ret = bios_load_linear(fn, 0x000e0000, 131072, 0); device_context_restore(); From 99c81fe03d640f06d16682e67ad84110bcfa9406 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 18:36:33 +0100 Subject: [PATCH 0621/1190] IBM PC/XT/AT and PB450: Remove "Device" from machine device_t names. --- src/machine/m_at.c | 4 ++-- src/machine/m_at_386dx_486.c | 2 +- src/machine/m_xt.c | 12 ++++++------ src/machine/m_xt_laserxt.c | 11 +++++++---- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 3f5e88011..8a561630c 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -187,7 +187,7 @@ static const device_config_t ibmat_config[] = { }; const device_t ibmat_device = { - .name = " IBM AT Devices", + .name = "IBM AT", .internal_name = "ibmat_device", .flags = 0, .local = 0, @@ -294,7 +294,7 @@ static const device_config_t ibmxt286_config[] = { }; const device_t ibmxt286_device = { - .name = "IBM XT Model 286 Devices", + .name = "IBM XT Model 286", .internal_name = "ibmxt286_device", .flags = 0, .local = 0, diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 639233e10..0ee353f53 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -708,7 +708,7 @@ static const device_config_t pb450_config[] = { }; const device_t pb450_device = { - .name = "Packard Bell PB450 Devices", + .name = "Packard Bell PB450", .internal_name = "pb450_device", .flags = 0, .local = 0, diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 78d2daa13..13f9c52ca 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -108,7 +108,7 @@ static const device_config_t ibmpc_config[] = { }; const device_t ibmpc_device = { - .name = "IBM PC (1981) Device", + .name = "IBM PC (1981)", .internal_name = "ibmpc_device", .flags = 0, .local = 0, @@ -218,7 +218,7 @@ static const device_config_t ibmpc82_config[] = { }; const device_t ibmpc82_device = { - .name = "IBM PC (1982) Devices", + .name = "IBM PC (1982)", .internal_name = "ibmpc82_device", .flags = 0, .local = 0, @@ -331,7 +331,7 @@ static const device_config_t ibmxt_config[] = { }; const device_t ibmxt_device = { - .name = "IBM XT (1982) Device", + .name = "IBM XT (1982)", .internal_name = "ibmxt_device", .flags = 0, .local = 0, @@ -451,7 +451,7 @@ static const device_config_t ibmxt86_config[] = { }; const device_t ibmxt86_device = { - .name = "IBM XT (1986) Device", + .name = "IBM XT (1986)", .internal_name = "ibmxt86_device", .flags = 0, .local = 0, @@ -624,7 +624,7 @@ static const device_config_t jukopc_config[] = { }; const device_t jukopc_device = { - .name = "Juko ST Devices", + .name = "Juko ST", .internal_name = "jukopc_device", .flags = 0, .local = 0, @@ -949,7 +949,7 @@ static const device_config_t vendex_config[] = { }; const device_t vendex_device = { - .name = "Vendex 888T Devices", + .name = "Vendex 888T", .internal_name = "vendex_device", .flags = 0, .local = 0, diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 877d26ff5..595cce1ca 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -154,6 +154,8 @@ machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3) standalone_gameport_type = &gameport_device; laserxt_init(is_lxt3); + + device_add(&keyboard_xt_lxt3_device); } int @@ -167,8 +169,6 @@ machine_xt_laserxt_init(const machine_t *model) if (bios_only || !ret) return ret; - device_add(&keyboard_xt_device); - machine_xt_laserxt_common_init(model, 0); return ret; @@ -179,14 +179,17 @@ machine_xt_lxt3_init(const machine_t *model) { int ret; +#if 0 ret = bios_load_linear("roms/machines/lxt3/27c64d.bin", 0x000fe000, 8192, 0); +#else + ret = bios_load_linear("roms/machines/lxt3/vtech-laser-xt3-bios-v1-26-27c64-637cfbe96dfa1809192278.bin", + 0x000fe000, 8192, 0); +#endif if (bios_only || !ret) return ret; - device_add(&keyboard_xt_lxt3_device); - machine_xt_laserxt_common_init(model, 1); return ret; From c1ecafaeb55e597e068ad61a8a563d5162e81019 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 18:38:20 +0100 Subject: [PATCH 0622/1190] IBM PS/1 Model 2011: No need to explicitly refer to the zeroth element of the config array. --- src/machine/m_ps1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 41821a4a8..07128f157 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -290,7 +290,7 @@ const device_t ps1_2011_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, - .config = &ps1_2011_config[0] + .config = &ps1_2011_config }; static void From e48c6c8e8bd631471b45052c69270249e5193baa Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 18:40:27 +0100 Subject: [PATCH 0623/1190] Laser XT3: No longer use the other BIOS that has not yet been committed. --- src/machine/m_xt_laserxt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 595cce1ca..c0405f99a 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -179,13 +179,8 @@ machine_xt_lxt3_init(const machine_t *model) { int ret; -#if 0 ret = bios_load_linear("roms/machines/lxt3/27c64d.bin", 0x000fe000, 8192, 0); -#else - ret = bios_load_linear("roms/machines/lxt3/vtech-laser-xt3-bios-v1-26-27c64-637cfbe96dfa1809192278.bin", - 0x000fe000, 8192, 0); -#endif if (bios_only || !ret) return ret; From 8b646ccc49a5d6b4f0e7ce9ccf7042d7d89c14f2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 18:47:21 +0100 Subject: [PATCH 0624/1190] Fix a compile-breaking mistake in machine/m_ps1.c. --- src/machine/m_ps1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 07128f157..c22463de4 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -290,7 +290,7 @@ const device_t ps1_2011_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, - .config = &ps1_2011_config + .config = ps1_2011_config }; static void From b6b840b67ec8f680d69d0672e49b8a0e6fd851df Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 19:54:48 +0100 Subject: [PATCH 0625/1190] Recognize 8514/a-type cards as (S)VGA for the purposes of force 4:3 calculations, fixes blurry picture and wrong resolution. --- src/86box.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/86box.c b/src/86box.c index 2b6e1ba9f..ad1cfc519 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1624,6 +1624,8 @@ set_screen_size_monitor(int x, int y, int monitor_index) { int temp_overscan_x = monitors[monitor_index].mon_overscan_x; int temp_overscan_y = monitors[monitor_index].mon_overscan_y; + int is_svga = (video_get_type_monitor(monitor_index) == VIDEO_FLAG_TYPE_SPECIAL) || + (video_get_type_monitor(monitor_index) == VIDEO_FLAG_TYPE_8514); double dx; double dy; double dtx; @@ -1657,19 +1659,19 @@ set_screen_size_monitor(int x, int y, int monitor_index) dty = (double) temp_overscan_y; /* Account for possible overscan. */ - if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y == 16)) { + if (!is_svga && (temp_overscan_y == 16)) { /* CGA */ dy = (((dx - dtx) / 4.0) * 3.0) + dty; - } else if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y < 16)) { + } else if (!is_svga && (temp_overscan_y < 16)) { /* MDA/Hercules */ - dy = (x / 4.0) * 3.0; + dy = (dx / 4.0) * 3.0; } else { if (enable_overscan) { /* EGA/(S)VGA with overscan */ dy = (((dx - dtx) / 4.0) * 3.0) + dty; } else { /* EGA/(S)VGA without overscan */ - dy = (x / 4.0) * 3.0; + dy = (dx / 4.0) * 3.0; } } monitors[monitor_index].mon_unscaled_size_y = (int) dy; From 5a4a939e02cca97d9f35d3cf4581a89ed87bc3ac Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 29 Mar 2025 20:27:20 +0100 Subject: [PATCH 0626/1190] More fixes to the 8514/A compatible side. 1. Use proper identification to what chips use what. 2. Apply some mode switch fixes to the ATI 8514/A Ultra and make 1024x768 87Hz interlaced the default mode if htotal is 0 and on ati8514_init. 3. Add the undocumented ports to the ATI 8514/A Ultra add-on as well. --- src/include/86box/vid_8514a.h | 5 ++ src/video/vid_8514a.c | 5 +- src/video/vid_ati_mach8.c | 160 ++++++++++++++++++++-------------- src/video/vid_svga.c | 6 +- 4 files changed, 103 insertions(+), 73 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index 153bface4..a467311ca 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -250,4 +250,9 @@ typedef struct ibm8514_t { } ibm8514_t; +#define IBM_8514A (((dev->local & 0xff) == 0x00) && (dev->extensions == 0x00)) +#define ATI_8514A_ULTRA (((dev->local & 0xff) == 0x00) && (dev->extensions == 0x01)) +#define ATI_GRAPHICS_ULTRA ((dev->local & 0xff) == 0x01) +#define ATI_MACH32 ((dev->local & 0xff) == 0x02) + #endif /*VIDEO_8514A_H*/ diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index efb05a307..df4cd7d9a 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -3846,10 +3846,7 @@ ibm8514_recalctimings(svga_t *svga) else svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0; - if (dev->dispend == 766) - dev->dispend += 2; - - if (dev->dispend == 478) + if ((dev->dispend == 478) || (dev->dispend == 766)) dev->dispend += 2; if (dev->interlace) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 9f1bb99d6..ba32dc129 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2250,7 +2250,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; - if (((dev->disp_cntl & 0x60) == 0x20) && ((dev->local & 0xff) >= 0x02)) { + if (((dev->disp_cntl & 0x60) == 0x20) && ATI_MACH32) { if ((addr >= 0x3c6) && (addr <= 0x3c9)) { mach_log("VGA DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); @@ -2281,7 +2281,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) } break; case 0xad: - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if ((old ^ val) & 0x0c) { mach_log("ATI AD bits 2-3.\n"); svga_recalctimings(svga); @@ -2301,14 +2301,14 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (mach->regs[0xbe] & 0x08) { /* Read/write bank mode */ mach->bank_r = (((mach->regs[0xb2] & 1) << 3) | ((mach->regs[0xb2] & 0xe0) >> 5)); mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2); mach->bank_w |= ((mach->regs[0xae] & 3) << 4); } mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); } else { /* Single bank mode */ mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) mach->bank_w |= ((mach->regs[0xae] & 3) << 4); mach->bank_r = mach->bank_w; @@ -2338,7 +2338,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) } break; case 0xb8: - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if ((old ^ val) & 0x40) { mach_log("ATI B8 bit 6.\n"); svga_recalctimings(svga); @@ -2367,7 +2367,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); mach_log("8514/A RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->regs[0xb0] & 0x20) { /*ATI extended 8514/A mode.*/ mach_log("Extended 8514/A mode.\n"); dev->vendor_mode = 1; @@ -2394,7 +2394,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) rs2 = !!(mach->regs[0xa0] & 0x20); rs3 = !!(mach->regs[0xa0] & 0x40); mach_log("VGA RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (svga->attrregs[0x10] & 0x40) { mach_log("VGA mode.\n"); dev->vendor_mode = 0; @@ -2495,7 +2495,7 @@ mach_in(uint16_t addr, void *priv) case 0xb0: temp = mach->regs[0xb0] | 0x80; temp &= ~0x18; - if ((dev->local & 0xff) >= 0x02) { /*Mach32 VGA 1MB memory*/ + if (ATI_MACH32) { /*Mach32 VGA 1MB memory*/ temp |= 0x08; } else { /*ATI 28800 VGA 512kB memory*/ temp |= 0x10; @@ -2524,7 +2524,7 @@ mach_in(uint16_t addr, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (dev->on) temp = svga_in(addr, svga); else { @@ -2669,6 +2669,9 @@ mach_set_resolution(mach_t *mach, svga_t *svga) ibm8514_t *dev = (ibm8514_t *) svga->dev8514; dev->hdisp = (dev->hdisped + 1) << 3; + if (!dev->htotal) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ + dev->htotal = 0x9d; + dev->h_total = dev->htotal + 1; dev->vdisp = (dev->v_disp + 1) >> 1; @@ -2693,6 +2696,16 @@ mach_set_resolution(mach_t *mach, svga_t *svga) dev->vdisp = 480; svga_recalctimings(svga); } + } else { + if (ATI_8514A_ULTRA) { + if (dev->accel.advfunc_cntl & 0x04) { + if (dev->hdisp == 640) { + dev->hdisp = 1024; + dev->vdisp = 768; + svga_recalctimings(svga); + } + } + } } } } @@ -2712,7 +2725,7 @@ ati8514_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; - mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", + pclog("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); dev->h_disp = dev->hdisp; @@ -2756,7 +2769,7 @@ mach_recalctimings(svga_t *svga) clock_sel = ((svga->miscout >> 2) & 3) | ((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->regs[0xad] & 0x04) svga->ma_latch |= 0x40000; @@ -2785,7 +2798,7 @@ mach_recalctimings(svga_t *svga) } else svga->packed_4bpp = 0; - if ((dev->local & 0xff) < 0x02) { + if (!ATI_MACH32) { if ((mach->regs[0xb6] & 0x18) == 0x08) { svga->hdisp <<= 1; svga->htotal <<= 1; @@ -2823,7 +2836,7 @@ mach_recalctimings(svga_t *svga) if (dev->interlace) dev->dispend >>= 1; - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace, svga->hdisp); @@ -2913,7 +2926,7 @@ mach_recalctimings(svga_t *svga) if ((svga->gdcreg[5] & 0x40) || (svga->attrregs[0x10] & 0x40) || (mach->regs[0xb0] & 0x20)) { svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); mach_log("VGA clock=%02x.\n", mach->regs[0xa7] & 0x80); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->regs[0xb8] & 0x40) svga->clock *= 2; } else { @@ -2960,7 +2973,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u switch (port) { case 0x2e8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) dev->htotal = val; @@ -2969,7 +2982,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xae8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_start, val); } @@ -2978,7 +2991,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xee8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_width, val); } @@ -2995,14 +3008,17 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x6e8: if (len == 2) { mach_log("HDISP and HTOTAL=%04x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x08)) { - WRITE8(port, dev->hdisped, val); + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if (!(mach->shadow_cntl & 0x08)) { + WRITE8(port, dev->hdisped, val); + } } - if (!(mach->shadow_cntl & 0x04)) - dev->htotal = (val >> 8) & 0xff; - + if (ATI_8514A_ULTRA) { + if (!(mach->shadow_cntl & 0x04)) + dev->htotal = (val >> 8) & 0xff; + } mach_set_resolution(mach, svga); } } else { @@ -3029,7 +3045,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x6e9: if (len == 1) { mach_log("HDISP and HTOTAL+1=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) { dev->htotal = val; } @@ -3040,7 +3056,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x12e8: if (len == 2) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x10)) { dev->v_total_reg = val; dev->v_total_reg &= 0x1fff; @@ -3048,7 +3064,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_set_resolution(mach, svga); } } else { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x10)) { WRITE8(port, dev->v_total_reg, val); dev->v_total_reg &= 0x1fff; @@ -3061,7 +3077,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x12e9: if (len == 1) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ WRITE8(port, dev->v_total_reg, val); dev->v_total_reg &= 0x1fff; @@ -3109,7 +3125,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x1ae8: if (len == 2) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ dev->v_sync_start = val; dev->v_sync_start &= 0x1fff; @@ -3119,7 +3135,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); } else { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; @@ -3130,7 +3146,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x1ae9: if (len == 1) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; @@ -3181,12 +3197,12 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); - if ((dev->local & 0xff) < 0x02) { - dev->ext_crt_pitch = 128; - mach_set_resolution(mach, svga); - } else { + if (ATI_MACH32) { mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); + } else { + dev->ext_crt_pitch = 128; + mach_set_resolution(mach, svga); } mach_log("Vendor IBM mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); break; @@ -3390,7 +3406,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { if ((dev->accel.multifunc_cntl >> 12) == 5) { - if ((dev->local & 0xff) < 0x02) + if (!ATI_MACH32) dev->ext_crt_pitch = 128; } } @@ -3514,12 +3530,12 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else dev->ext_crt_pitch <<= 1; } - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { dev->on |= 0x01; dev->vendor_mode = 1; } svga_recalctimings(svga); - if ((dev->local & 0xff) >= 0x01) + if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode=%02x.\n", port, val, dev->ext_crt_pitch, len, mach->regs[0xb0] & 0x20); @@ -3548,17 +3564,17 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->local_cntl, val); } - if ((dev->local & 0xff) >= 0x01) + if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); break; case 0x36ee: case 0x36ef: if (len == 2) { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) mach->misc = val; } else { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) WRITE8(port, mach->misc, val); } mach->misc &= 0xfff0; @@ -3621,7 +3637,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("Vendor ATI mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); svga_recalctimings(svga); - if ((dev->local & 0xff) >= 0x01) + if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); break; @@ -3675,7 +3691,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (!mach->pci_bus) mach->linear_base = (mach->memory_aperture & 0xff00) << 12; - if ((dev->local & 0xff) >= 0x01) + if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); break; @@ -3729,7 +3745,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->accel.ext_ge_config, val); } - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->accel.crt_pitch & 0xff) dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; @@ -4407,46 +4423,46 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0xdaee: if (len == 2) { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_x; } else { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_x & 0xff; } break; case 0xdaef: if (len == 1) { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_x >> 8; } break; case 0xdeee: if (len == 2) { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_y; } else { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_y & 0xff; } break; case 0xdeef: if (len == 1) { - if ((dev->local & 0xff) >= 0x02) + if (ATI_MACH32) temp = mach->accel.src_y >> 8; } break; case 0xfaee: if (len == 2) { - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->pci_bus) temp = 0x0017; else temp = 0x22f7; } } else { - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->pci_bus) temp = 0x17; else @@ -4456,7 +4472,7 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in break; case 0xfaef: if (len == 1) { - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->pci_bus) temp = 0x00; else @@ -4604,7 +4620,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x36ee: case 0x36ef: - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { READ8(port, mach->misc); if (!(port & 1)) { temp &= ~0x0c; @@ -5148,7 +5164,7 @@ mach32_write(uint32_t addr, uint8_t val, void *priv) return; } - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; switch (addr & 0x06) { case 0x00: @@ -5188,7 +5204,7 @@ mach32_writew(uint32_t addr, uint16_t val, void *priv) return; } - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; if (addr & 0x04) { mach32_write_common(addr - 2, val & 0x0f, 0, mach, svga); @@ -5223,7 +5239,7 @@ mach32_writel(uint32_t addr, uint32_t val, void *priv) return; } - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; mach32_write_common(addr, val & 0x0f, 0, mach, svga); mach32_write_common(addr + 1, (val >> 4) & 0x0f, 0, mach, svga); @@ -5639,7 +5655,7 @@ mach32_read(uint32_t addr, void *priv) (void) xga_read_test(addr, svga); addr = (addr & svga->banked_mask) + svga->read_bank; - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; switch (addr & 0x06) { case 0x00: @@ -5676,7 +5692,7 @@ mach32_readw(uint32_t addr, void *priv) (void) xga_read_test(addr, svga); addr = (addr & svga->banked_mask) + svga->read_bank; - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; if (addr & 0x04) { ret = mach32_read_common(addr - 2, 0, mach, svga) & 0x0f; @@ -5708,7 +5724,7 @@ mach32_readl(uint32_t addr, void *priv) (void) xga_read_test(addr, svga); addr = (addr & svga->banked_mask) + svga->read_bank; - if ((((dev->local & 0xff) >= 0x02) && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; ret = mach32_read_common(addr, 0, mach, svga) & 0x0f; ret |= (mach32_read_common(addr + 1, 0, mach, svga) << 4); @@ -5998,7 +6014,7 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; - if (((dev->local & 0xff) >= 0x02) && !(dev->accel.advfunc_cntl & 0x01) && !(mach->accel.clock_sel & 0x01)) { + if (ATI_MACH32 && !(dev->accel.advfunc_cntl & 0x01) && !(mach->accel.clock_sel & 0x01)) { if ((svga->gdcreg[6] & 0x01) || (svga->attrregs[0x10] & 0x01)) { if (svga->attrregs[0x10] & 0x40) { dev->vendor_mode = 0; @@ -6035,7 +6051,7 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) mem_mapping_disable(&mach->mmio_linear_mapping); } - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (dev->on && dev->vendor_mode) { mach_log("Mach32 banked mapping.\n"); mem_mapping_disable(&svga->mapping); @@ -6216,6 +6232,7 @@ ati8514_io_set(svga_t *svga) io_sethandler(0x7eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0x82ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0x86ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); + io_sethandler(0x8aee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0x8eee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0x92ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0x96ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); @@ -6238,6 +6255,7 @@ ati8514_io_set(svga_t *svga) io_sethandler(0xdeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xe2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xe6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); + io_sethandler(0xeaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xeeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); @@ -6331,6 +6349,7 @@ mach_io_remove(mach_t *mach) io_removehandler(0x7eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0x82ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0x86ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); + io_removehandler(0x8aee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0x8eee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0x92ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0x96ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); @@ -6353,6 +6372,7 @@ mach_io_remove(mach_t *mach) io_removehandler(0xdeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0xe2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0xe6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); + io_removehandler(0xeaee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0xeeee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0xf2ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); io_removehandler(0xf6ee, 0x0002, mach_accel_inb, mach_accel_inw, mach_accel_inl, mach_accel_outb, mach_accel_outw, mach_accel_outl, mach); @@ -6817,7 +6837,7 @@ mach8_init(const device_t *info) dev->vram_512k_8514 = dev->vram_amount == 512; dev->accel.cmd_back = 1; - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { if (mach->pci_bus) { if (mach->has_bios) { rom_init(&mach->bios_rom, @@ -6852,7 +6872,7 @@ mach8_init(const device_t *info) 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { svga_init(info, svga, mach, dev->vram_amount << 10, /*default: 2MB for Mach32*/ mach_recalctimings, mach_in, mach_out, @@ -6940,7 +6960,7 @@ mach8_init(const device_t *info) mach_io_set(mach); mach->accel.cmd_type = -2; - if ((dev->local & 0xff) >= 0x02) { + if (ATI_MACH32) { svga->decode_mask = (4 << 20) - 1; mach->cursor_col_1 = 0xff; mach->ext_cur_col_1_r = 0xff; @@ -6985,13 +7005,21 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) mach_t *mach = (mach_t *) ext8514; ibm8514_t *dev = (ibm8514_t *) dev8514; + /*Init as 1024x768 87hz interlaced first, per 8514/A.*/ dev->on = 0; dev->ext_pitch = 1024; dev->ext_crt_pitch = 0x80; dev->accel_bpp = 8; dev->rowoffset = 0x80; - dev->hdisp = 1024; - dev->vdisp = 768; + dev->hdisped = 0x7f; + dev->v_disp = 0x05ff; + dev->htotal = 0x9d; + dev->v_total_reg = 0x0668; + dev->v_sync_start = 0x0600; + dev->disp_cntl = 0x33; + mach->accel.clock_sel = 0x1c; + mach->shadow_set = 0x02; + mach->resolution_crt = 0x02; io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); ati8514_io_set(svga); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index a44838d68..8d1535dda 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -904,7 +904,7 @@ svga_recalctimings(svga_t *svga) svga->recalctimings_ex(svga); if (ibm8514_active && (svga->dev8514 != NULL)) { - if ((dev->local & 0xff) == 0x00) + if (IBM_8514A || ATI_8514A_ULTRA) ibm8514_recalctimings(svga); } @@ -1031,8 +1031,8 @@ svga_recalctimings(svga_t *svga) if (ibm8514_active && (svga->dev8514 != NULL)) { if (dev->on) { disptime8514 = dev->h_total; - _dispontime8514 = (dev->hdisped + 1) * 8; - svga_log("HDISPED 8514=%d, htotal=%02x.\n", (dev->hdisped + 1) << 3, dev->h_total); + _dispontime8514 = dev->h_disp; + svga_log("HTOTAL=%d, HDISP=%d.\n", dev->h_total, dev->h_disp); } } From ef588c118a1123161a8ee3ba7790c58686627487 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 29 Mar 2025 20:36:00 +0100 Subject: [PATCH 0627/1190] Fixed log excess. --- src/video/vid_8514a.c | 4 ++-- src/video/vid_ati_mach8.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index df4cd7d9a..393b90b57 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -357,13 +357,13 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0xae8: WRITE8(port, dev->hsync_start, val); - pclog("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_start=%d.\n", port, val, (val + 1) << 3); + ibm8514_log("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_start=%d.\n", port, val, (val + 1) << 3); svga_recalctimings(svga); break; case 0xee8: WRITE8(port, dev->hsync_width, val); - pclog("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_width=%d, hsyncpol=%02x.\n", port, val & 0x1f, ((val & 0x1f) + 1) << 3, val & 0x20); + ibm8514_log("IBM 8514/A compatible: (0x%04x): val=0x%02x, hsync_width=%d, hsyncpol=%02x.\n", port, val & 0x1f, ((val & 0x1f) + 1) << 3, val & 0x20); svga_recalctimings(svga); break; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index ba32dc129..c21730497 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2725,7 +2725,7 @@ ati8514_recalctimings(svga_t *svga) dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; - pclog("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", + mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); dev->h_disp = dev->hdisp; From eeab2fe4090a75999bfdedb6ded9f4c82371ffbc Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 29 Mar 2025 20:56:06 +0100 Subject: [PATCH 0628/1190] NE2000 Compatibles: Store the UI correctly. --- src/network/net_ne2000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 71e5c2ca7..e45b55b22 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1071,7 +1071,7 @@ nic_init(const device_t *info) mac_oui = (((int) dev->maclocal[0]) << 16); mac_oui |= (((int) dev->maclocal[1]) << 8); mac_oui |= ((int) dev->maclocal[2]); - device_set_config_mac("mac", mac); + device_set_config_mac("mac_oui", mac_oui); } else { dev->maclocal[0] = (mac_oui >> 16) & 0xff; dev->maclocal[1] = (mac_oui >> 8) & 0xff; From 90464f7914d9d2ea0e99541f2729f2787e9d6c51 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 03:12:55 +0200 Subject: [PATCH 0629/1190] OKI IF386AX: Default NVR to 0x00's instead of 0xFF's, in order to default it to CRT instead of LCD. --- src/device/serial.c | 3 +-- src/machine/m_at_286_386sx.c | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/device/serial.c b/src/device/serial.c index 8483f7fe3..deb97225a 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -999,8 +999,7 @@ void serial_standalone_init(void) { while (next_inst < SERIAL_MAX) - device_add_inst(!strcmp(machine_get_internal_name(), "if386sx") ? &ns16450_device : - &ns8250_device, next_inst + 1); + device_add_inst(&ns8250_device, next_inst + 1); }; const device_t ns8250_device = { diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 033233955..b084bfbbd 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -653,7 +653,9 @@ machine_at_if386sx_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); /* NVR that is initialized to all 0x00's. */ + device_add(&keyboard_at_phoenix_device); device_add(&neat_sx_device); @@ -663,6 +665,12 @@ machine_at_if386sx_init(const machine_t *model) if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); + /* + One serial port - on the real hardware IF386AX, it is on the VL 16C451, + alognside the bidirectional parallel port. + */ + device_add_inst(&ns16450_device, 1); + return ret; } From 19e01b8ddfb318f892c6f49859d63d19e9d74e2b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 03:40:08 +0200 Subject: [PATCH 0630/1190] UI: Optimize several Settings pages to reduce the amount of iterations and repeated calls to functions where multiple there are multiple instances of the same device type, should further speed up te opening of the Settings dialog. --- src/qt/qt_settingsnetwork.cpp | 78 +++++++++++++----------- src/qt/qt_settingsotherperipherals.cpp | 56 ++++++++++------- src/qt/qt_settingsports.cpp | 59 +++++++++++------- src/qt/qt_settingssound.cpp | 63 ++++++++++--------- src/qt/qt_settingsstoragecontrollers.cpp | 55 ++++++++++------- 5 files changed, 184 insertions(+), 127 deletions(-) diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index a0acd7a3f..9a53411d5 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -137,54 +137,63 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) { this->machineId = machineId; - int c = 0; - int selectedRow = 0; + int c = 0; + int selectedRow = 0; - for (int i = 0; i < NET_CARD_MAX; ++i) { - auto *cbox = findChild(QString("comboBoxNIC%1").arg(i + 1)); - auto *model = cbox->model(); - auto removeRows = model->rowCount(); - c = 0; - selectedRow = 0; + // Network Card + QComboBox * cbox_[NET_CARD_MAX] = { 0 }; + QAbstractItemModel *models[NET_CARD_MAX] = { 0 }; + int removeRows_[NET_CARD_MAX] = { 0 }; + int selectedRows[NET_CARD_MAX] = { 0 }; + int m_has_net = machine_has_flags(machineId, MACHINE_NIC); - while (true) { - /* Skip "internal" if machine doesn't have it or this is not the primary card. */ - if ((c == 1) && ((i > 0) || (machine_has_flags(machineId, MACHINE_NIC) == 0))) { - c++; - continue; - } + for (uint8_t i = 0; i < NET_CARD_MAX; ++i) { + cbox_[i] = findChild(QString("comboBoxNIC%1").arg(i + 1)); + models[i] = cbox_[i]->model(); + removeRows_[i] = models[i]->rowCount(); + } - auto name = DeviceConfig::DeviceName(network_card_getdevice(c), network_card_get_internal_name(c), 1); - if (name.isEmpty()) { - break; - } + c = 0; + while (true) { + const QString name = DeviceConfig::DeviceName(network_card_getdevice(c), + network_card_get_internal_name(c), 1); - if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == net_cards_conf[i].device_num) { - selectedRow = row - removeRows; + if (name.isEmpty()) + break; + + if (network_card_available(c)) { + if (device_is_valid(network_card_getdevice(c), machineId)) { + for (uint8_t i = 0; i < NET_CARD_MAX; ++i) { + if ((c != 1) || ((i == 0) && m_has_net)) { + int row = Models::AddEntry(models[i], name, c); + + if (c == net_cards_conf[i].device_num) + selectedRows[i] = row - removeRows_[i]; + } } } - c++; } - model->removeRows(0, removeRows); - cbox->setEnabled(model->rowCount() > 0); - cbox->setCurrentIndex(-1); - cbox->setCurrentIndex(selectedRow); + c++; + } - cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); - model = cbox->model(); - removeRows = model->rowCount(); + for (uint8_t i = 0; i < NET_CARD_MAX; ++i) { + models[i]->removeRows(0, removeRows_[i]); + cbox_[i]->setEnabled(models[i]->rowCount() > 1); + cbox_[i]->setCurrentIndex(-1); + cbox_[i]->setCurrentIndex(selectedRows[i]); + + auto cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); + auto model = cbox->model(); + auto removeRows = model->rowCount(); Models::AddEntry(model, tr("Null Driver"), NET_TYPE_NONE); Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP); - if (network_ndev > 1) { + if (network_ndev > 1) Models::AddEntry(model, "PCap", NET_TYPE_PCAP); - } - if (network_devmap.has_vde) { + + if (network_devmap.has_vde) Models::AddEntry(model, "VDE", NET_TYPE_VDE); - } model->removeRows(0, removeRows); cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type)); @@ -205,6 +214,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) model->removeRows(0, removeRows); cbox->setCurrentIndex(selectedRow); } + if (net_cards_conf[i].net_type == NET_TYPE_VDE) { QString currentVdeSocket = net_cards_conf[i].host_dev_name; auto editline = findChild(QString("socketVDENIC%1").arg(i+1)); diff --git a/src/qt/qt_settingsotherperipherals.cpp b/src/qt/qt_settingsotherperipherals.cpp index a7db551ad..b780dc1a6 100644 --- a/src/qt/qt_settingsotherperipherals.cpp +++ b/src/qt/qt_settingsotherperipherals.cpp @@ -83,31 +83,45 @@ SettingsOtherPeripherals::onCurrentMachineChanged(int machineId) ui->comboBoxRTC->setCurrentIndex(selectedRow); ui->pushButtonConfigureRTC->setEnabled((isartc_type != 0) && isartc_has_config(isartc_type) && machineHasIsa); - for (int c = 0; c < ISAMEM_MAX; c++) { - auto *cbox = findChild(QString("comboBoxCard%1").arg(c + 1)); - model = cbox->model(); - d = 0; - selectedRow = 0; - while (true) { - QString name = DeviceConfig::DeviceName(isamem_get_device(d), isamem_get_internal_name(d), 0); - if (name.isEmpty()) { - break; - } + // ISA Memory Expansion Card + QComboBox * cbox[ISAMEM_MAX] = { 0 }; + QAbstractItemModel *models[ISAMEM_MAX] = { 0 }; + int removeRows_[ISAMEM_MAX] = { 0 }; + int selectedRows[ISAMEM_MAX] = { 0 }; - if (!device_is_valid(isamem_get_device(d), machineId)) { - break; - } + for (uint8_t c = 0; c < ISAMEM_MAX; ++c) { + cbox[c] = findChild(QString("comboBoxCard%1").arg(c + 1)); + models[c] = cbox[c]->model(); + removeRows_[c] = models[c]->rowCount(); + } - int row = Models::AddEntry(model, name, d); - if (d == isamem_type[c]) { - selectedRow = row; + d = 0; + while (true) { + const QString name = DeviceConfig::DeviceName(isamem_get_device(d), + isamem_get_internal_name(d), 0); + + if (name.isEmpty()) + break; + + if (device_is_valid(isamem_get_device(d), machineId)) { + for (uint8_t c = 0; c < ISAMEM_MAX; ++c) { + int row = Models::AddEntry(models[c], name, d); + + if (d == isamem_type[c]) + selectedRows[c] = row - removeRows_[c]; } - ++d; } - cbox->setCurrentIndex(-1); - cbox->setCurrentIndex(selectedRow); - cbox->setEnabled(machineHasIsa); - findChild(QString("pushButtonConfigureCard%1").arg(c + 1))->setEnabled((isamem_type[c] != 0) && isamem_has_config(isamem_type[c]) && machineHasIsa); + + d++; + } + + for (uint8_t c = 0; c < ISAMEM_MAX; ++c) { + models[c]->removeRows(0, removeRows_[c]); + cbox[c]->setEnabled(models[c]->rowCount() > 1); + cbox[c]->setCurrentIndex(-1); + cbox[c]->setCurrentIndex(selectedRows[c]); + findChild(QString("pushButtonConfigureCard%1").arg(c + 1))->setEnabled((isamem_type[c] != 0) && + isamem_has_config(isamem_type[c]) && machineHasIsa); } } diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index cb1ab794a..f68106dc9 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -73,34 +73,49 @@ SettingsPorts::onCurrentMachineChanged(int machineId) { this->machineId = machineId; - for (int i = 0; i < PARALLEL_MAX; i++) { - auto *cbox = findChild(QString("comboBoxLpt%1").arg(i + 1)); - auto *model = cbox->model(); - const auto removeRows = model->rowCount(); - int c = 0; - int selectedRow = 0; - while (true) { - const char *lptName = lpt_device_get_name(c); - if (lptName == nullptr) { - break; - } + int c = 0; - int row = Models::AddEntry(model, tr(lptName), c); - if (c == lpt_ports[i].device) { - selectedRow = row - removeRows; - } - c++; + // LPT Device + QComboBox * cbox[PARALLEL_MAX] = { 0 }; + QAbstractItemModel *models[PARALLEL_MAX] = { 0 }; + int removeRows_[PARALLEL_MAX] = { 0 }; + int selectedRows[PARALLEL_MAX] = { 0 }; + + for (uint8_t i = 0; i < PARALLEL_MAX; ++i) { + cbox[i] = findChild(QString("comboBoxLpt%1").arg(i + 1)); + models[i] = cbox[i]->model(); + removeRows_[i] = models[i]->rowCount(); + } + + while (true) { + const char *lptName = lpt_device_get_name(c); + + if (lptName == nullptr) + break; + + const QString name = tr(lptName); + + for (uint8_t i = 0; i < PARALLEL_MAX; ++i) { + int row = Models::AddEntry(models[i], name, c); + + if (c == lpt_ports[i].device) + selectedRows[i] = row - removeRows_[i]; } - model->removeRows(0, removeRows); - cbox->setEnabled(model->rowCount() > 0); - cbox->setCurrentIndex(-1); - cbox->setCurrentIndex(selectedRow); + + c++; + } + + for (uint8_t i = 0; i < PARALLEL_MAX; ++i) { + models[i]->removeRows(0, removeRows_[i]); + cbox[i]->setEnabled(models[i]->rowCount() > 1); + cbox[i]->setCurrentIndex(-1); + cbox[i]->setCurrentIndex(selectedRows[i]); auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); if (checkBox != NULL) checkBox->setChecked(lpt_ports[i].enabled > 0); - if (cbox != NULL) - cbox->setEnabled(lpt_ports[i].enabled > 0); + if (cbox[i] != NULL) + cbox[i]->setEnabled(lpt_ports[i].enabled > 0); } for (int i = 0; i < SERIAL_MAX; i++) { diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index cca903076..3e1240888 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -73,46 +73,51 @@ SettingsSound::onCurrentMachineChanged(const int machineId) { this->machineId = machineId; - int c; - int selectedRow; + int c; + int selectedRow; // Sound Card + QComboBox * cbox[SOUND_CARD_MAX] = { 0 }; + QAbstractItemModel *models[SOUND_CARD_MAX] = { 0 }; + int removeRows_[SOUND_CARD_MAX] = { 0 }; + int selectedRows[SOUND_CARD_MAX] = { 0 }; + int m_has_snd = machine_has_flags(machineId, MACHINE_SOUND); + for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { - QComboBox *cbox = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); - c = 0; - auto model = cbox->model(); - auto removeRows = model->rowCount(); - selectedRow = 0; + cbox[i] = findChild(QString("comboBoxSoundCard%1").arg(i + 1)); + models[i] = cbox[i]->model(); + removeRows_[i] = models[i]->rowCount(); + } - while (true) { - /* Skip "internal" if machine doesn't have it or this is not the primary card. */ - if ((c == 1) && ((i > 0) || (machine_has_flags(machineId, MACHINE_SOUND) == 0))) { - c++; - continue; - } + c = 0; + while (true) { + const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), + sound_card_get_internal_name(c), 1); - const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), sound_card_get_internal_name(c), 1); - if (name.isEmpty()) { - break; - } + if (name.isEmpty()) + break; - if (sound_card_available(c)) { - const device_t *sound_dev = sound_card_getdevice(c); - if (device_is_valid(sound_dev, machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == sound_card_current[i]) { - selectedRow = row - removeRows; + if (sound_card_available(c)) { + if (device_is_valid(sound_card_getdevice(c), machineId)) { + for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { + if ((c != 1) || ((i == 0) && m_has_snd)) { + int row = Models::AddEntry(models[i], name, c); + + if (c == sound_card_current[i]) + selectedRows[i] = row - removeRows_[i]; } } } - - c++; } - model->removeRows(0, removeRows); - cbox->setEnabled(model->rowCount() > 0); - cbox->setCurrentIndex(-1); - cbox->setCurrentIndex(selectedRow); + c++; + } + + for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { + models[i]->removeRows(0, removeRows_[i]); + cbox[i]->setEnabled(models[i]->rowCount() > 1); + cbox[i]->setCurrentIndex(-1); + cbox[i]->setCurrentIndex(selectedRows[i]); } // Midi Out diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index 4adfe1546..eebed79e2 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -171,35 +171,48 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxCDInterface->setCurrentIndex(-1); ui->comboBoxCDInterface->setCurrentIndex(selectedRow); + // SCSI Card + QComboBox * cbox[SCSI_CARD_MAX] = { 0 }; + QAbstractItemModel *models[SCSI_CARD_MAX] = { 0 }; + int removeRows_[SCSI_CARD_MAX] = { 0 }; + int selectedRows[SCSI_CARD_MAX] = { 0 }; + int m_has_scsi = machine_has_flags(machineId, MACHINE_SCSI); + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { - QComboBox *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); - c = 0; - model = cbox->model(); - removeRows = model->rowCount(); - selectedRow = 0; + cbox[i] = findChild(QString("comboBoxSCSI%1").arg(i + 1)); + models[i] = cbox[i]->model(); + removeRows_[i] = models[i]->rowCount(); + } - while (true) { - QString name = DeviceConfig::DeviceName(scsi_card_getdevice(c), scsi_card_get_internal_name(c), 1); - if (name.isEmpty()) { - break; - } + c = 0; + while (true) { + const QString name = DeviceConfig::DeviceName(scsi_card_getdevice(c), + scsi_card_get_internal_name(c), 1); - if (scsi_card_available(c)) { - const device_t *scsi_dev = scsi_card_getdevice(c); - if (device_is_valid(scsi_dev, machineId)) { - int row = Models::AddEntry(model, name, c); - if (c == scsi_card_current[i]) { - selectedRow = row - removeRows; + if (name.isEmpty()) + break; + + if (scsi_card_available(c)) { + if (device_is_valid(scsi_card_getdevice(c), machineId)) { + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + if ((c != 1) || ((i == 0) && m_has_scsi)) { + int row = Models::AddEntry(models[i], name, c); + + if (c == scsi_card_current[i]) + selectedRows[i] = row - removeRows_[i]; } } } - c++; } - model->removeRows(0, removeRows); - cbox->setEnabled(model->rowCount() > 0); - cbox->setCurrentIndex(-1); - cbox->setCurrentIndex(selectedRow); + c++; + } + + for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { + models[i]->removeRows(0, removeRows_[i]); + cbox[i]->setEnabled(models[i]->rowCount() > 1); + cbox[i]->setCurrentIndex(-1); + cbox[i]->setCurrentIndex(selectedRows[i]); } int is_at = IS_AT(machineId); From 3fc6d29462a2f3bf6e5c7ecf79ca423e9f5ebb33 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 04:53:48 +0200 Subject: [PATCH 0631/1190] JEGA/JVGA: Only update renderer override on master, do not update CRTC cursor location unless it's either master or slave, and only override the text mode renderer - fixes AX Windows 3.0 386 enhanced mode returning from DOS box to full screen. --- src/video/vid_ega.c | 5 +---- src/video/vid_ega_render.c | 5 +++++ src/video/vid_jega.c | 39 +++++++++++++++++++++++++++---------- src/video/vid_svga.c | 6 ++---- src/video/vid_svga_render.c | 10 ++++++++++ 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index f002ef999..5b5427b9e 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -783,10 +783,7 @@ ega_poll(void *priv) ega->y_add *= ega->vres + 1; for (y = 0; y <= ega->vres; y++) { /* Render scanline */ - if (ega->render_override) - ega->render_override(ega->priv_parent); - else - ega->render(ega); + ega->render(ega); /* Render overscan */ ega->x_add = (overscan_x >> 1); diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 10667084a..8a73ffbbb 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -107,6 +107,11 @@ ega_render_overscan_right(ega_t *ega) void ega_render_text(ega_t *ega) { + if (ega->render_override) { + ega->render_override(ega->priv_parent); + return; + } + if ((ega->displine + ega->y_add) < 0) return; diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 11c9cbf8d..a238fbff9 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -464,21 +464,40 @@ jega_out(uint16_t addr, uint8_t val, void *priv) case 0x3d5: /* Data */ if (jega->regs_index != RINVALID_INDEX) { + if ((jega->regs_index < 7) && (jega->regs[0x11] & 0x80)) + return; + if ((jega->regs_index == 7) && (jega->regs[0x11] & 0x80)) + val = (jega->regs[7] & ~0x10) | (val & 0x10); + /* + Do not allow cursor updates if neither master nor slave is + active - the AX Windows 3.0 386 Enhanced Mode DOS grabber + relies on this for the cursor position to behave correctly. + */ + if ((jega->regs_index >= 0x0e) && (jega->regs_index <= 0x0f) && !(jega->regs[RMOD1] & 0x0c)) + return; jega->regs[jega->regs_index] = val; jega_log("JEGA Out %04X(%02X) %02Xh(%d) %04X:%04X\n", addr, jega->regs_index, val, val, cs >> 4, cpu_state.pc); switch (jega->regs_index) { case RMOD1: /* if the value is changed */ - if (jega->is_vga) { - if (val & 0x40) - jega->vga.svga.render_override = NULL; - else - jega->vga.svga.render_override = jega_render_text; - } else { - if (val & 0x40) - jega->ega.render_override = NULL; - else - jega->ega.render_override = jega_render_text; + /* + Do not allow override toggling unless it's on master and + only override the text renderer - the AX Windows 3.0 386 + Enhanced Mode DOS grabber relies on this for the grabbing + to behave correctly. + */ + if (val & 0x08) { + if (jega->is_vga) { + if (val & 0x40) + jega->vga.svga.render_override = NULL; + else + jega->vga.svga.render_override = jega_render_text; + } else { + if (val & 0x40) + jega->ega.render_override = NULL; + else + jega->ega.render_override = jega_render_text; + } } break; case RDAGS: diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 8d1535dda..b4abc18e5 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1176,10 +1176,7 @@ svga_do_render(svga_t *svga) } if (!svga->override) { - if (svga->render_override) - svga->render_override(svga->priv_parent); - else - svga->render(svga); + svga->render(svga); svga->x_add = (svga->monitor->mon_overscan_x >> 1); svga_render_overscan_left(svga); @@ -2019,6 +2016,7 @@ svga_doblit(int wx, int wy, svga_t *svga) /* Block resolution changes while in DPMS mode to avoid getting a bogus screen width (320). We're already rendering a blank screen anyway. */ + pclog("%i + %i, %i + %i\n", svga->monitor->mon_xsize, x_add, svga->monitor->mon_ysize, y_add); if (!svga->dpms) set_screen_size_monitor(svga->monitor->mon_xsize + x_add, svga->monitor->mon_ysize + y_add, svga->monitor_index); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index c05d308fa..fbd667a1b 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -147,6 +147,11 @@ svga_render_text_40(svga_t *svga) int bg; uint32_t addr = 0; + if (svga->render_override) { + svga->render_override(svga->priv_parent); + return; + } + if ((svga->displine + svga->y_add) < 0) return; @@ -225,6 +230,11 @@ svga_render_text_80(svga_t *svga) int bg; uint32_t addr = 0; + if (svga->render_override) { + svga->render_override(svga->priv_parent); + return; + } + if ((svga->displine + svga->y_add) < 0) return; From e4877a57c52e81cace94e7e025352a9d1a0dca03 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 07:28:20 +0200 Subject: [PATCH 0632/1190] EGA/JEGA: More fixes and implemented more C&T SuperEGA behavior. --- src/video/vid_ega.c | 97 ++++++++++++++++++++++++++++++++------------ src/video/vid_jega.c | 3 +- 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 5b5427b9e..82c88d827 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -61,14 +61,38 @@ int update_overscan = 0; uint8_t ega_in(uint16_t addr, void *priv); +static int +ega_get_type(ega_t *ega) +{ + int ret = ega_type; + + if (ega->actual_type == EGA_SUPEREGA) + ret = (ega->crtc[0x17] & 0x10) ? EGA_TYPE_OTHER : EGA_TYPE_IBM; + + return ret; +} + +static int +ega_get_actual_type(ega_t *ega) +{ + int ret = ega->actual_type; + + if (ega->actual_type == EGA_SUPEREGA) + ret = (ega->crtc[0x17] & 0x10) ? EGA_SUPEREGA : EGA_IBM; + + return ret; +} + void ega_out(uint16_t addr, uint8_t val, void *priv) { ega_t *ega = (ega_t *) priv; uint8_t o; uint8_t old; - uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; - uint8_t crtcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x1f; + int type = ega_get_type(ega); + int atype = ega_get_actual_type(ega); + uint8_t gdcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t crtcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x1f; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -94,7 +118,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) case 0x3c0: case 0x3c1: - if (ega->actual_type == EGA_SUPEREGA) + if (atype == EGA_SUPEREGA) val &= 0x7f; /* Bit 7 indicates the flipflop status (read only) */ if (!ega->attrff) { ega->attraddr = val & 31; @@ -110,7 +134,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->attrregs[ega->attraddr & 31] = val; if (ega->attraddr < 16) ega->fullchange = changeframecount; - if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) { + int is_attr14 = ega->chipset && (ega->attraddr == 0x14); + if ((ega->attraddr == 0x10) || is_attr14 || (ega->attraddr < 0x10)) { for (uint8_t c = 0; c < 16; c++) { if (ega->chipset) { if (ega->attrregs[0x10] & 0x80) @@ -148,7 +173,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if (!(val & 1)) io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); ega_recalctimings(ega); - if ((ega_type == EGA_TYPE_COMPAQ) && !(val & 0x02)) + if ((type == EGA_TYPE_COMPAQ) && !(val & 0x02)) mem_mapping_disable(&ega->mapping); else switch (ega->gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ @@ -198,7 +223,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) } break; case 0x3c6: - if (ega_type == EGA_TYPE_COMPAQ) + if (type == EGA_TYPE_COMPAQ) ega->ctl_mode = val; break; case 0x3ce: @@ -219,7 +244,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->chain2_read = val & 0x10; break; case 6: - if ((ega_type == EGA_TYPE_COMPAQ) && !(ega->miscout & 0x02)) + if ((type == EGA_TYPE_COMPAQ) && !(ega->miscout & 0x02)) mem_mapping_disable(&ega->mapping); else switch (val & 0xc) { case 0x0: /*128k at A0000*/ @@ -306,6 +331,8 @@ ega_in(uint16_t addr, void *priv) ega_t *ega = (ega_t *) priv; uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; uint8_t ret = 0xff; + int type = ega_get_type(ega); + int atype = ega_get_actual_type(ega); if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -329,48 +356,58 @@ ega_in(uint16_t addr, void *priv) break; case 0x3c0: - if (ega_type == EGA_TYPE_OTHER) - ret = ega->attraddr | ega->attr_palette_enable; - if (ega->actual_type == EGA_SUPEREGA && ega->attrff) - ret |= 0x80; /* Bit 7 indicates the flipflop status (read only) */ - break; case 0x3c1: - if (ega_type == EGA_TYPE_OTHER) - ret = ega->attrregs[ega->attraddr]; + if (type == EGA_TYPE_OTHER) { + int data = (atype == EGA_SUPEREGA) ? (ega->attrff & 1) : (addr & 1); + if (data) + ret = ega->attrregs[ega->attraddr]; + else + ret = ega->attraddr | ega->attr_palette_enable; + if (atype == EGA_SUPEREGA) + /* Bit 7 indicates the flipflop status (read only) */ + ret = (ret & 0x3f) | (ega->attrff ? 0x80 : 0x00); + } break; case 0x3c2: ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; case 0x3c4: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->seqaddr; break; case 0x3c5: - if (ega_type == EGA_TYPE_OTHER) - ret = ega->seqregs[ega->seqaddr & 0xf]; + if (type == EGA_TYPE_OTHER) { + if ((ega->seqaddr & 0x0f) > 0x04) + ret = ega->chipset ? ega->seqregs[ega->seqaddr & 0xf] : 0xff; + else + ret = ega->seqregs[ega->seqaddr & 0xf]; + } break; case 0x3c6: - if (ega_type == EGA_TYPE_COMPAQ) + if (type == EGA_TYPE_COMPAQ) ret = ega->ctl_mode; break; case 0x3c8: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = 2; break; case 0x3cc: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->miscout; break; case 0x3ce: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->gdcaddr; break; case 0x3cf: - if (ega_type == EGA_TYPE_OTHER) { + if (type == EGA_TYPE_OTHER) { switch (ega->gdcaddr & gdcmask) { default: ret = ega->gdcreg[ega->gdcaddr & gdcmask]; break; + case 0x09 ... 0xf7: + ret = ega->chipset ? ega->gdcreg[ega->gdcaddr & gdcmask] : 0xff; + break; case 0xf8: ret = ega->la; break; @@ -388,8 +425,14 @@ ega_in(uint16_t addr, void *priv) break; case 0x3d0: case 0x3d4: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) { ret = ega->crtcreg; + if (atype == EGA_SUPEREGA) { + ret = (ret & 0x1f) | 0xc0; + if ((ega->crtcreg & 0xc0) == 0xc0) + ret |= 0x20; + } + } break; case 0x3d1: case 0x3d5: @@ -402,28 +445,28 @@ ega_in(uint16_t addr, void *priv) break; case 0x10: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->crtc[ega->crtcreg]; else ret = ega->light_pen >> 8; break; case 0x11: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->crtc[ega->crtcreg]; else ret = ega->light_pen & 0xff; break; default: - if (ega_type == EGA_TYPE_OTHER) + if (type == EGA_TYPE_OTHER) ret = ega->crtc[ega->crtcreg]; break; } break; case 0x3da: ega->attrff = 0; - if (ega_type == EGA_TYPE_COMPAQ) { + if (type == EGA_TYPE_COMPAQ) { ret = ega->stat & 0xcf; switch ((ega->attrregs[0x12] >> 4) & 0x03) { case 0x00: diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index a238fbff9..4240f5e98 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -428,7 +428,8 @@ jega_out(uint16_t addr, uint8_t val, void *priv) } } else { jega->attrregs[jega->attraddr & 31] = val; - if (jega->attraddr < 0x10) { + int is_attr14 = jega->is_vga ? (jega->attraddr == 0x14) : 0; + if (is_attr14 || (jega->attraddr < 0x10)) { for (uint8_t c = 0; c < 16; c++) { if (jega->is_vga) { if (jega->attrregs[0x10] & 0x80) From d2afb44412e414b0357c3f318c0fb5f5fbf41237 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 07:32:46 +0200 Subject: [PATCH 0633/1190] SVGA: Remove some excess logging. --- src/video/vid_svga.c | 1 - src/video/vid_svga_render.c | 9 --------- 2 files changed, 10 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index b4abc18e5..d0189e0f7 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -2016,7 +2016,6 @@ svga_doblit(int wx, int wy, svga_t *svga) /* Block resolution changes while in DPMS mode to avoid getting a bogus screen width (320). We're already rendering a blank screen anyway. */ - pclog("%i + %i, %i + %i\n", svga->monitor->mon_xsize, x_add, svga->monitor->mon_ysize, y_add); if (!svga->dpms) set_screen_size_monitor(svga->monitor->mon_xsize + x_add, svga->monitor->mon_ysize + y_add, svga->monitor_index); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index fbd667a1b..d47697a7e 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -85,18 +85,9 @@ svga_render_blank(svga_t *svga) break; } -#if 0 - pclog("svga->displine = %i, svga->y_add = %i, svga->x_add = %i\n", svga->displine, svga->y_add, svga->x_add); -#endif uint32_t *line_ptr = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; -#if 0 - pclog("svga->hdisp = %i, svga->scrollcache = %i, char_width = %i, sizeof(uint32_t) = %i\n", svga->hdisp, svga->scrollcache, char_width, sizeof(uint32_t)); -#endif uint32_t line_width = (uint32_t) (svga->hdisp + svga->scrollcache) * char_width * sizeof(uint32_t); -#if 0 - pclog("line_width = %i\n", line_width); -#endif if ((svga->hdisp + svga->scrollcache) > 0) memset(line_ptr, 0, line_width); } From 5569fa6f5dfbe2bed794236515307fcedcf17b91 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 08:22:14 +0200 Subject: [PATCH 0634/1190] C&T SuperEGA: More fixes, the BIOS no longer freezes on attempting to boot from anything. --- src/video/vid_ega.c | 90 +++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 82c88d827..03121751d 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -61,37 +61,15 @@ int update_overscan = 0; uint8_t ega_in(uint16_t addr, void *priv); -static int -ega_get_type(ega_t *ega) -{ - int ret = ega_type; - - if (ega->actual_type == EGA_SUPEREGA) - ret = (ega->crtc[0x17] & 0x10) ? EGA_TYPE_OTHER : EGA_TYPE_IBM; - - return ret; -} - -static int -ega_get_actual_type(ega_t *ega) -{ - int ret = ega->actual_type; - - if (ega->actual_type == EGA_SUPEREGA) - ret = (ega->crtc[0x17] & 0x10) ? EGA_SUPEREGA : EGA_IBM; - - return ret; -} - void ega_out(uint16_t addr, uint8_t val, void *priv) { ega_t *ega = (ega_t *) priv; uint8_t o; uint8_t old; - int type = ega_get_type(ega); - int atype = ega_get_actual_type(ega); - uint8_t gdcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x0f; + int type = ega_type; + int atype = ega->actual_type; + uint8_t gdcmask = (ega_type == EGA_SUPEREGA) ? 0xff : 0x0f; uint8_t crtcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x1f; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) @@ -168,7 +146,8 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->pallook = ega->vres ? pallook16 : pallook64; ega->vidclock = val & 4; ega->miscout = val; - ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : pallook64[ega->attrregs[0x11] & 0x3f]; + ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : + pallook64[ega->attrregs[0x11] & 0x3f]; io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); if (!(val & 1)) io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); @@ -290,28 +269,34 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if (ega->chipset) ega->crtcreg = val & 0x3f; else - ega->crtcreg = val & crtcmask; + ega->crtcreg = val; return; case 0x3d1: case 0x3d5: + int idx = ega->crtcreg; + if (ega->chipset) { if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80)) return; if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80)) val = (ega->crtc[7] & ~0x10) | (val & 0x10); } else { - if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80)) + idx &= crtcmask; + if ((idx >= 0x19) & (idx <= 0xf6)) return; - if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80)) + if ((idx < 7) && (ega->crtc[0x11] & 0x80)) + return; + if ((idx == 7) && (ega->crtc[0x11] & 0x80)) val = (ega->crtc[7] & ~0x10) | (val & 0x10); } - old = ega->crtc[ega->crtcreg]; - ega->crtc[ega->crtcreg] = val; + old = ega->crtc[idx]; + ega->crtc[idx] = val; if (old != val) { - if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) { - if ((ega->crtcreg == 0xc) || (ega->crtcreg == 0xd)) { + if ((idx < 0xe) || (idx > 0x10)) { + if ((idx == 0xc) || (idx == 0xd)) { ega->fullchange = 3; - ega->ma_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + ((ega->crtc[8] & 0x60) >> 5); + ega->ma_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + + ((ega->crtc[8] & 0x60) >> 5); } else { ega->fullchange = changeframecount; ega_recalctimings(ega); @@ -329,10 +314,11 @@ uint8_t ega_in(uint16_t addr, void *priv) { ega_t *ega = (ega_t *) priv; - uint8_t gdcmask = (ega->actual_type == EGA_SUPEREGA) ? 0xff : 0x0f; - uint8_t ret = 0xff; - int type = ega_get_type(ega); - int atype = ega_get_actual_type(ega); + uint8_t ret = 0xff; + int type = ega_type; + int atype = ega->actual_type; + uint8_t gdcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x0f; + uint8_t crtcmask = (atype == EGA_SUPEREGA) ? 0xff : 0x1f; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -372,8 +358,12 @@ ega_in(uint16_t addr, void *priv) ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00; break; case 0x3c4: - if (type == EGA_TYPE_OTHER) - ret = ega->seqaddr; + if (type == EGA_TYPE_OTHER) { + if (atype == EGA_SUPEREGA) + ret = 0x1f | ((ega->miscout & 0x01) << 5); + else + ret = ega->seqaddr; + } break; case 0x3c5: if (type == EGA_TYPE_OTHER) { @@ -396,8 +386,14 @@ ega_in(uint16_t addr, void *priv) ret = ega->miscout; break; case 0x3ce: - if (type == EGA_TYPE_OTHER) + if (ega_type == EGA_TYPE_OTHER) { ret = ega->gdcaddr; + if (atype == EGA_SUPEREGA) { + ret = (ret & 0x0f) | 0xe0; + if ((ega->gdcaddr & 0xe0) == 0xe0) + ret |= 0x10; + } + } break; case 0x3cf: if (type == EGA_TYPE_OTHER) { @@ -425,7 +421,7 @@ ega_in(uint16_t addr, void *priv) break; case 0x3d0: case 0x3d4: - if (type == EGA_TYPE_OTHER) { + if (ega_type == EGA_TYPE_OTHER) { ret = ega->crtcreg; if (atype == EGA_SUPEREGA) { ret = (ret & 0x1f) | 0xc0; @@ -436,7 +432,7 @@ ega_in(uint16_t addr, void *priv) break; case 0x3d1: case 0x3d5: - switch (ega->crtcreg) { + switch (ega->crtcreg & crtcmask) { case 0xc: case 0xd: case 0xe: @@ -458,6 +454,11 @@ ega_in(uint16_t addr, void *priv) ret = ega->light_pen & 0xff; break; + case 0x19 ... 0xf6: + if (type == EGA_TYPE_OTHER) + ret = ega->chipset ? ega->crtc[ega->crtcreg] : 0xff; + break; + default: if (type == EGA_TYPE_OTHER) ret = ega->crtc[ega->crtcreg]; @@ -672,7 +673,8 @@ ega_recalctimings(ega_t *ega) disptime = (double) (ega->crtc[0] + 2); _dispontime = (double) (ega->crtc[1] + 1); } - if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0xf9] & 0x01)) { + if ((ega->actual_type == EGA_SUPEREGA) && (ega->crtc[0x17] & 0x10) && + (ega->crtc[0xf9] & 0x01)) { disptime *= 2.0; _dispontime *= 2.0; } From 512154e4a837c76405f446c0691e321817c526c2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 30 Mar 2025 09:00:39 +0200 Subject: [PATCH 0635/1190] EGA: Add braces around a case block to make clang happy. --- src/video/vid_ega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 03121751d..8333e522e 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -272,7 +272,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) ega->crtcreg = val; return; case 0x3d1: - case 0x3d5: + case 0x3d5: { int idx = ega->crtcreg; if (ega->chipset) { @@ -305,7 +305,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) } break; - default: + } default: break; } } From 8f94ccec8045afda48b88990d07b9ae966b91da7 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 30 Mar 2025 21:03:46 +0600 Subject: [PATCH 0636/1190] Qt: Fix HiDPI scaling on non-software renderers --- src/qt/qt_hardwarerenderer.cpp | 7 +++++-- src/qt/qt_openglrenderer.cpp | 29 ++++++++++++++++------------- src/qt/qt_renderercommon.cpp | 3 +++ src/qt/qt_renderercommon.hpp | 2 ++ src/qt/qt_vulkanrenderer.cpp | 16 +++++----------- src/qt/qt_vulkanwindowrenderer.cpp | 5 ++++- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp index ee2ec07df..d5aa86b79 100644 --- a/src/qt/qt_hardwarerenderer.cpp +++ b/src/qt/qt_hardwarerenderer.cpp @@ -37,7 +37,7 @@ void HardwareRenderer::resizeGL(int w, int h) { m_context->makeCurrent(this); - glViewport(0, 0, qRound(w * devicePixelRatio()), qRound(h * devicePixelRatio())); + glViewport(0, 0, qRound(w * devicePixelRatioF()), qRound(h * devicePixelRatioF())); } #define PROGRAM_VERTEX_ATTRIBUTE 0 @@ -220,14 +220,17 @@ HardwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) #endif buf_usage[buf_idx].clear(); source.setRect(x, y, w, h); - if (origSource != source) + if (origSource != source) { + this->pixelRatio = devicePixelRatioF(); onResize(this->width(), this->height()); + } update(); } void HardwareRenderer::resizeEvent(QResizeEvent *event) { + this->pixelRatio = devicePixelRatioF(); onResize(width(), height()); QOpenGLWindow::resizeEvent(event); diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index b465bfddd..cc48ca06e 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1154,14 +1154,15 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) buf_usage[buf_idx].clear(); source.setRect(x, y, w, h); + this->pixelRatio = devicePixelRatio(); onResize(this->width(), this->height()); #ifdef Q_OS_MACOS glw.glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); + destination.x(), + destination.y(), + destination.width(), + destination.height()); #endif if (video_framerate == -1) @@ -1187,6 +1188,7 @@ OpenGLRenderer::exposeEvent(QExposeEvent *event) if (!isInitialized) initialize(); + this->pixelRatio = devicePixelRatio(); onResize(size().width(), size().height()); } @@ -1195,6 +1197,7 @@ OpenGLRenderer::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); + this->pixelRatio = devicePixelRatio(); onResize(event->size().width(), event->size().height()); if (notReady()) @@ -1203,10 +1206,10 @@ OpenGLRenderer::resizeEvent(QResizeEvent *event) context->makeCurrent(this); glw.glViewport( - destination.x() * devicePixelRatio(), - destination.y() * devicePixelRatio(), - destination.width() * devicePixelRatio(), - destination.height() * devicePixelRatio()); + destination.x(), + destination.y(), + destination.width(), + destination.height()); } void @@ -1386,10 +1389,10 @@ OpenGLRenderer::render() uint32_t x, y, w, h; } window_rect; - window_rect.x = destination.x() * devicePixelRatio(); - window_rect.y = destination.y() * devicePixelRatio(); - window_rect.w = destination.width() * devicePixelRatio(); - window_rect.h = destination.height() * devicePixelRatio(); + window_rect.x = destination.x(); + window_rect.y = destination.y(); + window_rect.w = destination.width(); + window_rect.h = destination.height(); glw.glBindTexture(GL_TEXTURE_2D, scene_texture.id); scene_texture.min_filter = scene_texture.mag_filter = video_filter_method ? GL_LINEAR : GL_NEAREST; @@ -1652,7 +1655,7 @@ OpenGLRenderer::render() } if (monitors[r_monitor_index].mon_screenshots) { - int width = destination.width() * devicePixelRatio(), height = destination.height() * devicePixelRatio(); + int width = destination.width(), height = destination.height(); char path[1024]; char fn[256]; diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp index 2a20ff63c..3a34452e6 100644 --- a/src/qt/qt_renderercommon.cpp +++ b/src/qt/qt_renderercommon.cpp @@ -59,6 +59,9 @@ RendererCommon::onResize(int width, int height) bool main_max = main_window->isMaximized(); bool main_is_max = (main_is_ancestor && main_max == false); + width = round(pixelRatio * width); + height = round(pixelRatio * height); + if (is_fs && (video_fullscreen_scale_maximized ? (parent_max && main_is_max) : 1)) destination.setRect(0, 0, width, height); else { diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index bbda9516b..333b9df0a 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -49,5 +49,7 @@ protected: QRect destination; QWidget *parentWidget { nullptr }; + double pixelRatio = 1.0; + std::vector buf_usage; }; diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp index 39830569c..2306661ec 100644 --- a/src/qt/qt_vulkanrenderer.cpp +++ b/src/qt/qt_vulkanrenderer.cpp @@ -970,17 +970,11 @@ VulkanRenderer2::startNextFrame() m_devFuncs->vkCmdBindVertexBuffers(cb, 0, 1, &m_buf, &vbOffset); VkViewport viewport; - if (dpi_scale) { - viewport.x = destination.x() * m_window->devicePixelRatio(); - viewport.y = destination.y() * m_window->devicePixelRatio(); - viewport.width = destination.width() * m_window->devicePixelRatio(); - viewport.height = destination.height() * m_window->devicePixelRatio(); - } else { - viewport.x = destination.x(); - viewport.y = destination.y(); - viewport.width = destination.width(); - viewport.height = destination.height(); - } + viewport.x = destination.x(); + viewport.y = destination.y(); + viewport.width = destination.width(); + viewport.height = destination.height(); + viewport.minDepth = 0; viewport.maxDepth = 1; m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport); diff --git a/src/qt/qt_vulkanwindowrenderer.cpp b/src/qt/qt_vulkanwindowrenderer.cpp index ab46b5961..d0fbb39a3 100644 --- a/src/qt/qt_vulkanwindowrenderer.cpp +++ b/src/qt/qt_vulkanwindowrenderer.cpp @@ -846,6 +846,7 @@ VulkanWindowRenderer::createRenderer() void VulkanWindowRenderer::resizeEvent(QResizeEvent *event) { + this->pixelRatio = devicePixelRatio(); onResize(width(), height()); QVulkanWindow::resizeEvent(event); @@ -868,8 +869,10 @@ VulkanWindowRenderer::onBlit(int buf_idx, int x, int y, int w, int h) if (isExposed()) requestUpdate(); buf_usage[0].clear(); - if (origSource != source) + if (origSource != source) { + this->pixelRatio = devicePixelRatio(); onResize(this->width(), this->height()); + } } uint32_t From 5ae5e99e41010861ab185012f47504fed40304dc Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 30 Mar 2025 22:06:16 +0200 Subject: [PATCH 0637/1190] Major changes on the 8514/A side again (March 30th, 2025) 1. The DX/DY coordinates for BitBLT are now signed again, fixes 8514/A cursor issues. 2. Made the busy/data available processor statuses more like the ATI one for more stability and no stalls, fixes Windows 3.x and IBM OS/2 1.x (possibly later ones too) that use the built-in 8514/A driver. 3. Made the mode switching clearer (through a note) regarding the shadow sets, this should make every program happy, I hope. 4. In the Mach32 series only, a first load of the CRT sets also initializes the GE offsets if the corresponding bit is set, fixes Mach8/32 mode tests in their eeprom and demoai with hdiload from ATI/IBM. --- src/include/86box/vid_8514a.h | 4 +- src/include/86box/vid_ati_mach8.h | 3 +- src/video/vid_8514a.c | 199 +++++++++++++++------------ src/video/vid_ati_mach8.c | 215 +++++++++++++++++++----------- 4 files changed, 256 insertions(+), 165 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index a467311ca..7694a028a 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -92,8 +92,8 @@ typedef struct ibm8514_t { uint16_t advfunc_cntl; uint16_t cur_y; uint16_t cur_x; - uint16_t destx; - uint16_t desty; + int16_t destx; + int16_t desty; int16_t desty_axstp; int16_t destx_distp; int16_t err_term; diff --git a/src/include/86box/vid_ati_mach8.h b/src/include/86box/vid_ati_mach8.h index 4a5d3deb5..8ed1dbc74 100644 --- a/src/include/86box/vid_ati_mach8.h +++ b/src/include/86box/vid_ati_mach8.h @@ -77,7 +77,8 @@ typedef struct mach_t { uint8_t overscan_g_col_24; uint8_t overscan_r_col_24; uint16_t fifo_test_data[17]; - int resolution_crt; + int port_len; + int crt_resolution; struct { uint8_t line_idx; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 393b90b57..7c0bf9702 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -834,10 +834,25 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) if (dev->force_busy) temp |= 0x0200; /*Hardware busy*/ - dev->force_busy = 0; + + if (dev->accel.cmd_back) + dev->force_busy = 0; + if (dev->data_available) { temp |= 0x0100; /*Read Data available*/ - dev->data_available = 0; + switch (dev->accel.cmd >> 13) { + case 2: + case 3: + case 4: + case 6: + if (dev->accel.sy < 0) + dev->data_available = 0; + break; + default: + if (!dev->accel.sy) + dev->data_available = 0; + break; + } } } break; @@ -850,9 +865,22 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) temp |= 0x02; /*Hardware busy*/ dev->force_busy2 = 0; + if (dev->data_available2) { temp |= 0x01; /*Read Data available*/ - dev->data_available2 = 0; + switch (dev->accel.cmd >> 13) { + case 2: + case 3: + case 4: + case 6: + if (dev->accel.sy < 0) + dev->data_available2 = 0; + break; + default: + if (!dev->accel.sy) + dev->data_available2 = 0; + break; + } } } break; @@ -931,10 +959,10 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) if (cmd == 6) { if ((dev->subsys_cntl & INT_GE_BSY) && !(dev->subsys_stat & INT_GE_BSY) && - (dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r_ibm) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b_ibm)) + (dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r_ibm) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b_ibm)) temp |= INT_GE_BSY; } else { if ((dev->subsys_cntl & INT_GE_BSY) && @@ -2796,8 +2824,13 @@ skip_nibble_rect_write: { dev->accel.x_count = 0; - dev->accel.dx_ibm = dev->accel.destx; - dev->accel.dy_ibm = dev->accel.desty; + dev->accel.dx = dev->accel.destx; + if (dev->accel.destx >= 0x600) + dev->accel.dx |= ~0x5ff; + + dev->accel.dy = dev->accel.desty; + if (dev->accel.desty >= 0x600) + dev->accel.dy |= ~0x5ff; dev->accel.cx = dev->accel.cur_x; if (dev->accel.cur_x >= 0x600) @@ -2812,13 +2845,13 @@ skip_nibble_rect_write: if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } dev->accel.fill_state = 0; @@ -2844,15 +2877,15 @@ skip_nibble_rect_write: dev->data_available2 = 1; return; /*Wait for data from CPU*/ } else - ibm8514_log("BitBLT normal: Parameters: DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, dstheight=%d, clipl=%d, clipr=%d, clipt=%d, clipb=%d.\n", dev->accel.dx_ibm, dev->accel.dy_ibm, dev->accel.cx, dev->accel.cy, dev->accel.sx, dev->accel.sy, clip_l, clip_r, clip_t, clip_b); + ibm8514_log("BitBLT normal: Parameters: DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, dstheight=%d, clipl=%d, clipr=%d, clipt=%d, clipb=%d.\n", dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, dev->accel.sx, dev->accel.sy, clip_l, clip_r, clip_t, clip_b); } if (cpu_input) { while (count-- && (dev->accel.sy >= 0)) { - if ((dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b)) { + if ((dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) { if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -2916,7 +2949,7 @@ skip_nibble_rect_write: } } - READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -2932,20 +2965,20 @@ skip_nibble_rect_write: goto skip_nibble_bitblt_write; dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } else { MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } } if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm++; + dev->accel.dx++; dev->accel.cx++; } else { - dev->accel.dx_ibm--; + dev->accel.dx--; dev->accel.cx--; } @@ -2972,30 +3005,30 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm -= (dev->accel.sx + 1); + dev->accel.dx -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx_ibm += (dev->accel.sx + 1); + dev->accel.dx += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy_ibm++; + dev->accel.dy++; dev->accel.cy++; } else { - dev->accel.dy_ibm--; + dev->accel.dy--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } dev->accel.sy--; @@ -3018,10 +3051,10 @@ skip_nibble_bitblt_write: mix_dat >>= 8; dev->accel.temp_cnt = 8; } - if ((dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b)) { + if ((dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3040,7 +3073,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3052,7 +3085,7 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } @@ -3063,10 +3096,10 @@ skip_nibble_bitblt_write: } if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm++; + dev->accel.dx++; dev->accel.cx++; } else { - dev->accel.dx_ibm--; + dev->accel.dx--; dev->accel.cx--; } @@ -3075,30 +3108,30 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm -= (dev->accel.sx + 1); + dev->accel.dx -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx_ibm += (dev->accel.sx + 1); + dev->accel.dx += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy_ibm++; + dev->accel.dy++; dev->accel.cy++; } else { - dev->accel.dy_ibm--; + dev->accel.dy--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } dev->accel.sy--; @@ -3117,10 +3150,10 @@ skip_nibble_bitblt_write: dev->accel.temp_cnt = 8; mix_dat = old_mix_dat; } - if ((dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b)) { + if ((dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) { switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -3139,7 +3172,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3151,7 +3184,7 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & 0x01, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } @@ -3159,10 +3192,10 @@ skip_nibble_bitblt_write: mix_dat >>= 1; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm++; + dev->accel.dx++; dev->accel.cx++; } else { - dev->accel.dx_ibm--; + dev->accel.dx--; dev->accel.cx--; } @@ -3171,36 +3204,36 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm -= (dev->accel.sx + 1); + dev->accel.dx -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx_ibm += (dev->accel.sx + 1); + dev->accel.dx += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy_ibm++; + dev->accel.dy++; dev->accel.cy++; } else { - dev->accel.dy_ibm--; + dev->accel.dy--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } dev->accel.sy--; if (dev->accel.sy < 0) { - dev->accel.destx = dev->accel.dx_ibm; - dev->accel.desty = dev->accel.dy_ibm; + dev->accel.destx = dev->accel.dx; + dev->accel.desty = dev->accel.dy; dev->accel.cmd_back = 1; dev->fifo_idx = 0; return; @@ -3214,13 +3247,13 @@ skip_nibble_bitblt_write: int64_t dx; cx = (int64_t) dev->accel.cx; - dx = (int64_t) dev->accel.dx_ibm; + dx = (int64_t) dev->accel.dx; while (1) { if ((dx >= (((int64_t)clip_l) * 3)) && (dx <= (((uint64_t)clip_r) * 3)) && - (dev->accel.dy_ibm >= (clip_t << 1)) && - (dev->accel.dy_ibm <= (clip_b << 1))) { + (dev->accel.dy >= (clip_t << 1)) && + (dev->accel.dy <= (clip_b << 1))) { READ(dev->accel.src + cx, src_dat); READ(dev->accel.dest + dx, dest_dat); dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); @@ -3239,10 +3272,10 @@ skip_nibble_bitblt_write: } } else { while (count-- && dev->accel.sy >= 0) { - if ((dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b)) { + if ((dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) { if (pixcntl == 3) { if (!(dev->accel.cmd & 0x10) && ((frgd_mix != 3) || (bkgd_mix != 3))) { READ(dev->accel.src + dev->accel.cx, mix_dat); @@ -3276,7 +3309,7 @@ skip_nibble_bitblt_write: break; } - READ(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); if ((compare_mode == 0) || ((compare_mode == 0x10) && (dest_dat >= compare)) || @@ -3291,11 +3324,11 @@ skip_nibble_bitblt_write: if (dev->accel.cmd & 0x04) { if (dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } else { - WRITE(dev->accel.dest + dev->accel.dx_ibm, dest_dat); - ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx_ibm, dev->accel.dy_ibm, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); } } } @@ -3304,10 +3337,10 @@ skip_nibble_bitblt_write: mix_dat |= 1; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm++; + dev->accel.dx++; dev->accel.cx++; } else { - dev->accel.dx_ibm--; + dev->accel.dx--; dev->accel.cx--; } @@ -3317,36 +3350,36 @@ skip_nibble_bitblt_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { - dev->accel.dx_ibm -= (dev->accel.sx + 1); + dev->accel.dx -= (dev->accel.sx + 1); dev->accel.cx -= (dev->accel.sx + 1); } else { - dev->accel.dx_ibm += (dev->accel.sx + 1); + dev->accel.dx += (dev->accel.sx + 1); dev->accel.cx += (dev->accel.sx + 1); } if (dev->accel.cmd & 0x80) { - dev->accel.dy_ibm++; + dev->accel.dy++; dev->accel.cy++; } else { - dev->accel.dy_ibm--; + dev->accel.dy--; dev->accel.cy--; } if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } else if (dev->bpp) { dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); } else { dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy_ibm * dev->pitch); + dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); } dev->accel.sy--; if (dev->accel.sy < 0) { - dev->accel.destx = dev->accel.dx_ibm; - dev->accel.desty = dev->accel.dy_ibm; + dev->accel.destx = dev->accel.dx; + dev->accel.desty = dev->accel.dy; dev->accel.cmd_back = 1; dev->fifo_idx = 0; return; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index c21730497..474ae5660 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -344,7 +344,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); - mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i.\n", cmd_type, frgd_sel, bkgd_sel, mono_src); + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config); switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -900,14 +900,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } dev->accel.sy = 0; - if (mach->accel.dp_config & 0x02) - dev->accel.dest = (dev->accel.dy * dev->pitch); - else { - if (dev->bpp) - dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - else - dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + if (dev->bpp) + dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); + else + dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); mach->accel.src_stepx = 0; /*Source Width*/ @@ -2221,7 +2217,7 @@ mach_accel_out_pixtrans(svga_t *svga, mach_t *mach, ibm8514_t *dev, uint16_t val case 0x200: /*16-bit size*/ if (mono_src == 2) { if ((frgd_sel != 2) && (bkgd_sel != 2)) { - if (((mach->accel.dp_config & 0x1000) && !swap) || swap) { + if (((mach->accel.dp_config & 0x1000) && !swap) || (!(mach->accel.dp_config & 0x1000) && swap)) { mach_log("16-bit bus size swap.\n"); val = (val >> 8) | (val << 8); } @@ -2663,17 +2659,22 @@ ati_render_32bpp(svga_t *svga) } } +/*The situation is the following: + When ATI mode is selected, allow complete auto-detection. + But when 8514/A mode is selected, allow detection based on the shadow register sets. +*/ + static void mach_set_resolution(mach_t *mach, svga_t *svga) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; dev->hdisp = (dev->hdisped + 1) << 3; - if (!dev->htotal) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ - dev->htotal = 0x9d; - dev->h_total = dev->htotal + 1; + if (dev->h_total == 1) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ + dev->h_total = 0x9e; + dev->vdisp = (dev->v_disp + 1) >> 1; if ((dev->vdisp == 478) || (dev->vdisp == 598) || (dev->vdisp == 766) || (dev->vdisp == 1022)) dev->vdisp += 2; @@ -2686,26 +2687,72 @@ mach_set_resolution(mach_t *mach, svga_t *svga) if (dev->interlace) dev->v_syncstart >>= 1; - mach_log("Shadow set ATI=%x, shadow set 8514/A=%x, resolution h=%d, v=%d.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + mach_log("Shadow set ATI=%x, shadow set 8514/A=%x, resolution h=%d, v=%d, vtotal=%d, vsyncstart=%d.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart); if ((mach->accel.clock_sel & 0x01) || dev->bpp || ((mach->accel.ext_ge_config & 0x30) == 0x30)) /*ATI and 15bpp+ mode*/ svga_recalctimings(svga); else { /*8514/A mode*/ - if (mach->resolution_crt == 0x02) { - if (!(dev->accel.advfunc_cntl & 0x04)) { - dev->hdisp = 640; - dev->vdisp = 480; - svga_recalctimings(svga); - } - } else { - if (ATI_8514A_ULTRA) { - if (dev->accel.advfunc_cntl & 0x04) { - if (dev->hdisp == 640) { - dev->hdisp = 1024; - dev->vdisp = 768; + switch (mach->shadow_set & 0x03) { + case 0x00: /*Primary CRT Register set*/ + if (dev->on) { + if (mach->crt_resolution == 0x01) { + if (ATI_8514A_ULTRA) { + if (dev->accel.advfunc_cntl & 0x04) { + if (dev->hdisp == 640) { + dev->hdisp = 1024; + dev->vdisp = 768; + svga_recalctimings(svga); + } + } else { + if (dev->hdisp == 1024) { + dev->hdisp = 640; + dev->vdisp = 480; + svga_recalctimings(svga); + } + } + } else + svga_recalctimings(svga); + } else if (mach->crt_resolution == 0x02) { + if (dev->accel.advfunc_cntl & 0x04) { + if (dev->hdisp == 640) { + dev->hdisp = 1024; + dev->vdisp = 768; + svga_recalctimings(svga); + } + } else { + if (dev->hdisp == 1024) { + dev->hdisp = 640; + dev->vdisp = 480; + svga_recalctimings(svga); + } + } + } else svga_recalctimings(svga); - } } - } + break; + case 0x01: /*Shadow 640x480 CRT register set*/ + if (dev->on) { + if (!(dev->accel.advfunc_cntl & 0x04)) { + if (dev->hdisp == 1024) { + dev->hdisp = 640; + dev->vdisp = 480; + } + } + svga_recalctimings(svga); + } + break; + case 0x02: /*Shadow 1024x768 CRT register set*/ + if (dev->on) { + if (dev->accel.advfunc_cntl & 0x04) { + if (dev->hdisp == 640) { + dev->hdisp = 1024; + dev->vdisp = 768; + } + } + svga_recalctimings(svga); + } + break; + default: + break; } } } @@ -2739,6 +2786,7 @@ ati8514_recalctimings(svga_t *svga) if (dev->interlace) dev->dispend >>= 1; + mach->crt_resolution = 0x00; mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); @@ -2752,7 +2800,6 @@ ati8514_recalctimings(svga_t *svga) } } dev->accel_bpp = 8; - mach->resolution_crt = 0; svga->render8514 = ibm8514_render_8bpp; } } @@ -2808,15 +2855,15 @@ mach_recalctimings(svga_t *svga) svga->ati_4color = 0; } - mach_log("ON?=%d, override=%d.\n", dev->on, svga->override); + mach_log("ON?=%d, override=%d, gelo=%04x, gehi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, svga->hdisp); if (dev->on) { - mach_log("8514/A ON, extpitch=%d, devma=%x, vgamalatch=%x.\n", dev->ext_pitch, dev->ma, svga->ma_latch); - dev->ma_latch = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2; + dev->ma_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.ge_offset = dev->accel.ge_offset; + mach_log("8514/A ON, extpitch=%d, geoffset=%x, 8514malatch=%x, vgamalatch=%x.\n", dev->ext_pitch, mach->accel.ge_offset, dev->ma_latch, svga->ma_latch); mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x, interlace=%x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, @@ -2836,6 +2883,7 @@ mach_recalctimings(svga_t *svga) if (dev->interlace) dev->dispend >>= 1; + mach->crt_resolution = 0x00; if (ATI_MACH32) { mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, @@ -2877,7 +2925,6 @@ mach_recalctimings(svga_t *svga) dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, dev->accel_bpp, mach->shadow_set & 3, svga->hdisp); - mach->resolution_crt = 0; switch (dev->accel_bpp) { case 8: svga->render8514 = ibm8514_render_8bpp; @@ -2915,7 +2962,6 @@ mach_recalctimings(svga_t *svga) } } dev->accel_bpp = 8; - mach->resolution_crt = 0; svga->render8514 = ibm8514_render_8bpp; } } else { @@ -2973,7 +3019,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u switch (port) { case 0x2e8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) dev->htotal = val; @@ -2982,44 +3028,44 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xae8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_start, val); } - svga_recalctimings(svga); + mach_set_resolution(mach, svga); } break; case 0xee8: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_width, val); } - svga_recalctimings(svga); + mach_set_resolution(mach, svga); } break; case 0x1ee8: case 0x1ee9: if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) /*For 8514/A mode, take the shadow sets into account.*/ - svga_recalctimings(svga); + mach_set_resolution(mach, svga); break; case 0x6e8: if (len == 2) { mach_log("HDISP and HTOTAL=%04x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { - if (!(mach->shadow_cntl & 0x08)) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) + dev->htotal = (val >> 8) & 0xff; + + if (!(mach->shadow_cntl & 0x08)) { + if (dev->htotal || (mach->accel.clock_sel & 0x01)) { WRITE8(port, dev->hdisped, val); } } - if (ATI_8514A_ULTRA) { - if (!(mach->shadow_cntl & 0x04)) - dev->htotal = (val >> 8) & 0xff; - } - mach_set_resolution(mach, svga); + if (dev->htotal || (mach->accel.clock_sel & 0x01)) + mach_set_resolution(mach, svga); } } else { mach_log("HDISP and HTOTAL=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); @@ -3032,9 +3078,6 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (!(mach->shadow_cntl & 0x08)) { WRITE8(port, dev->hdisped, val); } - if (mach->resolution_crt == 0x00) - mach->resolution_crt = 0x02; - mach_set_resolution(mach, svga); } } @@ -3045,10 +3088,10 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x6e9: if (len == 1) { mach_log("HDISP and HTOTAL+1=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x04)) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x04)) dev->htotal = val; - } + mach_set_resolution(mach, svga); } } @@ -3056,7 +3099,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x12e8: if (len == 2) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x10)) { dev->v_total_reg = val; dev->v_total_reg &= 0x1fff; @@ -3064,7 +3107,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_set_resolution(mach, svga); } } else { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x10)) { WRITE8(port, dev->v_total_reg, val); dev->v_total_reg &= 0x1fff; @@ -3077,7 +3120,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x12e9: if (len == 1) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ WRITE8(port, dev->v_total_reg, val); dev->v_total_reg &= 0x1fff; @@ -3090,8 +3133,14 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x16e8: if (len == 2) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { - if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x20)) { + dev->v_disp = val; + dev->v_disp &= 0x1fff; + } + mach_set_resolution(mach, svga); + } else if (!(mach->accel.clock_sel & 0x01) && ((mach->shadow_set & 0x03) == 0x00) && dev->on) { /*Still write the parameter even after going to 8514/A mode if needed*/ + if (!(mach->shadow_cntl & 0x20)) { dev->v_disp = val; dev->v_disp &= 0x1fff; } @@ -3100,8 +3149,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); } else { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { - if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x20)) { WRITE8(port, dev->v_disp, val); dev->v_disp &= 0x1fff; } @@ -3111,8 +3160,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x16e9: if (len == 1) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { - if (!(mach->shadow_cntl & 0x20)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x20)) { WRITE8(port, dev->v_disp, val); dev->v_disp &= 0x1fff; } @@ -3125,8 +3174,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x1ae8: if (len == 2) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { - if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x10)) { dev->v_sync_start = val; dev->v_sync_start &= 0x1fff; } @@ -3135,8 +3184,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); } else { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { - if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x10)) { WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; } @@ -3146,8 +3195,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x1ae9: if (len == 1) { - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03)) || ATI_8514A_ULTRA) { - if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ + if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ + if (!(mach->shadow_cntl & 0x10)) { WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; } @@ -3168,7 +3217,6 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u svga_recalctimings(svga); break; - case 0x42e8: case 0x42e9: mach_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); @@ -3672,11 +3720,19 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if ((mach->shadow_set & 0x03) == 0x00) mach_log("Primary CRT register set.\n"); else if ((mach->shadow_set & 0x03) == 0x01) { + mach->crt_resolution = 0x01; mach_log("CRT Shadow Set 1: 640x480.\n"); - mach->resolution_crt = 0x01; } else if ((mach->shadow_set & 0x03) == 0x02) { + mach->crt_resolution = 0x02; mach_log("CRT Shadow Set 2: 1024x768.\n"); - mach->resolution_crt = 0x02; + } + + if (ATI_MACH32) { + if ((mach->shadow_set & 0x300) == 0x000) { + mach_log("Load both SRC/DST GE Offset/Pitch.\n"); + mach->accel.ge_offset_lo = 0; + mach->accel.ge_offset_hi = 0; + } } break; @@ -4182,11 +4238,11 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 4: case 6: if (dev->accel.sy < 0) - dev->data_available = 0; + dev->data_available2 = 0; break; default: if (!dev->accel.sy) - dev->data_available = 0; + dev->data_available2 = 0; break; } } @@ -4525,10 +4581,10 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) if (cmd == 6) { if ((dev->subsys_cntl & INT_GE_BSY) && !(dev->subsys_stat & INT_GE_BSY) && - (dev->accel.dx_ibm >= clip_l) && - (dev->accel.dx_ibm <= clip_r_ibm) && - (dev->accel.dy_ibm >= clip_t) && - (dev->accel.dy_ibm <= clip_b_ibm)) + (dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r_ibm) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b_ibm)) temp |= INT_GE_BSY; } else { if ((dev->subsys_cntl & INT_GE_BSY) && @@ -4678,6 +4734,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) temp = 0x0000; } } else { + mach_log("ScratchPad0=%x.\n", mach->accel.scratch0); if (mach->accel.scratch0 == 0x1234) temp = 0x0000; } @@ -7019,7 +7076,7 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) dev->disp_cntl = 0x33; mach->accel.clock_sel = 0x1c; mach->shadow_set = 0x02; - mach->resolution_crt = 0x02; + mach->crt_resolution = 0x02; io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); ati8514_io_set(svga); From 8ff30ab2e63c55a03190b70040bc37bdac703d8d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 30 Mar 2025 23:17:58 +0200 Subject: [PATCH 0638/1190] Mach64 ISA/VLB LFB update of the day (March 30th, 2025) The LFB can now be enabled properly on the ISA/VLB variants of the Mach64GX. --- src/video/vid_ati_mach64.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 24935e3a2..4ec9afff8 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -3768,6 +3768,9 @@ mach64_ext_outb(uint16_t port, uint8_t val, void *priv) case 0x6aee: case 0x6aef: WRITE8(port, mach64->config_cntl, val); + if (!mach64->pci) + mach64->linear_base = (mach64->config_cntl & 0x3ff0) << 18; + mach64_updatemapping(mach64); break; From 3f0138a58c117c96fec7e74326ca0a31fa48e537 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 31 Mar 2025 04:35:17 +0200 Subject: [PATCH 0639/1190] VIA On-board AC'97 Audio: Fix PCI registers, implement PCI Power Manager capability registers, properly separate the modem SGD from the audio SGD, and fix 5-bit volume attenuation, this also fixes audio playback in NT 4.0. --- src/chipset/via_pipc.c | 149 +++++++++++++++++------- src/sound/snd_ac97_codec.c | 5 +- src/sound/snd_ac97_via.c | 224 ++++++++++++++++++++----------------- 3 files changed, 233 insertions(+), 145 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 6b855f5aa..248664983 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -493,14 +493,28 @@ pipc_reset_hard(void *priv) } dev->ac97_regs[i][0x1c] = 0x01; + if (i == 0) { + dev->ac97_regs[i][0x34] = 0xc0; + + dev->ac97_regs[i][0xc0] = 0x01; + dev->ac97_regs[i][0xc1] = 0x00; + dev->ac97_regs[i][0xc2] = 0x03; + dev->ac97_regs[i][0xc3] = 0x00; + + dev->ac97_regs[i][0xc4] = 0x00; + dev->ac97_regs[i][0xc5] = 0x00; + dev->ac97_regs[i][0xc6] = 0x00; + dev->ac97_regs[i][0xc7] = 0x00; + } + dev->ac97_regs[i][0x3d] = 0x03; - if (i == 0) + if (i == 0) { dev->ac97_regs[i][0x40] = 0x01; - - dev->ac97_regs[i][0x43] = 0x1c; - dev->ac97_regs[i][0x48] = 0x01; - dev->ac97_regs[i][0x4b] = 0x02; + dev->ac97_regs[i][0x43] = 0x1c; + dev->ac97_regs[i][0x48] = 0x01; + dev->ac97_regs[i][0x4b] = 0x00; + } pipc_sgd_handlers(dev, i); pipc_codec_handlers(dev, i); @@ -742,10 +756,12 @@ pipc_codec_handlers(pipc_t *dev, uint8_t modem) if (!dev->ac97) return; + uint32_t base = (dev->ac97_regs[modem][0x1d] << 8); + if (modem) - ac97_via_remap_modem_codec(dev->ac97, dev->ac97_regs[1][0x1d] << 8, dev->ac97_regs[1][0x04] & PCI_COMMAND_IO); + ac97_via_remap_modem_codec(dev->ac97, base, dev->ac97_regs[1][0x04] & PCI_COMMAND_IO); else - ac97_via_remap_audio_codec(dev->ac97, dev->ac97_regs[0][0x1d] << 8, dev->ac97_regs[0][0x04] & PCI_COMMAND_IO); + ac97_via_remap_audio_codec(dev->ac97, base, dev->ac97_regs[0][0x04] & PCI_COMMAND_IO); } static uint8_t @@ -1204,7 +1220,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x77: if ((dev->local >= VIA_PIPC_686A) && (val & 0x10)) - pclog("PIPC: Warning: Internal I/O APIC enabled.\n"); + warning("PIPC: Warning: Internal I/O APIC enabled.\n"); nvr_via_wp_set(!!(val & 0x04), 0x32, dev->nvr); nvr_via_wp_set(!!(val & 0x02), 0x0d, dev->nvr); break; @@ -1488,36 +1504,39 @@ pipc_write(int func, int addr, uint8_t val, void *priv) break; } } else if (func <= pm_func + 2) { /* AC97 / MC97 */ - /* Read-only addresses. */ - if ((addr < 0x4) || ((addr >= 0x6) && (addr < 0x9)) || ((addr >= 0xc) && (addr < 0x11)) || (addr == 0x16) || (addr == 0x17) || (addr == 0x1a) || (addr == 0x1b) || ((addr >= 0x1e) && (addr < 0x2c)) || ((addr >= 0x30) && (addr < 0x34)) || ((addr >= 0x35) && (addr < 0x3c)) || ((addr >= 0x3d) && (addr < 0x41)) || ((addr >= 0x45) && (addr < 0x4a)) || (addr >= 0x4c)) - return; - /* Small shortcut. */ func = func - pm_func - 1; - /* Check disable bits and specific read-only addresses for both controllers. */ - if ((func == 0) && (((addr >= 0x09) && (addr < 0xc)) || (addr == 0x44) || (dev->pci_isa_regs[0x85] & 0x04))) + /* Check disable bits. */ + if ((func == 0) && (dev->pci_isa_regs[0x85] & 0x04)) return; - if ((func == 1) && ((addr == 0x14) || (addr == 0x15) || (addr == 0x18) || (addr == 0x19) || (addr == 0x42) || (addr == 0x43) || (addr == 0x48) || (addr == 0x4a) || (addr == 0x4b) || (dev->pci_isa_regs[0x85] & 0x08))) + if ((func == 1) && (dev->pci_isa_regs[0x85] & 0x08)) return; switch (addr) { case 0x04: - dev->ac97_regs[func][addr] = val; + dev->ac97_regs[func][addr] = val & 0x01; pipc_sgd_handlers(dev, func); + if (func == 0) { + pipc_fmnmi_handlers(dev, func); + pipc_sb_handlers(dev, func); + } pipc_codec_handlers(dev, func); - pipc_fmnmi_handlers(dev, func); break; case 0x09: case 0x0a: case 0x0b: - if (dev->ac97_regs[func][0x44] & 0x20) + /* Not writable on audio, only on modem. */ + if ((func == 1) && (dev->ac97_regs[func][0x44] & 0x20)) dev->ac97_regs[func][addr] = val; break; - case 0x10: + /* + The lowest 10 bytes are always 0x01, indicating + a 256-byte I/O space. + */ case 0x11: dev->ac97_regs[func][addr] = val; pipc_sgd_handlers(dev, func); @@ -1525,21 +1544,26 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x14: case 0x15: - if (addr == 0x14) - val = (val & 0xfc) | 1; - dev->ac97_regs[func][addr] = val; - pipc_fmnmi_handlers(dev, func); + /* Not present on modem. */ + if (func == 0) { + if (addr == 0x14) + val = (val & 0xfc) | 1; + dev->ac97_regs[func][addr] = val; + pipc_fmnmi_handlers(dev, func); + } break; case 0x18: case 0x19: - if (addr == 0x18) - val = (val & 0xfc) | 1; - dev->ac97_regs[func][addr] = val; - pipc_sb_handlers(dev, func); + /* Not present on modem. */ + if (func == 0) { + if (addr == 0x18) + val = (val & 0xfc) | 1; + dev->ac97_regs[func][addr] = val; + pipc_sb_handlers(dev, func); + } break; - case 0x1c: case 0x1d: dev->ac97_regs[func][addr] = val; pipc_codec_handlers(dev, func); @@ -1549,39 +1573,84 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x2d: case 0x2e: case 0x2f: - if ((func == 0) && (dev->ac97_regs[func][0x42] & 0x20)) + if (((func == 0) && (dev->ac97_regs[func][0x42] & 0x20)) || + ((func == 1) && (dev->ac97_regs[func][0x44] & 0x10))) dev->ac97_regs[func][addr] = val; break; + case 0x3c: + dev->ac97_regs[func][addr] = val & 0x0f; + break; + case 0x41: dev->ac97_regs[func][addr] = val; ac97_via_write_control(dev->ac97, func, val); break; case 0x42: - case 0x4a: - case 0x4b: - dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val; - gameport_remap(dev->gameport, (dev->ac97_regs[0][0x42] & 0x08) ? ((dev->ac97_regs[0][0x4b] << 8) | (dev->ac97_regs[0][0x4a] & 0xf8)) : 0); - if (addr == 0x42) - pipc_sb_handlers(dev, func); + case 0x4a ... 0x4b: + if (func == 0) { + dev->ac97_regs[func][addr] = val; + gameport_remap(dev->gameport, (dev->ac97_regs[func][0x42] & 0x08) ? + ((dev->ac97_regs[func][0x4b] << 8) | + (dev->ac97_regs[func][0x4a] & 0xf8)) : 0); + + if (addr == 0x42) + pipc_sb_handlers(dev, func); + } break; case 0x43: - dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val; + if (func == 0) + dev->ac97_regs[func][addr] = val; break; case 0x44: - dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val & 0xf0; + if (func == 1) + dev->ac97_regs[func][addr] = val & 0xf0; break; - case 0x45: case 0x48: - dev->ac97_regs[0][addr] = dev->ac97_regs[1][addr] = val & 0x0f; + if (func == 0) + dev->ac97_regs[func][addr] = val & 0x0f; + break; + + case 0x80: + case 0x81: + case 0x82: + dev->ac97_regs[func][addr] = val; + break; + case 0x83: + dev->ac97_regs[func][addr] = ((dev->ac97_regs[func][addr] & 0x01) | + (val & 0xc0)) & ~(val & 0x0a); + break; + + case 0x88: + case 0x89: + dev->ac97_regs[func][addr] = val; + break; + case 0x8a: + case 0x8b: + dev->ac97_regs[func][addr] &= ~val; + break; + + case 0x8e: + case 0x8f: + dev->ac97_regs[func][addr] = val; + break; + + case 0xc4: + if (func == 0) + dev->ac97_regs[func][addr] = (dev->ac97_regs[func][addr] & 0x0c) | + (val & 0x03); + break; + case 0xc5: + if (func == 0) + dev->ac97_regs[func][addr] = (dev->ac97_regs[func][addr] & 0x60) | + (val & 0x9f); break; default: - dev->ac97_regs[func][addr] = val; break; } } diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index e92830f67..7a9951289 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -539,8 +539,9 @@ ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) *l = codec_attn[0x3f - (l_val & 0x3f)]; *r = codec_attn[0x3f - (r_val & 0x3f)]; } else { /* 5-bit gain */ - *l = codec_attn[0x47 - (l_val & 0x1f)]; - *r = codec_attn[0x47 - (r_val & 0x1f)]; + /* Yes, 0x3f is correct, the 0x47 was most likely a decimal-hex mix-up. */ + *l = codec_attn[0x3f - (l_val & 0x1f)]; + *r = codec_attn[0x3f - (r_val & 0x1f)]; } /* Apply per-channel mute and center/LFE powerdowns where applicable. */ diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 8c1e45c40..68ef5fe5d 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -24,6 +24,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include <86box/dma.h> #include <86box/mem.h> #include <86box/pci.h> #include <86box/pic.h> @@ -31,10 +32,13 @@ #include <86box/sound.h> #include <86box/timer.h> #include <86box/plat_unused.h> +#include "cpu.h" typedef struct ac97_via_sgd_t { uint8_t id; uint8_t always_run; + uint8_t modem; + uint8_t pad; struct _ac97_via_ *dev; uint32_t entry_ptr; @@ -63,7 +67,7 @@ typedef struct _ac97_via_ { uint16_t audio_codec_base; uint16_t modem_sgd_base; uint16_t modem_codec_base; - uint8_t sgd_regs[256]; + uint8_t sgd_regs[2][256]; uint8_t pcm_enabled : 1; uint8_t fm_enabled : 1; uint8_t vsr_enabled : 1; @@ -78,7 +82,7 @@ typedef struct _ac97_via_ { int irq_pin; ac97_codec_t *codec[2][2]; - ac97_via_sgd_t sgd[6]; + ac97_via_sgd_t sgd[2][6]; int master_vol_l; int master_vol_r; @@ -105,7 +109,7 @@ ac97_via_log(const char *fmt, ...) #endif static void ac97_via_sgd_process(void *priv); -static void ac97_via_update_codec(ac97_via_t *dev); +static void ac97_via_update_codec(ac97_via_t *dev, int modem); static void ac97_via_speed_changed(void *priv); static void ac97_via_filter_cd_audio(int channel, double *buffer, void *priv); @@ -160,29 +164,29 @@ ac97_via_write_control(void *priv, uint8_t modem, uint8_t val) /* Start or stop PCM playback. */ i = (val & 0xf4) == 0xc4; if (i && !dev->pcm_enabled) - timer_advance_u64(&dev->sgd[0].poll_timer, dev->sgd[0].timer_latch); + timer_advance_u64(&dev->sgd[0][0].poll_timer, dev->sgd[0][0].timer_latch); dev->pcm_enabled = i; /* Start or stop FM playback. */ i = (val & 0xf2) == 0xc2; if (i && !dev->fm_enabled) - timer_advance_u64(&dev->sgd[2].poll_timer, dev->sgd[2].timer_latch); + timer_advance_u64(&dev->sgd[0][2].poll_timer, dev->sgd[0][2].timer_latch); dev->fm_enabled = i; /* Update primary audio codec state. */ if (dev->codec[0][0]) - ac97_via_update_codec(dev); + ac97_via_update_codec(dev, 0); } } static void -ac97_via_update_irqs(ac97_via_t *dev) +ac97_via_update_irqs(ac97_via_t *dev, int modem) { /* Check interrupt flags in all SGDs. */ for (uint8_t i = 0x00; i < ((sizeof(dev->sgd) / sizeof(dev->sgd[0])) << 4); i += 0x10) { /* Stop immediately if any flag is set. Doing it this way optimizes rising edges for the playback SGD (0 - first to be checked). */ - if (dev->sgd_regs[i] & (dev->sgd_regs[i | 0x2] & 0x03)) { + if (dev->sgd_regs[modem][i] & (dev->sgd_regs[modem][i | 0x2] & 0x03)) { pci_set_irq(dev->pci_slot, dev->irq_pin, &dev->irq_state); return; } @@ -192,15 +196,15 @@ ac97_via_update_irqs(ac97_via_t *dev) } static void -ac97_via_update_codec(ac97_via_t *dev) +ac97_via_update_codec(ac97_via_t *dev, int modem) { /* Get primary audio codec. */ - ac97_codec_t *codec = dev->codec[0][0]; + ac97_codec_t *codec = dev->codec[modem][0]; /* Update volumes according to codec registers. */ ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); - ac97_codec_getattn(codec, 0x18, &dev->sgd[0].vol_l, &dev->sgd[0].vol_r); - ac97_codec_getattn(codec, 0x18, &dev->sgd[2].vol_l, &dev->sgd[2].vol_r); /* VIAFMTSR sets Master, CD and PCM volumes to 0 dB */ + ac97_codec_getattn(codec, 0x18, &dev->sgd[modem][0].vol_l, &dev->sgd[modem][0].vol_r); + ac97_codec_getattn(codec, 0x18, &dev->sgd[modem][2].vol_l, &dev->sgd[modem][2].vol_r); /* VIAFMTSR sets Master, CD and PCM volumes to 0 dB */ ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); /* Update sample rate according to codec registers and the variable sample rate flag. */ @@ -211,9 +215,9 @@ uint8_t ac97_via_sgd_read(uint16_t addr, void *priv) { const ac97_via_t *dev = (ac97_via_t *) priv; -#ifdef ENABLE_AC97_VIA_LOG +// #ifdef ENABLE_AC97_VIA_LOG uint8_t modem = (addr & 0xff00) == dev->modem_sgd_base; -#endif +// #endif addr &= 0xff; uint8_t ret; @@ -221,83 +225,83 @@ ac97_via_sgd_read(uint16_t addr, void *priv) /* Process SGD channel registers. */ switch (addr & 0xf) { case 0x4: - ret = dev->sgd[addr >> 4].entry_ptr; + ret = dev->sgd[modem][addr >> 4].entry_ptr; break; case 0x5: - ret = dev->sgd[addr >> 4].entry_ptr >> 8; + ret = dev->sgd[modem][addr >> 4].entry_ptr >> 8; break; case 0x6: - ret = dev->sgd[addr >> 4].entry_ptr >> 16; + ret = dev->sgd[modem][addr >> 4].entry_ptr >> 16; break; case 0x7: - ret = dev->sgd[addr >> 4].entry_ptr >> 24; + ret = dev->sgd[modem][addr >> 4].entry_ptr >> 24; break; case 0xc: - ret = dev->sgd[addr >> 4].sample_count; + ret = dev->sgd[modem][addr >> 4].sample_count; break; case 0xd: - ret = dev->sgd[addr >> 4].sample_count >> 8; + ret = dev->sgd[modem][addr >> 4].sample_count >> 8; break; case 0xe: - ret = dev->sgd[addr >> 4].sample_count >> 16; + ret = dev->sgd[modem][addr >> 4].sample_count >> 16; break; default: - ret = dev->sgd_regs[addr]; + ret = dev->sgd_regs[modem][addr]; break; } } else { /* Process regular registers. */ switch (addr) { case 0x84: - ret = (dev->sgd_regs[0x00] & 0x01); - ret |= (dev->sgd_regs[0x10] & 0x01) << 1; - ret |= (dev->sgd_regs[0x20] & 0x01) << 2; + ret = (dev->sgd_regs[modem][0x00] & 0x01); + ret |= (dev->sgd_regs[modem][0x10] & 0x01) << 1; + ret |= (dev->sgd_regs[modem][0x20] & 0x01) << 2; - ret |= (dev->sgd_regs[0x00] & 0x02) << 3; - ret |= (dev->sgd_regs[0x10] & 0x02) << 4; - ret |= (dev->sgd_regs[0x20] & 0x02) << 5; + ret |= (dev->sgd_regs[modem][0x00] & 0x02) << 3; + ret |= (dev->sgd_regs[modem][0x10] & 0x02) << 4; + ret |= (dev->sgd_regs[modem][0x20] & 0x02) << 5; break; case 0x85: - ret = (dev->sgd_regs[0x00] & 0x04) >> 2; - ret |= (dev->sgd_regs[0x10] & 0x04) >> 1; - ret |= (dev->sgd_regs[0x20] & 0x04); + ret = (dev->sgd_regs[modem][0x00] & 0x04) >> 2; + ret |= (dev->sgd_regs[modem][0x10] & 0x04) >> 1; + ret |= (dev->sgd_regs[modem][0x20] & 0x04); - ret |= (dev->sgd_regs[0x00] & 0x80) >> 3; - ret |= (dev->sgd_regs[0x10] & 0x80) >> 2; - ret |= (dev->sgd_regs[0x20] & 0x80) >> 1; + ret |= (dev->sgd_regs[modem][0x00] & 0x80) >> 3; + ret |= (dev->sgd_regs[modem][0x10] & 0x80) >> 2; + ret |= (dev->sgd_regs[modem][0x20] & 0x80) >> 1; break; case 0x86: - ret = (dev->sgd_regs[0x40] & 0x01); - ret |= (dev->sgd_regs[0x50] & 0x01) << 1; + ret = (dev->sgd_regs[modem][0x40] & 0x01); + ret |= (dev->sgd_regs[modem][0x50] & 0x01) << 1; - ret |= (dev->sgd_regs[0x40] & 0x02) << 3; - ret |= (dev->sgd_regs[0x50] & 0x02) << 4; + ret |= (dev->sgd_regs[modem][0x40] & 0x02) << 3; + ret |= (dev->sgd_regs[modem][0x50] & 0x02) << 4; break; case 0x87: - ret = (dev->sgd_regs[0x40] & 0x04) >> 2; - ret |= (dev->sgd_regs[0x50] & 0x04) >> 1; + ret = (dev->sgd_regs[modem][0x40] & 0x04) >> 2; + ret |= (dev->sgd_regs[modem][0x50] & 0x04) >> 1; - ret |= (dev->sgd_regs[0x40] & 0x80) >> 3; - ret |= (dev->sgd_regs[0x50] & 0x80) >> 2; + ret |= (dev->sgd_regs[modem][0x40] & 0x80) >> 3; + ret |= (dev->sgd_regs[modem][0x50] & 0x80) >> 2; break; default: - ret = dev->sgd_regs[addr]; + ret = dev->sgd_regs[modem][addr]; break; } } - ac97_via_log("AC97 VIA %d: sgd_read(%02X) = %02X\n", modem, addr, ret); + ac97_via_log("[%04X:%08X] [%i] AC97 VIA %d: sgd_read(%02X) = %02X\n", CS, cpu_state.pc, msw & 1, modem, addr, ret); return ret; } @@ -311,7 +315,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) ac97_codec_t *codec; addr &= 0xff; - ac97_via_log("AC97 VIA %d: sgd_write(%02X, %02X)\n", modem, addr, val); + ac97_via_log("[%04X:%08X] [%i] AC97 VIA %d: sgd_write(%02X, %02X)\n", CS, cpu_state.pc, msw & 1, modem, addr, val); + + // if ((CS == 0x10000) && (cpu_state.pc == 0x000073d1)) /* Check function-specific read only registers. */ if ((addr >= (modem ? 0x00 : 0x40)) && (addr < (modem ? 0x40 : 0x60))) @@ -324,42 +330,42 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) switch (addr & 0xf) { case 0x0: /* Clear RWC status bits. */ - dev->sgd_regs[addr] &= ~(val & 0x07); + dev->sgd_regs[modem][addr] &= ~(val & 0x07); /* Update status interrupts. */ - ac97_via_update_irqs(dev); + ac97_via_update_irqs(dev, modem); return; case 0x1: /* Start SGD if requested. */ if (val & 0x80) { - if (dev->sgd_regs[addr & 0xf0] & 0x80) { + if (dev->sgd_regs[modem][addr & 0xf0] & 0x80) { /* Queue SGD trigger if already running. */ - dev->sgd_regs[addr & 0xf0] |= 0x08; + dev->sgd_regs[modem][addr & 0xf0] |= 0x08; } else { /* Start SGD immediately. */ - dev->sgd_regs[addr & 0xf0] = (dev->sgd_regs[addr & 0xf0] & ~0x47) | 0x80; + dev->sgd_regs[modem][addr & 0xf0] = (dev->sgd_regs[modem][addr & 0xf0] & ~0x47) | 0x80; /* Start at the specified entry pointer. */ - dev->sgd[addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[(addr & 0xf0) | 0x4]) & 0xfffffffe; - dev->sgd[addr >> 4].restart = 2; + dev->sgd[modem][addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[modem][(addr & 0xf0) | 0x4]) & 0xfffffffe; + dev->sgd[modem][addr >> 4].restart = 2; /* Start the actual SGD process. */ - ac97_via_sgd_process(&dev->sgd[addr >> 4]); + ac97_via_sgd_process(&dev->sgd[modem][addr >> 4]); } } /* Stop SGD if requested. */ if (val & 0x40) - dev->sgd_regs[addr & 0xf0] &= ~0x88; + dev->sgd_regs[modem][addr & 0xf0] &= ~0x88; val &= 0x08; /* (Un)pause SGD if requested. */ if (val & 0x08) - dev->sgd_regs[addr & 0xf0] |= 0x40; + dev->sgd_regs[modem][addr & 0xf0] |= 0x40; else - dev->sgd_regs[addr & 0xf0] &= ~0x40; + dev->sgd_regs[modem][addr & 0xf0] &= ~0x40; break; @@ -387,7 +393,7 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) case 0x82: /* Determine the selected codec. */ - i = !!(dev->sgd_regs[0x83] & 0x40); + i = !!(dev->sgd_regs[modem][0x83] & 0x40); codec = dev->codec[modem][i]; /* Keep value in register if this codec is not present. */ @@ -395,20 +401,20 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) /* Read from or write to codec. */ if (val & 0x80) { if (val & 1) { /* return 0x0000 on unaligned reads (real 686B behavior) */ - dev->sgd_regs[0x80] = dev->sgd_regs[0x81] = 0x00; + dev->sgd_regs[modem][0x80] = dev->sgd_regs[modem][0x81] = 0x00; } else { - *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[0x80]) = ac97_codec_readw(codec, val); + *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[modem][0x80]) = ac97_codec_readw(codec, val); } /* Flag data/status/index for this codec as valid. */ - dev->sgd_regs[0x83] |= 0x02 << (i << 1); + dev->sgd_regs[modem][0x83] |= 0x02 << (i << 1); } else if (!(val & 1)) { /* do nothing on unaligned writes */ ac97_codec_writew(codec, val, - *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[0x80])); + *((uint16_t *) &dev->codec_shadow[modem].regs_codec[i][val & 0x7f]) = *((uint16_t *) &dev->sgd_regs[modem][0x80])); /* Update primary audio codec state if that codec was written to. */ if (!modem && !i) { - ac97_via_update_codec(dev); + ac97_via_update_codec(dev, 0); /* Set up CD audio filter if CD volume was written to. Setting it up at init prevents CD audio from working on other cards, but @@ -424,9 +430,9 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) case 0x83: /* Clear RWC status bits. */ #if 0 /* race condition with Linux accessing a register and clearing status bits on the same dword write */ - val = (dev->sgd_regs[addr] & ~(val & 0x0a)) | (val & 0xc0); + val = ((dev->sgd_regs[modem][addr] & 0x3f) & ~(val & 0x0a)) | (val & 0xc0); #else - val = dev->sgd_regs[addr] | (val & 0xc0); + val = (dev->sgd_regs[modem][addr] & 0x3f) | (val & 0xc0); #endif break; @@ -435,7 +441,7 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv) } } - dev->sgd_regs[addr] = val; + dev->sgd_regs[modem][addr] = val; } void @@ -479,6 +485,8 @@ ac97_via_codec_read(uint16_t addr, void *priv) ac97_via_log("AC97 VIA %d: codec_read(%02X) = %02X\n", modem, addr, ret); + ac97_via_log("[%04X:%08X] [%i] AC97 VIA %d: codec_read(%02X) = %02X\n", CS, cpu_state.pc, msw & 1, modem, addr, ret); + return ret; } @@ -489,6 +497,8 @@ ac97_via_codec_write(uint16_t addr, uint8_t val, void *priv) uint8_t modem = (addr & 0xff00) == dev->modem_codec_base; addr &= 0xff; + ac97_via_log("[%04X:%08X] [%i] AC97 VIA %d: codec_write(%02X, %02X)\n", CS, cpu_state.pc, msw & 1, modem, addr, val); + ac97_via_log("AC97 VIA %d: codec_write(%02X, %02X)\n", modem, addr, val); /* Unknown behavior, maybe it does write to the shadow registers? */ @@ -501,12 +511,12 @@ ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint8_t enable) ac97_via_t *dev = (ac97_via_t *) priv; if (dev->audio_codec_base) - io_removehandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + io_removehandler(dev->audio_codec_base, 4, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); dev->audio_codec_base = new_io_base; if (dev->audio_codec_base && enable) - io_sethandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + io_sethandler(dev->audio_codec_base, 4, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); } void @@ -515,12 +525,12 @@ ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable) ac97_via_t *dev = (ac97_via_t *) priv; if (dev->modem_codec_base) - io_removehandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + io_removehandler(dev->modem_codec_base, 4, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); dev->modem_codec_base = new_io_base; if (dev->modem_codec_base && enable) - io_sethandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); + io_sethandler(dev->modem_codec_base, 4, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev); } static void @@ -551,12 +561,12 @@ ac97_via_sgd_process(void *priv) ac97_via_t *dev = sgd->dev; /* Stop if this SGD is not active. */ - uint8_t sgd_status = dev->sgd_regs[sgd->id] & 0xc4; + uint8_t sgd_status = dev->sgd_regs[sgd->modem][sgd->id] & 0xc4; if (!(sgd_status & 0x80)) return; /* Schedule next run. */ - timer_on_auto(&sgd->dma_timer, 10.0); + timer_on_auto(&sgd->dma_timer, 1.0); /* Process SGD if it's active, and the FIFO has room or is disabled. */ if (((sgd_status & 0xc7) == 0x80) && (sgd->always_run || ((sgd->fifo_end - sgd->fifo_pos) <= (sizeof(sgd->fifo) - 4)))) { @@ -564,13 +574,15 @@ ac97_via_sgd_process(void *priv) if (sgd->restart) { /* (Re)load entry pointer if required. */ if (sgd->restart & 2) - sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->id | 0x4]) & 0xfffffffe; /* TODO: probe real hardware - does "even addr" actually mean dword aligned? */ + sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->modem][sgd->id | 0x4]) & 0xfffffffe; /* TODO: probe real hardware - does "even addr" actually mean dword aligned? */ sgd->restart = 0; /* Read entry. */ - sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr); + // sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr); + dma_bm_read(sgd->entry_ptr, (uint8_t *) &sgd->sample_ptr, 4, 4); sgd->entry_ptr += 4; - sgd->sample_count = mem_readl_phys(sgd->entry_ptr); + // sgd->sample_count = mem_readl_phys(sgd->entry_ptr); + dma_bm_read(sgd->entry_ptr, (uint8_t *) &sgd->sample_count, 4, 4); sgd->entry_ptr += 4; #ifdef ENABLE_AC97_VIA_LOG if (((sgd->sample_ptr == 0xffffffff) && (sgd->sample_count == 0xffffffff)) || ((sgd->sample_ptr == 0x00000000) && (sgd->sample_count == 0x00000000))) @@ -588,10 +600,12 @@ ac97_via_sgd_process(void *priv) if (sgd->id & 0x10) { /* Write channel: read data from FIFO. */ - mem_writel_phys(sgd->sample_ptr, *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)])); + // mem_writel_phys(sgd->sample_ptr, *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)])); + dma_bm_write(sgd->sample_ptr, &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)], 4, 4); } else { /* Read channel: write data to FIFO. */ - *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr); + // *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr); + dma_bm_read(sgd->sample_ptr, &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)], 4, 4); } sgd->fifo_end += 4; sgd->sample_ptr += 4; @@ -608,17 +622,17 @@ ac97_via_sgd_process(void *priv) ac97_via_log(" with STOP"); /* Raise STOP to pause SGD. */ - dev->sgd_regs[sgd->id] |= 0x04; + dev->sgd_regs[sgd->modem][sgd->id] |= 0x04; } if (sgd->entry_flags & 0x40) { ac97_via_log(" with FLAG"); /* Raise FLAG to pause SGD. */ - dev->sgd_regs[sgd->id] |= 0x01; + dev->sgd_regs[sgd->modem][sgd->id] |= 0x01; #ifdef ENABLE_AC97_VIA_LOG - if (dev->sgd_regs[sgd->id | 0x2] & 0x01) + if (dev->sgd_regs[sgd->modem][sgd->id | 0x2] & 0x01) ac97_via_log(" interrupt"); #endif } @@ -627,19 +641,19 @@ ac97_via_sgd_process(void *priv) ac97_via_log(" with EOL"); /* Raise EOL. */ - dev->sgd_regs[sgd->id] |= 0x02; + dev->sgd_regs[sgd->modem][sgd->id] |= 0x02; #ifdef ENABLE_AC97_VIA_LOG - if (dev->sgd_regs[sgd->id | 0x2] & 0x02) + if (dev->sgd_regs[sgd->modem][sgd->id | 0x2] & 0x02) ac97_via_log(" interrupt"); #endif /* Restart SGD if a trigger is queued or auto-start is enabled. */ - if ((dev->sgd_regs[sgd->id] & 0x08) || (dev->sgd_regs[sgd->id | 0x2] & 0x80)) { + if ((dev->sgd_regs[sgd->modem][sgd->id] & 0x08) || (dev->sgd_regs[sgd->modem][sgd->id | 0x2] & 0x80)) { ac97_via_log(" restart"); /* Un-queue trigger. */ - dev->sgd_regs[sgd->id] &= ~0x08; + dev->sgd_regs[sgd->modem][sgd->id] &= ~0x08; /* Go back to the starting block on the next run. */ sgd->restart = 2; @@ -647,13 +661,13 @@ ac97_via_sgd_process(void *priv) ac97_via_log(" finish"); /* Terminate SGD. */ - dev->sgd_regs[sgd->id] &= ~0x80; + dev->sgd_regs[sgd->modem][sgd->id] &= ~0x80; } } ac97_via_log("\n"); /* Fire any requested status interrupts. */ - ac97_via_update_irqs(dev); + ac97_via_update_irqs(dev, sgd->modem); } } } @@ -662,7 +676,7 @@ static void ac97_via_poll_stereo(void *priv) { ac97_via_t *dev = (ac97_via_t *) priv; - ac97_via_sgd_t *sgd = &dev->sgd[0]; /* Audio Read */ + ac97_via_sgd_t *sgd = &dev->sgd[0][0]; /* Audio Read */ /* Schedule next run if PCM playback is enabled. */ if (dev->pcm_enabled) @@ -672,7 +686,7 @@ ac97_via_poll_stereo(void *priv) ac97_via_update_stereo(dev, sgd); /* Feed next sample from the FIFO. */ - switch (dev->sgd_regs[sgd->id | 0x2] & 0x30) { + switch (dev->sgd_regs[0][sgd->id | 0x2] & 0x30) { case 0x00: /* Mono, 8-bit PCM */ if ((sgd->fifo_end - sgd->fifo_pos) >= 1) { sgd->out_l = sgd->out_r = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8; @@ -718,7 +732,7 @@ static void ac97_via_poll_fm(void *priv) { ac97_via_t *dev = (ac97_via_t *) priv; - ac97_via_sgd_t *sgd = &dev->sgd[2]; /* FM Read */ + ac97_via_sgd_t *sgd = &dev->sgd[0][2]; /* FM Read */ /* Schedule next run if FM playback is enabled. */ if (dev->fm_enabled) @@ -746,15 +760,15 @@ ac97_via_get_buffer(int32_t *buffer, int len, void *priv) { ac97_via_t *dev = (ac97_via_t *) priv; - ac97_via_update_stereo(dev, &dev->sgd[0]); - ac97_via_update_stereo(dev, &dev->sgd[2]); + ac97_via_update_stereo(dev, &dev->sgd[0][0]); + ac97_via_update_stereo(dev, &dev->sgd[0][2]); for (int c = 0; c < len * 2; c++) { - buffer[c] += dev->sgd[0].buffer[c] / 2; - buffer[c] += dev->sgd[2].buffer[c] / 2; + buffer[c] += dev->sgd[0][0].buffer[c] / 2; + buffer[c] += dev->sgd[0][2].buffer[c] / 2; } - dev->sgd[0].pos = dev->sgd[2].pos = 0; + dev->sgd[0][0].pos = dev->sgd[0][2].pos = 0; } static void @@ -780,8 +794,8 @@ ac97_via_speed_changed(void *priv) else freq = (double) SOUND_FREQ; - dev->sgd[0].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq)); - dev->sgd[2].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0)); /* FM operates at a fixed 24 KHz */ + dev->sgd[0][0].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq)); + dev->sgd[0][2].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0)); /* FM operates at a fixed 24 KHz */ } static void * @@ -799,19 +813,23 @@ ac97_via_init(UNUSED(const device_t *info)) /* Set up SGD channels. */ for (uint8_t i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) { - dev->sgd[i].id = i << 4; - dev->sgd[i].dev = dev; + for (uint8_t j = 0; j < 2; j++) { + dev->sgd[j][i].id = i << 4; + dev->sgd[j][i].dev = dev; - /* Disable the FIFO on SGDs we don't care about. */ - if ((i != 0) && (i != 2)) - dev->sgd[i].always_run = 1; + dev->sgd[j][i].modem = j; - timer_add(&dev->sgd[i].dma_timer, ac97_via_sgd_process, &dev->sgd[i], 0); + /* Disable the FIFO on SGDs we don't care about. */ + if ((i != 0) && (i != 2)) + dev->sgd[j][i].always_run = 1; + + timer_add(&dev->sgd[j][i].dma_timer, ac97_via_sgd_process, &dev->sgd[j][i], 0); + } } /* Set up playback pollers. */ - timer_add(&dev->sgd[0].poll_timer, ac97_via_poll_stereo, dev, 0); - timer_add(&dev->sgd[2].poll_timer, ac97_via_poll_fm, dev, 0); + timer_add(&dev->sgd[0][0].poll_timer, ac97_via_poll_stereo, dev, 0); + timer_add(&dev->sgd[0][2].poll_timer, ac97_via_poll_fm, dev, 0); ac97_via_speed_changed(dev); /* Set up playback handler. */ From afd910931b75019590f2fd1c87148fd10aa60ea0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 31 Mar 2025 04:36:37 +0200 Subject: [PATCH 0640/1190] Fix an accidental CPU mess-up. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index fa383139b..e421e5637 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1713,7 +1713,7 @@ const machine_t machines[] = { { .name = "[8088] VTech Laser Turbo XT", .internal_name = "ltxt", - .type = MACHINE_TYPE_8088, + .type = MACHINE_TYPE_8088_VTECH, .chipset = MACHINE_CHIPSET_DISCRETE, .init = machine_xt_laserxt_init, .p1_handler = NULL, @@ -1762,7 +1762,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8088_VTECH, + .package = CPU_PKG_8088, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, From a00f4e2e7f006f41aacd0d67b0e35403ddef05f8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 31 Mar 2025 06:12:56 +0200 Subject: [PATCH 0641/1190] The _VTECH suffix is supposed to be on the CPU package, not on the machine type. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e421e5637..142571d9d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1713,7 +1713,7 @@ const machine_t machines[] = { { .name = "[8088] VTech Laser Turbo XT", .internal_name = "ltxt", - .type = MACHINE_TYPE_8088_VTECH, + .type = MACHINE_TYPE_8088, .chipset = MACHINE_CHIPSET_DISCRETE, .init = machine_xt_laserxt_init, .p1_handler = NULL, @@ -1721,7 +1721,7 @@ const machine_t machines[] = { .available_flag = MACHINE_AVAILABLE, .gpio_acpi_handler = NULL, .cpu = { - .package = CPU_PKG_8088, + .package = CPU_PKG_8088_VTECH, .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, From 73dfb3fea9e825618055eb992ade9b6a703da4cb Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 31 Mar 2025 22:48:46 +0600 Subject: [PATCH 0642/1190] Hardware Renderer: Make sure to account for devicePixelRatio when setting up the matrix --- src/qt/qt_hardwarerenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp index d5aa86b79..fb84606b0 100644 --- a/src/qt/qt_hardwarerenderer.cpp +++ b/src/qt/qt_hardwarerenderer.cpp @@ -145,7 +145,7 @@ HardwareRenderer::paintGL() QVector texcoords; QMatrix4x4 mat; mat.setToIdentity(); - mat.ortho(QRectF(0, 0, (qreal) width(), (qreal) height())); + mat.ortho(QRectF(0, 0, (qreal) width() * (qreal) devicePixelRatioF(), (qreal) height() * (qreal) devicePixelRatioF())); verts.push_back(QVector2D((float) destination.x(), (float) destination.y())); verts.push_back(QVector2D((float) destination.x(), (float) destination.y() + (float) destination.height())); verts.push_back(QVector2D((float) destination.x() + (float) destination.width(), (float) destination.y() + (float) destination.height())); From 04247b3c25401039ea1d4aa1df150691de921c5b Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Apr 2025 06:36:16 +0200 Subject: [PATCH 0643/1190] Both recompilers: Temporarily disable recompilation of exactly four memory versions in 32-bit address move of opcode C6h (8-bit MOV immediate) because they currently break NT 3.x NTVDM, fixes #5038. --- src/codegen/codegen_ops_mov.h | 8 +++++++- src/codegen_new/codegen_ops_mov.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/codegen/codegen_ops_mov.h b/src/codegen/codegen_ops_mov.h index 039489035..6a5054b81 100644 --- a/src/codegen/codegen_ops_mov.h +++ b/src/codegen/codegen_ops_mov.h @@ -152,7 +152,13 @@ ropMOV_b_imm(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t { if ((fetchdat & 0xc0) == 0xc0) { STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); - } else { + } +/* TODO: Fix the recompilation of that specific case so it no longer breaks NT 3.x NTVDM. */ +#ifndef RECOMPILE_MOVB_IMM_MEM_ALWAYS + else if (((fetchdat & 0xfc) == 0x80) && (op_32 & 0x200)) + return 0; +#endif + else { x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); uint32_t imm = fastreadb(cs + op_pc + 1); int host_reg = LOAD_REG_IMM(imm); diff --git a/src/codegen_new/codegen_ops_mov.c b/src/codegen_new/codegen_ops_mov.c index 031d2ea05..f79a959a7 100644 --- a/src/codegen_new/codegen_ops_mov.c +++ b/src/codegen_new/codegen_ops_mov.c @@ -296,7 +296,13 @@ ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, UNUSED(uint8_t opcode), uint32_t imm = fastreadb(cs + op_pc + 1); uop_MOV_IMM(ir, IREG_8(dest_reg), imm); - } else { + } +/* TODO: Fix the recompilation of that specific case so it no longer breaks NT 3.x NTVDM. */ +#ifndef RECOMPILE_MOVB_IMM_MEM_ALWAYS + else if (((fetchdat & 0xfc) == 0x80) && (op_32 & 0x200)) + return 0; +#endif + else { uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); codegen_check_seg_write(block, ir, target_seg); From 4c0f0ddd24c0e0ef0df2d035d9fcc337f7164082 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Apr 2025 06:42:14 +0200 Subject: [PATCH 0644/1190] VIA AC'97: Restore the 0x47 back (turns out it was *NOT* a mix-up), but divide by 208925 instead of by 32767, in order to keep the maximum in the -32768 to 32767 range even at +12 dB gain. --- src/sound/snd_ac97_codec.c | 2 +- src/sound/snd_ac97_via.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 7a9951289..ad535591f 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -537,7 +537,7 @@ ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) uint8_t r_val = val; if (reg <= 0x06) { /* 6-bit level */ *l = codec_attn[0x3f - (l_val & 0x3f)]; - *r = codec_attn[0x3f - (r_val & 0x3f)]; + *r = codec_attn[0x47 - (r_val & 0x3f)]; } else { /* 5-bit gain */ /* Yes, 0x3f is correct, the 0x47 was most likely a decimal-hex mix-up. */ *l = codec_attn[0x3f - (l_val & 0x1f)]; diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 68ef5fe5d..2d994b08f 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -536,8 +536,13 @@ ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable) static void ac97_via_update_stereo(ac97_via_t *dev, ac97_via_sgd_t *sgd) { +#ifdef OLD_CODE int32_t l = (((sgd->out_l * sgd->vol_l) >> 15) * dev->master_vol_l) >> 15; int32_t r = (((sgd->out_r * sgd->vol_r) >> 15) * dev->master_vol_r) >> 15; +#else + int32_t l = (((sgd->out_l * sgd->vol_l) / 208925) * dev->master_vol_l) >> 15; + int32_t r = (((sgd->out_r * sgd->vol_r) / 208925) * dev->master_vol_r) >> 15; +#endif if (l < -32768) l = -32768; From 5ea48b20277374e23a1cf3208cfdd2153f7fc25a Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Apr 2025 06:42:51 +0200 Subject: [PATCH 0645/1190] Correct the fix. --- src/sound/snd_ac97_codec.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index ad535591f..e92830f67 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -537,11 +537,10 @@ ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r) uint8_t r_val = val; if (reg <= 0x06) { /* 6-bit level */ *l = codec_attn[0x3f - (l_val & 0x3f)]; - *r = codec_attn[0x47 - (r_val & 0x3f)]; + *r = codec_attn[0x3f - (r_val & 0x3f)]; } else { /* 5-bit gain */ - /* Yes, 0x3f is correct, the 0x47 was most likely a decimal-hex mix-up. */ - *l = codec_attn[0x3f - (l_val & 0x1f)]; - *r = codec_attn[0x3f - (r_val & 0x1f)]; + *l = codec_attn[0x47 - (l_val & 0x1f)]; + *r = codec_attn[0x47 - (r_val & 0x1f)]; } /* Apply per-channel mute and center/LFE powerdowns where applicable. */ From 1783da99a4b2becec060134c0ffcec57cdcccd6f Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Apr 2025 08:48:01 +0200 Subject: [PATCH 0646/1190] 86F internal handler: make the common handlers function initialize the floppy density hole return function, fixes 3-mode (dual-RPM) 3.5" drives. --- src/floppy/fdd_86f.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index f5626e35b..0a7120b16 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -3452,6 +3452,7 @@ d86f_common_handlers(int drive) drives[drive].poll = d86f_poll; drives[drive].format = d86f_proxy_format; drives[drive].stop = d86f_stop; + drives[drive].hole = d86f_hole; } int From 3e7f8a18de884e4ffe7ed9962b34442a4960017a Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Apr 2025 09:18:12 +0200 Subject: [PATCH 0647/1190] FDC: Initialize DRVRATE to 1 on the OKI IF386AX so that 1.25 MB floppies can be read on a 3.5" 3-mode drive. --- src/floppy/fdc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 51c3aa24a..6ffa47f29 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -2268,10 +2268,21 @@ fdc_reset(void *priv) fdc_update_rwc(fdc, 1, default_rwc); fdc_update_rwc(fdc, 2, default_rwc); fdc_update_rwc(fdc, 3, default_rwc); - fdc_update_drvrate(fdc, 0, 0); - fdc_update_drvrate(fdc, 1, 0); - fdc_update_drvrate(fdc, 2, 0); - fdc_update_drvrate(fdc, 3, 0); + /* + The OKI IF386SX natively supports the Japanese 1.25 MB floppy format, + since it can read such images just fine, it also attempts to use data + rate 01 on a 3.5" MB drive (which is the only kind it can physically + take, anyway), and rate 01 on a 3.5" MB drive is usually used by 3-mode + drives to switch to 360 RPM. Hence why I'm switching DRVDEN to 1, so + rate 01 becomes 500 kbps, so on a 3-mode 3.5" drive, 1.25 MB floppies + can be read. The side effect is that to read 5.25" 360k drives, you + need to use a dual-RPM 5.25" drive - but hey, that finally gets those + drives some usage as well. + */ + fdc_update_drvrate(fdc, 0, !strcmp(machine_get_internal_name(), "if386sx")); + fdc_update_drvrate(fdc, 1, !strcmp(machine_get_internal_name(), "if386sx")); + fdc_update_drvrate(fdc, 2, !strcmp(machine_get_internal_name(), "if386sx")); + fdc_update_drvrate(fdc, 3, !strcmp(machine_get_internal_name(), "if386sx")); fdc_update_drv2en(fdc, 1); fdc_update_rates(fdc); From fd618440618e3d6e426d60e59921fd8495531b09 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 1 Apr 2025 15:44:37 +0600 Subject: [PATCH 0648/1190] Switch to SAASound for CMS --- src/include/86box/snd_cms.h | 23 +- src/sound/CMakeLists.txt | 3 + src/sound/saasound/CMakeLists.txt | 16 + src/sound/saasound/SAAAmp.cpp | 203 +++++++++ src/sound/saasound/SAAAmp.h | 44 ++ src/sound/saasound/SAAConfig.h | 41 ++ src/sound/saasound/SAADevice.cpp | 392 +++++++++++++++++ src/sound/saasound/SAADevice.h | 69 +++ src/sound/saasound/SAAEnv.cpp | 380 ++++++++++++++++ src/sound/saasound/SAAEnv.h | 54 +++ src/sound/saasound/SAAFreq.cpp | 280 ++++++++++++ src/sound/saasound/SAAFreq.dat | 141 ++++++ src/sound/saasound/SAAFreq.h | 72 +++ src/sound/saasound/SAAImpl.cpp | 487 +++++++++++++++++++++ src/sound/saasound/SAAImpl.h | 75 ++++ src/sound/saasound/SAANoise.cpp | 180 ++++++++ src/sound/saasound/SAANoise.h | 54 +++ src/sound/saasound/SAASndC.cpp | 100 +++++ src/sound/saasound/SAASndC.h | 102 +++++ src/sound/saasound/SAASound.cpp | 13 + src/sound/saasound/SAASound.h | 130 ++++++ src/sound/saasound/defns.h | 59 +++ src/sound/saasound/resource.h | 15 + src/sound/saasound/saasound_cmake_config.h | 14 + src/sound/saasound/types.h | 34 ++ src/sound/snd_cms.c | 138 ++---- 26 files changed, 3006 insertions(+), 113 deletions(-) create mode 100644 src/sound/saasound/CMakeLists.txt create mode 100755 src/sound/saasound/SAAAmp.cpp create mode 100755 src/sound/saasound/SAAAmp.h create mode 100644 src/sound/saasound/SAAConfig.h create mode 100644 src/sound/saasound/SAADevice.cpp create mode 100644 src/sound/saasound/SAADevice.h create mode 100755 src/sound/saasound/SAAEnv.cpp create mode 100755 src/sound/saasound/SAAEnv.h create mode 100755 src/sound/saasound/SAAFreq.cpp create mode 100755 src/sound/saasound/SAAFreq.dat create mode 100755 src/sound/saasound/SAAFreq.h create mode 100644 src/sound/saasound/SAAImpl.cpp create mode 100755 src/sound/saasound/SAAImpl.h create mode 100755 src/sound/saasound/SAANoise.cpp create mode 100755 src/sound/saasound/SAANoise.h create mode 100755 src/sound/saasound/SAASndC.cpp create mode 100644 src/sound/saasound/SAASndC.h create mode 100755 src/sound/saasound/SAASound.cpp create mode 100644 src/sound/saasound/SAASound.h create mode 100644 src/sound/saasound/defns.h create mode 100755 src/sound/saasound/resource.h create mode 100644 src/sound/saasound/saasound_cmake_config.h create mode 100755 src/sound/saasound/types.h diff --git a/src/include/86box/snd_cms.h b/src/include/86box/snd_cms.h index 8eec22935..8201fe32c 100644 --- a/src/include/86box/snd_cms.h +++ b/src/include/86box/snd_cms.h @@ -7,23 +7,20 @@ #define MASTER_CLOCK 7159090 typedef struct cms_t { - int addrs[2]; - uint8_t regs[2][32]; - uint16_t latch[2][6]; - int freq[2][6]; - float count[2][6]; - int vol[2][6][2]; - int stat[2][6]; - uint16_t noise[2][2]; - uint16_t noisefreq[2][2]; - int noisecount[2][2]; - int noisetype[2][2]; +#ifdef SAASOUND_H_INCLUDED + SAASND saasound; + SAASND saasound2; +#else + void* saasound; + void* saasound2; +#endif uint8_t latched_data; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[WTBUFLEN * 2]; + int16_t buffer2[WTBUFLEN * 2]; - int pos; + int pos, pos2; } cms_t; extern void cms_update(cms_t *cms); diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 0a04b0ff1..d575717a0 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -180,6 +180,9 @@ endif() add_subdirectory(ymfm) target_link_libraries(86Box ymfm) +add_subdirectory(saasound) +target_link_libraries(86Box saasound) + if(GUSMAX) target_compile_definitions(snd PRIVATE USE_GUSMAX) endif() diff --git a/src/sound/saasound/CMakeLists.txt b/src/sound/saasound/CMakeLists.txt new file mode 100644 index 000000000..2db75493e --- /dev/null +++ b/src/sound/saasound/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(saasound OBJECT + SAAAmp.cpp + SAAAmp.h + SAADevice.cpp + SAADevice.h + SAAEnv.cpp + SAAEnv.h + SAAFreq.cpp + SAAFreq.h + SAAImpl.cpp + SAAImpl.h + SAANoise.cpp + SAANoise.h + SAASndC.cpp + SAASndC.h + SAASound.cpp) \ No newline at end of file diff --git a/src/sound/saasound/SAAAmp.cpp b/src/sound/saasound/SAAAmp.cpp new file mode 100755 index 000000000..8f2473fb1 --- /dev/null +++ b/src/sound/saasound/SAAAmp.cpp @@ -0,0 +1,203 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAAmp.cpp: implementation of the CSAAAmp class. +// This class handles Tone/Noise mixing, Envelope application and +// amplification. +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" +#include "types.h" +#include "SAANoise.h" +#include "SAAEnv.h" +#include "SAAFreq.h" +#include "SAAAmp.h" +#include "defns.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAAAmp::CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator) +: +m_pcConnectedToneGenerator(ToneGenerator), +m_pcConnectedNoiseGenerator(NoiseGenerator), +m_pcConnectedEnvGenerator(EnvGenerator), +m_bUseEnvelope(EnvGenerator != NULL) +{ + leftlevel = 0; + leftlevela0x0e = 0; + rightlevel = 0; + rightlevela0x0e = 0; + m_nMixMode = 0; + m_bMute=true; + m_bSync = false; + m_nOutputIntermediate=0; + last_level_byte=0; + SetAmpLevel(0x00); + +} + +CSAAAmp::~CSAAAmp() +{ + // Nothing to do +} + +void CSAAAmp::SetAmpLevel(BYTE level_byte) +{ + // if level unchanged since last call then do nothing + if (level_byte != last_level_byte) + { + last_level_byte = level_byte; + leftlevel = level_byte & 0x0f; + leftlevela0x0e = leftlevel & 0x0e; + + rightlevel = (level_byte >> 4) & 0x0f; + rightlevela0x0e = rightlevel & 0x0e; + } + +} + +void CSAAAmp::SetToneMixer(BYTE bEnabled) +{ + if (bEnabled == 0) + { + // clear mixer bit + m_nMixMode &= ~(0x01); + } + else + { + // set mixer bit + m_nMixMode |= 0x01; + } +} + +void CSAAAmp::SetNoiseMixer(BYTE bEnabled) +{ + if (bEnabled == 0) + { + m_nMixMode &= ~(0x02); + } + else + { + m_nMixMode |= 0x02; + } +} + +void CSAAAmp::Mute(bool bMute) +{ + // m_bMute refers to the GLOBAL mute setting (register 28 bit 0) + // NOT the per-channel mixer settings !! + m_bMute = bMute; +} + +void CSAAAmp::Sync(bool bSync) +{ + // m_bSync refers to the GLOBAL sync setting (register 28 bit 1) + m_bSync = bSync; +} + +void CSAAAmp::Tick(void) +{ + // updates m_nOutputIntermediate to 0, 1 or 2 + // + + // connected oscillator always ticks (this isn't really connected to the amp) + int level = m_pcConnectedToneGenerator->Tick(); + + switch (m_nMixMode) + { + case 0: + // no tone or noise for this channel + m_nOutputIntermediate = 0; + break; + case 1: + // tone only for this channel + m_nOutputIntermediate = level * 2; + // NOTE: ConnectedToneGenerator returns either 0 or 1 + break; + case 2: + // noise only for this channel + m_nOutputIntermediate = m_pcConnectedNoiseGenerator->Level() * 2; + // NOTE: ConnectedNoiseGenerator()->Level() returns either 0 or 1 + break; + case 3: + // tone+noise for this channel ... mixing algorithm : + // tone noise output + // 0 0 0 + // 1 0 2 + // 0 1 0 + // 1 1 1 + // = 2 * tone - 1 * (tone & noise) + // = tone * (2 - noise) + m_nOutputIntermediate = level * (2 - m_pcConnectedNoiseGenerator->Level()); + break; + } + // intermediate is between 0 and 2 +} + +inline int CSAAAmp::EffectiveAmplitude(int amp, int env) const +{ + // Return the effective amplitude of the low-pass-filtered result of the logical + // AND of the amplitude PDM and envelope PDM patterns. This is a more accurate + // evaluation of the SAA than simply returning amp * env , based on how the SAA + // implements pulse-density modulation. + static const int pdm[16][16] = { + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,2,2,2,2,2,2,2,2,4,4,4,4}, + {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8}, + {0,1,1,2,4,5,5,6,6,7,7,8,10,11,11,12}, + {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, + {0,1,2,3,6,7,8,9,10,11,12,13,16,17,18,19}, + {0,2,3,5,6,8,9,11,12,14,15,17,18,20,21,23}, + {0,2,3,5,8,10,11,13,14,16,17,19,22,24,25,27}, + {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}, + {0,2,4,6,10,12,14,16,18,20,22,24,28,30,32,34}, + {0,3,5,8,10,13,15,18,20,23,25,28,30,33,35,38}, + {0,3,5,8,12,15,17,20,22,25,27,30,34,37,39,42}, + {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}, + {0,3,6,9,14,17,20,23,26,29,32,35,40,43,46,49}, + {0,4,7,11,14,18,21,25,28,32,35,39,42,46,49,53}, + {0,4,7,11,16,20,23,27,30,34,37,41,46,50,53,57} + }; + + return(pdm[amp][env] * 4); +} + +void CSAAAmp::TickAndOutputStereo(unsigned int & left, unsigned int & right) +{ + // This returns a value between 0 and 480 inclusive. + // This represents the full dynamic range of one output mixer (tone, or noise+tone, at full volume, + // without envelopes enabled). Note that, with envelopes enabled, the actual dynamic range + // is reduced on-chip to just over 88% of this (424), so the "loudest" output requires disabling envs. + // NB for 6 channels at full volume, with simple additive mixing, you would see a combined + // output of 2880, and a multiplier of 11 (=31680) fits comfortably within 16-bit signed output range. + + if (m_bSync) + { + // TODO check this + left = right = 0; + return; + } + + // first, do the Tick: + Tick(); + + // now calculate the returned amplitude for this sample: + //////////////////////////////////////////////////////// + + if (m_bMute) + { + left = right = 0; + } + else if (m_bUseEnvelope && m_pcConnectedEnvGenerator->IsActive()) + { + left = EffectiveAmplitude(m_pcConnectedEnvGenerator->LeftLevel(), leftlevela0x0e) * (2 - m_nOutputIntermediate); + right = EffectiveAmplitude(m_pcConnectedEnvGenerator->RightLevel(), rightlevela0x0e) * (2 - m_nOutputIntermediate); + } + else + { + left = leftlevel * m_nOutputIntermediate * 16; + right = rightlevel * m_nOutputIntermediate * 16; + } +} diff --git a/src/sound/saasound/SAAAmp.h b/src/sound/saasound/SAAAmp.h new file mode 100755 index 000000000..4a6761f21 --- /dev/null +++ b/src/sound/saasound/SAAAmp.h @@ -0,0 +1,44 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAAmp.h: interface for the CSAAAmp class. +// This class handles Tone/Noise mixing, Envelope application and +// amplification. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAAAMP_H_INCLUDED +#define SAAAMP_H_INCLUDED + +class CSAAAmp +{ +private: + int leftlevel; + int leftlevela0x0e; + int rightlevel; + int rightlevela0x0e; + int m_nOutputIntermediate; + unsigned int m_nMixMode; + CSAAFreq * const m_pcConnectedToneGenerator; // not const because amp calls ->Tick() + const CSAANoise * const m_pcConnectedNoiseGenerator; + const CSAAEnv * const m_pcConnectedEnvGenerator; + const bool m_bUseEnvelope; + mutable bool m_bMute; + mutable bool m_bSync; + mutable BYTE last_level_byte; + int EffectiveAmplitude(int amp, int env) const; + +public: + CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator); + ~CSAAAmp(); + + void SetAmpLevel(BYTE level_byte); // really just a BYTE + void SetToneMixer(BYTE bEnabled); + void SetNoiseMixer(BYTE bEnabled); + void Mute(bool bMute); + void Sync(bool bSync); + void Tick(void); + void TickAndOutputStereo(unsigned int & left, unsigned int & right); + +}; + +#endif // SAAAMP_H_INCLUDED diff --git a/src/sound/saasound/SAAConfig.h b/src/sound/saasound/SAAConfig.h new file mode 100644 index 000000000..a655ec59f --- /dev/null +++ b/src/sound/saasound/SAAConfig.h @@ -0,0 +1,41 @@ +// Part of SAASound copyright 2020 Dave Hooper +// +// SAAConfig.h: configuration file handler class +// +////////////////////////////////////////////////////////////////////// + +#include "defns.h" +#ifdef USE_CONFIG_FILE + +#ifndef SAA_CONFIG_H_INCLUDED +#define SAA_CONFIG_H_INCLUDED + +#define INI_READONLY +#define INI_ANSIONLY /*nb not really 'ANSI', this just forces all read/write to use 8-bit char*/ +#include "minIni/minIni.h" + +class SAAConfig +{ +private: + minIni m_minIni; + bool m_bHasReadConfig; + +public: + bool m_bGenerateRegisterLogs; + bool m_bGeneratePcmLogs; + bool m_bGeneratePcmSeparateChannels; + t_string m_strRegisterLogPath; + t_string m_strPcmOutputPath; + unsigned int m_nOversample; + bool m_bHighpass; + double m_nBoost; + + SAAConfig(); + void ReadConfig(); + + t_string getChannelPcmOutputPath(int); +}; + +#endif // SAA_CONFIG_H_INCLUDED + +#endif // USE_CONFIG_FILE \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.cpp b/src/sound/saasound/SAADevice.cpp new file mode 100644 index 000000000..306aa477a --- /dev/null +++ b/src/sound/saasound/SAADevice.cpp @@ -0,0 +1,392 @@ +// Part of SAASound copyright 2020 Dave Hooper +// +// SAADevice.cpp: connecting the subcomponents of the SAA1099 together. +// This class handles device inputs and outputs (clocking, data and +// address bus, and simulated output) +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" +#include "types.h" +#include "SAAEnv.h" +#include "SAANoise.h" +#include "SAAFreq.h" +#include "SAAAmp.h" +#include "SAASound.h" +#include "SAAImpl.h" +#include "defns.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAADevice::CSAADevice() + : + m_nCurrentSaaReg(0), + m_bOutputEnabled(false), + m_bSync(false), + m_bHighpass(true), + m_nOversample(0), + m_Noise0(0xffffffff), + m_Noise1(0xffffffff), + m_Env0(), + m_Env1(), + m_Osc0(&m_Noise0, NULL), + m_Osc1(NULL, &m_Env0), + m_Osc2(NULL, NULL), + m_Osc3(&m_Noise1, NULL), + m_Osc4(NULL, &m_Env1), + m_Osc5(NULL, NULL), + m_Amp0(&m_Osc0, &m_Noise0, NULL), + m_Amp1(&m_Osc1, &m_Noise0, NULL), + m_Amp2(&m_Osc2, &m_Noise0, &m_Env0), + m_Amp3(&m_Osc3, &m_Noise1, NULL), + m_Amp4(&m_Osc4, &m_Noise1, NULL), + m_Amp5(&m_Osc5, &m_Noise1, &m_Env1) +{ + // Create and link up the objects that make up the emulator + Noise[0] = &m_Noise0; + Noise[1] = &m_Noise1; + Env[0] = &m_Env0; + Env[1] = &m_Env1; + + // Create oscillators (tone generators) and link to noise generators and + // envelope controllers + Osc[0] = &m_Osc0; + Osc[1] = &m_Osc1; + Osc[2] = &m_Osc2; + Osc[3] = &m_Osc3; + Osc[4] = &m_Osc4; + Osc[5] = &m_Osc5; + + // Create amplification/mixing stages and link to appropriate oscillators, + // noise generators and envelope controllers + Amp[0] = &m_Amp0; + Amp[1] = &m_Amp1; + Amp[2] = &m_Amp2; + Amp[3] = &m_Amp3; + Amp[4] = &m_Amp4; + Amp[5] = &m_Amp5; + + _SetClockRate(EXTERNAL_CLK_HZ); + _SetOversample(DEFAULT_OVERSAMPLE); +} + +CSAADevice::~CSAADevice() +{ +} + +////////////////////////////////////////////////////////////////////// +// CSAASound members +////////////////////////////////////////////////////////////////////// + +void CSAADevice::_SetClockRate(unsigned int nClockRate) +{ + m_Osc0._SetClockRate(nClockRate); + m_Osc1._SetClockRate(nClockRate); + m_Osc2._SetClockRate(nClockRate); + m_Osc3._SetClockRate(nClockRate); + m_Osc4._SetClockRate(nClockRate); + m_Osc5._SetClockRate(nClockRate); + m_Noise0._SetClockRate(nClockRate); + m_Noise1._SetClockRate(nClockRate); +} + +void CSAADevice::_SetSampleRate(unsigned int nSampleRate) +{ + m_Osc0._SetSampleRate(nSampleRate); + m_Osc1._SetSampleRate(nSampleRate); + m_Osc2._SetSampleRate(nSampleRate); + m_Osc3._SetSampleRate(nSampleRate); + m_Osc4._SetSampleRate(nSampleRate); + m_Osc5._SetSampleRate(nSampleRate); + m_Noise0._SetSampleRate(nSampleRate); + m_Noise1._SetSampleRate(nSampleRate); +} + +void CSAADevice::_SetOversample(unsigned int nOversample) +{ + if (nOversample != m_nOversample) + { + m_nOversample = nOversample; + m_Osc0._SetOversample(nOversample); + m_Osc1._SetOversample(nOversample); + m_Osc2._SetOversample(nOversample); + m_Osc3._SetOversample(nOversample); + m_Osc4._SetOversample(nOversample); + m_Osc5._SetOversample(nOversample); + m_Noise0._SetOversample(nOversample); + m_Noise1._SetOversample(nOversample); + } +} + +void CSAADevice::_WriteData(BYTE nData) +{ +#if defined(DEBUG) || defined(DEBUGSAA) + m_Reg[m_nCurrentSaaReg] = nData; +#endif + + // route nData to the appropriate place + switch (m_nCurrentSaaReg) + { + // Amplitude data (==> Amp) + case 0: + m_Amp0.SetAmpLevel(nData); + break; + case 1: + m_Amp1.SetAmpLevel(nData); + break; + case 2: + m_Amp2.SetAmpLevel(nData); + break; + case 3: + m_Amp3.SetAmpLevel(nData); + break; + case 4: + m_Amp4.SetAmpLevel(nData); + break; + case 5: + m_Amp5.SetAmpLevel(nData); + break; + + // Freq data (==> Osc) + case 8: + m_Osc0.SetFreqOffset(nData); + break; + case 9: + m_Osc1.SetFreqOffset(nData); + break; + case 10: + m_Osc2.SetFreqOffset(nData); + break; + case 11: + m_Osc3.SetFreqOffset(nData); + break; + case 12: + m_Osc4.SetFreqOffset(nData); + break; + case 13: + m_Osc5.SetFreqOffset(nData); + break; + + // Freq octave data (==> Osc) for channels 0,1 + case 16: + m_Osc0.SetFreqOctave(nData & 0x07); + m_Osc1.SetFreqOctave((nData >> 4) & 0x07); + break; + + // Freq octave data (==> Osc) for channels 2,3 + case 17: + m_Osc2.SetFreqOctave(nData & 0x07); + m_Osc3.SetFreqOctave((nData >> 4) & 0x07); + break; + + // Freq octave data (==> Osc) for channels 4,5 + case 18: + m_Osc4.SetFreqOctave(nData & 0x07); + m_Osc5.SetFreqOctave((nData >> 4) & 0x07); + break; + + // Tone mixer control (==> Amp) + case 20: + m_Amp0.SetToneMixer(nData & 0x01); + m_Amp1.SetToneMixer(nData & 0x02); + m_Amp2.SetToneMixer(nData & 0x04); + m_Amp3.SetToneMixer(nData & 0x08); + m_Amp4.SetToneMixer(nData & 0x10); + m_Amp5.SetToneMixer(nData & 0x20); + break; + + // Noise mixer control (==> Amp) + case 21: + m_Amp0.SetNoiseMixer(nData & 0x01); + m_Amp1.SetNoiseMixer(nData & 0x02); + m_Amp2.SetNoiseMixer(nData & 0x04); + m_Amp3.SetNoiseMixer(nData & 0x08); + m_Amp4.SetNoiseMixer(nData & 0x10); + m_Amp5.SetNoiseMixer(nData & 0x20); + break; + + // Noise frequency/source control (==> Noise) + case 22: + m_Noise0.SetSource(nData & 0x03); + m_Noise1.SetSource((nData >> 4) & 0x03); + break; + + // Envelope control data (==> Env) for envelope controller #0 + case 24: + m_Env0.SetEnvControl(nData); + break; + + // Envelope control data (==> Env) for envelope controller #1 + case 25: + m_Env1.SetEnvControl(nData); + break; + + // Global enable and reset (sync) controls + case 28: + { + // Reset (sync) bit + bool bSync = bool(nData & 0x02); + if (bSync != m_bSync) + { + // Sync all devices + // This amounts to telling them all to reset to a + // known state, which is also a state that doesn't change + // (i.e. no audio output, although there are some exceptions) + // bSync=true => all devices are sync (aka reset); + // bSync=false => all devices are allowed to run and generate changing output + m_Osc0.Sync(bSync); + m_Osc1.Sync(bSync); + m_Osc2.Sync(bSync); + m_Osc3.Sync(bSync); + m_Osc4.Sync(bSync); + m_Osc5.Sync(bSync); + m_Noise0.Sync(bSync); + m_Noise1.Sync(bSync); + m_Amp0.Sync(bSync); + m_Amp1.Sync(bSync); + m_Amp2.Sync(bSync); + m_Amp3.Sync(bSync); + m_Amp4.Sync(bSync); + m_Amp5.Sync(bSync); + m_bSync = bSync; + } + + // Global mute bit + bool bOutputEnabled = bool(nData & 0x01); + if (bOutputEnabled != m_bOutputEnabled) + { + // unmute all amps - sound 'enabled' + m_Amp0.Mute(!bOutputEnabled); + m_Amp1.Mute(!bOutputEnabled); + m_Amp2.Mute(!bOutputEnabled); + m_Amp3.Mute(!bOutputEnabled); + m_Amp4.Mute(!bOutputEnabled); + m_Amp5.Mute(!bOutputEnabled); + m_bOutputEnabled = bOutputEnabled; + } + } + break; + + default: + // anything else means data is being written to a register + // that is not used within the SAA-1099 architecture + // hence, we ignore it. + {} + } +} + +void CSAADevice::_WriteAddress(BYTE nReg) +{ + m_nCurrentSaaReg = nReg & 31; + if (m_nCurrentSaaReg == 24) + { + m_Env0.ExternalClock(); + } + else if (m_nCurrentSaaReg == 25) + { + m_Env1.ExternalClock(); + } +} + +#if 1 +BYTE CSAADevice::_ReadAddress(void) +{ + // Not a real hardware function of the SAA-1099, which is write-only + // However, this is used by SAAImpl to generate debug logs (if enabled) + return(m_nCurrentSaaReg); +} +#endif +#if defined(DEBUG) +BYTE CSAADevice::_ReadData(void) +{ + // Not a real hardware function of the SAA-1099, which is write-only + // This is only compiled for Debug builds + return(m_Reg[m_nCurrentSaaReg]); +} +#endif + +void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed) +{ + unsigned int temp_left, temp_right; + unsigned int accum_left = 0, accum_right = 0; + for (int i = 1 << m_nOversample; i > 0; i--) + { + m_Noise0.Tick(); + m_Noise1.Tick(); + m_Amp0.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + m_Amp1.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + m_Amp2.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + m_Amp3.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + m_Amp4.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + m_Amp5.TickAndOutputStereo(temp_left, temp_right); + accum_left += temp_left; + accum_right += temp_right; + } + left_mixed = accum_left; + right_mixed = accum_right; +} + +void CSAADevice::_TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed, + unsigned int& left0, unsigned int& right0, + unsigned int& left1, unsigned int& right1, + unsigned int& left2, unsigned int& right2, + unsigned int& left3, unsigned int& right3, + unsigned int& left4, unsigned int& right4, + unsigned int& left5, unsigned int& right5 +) +{ + unsigned int temp_left, temp_right; + unsigned int accum_left = 0, accum_right = 0; + left0 = left1 = left2 = left3 = left4 = left5 = 0; + right0 = right1 = right2 = right3 = right4 = right5 = 0; + for (int i = 1 << m_nOversample; i > 0; i--) + { + m_Noise0.Tick(); + m_Noise1.Tick(); + m_Amp0.TickAndOutputStereo(temp_left, temp_right); + left0 += temp_left; + right0 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + m_Amp1.TickAndOutputStereo(temp_left, temp_right); + left1 += temp_left; + right1 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + m_Amp2.TickAndOutputStereo(temp_left, temp_right); + left2 += temp_left; + right2 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + m_Amp3.TickAndOutputStereo(temp_left, temp_right); + left3 += temp_left; + right3 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + m_Amp4.TickAndOutputStereo(temp_left, temp_right); + left4 += temp_left; + right4 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + m_Amp5.TickAndOutputStereo(temp_left, temp_right); + left5 += temp_left; + right5 += temp_right; + accum_left += temp_left; + accum_right += temp_right; + } + left_mixed = accum_left; + right_mixed = accum_right; +} \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.h b/src/sound/saasound/SAADevice.h new file mode 100644 index 000000000..7b697821f --- /dev/null +++ b/src/sound/saasound/SAADevice.h @@ -0,0 +1,69 @@ +// Part of SAASound copyright 2020 Dave Hooper +// +// SAADevice.h: connecting the subcomponents of the SAA1099 together. +// This class handles device inputs and outputs (clocking, data and +// address bus, and simulated output) +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAADEVICE_H_INCLUDED +#define SAADEVICE_H_INCLUDED + +#include "SAASound.h" +#include "SAANoise.h" +#include "SAAEnv.h" +#include "SAAFreq.h" +#include "SAAAmp.h" + +class CSAADevice +{ +private: + int m_nCurrentSaaReg; + bool m_bOutputEnabled; + bool m_bSync; + bool m_bHighpass; + int m_nOversample; + + CSAANoise m_Noise0, m_Noise1; + CSAAEnv m_Env0, m_Env1; + CSAAFreq m_Osc0, m_Osc1, m_Osc2, m_Osc3, m_Osc4, m_Osc5; + CSAAAmp m_Amp0, m_Amp1, m_Amp2, m_Amp3, m_Amp4, m_Amp5; + + CSAANoise* Noise[2]; + CSAAEnv* Env[2]; + CSAAFreq* Osc[6]; + CSAAAmp* Amp[6]; + +#if defined(DEBUG) || defined(DEBUGSAA) + BYTE m_Reg[32]; +#endif + +public: + CSAADevice(); + ~CSAADevice(); + + void _WriteAddress(BYTE nReg); + void _WriteData(BYTE nData); +#if 1 + BYTE _ReadAddress(void); +#endif +#if defined(DEBUG) + BYTE _ReadData(void); +#endif + + void _SetClockRate(unsigned int nClockRate); + void _SetSampleRate(unsigned int nSampleRate); + void _SetOversample(unsigned int nOversample); + void _TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed); + void _TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed, + unsigned int& left0, unsigned int& right0, + unsigned int& left1, unsigned int& right1, + unsigned int& left2, unsigned int& right2, + unsigned int& left3, unsigned int& right3, + unsigned int& left4, unsigned int& right4, + unsigned int& left5, unsigned int& right5 + ); + +}; + +#endif // SAADEVICE_H_INCLUDED \ No newline at end of file diff --git a/src/sound/saasound/SAAEnv.cpp b/src/sound/saasound/SAAEnv.cpp new file mode 100755 index 000000000..ae8191112 --- /dev/null +++ b/src/sound/saasound/SAAEnv.cpp @@ -0,0 +1,380 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAEnv.cpp: implementation of the CSAAEnv class. +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" +#include "types.h" +#include "SAAEnv.h" + + +////////////////////////////////////////////////////////////////////// +// Static member initialisation +////////////////////////////////////////////////////////////////////// + +const ENVDATA CSAAEnv::cs_EnvData[8] = +{ + {1,false, { {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, + {1,true, { {{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}}, + {{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14},{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14}}}}, + {1,false, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, + {{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, + {1,true, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, + {{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, + {2,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}}, + {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}}, + {2,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}}, + {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}}, + {1,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, + {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, + {1,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, + {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}} +}; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAAEnv::CSAAEnv() +: +m_bEnabled(false), +m_bNewData(false), +m_nNextData(0), +m_bEnvelopeEnded(true), +m_nPhase(0), +m_nPhasePosition(0), +m_nResolution(1) +{ + // initialise itself with the value 'zero' + SetEnvControl(0); +} + +CSAAEnv::~CSAAEnv() +{ + // Nothing to do +} + +void CSAAEnv::InternalClock(void) +{ + // will only do something if envelope clock mode is set to internal + // and the env control is enabled + if (m_bEnabled && (!m_bClockExternally)) Tick(); +} + +void CSAAEnv::ExternalClock(void) +{ + // will only do something if envelope clock mode is set to external + // and the env control is enabled + if (m_bClockExternally && m_bEnabled) Tick(); +} + +void CSAAEnv::SetEnvControl(int nData) +{ + // process immediate stuff first: + // start with the Enabled flag. if env is disabled, + // there's not much to do + bool bEnabled = ((nData & 0x80)==0x80); + if (!bEnabled && !m_bEnabled) + return; + m_bEnabled = bEnabled; + if (!m_bEnabled) + { + // env control was enabled, and now disabled + // Any subsequent env control changes are immediate. + m_bEnvelopeEnded = true; + return; + } + + // Resolution (3bit/4bit) is also immediately processed + int new_resolution = ((nData & 0x10) == 0x10) ? 2 : 1; + // NOTE: undocumented behaviour when changing resolution mid-waveform + // Empirically, the following matches observations: + // * When ticking the env generator with 4-bit resolution, the position += 1 + // * When ticking the env generator with 3-bit resolution, the position += 2 + // * When changing between 4-bit resolution and 3-bit resolution + // without ticking the env generator, the position is unchanged + // (although, effectively, the LSB is ignored. Purely as an implementation + // detail, I'm implementing this as clearing the LSB ie LSB=0; see next point) + // * When changing between 3-bit resolution and 4-bit resolution + // without ticking the env generator, the position LSB is set to 1 + // See test case: envext_34b + // + if (m_nResolution == 1 && new_resolution == 2) + { + // change from 4-bit to 3-bit + m_nPhasePosition &= 0xe; + } + else if (m_nResolution == 2 && new_resolution == 1) + { + // change from 3-bit to 4-bit + m_nPhasePosition |= 0x1; + } + m_nResolution = new_resolution; + + // now buffered stuff: but only if it's ok to, and only if the + // envgenerator is not disabled. otherwise it just stays buffered until + // the Tick() function sets m_bEnvelopeEnded to true and realises there is + // already some new data waiting + if (m_bEnvelopeEnded) + { + SetNewEnvData(nData); // also does the SetLevels() call for us. + m_bNewData=false; + } + else + { + // since the 'next resolution' changes arrive unbuffered, we + // may need to change the current level because of this: + SetLevels(); + + // store current new data, and set the newdata flag: + m_bNewData = true; + m_nNextData = nData; + } + +} + +int CSAAEnv::LeftLevel(void) const +{ + return m_nLeftLevel; +} + +int CSAAEnv::RightLevel(void) const +{ + return m_nRightLevel; +} + +inline void CSAAEnv::Tick(void) +{ + // if disabled, do nothing + if (!m_bEnabled) // m_bEnabled is set directly, not buffered, so this is ok + { + // for sanity, reset stuff: + m_bEnvelopeEnded = true; + m_nPhase = 0; + m_nPhasePosition = 0; + return; + } + + // else : m_bEnabled + + + if (m_bEnvelopeEnded) + { + // do nothing + // (specifically, don't change the values of m_bEnvelopeEnded, + // m_nPhase and m_nPhasePosition, as these will still be needed + // by SetLevels() should it be called again) + + return; + } + + + // else : !m_bEnvelopeEnded + // Continue playing the same envelope ... + // increments the phaseposition within an envelope. + // also handles looping and resolution appropriately. + // Changes the level of the envelope accordingly + // through calling SetLevels() . This must be called after making + // any changes that will affect the output levels of the env controller!! + // SetLevels also handles left-right channel inverting + + // increment phase position + m_nPhasePosition += m_nResolution; + + // if this means we've gone past 16 (the end of a phase) + // then change phase, and if necessary, loop + // Refer to datasheet for meanings of (3) and (4) in following text + // w.r.t SAA1099 envelopes + + // Note that we will always reach position (3) or (4), even if we keep toggling + // resolution from 4-bit to 3-bit and back, because the counter will always wrap to 0. + // In fact it's quite elegant: + // No matter how you increment and toggle and increment and toggle, the counter + // will at some point be either 0xe (either 4-bit mode or 3-bit mode) or 0xf (4-bit mode only). + // Depending on the mode, even if you change the mode, the next increment, + // or the one after it, will then take it to 0. + // 0xe + 2 (3bit mode) => 0x0 + // 0xe + 1 (4bit mode) => 0xf + // 0xf + 1 (4bit mode) => 0x0 + // 0xe -> (toggle 3bit mode to 4bit mode) => 0xf + // 0xe -> (toggle 4bit mode to 3bit mode) => 0xe + // 0xf -> (toggle 4bit mode to 3bit mode) => 0xe + // + // but there is a subtlety (of course), which is that any changes at point (3) + // can take place immediately you hit point (3), but changes at point (4) are actually + // only acted upon when the counter transitions from 0xe (or 0xf) to 0x0 (which also + // means that, for these looping envelopes, which are the ones that have a point(4), + // immediately after the counter wrapping to 0x0, a write to the env data register will + // NOT set the waveform and will NOT reset the phase/phaseposition (even though it + // will still let you toggle the 4bit/3bit mode, which will change the phaseposition LSB!) + // See test case: envext_34c + + bool bProcessNewDataIfAvailable = false; + if (m_nPhasePosition >= 16) + { + m_nPhase++; + + // if we should loop, then do so - and we've reached position (4) + // otherwise, if we shouldn't loop, + // then we've reached position (3) and so we say that + // we're ok for new data. + if (m_nPhase == m_nNumberOfPhases) + { + // at position (3) or (4) + if (!m_bLooping) + { + // position (3) only + // note that it seems that the sustain level is ALWAYS zero + // in the case of non-looping waveforms + m_bEnvelopeEnded = true; + bProcessNewDataIfAvailable = true; + } + else + { + // position (4) only + // note that any data already latched is ONLY acted upon + // at THIS point. If (after this Tick has completed) any new + // env data is written, it will NOT be acted upon, until + // we get back to position (4) again. + // this is why m_bEnvelopeEnded (which affects the behaviour + // of the SetEnvControl method) is FALSE here. + // See test case: envext_34c (as noted earlier) + m_bEnvelopeEnded = false; + // set phase pointer to start of envelope for loop + // and reset m_nPhasePosition + m_nPhase=0; + m_nPhasePosition -= 16; + bProcessNewDataIfAvailable = true; + } + } + else // (m_nPhase < m_nNumberOfPhases) + { + // not at position (3) or (4) ... + // (i.e., we're in the middle of an envelope with + // more than one phase. Specifically, we're in + // the middle of envelope 4 or 5 - the + // triangle envelopes - but that's not important) + + // any commands sent to this envelope controller + // will be buffered. Set the flag to indicate this. + m_bEnvelopeEnded = false; + m_nPhasePosition -= 16; + } + } + else // (m_nPhasePosition < 16) + { + // still within the same phase; + // but, importantly, we are no longer at the start of the phase ... + // so new data cannot be acted on immediately, and must + // be buffered + m_bEnvelopeEnded = false; + // Phase and PhasePosition have already been updated. + // SetLevels() will need to be called to actually calculate + // the output 'level' of this envelope controller + } + + + // if we have new (buffered) data, now is the time to act on it + if (m_bNewData && bProcessNewDataIfAvailable) + { + m_bNewData = false; + SetNewEnvData(m_nNextData); + } + else + { + // ok, we didn't have any new buffered date to act on, + // so we just call SetLevels() to calculate the output level + // for whatever the current envelope is + SetLevels(); + } + +} + +inline void CSAAEnv::SetLevels(void) +{ + // sets m_nLeftLevel + // Also sets m_nRightLevel in terms of m_nLeftLevel + // and m_bInvertRightChannel + + // m_nResolution: 1 means 4-bit resolution; 2 means 3-bit resolution. Resolution of envelope waveform. + + // Note that this is handled 'immediately', and doesn't wait for synchronisation of + // the envelope waveform (this is important, see test case EnvExt_imm) + // It is therefore possible to switch between 4-bit and 3-bit resolution in the middle of + // an envelope waveform. if you are at an 'odd' phase position, you would be able to hear + // the difference. if you are at an 'even' phase position, the volume level for 4-bit + // and 3-bit would be the same. + // NOTE: additional test cases are required. + + switch (m_nResolution) + { + case 1: // 4 bit res waveforms + default: + { + // special case: if envelope is not a looping one, and we're at the end + // then our level should be zero (all of the non-looping waveforms have + // a sustain level of zero): + if (m_bEnvelopeEnded && !m_bLooping) + m_nLeftLevel = 0; + else + m_nLeftLevel = m_pEnvData->nLevels[0][m_nPhase][m_nPhasePosition]; + + if (m_bInvertRightChannel) + m_nRightLevel = 15-m_nLeftLevel; + else + m_nRightLevel = m_nLeftLevel; + break; + } + case 2: // 3 bit res waveforms + { + // special case: if envelope is not a looping one, and we're at the end + // then our level should be zero (all of the non-looping waveforms have + // a sustain level of zero): + if (m_bEnvelopeEnded && !m_bLooping) + m_nLeftLevel = 0; + else + m_nLeftLevel = m_pEnvData->nLevels[1][m_nPhase][m_nPhasePosition]; + if (m_bInvertRightChannel) + m_nRightLevel = 14-m_nLeftLevel; + else + m_nRightLevel = m_nLeftLevel; + break; + } + } +} + + +inline void CSAAEnv::SetNewEnvData(int nData) +{ + // loads envgenerator's registers according to the bits set + // in nData + + m_nPhase = 0; + m_nPhasePosition = 0; + m_pEnvData = &(cs_EnvData[(nData >> 1) & 0x07]); + m_bInvertRightChannel = ((nData & 0x01) == 0x01); + m_bClockExternally = ((nData & 0x20) == 0x20); + m_nNumberOfPhases = m_pEnvData->nNumberOfPhases; + m_bLooping = m_pEnvData->bLooping; + m_nResolution = (((nData & 0x10)==0x10) ? 2 : 1); + m_bEnabled = ((nData & 0x80) == 0x80); + if (m_bEnabled) + { + m_bEnvelopeEnded = false; + // is this right? + // YES. See test case EnvExt_34c (setting data multiple times + // when at a point (3) resets the waveform so you're no longer + // at a point (3). + } + else + { + // DISABLED - so set stuff accordingly + m_bEnvelopeEnded = true; + m_nPhase = 0; + m_nPhasePosition = 0; + } + + SetLevels(); +} diff --git a/src/sound/saasound/SAAEnv.h b/src/sound/saasound/SAAEnv.h new file mode 100755 index 000000000..131659c06 --- /dev/null +++ b/src/sound/saasound/SAAEnv.h @@ -0,0 +1,54 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAEnv.h: interface for the CSAAEnv class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAAENV_H_INCLUDED +#define SAAENV_H_INCLUDED + +class CSAAEnv +{ +private: + int m_nLeftLevel, m_nRightLevel; + ENVDATA const * m_pEnvData; + + bool m_bEnabled; + bool m_bInvertRightChannel; + BYTE m_nPhase; + BYTE m_nPhasePosition; + bool m_bEnvelopeEnded; + char m_nPhaseAdd[2]; + char m_nCurrentPhaseAdd; + bool m_bLooping; + char m_nNumberOfPhases; + char m_nResolution; + char m_nInitialLevel; + bool m_bNewData; + BYTE m_nNextData; + bool m_bClockExternally; + static const ENVDATA cs_EnvData[8]; + + void Tick(void); + void SetLevels(void); + void SetNewEnvData(int nData); + +public: + CSAAEnv(); + ~CSAAEnv(); + + void InternalClock(void); + void ExternalClock(void); + void SetEnvControl(int nData); // really just a BYTE + int LeftLevel(void) const; + int RightLevel(void) const; + bool IsActive(void) const; + +}; + +inline bool CSAAEnv::IsActive(void) const +{ + return m_bEnabled; +} + +#endif // SAAENV_H_INCLUDED diff --git a/src/sound/saasound/SAAFreq.cpp b/src/sound/saasound/SAAFreq.cpp new file mode 100755 index 000000000..52cbc7a3d --- /dev/null +++ b/src/sound/saasound/SAAFreq.cpp @@ -0,0 +1,280 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAFreq.cpp: implementation of the CSAAFreq class. +// only 7-bit fractional accuracy on oscillator periods. I may consider fixing that. +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" +#include "types.h" +#include "SAANoise.h" +#include "SAAEnv.h" +#include "SAAFreq.h" +#include "defns.h" + +#ifdef SAAFREQ_FIXED_CLOCKRATE +// 'load in' the data for the static frequency lookup table +// precomputed for a fixed clockrate +// See: tools/freqdat.py +const unsigned long CSAAFreq::m_FreqTable[2048] = { +#include "SAAFreq.dat" +}; +#else +unsigned long CSAAFreq::m_FreqTable[2048]; +unsigned long CSAAFreq::m_nClockRate = 0; +#endif // SAAFREQ_FIXED_CLOCKRATE + +const int INITIAL_LEVEL = 1; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAAFreq::CSAAFreq(CSAANoise * const NoiseGenerator, CSAAEnv * const EnvGenerator) +: +m_nCounter(0), m_nCounter_low(0), m_nAdd(0), +m_nLevel(INITIAL_LEVEL), +m_nOversample(0), m_nCounterLimit_low(1), +m_nCurrentOffset(0), m_nCurrentOctave(0), m_nNextOffset(0), m_nNextOctave(0), +m_bIgnoreOffsetData(false), m_bNewData(false), +m_bSync(false), +m_nSampleRate(SAMPLE_RATE_HZ), +m_pcConnectedNoiseGenerator(NoiseGenerator), +m_pcConnectedEnvGenerator(EnvGenerator), +m_nConnectedMode((NoiseGenerator == NULL) ? ((EnvGenerator == NULL) ? 0 : 1) : 2) +{ + _SetClockRate(EXTERNAL_CLK_HZ); + SetAdd(); // current octave, current offset +} + +CSAAFreq::~CSAAFreq() +{ + // Nothing to do +} + +void CSAAFreq::SetFreqOffset(BYTE nOffset) +{ + // nOffset between 0 and 255 + + if (!m_bSync) + { + m_nNextOffset = nOffset; + m_bNewData=true; + if (m_nNextOctave==m_nCurrentOctave) + { + // According to Philips, if you send the SAA-1099 + // new Octave data and then new Offset data in that + // order, on the next half-cycle of the current frequency + // generator, ONLY the octave data is acted upon. + // The offset data will be acted upon next time. + + // ?? TEST CASE : if you set the octave and then the offset + // but the octave you set it to is the same one it already was. + // Will this ignore the offset data? + // Do you get the same behaviour if you set offset THEN octave + // even if you set octave to the same value it was before? + + m_bIgnoreOffsetData=true; + } + } + else + { + // updates straightaway if m_bSync + m_bNewData=false; + m_bIgnoreOffsetData = false; + m_nCurrentOffset = nOffset; + m_nNextOffset = nOffset; + m_nCurrentOctave = m_nNextOctave; + SetAdd(); + } + +} + +void CSAAFreq::SetFreqOctave(BYTE nOctave) +{ + // nOctave between 0 and 7 + + if (!m_bSync) + { + m_nNextOctave = nOctave; + m_bNewData=true; + m_bIgnoreOffsetData = false; + } + else + { + // updates straightaway if m_bSync + m_bNewData=false; + m_bIgnoreOffsetData = false; + m_nCurrentOctave = nOctave; + m_nNextOctave = nOctave; + m_nCurrentOffset = m_nNextOffset; + SetAdd(); + } +} + +void CSAAFreq::UpdateOctaveOffsetData(void) +{ + // loads the buffered new octave and new offset data into the current registers + // and sets up the new frequency for this frequency generator (i.e. sets up m_nAdd) + // - called during Sync, and called when waveform half-cycle completes + + // How the SAA-1099 really treats new data: + // if only new octave data is present, + // then set new period based on just the octave data + // Otherwise, if only new offset data is present, + // then set new period based on just the offset data + // Otherwise, if new octave data is present, and new offset data is present, + // and the offset data was set BEFORE the octave data, + // then set new period based on both the octave and offset data + // Else, if the offset data came AFTER the new octave data + // then set new period based on JUST THE OCTAVE DATA, and continue + // signalling the offset data as 'new', so it will be acted upon + // next half-cycle + // + // Weird, I know. But that's how it works. Philips even documented as much. + + if (!m_bNewData) + { + // optimise for the most common case! No new data! + return; + } + + m_nCurrentOctave=m_nNextOctave; + if (!m_bIgnoreOffsetData) + { + m_nCurrentOffset=m_nNextOffset; + m_bNewData=false; + } + m_bIgnoreOffsetData=false; + + SetAdd(); +} + +void CSAAFreq::_SetSampleRate(unsigned int nSampleRate) +{ + m_nSampleRate = nSampleRate; +} + +void CSAAFreq::_SetOversample(unsigned int oversample) +{ + // oversample is a power of 2 i.e. + // if oversample == 2 then 4x oversample + // if oversample == 6 then 64x oversample + if (oversample < m_nOversample) + { + m_nCounter_low <<= (m_nOversample - oversample); + } + else + { + m_nCounter_low >>= (oversample - m_nOversample); + } + + m_nCounterLimit_low = 1<= (m_nSampleRate<<12)) + { + m_nCounter -= (m_nSampleRate<<12); + m_nCounter_low++; + if (m_nCounter_low >= m_nCounterLimit_low) + { + // period elapsed for (at least) one half-cycle of + // current frequency + m_nCounter_low = 0; + // flip state - from 0 to 1 or vice versa + m_nLevel = 1 - m_nLevel; + + // trigger any connected devices + switch (m_nConnectedMode) + { + case 1: + // env trigger + m_pcConnectedEnvGenerator->InternalClock(); + break; + + case 2: + // noise trigger + m_pcConnectedNoiseGenerator->Trigger(); + break; + + default: + // do nothing + break; + } + + // get new frequency (set period length m_nAdd) if new data is waiting: + UpdateOctaveOffsetData(); + } + } + + return m_nLevel; +} + +void CSAAFreq::SetAdd(void) +{ + // nOctave between 0 and 7; nOffset between 0 and 255 + + // Used to be: + // m_nAdd = (15625 << nOctave) / (511 - nOffset); + // Now just table lookup: + m_nAdd = m_FreqTable[m_nCurrentOctave<<8 | m_nCurrentOffset]; +} + +void CSAAFreq::Sync(bool bSync) +{ + m_bSync = bSync; + + // update straightaway if m_bSync + if (m_bSync) + { + m_nCounter = 0; + m_nCounter_low = 0; + + // this seems to need to be required to make the Fred59 SPACE DEMO audio work correctly + m_nLevel = INITIAL_LEVEL; + + m_nCurrentOctave=m_nNextOctave; + m_nCurrentOffset=m_nNextOffset; + SetAdd(); + } +} diff --git a/src/sound/saasound/SAAFreq.dat b/src/sound/saasound/SAAFreq.dat new file mode 100755 index 000000000..04fb9081a --- /dev/null +++ b/src/sound/saasound/SAAFreq.dat @@ -0,0 +1,141 @@ +/* +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// Precalculated oscillator frequency period steps +// Higher scaling for better accuracy. +// +// After construction, it's important to SetSampleRate before +// trying to use the generator. +// (Just because the CSAANoise object has a default samplerate +// doesn't mean you should rely on it) +// +////////////////////////////////////////////////////////////////////// +*/ + 250489 , 250980 , 251473 , 251969 , 252465 , 252964 , 253465 , 253968 , 254473 , 254980 , 255489 , 256000 , 256513 , 257028 , 257545 , 258065 , + 258586 , 259109 , 259635 , 260163 , 260692 , 261224 , 261759 , 262295 , 262834 , 263374 , 263918 , 264463 , 265010 , 265560 , 266112 , 266667 , + 267223 , 267782 , 268344 , 268908 , 269474 , 270042 , 270613 , 271186 , 271762 , 272340 , 272921 , 273504 , 274090 , 274678 , 275269 , 275862 , + 276458 , 277056 , 277657 , 278261 , 278867 , 279476 , 280088 , 280702 , 281319 , 281938 , 282561 , 283186 , 283814 , 284444 , 285078 , 285714 , + 286353 , 286996 , 287640 , 288288 , 288939 , 289593 , 290249 , 290909 , 291572 , 292237 , 292906 , 293578 , 294253 , 294931 , 295612 , 296296 , + 296984 , 297674 , 298368 , 299065 , 299766 , 300469 , 301176 , 301887 , 302600 , 303318 , 304038 , 304762 , 305489 , 306220 , 306954 , 307692 , + 308434 , 309179 , 309927 , 310680 , 311436 , 312195 , 312958 , 313725 , 314496 , 315271 , 316049 , 316832 , 317618 , 318408 , 319202 , 320000 , + 320802 , 321608 , 322418 , 323232 , 324051 , 324873 , 325700 , 326531 , 327366 , 328205 , 329049 , 329897 , 330749 , 331606 , 332468 , 333333 , + 334204 , 335079 , 335958 , 336842 , 337731 , 338624 , 339523 , 340426 , 341333 , 342246 , 343164 , 344086 , 345013 , 345946 , 346883 , 347826 , + 348774 , 349727 , 350685 , 351648 , 352617 , 353591 , 354571 , 355556 , 356546 , 357542 , 358543 , 359551 , 360563 , 361582 , 362606 , 363636 , + 364672 , 365714 , 366762 , 367816 , 368876 , 369942 , 371014 , 372093 , 373178 , 374269 , 375367 , 376471 , 377581 , 378698 , 379822 , 380952 , + 382090 , 383234 , 384384 , 385542 , 386707 , 387879 , 389058 , 390244 , 391437 , 392638 , 393846 , 395062 , 396285 , 397516 , 398754 , 400000 , + 401254 , 402516 , 403785 , 405063 , 406349 , 407643 , 408946 , 410256 , 411576 , 412903 , 414239 , 415584 , 416938 , 418301 , 419672 , 421053 , + 422442 , 423841 , 425249 , 426667 , 428094 , 429530 , 430976 , 432432 , 433898 , 435374 , 436860 , 438356 , 439863 , 441379 , 442907 , 444444 , + 445993 , 447552 , 449123 , 450704 , 452297 , 453901 , 455516 , 457143 , 458781 , 460432 , 462094 , 463768 , 465455 , 467153 , 468864 , 470588 , + 472325 , 474074 , 475836 , 477612 , 479401 , 481203 , 483019 , 484848 , 486692 , 488550 , 490421 , 492308 , 494208 , 496124 , 498054 , 500000 , + 500978 , 501961 , 502947 , 503937 , 504931 , 505929 , 506931 , 507937 , 508946 , 509960 , 510978 , 512000 , 513026 , 514056 , 515091 , 516129 , + 517172 , 518219 , 519270 , 520325 , 521385 , 522449 , 523517 , 524590 , 525667 , 526749 , 527835 , 528926 , 530021 , 531120 , 532225 , 533333 , + 534447 , 535565 , 536688 , 537815 , 538947 , 540084 , 541226 , 542373 , 543524 , 544681 , 545842 , 547009 , 548180 , 549356 , 550538 , 551724 , + 552916 , 554113 , 555315 , 556522 , 557734 , 558952 , 560175 , 561404 , 562637 , 563877 , 565121 , 566372 , 567627 , 568889 , 570156 , 571429 , + 572707 , 573991 , 575281 , 576577 , 577878 , 579186 , 580499 , 581818 , 583144 , 584475 , 585812 , 587156 , 588506 , 589862 , 591224 , 592593 , + 593968 , 595349 , 596737 , 598131 , 599532 , 600939 , 602353 , 603774 , 605201 , 606635 , 608076 , 609524 , 610979 , 612440 , 613909 , 615385 , + 616867 , 618357 , 619855 , 621359 , 622871 , 624390 , 625917 , 627451 , 628993 , 630542 , 632099 , 633663 , 635236 , 636816 , 638404 , 640000 , + 641604 , 643216 , 644836 , 646465 , 648101 , 649746 , 651399 , 653061 , 654731 , 656410 , 658098 , 659794 , 661499 , 663212 , 664935 , 666667 , + 668407 , 670157 , 671916 , 673684 , 675462 , 677249 , 679045 , 680851 , 682667 , 684492 , 686327 , 688172 , 690027 , 691892 , 693767 , 695652 , + 697548 , 699454 , 701370 , 703297 , 705234 , 707182 , 709141 , 711111 , 713092 , 715084 , 717087 , 719101 , 721127 , 723164 , 725212 , 727273 , + 729345 , 731429 , 733524 , 735632 , 737752 , 739884 , 742029 , 744186 , 746356 , 748538 , 750733 , 752941 , 755162 , 757396 , 759644 , 761905 , + 764179 , 766467 , 768769 , 771084 , 773414 , 775758 , 778116 , 780488 , 782875 , 785276 , 787692 , 790123 , 792570 , 795031 , 797508 , 800000 , + 802508 , 805031 , 807571 , 810127 , 812698 , 815287 , 817891 , 820513 , 823151 , 825806 , 828479 , 831169 , 833876 , 836601 , 839344 , 842105 , + 844884 , 847682 , 850498 , 853333 , 856187 , 859060 , 861953 , 864865 , 867797 , 870748 , 873720 , 876712 , 879725 , 882759 , 885813 , 888889 , + 891986 , 895105 , 898246 , 901408 , 904594 , 907801 , 911032 , 914286 , 917563 , 920863 , 924188 , 927536 , 930909 , 934307 , 937729 , 941176 , + 944649 , 948148 , 951673 , 955224 , 958801 , 962406 , 966038 , 969697 , 973384 , 977099 , 980843 , 984615 , 988417 , 992248 , 996109 , 1000000 , + 1001957 , 1003922 , 1005894 , 1007874 , 1009862 , 1011858 , 1013861 , 1015873 , 1017893 , 1019920 , 1021956 , 1024000 , 1026052 , 1028112 , 1030181 , 1032258 , + 1034343 , 1036437 , 1038540 , 1040650 , 1042770 , 1044898 , 1047035 , 1049180 , 1051335 , 1053498 , 1055670 , 1057851 , 1060041 , 1062241 , 1064449 , 1066667 , + 1068894 , 1071130 , 1073375 , 1075630 , 1077895 , 1080169 , 1082452 , 1084746 , 1087049 , 1089362 , 1091684 , 1094017 , 1096360 , 1098712 , 1101075 , 1103448 , + 1105832 , 1108225 , 1110629 , 1113043 , 1115468 , 1117904 , 1120350 , 1122807 , 1125275 , 1127753 , 1130243 , 1132743 , 1135255 , 1137778 , 1140312 , 1142857 , + 1145414 , 1147982 , 1150562 , 1153153 , 1155756 , 1158371 , 1160998 , 1163636 , 1166287 , 1168950 , 1171625 , 1174312 , 1177011 , 1179724 , 1182448 , 1185185 , + 1187935 , 1190698 , 1193473 , 1196262 , 1199063 , 1201878 , 1204706 , 1207547 , 1210402 , 1213270 , 1216152 , 1219048 , 1221957 , 1224880 , 1227818 , 1230769 , + 1233735 , 1236715 , 1239709 , 1242718 , 1245742 , 1248780 , 1251834 , 1254902 , 1257985 , 1261084 , 1264198 , 1267327 , 1270471 , 1273632 , 1276808 , 1280000 , + 1283208 , 1286432 , 1289673 , 1292929 , 1296203 , 1299492 , 1302799 , 1306122 , 1309463 , 1312821 , 1316195 , 1319588 , 1322997 , 1326425 , 1329870 , 1333333 , + 1336815 , 1340314 , 1343832 , 1347368 , 1350923 , 1354497 , 1358090 , 1361702 , 1365333 , 1368984 , 1372654 , 1376344 , 1380054 , 1383784 , 1387534 , 1391304 , + 1395095 , 1398907 , 1402740 , 1406593 , 1410468 , 1414365 , 1418283 , 1422222 , 1426184 , 1430168 , 1434174 , 1438202 , 1442254 , 1446328 , 1450425 , 1454545 , + 1458689 , 1462857 , 1467049 , 1471264 , 1475504 , 1479769 , 1484058 , 1488372 , 1492711 , 1497076 , 1501466 , 1505882 , 1510324 , 1514793 , 1519288 , 1523810 , + 1528358 , 1532934 , 1537538 , 1542169 , 1546828 , 1551515 , 1556231 , 1560976 , 1565749 , 1570552 , 1575385 , 1580247 , 1585139 , 1590062 , 1595016 , 1600000 , + 1605016 , 1610063 , 1615142 , 1620253 , 1625397 , 1630573 , 1635783 , 1641026 , 1646302 , 1651613 , 1656958 , 1662338 , 1667752 , 1673203 , 1678689 , 1684211 , + 1689769 , 1695364 , 1700997 , 1706667 , 1712375 , 1718121 , 1723906 , 1729730 , 1735593 , 1741497 , 1747440 , 1753425 , 1759450 , 1765517 , 1771626 , 1777778 , + 1783972 , 1790210 , 1796491 , 1802817 , 1809187 , 1815603 , 1822064 , 1828571 , 1835125 , 1841727 , 1848375 , 1855072 , 1861818 , 1868613 , 1875458 , 1882353 , + 1889299 , 1896296 , 1903346 , 1910448 , 1917603 , 1924812 , 1932075 , 1939394 , 1946768 , 1954198 , 1961686 , 1969231 , 1976834 , 1984496 , 1992218 , 2000000 , + 2003914 , 2007843 , 2011788 , 2015748 , 2019724 , 2023715 , 2027723 , 2031746 , 2035785 , 2039841 , 2043912 , 2048000 , 2052104 , 2056225 , 2060362 , 2064516 , + 2068687 , 2072874 , 2077079 , 2081301 , 2085540 , 2089796 , 2094070 , 2098361 , 2102669 , 2106996 , 2111340 , 2115702 , 2120083 , 2124481 , 2128898 , 2133333 , + 2137787 , 2142259 , 2146751 , 2151261 , 2155789 , 2160338 , 2164905 , 2169492 , 2174098 , 2178723 , 2183369 , 2188034 , 2192719 , 2197425 , 2202151 , 2206897 , + 2211663 , 2216450 , 2221258 , 2226087 , 2230937 , 2235808 , 2240700 , 2245614 , 2250549 , 2255507 , 2260486 , 2265487 , 2270510 , 2275556 , 2280624 , 2285714 , + 2290828 , 2295964 , 2301124 , 2306306 , 2311512 , 2316742 , 2321995 , 2327273 , 2332574 , 2337900 , 2343249 , 2348624 , 2354023 , 2359447 , 2364896 , 2370370 , + 2375870 , 2381395 , 2386946 , 2392523 , 2398126 , 2403756 , 2409412 , 2415094 , 2420804 , 2426540 , 2432304 , 2438095 , 2443914 , 2449761 , 2455635 , 2461538 , + 2467470 , 2473430 , 2479419 , 2485437 , 2491484 , 2497561 , 2503667 , 2509804 , 2515971 , 2522167 , 2528395 , 2534653 , 2540943 , 2547264 , 2553616 , 2560000 , + 2566416 , 2572864 , 2579345 , 2585859 , 2592405 , 2598985 , 2605598 , 2612245 , 2618926 , 2625641 , 2632391 , 2639175 , 2645995 , 2652850 , 2659740 , 2666667 , + 2673629 , 2680628 , 2687664 , 2694737 , 2701847 , 2708995 , 2716180 , 2723404 , 2730667 , 2737968 , 2745308 , 2752688 , 2760108 , 2767568 , 2775068 , 2782609 , + 2790191 , 2797814 , 2805479 , 2813187 , 2820937 , 2828729 , 2836565 , 2844444 , 2852368 , 2860335 , 2868347 , 2876404 , 2884507 , 2892655 , 2900850 , 2909091 , + 2917379 , 2925714 , 2934097 , 2942529 , 2951009 , 2959538 , 2968116 , 2976744 , 2985423 , 2994152 , 3002933 , 3011765 , 3020649 , 3029586 , 3038576 , 3047619 , + 3056716 , 3065868 , 3075075 , 3084337 , 3093656 , 3103030 , 3112462 , 3121951 , 3131498 , 3141104 , 3150769 , 3160494 , 3170279 , 3180124 , 3190031 , 3200000 , + 3210031 , 3220126 , 3230284 , 3240506 , 3250794 , 3261146 , 3271565 , 3282051 , 3292605 , 3303226 , 3313916 , 3324675 , 3335505 , 3346405 , 3357377 , 3368421 , + 3379538 , 3390728 , 3401993 , 3413333 , 3424749 , 3436242 , 3447811 , 3459459 , 3471186 , 3482993 , 3494881 , 3506849 , 3518900 , 3531034 , 3543253 , 3555556 , + 3567944 , 3580420 , 3592982 , 3605634 , 3618375 , 3631206 , 3644128 , 3657143 , 3670251 , 3683453 , 3696751 , 3710145 , 3723636 , 3737226 , 3750916 , 3764706 , + 3778598 , 3792593 , 3806691 , 3820896 , 3835206 , 3849624 , 3864151 , 3878788 , 3893536 , 3908397 , 3923372 , 3938462 , 3953668 , 3968992 , 3984436 , 4000000 , + 4007828 , 4015686 , 4023576 , 4031496 , 4039448 , 4047431 , 4055446 , 4063492 , 4071571 , 4079681 , 4087824 , 4096000 , 4104208 , 4112450 , 4120724 , 4129032 , + 4137374 , 4145749 , 4154158 , 4162602 , 4171079 , 4179592 , 4188139 , 4196721 , 4205339 , 4213992 , 4222680 , 4231405 , 4240166 , 4248963 , 4257796 , 4266667 , + 4275574 , 4284519 , 4293501 , 4302521 , 4311579 , 4320675 , 4329810 , 4338983 , 4348195 , 4357447 , 4366738 , 4376068 , 4385439 , 4394850 , 4404301 , 4413793 , + 4423326 , 4432900 , 4442516 , 4452174 , 4461874 , 4471616 , 4481400 , 4491228 , 4501099 , 4511013 , 4520971 , 4530973 , 4541020 , 4551111 , 4561247 , 4571429 , + 4581655 , 4591928 , 4602247 , 4612613 , 4623025 , 4633484 , 4643991 , 4654545 , 4665148 , 4675799 , 4686499 , 4697248 , 4708046 , 4718894 , 4729792 , 4740741 , + 4751740 , 4762791 , 4773893 , 4785047 , 4796253 , 4807512 , 4818824 , 4830189 , 4841608 , 4853081 , 4864608 , 4876190 , 4887828 , 4899522 , 4911271 , 4923077 , + 4934940 , 4946860 , 4958838 , 4970874 , 4982968 , 4995122 , 5007335 , 5019608 , 5031941 , 5044335 , 5056790 , 5069307 , 5081886 , 5094527 , 5107232 , 5120000 , + 5132832 , 5145729 , 5158690 , 5171717 , 5184810 , 5197970 , 5211196 , 5224490 , 5237852 , 5251282 , 5264781 , 5278351 , 5291990 , 5305699 , 5319481 , 5333333 , + 5347258 , 5361257 , 5375328 , 5389474 , 5403694 , 5417989 , 5432361 , 5446809 , 5461333 , 5475936 , 5490617 , 5505376 , 5520216 , 5535135 , 5550136 , 5565217 , + 5580381 , 5595628 , 5610959 , 5626374 , 5641873 , 5657459 , 5673130 , 5688889 , 5704735 , 5720670 , 5736695 , 5752809 , 5769014 , 5785311 , 5801700 , 5818182 , + 5834758 , 5851429 , 5868195 , 5885057 , 5902017 , 5919075 , 5936232 , 5953488 , 5970845 , 5988304 , 6005865 , 6023529 , 6041298 , 6059172 , 6077151 , 6095238 , + 6113433 , 6131737 , 6150150 , 6168675 , 6187311 , 6206061 , 6224924 , 6243902 , 6262997 , 6282209 , 6301538 , 6320988 , 6340557 , 6360248 , 6380062 , 6400000 , + 6420063 , 6440252 , 6460568 , 6481013 , 6501587 , 6522293 , 6543131 , 6564103 , 6585209 , 6606452 , 6627832 , 6649351 , 6671010 , 6692810 , 6714754 , 6736842 , + 6759076 , 6781457 , 6803987 , 6826667 , 6849498 , 6872483 , 6895623 , 6918919 , 6942373 , 6965986 , 6989761 , 7013699 , 7037801 , 7062069 , 7086505 , 7111111 , + 7135889 , 7160839 , 7185965 , 7211268 , 7236749 , 7262411 , 7288256 , 7314286 , 7340502 , 7366906 , 7393502 , 7420290 , 7447273 , 7474453 , 7501832 , 7529412 , + 7557196 , 7585185 , 7613383 , 7641791 , 7670412 , 7699248 , 7728302 , 7757576 , 7787072 , 7816794 , 7846743 , 7876923 , 7907336 , 7937984 , 7968872 , 8000000 , + 8015656 , 8031373 , 8047151 , 8062992 , 8078895 , 8094862 , 8110891 , 8126984 , 8143141 , 8159363 , 8175649 , 8192000 , 8208417 , 8224900 , 8241449 , 8258065 , + 8274747 , 8291498 , 8308316 , 8325203 , 8342159 , 8359184 , 8376278 , 8393443 , 8410678 , 8427984 , 8445361 , 8462810 , 8480331 , 8497925 , 8515593 , 8533333 , + 8551148 , 8569038 , 8587002 , 8605042 , 8623158 , 8641350 , 8659619 , 8677966 , 8696391 , 8714894 , 8733475 , 8752137 , 8770878 , 8789700 , 8808602 , 8827586 , + 8846652 , 8865801 , 8885033 , 8904348 , 8923747 , 8943231 , 8962801 , 8982456 , 9002198 , 9022026 , 9041943 , 9061947 , 9082040 , 9102222 , 9122494 , 9142857 , + 9163311 , 9183857 , 9204494 , 9225225 , 9246050 , 9266968 , 9287982 , 9309091 , 9330296 , 9351598 , 9372998 , 9394495 , 9416092 , 9437788 , 9459584 , 9481481 , + 9503480 , 9525581 , 9547786 , 9570093 , 9592506 , 9615023 , 9637647 , 9660377 , 9683215 , 9706161 , 9729216 , 9752381 , 9775656 , 9799043 , 9822542 , 9846154 , + 9869880 , 9893720 , 9917676 , 9941748 , 9965937 , 9990244 , 10014670 , 10039216 , 10063882 , 10088670 , 10113580 , 10138614 , 10163772 , 10189055 , 10214464 , 10240000 , + 10265664 , 10291457 , 10317380 , 10343434 , 10369620 , 10395939 , 10422392 , 10448980 , 10475703 , 10502564 , 10529563 , 10556701 , 10583979 , 10611399 , 10638961 , 10666667 , + 10694517 , 10722513 , 10750656 , 10778947 , 10807388 , 10835979 , 10864721 , 10893617 , 10922667 , 10951872 , 10981233 , 11010753 , 11040431 , 11070270 , 11100271 , 11130435 , + 11160763 , 11191257 , 11221918 , 11252747 , 11283747 , 11314917 , 11346260 , 11377778 , 11409471 , 11441341 , 11473389 , 11505618 , 11538028 , 11570621 , 11603399 , 11636364 , + 11669516 , 11702857 , 11736390 , 11770115 , 11804035 , 11838150 , 11872464 , 11906977 , 11941691 , 11976608 , 12011730 , 12047059 , 12082596 , 12118343 , 12154303 , 12190476 , + 12226866 , 12263473 , 12300300 , 12337349 , 12374622 , 12412121 , 12449848 , 12487805 , 12525994 , 12564417 , 12603077 , 12641975 , 12681115 , 12720497 , 12760125 , 12800000 , + 12840125 , 12880503 , 12921136 , 12962025 , 13003175 , 13044586 , 13086262 , 13128205 , 13170418 , 13212903 , 13255663 , 13298701 , 13342020 , 13385621 , 13429508 , 13473684 , + 13518152 , 13562914 , 13607973 , 13653333 , 13698997 , 13744966 , 13791246 , 13837838 , 13884746 , 13931973 , 13979522 , 14027397 , 14075601 , 14124138 , 14173010 , 14222222 , + 14271777 , 14321678 , 14371930 , 14422535 , 14473498 , 14524823 , 14576512 , 14628571 , 14681004 , 14733813 , 14787004 , 14840580 , 14894545 , 14948905 , 15003663 , 15058824 , + 15114391 , 15170370 , 15226766 , 15283582 , 15340824 , 15398496 , 15456604 , 15515152 , 15574144 , 15633588 , 15693487 , 15753846 , 15814672 , 15875969 , 15937743 , 16000000 , + 16031311 , 16062745 , 16094303 , 16125984 , 16157791 , 16189723 , 16221782 , 16253968 , 16286282 , 16318725 , 16351297 , 16384000 , 16416834 , 16449799 , 16482897 , 16516129 , + 16549495 , 16582996 , 16616633 , 16650407 , 16684318 , 16718367 , 16752556 , 16786885 , 16821355 , 16855967 , 16890722 , 16925620 , 16960663 , 16995851 , 17031185 , 17066667 , + 17102296 , 17138075 , 17174004 , 17210084 , 17246316 , 17282700 , 17319239 , 17355932 , 17392781 , 17429787 , 17466951 , 17504274 , 17541756 , 17579399 , 17617204 , 17655172 , + 17693305 , 17731602 , 17770065 , 17808696 , 17847495 , 17886463 , 17925602 , 17964912 , 18004396 , 18044053 , 18083885 , 18123894 , 18164080 , 18204444 , 18244989 , 18285714 , + 18326622 , 18367713 , 18408989 , 18450450 , 18492099 , 18533937 , 18575964 , 18618182 , 18660592 , 18703196 , 18745995 , 18788991 , 18832184 , 18875576 , 18919169 , 18962963 , + 19006961 , 19051163 , 19095571 , 19140187 , 19185012 , 19230047 , 19275294 , 19320755 , 19366430 , 19412322 , 19458432 , 19504762 , 19551313 , 19598086 , 19645084 , 19692308 , + 19739759 , 19787440 , 19835351 , 19883495 , 19931873 , 19980488 , 20029340 , 20078431 , 20127764 , 20177340 , 20227160 , 20277228 , 20327543 , 20378109 , 20428928 , 20480000 , + 20531328 , 20582915 , 20634761 , 20686869 , 20739241 , 20791878 , 20844784 , 20897959 , 20951407 , 21005128 , 21059126 , 21113402 , 21167959 , 21222798 , 21277922 , 21333333 , + 21389034 , 21445026 , 21501312 , 21557895 , 21614776 , 21671958 , 21729443 , 21787234 , 21845333 , 21903743 , 21962466 , 22021505 , 22080863 , 22140541 , 22200542 , 22260870 , + 22321526 , 22382514 , 22443836 , 22505495 , 22567493 , 22629834 , 22692521 , 22755556 , 22818942 , 22882682 , 22946779 , 23011236 , 23076056 , 23141243 , 23206799 , 23272727 , + 23339031 , 23405714 , 23472779 , 23540230 , 23608069 , 23676301 , 23744928 , 23813953 , 23883382 , 23953216 , 24023460 , 24094118 , 24165192 , 24236686 , 24308605 , 24380952 , + 24453731 , 24526946 , 24600601 , 24674699 , 24749245 , 24824242 , 24899696 , 24975610 , 25051988 , 25128834 , 25206154 , 25283951 , 25362229 , 25440994 , 25520249 , 25600000 , + 25680251 , 25761006 , 25842271 , 25924051 , 26006349 , 26089172 , 26172524 , 26256410 , 26340836 , 26425806 , 26511327 , 26597403 , 26684039 , 26771242 , 26859016 , 26947368 , + 27036304 , 27125828 , 27215947 , 27306667 , 27397993 , 27489933 , 27582492 , 27675676 , 27769492 , 27863946 , 27959044 , 28054795 , 28151203 , 28248276 , 28346021 , 28444444 , + 28543554 , 28643357 , 28743860 , 28845070 , 28946996 , 29049645 , 29153025 , 29257143 , 29362007 , 29467626 , 29574007 , 29681159 , 29789091 , 29897810 , 30007326 , 30117647 , + 30228782 , 30340741 , 30453532 , 30567164 , 30681648 , 30796992 , 30913208 , 31030303 , 31148289 , 31267176 , 31386973 , 31507692 , 31629344 , 31751938 , 31875486 , 32000000 , + 32062622 , 32125490 , 32188605 , 32251969 , 32315582 , 32379447 , 32443564 , 32507937 , 32572565 , 32637450 , 32702595 , 32768000 , 32833667 , 32899598 , 32965795 , 33032258 , + 33098990 , 33165992 , 33233266 , 33300813 , 33368635 , 33436735 , 33505112 , 33573770 , 33642710 , 33711934 , 33781443 , 33851240 , 33921325 , 33991701 , 34062370 , 34133333 , + 34204593 , 34276151 , 34348008 , 34420168 , 34492632 , 34565401 , 34638478 , 34711864 , 34785563 , 34859574 , 34933902 , 35008547 , 35083512 , 35158798 , 35234409 , 35310345 , + 35386609 , 35463203 , 35540130 , 35617391 , 35694989 , 35772926 , 35851204 , 35929825 , 36008791 , 36088106 , 36167770 , 36247788 , 36328160 , 36408889 , 36489978 , 36571429 , + 36653244 , 36735426 , 36817978 , 36900901 , 36984199 , 37067873 , 37151927 , 37236364 , 37321185 , 37406393 , 37491991 , 37577982 , 37664368 , 37751152 , 37838337 , 37925926 , + 38013921 , 38102326 , 38191142 , 38280374 , 38370023 , 38460094 , 38550588 , 38641509 , 38732861 , 38824645 , 38916865 , 39009524 , 39102625 , 39196172 , 39290168 , 39384615 , + 39479518 , 39574879 , 39670702 , 39766990 , 39863747 , 39960976 , 40058680 , 40156863 , 40255528 , 40354680 , 40454321 , 40554455 , 40655087 , 40756219 , 40857855 , 40960000 , + 41062657 , 41165829 , 41269521 , 41373737 , 41478481 , 41583756 , 41689567 , 41795918 , 41902813 , 42010256 , 42118252 , 42226804 , 42335917 , 42445596 , 42555844 , 42666667 , + 42778068 , 42890052 , 43002625 , 43115789 , 43229551 , 43343915 , 43458886 , 43574468 , 43690667 , 43807487 , 43924933 , 44043011 , 44161725 , 44281081 , 44401084 , 44521739 , + 44643052 , 44765027 , 44887671 , 45010989 , 45134986 , 45259669 , 45385042 , 45511111 , 45637883 , 45765363 , 45893557 , 46022472 , 46152113 , 46282486 , 46413598 , 46545455 , + 46678063 , 46811429 , 46945559 , 47080460 , 47216138 , 47352601 , 47489855 , 47627907 , 47766764 , 47906433 , 48046921 , 48188235 , 48330383 , 48473373 , 48617211 , 48761905 , + 48907463 , 49053892 , 49201201 , 49349398 , 49498489 , 49648485 , 49799392 , 49951220 , 50103976 , 50257669 , 50412308 , 50567901 , 50724458 , 50881988 , 51040498 , 51200000 , + 51360502 , 51522013 , 51684543 , 51848101 , 52012698 , 52178344 , 52345048 , 52512821 , 52681672 , 52851613 , 53022654 , 53194805 , 53368078 , 53542484 , 53718033 , 53894737 , + 54072607 , 54251656 , 54431894 , 54613333 , 54795987 , 54979866 , 55164983 , 55351351 , 55538983 , 55727891 , 55918089 , 56109589 , 56302405 , 56496552 , 56692042 , 56888889 , + 57087108 , 57286713 , 57487719 , 57690141 , 57893993 , 58099291 , 58306050 , 58514286 , 58724014 , 58935252 , 59148014 , 59362319 , 59578182 , 59795620 , 60014652 , 60235294 , + 60457565 , 60681481 , 60907063 , 61134328 , 61363296 , 61593985 , 61826415 , 62060606 , 62296578 , 62534351 , 62773946 , 63015385 , 63258687 , 63503876 , 63750973 , 64000000 diff --git a/src/sound/saasound/SAAFreq.h b/src/sound/saasound/SAAFreq.h new file mode 100755 index 000000000..478754621 --- /dev/null +++ b/src/sound/saasound/SAAFreq.h @@ -0,0 +1,72 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAFreq.h: interface for the CSAAFreq class. +// Note about Samplerates: 0=44100, 1=22050; 2=11025 +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAAFREQ_H_INCLUDE +#define SAAFREQ_H_INCLUDE + +#include "defns.h" + +class CSAAFreq +{ +private: +#ifdef SAAFREQ_FIXED_CLOCKRATE + // 'load in' the data for the static frequency lookup table + // precomputed for a fixed clockrate + // See: tools/freqdat.py + const static unsigned long m_FreqTable[2048]; +#else + // we'll calculate the frequency lookup table at runtime. + static unsigned long m_FreqTable[2048]; + static unsigned long m_nClockRate; +#endif + + unsigned long m_nCounter; + unsigned long m_nAdd; + unsigned long m_nCounter_low; + unsigned int m_nOversample; + unsigned long m_nCounterLimit_low; + int m_nLevel; + + int m_nCurrentOffset; + int m_nCurrentOctave; + int m_nNextOffset; + int m_nNextOctave; + bool m_bIgnoreOffsetData; + bool m_bNewData; + bool m_bSync; + + unsigned long m_nSampleRate; + CSAANoise * const m_pcConnectedNoiseGenerator; + CSAAEnv * const m_pcConnectedEnvGenerator; + const int m_nConnectedMode; // 0 = nothing; 1 = envgenerator; 2 = noisegenerator + + void UpdateOctaveOffsetData(void); + void SetAdd(void); + +public: + CSAAFreq(CSAANoise * const pcNoiseGenerator, CSAAEnv * const pcEnvGenerator); + ~CSAAFreq(); + void SetFreqOffset(BYTE nOffset); + void SetFreqOctave(BYTE nOctave); + void _SetSampleRate(unsigned int nSampleRate); + void _SetOversample(unsigned int oversample); + void _SetClockRate(int nClockRate); + void Sync(bool bSync); + int Tick(void); + int Level(void) const; + +}; + +inline int CSAAFreq::Level(void) const +{ + if (m_bSync) + return 1; + + return m_nLevel; +} + +#endif // SAAFREQ_H_INCLUDE diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp new file mode 100644 index 000000000..8545d3849 --- /dev/null +++ b/src/sound/saasound/SAAImpl.cpp @@ -0,0 +1,487 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAAImpl.cpp: implementation of the CSAASound class. +// the bones of the 'virtual SAA-1099' emulation +// +// the actual sound generation is carried out in the other classes; +// this class provides the output stage and the external interface only +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" + +#include "types.h" +#include "SAAImpl.h" +#include "defns.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAASoundInternal::CSAASoundInternal() + : +m_nClockRate(EXTERNAL_CLK_HZ), +m_bHighpass(false), +m_nSampleRate(SAMPLE_RATE_HZ), +m_nOversample(DEFAULT_OVERSAMPLE), +m_uParam(0), +m_uParamRate(0), +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) +m_nDebugSample(0), +#endif +m_chip() +{ +#ifdef USE_CONFIG_FILE + m_Config.ReadConfig(); +#endif + +#if defined(DEBUGSAA) + m_dbgfile.open(_T(DEBUG_SAA_REGISTER_LOG), std::ios_base::out); + m_pcmfile.open(_T(DEBUG_SAA_PCM_LOG), std::ios_base::out | std::ios_base::binary); +#elif defined(USE_CONFIG_FILE) + if (m_Config.m_bGenerateRegisterLogs) + m_dbgfile.open(m_Config.m_strRegisterLogPath, std::ios_base::out); + if (m_Config.m_bGeneratePcmLogs) + m_pcmfile.open(m_Config.m_strPcmOutputPath, std::ios_base::out | std::ios_base::binary); + + if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels) + { + for (int i = 0; i < 6; i++) + { + m_channel_pcmfile[i].open(m_Config.getChannelPcmOutputPath(i), std::ios_base::out | std::ios_base::binary); + } + } + + +#endif + // set parameters + // TODO support defaults and overrides from config file + // m_chip.SetSoundParameters(SAAP_FILTER | SAAP_11025 | SAAP_8BIT | SAAP_MONO); + // reset the virtual SAA + // m_chip.Clear(); + + m_chip._SetClockRate(m_nClockRate); + m_chip._SetOversample(m_nOversample); +} + +CSAASoundInternal::~CSAASoundInternal() +{ + // +} + +////////////////////////////////////////////////////////////////////// +// CSAASound members +////////////////////////////////////////////////////////////////////// + +void CSAASoundInternal::SetClockRate(unsigned int nClockRate) +{ + m_nClockRate = nClockRate; + m_chip._SetClockRate(m_nClockRate); +} + +void CSAASoundInternal::Clear(void) +{ + // reinitialises virtual SAA: + // sets reg 28 to 0x02; - sync and disabled + // sets regs 00-31 (except 28) to 0x00; + // sets reg 28 to 0x00; + // sets current reg to 0 + WriteAddressData(28,2); + for (int i=31; i>=0; i--) + { + if (i!=28) WriteAddressData(i,0); + } + WriteAddressData(28,0); + WriteAddress(0); +} + +void CSAASoundInternal::WriteData(BYTE nData) +{ + // originated from an OUT 255,d call + m_chip._WriteData(nData); +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) +#ifdef USE_CONFIG_FILE + if (m_Config.m_bGenerateRegisterLogs) + { +#endif + m_dbgfile << m_nDebugSample << " " << (int)m_chip._ReadAddress() << ":" << (int)nData << std::endl; +#ifdef USE_CONFIG_FILE + } +#endif +#endif +} + +void CSAASoundInternal::WriteAddress(BYTE nReg) +{ + // originated from an OUT 511,r call + m_chip._WriteAddress(nReg); +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) +#ifdef USE_CONFIG_FILE + if (m_Config.m_bGenerateRegisterLogs) + { +#endif + m_dbgfile << m_nDebugSample << " " << (int)nReg << ":"; + if (nReg==24) + { + m_dbgfile << ""; + } + else if (nReg==25) + { + m_dbgfile << ""; + } + m_dbgfile << std::endl; +#ifdef USE_CONFIG_FILE + } +#endif +#endif +} + +void CSAASoundInternal::WriteAddressData(BYTE nReg, BYTE nData) +{ + // performs WriteAddress(nReg) followed by WriteData(nData) + m_chip._WriteAddress(nReg); + m_chip._WriteData(nData); +} + +#if 1 +BYTE CSAASoundInternal::ReadAddress(void) +{ + // Not a real hardware function of the SAA-1099, which is write-only + return(m_chip._ReadAddress()); +} +#else +BYTE CSAASoundInternal::ReadAddress(void) +{ + // Not a real hardware function of the SAA-1099, which is write-only + return(0); +} +#endif + +void CSAASoundInternal::SetSoundParameters(SAAPARAM uParam) +{ + // set samplerate properties from uParam (deprecated but still supported) + unsigned int nSampleRate = m_nSampleRate; + switch (uParam & SAAP_MASK_SAMPLERATE) + { + case SAAP_44100: + nSampleRate = 44100; + m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_44100; + break; + case SAAP_22050: + nSampleRate = 22050; + m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_22050; + break; + case SAAP_11025: + nSampleRate = 11025; + m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_11025; + break; + case 0:// change nothing! + default: + break; + } + + if (nSampleRate != m_nSampleRate) + { + m_nSampleRate = nSampleRate; + m_chip._SetSampleRate(m_nSampleRate); + } + + // set filter properties from uParam + m_uParam = (m_uParam & ~SAAP_MASK_FILTER) | (uParam & SAAP_MASK_FILTER); + + m_bHighpass=true; +} + +void CSAASoundInternal::SetSampleRate(unsigned int nSampleRate) +{ + if (nSampleRate != m_nSampleRate) + { + m_nSampleRate = nSampleRate; + m_chip._SetSampleRate(m_nSampleRate); + } +} + +void CSAASoundInternal::SetOversample(unsigned int nOversample) +{ + if (nOversample != m_nOversample) + { + m_nOversample = nOversample; + m_chip._SetOversample(m_nOversample); + } +} + +SAAPARAM CSAASoundInternal::GetCurrentSoundParameters(void) +{ + return m_uParam | m_uParamRate; +} + +unsigned short CSAASoundInternal::GetCurrentBytesPerSample(void) +{ + // 16 bit stereo => 4 bytes per sample + return 4; +} + +/*static*/ unsigned short CSAASound::GetBytesPerSample(SAAPARAM uParam) +{ + // 16 bit stereo => 4 bytes per sample + switch (uParam & (SAAP_MASK_CHANNELS | SAAP_MASK_BITDEPTH)) + { + case SAAP_STEREO | SAAP_16BIT: + return 4; + default: + return 0; + } +} + +unsigned long CSAASoundInternal::GetCurrentSampleRate(void) +{ + return CSAASound::GetSampleRate(m_uParamRate); +} + +/*static*/ unsigned long CSAASound::GetSampleRate(SAAPARAM uParam) // static member function +{ + switch (uParam & SAAP_MASK_SAMPLERATE) + { + case SAAP_11025: + return 11025; + case SAAP_22050: + return 22050; + case SAAP_44100: + return 44100; + default: + return 0; + } +} + +#if defined(USE_CONFIG_FILE) || (defined(DEFAULT_BOOST) && DEFAULT_BOOST>1) +#define DO_BOOST +#endif + +void scale_for_output(unsigned int left_input, unsigned int right_input, + double oversample_scalar, bool highpass, double boost, + double& filterout_z1_left, double& filterout_z1_right, + BYTE* &pBuffer) +{ + double float_left = (double)left_input; + double float_right = (double)right_input; + float_left /= oversample_scalar; + float_right /= oversample_scalar; + + // scale output into good range + float_left *= DEFAULT_UNBOOSTED_MULTIPLIER; + float_right *= DEFAULT_UNBOOSTED_MULTIPLIER; + + if (highpass) + { + /* cutoff = 5 Hz (say) + const double b1 = exp(-2.0 * M_PI * (Fc/Fs)) + const double a0 = 1.0 - b1; + */ + const double b1 = 0.99928787; + const double a0 = 1.0 - b1; + + filterout_z1_left = float_left * a0 + filterout_z1_left * b1; + filterout_z1_right = float_right * a0 + filterout_z1_right * b1; + float_left -= filterout_z1_left; + float_right -= filterout_z1_right; + } + + // multiply by boost, if defined +#if defined(DO_BOOST) + float_left *= boost; + float_right *= boost; +#endif + // convert to 16-bit signed range with hard clipping + signed short left_output = (signed short)(float_left > 32767 ? 32767 : float_left < -32768 ? -32768 : float_left); + signed short right_output = (signed short)(float_right > 32767 ? 32767 : float_right < -32768 ? -32768 : float_right); + + *pBuffer++ = left_output & 0x00ff; + *pBuffer++ = (left_output >> 8) & 0x00ff; + *pBuffer++ = right_output & 0x00ff; + *pBuffer++ = (right_output >> 8) & 0x00ff; +} + +void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) +{ + unsigned int left_mixed, right_mixed; + static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; + +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) + BYTE* pBufferStart = pBuffer; + unsigned long nTotalSamples = nSamples; +#endif + +#if defined(DO_BOOST) +#if defined(USE_CONFIG_FILE) + double nBoost = m_Config.m_nBoost; +#else + double nBoost = DEFAULT_BOOST; +#endif +#else + double nBoost = 1.0; +#endif + + double oversample = double(1 << m_nOversample); + +#if defined(USE_CONFIG_FILE) + static double filterout_z1_left_0 = 0, filterout_z1_right_0 = 0; + static double filterout_z1_left_1 = 0, filterout_z1_right_1 = 0; + static double filterout_z1_left_2 = 0, filterout_z1_right_2 = 0; + static double filterout_z1_left_3 = 0, filterout_z1_right_3 = 0; + static double filterout_z1_left_4 = 0, filterout_z1_right_4 = 0; + static double filterout_z1_left_5 = 0, filterout_z1_right_5 = 0; + + if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels) + { + unsigned int left0, right0, left1, right1, left2, right2, left3, right3, left4, right4, left5, right5; + BYTE* pChannelBufferPtr[6] = { m_pChannelBuffer[0], m_pChannelBuffer[1], m_pChannelBuffer[2], m_pChannelBuffer[3], m_pChannelBuffer[4], m_pChannelBuffer[5] }; + + while (nSamples--) + { + m_chip._TickAndOutputSeparate(left_mixed, right_mixed, + left0, right0, + left1, right1, + left2, right2, + left3, right3, + left4, right4, + left5, right5); + scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer); + + // and the separate channels + scale_for_output(left0, right0, oversample, m_bHighpass, nBoost, filterout_z1_left_0, filterout_z1_right_0, pChannelBufferPtr[0]); + scale_for_output(left1, right1, oversample, m_bHighpass, nBoost, filterout_z1_left_1, filterout_z1_right_1, pChannelBufferPtr[1]); + scale_for_output(left2, right2, oversample, m_bHighpass, nBoost, filterout_z1_left_2, filterout_z1_right_2, pChannelBufferPtr[2]); + scale_for_output(left3, right3, oversample, m_bHighpass, nBoost, filterout_z1_left_3, filterout_z1_right_3, pChannelBufferPtr[3]); + scale_for_output(left4, right4, oversample, m_bHighpass, nBoost, filterout_z1_left_4, filterout_z1_right_4, pChannelBufferPtr[4]); + scale_for_output(left5, right5, oversample, m_bHighpass, nBoost, filterout_z1_left_5, filterout_z1_right_5, pChannelBufferPtr[5]); + + // flush channel output PCM buffers when full + if (pChannelBufferPtr[0] >= m_pChannelBuffer[0] + CHANNEL_BUFFER_SIZE) + { + for (int i = 0; i < 6; i++) + { + m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], CHANNEL_BUFFER_SIZE); + pChannelBufferPtr[i] = m_pChannelBuffer[i]; + } + } + } + // flush remaining channel PCM output data + if (pChannelBufferPtr[0] >= m_pChannelBuffer[0]) + { + for (int i = 0; i < 6; i++) + { + m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], pChannelBufferPtr[i]-m_pChannelBuffer[i]); + } + } + } + else + { +#endif + while (nSamples--) + { + m_chip._TickAndOutputStereo(left_mixed, right_mixed); + scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer); + } + +#if defined(USE_CONFIG_FILE) + } +#endif + +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) +#ifdef USE_CONFIG_FILE + if (m_Config.m_bGeneratePcmLogs) + { +#endif + m_pcmfile.write((const char *)pBufferStart, nTotalSamples * (unsigned long)GetCurrentBytesPerSample()); + m_nDebugSample += nTotalSamples; +#ifdef USE_CONFIG_FILE + } +#endif + +#endif +} + +/////////////////////////////////////////////////////// + +LPCSAASOUND SAAAPI CreateCSAASound(void) +{ + return (new CSAASoundInternal); +} + +void SAAAPI DestroyCSAASound(LPCSAASOUND object) +{ + delete (object); +} + + +/* thoughts on lowpass filtering as part of oversampling. +I tried this and really it didn't seem to make a lot of (audible) difference. + +// lowpass oversample filter adds complexity and not particularly audibly better than simple averaging. +// use_lowpass_oversample_filter_average_output adds an additional averaging step to the output of the oversample +// filter. this seems critical, because without this, the raw output of the lowpass filter is full of aliases +// If use_lowpass_oversample_filter is False, then the _average_output flag is ignored. +// Default, use_lowpass_oversample_filter is False, it sounds just fine really. + +//#define USE_LOWPASS_OVERSAMPLE_FILTER +#undef USE_LOWPASS_OVERSAMPLE_FILTER +//#define USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT +#undef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT + +#ifdef USE_LOWPASS_OVERSAMPLE_FILTER +static double oversample_lp_filterout_z1_left_stages[10] = { 0,0,0,0,0,0,0,0,0,0 }; +static double oversample_lp_filterout_z1_right_stages[10] = { 0,0,0,0,0,0,0,0,0,0 }; +double averaged_filterout_left = 0.0, averaged_filterout_right = 0.0; +const int nStages = 10; +for (int i = 0; i < 1 << m_nOversample; i++) +{ + Noise[0]->Tick(); + Noise[1]->Tick(); + f_left = f_right = 0; + for (int c = 0; c < 6; c++) + { + Amp[c]->TickAndOutputStereo(temp_left, temp_right); + f_left += (double)temp_left; + f_right += (double)temp_right; + } + // apply lowpass here. + // HACK: ASSUME m_nOversample is 64 (I was experimenting only using the 64x oversample anyway) + // therefore Fs = 44100*64 + // let's set Fc = 10kHz + // so Fc/Fs = 0.00354308390022675736961451247166 + // const double b1 = exp(-2.0 * M_PI * (Fc/Fs)) + // const double a0 = 1.0 - b1; + // const double b1 = 0.9779841137335348363722276130195; + const double b1 = 0.977; + const double a0 = 1.0 - b1; + + oversample_lp_filterout_z1_left_stages[0] = f_left * a0 + oversample_lp_filterout_z1_left_stages[0] * b1; + for (int stage = 1; stage < nStages; stage++) + oversample_lp_filterout_z1_left_stages[stage] = oversample_lp_filterout_z1_left_stages[stage - 1] * a0 + oversample_lp_filterout_z1_left_stages[stage] * b1; + oversample_lp_filterout_z1_right_stages[0] = f_right * a0 + oversample_lp_filterout_z1_right_stages[0] * b1; + for (int stage = 1; stage < nStages; stage++) + oversample_lp_filterout_z1_right_stages[stage] = oversample_lp_filterout_z1_right_stages[stage - 1] * a0 + oversample_lp_filterout_z1_right_stages[stage] * b1; + +#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT + averaged_filterout_left += oversample_lp_filterout_4z1_left; + averaged_filterout_right += oversample_lp_filterout_4z1_right; +#endif +} + +// by the end of this loop we will have computed the oversample lowpass filter m_nOversample times +// and yielded exactly ONE sample output. +#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT +f_left = averaged_filterout_left / (1 << m_nOversample); +f_right = averaged_filterout_right / (1 << m_nOversample); +#else +f_left = oversample_lp_filterout_z1_left_stages[nStages - 1]; +f_right = oversample_lp_filterout_z1_right_stages[nStages - 1]; +#endif + +#else + // do the simple 1/N averaging which is easier and sounds good enough + +#endif + +*/ + diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h new file mode 100755 index 000000000..61fa79c58 --- /dev/null +++ b/src/sound/saasound/SAAImpl.h @@ -0,0 +1,75 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// This is the internal implementation (header file) of the SAASound object. +// This is done so that the external interface to the object always stays the same +// (SAASound.h) even though the internal object can change +// .. Meaning future releases don't require relinking everyone elses code against +// the updated saasound stuff +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAAIMPL_H_INCLUDED +#define SAAIMPL_H_INCLUDED + +#include "SAASound.h" +#include "SAADevice.h" +#ifdef USE_CONFIG_FILE +#include "SAAConfig.h" +#endif + +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) +#include +#include +#include + +#if defined(USE_CONFIG_FILE) +const int CHANNEL_BUFFER_SIZE=1024; +#endif +#endif + +class CSAASoundInternal : public CSAASound +{ +private: + CSAADevice m_chip; + int m_uParam, m_uParamRate; + unsigned int m_nClockRate; + unsigned int m_nSampleRate; + unsigned int m_nOversample; + bool m_bHighpass; +#ifdef USE_CONFIG_FILE + SAAConfig m_Config; +#endif +#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) + unsigned long m_nDebugSample; + std::ofstream m_dbgfile, m_pcmfile; +#if defined(USE_CONFIG_FILE) + std::ofstream m_channel_pcmfile[6]; + BYTE m_pChannelBuffer[6][CHANNEL_BUFFER_SIZE]; +#endif +#endif + +public: + CSAASoundInternal(); + ~CSAASoundInternal(); + + void SetClockRate(unsigned int nClockRate); + void SetSampleRate(unsigned int nClockRate); + void SetOversample(unsigned int nOversample); + void SetSoundParameters(SAAPARAM uParam); + void WriteAddress(BYTE nReg); + void WriteData(BYTE nData); + void WriteAddressData(BYTE nReg, BYTE nData); + BYTE ReadAddress(void); + void Clear(void); + + SAAPARAM GetCurrentSoundParameters(void); + unsigned long GetCurrentSampleRate(void); + static unsigned long GetSampleRate(SAAPARAM uParam); + unsigned short GetCurrentBytesPerSample(void); + static unsigned short GetBytesPerSample(SAAPARAM uParam); + + void GenerateMany(BYTE * pBuffer, unsigned long nSamples); + +}; + +#endif // SAAIMPL_H_INCLUDED diff --git a/src/sound/saasound/SAANoise.cpp b/src/sound/saasound/SAANoise.cpp new file mode 100755 index 000000000..895a5a103 --- /dev/null +++ b/src/sound/saasound/SAANoise.cpp @@ -0,0 +1,180 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAANoise.cpp: implementation of the CSAANoise class. +// One noise generator +// +// After construction, it's important to SetSampleRate before +// trying to use the generator. +// (Just because the CSAANoise object has a default samplerate +// doesn't mean you should rely on it) +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" + +#include "types.h" +#include "SAANoise.h" +#include "defns.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CSAANoise::CSAANoise() +: +m_nCounter(0), +m_nCounter_low(0), +m_nCounterLimit_low(1), +m_nOversample(0), +m_bSync(false), +m_nSampleRate(SAMPLE_RATE_HZ), +m_nSourceMode(0), +m_nRand(1) +{ + _SetClockRate(EXTERNAL_CLK_HZ); + m_nAdd = m_nAddBase; +} + +CSAANoise::CSAANoise(unsigned long seed) +: +m_nCounter(0), +m_nCounter_low(0), +m_nCounterLimit_low(1), +m_nOversample(0), +m_bSync(false), +m_nSampleRate(SAMPLE_RATE_HZ), +m_nSourceMode(0), +m_nRand(seed) +{ + _SetClockRate(EXTERNAL_CLK_HZ); + m_nAdd = m_nAddBase; +} + +CSAANoise::~CSAANoise() +{ + // Nothing to do +} + +void CSAANoise::_SetClockRate(int nClockRate) +{ + // at 8MHz the clock rate is 31.250kHZ + // This is simply the clock rate divided by 256 i.e. 2^8 + // We then shift this by 2^12 (like the Freq) for better + // period accuracy. So that's the same as shifting by (12-8) + m_nAddBase = nClockRate << (12 - 8); +} + +void CSAANoise::Seed(unsigned long seed) +{ + m_nRand = seed; +} + +void CSAANoise::SetSource(int nSource) +{ + m_nSourceMode = nSource; + m_nAdd = m_nAddBase >> m_nSourceMode; +} + +void CSAANoise::Trigger(void) +{ + // Trigger only does anything useful when we're + // clocking from the frequency generator - i.e + // if bUseFreqGen = true (i.e. SourceMode = 3) + + // So if we're clocking from the noise generator + // clock (ie, SourceMode = 0, 1 or 2) then do nothing + +// No point actually checking m_bSync here ... because if sync is true, +// then frequency generators won't actually be generating Trigger pulses +// so we wouldn't even get here! + // EXCEPT - cool edge case: if sync is set, then actually the Noise Generator + // is triggered on EVERY CLOCK PULSE (i.e. 8MHz noise). So indeed it is correct + // to not check for sync here. NEEDS TEST CASE. + + if (m_nSourceMode == 3) + { + ChangeLevel(); + } +} + +void CSAANoise::Tick(void) +{ + // Tick only does anything useful when we're + // clocking from the noise generator clock + // (ie, SourceMode = 0, 1 or 2) + + // So, if SourceMode = 3 (ie, we're clocking from a + // frequency generator ==> bUseFreqGen = true) + // then do nothing + if ( (!m_bSync) && (m_nSourceMode!=3) ) + { + m_nCounter += m_nAdd; + while (m_nCounter >= (m_nSampleRate<<12)) + { + m_nCounter -= (m_nSampleRate<<12); + m_nCounter_low++; + if (m_nCounter_low >= m_nCounterLimit_low) + { + m_nCounter_low = 0; + ChangeLevel(); + } + } + } +} + +void CSAANoise::Sync(bool bSync) +{ + if (bSync) + { + m_nCounter = 0; + m_nCounter_low = 0; + } + m_bSync = bSync; +} + + +void CSAANoise::_SetSampleRate(int nSampleRate) +{ + m_nSampleRate = nSampleRate; +} + + +void CSAANoise::_SetOversample(unsigned int oversample) +{ + // oversample is a power of 2 i.e. + // if oversample == 2 then 4x oversample + // if oversample == 6 then 64x oversample + if (oversample < m_nOversample) + { + m_nCounter_low <<= (m_nOversample - oversample); + } + else + { + m_nCounter_low >>= (oversample - m_nOversample); + } + + m_nCounterLimit_low = 1<> 1) ^ 0x20400; + } + else + { + m_nRand >>= 1; + } +} diff --git a/src/sound/saasound/SAANoise.h b/src/sound/saasound/SAANoise.h new file mode 100755 index 000000000..61a65dee8 --- /dev/null +++ b/src/sound/saasound/SAANoise.h @@ -0,0 +1,54 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAANoise.h: interface for the CSAANoise class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAANOISE_H_INCLUDED +#define SAANOISE_H_INCLUDED + +class CSAANoise +{ +private: + unsigned long m_nCounter; + unsigned long m_nAdd; + unsigned long m_nCounter_low; + unsigned int m_nOversample; + unsigned long m_nCounterLimit_low; + bool m_bSync; // see description of "SYNC" bit of register 28 + unsigned long m_nSampleRate; // = 44100 when RateMode=0, for example + int m_nSourceMode; + unsigned long m_nAddBase; // nAdd for 31.25 kHz noise at 44.1 kHz samplerate + + // pseudo-random number generator + unsigned long m_nRand; + + void ChangeLevel(void); + + +public: + CSAANoise(); + CSAANoise(unsigned long seed); + ~CSAANoise(); + + void SetSource(int nSource); + void Trigger(void); + void _SetSampleRate(int nSampleRate); + void _SetOversample(unsigned int oversample); + void _SetClockRate(int nClockRate); + void Seed(unsigned long seed); + + void Tick(void); + int Level(void) const; + void Sync(bool bSync); + +}; + +inline int CSAANoise::Level(void) const +{ + // returns 0 or 1 + return (m_nRand & 0x00000001); +} + + +#endif // SAANOISE_H_INCLUDED diff --git a/src/sound/saasound/SAASndC.cpp b/src/sound/saasound/SAASndC.cpp new file mode 100755 index 000000000..9af0d76e7 --- /dev/null +++ b/src/sound/saasound/SAASndC.cpp @@ -0,0 +1,100 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// Thanks to this file (and associated header file) you can now +// use CSAASound from within a standard 'C' program +// +////////////////////////////////////////////////////////////////////// + +#include "SAASound.h" +#include "types.h" +#include "SAAEnv.h" +#include "SAANoise.h" +#include "SAAFreq.h" +#include "SAAAmp.h" +#include "SAASound.h" +#include "SAAImpl.h" + +SAASND SAAAPI newSAASND(void) +{ + return (SAASND)(new CSAASoundInternal()); +} + +void SAAAPI deleteSAASND(SAASND object) +{ + delete (LPCSAASOUND)(object); +} + +void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate) +{ + ((LPCSAASOUND)(object))->SetClockRate(nClockRate); +} + +void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam) +{ + ((LPCSAASOUND)(object))->SetSoundParameters(uParam); +} + +void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg) +{ + ((LPCSAASOUND)(object))->WriteAddress(nReg); +} + +void SAAAPI SAASNDWriteData(SAASND object, BYTE nData) +{ + ((LPCSAASOUND)(object))->WriteData(nData); +} + +void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData) +{ + ((LPCSAASOUND)(object))->WriteAddressData(nReg, nData); +} + +void SAAAPI SAASNDClear(SAASND object) +{ + ((LPCSAASOUND)(object))->Clear(); +} + +SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object) +{ + return ((LPCSAASOUND)(object))->GetCurrentSoundParameters(); +} + +unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object) +{ + return ((LPCSAASOUND)(object))->GetCurrentBytesPerSample(); +} + +unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam) +{ + return CSAASound::GetBytesPerSample(uParam); +} + +unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object) +{ + return ((LPCSAASOUND)(object))->GetCurrentSampleRate(); +} + +unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam) +{ + return CSAASound::GetSampleRate(uParam); +} + +void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples) +{ + ((LPCSAASOUND)(object))->GenerateMany(pBuffer, nSamples); +} + +void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate) +{ + return ((LPCSAASOUND)(object))->SetSampleRate(nSampleRate); +} + +void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample) +{ + return ((LPCSAASOUND)(object))->SetOversample(nOversample); +} + +BYTE SAAAPI SAASNDReadAddress(SAASND object) +{ + return ((LPCSAASOUND)(object))->ReadAddress(); +} diff --git a/src/sound/saasound/SAASndC.h b/src/sound/saasound/SAASndC.h new file mode 100644 index 000000000..c6fd65765 --- /dev/null +++ b/src/sound/saasound/SAASndC.h @@ -0,0 +1,102 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// ********** +// * PUBLIC * +// ********** +// +// SAASndC.h: "C-style" interface for the CSAASound class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAASNDC_H_INCLUDED +#define SAASNDC_H_INCLUDED + +#ifdef _MSC_VER +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +#endif + +#ifndef SAASOUND_H_INCLUDED + +// Parameters for use with SetSoundParameters, for example, +// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAAP_16BIT | SAAP_STEREO); +#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400 +#define SAAP_FILTER_OVERSAMPLE64x 0x00000300 +#define SAAP_FILTER_OVERSAMPLE2x 0x00000200 +#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x +#define SAAP_NOFILTER 0x00000100 +#define SAAP_44100 0x00000030 +#define SAAP_22050 0x00000020 +#define SAAP_11025 0x00000010 +#define SAAP_16BIT 0x0000000c +#define SAAP_8BIT 0x00000004 +#define SAAP_STEREO 0x00000003 +#define SAAP_MONO 0x00000001 + +// Bitmasks for use with GetCurrentSoundParameters, for example, +// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters() +#define SAAP_MASK_FILTER 0x00000f00 +#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00 +#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300 +#define SAAP_MASK_SAMPLERATE 0x000000030 +#define SAAP_MASK_BITDEPTH 0x0000000c +#define SAAP_MASK_CHANNELS 0x00000003 + +typedef unsigned long SAAPARAM; + + +#ifndef BYTE +#define BYTE unsigned char +#endif + +#ifdef WIN32 +#ifndef WINAPI +#define WINAPI __stdcall +#endif +#define EXTAPI __declspec(dllexport) WINAPI +#else // Win32 +#ifndef WINAPI +#define WINAPI /**/ +#endif +#define EXTAPI /**/ +#endif // Win32 + +#endif // SAASOUND_H_INCLUDED + +typedef void * SAASND; + +// the following are implemented as calls, etc, to a class. + +#ifdef __cplusplus +extern "C" { +#endif + +SAASND EXTAPI newSAASND(void); +void EXTAPI deleteSAASND(SAASND object); + +void EXTAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam); +void EXTAPI SAASNDWriteAddress(SAASND object, BYTE nReg); +void EXTAPI SAASNDWriteData(SAASND object, BYTE nData); +void EXTAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData); +void EXTAPI SAASNDClear(SAASND object); +BYTE EXTAPI SAASNDReadAddress(SAASND object); + +SAAPARAM EXTAPI SAASNDGetCurrentSoundParameters(SAASND object); +unsigned short EXTAPI SAASNDGetCurrentBytesPerSample(SAASND object); +unsigned short EXTAPI SAASNDGetBytesPerSample(SAAPARAM uParam); +unsigned long EXTAPI SAASNDGetCurrentSampleRate(SAASND object); +unsigned long EXTAPI SAASNDGetSampleRate(SAAPARAM uParam); + +void EXTAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples); + +void EXTAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate); +void EXTAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate); +void EXTAPI SAASNDSetOversample(SAASND object, unsigned int nOversample); + + +#ifdef __cplusplus +}; // extern "C" +#endif + +#endif // SAASNDC_H_INCLUDED diff --git a/src/sound/saasound/SAASound.cpp b/src/sound/saasound/SAASound.cpp new file mode 100755 index 000000000..c5e33d862 --- /dev/null +++ b/src/sound/saasound/SAASound.cpp @@ -0,0 +1,13 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAASound.cpp - dummy function +// +////////////////////////////////////////////////////////////////////// + +#include + +// Provide something so the compiler doesn't optimise us out of existance +int SomeFunction () +{ + return 42; +} diff --git a/src/sound/saasound/SAASound.h b/src/sound/saasound/SAASound.h new file mode 100644 index 000000000..a5e9265ac --- /dev/null +++ b/src/sound/saasound/SAASound.h @@ -0,0 +1,130 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// SAASound.h: interface for the CSAASound class. +// +// This corresponds to the public (exported) DLL interface, so all +// APIs and client factory methods belong here. +// +// Compatibility notes : the intention is for this to be fully backwards +// compatible across minor and patch versions. Any backwards breaking changes +// should be reflected as a major version increment. New functionality can be added +// in minor versions so long as backwards compatiblity is maintained +// +// Version 3.3.0 (4th Dec 2018) +// +////////////////////////////////////////////////////////////////////// + +#ifndef SAASOUND_H_INCLUDED +#define SAASOUND_H_INCLUDED + +// define this if you want to output diagnostic text and PCM files +//#define DEBUGSAA + +// Parameters for use with SetSoundParameters, for example, +// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAA_16BIT | SAA_STEREO); +// SAAP_FILTER_HIGHPASS_SIMPLE can be ORd with SAAP_FILTER_OVERSAMPLE64x/2x +#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400 +#define SAAP_FILTER_OVERSAMPLE64x 0x00000300 +#define SAAP_FILTER_OVERSAMPLE2x 0x00000200 +#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x +#define SAAP_NOFILTER 0x00000100 +#define SAAP_44100 0x00000030 +#define SAAP_22050 0x00000020 +#define SAAP_11025 0x00000010 +#define SAAP_16BIT 0x0000000c +#define SAAP_8BIT 0x00000004 +#define SAAP_STEREO 0x00000003 +#define SAAP_MONO 0x00000001 + +// Bitmasks for use with GetCurrentSoundParameters, for example, +// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters() +#define SAAP_MASK_FILTER 0x00000f00 +#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00 +#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300 +#define SAAP_MASK_SAMPLERATE 0x000000030 +#define SAAP_MASK_BITDEPTH 0x0000000c +#define SAAP_MASK_CHANNELS 0x00000003 + +typedef unsigned long SAAPARAM; + + +#ifndef BYTE +#define BYTE unsigned char +#endif + +#ifdef _WIN32 +#define SAAAPI _stdcall +#else +#define SAAAPI +#endif + + +#ifdef __cplusplus + +class CSAASound +{ +public: + virtual ~CSAASound() { } + + virtual void SetSoundParameters (SAAPARAM uParam) = 0; + virtual void WriteAddress (BYTE nReg) = 0; + virtual void WriteData (BYTE nData) = 0; + virtual void WriteAddressData (BYTE nReg, BYTE nData) = 0; + virtual void Clear () = 0; + virtual BYTE ReadAddress () = 0; + + virtual SAAPARAM GetCurrentSoundParameters () = 0; + virtual unsigned long GetCurrentSampleRate () = 0; + static unsigned long GetSampleRate (SAAPARAM uParam); + virtual unsigned short GetCurrentBytesPerSample () = 0; + static unsigned short GetBytesPerSample (SAAPARAM uParam); + + virtual void GenerateMany (BYTE * pBuffer, unsigned long nSamples) = 0; + + virtual void SetClockRate(unsigned int nClockRate) = 0; + virtual void SetSampleRate(unsigned int nSampleRate) = 0; + virtual void SetOversample(unsigned int nOversample) = 0; +}; + +typedef class CSAASound * LPCSAASOUND; + +LPCSAASOUND SAAAPI CreateCSAASound(void); +void SAAAPI DestroyCSAASound(LPCSAASOUND object); + +#endif // __cplusplus + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * SAASND; + +// "C-style" interface for the CSAASound class +SAASND SAAAPI newSAASND(void); +void SAAAPI deleteSAASND(SAASND object); + +void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam); +void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg); +void SAAAPI SAASNDWriteData(SAASND object, BYTE nData); +void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData); +void SAAAPI SAASNDClear(SAASND object); + +SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object); +unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object); +unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam); +unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object); +unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam); + +void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples); +void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate); +void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate); +void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample); + +BYTE SAAAPI SAASNDReadAddress(SAASND object); + +#ifdef __cplusplus +}; // extern "C" +#endif + +#endif // SAASOUND_H_INCLUDED diff --git a/src/sound/saasound/defns.h b/src/sound/saasound/defns.h new file mode 100644 index 000000000..e81d1c819 --- /dev/null +++ b/src/sound/saasound/defns.h @@ -0,0 +1,59 @@ +// Part of SAASound copyright 2020 Dave Hooper +// +// defns.h: compile-time configuration parameters +// +////////////////////////////////////////////////////////////////////// + +#ifndef DEFNS_H_INCLUDED +#define DEFNS_H_INCLUDED + +#define HAVE_CONFIG_H +#ifdef HAVE_CONFIG_H +// using CMAKE +#include "saasound_cmake_config.h" +#else + +// initial default SAA1099 crystal clock rate in HZ (can be changed subsequently by calling SetClockRate) +#define EXTERNAL_CLK_HZ 8000000 + +// define SAAFREQ_FIXED_CLOCKRATE if the above external clock rate is the only supported clock rate +// i.e. only support a single compile-time clock rate (=> this also prevents using the SetClockRate method) +#undef SAAFREQ_FIXED_CLOCKRATE +// #define SAAFREQ_FIXED_CLOCKRATE + +// initial default sample rate (audio samplerate) +#define SAMPLE_RATE_HZ 44100 + +// initial default oversample (audio quality) recommend 0<=oversample<=6 +#define DEFAULT_OVERSAMPLE 6 + +// Whether to dump out a log of all register and value changes and raw output pcm +//#define DEBUGSAA +#undef DEBUGSAA + +// the (default) names of the register output and pcm output log files. +// If you're using a config file, you can change these (or, if you enable +// debugging via the config file settings, but leave the filenames unspecified, +// it will use these defaults) +#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt" +#define DEBUG_SAA_PCM_LOG "debugsaa.pcm" +// Whether to include support for these debug logs via config file (only making +// sense if USE_CONFIG_FILE is also defined) + +// Whether to support a startup configuration file that is parsed at load time +// #undef USE_CONFIG_FILE +#define USE_CONFIG_FILE + +// and if so, what is its location +#ifdef USE_CONFIG_FILE +#define CONFIG_FILE_PATH "SAASound.cfg" +#endif // USE_CONFIG_FILE + +#define DEFAULT_UNBOOSTED_MULTIPLIER 11.35 + +#define DEFAULT_BOOST 1 + + +#endif // HAVE_CONFIG_H + +#endif // DEFNS_H_INCLUDED diff --git a/src/sound/saasound/resource.h b/src/sound/saasound/resource.h new file mode 100755 index 000000000..0b893bf3a --- /dev/null +++ b/src/sound/saasound/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by SAASound.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/sound/saasound/saasound_cmake_config.h b/src/sound/saasound/saasound_cmake_config.h new file mode 100644 index 000000000..da914a71b --- /dev/null +++ b/src/sound/saasound/saasound_cmake_config.h @@ -0,0 +1,14 @@ +#pragma once + +#define EXTERNAL_CLK_HZ 7159090 +/* #undef SAAFREQ_FIXED_CLOCKRATE */ +#define SAMPLE_RATE_HZ 44100 +#define DEFAULT_OVERSAMPLE 6 +#define DEFAULT_UNBOOSTED_MULTIPLIER 11.3 +#define DEFAULT_BOOST 1 +/* #undef DEBUGSAA */ +#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt" +#define DEBUG_SAA_PCM_LOG "debugsaa.pcm" + +/* #undef USE_CONFIG_FILE */ +#define CONFIG_FILE_PATH "SAASound.cfg" diff --git a/src/sound/saasound/types.h b/src/sound/saasound/types.h new file mode 100755 index 000000000..4eb62f485 --- /dev/null +++ b/src/sound/saasound/types.h @@ -0,0 +1,34 @@ +// Part of SAASound copyright 1998-2018 Dave Hooper +// +// handy typedefs +// +////////////////////////////////////////////////////////////////////// + +#ifndef TYPES_H_INCLUDED +#define TYPES_H_INCLUDED + +#if defined(__i386__) || defined(WIN32) || \ + (defined(__alpha__) || defined(__alpha)) || \ + defined(__arm__) || \ + (defined(__mips__) && defined(__MIPSEL__)) +#else +#define __BIG_ENDIAN +#endif + + +#ifndef NULL +#define NULL 0 +#endif + +typedef struct +{ + int nNumberOfPhases; + bool bLooping; + int nLevels[2][2][16]; // [Resolution][Phase][Withinphase] +} ENVDATA; + +#ifdef WIN32 +extern "C" void _stdcall OutputDebugStringA (char*); +#endif + +#endif diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 66dff80f3..60165365d 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -8,6 +8,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> +#include "saasound/SAASound.h" #include <86box/snd_cms.h> #include <86box/sound.h> #include <86box/plat_unused.h> @@ -15,62 +16,13 @@ void cms_update(cms_t *cms) { - for (; cms->pos < sound_pos_global; cms->pos++) { - int16_t out_l = 0; - int16_t out_r = 0; - - for (uint8_t c = 0; c < 4; c++) { - switch (cms->noisetype[c >> 1][c & 1]) { - case 0: - cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 256; - break; - case 1: - cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 512; - break; - case 2: - cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 1024; - break; - case 3: - cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; - break; - - default: - break; - } - } - for (uint8_t c = 0; c < 2; c++) { - if (cms->regs[c][0x1C] & 1) { - for (uint8_t d = 0; d < 6; d++) { - if (cms->regs[c][0x14] & (1 << d)) { - if (cms->stat[c][d]) - out_l += (cms->vol[c][d][0] * 90); - if (cms->stat[c][d]) - out_r += (cms->vol[c][d][1] * 90); - cms->count[c][d] += cms->freq[c][d]; - if (cms->count[c][d] >= 24000) { - cms->count[c][d] -= 24000; - cms->stat[c][d] ^= 1; - } - } else if (cms->regs[c][0x15] & (1 << d)) { - if (cms->noise[c][d / 3] & 1) - out_l += (cms->vol[c][d][0] * 90); - if (cms->noise[c][d / 3] & 1) - out_r += (cms->vol[c][d][0] * 90); - } - } - for (uint8_t d = 0; d < 2; d++) { - cms->noisecount[c][d] += cms->noisefreq[c][d]; - while (cms->noisecount[c][d] >= 24000) { - cms->noisecount[c][d] -= 24000; - cms->noise[c][d] <<= 1; - if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) - cms->noise[c][d] |= 1; - } - } - } - } - cms->buffer[cms->pos << 1] = out_l; - cms->buffer[(cms->pos << 1) + 1] = out_r; + if (cms->pos < wavetable_pos_global) { + SAASNDGenerateMany(cms->saasound, (unsigned char*)&cms->buffer[cms->pos], wavetable_pos_global - cms->pos); + cms->pos = wavetable_pos_global; + } + if (cms->pos2 < wavetable_pos_global) { + SAASNDGenerateMany(cms->saasound2, (unsigned char*)&cms->buffer2[cms->pos2], wavetable_pos_global - cms->pos2); + cms->pos2 = wavetable_pos_global; } } @@ -87,6 +39,19 @@ cms_get_buffer(int32_t *buffer, int len, void *priv) cms->pos = 0; } +void +cms_get_buffer_2(int32_t *buffer, int len, void *priv) +{ + cms_t *cms = (cms_t *) priv; + + cms_update(cms); + + for (int c = 0; c < len * 2; c++) + buffer[c] += cms->buffer2[c]; + + cms->pos2 = 0; +} + void cms_write(uint16_t addr, uint8_t val, void *priv) { @@ -96,54 +61,19 @@ cms_write(uint16_t addr, uint8_t val, void *priv) switch (addr & 0xf) { case 0x1: /* SAA #1 Register Select Port */ - cms->addrs[0] = val & 31; + SAASNDWriteAddress(cms->saasound, val & 31); break; case 0x3: /* SAA #2 Register Select Port */ - cms->addrs[1] = val & 31; + SAASNDWriteAddress(cms->saasound2, val & 31); break; case 0x0: /* SAA #1 Data Port */ + cms_update(cms); + SAASNDWriteData(cms->saasound, val); + break; case 0x2: /* SAA #2 Data Port */ cms_update(cms); - cms->regs[chip][cms->addrs[chip] & 31] = val; - switch (cms->addrs[chip] & 31) { - case 0x00: - case 0x01: - case 0x02: /*Volume*/ - case 0x03: - case 0x04: - case 0x05: - voice = cms->addrs[chip] & 7; - cms->vol[chip][voice][0] = val & 0xf; - cms->vol[chip][voice][1] = val >> 4; - break; - case 0x08: - case 0x09: - case 0x0A: /*Frequency*/ - case 0x0B: - case 0x0C: - case 0x0D: - voice = cms->addrs[chip] & 7; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; - cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - break; - case 0x10: - case 0x11: - case 0x12: /*Octave*/ - voice = (cms->addrs[chip] & 3) << 1; - cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); - cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); - cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); - cms->freq[chip][voice + 1] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); - break; - case 0x16: /*Noise*/ - cms->noisetype[chip][0] = val & 3; - cms->noisetype[chip][1] = (val >> 4) & 3; - break; - - default: - break; - } + SAASNDWriteData(cms->saasound2, val); break; case 0x6: /* GameBlaster Write Port */ @@ -163,9 +93,9 @@ cms_read(uint16_t addr, void *priv) switch (addr & 0xf) { case 0x1: /* SAA #1 Register Select Port */ - return cms->addrs[0]; + return SAASNDReadAddress(cms->saasound); case 0x3: /* SAA #2 Register Select Port */ - return cms->addrs[1]; + return SAASNDReadAddress(cms->saasound2); case 0x4: /* GameBlaster Read port (Always returns 0x7F) */ return 0x7f; case 0xa: /* GameBlaster Read Port */ @@ -185,7 +115,12 @@ cms_init(UNUSED(const device_t *info)) uint16_t addr = device_get_config_hex16("base"); io_sethandler(addr, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); - sound_add_handler(cms_get_buffer, cms); + cms->saasound = newSAASND(); + SAASNDSetSoundParameters(cms->saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); + cms->saasound2 = newSAASND(); + SAASNDSetSoundParameters(cms->saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); + wavetable_add_handler(cms_get_buffer, cms); + wavetable_add_handler(cms_get_buffer_2, cms); return cms; } @@ -194,6 +129,9 @@ cms_close(void *priv) { cms_t *cms = (cms_t *) priv; + deleteSAASND(cms->saasound); + deleteSAASND(cms->saasound2); + free(cms); } From b644016d1e0a7a917637c2fadcf8d8056d09b4ab Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 1 Apr 2025 23:11:09 +0600 Subject: [PATCH 0649/1190] Port Sound Blaster 1.x/2.x SAA1099 emulation to SAASound --- src/sound/snd_sb.c | 65 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e89946486..4a17fe20b 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -41,6 +41,7 @@ #include <86box/sound.h> #include "cpu.h" #include <86box/timer.h> +#include "saasound/SAASound.h" #include <86box/snd_sb.h> #include <86box/plat_unused.h> @@ -145,6 +146,42 @@ sb_log(const char *fmt, ...) # define sb_log(fmt, ...) #endif +void +sb_cms_get_buffer(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + cms_update(&sb->cms); + + for (int c = 0; c < len * 2; c++) { + if (sb->mixer_enabled) { + buffer[c] += sb->cms.buffer[c] * sb->mixer_sb2.fm; + } + else + buffer[c] += sb->cms.buffer[c]; + } + + sb->cms.pos = 0; +} + +void +sb_cms_get_buffer_2(int32_t *buffer, int len, void *priv) +{ + sb_t *sb = (sb_t *) priv; + + cms_update(&sb->cms); + + for (int c = 0; c < len * 2; c++) { + if (sb->mixer_enabled) { + buffer[c] += sb->cms.buffer2[c] * sb->mixer_sb2.fm; + } + else + buffer[c] += sb->cms.buffer2[c]; + } + + sb->cms.pos2 = 0; +} + /* SB 1, 1.5, MCV, and 2 do not have a mixer, so signal is hardwired. */ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) @@ -155,23 +192,10 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) sb_dsp_update(&sb->dsp); - if (sb->cms_enabled) - cms_update(&sb->cms); - for (int c = 0; c < len * 2; c += 2) { double out_l = 0.0; double out_r = 0.0; - if (sb->cms_enabled) { - out_l += sb->cms.buffer[c]; - out_r += sb->cms.buffer[c + 1]; - } - - if (sb->cms_enabled && sb->mixer_enabled) { - out_l *= mixer->fm; - out_r *= mixer->fm; - } - /* TODO: Recording: I assume it has direct mic and line in like SB2. It is unclear from the docs if it has a filter, but it probably does. */ /* TODO: Recording: Mic and line In with AGC. */ @@ -192,9 +216,6 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) } sb->dsp.pos = 0; - - if (sb->cms_enabled) - sb->cms.pos = 0; } static void @@ -2890,6 +2911,13 @@ sb_init(UNUSED(const device_t *info)) cms_read, NULL, NULL, cms_write, NULL, NULL, &sb->cms); + + sb->cms.saasound = newSAASND(); + SAASNDSetSoundParameters(sb->cms.saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); + sb->cms.saasound2 = newSAASND(); + SAASNDSetSoundParameters(sb->cms.saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); + wavetable_add_handler(sb_cms_get_buffer, sb); + wavetable_add_handler(sb_cms_get_buffer_2, sb); } if (mixer_addr > 0x000) { @@ -4044,6 +4072,11 @@ sb_close(void *priv) sb_t *sb = (sb_t *) priv; sb_dsp_close(&sb->dsp); + if (sb->cms_enabled) { + deleteSAASND(sb->cms.saasound); + deleteSAASND(sb->cms.saasound2); + } + free(sb); } From ee71952e02a272422cfe39cd00265c2cfc7d23f2 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 2 Apr 2025 00:33:24 +0600 Subject: [PATCH 0650/1190] Don't attempt altering window position if fullscreen --- src/qt/qt_mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index b3d0d9fa9..4c04ce76e 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -803,7 +803,7 @@ MainWindow::resizeEvent(QResizeEvent *event) { //qDebug() << pos().x() + event->size().width(); //qDebug() << pos().y() + event->size().height(); - if (vid_resize == 1) + if (vid_resize == 1 || video_fullscreen) return; int newX = pos().x(); From 3956032b94e20d47175b940c19c2830228f55357 Mon Sep 17 00:00:00 2001 From: Emlyn Corrin Date: Tue, 1 Apr 2025 20:05:08 +0100 Subject: [PATCH 0651/1190] Display ISABugger status in monospace font with colour for the LED bits --- src/device/bugger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/device/bugger.c b/src/device/bugger.c index b56937a43..6b9ed43cc 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -84,7 +84,7 @@ static uint8_t bug_spcfg; /* serial port configuration */ #define FIFO_LEN 256 static uint8_t bug_buff[FIFO_LEN]; /* serial port data buffer */ static uint8_t *bug_bptr; -#define UISTR_LEN 24 +#define UISTR_LEN 91 static char bug_str[UISTR_LEN]; /* UI output string */ extern void ui_sb_bugui(char *__str); @@ -112,7 +112,7 @@ static void bug_setui(void) { /* Format all current info in a string. */ - sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c", + sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c", bug_seg2, bug_seg1, (bug_ledg & 0x80) ? 'G' : 'g', (bug_ledg & 0x40) ? 'G' : 'g', (bug_ledg & 0x20) ? 'G' : 'g', (bug_ledg & 0x10) ? 'G' : 'g', From 5e61b78b782dfaf8b4139c598deecc40ad412cd8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 2 Apr 2025 01:10:21 +0600 Subject: [PATCH 0652/1190] Make sure that floppy icons and options do not appear if there's no floppy controller available --- src/floppy/fdc.c | 6 ++++++ src/qt/qt_machinestatus.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 51c3aa24a..e656e639c 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -79,6 +79,8 @@ int floppyrate[4]; int fdc_current[FDC_MAX] = { 0, 0 }; +volatile int fdcinited = 0; + #ifdef ENABLE_FDC_LOG int fdc_do_log = ENABLE_FDC_LOG; @@ -2337,6 +2339,8 @@ fdc_close(void *priv) fifo_close(fdc->fifo_p); + fdcinited = 0; + free(fdc); } @@ -2382,6 +2386,8 @@ fdc_init(const device_t *info) fdc_reset(fdc); + fdcinited = 1; + return fdc; } diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index d555be360..aba7fc1d4 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -40,6 +40,8 @@ extern "C" { #include <86box/ui.h> #include <86box/machine_status.h> #include <86box/config.h> + +extern volatile int fdcinited; }; #include @@ -303,6 +305,9 @@ MachineStatus::hasSCSI() void MachineStatus::iterateFDD(const std::function &cb) { + if (!fdcinited) + return; + for (int i = 0; i < FDD_NUM; ++i) { if (fdd_get_type(i) != 0) { cb(i); From dd5a25aad39830c9c674b26b5c3beaba8a405f11 Mon Sep 17 00:00:00 2001 From: Emlyn Corrin Date: Tue, 1 Apr 2025 21:56:41 +0100 Subject: [PATCH 0653/1190] Only set LED colour when it is lit --- src/device/bugger.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/device/bugger.c b/src/device/bugger.c index 6b9ed43cc..6a30df7be 100644 --- a/src/device/bugger.c +++ b/src/device/bugger.c @@ -84,7 +84,10 @@ static uint8_t bug_spcfg; /* serial port configuration */ #define FIFO_LEN 256 static uint8_t bug_buff[FIFO_LEN]; /* serial port data buffer */ static uint8_t *bug_bptr; -#define UISTR_LEN 91 + +static char LED_R[] = "R"; +static char LED_G[] = "G"; +#define UISTR_LEN (17 + 8 * sizeof(LED_G) + 8 * sizeof(LED_R)) static char bug_str[UISTR_LEN]; /* UI output string */ extern void ui_sb_bugui(char *__str); @@ -112,16 +115,16 @@ static void bug_setui(void) { /* Format all current info in a string. */ - sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c", + sprintf(bug_str, "%02X:%02X %s%s%s%s%s%s%s%s-%s%s%s%s%s%s%s%s", bug_seg2, bug_seg1, - (bug_ledg & 0x80) ? 'G' : 'g', (bug_ledg & 0x40) ? 'G' : 'g', - (bug_ledg & 0x20) ? 'G' : 'g', (bug_ledg & 0x10) ? 'G' : 'g', - (bug_ledg & 0x08) ? 'G' : 'g', (bug_ledg & 0x04) ? 'G' : 'g', - (bug_ledg & 0x02) ? 'G' : 'g', (bug_ledg & 0x01) ? 'G' : 'g', - (bug_ledr & 0x80) ? 'R' : 'r', (bug_ledr & 0x40) ? 'R' : 'r', - (bug_ledr & 0x20) ? 'R' : 'r', (bug_ledr & 0x10) ? 'R' : 'r', - (bug_ledr & 0x08) ? 'R' : 'r', (bug_ledr & 0x04) ? 'R' : 'r', - (bug_ledr & 0x02) ? 'R' : 'r', (bug_ledr & 0x01) ? 'R' : 'r'); + (bug_ledg & 0x80) ? LED_G : "g", (bug_ledg & 0x40) ? LED_G : "g", + (bug_ledg & 0x20) ? LED_G : "g", (bug_ledg & 0x10) ? LED_G : "g", + (bug_ledg & 0x08) ? LED_G : "g", (bug_ledg & 0x04) ? LED_G : "g", + (bug_ledg & 0x02) ? LED_G : "g", (bug_ledg & 0x01) ? LED_G : "g", + (bug_ledr & 0x80) ? LED_R : "r", (bug_ledr & 0x40) ? LED_R : "r", + (bug_ledr & 0x20) ? LED_R : "r", (bug_ledr & 0x10) ? LED_R : "r", + (bug_ledr & 0x08) ? LED_R : "r", (bug_ledr & 0x04) ? LED_R : "r", + (bug_ledr & 0x02) ? LED_R : "r", (bug_ledr & 0x01) ? LED_R : "r"); /* Send formatted string to the UI. */ ui_sb_bugui(bug_str); From 2a8e4d5a68cfc04debdfad855df2331a1d61d15a Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Apr 2025 08:34:34 +0200 Subject: [PATCH 0654/1190] PCI and ACPI - when resetting all devices, also reset (ie. zero) all of the emulated RAM as well, fixes Windows 2000 after soft reset on later machines such as the ASUS P2B-LS. --- src/acpi.c | 4 +++- src/include/86box/mem.h | 1 + src/mem/mem.c | 13 +++++++++++++ src/pci.c | 2 ++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/acpi.c b/src/acpi.c index ccd51ebca..963f26ae6 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -1025,8 +1025,10 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p nvr_reg_write(0x000f, 0xff, dev->nvr); } - if (sus_typ & SUS_RESET_PCI) + if (sus_typ & SUS_RESET_PCI) { device_reset_all(DEVICE_PCI); + mem_zero(); + } if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 81b46b2fa..f8d0f659a 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -459,6 +459,7 @@ extern void mem_a20_recalc(void); extern void mem_init(void); extern void mem_close(void); +extern void mem_zero(void); extern void mem_reset(void); extern void mem_remap_top_ex(int kb, uint32_t start); extern void mem_remap_top_ex_nomid(int kb, uint32_t start); diff --git a/src/mem/mem.c b/src/mem/mem.c index 074b44bda..c4d11300b 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2792,6 +2792,17 @@ mem_init_ram_mapping(mem_mapping_t *mapping, uint32_t base, uint32_t size) mem_add_ram_mapping(mapping, base, size); } +void +mem_zero(void) +{ +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) + if (mem_size > 1048576) + memset(ram2, 0x00, ram2_size + 16); +#endif + + memset(ram, 0x00, ram_size + 16); +} + /* Reset the memory state. */ void mem_reset(void) @@ -2867,8 +2878,10 @@ mem_reset(void) return; } memset(ram, 0x00, ram_size + 16); +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (mem_size > 1048576) ram2 = &(ram[1 << 30]); +#endif } /* diff --git a/src/pci.c b/src/pci.c index ab585c456..c2e4ca237 100644 --- a/src/pci.c +++ b/src/pci.c @@ -419,6 +419,8 @@ pci_trc_reset(uint8_t val) mem_a20_recalc(); flushmmucache(); + + mem_zero(); } #ifdef USE_DYNAREC From de04870db26175dfd065a5708d85a337ca07aad4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Apr 2025 08:58:16 +0200 Subject: [PATCH 0655/1190] CMS/SAA: Fix warnings. --- src/sound/saasound/SAADevice.cpp | 2 +- src/sound/saasound/SAAEnv.cpp | 8 ++++---- src/sound/saasound/SAAFreq.cpp | 17 ++++++++++++----- src/sound/saasound/SAAImpl.cpp | 14 ++++++++------ src/sound/saasound/SAANoise.cpp | 4 ++-- src/sound/snd_cms.c | 2 -- 6 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/sound/saasound/SAADevice.cpp b/src/sound/saasound/SAADevice.cpp index 306aa477a..718b05a95 100644 --- a/src/sound/saasound/SAADevice.cpp +++ b/src/sound/saasound/SAADevice.cpp @@ -107,7 +107,7 @@ void CSAADevice::_SetSampleRate(unsigned int nSampleRate) void CSAADevice::_SetOversample(unsigned int nOversample) { - if (nOversample != m_nOversample) + if (((int) nOversample) != m_nOversample) { m_nOversample = nOversample; m_Osc0._SetOversample(nOversample); diff --git a/src/sound/saasound/SAAEnv.cpp b/src/sound/saasound/SAAEnv.cpp index ae8191112..049f51f96 100755 --- a/src/sound/saasound/SAAEnv.cpp +++ b/src/sound/saasound/SAAEnv.cpp @@ -40,12 +40,12 @@ const ENVDATA CSAAEnv::cs_EnvData[8] = CSAAEnv::CSAAEnv() : m_bEnabled(false), -m_bNewData(false), -m_nNextData(0), -m_bEnvelopeEnded(true), m_nPhase(0), m_nPhasePosition(0), -m_nResolution(1) +m_bEnvelopeEnded(true), +m_nResolution(1), +m_bNewData(false), +m_nNextData(0) { // initialise itself with the value 'zero' SetEnvControl(0); diff --git a/src/sound/saasound/SAAFreq.cpp b/src/sound/saasound/SAAFreq.cpp index 52cbc7a3d..61a04f6ad 100755 --- a/src/sound/saasound/SAAFreq.cpp +++ b/src/sound/saasound/SAAFreq.cpp @@ -32,11 +32,18 @@ const int INITIAL_LEVEL = 1; CSAAFreq::CSAAFreq(CSAANoise * const NoiseGenerator, CSAAEnv * const EnvGenerator) : -m_nCounter(0), m_nCounter_low(0), m_nAdd(0), +m_nCounter(0), +m_nAdd(0), +m_nCounter_low(0), +m_nOversample(0), +m_nCounterLimit_low(1), m_nLevel(INITIAL_LEVEL), -m_nOversample(0), m_nCounterLimit_low(1), -m_nCurrentOffset(0), m_nCurrentOctave(0), m_nNextOffset(0), m_nNextOctave(0), -m_bIgnoreOffsetData(false), m_bNewData(false), +m_nCurrentOffset(0), +m_nCurrentOctave(0), +m_nNextOffset(0), +m_nNextOctave(0), +m_bIgnoreOffsetData(false), +m_bNewData(false), m_bSync(false), m_nSampleRate(SAMPLE_RATE_HZ), m_pcConnectedNoiseGenerator(NoiseGenerator), @@ -194,7 +201,7 @@ void CSAAFreq::_SetClockRate(int nClockRate) // Finally, note that the standard formula corresponds to a 8MHz base clock // so we rescale the final result by the ratio nClockRate/8000000 - if (nClockRate != m_nClockRate) + if (((unsigned long) nClockRate) != m_nClockRate) { m_nClockRate = nClockRate; int ix = 0; diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp index 8545d3849..f136eefc6 100644 --- a/src/sound/saasound/SAAImpl.cpp +++ b/src/sound/saasound/SAAImpl.cpp @@ -20,16 +20,18 @@ CSAASoundInternal::CSAASoundInternal() : -m_nClockRate(EXTERNAL_CLK_HZ), -m_bHighpass(false), -m_nSampleRate(SAMPLE_RATE_HZ), -m_nOversample(DEFAULT_OVERSAMPLE), +m_chip(), m_uParam(0), m_uParamRate(0), +m_nClockRate(EXTERNAL_CLK_HZ), +m_nSampleRate(SAMPLE_RATE_HZ), +m_nOversample(DEFAULT_OVERSAMPLE), #if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -m_nDebugSample(0), +m_bHighpass(false), +m_nDebugSample(0) +#else +m_bHighpass(false) #endif -m_chip() { #ifdef USE_CONFIG_FILE m_Config.ReadConfig(); diff --git a/src/sound/saasound/SAANoise.cpp b/src/sound/saasound/SAANoise.cpp index 895a5a103..1cf3458dd 100755 --- a/src/sound/saasound/SAANoise.cpp +++ b/src/sound/saasound/SAANoise.cpp @@ -25,8 +25,8 @@ CSAANoise::CSAANoise() : m_nCounter(0), m_nCounter_low(0), -m_nCounterLimit_low(1), m_nOversample(0), +m_nCounterLimit_low(1), m_bSync(false), m_nSampleRate(SAMPLE_RATE_HZ), m_nSourceMode(0), @@ -40,8 +40,8 @@ CSAANoise::CSAANoise(unsigned long seed) : m_nCounter(0), m_nCounter_low(0), -m_nCounterLimit_low(1), m_nOversample(0), +m_nCounterLimit_low(1), m_bSync(false), m_nSampleRate(SAMPLE_RATE_HZ), m_nSourceMode(0), diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 60165365d..c6591b1fc 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -56,8 +56,6 @@ void cms_write(uint16_t addr, uint8_t val, void *priv) { cms_t *cms = (cms_t *) priv; - int voice; - int chip = (addr & 2) >> 1; switch (addr & 0xf) { case 0x1: /* SAA #1 Register Select Port */ From 420a08ee2c8755dc1ba6785cbd5e31247aac1c1f Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Apr 2025 17:18:44 +0200 Subject: [PATCH 0656/1190] mem.c: Do not initialize the > 1 GB mapping on 64-bit binaries where it is not necessary. --- src/mem/mem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mem/mem.c b/src/mem/mem.c index c4d11300b..8c2cfd6cc 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2976,6 +2976,7 @@ mem_reset(void) else if (cpu_16bitbus && is6117 && mem_size > 65408) mem_init_ram_mapping(&ram_high_mapping, 0x100000, (65408 - 1024) * 1024); else { +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (mem_size > 1048576) { mem_init_ram_mapping(&ram_high_mapping, 0x100000, (1048576 - 1024) * 1024); @@ -2988,6 +2989,9 @@ mem_reset(void) ram2, MEM_MAPPING_INTERNAL, NULL); } else mem_init_ram_mapping(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024); +#else + mem_init_ram_mapping(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024); +#endif } } From 98efd05ddaa32823028c2130ffeb26ea40bbc6a2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Apr 2025 18:45:27 +0200 Subject: [PATCH 0657/1190] Alfredo, Batman's Renvenge, and Plato: Pre-initialize NVR to 0x00 instead of 0xFF and give them the correct Phoenix keyboard controller, fixes hang after the first soft reset. --- src/machine/m_at_386dx_486.c | 4 +++- src/machine/m_at_socket4.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0ee353f53..572cebc2e 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1249,6 +1249,8 @@ machine_at_alfredo_init(const machine_t *model) return ret; machine_at_common_init(model); + + device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); @@ -1258,7 +1260,7 @@ machine_at_alfredo_init(const machine_t *model) pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_pci_device); + device_add(&keyboard_ps2_phoenix_device); device_add(&sio_device); device_add(&fdc37c663_device); device_add(&intel_flash_bxt_ami_device); diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 78df5b0cb..072d52e01 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -44,7 +44,9 @@ void machine_at_premiere_common_init(const machine_t *model, int pci_switch) { - machine_at_common_init(model); + machine_at_common_init_ex(model); + + device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2 | pci_switch); @@ -54,7 +56,7 @@ machine_at_premiere_common_init(const machine_t *model, int pci_switch) pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_phoenix_device); device_add(&sio_zb_device); device_add(&fdc37c665_device); device_add(&intel_flash_bxt_ami_device); From babac318944a5aa80daedd99d76f3abaf651f915 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Apr 2025 18:46:35 +0200 Subject: [PATCH 0658/1190] Fixed a compile-breaking mistake. --- src/machine/m_at_386dx_486.c | 2 +- src/machine/m_at_socket4.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 572cebc2e..7f285af65 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1248,7 +1248,7 @@ machine_at_alfredo_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 072d52e01..0d78c6de3 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -44,7 +44,7 @@ void machine_at_premiere_common_init(const machine_t *model, int pci_switch) { - machine_at_common_init_ex(model); + machine_at_common_init_ex(model, 2); device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); From 57851e7606d02ed15fb470641158d2b1dfb98c66 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 2 Apr 2025 16:21:50 -0300 Subject: [PATCH 0659/1190] AD1848: Logging and clean-ups I forgot to commit --- src/sound/snd_ad1848.c | 78 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 87755a96c..202fd891a 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -19,11 +19,12 @@ * Copyright 2021-2025 RichardG. */ #include +#include #include #include #include #include - +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/dma.h> #include <86box/pic.h> @@ -36,6 +37,24 @@ #define CS4232 0x02 #define CS4236 0x03 +#ifdef ENABLE_AD1848_LOG +int ad1848_do_log = ENABLE_AD1848_LOG; + +static void +ad1848_log(const char *fmt, ...) +{ + va_list ap; + + if (ad1848_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define ad1848_log(fmt, ...) +#endif + static int ad1848_vols_7bits[128]; static double ad1848_vols_5bits_aux_gain[32]; @@ -46,12 +65,14 @@ extern uint8_t adjustMap4[64]; void ad1848_setirq(ad1848_t *ad1848, int irq) { + ad1848_log("AD1848: setirq(%d)\n", irq); ad1848->irq = irq; } void ad1848_setdma(ad1848_t *ad1848, int newdma) { + ad1848_log("AD1848: setdma(%d)\n", newdma); ad1848->dma = newdma; } @@ -62,6 +83,7 @@ ad1848_updatevolmask(ad1848_t *ad1848) ad1848->wave_vol_mask = 0x7f; else ad1848->wave_vol_mask = 0x3f; + ad1848_log("AD1848: updatevolmask(%02X)\n", ad1848->wave_vol_mask); } static double @@ -99,6 +121,8 @@ ad1848_get_default_freq(ad1848_t *ad1848) break; } + ad1848_log("AD1848: Frequency %f through default path\n", freq); + return freq; } @@ -136,6 +160,8 @@ ad1848_updatefreq(ad1848_t *ad1848) freq /= 2558.0; break; } + + ad1848_log("AD1848: Frequency %f through CS4236B+ path\n", freq); } else if (ad1848->regs[22] & 0x80) { const uint8_t set = (ad1848->regs[22] >> 1) & 0x3f; freq = (ad1848->regs[22] & 1) ? 33868800.0 : 49152000.0; @@ -153,6 +179,8 @@ ad1848_updatefreq(ad1848_t *ad1848) freq /= 256 * set; break; } + + ad1848_log("AD1848: Frequency %f through CS4232+ path\n", freq); } else freq = ad1848_get_default_freq(ad1848); } else @@ -182,18 +210,16 @@ ad1848_read(uint16_t addr, void *priv) ad1848->regs[ad1848->index] = ret; break; - case 18: - case 19: + case 18 ... 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */ - ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */ + ret = ad1848->xregs[6 | (ad1848->index & 1)]; /* real FM volume on registers 6 and 7 */ else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */ - ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */ + ret = ad1848->xregs[16 | (ad1848->index & 1)]; /* real wavetable volume on registers 16 and 17 */ } break; - case 20: - case 21: + case 20 ... 21: /* Backdoor to the Control/RAM registers on CS4235+. */ if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) ret = ad1848->cram_read(ad1848->index - 15, ad1848->cram_priv); @@ -229,13 +255,16 @@ ad1848_read(uint16_t addr, void *priv) default: break; } + ad1848_log("AD1848: read(X%d) = %02X\n", ad1848->xindex, ret); + return ret; } break; default: break; } - break; + ad1848_log("AD1848: read(I%d) = %02X\n", ad1848->index, ret); + return ret; case 2: ret = ad1848->status; @@ -245,6 +274,8 @@ ad1848_read(uint16_t addr, void *priv) break; } + ad1848_log("AD1848: read(%04X) = %02X\n", addr, ret); + return ret; } @@ -295,7 +326,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 11: - return; + goto readonly_i; case 12: if (ad1848->type >= AD1848_TYPE_CS4248) { @@ -307,19 +338,19 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) ad1848->fmt_mask &= ~0x80; } } - return; + goto readonly_i; case 14: ad1848->count = ad1848->regs[15] | (val << 8); break; - case 18: - case 19: + case 18 ... 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { if (ad1848->type >= AD1848_TYPE_CS4235) { if (ad1848->xregs[18] & 0x20) /* AUX1 remapping */ ad1848->regs[ad1848->index & 3] = val; /* also controls AUX1 on registers 2 and 3 */ } else { + temp = 0; if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */ ad1848->xregs[6 | (ad1848->index & 1)] = val; /* real FM volume on extended registers 6 and 7 */ temp = 1; @@ -343,7 +374,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) /* Stop here if any remapping is enabled. */ if (temp) - return; + goto readonly_i; } /* HACK: the Windows 9x driver's "Synth" control writes to this @@ -362,8 +393,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) } break; - case 20: - case 21: + case 20 ... 21: /* Backdoor to the Control/RAM registers on CS4235+. */ if ((ad1848->type >= AD1848_TYPE_CS4235) && (ad1848->xregs[18] & 0x80)) { ad1848->cram_write(ad1848->index - 15, val, ad1848->cram_priv); @@ -421,7 +451,7 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 25: - return; + goto readonly_x; case 26 ... 28: case 30: @@ -438,6 +468,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) if (updatefreq) ad1848_updatefreq(ad1848); +readonly_x: + ad1848_log("AD1848: write(X%d, %02X)\n", ad1848->xindex, val); return; } break; @@ -451,14 +483,14 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) break; case 25: - return; + goto readonly_i; case 27: if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236)) - return; + goto readonly_i; break; case 29: if ((ad1848->type != AD1848_TYPE_CS4232) && (ad1848->type != AD1848_TYPE_CS4236)) - return; + goto readonly_i; break; default: @@ -480,7 +512,9 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) else ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; - break; +readonly_i: + ad1848_log("AD1848: write(I%d, %02X)\n", ad1848->index, val); + return; case 2: ad1848->status &= 0xfe; @@ -490,6 +524,8 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) default: break; } + + ad1848_log("AD1848: write(%04X, %02X)\n", addr, val); } void @@ -743,6 +779,8 @@ ad1848_init(ad1848_t *ad1848, uint8_t type) uint8_t c; double attenuation; + ad1848_log("AD1848: init(%02X)\n", type); + ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; ad1848->mce = 0x40; From f56f636248aea56ce4dafabbf0a18597d167ce02 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 2 Apr 2025 16:27:10 -0300 Subject: [PATCH 0660/1190] Report 4 GB cacheable memory on Deschutes CPUs, fixes modern Linux limiting itself to 512 MB on some machines --- src/cpu/cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 910d40765..61bd8bf36 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -2649,6 +2649,11 @@ cpu_ven_reset(void) case CPU_PENTIUM2: case CPU_PENTIUM2D: msr.mtrr_cap = 0x00000508ULL; + + /* 4 GB cacheable space on Deschutes 651h and later (including the 1632h + Overdrive) according to the Pentium II Processor Specification Update. */ + if (cpu_s->cpuid_model >= 0x651) + msr.bbl_cr_ctl3 |= 0x00300000; break; case CPU_CYRIX3S: @@ -4103,7 +4108,7 @@ pentium_invalid_wrmsr: break; /* BBL_CR_CTL3 - L2 Cache Control Register 3 */ case 0x11e: - msr.bbl_cr_ctl3 = EAX | ((uint64_t) EDX << 32); + msr.bbl_cr_ctl3 = (msr.bbl_cr_ctl3 & 0x02f00000) | (EAX & ~0x02f00000) | ((uint64_t) EDX << 32); break; /* Unknown */ case 0x131: From 5432c1dd1382331b94985283b5034daafef4c37d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 2 Apr 2025 21:33:26 +0200 Subject: [PATCH 0661/1190] 8514/A compatible changes of the day (April 2nd, 2025) 1. Aliases are aliases, period. 2. Actually make the ports using bit 15 of their range use the command FIFO. 3. Improved the special ATI command 0xc2b5 in the IBM bitblt side, fixes cursor issues in 24bpp mode using OS/2. 4. When the FIFO is empty, clear the busy and available flags. 5. Also reapply a workaround for 24bpp foreground color patterns in ATI command Scan To X command, fixes patterns in OS/2 and possibly elsewhere. 6. Accelerated HiColor mode, in the IBM passthrough mode, should always be enabled, for now, as well as the Extended ATI Mach32 8bpp mode when prompted, fixes OS/2 booting into the GUI in HiColor mode. 7. Dummy data path configuration values on direct linedraw should not trigger a pixtrans read when it's not needed, fixes possible hang ups in IBM/ATI mode when the busy flag remains enabled. --- src/video/vid_8514a.c | 171 +++++++++------ src/video/vid_ati_mach8.c | 438 +++++++++++++++++++++++--------------- 2 files changed, 375 insertions(+), 234 deletions(-) diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 7c0bf9702..8925f01da 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -334,6 +334,13 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + if (port & 0x8000) { + if ((port != 0xe2e8) && (port != 0xe2e9) && (port != 0xe6e8) && (port != 0xe6e9)) { + if (port & 0x4000) + port &= ~0x4000; + } + } + switch (port) { case 0x2e8: WRITE8(port, dev->htotal, val); @@ -499,19 +506,16 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x82e8: - case 0xc2e8: if (len == 2) dev->accel.cur_y = val & 0x7ff; break; case 0x86e8: - case 0xc6e8: if (len == 2) dev->accel.cur_x = val & 0x7ff; break; case 0x8ae8: - case 0xcae8: if (len == 2) { dev->accel.desty = val & 0x7ff; dev->accel.desty_axstp = val & 0x3fff; @@ -521,7 +525,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x8ee8: - case 0xcee8: if (len == 2) { dev->accel.destx = val & 0x7ff; dev->accel.destx_distp = val & 0x3fff; @@ -531,12 +534,8 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x92e8: - if (len == 2) - dev->test = val; - fallthrough; - - case 0xd2e8: if (len == 2) { + dev->test = val; dev->accel.err_term = val & 0x3fff; if (val & 0x2000) dev->accel.err_term |= ~0x1fff; @@ -544,7 +543,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x96e8: - case 0xd6e8: if (len == 2) { dev->accel.maj_axis_pcnt = val & 0x7ff; dev->accel.maj_axis_pcnt_no_limit = val; @@ -552,7 +550,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x9ae8: - case 0xdae8: dev->accel.ssv_state = 0; if (len == 2) { dev->data_available = 0; @@ -562,13 +559,12 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (dev->accel.cmd & 0x100) dev->accel.cmd_back = 0; - ibm8514_log("8514/A CMD=%04x, back=%d, frgd color=%04x, frgdmix=%02x, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.cmd_back, dev->accel.frgd_color, dev->accel.frgd_mix, dev->accel.multifunc[0x0a]); + ibm8514_log("8514/A CMD=%04x, frgd color=%04x, frgdmix=%02x, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.frgd_color, dev->accel.frgd_mix, dev->accel.multifunc[0x0a]); ibm8514_accel_start(-1, 0, -1, 0, svga, len); } break; case 0x9ee8: - case 0xdee8: dev->accel.ssv_state = 1; if (len == 2) { dev->accel.short_stroke = val; @@ -628,35 +624,29 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0xaae8: - case 0xeae8: if (len == 2) dev->accel.wrt_mask = val; break; case 0xaee8: - case 0xeee8: if (len == 2) dev->accel.rd_mask = val; break; case 0xb2e8: - case 0xf2e8: if (len == 2) dev->accel.color_cmp = val; break; case 0xb6e8: - case 0xf6e8: dev->accel.bkgd_mix = val & 0xff; break; case 0xbae8: - case 0xfae8: dev->accel.frgd_mix = val & 0xff; break; case 0xbee8: - case 0xfee8: if (len == 2) { dev->accel.multifunc_cntl = val; dev->accel.multifunc[dev->accel.multifunc_cntl >> 12] = dev->accel.multifunc_cntl & 0xfff; @@ -765,10 +755,12 @@ ibm8514_accel_out(uint16_t port, uint32_t val, svga_t *svga, int len) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - if (dev->accel.cmd_back) { - dev->fifo_idx++; - if (dev->fifo_idx > 8) - dev->fifo_idx = 8; + if (port & 0x8000) { + if (dev->accel.cmd_back) { + dev->fifo_idx++; + if (dev->fifo_idx > 8) + dev->fifo_idx = 8; + } } ibm8514_accel_out_fifo(svga, port, val, len); @@ -799,13 +791,11 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) switch (port) { case 0x82e8: - case 0xc2e8: if (len == 2) temp = dev->accel.cur_y; break; case 0x86e8: - case 0xc6e8: if (len == 2) temp = dev->accel.cur_x; break; @@ -821,7 +811,6 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) break; case 0x9ae8: - case 0xdae8: if (len == 2) { if (dev->fifo_idx <= 8) { for (int i = 1; i <= dev->fifo_idx; i++) @@ -835,9 +824,6 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) if (dev->force_busy) temp |= 0x0200; /*Hardware busy*/ - if (dev->accel.cmd_back) - dev->force_busy = 0; - if (dev->data_available) { temp |= 0x0100; /*Read Data available*/ switch (dev->accel.cmd >> 13) { @@ -857,7 +843,6 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) } break; case 0x9ae9: - case 0xdae9: if (len == 1) { dev->fifo_idx = 0; @@ -974,7 +959,7 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) temp |= INT_GE_BSY; } - if (dev->accel.cmd_back) { + if (!dev->fifo_idx) { dev->force_busy = 0; dev->force_busy2 = 0; dev->data_available = 0; @@ -1033,6 +1018,8 @@ ibm8514_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t dev->accel.ssv_len_back = dev->accel.ssv_len; if (ibm8514_cpu_src(svga)) { + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 0; dev->data_available2 = 0; return; /*Wait for data from CPU*/ @@ -1079,11 +1066,6 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat rd_mask_polygon &= 0xff; } - if (!dev->accel.cmd_back) { - dev->force_busy = 1; - dev->force_busy2 = 1; - } - frgd_mix = (dev->accel.frgd_mix >> 5) & 3; bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; @@ -1251,8 +1233,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat cpu_dat >>= 8; if (!dev->accel.ssv_len) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1348,8 +1334,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat cpu_dat >>= 8; if (!dev->accel.ssv_len) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1413,10 +1403,14 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.output = 1; } } + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 0; dev->data_available2 = 0; return; /*Wait for data from CPU*/ } else if (ibm8514_cpu_dest(svga)) { + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -1524,8 +1518,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } if (!dev->accel.sy) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; if (!cpu_input) { dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; @@ -1645,8 +1643,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat cpu_dat >>= 8; if (!dev->accel.sy) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1749,8 +1751,12 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat cpu_dat >>= 8; if (!dev->accel.sy) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; if (!cpu_input) { dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; @@ -1855,6 +1861,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } } } + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 0; dev->data_available2 = 0; return; /*Wait for data from CPU*/ @@ -1872,6 +1880,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } } ibm8514_log("INPUT=%d.\n", dev->accel.input); + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 1; dev->data_available2 = 1; return; /*Wait for data from CPU*/ @@ -2031,8 +2041,10 @@ skip_vector_rect_write: dev->accel.x_count = 0; if (dev->accel.sy < 0) { - dev->accel.cmd_back = 1; + dev->force_busy = 0; + dev->force_busy2 = 0; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; } return; } @@ -2043,6 +2055,7 @@ skip_vector_rect_write: ibm8514_log("Vectored Rectangle with normal processing (TODO).\n"); } else { /*Normal Rectangle*/ if (cpu_input) { + ibm8514_log("Normal Pixel Rectangle Fill Transfer SY=%d.\n", dev->accel.sy); while (count-- && (dev->accel.sy >= 0)) { if ((dev->accel.cx >= clip_l) && (dev->accel.cx <= clip_r) && @@ -2192,9 +2205,11 @@ skip_nibble_rect_write: dev->accel.x_count = 0; if (dev->accel.sy < 0) { - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; } + dev->force_busy = 0; + dev->force_busy2 = 0; return; } } @@ -2280,8 +2295,8 @@ skip_nibble_rect_write: dev->accel.sy--; if (dev->accel.sy < 0) { - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; } return; } @@ -2366,8 +2381,8 @@ skip_nibble_rect_write: dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; } - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -2478,10 +2493,10 @@ skip_nibble_rect_write: if (dev->accel.sy < 0) { ibm8514_log(".\n"); - dev->accel.cmd_back = 1; dev->fifo_idx = 0; dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; + dev->accel.cmd_back = 1; return; } } @@ -2568,8 +2583,8 @@ skip_nibble_rect_write: dev->accel.cur_x = dev->accel.cx; dev->accel.cur_y = dev->accel.cy; } - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -2599,10 +2614,14 @@ skip_nibble_rect_write: ibm8514_log("Polygon Boundary activated=%04x, len=%d, cur(%d,%d), frgdmix=%02x, err=%d, clipping: l=%d, r=%d, t=%d, b=%d, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.sy, dev->accel.cx, dev->accel.cy, dev->accel.frgd_mix & 0x1f, dev->accel.err_term, clip_l, clip_r, clip_t, clip_b, dev->accel.multifunc[0x0a]); if (ibm8514_cpu_src(svga)) { + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 0; dev->data_available2 = 0; return; /*Wait for data from CPU*/ } else if (ibm8514_cpu_dest(svga)) { + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -2671,8 +2690,12 @@ skip_nibble_rect_write: cpu_dat >>= 8; if (!dev->accel.sy) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -2776,8 +2799,12 @@ skip_nibble_rect_write: cpu_dat >>= 8; if (!dev->accel.sy) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -2869,10 +2896,14 @@ skip_nibble_rect_write: } } } + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 0; dev->data_available2 = 0; return; /*Wait for data from CPU*/ } else if (ibm8514_cpu_dest(svga)) { + dev->force_busy = 1; + dev->force_busy2 = 1; dev->data_available = 1; dev->data_available2 = 1; return; /*Wait for data from CPU*/ @@ -3036,6 +3067,8 @@ skip_nibble_bitblt_write: if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; + dev->force_busy = 0; + dev->force_busy2 = 0; dev->fifo_idx = 0; } return; @@ -3234,8 +3267,8 @@ skip_nibble_bitblt_write: if (dev->accel.sy < 0) { dev->accel.destx = dev->accel.dx; dev->accel.desty = dev->accel.dy; - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -3254,9 +3287,29 @@ skip_nibble_bitblt_write: (dx <= (((uint64_t)clip_r) * 3)) && (dev->accel.dy >= (clip_t << 1)) && (dev->accel.dy <= (clip_b << 1))) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = 0; + break; + case 3: + READ(dev->accel.src + cx, src_dat); + break; + + default: + break; + } + READ(dev->accel.src + cx, src_dat); READ(dev->accel.dest + dx, dest_dat); - dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); WRITE(dev->accel.dest + dx, dest_dat); } @@ -3265,8 +3318,8 @@ skip_nibble_bitblt_write: dev->accel.sx--; if (dev->accel.sx < 0) { - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -3321,15 +3374,8 @@ skip_nibble_bitblt_write: old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - - if (dev->accel.cmd & 0x04) { - if (dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); - } - } else { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); - ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); - } + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); } } @@ -3380,8 +3426,8 @@ skip_nibble_bitblt_write: if (dev->accel.sy < 0) { dev->accel.destx = dev->accel.dx; dev->accel.desty = dev->accel.dy; - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -4020,6 +4066,7 @@ ibm8514_init(const device_t *info) default: dev->extensions = 0; ibm8514_io_set(svga); + dev->accel.cmd_back = 1; if (dev->type & DEVICE_MCA) { dev->pos_regs[0] = 0x7f; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 474ae5660..9f92ebde1 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -69,6 +69,7 @@ static uint8_t ati8514_accel_inb(uint16_t port, void *priv); static uint16_t ati8514_accel_inw(uint16_t port, void *priv); static uint32_t ati8514_accel_inl(uint16_t port, void *priv); +static void mach_set_resolution(mach_t *mach, svga_t *svga); static void mach32_updatemapping(mach_t *mach, svga_t *svga); static __inline void mach32_writew_linear(uint32_t addr, uint16_t val, mach_t *mach); static __inline void mach32_write_common(uint32_t addr, uint8_t val, int linear, mach_t *mach, svga_t *svga); @@ -326,12 +327,6 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 bkgd_sel = (mach->accel.dp_config >> 7) & 3; mono_src = (mach->accel.dp_config >> 5) & 3; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { - mach->force_busy = 1; - dev->force_busy = 1; - dev->force_busy2 = 1; - } - if (cpu_input) { if (dev->bpp) { if ((mach->accel.dp_config & 0x200) && (count == 2)) @@ -339,12 +334,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } - if ((dev->accel_bpp == 8) || (dev->accel_bpp == 15) || (dev->accel_bpp == 16) || (dev->accel_bpp == 24)) - mach_log("RdMask=%04x, DPCONFIG=%04x, Clipping: l=%d, r=%d, t=%d, b=%d, LineDrawOpt=%04x, BPP=%d, CMDType = %d, offs=%08x, cnt = %d, input = %d, mono_src = %d, frgdsel = %d, d(%d,%d), dstxend = %d, pitch = %d, extcrt = %d, rw = %x, monopattern = %x.\n", - dev->accel.rd_mask, mach->accel.dp_config, clip_l, clip_r, clip_t, clip_b, mach->accel.linedraw_opt, dev->accel_bpp, cmd_type, mach->accel.ge_offset, count, cpu_input, mono_src, frgd_sel, dev->accel.cur_x, dev->accel.cur_y, - mach->accel.dest_x_end, dev->ext_pitch, dev->ext_crt_pitch, mach->accel.dp_config & 1, mach->accel.mono_pattern_enable); - - mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config); + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y); switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -376,12 +366,18 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.linedraw_opt, mach->accel.dp_config, mach->accel.max_waitstates & 0x100); - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 0; dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -550,12 +546,22 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if ((mono_src == 1) && !count) { - dev->accel.cmd_back = 1; + if (cpu_input) { + mach->force_busy = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) { - dev->accel.cmd_back = 1; + if (cpu_input) { + mach->force_busy = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -777,12 +783,22 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if ((mono_src == 1) && !count) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } else if ((mono_src != 1) && (dev->accel.sx >= mach->accel.width)) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -976,12 +992,18 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 0; dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -1000,16 +1022,26 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dy_end == mach->accel.dy_start) { mach_log("No DEST.\n"); - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } if ((mono_src == 3) || (bkgd_sel == 3) || (frgd_sel == 3)) { if (mach->accel.sx_end == mach->accel.sx_start) { + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } mach_log("No SRC.\n"); - dev->accel.cmd_back = 1; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -1020,8 +1052,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mono_src, frgd_sel, bkgd_sel, dev->pitch); if (dev->accel.sy == mach->accel.height) { mach_log("No Blit on DPCONFIG=3251.\n"); - dev->accel.cmd_back = 1; + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; dev->fifo_idx = 0; + dev->accel.cmd_back = 1; return; } } @@ -1238,8 +1273,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if (dev->accel.sy >= mach->accel.height) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; if ((mono_src == 2) || (mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) return; if ((mono_src == 1) && (frgd_sel == 5) && (dev->accel_bpp == 24)) @@ -1279,14 +1319,20 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.cur_x, dev->accel.cur_y, dev->accel.dx, dev->accel.dy, mach->accel.cx_end_line, mach->accel.cy_end_line, mach->accel.bleft, mach->accel.bright, mach->accel.btop, mach->accel.bbottom); - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { mach_log("Write PIXTRANS.\n"); + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 0; dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { mach_log("Read PIXTRANS.\n"); + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -1398,8 +1444,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); if (!count) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1569,8 +1620,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); if (dev->accel.sx >= mach->accel.width) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1694,8 +1750,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); if (!count) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1853,8 +1914,13 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); if (dev->accel.sx >= mach->accel.width) { - dev->accel.cmd_back = 1; + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + } dev->fifo_idx = 0; + dev->accel.cmd_back = 1; break; } @@ -1986,14 +2052,38 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); - mach_log("ScanToX: Parameters=%04x: DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, srcwidth=%d, height=%d, clipl=%d, clipr=%d, clipt=%d, clipb=%d, frmix=%02x.\n", mach->accel.dp_config, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.src_width, dev->accel.sy, clip_l, clip_r, clip_t, clip_b, dev->accel.frgd_mix & 0x1f); + if ((dev->accel_bpp >= 24) && (frgd_sel == 5)) { + if (mach->accel.patt_len == 0x17) + mach->accel.color_pattern_idx = 0; - if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) { + dev->accel.x1 = dev->accel.dx + mach->accel.width; + if (dev->accel.x1 == dev->pitch) + dev->accel.x2 = mach->accel.width & 1; + else if ((dev->accel.x1 == mach->accel.width) && (dev->accel.dy & 1) && !dev->accel.y1 && dev->accel.x2) { + if (mach->accel.patt_len == 0x17) + mach->accel.color_pattern_idx = 3; + + dev->accel.x3 = 1; + } else + dev->accel.x3 = 0; + } + dev->accel.y1 = 0; + + mach_log("ScanToX: Parameters=%04x: xbit=%d, ybit=%d, widthbit=%d, DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, srcwidth=%d, height=%d, frmix=%02x.\n", + mach->accel.dp_config, dev->accel.dx & 1, dev->accel.dy & 1, mach->accel.width & 1, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.src_width, dev->accel.sy, dev->accel.frgd_mix & 0x1f); + + if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 0; dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + dev->force_busy = 1; + dev->force_busy2 = 1; + mach->force_busy = 1; dev->data_available = 1; dev->data_available2 = 1; return; @@ -2132,10 +2222,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.sx++; if (mach->accel.sx >= mach->accel.src_width) { mach->accel.sx = 0; - if (mach->accel.src_stepx == -1) { + if (mach->accel.src_stepx == -1) dev->accel.cx += mach->accel.src_width; - } else + else dev->accel.cx -= mach->accel.src_width; + dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); if (dev->bpp) dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); @@ -2143,13 +2234,24 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); } + mach_log("ColorIdx=%d, data=%02x, DestX=%d, DestY=%d.\n", mach->accel.color_pattern_idx, mach->accel.color_pattern[mach->accel.color_pattern_idx], dev->accel.dx, dev->accel.dy & 1); if (dev->bpp) mach->accel.color_pattern_idx += 2; else mach->accel.color_pattern_idx++; - if (mach->accel.color_pattern_idx > mach->accel.patt_len) - mach->accel.color_pattern_idx = 0; + if ((dev->accel_bpp >= 24) && (frgd_sel == 5) && (mach->accel.patt_len == 0x17)) { + if (dev->accel.x3) { + if (mach->accel.color_pattern_idx == 9) + mach->accel.color_pattern_idx = 3; + } else { + if (mach->accel.color_pattern_idx == 6) + mach->accel.color_pattern_idx = 0; + } + } else { + if (mach->accel.color_pattern_idx > mach->accel.patt_len) + mach->accel.color_pattern_idx = 0; + } dev->accel.dx += mach->accel.stepx; dev->accel.sx++; @@ -2167,11 +2269,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (dev->accel.sy >= 0) dev->accel.sy--; - dev->accel.cmd_back = 1; dev->fifo_idx = 0; dev->force_busy = 0; dev->force_busy2 = 0; mach->force_busy = 0; + dev->accel.cmd_back = 1; return; } } @@ -2368,7 +2470,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) mach_log("Extended 8514/A mode.\n"); dev->vendor_mode = 1; dev->on |= 0x01; - svga_recalctimings(svga); + mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); } if (dev->on) @@ -2395,7 +2497,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) mach_log("VGA mode.\n"); dev->vendor_mode = 0; dev->on &= ~0x01; - svga_recalctimings(svga); + mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); } if (dev->on) @@ -2688,30 +2790,11 @@ mach_set_resolution(mach_t *mach, svga_t *svga) dev->v_syncstart >>= 1; mach_log("Shadow set ATI=%x, shadow set 8514/A=%x, resolution h=%d, v=%d, vtotal=%d, vsyncstart=%d.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart); - if ((mach->accel.clock_sel & 0x01) || dev->bpp || ((mach->accel.ext_ge_config & 0x30) == 0x30)) /*ATI and 15bpp+ mode*/ - svga_recalctimings(svga); - else { /*8514/A mode*/ - switch (mach->shadow_set & 0x03) { - case 0x00: /*Primary CRT Register set*/ - if (dev->on) { - if (mach->crt_resolution == 0x01) { - if (ATI_8514A_ULTRA) { - if (dev->accel.advfunc_cntl & 0x04) { - if (dev->hdisp == 640) { - dev->hdisp = 1024; - dev->vdisp = 768; - svga_recalctimings(svga); - } - } else { - if (dev->hdisp == 1024) { - dev->hdisp = 640; - dev->vdisp = 480; - svga_recalctimings(svga); - } - } - } else - svga_recalctimings(svga); - } else if (mach->crt_resolution == 0x02) { + switch (mach->shadow_set & 0x03) { + case 0x00: /*Primary CRT Register set*/ + if (dev->on) { + if (mach->crt_resolution == 0x01) { + if (ATI_8514A_ULTRA) { if (dev->accel.advfunc_cntl & 0x04) { if (dev->hdisp == 640) { dev->hdisp = 1024; @@ -2727,33 +2810,48 @@ mach_set_resolution(mach_t *mach, svga_t *svga) } } else svga_recalctimings(svga); - } - break; - case 0x01: /*Shadow 640x480 CRT register set*/ - if (dev->on) { - if (!(dev->accel.advfunc_cntl & 0x04)) { - if (dev->hdisp == 1024) { - dev->hdisp = 640; - dev->vdisp = 480; - } - } - svga_recalctimings(svga); - } - break; - case 0x02: /*Shadow 1024x768 CRT register set*/ - if (dev->on) { + } else if (mach->crt_resolution == 0x02) { if (dev->accel.advfunc_cntl & 0x04) { if (dev->hdisp == 640) { dev->hdisp = 1024; dev->vdisp = 768; + svga_recalctimings(svga); + } + } else { + if (dev->hdisp == 1024) { + dev->hdisp = 640; + dev->vdisp = 480; + svga_recalctimings(svga); } } + } else svga_recalctimings(svga); + } + break; + case 0x01: /*Shadow 640x480 CRT register set*/ + if (dev->on) { + if (!(dev->accel.advfunc_cntl & 0x04)) { + if (dev->hdisp == 1024) { + dev->hdisp = 640; + dev->vdisp = 480; + } } - break; - default: - break; - } + svga_recalctimings(svga); + } + break; + case 0x02: /*Shadow 1024x768 CRT register set*/ + if (dev->on) { + if (dev->accel.advfunc_cntl & 0x04) { + if (dev->hdisp == 640) { + dev->hdisp = 1024; + dev->vdisp = 768; + } + } + svga_recalctimings(svga); + } + break; + default: + break; } } @@ -2855,7 +2953,7 @@ mach_recalctimings(svga_t *svga) svga->ati_4color = 0; } - mach_log("ON?=%d, override=%d, gelo=%04x, gehi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, svga->hdisp); + mach_log("ON=%d, override=%d, gelo=%04x, gehi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, svga->hdisp); if (dev->on) { dev->ma_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ dev->pitch = dev->ext_pitch; @@ -3015,6 +3113,15 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u int bkgd_sel; int mono_src; + if (port & 0x8000) { + if ((port & 0x06) != 0x06) { + if ((port != 0xe2e8) && (port != 0xe2e9) && (port != 0xe6e8) && (port != 0xe6e9)) { + if (port & 0x4000) + port &= ~0x4000; + } + } + } + mach_log("[%04X:%08X]: Port FIFO OUT=%04x, val=%04x, len=%d.\n", CS, cpu_state.pc, port, val, len); switch (port) { @@ -3240,12 +3347,16 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x4ae8: dev->accel.advfunc_cntl = val; - dev->on = dev->accel.advfunc_cntl & 0x01; + dev->on = val & 0x01; dev->vendor_mode = 0; - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d.\n", - CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp); + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d, extmode=%02x.\n", + CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, mach->regs[0xb0] & 0x20); if (ATI_MACH32) { + if ((mach->regs[0xb0] & 0x20) || (dev->accel_bpp >= 15)) { /*Account for the extended ATI 8514/A mode here too*/ + dev->on |= 0x01; + dev->vendor_mode = 1; + } mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); } else { @@ -3257,14 +3368,10 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x82e8: case 0x86e8: - case 0xc2e8: - case 0xc6e8: - case 0xf6ee: ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x8ae8: - case 0xcae8: ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { mach_log("SRCY=%d.\n", val & 0x07ff); @@ -3273,7 +3380,6 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x8ee8: - case 0xcee8: ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { mach_log("SRCX=%d.\n", val & 0x07ff); @@ -3282,64 +3388,55 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x92e8: - case 0xd2e8: ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x96e8: - case 0xd6e8: ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) mach->accel.test = val & 0x1fff; break; case 0x9ae8: - case 0xdae8: mach->accel.cmd_type = -1; ibm8514_accel_out_fifo(svga, port, val, len); break; case 0x9ee8: - case 0xdee8: ibm8514_accel_out_fifo(svga, port, val, len); break; case 0xa2e8: case 0xe2e8: if (port == 0xe2e8) { + mach_log("%04X: Background Color=%04x.\n", port, val); if (len == 2) { - if (dev->accel.cmd_back) { - if (mach->accel.cmd_type == 5) { - if (dev->accel.sy >= 0) { - if (mach_pixel_read(mach)) - break; - - mach_accel_out_pixtrans(svga, mach, dev, val); - } else - dev->accel.bkgd_color = val; - } else - dev->accel.bkgd_color = val; - - mach_log("%04X: CMDBack BKGDCOLOR, sy=%d, height=%d, val=%04x.\n", port, dev->accel.sy, mach->accel.height, val); - } else { + if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach_log("ATI transfer.\n"); mach_accel_out_pixtrans(svga, mach, dev, val); } else { if (ibm8514_cpu_dest(svga)) break; + mach_log("IBM transfer.\n"); ibm8514_accel_out_pixtrans(svga, port, val, len); } + } else { + dev->accel.bkgd_color = val; + mach_log("%04X: CMDBack BKGDCOLOR, sy=%d, height=%d, cmdtype=%d, val=%04x.\n", port, dev->accel.sy, mach->accel.height, mach->accel.cmd_type, val); } } else { - if (mach->accel.cmd_type >= 0) { - if (mach_pixel_read(mach)) - break; + if (dev->accel.cmd & 0x100) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; - mach->accel.pix_trans[1] = val; + mach->accel.pix_trans[1] = val; + } } } } else { @@ -3353,42 +3450,39 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xa6e8: case 0xe6e8: if (port == 0xe6e8) { + mach_log("%04X: Foreground Color=%04x.\n", port, val); if (len == 2) { - if (dev->accel.cmd_back) { - if (mach->accel.cmd_type == 5) { - if (dev->accel.sy >= 0) { - if (mach_pixel_read(mach)) - break; - - mach_accel_out_pixtrans(svga, mach, dev, val); - } else - dev->accel.frgd_color = val; - } else - dev->accel.frgd_color = val; - } else { + if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; + mach_log("ATI transfer.\n"); mach_accel_out_pixtrans(svga, mach, dev, val); } else { if (ibm8514_cpu_dest(svga)) break; + mach_log("IBM transfer.\n"); ibm8514_accel_out_pixtrans(svga, port, val, len); } - } + } else + dev->accel.frgd_color = val; } else { - if (mach->accel.cmd_type >= 0) { - if (mach_pixel_read(mach)) - break; + if (!dev->accel.cmd_back) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; - mach->accel.pix_trans[1] = val; + mach->accel.pix_trans[1] = val; + } } } } else { if (len == 2) dev->accel.frgd_color = val; + + mach_log("%04X: Foreground Color=%04x.\n", port, val); } break; @@ -3396,40 +3490,42 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xe6e9: mach_log("Write PORT=%04x, 8514/A=%x, val=%04x, len=%d.\n", port, dev->accel.cmd_back, val, len); if (len == 1) { - if (mach->accel.cmd_type >= 0) { - if (mach_pixel_read(mach)) - break; + if (!dev->accel.cmd_back) { + if (mach->accel.cmd_type >= 0) { + if (mach_pixel_read(mach)) + break; - mach->accel.pix_trans[0] = val; - frgd_sel = (mach->accel.dp_config >> 13) & 7; - bkgd_sel = (mach->accel.dp_config >> 7) & 3; - mono_src = (mach->accel.dp_config >> 5) & 3; + mach->accel.pix_trans[0] = val; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; + mono_src = (mach->accel.dp_config >> 5) & 3; - switch (mach->accel.dp_config & 0x200) { - case 0x000: /*8-bit size*/ - if (mono_src == 2) { - if ((frgd_sel != 2) && (bkgd_sel != 2)) { - mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, svga, mach, dev); + switch (mach->accel.dp_config & 0x200) { + case 0x000: /*8-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + mach_accel_start(mach->accel.cmd_type, 1, 8, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, svga, mach, dev); + } else + mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); } else mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); - } else - mach_accel_start(mach->accel.cmd_type, 1, 1, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); - break; - case 0x200: /*16-bit size*/ - if (mono_src == 2) { - if ((frgd_sel != 2) && (bkgd_sel != 2)) { - if (mach->accel.dp_config & 0x1000) - mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, svga, mach, dev); - else - mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, svga, mach, dev); + break; + case 0x200: /*16-bit size*/ + if (mono_src == 2) { + if ((frgd_sel != 2) && (bkgd_sel != 2)) { + if (mach->accel.dp_config & 0x1000) + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[1] | (mach->accel.pix_trans[0] << 8), 0, svga, mach, dev); + else + mach_accel_start(mach->accel.cmd_type, 1, 16, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), 0, svga, mach, dev); + } else + mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); } else mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); - } else - mach_accel_start(mach->accel.cmd_type, 1, 2, -1, mach->accel.pix_trans[0] | (mach->accel.pix_trans[1] << 8), svga, mach, dev); - break; + break; - default: - break; + default: + break; + } } } } @@ -3441,16 +3537,10 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xb2e8: case 0xb6e8: case 0xbae8: - case 0xeae8: - case 0xeee8: - case 0xf2e8: - case 0xf6e8: - case 0xfae8: ibm8514_accel_out_fifo(svga, port, val, len); break; case 0xbee8: - case 0xfee8: ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { if ((dev->accel.multifunc_cntl >> 12) == 5) { @@ -3728,10 +3818,10 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } if (ATI_MACH32) { + mach_log("Load both SRC/DST GE Offset/Pitch=%03x, offset=%08x.\n", mach->shadow_set & 0x300, dev->accel.ge_offset); if ((mach->shadow_set & 0x300) == 0x000) { - mach_log("Load both SRC/DST GE Offset/Pitch.\n"); - mach->accel.ge_offset_lo = 0; - mach->accel.ge_offset_hi = 0; + mach->accel.ge_offset_lo = 0x0000; + mach->accel.ge_offset_hi = 0x0000; } } break; @@ -3856,10 +3946,14 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x8eee: if (len == 2) { + frgd_sel = (mach->accel.dp_config >> 13) & 7; + if (mach->accel.patt_data_idx_reg < 0x10) { mach->accel.color_pattern[mach->accel.patt_data_idx] = val & 0xff; mach->accel.color_pattern[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); + if ((dev->accel_bpp >= 24) && (frgd_sel == 5) && (mach->accel.patt_len == 0x17)) + dev->accel.y1 = 1; } else { mach->accel.mono_pattern_normal[mach->accel.patt_data_idx - 0x10] = val & 0xff; mach->accel.mono_pattern_normal[(mach->accel.patt_data_idx + 1) - 0x10] = (val >> 8) & 0xff; @@ -4103,6 +4197,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if ((mono_src == 2) || (bkgd_sel == 2) || (frgd_sel == 2) || mach_pixel_read(mach)) dev->accel.cmd_back = 0; + if ((mach->accel.cmd_type == 3) && !dev->accel.cmd_back && (mach->accel.dp_config == 0x0000)) /*Avoid a hang with a dummy command.*/ + dev->accel.cmd_back = 1; + mach_log("LineDraw type=%x, dpconfig=%04x.\n", mach->accel.cmd_type, mach->accel.dp_config); mach_accel_start(mach->accel.cmd_type, 0, -1, -1, 0, svga, mach, dev); mach->accel.line_idx = (mach->accel.line_idx == 5) ? 4 : 2; @@ -4165,9 +4262,6 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in if (dev->force_busy) temp |= 0x0200; /*Hardware busy*/ - if (dev->accel.cmd_back) - dev->force_busy = 0; - if (dev->data_available) { temp |= 0x0100; /*Read Data available*/ if (mach->accel.cmd_type >= 0) { @@ -4623,7 +4717,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) } } - if (dev->accel.cmd_back) { + if (!dev->fifo_idx) { dev->force_busy = 0; dev->force_busy2 = 0; mach->force_busy = 0; @@ -4661,7 +4755,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) mach_log("FIFO Test IDX=%d, Data=%04x.\n", mach->fifo_test_idx, mach->fifo_test_data[mach->fifo_test_idx]); READ8(port, mach->fifo_test_data[mach->fifo_test_idx]); if (!mach->fifo_test_idx && ((mach->accel.dp_config == 0xaaaa) || (mach->accel.dp_config == 0x5555))) - mach->accel.dp_config = 0x2211; + mach->accel.dp_config = 0x2011; break; case 0x22ee: @@ -4761,7 +4855,6 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) if (mach->force_busy) temp |= 0x20; - mach->force_busy = 0; if (ati_eeprom_read(&mach->eeprom)) temp |= 0x40; @@ -6076,7 +6169,8 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) if (svga->attrregs[0x10] & 0x40) { dev->vendor_mode = 0; dev->on &= ~0x01; - svga_recalctimings(svga); + mach_log("No 8514/A mode on b8000.\n"); + mach_set_resolution(mach, svga); } } } @@ -6892,7 +6986,6 @@ mach8_init(const device_t *info) mach->ramdac_type = mach->pci_bus ? device_get_config_int("ramdac") : 1; dev->vram_amount = device_get_config_int("memory"); dev->vram_512k_8514 = dev->vram_amount == 512; - dev->accel.cmd_back = 1; if (ATI_MACH32) { if (mach->pci_bus) { @@ -7016,6 +7109,7 @@ mach8_init(const device_t *info) io_sethandler(0x02ea, 4, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); mach_io_set(mach); mach->accel.cmd_type = -2; + dev->accel.cmd_back = 1; if (ATI_MACH32) { svga->decode_mask = (4 << 20) - 1; @@ -7077,12 +7171,12 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) mach->accel.clock_sel = 0x1c; mach->shadow_set = 0x02; mach->crt_resolution = 0x02; + dev->accel.cmd_back = 1; io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); ati8514_io_set(svga); mach->accel.cmd_type = -2; mach->mca_bus = !!(dev->type & DEVICE_MCA); - dev->accel.cmd_back = 1; mach->config1 = 0x08 | 0x80; From 9c8c1a6f406aec432756ca19fdb4b8451bcd7260 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 2 Apr 2025 21:47:32 +0200 Subject: [PATCH 0662/1190] Trantor SCSI changes of the day (April 2nd, 2025) 1. The PAS SCSI controller driver mamv1.sys dislikes having bits 0-6 set when a transfer has completed, take account from this, fixes mamv1.sys incomplete CD transfers (bits 0-6 get re-enabled when the transfer is ongoing). 2. I now understand why the T128 doesn't have a block count register, it does the block count manually from the SCSI layer directly, this fixes Pseudo-DMA transfers when using, e.g.: CD transfers using a sector size of 2340 bytes. --- src/include/86box/scsi_device.h | 3 ++- src/include/86box/scsi_t128.h | 3 ++- src/scsi/scsi_t128.c | 29 +++++++++++------------------ src/sound/snd_pas16.c | 9 ++++++++- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 62da8b7dc..289201b04 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -467,9 +467,10 @@ typedef struct scsi_bus_t { int msgout_pos; int is_msgout; int state; - int dma_on_pio_enabled; uint32_t bus_phase; + uint32_t total_len; + uint32_t data_repeat; double period; double speed; diff --git a/src/include/86box/scsi_t128.h b/src/include/86box/scsi_t128.h index 65148a5d1..a3bc79335 100644 --- a/src/include/86box/scsi_t128.h +++ b/src/include/86box/scsi_t128.h @@ -30,7 +30,7 @@ typedef struct t128_t { uint8_t status; uint8_t buffer[512]; uint8_t ext_ram[0x80]; - uint8_t block_count; + uint32_t block_count; int block_loaded; int pos, host_pos; @@ -39,6 +39,7 @@ typedef struct t128_t { int bios_enabled; uint8_t pos_regs[8]; + int type; pc_timer_t timer; } t128_t; diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 3f273d1bb..94166054c 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -130,12 +130,12 @@ t128_read(uint32_t addr, void *priv) (t128->host_pos < MIN(512, dev->buffer_length))) { ret = t128->buffer[t128->host_pos++]; - t128_log("T128 Read transfer: pos=%i, addr=%x.\n", - t128->host_pos, addr & 0x1ff); + t128_log("T128 Read transfer: pos=%i, addr=%x, enabled timer=%d.\n", + t128->host_pos, addr & 0x1ff, timer_is_enabled(&t128->timer)); if (t128->host_pos == MIN(512, dev->buffer_length)) { - t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d.\n", - t128->status, scsi_bus->period, timer_is_enabled(&t128->timer)); + t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d, block=%d.\n", + t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), scsi_bus->data_pos); t128->status &= ~0x04; if (!t128->block_loaded) { @@ -192,10 +192,6 @@ t128_dma_send_ext(void *priv, void *ext_priv) t128_log("T128 DMA OUT, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); t128->host_pos = 0; - t128->block_count = dev->buffer_length >> 9; - - if (dev->buffer_length < 512) - t128->block_count = 1; t128->block_loaded = 1; t128->status |= 0x04; @@ -215,10 +211,6 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) t128_log("T128 DMA IN, len=%d.\n", dev->buffer_length); memset(t128->buffer, 0, MIN(512, dev->buffer_length)); t128->host_pos = MIN(512, dev->buffer_length); - t128->block_count = dev->buffer_length >> 9; - - if (dev->buffer_length < 512) - t128->block_count = 1; t128->block_loaded = 1; t128->status &= ~0x04; @@ -295,9 +287,9 @@ t128_callback(void *priv) t128->status &= ~0x02; t128->pos = 0; t128->host_pos = 0; - t128->block_count = (t128->block_count - 1) & 0xff; + scsi_bus->data_repeat = 0; t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); - if (!t128->block_count) { + if (scsi_bus->data_pos >= dev->buffer_length) { t128->block_loaded = 0; ncr->tcr |= TCR_LAST_BYTE_SENT; ncr->isr |= STATUS_END_OF_DMA; @@ -344,11 +336,11 @@ t128_callback(void *priv) t128->status &= ~0x02; t128->pos = 0; t128->host_pos = 0; - t128->block_count = (t128->block_count - 1) & 0xff; - t128_log("T128 Remaining blocks to be read=%d\n", t128->block_count); - if (!t128->block_count) { - t128->block_loaded = 0; + scsi_bus->data_repeat = 0; + t128_log("T128 blocks read=%d, total len=%d\n", scsi_bus->data_pos, dev->buffer_length); + if (scsi_bus->data_pos >= dev->buffer_length) { scsi_bus->bus_out |= BUS_REQ; + t128->block_loaded = 0; timer_on_auto(&t128->timer, 10.0); t128_log("IO End of read transfer\n"); } @@ -472,6 +464,7 @@ t128_init(const device_t *info) ncr->bus = scsi_get_bus(); scsi_bus = &ncr->scsibus; + t128->type = info->local; if (info->flags & DEVICE_MCA) { rom_init(&t128->bios_rom, T128_ROM, diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index 675582367..dd95eac4c 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -792,7 +792,14 @@ pas16_in(uint16_t port, void *priv) if ((scsi_bus->tx_mode == PIO_TX_BUS) && !(ret & 0x80)) ret |= 0x80; - pas16_log("5C01 read ret=%02x, status=%02x, txmode=%x.\n", ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode); + if (ret & 0x80) { + if (scsi_bus->data_repeat < MIN(511, scsi_bus->total_len)) + scsi_bus->data_repeat++; + } else { + if (scsi_bus->data_repeat == MIN(511, scsi_bus->total_len)) + ret = 0x00; + } + pas16_log("%04X:%08X: Port %04x read ret=%02x, status=%02x, txmode=%x, repeat=%d.\n", CS, cpu_state.pc, port + pas16->base, ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode, scsi_bus->data_repeat); } break; case 0x5c03: From 4bd374a7dfcceebac5249fb01409c7395762bb6d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 2 Apr 2025 16:55:57 -0300 Subject: [PATCH 0663/1190] Don't apply the Deschutes cacheability fix to Covington --- src/cpu/cpu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 61bd8bf36..ffe582604 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -2651,8 +2651,9 @@ cpu_ven_reset(void) msr.mtrr_cap = 0x00000508ULL; /* 4 GB cacheable space on Deschutes 651h and later (including the 1632h - Overdrive) according to the Pentium II Processor Specification Update. */ - if (cpu_s->cpuid_model >= 0x651) + Overdrive) according to the Pentium II Processor Specification Update. + Covington 651h (no L2 cache) reports the same 512 MB value as Klamath. */ + if (CPUID >= (!strncmp(cpu_f->internal_name, "celeron", 7) ? 0x660 : 0x651)) msr.bbl_cr_ctl3 |= 0x00300000; break; From cfc8e0dc4e6780bbdbbfb81ef6ac267730e21fb9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Apr 2025 06:17:27 +0200 Subject: [PATCH 0664/1190] Settings Storage Devices: No longer cut off the second SCSI controller. --- src/qt/qt_settingsstoragecontrollers.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index eebed79e2..002b9e1d3 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -195,12 +195,10 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) if (scsi_card_available(c)) { if (device_is_valid(scsi_card_getdevice(c), machineId)) { for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { - if ((c != 1) || ((i == 0) && m_has_scsi)) { - int row = Models::AddEntry(models[i], name, c); + int row = Models::AddEntry(models[i], name, c); - if (c == scsi_card_current[i]) - selectedRows[i] = row - removeRows_[i]; - } + if (c == scsi_card_current[i]) + selectedRows[i] = row - removeRows_[i]; } } } From df7acc618bccd33d504e8a5fa5d1a0e53e72ee0b Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Apr 2025 06:19:36 +0200 Subject: [PATCH 0665/1190] Remove the now unused variable m_has_scsi. --- src/qt/qt_settingsstoragecontrollers.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index 002b9e1d3..9bd1bda6f 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -176,7 +176,6 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) QAbstractItemModel *models[SCSI_CARD_MAX] = { 0 }; int removeRows_[SCSI_CARD_MAX] = { 0 }; int selectedRows[SCSI_CARD_MAX] = { 0 }; - int m_has_scsi = machine_has_flags(machineId, MACHINE_SCSI); for (uint8_t i = 0; i < SCSI_CARD_MAX; ++i) { cbox[i] = findChild(QString("comboBoxSCSI%1").arg(i + 1)); From c63d900a9383b74fbd8a5fa7209a0b2a6364a913 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 3 Apr 2025 06:35:53 +0200 Subject: [PATCH 0666/1190] CMS: Divide SAA samples by 2 so that the sum remains within the -32767 to 32768 range and avoids clipping. --- src/sound/snd_cms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index c6591b1fc..9491e3076 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -34,7 +34,7 @@ cms_get_buffer(int32_t *buffer, int len, void *priv) cms_update(cms); for (int c = 0; c < len * 2; c++) - buffer[c] += cms->buffer[c]; + buffer[c] += (cms->buffer[c] / 2); cms->pos = 0; } @@ -47,7 +47,7 @@ cms_get_buffer_2(int32_t *buffer, int len, void *priv) cms_update(cms); for (int c = 0; c < len * 2; c++) - buffer[c] += cms->buffer2[c]; + buffer[c] += (cms->buffer2[c] / 2); cms->pos2 = 0; } From fc06d3de89dfd58eb497f1e6b8d09cb0dbbfaa13 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 3 Apr 2025 15:16:58 +0900 Subject: [PATCH 0667/1190] PS55DA2: add char drawing func in BitBlt This build is still in work. * Added character drawing function to support for DOS/V Extension DSPXDA2 driver. * Implement CRTC regs: start address, end address, line compare to support line compare scrolling in DOS/V Extension. * Enable updating CRTC regs when output is disabled. --- src/video/vid_ps55da2.c | 424 +++++++++++++++++++++++++++------------- 1 file changed, 290 insertions(+), 134 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 1f00b7cc5..1875726b5 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -66,7 +66,7 @@ #define DA2_MASK_VRAM 0xfffff /* 0xFFFFF */ #define DA2_MASK_VRAMPLANE 0x1ffff /* 0x1FFFF */ #define DA2_PIXELCLOCK 29000000.0 /* 58 MHz interlaced */ -#define DA2_BLT_MEMSIZE 0x100 +#define DA2_BLT_MEMSIZE 0x1000 #define DA2_BLT_REGSIZE 0x40 #define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) #define DA2_DEBUG_BLTLOG_MAX (256 * 1024) @@ -112,8 +112,8 @@ EFD8h * Display Adapter/J [Atlas-SP2] [Japanese DOS and Display Adapter compatibility] - | | | K3.31 | J4.04 | J4.08 | OS2J1.3 | Win3.02 | DOSVExt | - | POS ID | Adapter Name | 5605JBK | 5605PAA | 5605PCA | 5605PDE | 5605PAW | 5605PXA | + | | | 5605JBK | 5605PAA | 5605PCA | 5605PDE | 5605PAW | 5605PXB | + | POS ID | Adapter Name | K3.31 | J4.05 | J4.08 | J1.33 | 3.02 | 2.0 | |------------|-----------------------------|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:| | EFFFh | Display Adapter | X | | | | | | | FFEDh | ? [Atlas EVT] | X | | | | | | @@ -124,7 +124,14 @@ | ECECh | Display Adapter IV,B1 | | X | X | X | X | X | | 9000-901Fh | Display Adapter A1,A2 | | X | X | | X | X | | EFD8h | Display Adapter /J | | | X | X | X | X | -*/ + + - 5605JBK : Japanese DOS K3.3, K3.4 (for PS/55 model 55xx-S, T, V, Z) + - 5605PAA : DOS J4.0 + - 5605PCA : DOS J4.0 (with MKK) + - 5605PDE : OS/2 Extended Edition J1.3 + - 5605PAW : Japanese Microsoft Windows 3.0 (IBMJ OEM) + - 5605PXB : DOS/V Extension V2.0 + */ /* IO 3E0/3E1:0Ah Hardware Configuration Value L (imported from OS/2 DDK) */ #define OldLSI 0x20 /* 1 = DA-2, 0 = DA-3 */ // #define Mon_ID3 0x10 @@ -163,8 +170,10 @@ #define LF_INDEX 0x3e2 #define LF_DATA 0x3e3 #define LF_MMIO_SEL 0x08 /* added */ +#define LF_MMIO_09 0x09 /* added */ #define LF_MMIO_ADDR 0x0A /* added */ #define LF_MMIO_MODE 0x0B /* added */ +#define LF_PD_RESET 0x18 /* added */ #define LC_INDEX 0x3E4 #define LC_DATA 0x3E5 #define LC_HORIZONTAL_TOTAL 0x00 @@ -251,12 +260,12 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -// #define ENABLE_DA2_LOG 1 +#define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG // # define ENABLE_DA2_DEBUGIO 1 -// # define ENABLE_DA2_DEBUGBLT 1 +# define ENABLE_DA2_DEBUGBLT 1 // # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 // # define ENABLE_DA2_DEBUGMONWAIT 1 @@ -328,7 +337,7 @@ typedef struct da2_t { int vtotal, dispend, vsyncstart, split, vblankstart; int hdisp, htotal, hdisp_time, rowoffset; - int lowres, interlace; + int lowres; int rowcount; double clock; uint32_t ma_latch, ca_adj; @@ -343,7 +352,7 @@ typedef struct da2_t { uint32_t ma, maback, ca; int vc; int sc; - int linepos, vslines, linecountff, oddeven; + int linepos, vslines, linecountff; int con, cursoron, blink, blinkconf; int scrollcache; int char_width; @@ -457,6 +466,53 @@ DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) da2->vram[addr] = val; return; } +/* get font data for bitblt operation */ +static uint32_t +getFontIBMJ(int32_t code, int line, int x, void *p) +{ + da2_t *da2 = (da2_t *) p; + uint32_t font = 0; + int fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ + if (code < 0x100) { /* SBCS 13x29 */ + code *= 0x40; + code += DA2_GAIJIRAM_SBCS + (line * 2) + x; + font = da2->mmio.ram[code]; + font <<= 8; + font |= da2->mmio.ram[code + 1]; + font <<= 16; + return font; + } + if ((code >= 0x8000) && (code <= 0x8183)) + code -= 0x6000; /* shift for IBM extended characters */ + if ((code < (DA2_FONTROM_SIZE / 72)) && (fline >= 0) && (fline < 24)) { /* DBCS 24x24 */ + code = (code * 72) + (fline * 3) + x; + // font = da2->mmio.font[code]; /* 0000 0000 0000 0000 0000 0000 1111 1111 */ + // font <<= 8; /* 0000 0000 0000 0000 1111 1111 0000 0000 */ + // font |= da2->mmio.font[code + 1] & 0xf0; /* 0000 0000 0000 0000 1111 1111 2222 0000 */ + // font <<= 3; /* 0000 0000 0000 0111 1111 1222 2000 0000 */ + // font |= da2->mmio.font[code + 1] & 0x0f; /* 0000 0000 0000 0111 1111 1222 2000 2222 */ + // font <<= 8; /* 0000 0111 1111 1222 2000 2222 0000 0000 */ + // font |= da2->mmio.font[code + 2]; /* 0000 0111 1111 1222 2000 2222 3333 3333 */ + // font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ + } else if ((code >= 0xb000) && (code <= 0xb75f)) { /* DBCS 26x29 */ + /* convert code->address in gaiji memory */ + code -= 0xb000; + code = (code * 0x80) + (line * 4) + x; + font = da2->mmio.ram[code]; + font <<= 8; + font |= da2->mmio.ram[code + 1]; + font <<= 8; + font |= da2->mmio.ram[code + 2]; + font <<= 8; + font |= da2->mmio.ram[code + 3]; + // font <<= 16; + } else if (code > (DA2_FONTROM_SIZE / 72)) + font = 0xffffffffu; + else + font = 0; + return font; +} + /* write pixel data with rop (Note: bitmask must be in big endian) */ static void DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) @@ -482,6 +538,11 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s for (int i = 0; i < 8; i++) { if (da2->bitblt.bitshift_destr > 0) srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; +// #ifdef ENABLE_DA2_DEBUGBLT +// if (i == 0) { +// pclog("writeplane: src %08X mask %08X dest %08X\n", srcpx->p8[i], mask32.d, writepx[i]); +// } +// #endif if (da2->bitblt.raster_op & 0x2010) /* NOT Src or NOT Pattern */ srcpx->p8[i] = ~srcpx->p8[i] & mask32.d; if (da2->bitblt.raster_op & 0x20) /* Dest NOT */ @@ -560,24 +621,68 @@ DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } +/* Reverse the bit order of attribute code IBGR to IRGB(used in Mode 3 and Cursor Color) */ +static int8_t +IBGRtoIRGB(uint8_t attr) +{ + attr = ((attr & 0x01) << 6) | ((attr & 0x02) << 4) | ((attr & 0x04) << 2) | ((attr & 0x08) << 4); + return attr >>= 4; +} static void -DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) +DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, uint32_t destaddr, uint16_t maskl, uint16_t maskr, da2_t *da2) { pixel32 srcpx; - if (srcaddr >= DA2_FONTROM_SIZE) { - da2_log("DA2 Putchar Addr Error %x\n", srcaddr); - return; + // if (codeIBMJ >= DA2_FONTROM_SIZE / 72) { + // da2_log("DA2 Putchar Addr Error %x\n", srcaddr); + // return; + // } + uint8_t color = (~attr >> 8) & 0x0f; + // color = IBGRtoIRGB(color); + uint8_t bg = (~attr >> 12) & 0x0f; + // bg = 0x00; + // bg = IBGRtoIRGB(bg); + uint32_t font = getFontIBMJ(codeIBMJ, line, 0, da2); + uint32_t fontinv; + if (width == 1) { + fontinv = ~font; + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; + } + pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); + DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; + } + pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); + DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); + } else { + font = (font & 0xfff80000) | ((font & 0x0000ffff) << 3); + fontinv = ~font; + pclog("putchar: ft %08X shftr %X\n", font, da2->bitblt.bitshift_destr); + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; + } + // pclog("putchar: %08X mask %04X\n", srcpx.p8[3], maskl); + DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; + } + // pclog("putchar: %08X mask %04X\n", srcpx.p8[3], maskr); + DA2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font << 16 : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv << 16 : 0; + } + // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[3], maskl, maskr); + DA2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); } - for (int i = 0; i < 8; i++) - srcpx.p8[i] = ((uint32_t) da2->mmio.font[srcaddr] << 24) - | ((uint32_t) da2->mmio.font[srcaddr + 1] << 16) - | ((uint32_t) da2->mmio.font[srcaddr + 2] << 8) - | ((uint32_t) da2->mmio.font[srcaddr + 3] << 0); - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); } #ifdef ENABLE_DA2_DEBUGBLT -uint8_t +static uint8_t pixel1tohex(uint32_t addr, int index, da2_t *da2) { uint8_t pixeldata = 0; @@ -587,14 +692,14 @@ pixel1tohex(uint32_t addr, int index, da2_t *da2) } return pixeldata; } -void +static void print_pixelbyte(uint32_t addr, da2_t *da2) { for (int i = 0; i < 8; i++) { pclog("%X", pixel1tohex(addr, i, da2)); } } -void +static void print_bytetobin(uint8_t b) { for (int i = 0; i < 8; i++) { @@ -606,17 +711,17 @@ print_bytetobin(uint8_t b) } } /* Convert internal char code to Shift JIS code */ -inline int +static int isKanji1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } -inline int +static int isKanji2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } -uint16_t +static uint16_t IBMJtoSJIS(uint16_t knj) { if (knj < 0x100) @@ -710,6 +815,27 @@ da2_bitblt_load(da2_t *da2) // da2->gdcreg[da2->bitblt.payload[i + 1]] = value64; i += 7; break; + case 0xa1: + value64 = da2->bitblt.payload[i + 9]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 8]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 7]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 6]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[i + 2]; + da2_bltlog("[%02x] %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], + da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7], da2->bitblt.payload[i + 8], da2->bitblt.payload[i + 9]); + da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; + i += 9; + break; case 0x00: break; default: @@ -734,14 +860,15 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.debug_reg_ip = 0; da2->bitblt.debug_exesteps = 0; #endif - da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0x0b], CS, cpu_state.pc); - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x3] >> 4) & 0x0f); /* set bit shift */ + da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0xb], CS, cpu_state.pc); + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x03] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; da2->bitblt.destaddr = da2->bitblt.reg[0x29]; da2->bitblt.size_x = da2->bitblt.reg[0x33]; da2->bitblt.size_y = da2->bitblt.reg[0x35]; da2->bitblt.destpitch = da2->bitblt.reg[0x21]; da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + /* 80h = 128d = 10000000b, 90h = 144d = 10010000b, B0h = 176d = 10110000 */ if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ { da2->bitblt.destaddr -= 2; @@ -757,7 +884,7 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.exec = DA2_BLT_CDONE; /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ - if (da2->bitblt.reg[0x10] == 0xbc04) { + if (!(da2->bitblt.reg[0xb] & 0x08)) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; /* Todo: addressing */ // if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ @@ -767,29 +894,22 @@ da2_bitblt_load(da2_t *da2) // da2->bitblt.destpitch += 2; // da2->bitblt.srcpitch += 2; // } - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + 2; + da2->bitblt.fcolor = da2->bitblt.reg[0x1]; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; da2->bitblt.destaddr += 2; da2->bitblt.srcpitch = 0; - da2->bitblt.bitshift_destr += 1; #ifdef ENABLE_DA2_DEBUGBLT - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); -#endif - } - /* Put SBCS char used by OS/2 */ - else if (da2->bitblt.reg[0x10] == 0x0004 || da2->bitblt.reg[0x10] == 0x0E04) { - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 64 + 2 + DA2_FONTROM_BASESBCS; - da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; - da2->bitblt.bitshift_destr += 1; -#ifdef ENABLE_DA2_DEBUGBLT - uint32_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint32_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + uint8_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint8_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + if (da2->bitblt.reg[0x12] < 0x100) { + sjis_h = 0x20; + sjis_l = da2->bitblt.reg[0x12]; + } else { + if (!(isKanji1(sjis_h))) + sjis_h = 0x3f; + if (!(isKanji2(sjis_l))) + sjis_l = 0x3f; + } da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), @@ -1040,49 +1160,35 @@ da2_bitblt_exec(void *p) da2->bitblt.srcaddr -= 2; break; case DA2_BLT_CPUTCHAR: /* used in OS/2 J1.3 wo ROM patch. TODO: still not work */ - // da2->bitblt.y += 2; - da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x * 2 + da2->bitblt.y * 130 + 0 + 260; - // pclog("scr %x dest %x :", da2->bitblt.srcaddr, da2->bitblt.destaddr); + da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.y * 130; // da2->bitblt.srcaddr += 2; - if (da2->bitblt.reg[0x12] < 0x100) - da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; - else - da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - // print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 2]); - // print_bytetobin(da2->mmio.font[da2->bitblt.srcaddr + 3]); - // pclog("\n"); - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - // if (1) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 3) { - da2->bitblt.exec = DA2_BLT_CDONE; - } - da2->bitblt.x = 0; + // if (da2->bitblt.reg[0x12] < 0x100) + // da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; + // else + // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + pclog("scr %x dest %x x %x y %x\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + if (da2->bitblt.y >= da2->bitblt.size_y) { + da2->bitblt.exec = DA2_BLT_CDONE; + } else { + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); + } da2->bitblt.y++; da2->bitblt.destaddr += 130; - // da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - // da2->bitblt.srcaddr += -1; - } else if (da2->bitblt.x == 0) { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - // da2->bitblt.x++; - } else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; - // da2->bitblt.x++; - } + // } // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; ////da2->bitblt.srcaddr += 2; // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; break; case DA2_BLT_CDONE: - if (!(da2->bitblt.reg[0x20] & 0x20)) { - /* initialize regs and set magic value for debug dump */ - for (int i = 0; i < DA2_BLT_REGSIZE; i++) { - if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) - da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; - } - } else /* without init regs */ + // if (!(da2->bitblt.reg[0x20] & 0x20)) { + // /* initialize regs and set magic value for debug dump */ + // for (int i = 0; i < DA2_BLT_REGSIZE; i++) { + // if (da2->bitblt.reg[i] != DA2_DEBUG_BLT_NEVERUSED) + // da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; + // } + // } else /* without init regs */ da2->bitblt.reg[0x20] = 0; /* need to stop execution */ if (da2->bitblt.indata) da2->bitblt.exec = DA2_BLT_CLOAD; @@ -1193,6 +1299,10 @@ da2_out(uint16_t addr, uint16_t val, void *p) da2->fctl[da2->fctladdr] = val; if (da2->fctladdr == 0 && oldval != val) { da2_iolog("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc); + } else if ((da2->fctladdr == LF_PD_RESET) && ((val & 0x7) == 7)) { + /* Reset Bitblt busy */ + da2->bitblt.indata = 0; + da2->bitblt.exec = DA2_BLT_CIDLE; } break; case LC_INDEX: @@ -1214,10 +1324,12 @@ da2_out(uint16_t addr, uint16_t val, void *p) val = 0; break; case LC_START_ADDRESS_HIGH: + // if (val == 0xff) /* adjust (need to confirm) */ + // val = 0; case LC_START_ADDRESS_LOW: /* The DOS J4.0 MODE 4 command and OS/2 driver write 0xFF00. OS/2 DOS MODE 1 setup reads this to set the base line, but it causes the screen glitch. */ - val = 0; + // val = 0; break; case LC_VERTICAL_TOTALJ: /* Vertical Total */ case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ @@ -1227,25 +1339,21 @@ da2_out(uint16_t addr, uint16_t val, void *p) val = 0x400; /* for debugging bitblt in Win 3.x */ #endif break; - case LC_VIEWPORT_SELECT: /* ViewPort Select? */ - // return; - break; - case LC_VIEWPORT_NUMBER: /* Compatibility? */ - break; } da2->crtc[da2->crtcaddr] = val; switch (da2->crtcaddr) { case LC_H_DISPLAY_ENABLE_END: case LC_VERTICAL_TOTALJ: case LC_MAXIMUM_SCAN_LINE: - // case LC_START_ADDRESS_HIGH: - // case LC_START_ADDRESS_LOW: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: case LC_VERTICAL_SYNC_START: case LC_V_DISPLAY_ENABLE_END: case LC_START_VERTICAL_BLANK: case LC_START_H_DISPLAY_ENAB: case LC_START_V_DISPLAY_ENAB: case LC_VIEWPORT_PRIORITY: + case LC_LINE_COMPAREJ: da2->fullchange = changeframecount; da2_recalctimings(da2); break; @@ -1432,7 +1540,7 @@ da2_in(uint16_t addr, void *p) // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); // } } - if (da2->bitblt.indata) temp |= 0x08; + // if (da2->bitblt.indata) temp |= 0x08; #ifdef ENABLE_DA2_DEBUGMONWAIT da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc); #endif @@ -1464,6 +1572,10 @@ da2_in(uint16_t addr, void *p) da2->cgastat &= ~0x30; else da2->cgastat ^= 0x30; /* toggle */ + if (da2->cgastat & 0x08) + da2->cgastat &= ~0x08; + else + da2->cgastat ^= 0x08; /* toggle */ temp = da2->cgastat; } else temp = da2->attrc[da2->attraddr]; @@ -1496,7 +1608,7 @@ static void da2_outb(uint16_t addr, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; - // da2_iolog("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); + da2_iolog("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI); da2->inflipflop = 0; switch (addr) { case LS_DATA: @@ -2195,17 +2307,18 @@ da2_recalctimings(da2_t *da2) double crtcconst; double _dispontime, _dispofftime, disptime; - /* if output disabled or VGA passthrough */ - if (da2->ioctl[LS_MODE] & 0x02 || !(da2->attrc[LV_COMPATIBILITY] & 0x08)) { - da2->render = da2_render_blank; - return; - } + // /* if output disabled or VGA passthrough */ + // if (da2->ioctl[LS_MODE] & 0x02 || !(da2->attrc[LV_COMPATIBILITY] & 0x08)) { + // da2->render = da2_render_blank; + // return; + // } da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff; da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff; - da2->split = 0xfff; + da2->split -= 1; + // da2->split = 0xfff; da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; @@ -2225,17 +2338,23 @@ da2_recalctimings(da2_t *da2) // da2->interlace = 0; - // da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW];//w + b + if (da2->crtc[LC_VIEWPORT_SELECT] & 0x80 || da2->split == 0) + da2->ma_latch = 0; + else + da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; // w + b + da2->ca_adj = 0; - da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; - da2->hdisp_time = da2->hdisp; da2->render = da2_render_blank; /* determine display mode */ // if (da2->attr_palette_enable && (da2->attrc[0x1f] & 0x08)) + /* if output disabled or VGA passthrough */ + if (da2->ioctl[LS_MODE] & 0x02 || !(da2->attrc[LV_COMPATIBILITY] & 0x08)) { + da2->render = da2_render_blank; + // return; /* 16 color graphics mode */ - if (!(da2->ioctl[LS_MODE] & 0x01)) { + } else if (!(da2->ioctl[LS_MODE] & 0x01)) { da2->hdisp *= 16; da2->char_width = 13; if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) { @@ -2294,7 +2413,7 @@ da2_recalctimings(da2_t *da2) da2_log("da2 horiz total %i display end %i vidclock %f\n", da2->crtc[0], da2->crtc[1], da2->clock); da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart); da2_log("da2 dispon %lu dispoff %lu on(us) %f off(us) %f\n",da2->dispontime, da2->dispofftime, (double)da2->dispontime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0, (double)da2->dispofftime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0); - // da2_log("da2->render %08X\n", da2->render); + da2_log("da2 linecompare %d\n", da2->split); } static void @@ -2452,7 +2571,7 @@ da2_mmio_read(uint32_t addr, void *p) uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; - addr += index * 0x40; + addr += index * 0x80; } // da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { @@ -2475,6 +2594,7 @@ da2_mmio_read(uint32_t addr, void *p) return da2->mmio.font[addr]; break; default: + da2_log("PS55_MemHnd: Invalid read mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return DA2_INVALIDACCESS8; /* invalid memory access */ break; } @@ -2549,35 +2669,56 @@ da2_mmio_readw(uint32_t addr, void *p) return (uint16_t) da2_mmio_read(addr, da2) | (uint16_t) (da2_mmio_read(addr + 1, da2) << 8); } } - +static void +da2_bitblt_addpayload(uint8_t val, void *p) +{ + da2_t *da2 = (da2_t *) p; + da2->bitblt.indata = 1; + if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! addr %x, val %x\n", da2->bitblt.payload_addr, val); + else { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + } +} static void da2_mmio_write(uint32_t addr, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; + uint32_t index = 0; // da2_log("da2_mmio_write %x %x\n", addr, val); // if ((addr & ~DA2_MASK_MMIO) != 0xA0000) // return; addr &= DA2_MASK_MMIO; - if (da2->ioctl[LS_MMIO] & 0x10) { + if (da2->ioctl[LS_MMIO] == 0x1f) {/* write bitblt fifo data */ + da2_bitblt_addpayload(val, da2); + } + else if (da2->ioctl[LS_MMIO] & 0x10) { /* access to gaiji ram */ // if(da2->ioctl[LS_MMIO] == 0x1f) da2_log("mw mem %x, addr %x, val %x, ESDI %x:%x DSSI %x:%x\n", da2->fctl[LF_MMIO_MODE], addr, val, ES, DI, DS, SI); /* Gaiji RAM */ if (da2->fctl[LF_MMIO_SEL] == 0x80) addr |= ((uint32_t) da2->fctl[LF_MMIO_ADDR] << 17); /* xxxy yyyy yyyy yyyy yyyy */ - else { - uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + else { + index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; - addr += index * 0x40; + // addr += index * 0x40; + // addr += index * 0x80; + // da2_log("da2_mmio_w io %x, sl %x, 09 %x, ad %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO],da2->fctl[LF_MMIO_SEL], + // da2->fctl[LF_MMIO_09],da2->fctl[LF_MMIO_ADDR], da2->fctl[LF_MMIO_MODE], addr, val); } - switch (da2->fctl[LF_MMIO_MODE]) { - case 0xb0: /* Gaiji RAM 1011 0000 */ + switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { + case 0xb0: /* Gaiji RAM 1011 0000 */ + addr += index * 0x80; da2->mmio.ram[addr & DA2_MASK_GAIJIRAM] = val; break; case 0x10: /* Font ROM 0001 0000 */ /* Read-Only */ break; - case 0x00: + case 0x00: /* SBCS in Gaiji RAM (used by DOS/V Extension DSPXDA2 driver) */ + addr += index * 0x40; + da2->mmio.ram[(DA2_GAIJIRAM_SBCS + addr) & DA2_MASK_GAIJIRAM] = val; // da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); // addr &= 0x7f;/* OS/2 write addr 1cf80-1cfc3, val xx */ // if (addr >= DA2_BLT_MEMSIZE) @@ -2585,16 +2726,9 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); // return; // } - da2->bitblt.indata = 1; - if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) - da2_log("da2_mmio_write payload overflow! mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - else { - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; - } break; default: - da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); + da2_log("da2_mmio_write failed io %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO] ,da2->fctl[LF_MMIO_MODE], addr, val); break; } } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ @@ -2802,15 +2936,21 @@ da2_mmio_writew(uint32_t addr, uint16_t val, void *p) // return; // if ((addr & ~0x1ffff) != 0xA0000) return; if (da2->ioctl[LS_MMIO] & 0x10) { - // da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); +#ifdef ENABLE_DA2_DEBUGVRAM + da2_log("da2_mmio_writeW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); +#endif da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } else if (!(da2->ioctl[LS_MODE] & 1)) { /* 16 color or 256 color mode */ - // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); +#ifdef ENABLE_DA2_DEBUGVRAM + da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); +#endif da2_mmio_gc_writeW(addr, val, da2); } else { /* mode 3h text */ +#ifdef ENABLE_DA2_DEBUGVRAM // if (addr & 0xff00 == 0) da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - // da2_log("da2_mmio_writeGW %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); + da2_log("da2_mmio_write3W %x %x %x %x %x %x\n", da2->ioctl[LS_MMIO], da2->fctl[LF_MMIO_SEL], da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr, val); +#endif da2_mmio_write(addr, val & 0xff, da2); da2_mmio_write(addr + 1, val >> 8, da2); } @@ -2836,7 +2976,7 @@ da2_code_writeb(uint32_t addr, uint8_t val, void *p) static void da2_code_writew(uint32_t addr, uint16_t val, void *p) { - // da2_log("DA2_code_writew: Write to %x, val %x\n", addr, val); + // da2_log("DA2_code_writ ew: Write to %x, val %x\n", addr, val); da2_t *da2 = (da2_t *) p; cycles -= video_timing_write_w; da2_code_write(addr, val & 0xff, da2); @@ -2945,8 +3085,6 @@ da2_poll(void *priv) da2->sc = 0; da2->maback += (da2->rowoffset << 1); /* color = 0x50(80), mono = 0x40(64) */ - if (da2->interlace) - da2->maback += (da2->rowoffset << 1); da2->maback &= da2->vram_display_mask; da2->ma = da2->maback; } else { @@ -2959,6 +3097,13 @@ da2_poll(void *priv) da2->vc++; da2->vc &= 2047; + if (da2->vc == da2->split) { + // da2->ma = da2->maback = da2->hblank_sub; + da2->ma = da2->maback = 0; + da2->sc = 0; + // da2->displine = 0; + } + if (da2->vc == da2->dispend) { da2->dispon = 0; // if (da2->crtc[10] & 0x20) da2->cursoron = 0; @@ -3002,13 +3147,11 @@ da2_poll(void *priv) da2->firstline_draw = 2000; da2->lastline_draw = 0; - da2->oddeven ^= 1; - - changeframecount = da2->interlace ? 3 : 2; + changeframecount = 2; da2->vslines = 0; da2->ma - = da2->maback = da2->ma_latch; + = da2->maback = da2->ma_latch << 1; da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; da2->ca <<= 1; @@ -3020,7 +3163,7 @@ da2_poll(void *priv) da2->vc = 0; da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; da2->dispon = 1; - da2->displine = (da2->interlace && da2->oddeven) ? 1 : 0; + da2->displine = 0; da2->scrollcache = da2->attrc[LV_PANNING] & 7; } if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) @@ -3111,7 +3254,6 @@ da2_reset(void *priv) da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ da2->ma_latch = 0; - da2->interlace = 0; da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ da2->attr_palette_enable = 0; /* disable attribute generator */ @@ -3245,6 +3387,12 @@ da2_close(void *p) fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); fclose(f); } + f = fopen("ram_low.dmp", "wb"); + if (f != NULL) { + fwrite(&ram[0x0], 0x100000, 1, f); + fclose(f); + } + pclog("closed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS); #endif #ifdef ENABLE_DA2_DEBUGBLT f = fopen("da2_bltdump.csv", "w"); @@ -3262,8 +3410,16 @@ da2_close(void *p) ; else if (da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y] == DA2_DEBUG_BLT_USEDRESET) fprintf(f, "\"\"\t"); - else + else { fprintf(f, "\"%X\"\t", da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + y]); + if (y == 0x12) { + int chr = da2->bitblt.debug_reg[x * DA2_DEBUG_BLTLOG_SIZE + 0x12]; + if ((chr >= 0x20) && (chr < 0x7f)) + fprintf(f, "\"%c\"\t", chr); + else + fprintf(f, "\"\"\t"); + } + } } fprintf(f, "\n"); } From 837f86a291e5bf696cd327b01a6d544901e052f4 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Thu, 3 Apr 2025 22:17:24 +0900 Subject: [PATCH 0668/1190] PS55DA2: Parse Bitblt data sequential --- src/video/vid_ps55da2.c | 212 +++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 88 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 1875726b5..613eb5888 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -66,7 +66,7 @@ #define DA2_MASK_VRAM 0xfffff /* 0xFFFFF */ #define DA2_MASK_VRAMPLANE 0x1ffff /* 0x1FFFF */ #define DA2_PIXELCLOCK 29000000.0 /* 58 MHz interlaced */ -#define DA2_BLT_MEMSIZE 0x1000 +#define DA2_BLT_MEMSIZE 0x10 #define DA2_BLT_REGSIZE 0x40 #define DA2_DEBUG_BLTLOG_SIZE (DA2_BLT_REGSIZE + 1) #define DA2_DEBUG_BLTLOG_MAX (256 * 1024) @@ -264,7 +264,7 @@ #endif #ifdef ENABLE_DA2_LOG -// # define ENABLE_DA2_DEBUGIO 1 +# define ENABLE_DA2_DEBUGIO 1 # define ENABLE_DA2_DEBUGBLT 1 // # define ENABLE_DA2_DEBUGVRAM 1 // # define ENABLE_DA2_DEBUGFULLSCREEN 1 @@ -292,6 +292,12 @@ da2_log(const char *fmt, ...) #endif #ifdef ENABLE_DA2_DEBUGBLT # define da2_bltlog da2_log +# define ENABLE_DA2_DEBUGBLT_DETAIL 1 +# ifdef ENABLE_DA2_DEBUGBLT_DETAIL +# define da2_bltreglog da2_log +# else +# define da2_bltreglog(fmt, ...) +# endif #else # define da2_bltlog(fmt, ...) #endif @@ -390,6 +396,7 @@ typedef struct da2_t { int raster_op; uint8_t payload[DA2_BLT_MEMSIZE]; int payload_addr; + int payload_opsize; int32_t reg[DA2_BLT_REGSIZE]; // must be signed int #ifdef ENABLE_DA2_DEBUGBLT int32_t *debug_reg; // for debug @@ -643,24 +650,24 @@ DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, ui // bg = IBGRtoIRGB(bg); uint32_t font = getFontIBMJ(codeIBMJ, line, 0, da2); uint32_t fontinv; - if (width == 1) { + if (width <= 2) { fontinv = ~font; for (int i = 0; i < 8; i++) { srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; } - pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); + // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); for (int i = 0; i < 8; i++) { srcpx.p8[i] = (color & (1 << i)) ? font : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } - pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); + // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); } else { font = (font & 0xfff80000) | ((font & 0x0000ffff) << 3); fontinv = ~font; - pclog("putchar: ft %08X shftr %X\n", font, da2->bitblt.bitshift_destr); + // pclog("putchar: ft %08X shftr %X\n", font, da2->bitblt.bitshift_destr); for (int i = 0; i < 8; i++) { srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; @@ -752,106 +759,103 @@ IBMJtoSJIS(uint16_t knj) return knj; } #endif + static void -da2_bitblt_load(da2_t *da2) +da2_bitblt_parse(da2_t *da2) { uint32_t value32; uint64_t value64; #ifdef ENABLE_DA2_DEBUGBLT - da2_log("bltload: loading params\n"); - da2_log("BitBlt memory:\n"); - if (da2->bitblt.payload[0] != 0) - for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) - { - int i = j * 8; - da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - } + // da2_log("bltload: loading params\n"); + // da2_log("BitBlt memory:\n"); + // if (da2->bitblt.payload[0] != 0) + // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) { + // int i = j * 8; + // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], + // da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7]); + // } #endif - int i = 0; - while (i < da2->bitblt.payload_addr) { - if (da2->bitblt.reg[0x20] & 0x1) - break; - switch (da2->bitblt.payload[i]) { + switch (da2->bitblt.payload[0]) { case 0x88: case 0x89: case 0x95: - value32 = da2->bitblt.payload[i + 3]; + value32 = da2->bitblt.payload[3]; value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_bltlog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - // da2->gdcreg[da2->bitblt.payload[i + 1]] = value32; - i += 3; + value32 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[1]] = value32; break; case 0x91: - value32 = da2->bitblt.payload[i + 5]; + value32 = da2->bitblt.payload[5]; value32 <<= 8; - value32 |= da2->bitblt.payload[i + 4]; + value32 |= da2->bitblt.payload[4]; value32 <<= 8; - value32 |= da2->bitblt.payload[i + 3]; + value32 |= da2->bitblt.payload[3]; value32 <<= 8; - value32 |= da2->bitblt.payload[i + 2]; - da2_bltlog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value32; - // da2->gdcreg[da2->bitblt.payload[i + 1]] = value32; - i += 5; + value32 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[1]] = value32; break; case 0x99: - value64 = da2->bitblt.payload[i + 7]; + value64 = da2->bitblt.payload[7]; value64 <<= 8; - value64 = da2->bitblt.payload[i + 6]; + value64 = da2->bitblt.payload[6]; value64 <<= 8; - value64 = da2->bitblt.payload[i + 5]; + value64 = da2->bitblt.payload[5]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 4]; + value64 |= da2->bitblt.payload[4]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 3]; + value64 |= da2->bitblt.payload[3]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 2]; - da2_bltlog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7]); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; - // da2->gdcreg[da2->bitblt.payload[i + 1]] = value64; - i += 7; + value64 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], + da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7]); + da2->bitblt.reg[da2->bitblt.payload[1]] = value64; break; case 0xa1: - value64 = da2->bitblt.payload[i + 9]; + value64 = da2->bitblt.payload[9]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 8]; + value64 |= da2->bitblt.payload[8]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 7]; + value64 |= da2->bitblt.payload[7]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 6]; + value64 |= da2->bitblt.payload[6]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 5]; + value64 |= da2->bitblt.payload[5]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 4]; + value64 |= da2->bitblt.payload[4]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 3]; + value64 |= da2->bitblt.payload[3]; value64 <<= 8; - value64 |= da2->bitblt.payload[i + 2]; - da2_bltlog("[%02x] %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[i], da2->bitblt.payload[i + 1], da2->bitblt.payload[i + 2], da2->bitblt.payload[i + 3], - da2->bitblt.payload[i + 4], da2->bitblt.payload[i + 5], da2->bitblt.payload[i + 6], da2->bitblt.payload[i + 7], da2->bitblt.payload[i + 8], da2->bitblt.payload[i + 9]); - da2->bitblt.reg[da2->bitblt.payload[i + 1]] = value64; - i += 9; + value64 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], + da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7], da2->bitblt.payload[8], da2->bitblt.payload[9]); + da2->bitblt.reg[da2->bitblt.payload[1]] = value64; break; - case 0x00: + case 0x00: /* Win 3.0 Clock writes invalid zero data. */ break; default: da2_log("bltload: Unknown PreOP!\n"); break; } - i++; + if (da2->bitblt.reg[0x20] & 0x01) { /* Execute Bitblt immediately (for OS/2 J1.3) */ + da2->bitblt.exec = DA2_BLT_CLOAD; + da2_bitblt_exec(da2); } - da2->bitblt.exec = DA2_BLT_CIDLE; /* clear payload memory */ memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); da2->bitblt.payload_addr = 0; + da2->bitblt.indata = 0; +} + +static void +da2_bitblt_load(da2_t *da2) +{ /* [89] 20: 0001 (1) then execute payload */ - if (da2->bitblt.reg[0x20] & 0x1) { + // if (da2->bitblt.reg[0x20] & 0x1) { + da2->bitblt.reg[0x20] = 0; /* need to stop execution */ #ifdef ENABLE_DA2_DEBUGBLT - for (i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + for (int i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; } da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; @@ -860,7 +864,6 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.debug_reg_ip = 0; da2->bitblt.debug_exesteps = 0; #endif - da2_log("bltload_exec: %x, rop: %x CS:PC=%4x:%4x\n", da2->bitblt.reg[0x5], da2->bitblt.reg[0xb], CS, cpu_state.pc); da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x03] >> 4) & 0x0f); /* set bit shift */ da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; da2->bitblt.destaddr = da2->bitblt.reg[0x29]; @@ -869,7 +872,11 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.destpitch = da2->bitblt.reg[0x21]; da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; /* 80h = 128d = 10000000b, 90h = 144d = 10010000b, B0h = 176d = 10110000 */ - if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ + /* + DOS/V Extension 1040x725 some DBCS uses 0xB0 others 0x90 + B0: BitShift is 1-6 + */ + if (da2->bitblt.reg[0x2F] & 0x10) /* destaddr -= 2, length += 1; */ { da2->bitblt.destaddr -= 2; da2->bitblt.size_x += 1; @@ -897,7 +904,7 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.fcolor = da2->bitblt.reg[0x1]; da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; da2->bitblt.destaddr += 2; - da2->bitblt.srcpitch = 0; + // da2->bitblt.srcpitch = 0; #ifdef ENABLE_DA2_DEBUGBLT uint8_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint8_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; @@ -914,6 +921,11 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); +#else +da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); #endif } /* Draw a line */ @@ -1002,17 +1014,19 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.size_x, da2->bitblt.size_y); // da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); } - } + // } } static void da2_bitblt_exec(void *p) { da2_t *da2 = (da2_t *) p; // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); -#ifdef ENABLE_DA2_DEBUGBLT +#ifdef ENABLE_DA2_DEBUGBLT_DETAIL if(!(da2->bitblt.debug_exesteps & 0xff)) da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); da2->bitblt.debug_exesteps++; +#else + da2_log("bltload_exec: %x, CS:PC=%4x:%4x\n", da2->bitblt.exec, CS, cpu_state.pc); #endif switch (da2->bitblt.exec) { case DA2_BLT_CIDLE: @@ -1020,7 +1034,7 @@ da2_bitblt_exec(void *p) break; case DA2_BLT_CLOAD: da2_bitblt_load(da2); - da2->bitblt.indata = 0; + // da2->bitblt.indata = 0; break; case DA2_BLT_CLINE: /* Draw a dot */ @@ -1160,22 +1174,22 @@ da2_bitblt_exec(void *p) da2->bitblt.srcaddr -= 2; break; case DA2_BLT_CPUTCHAR: /* used in OS/2 J1.3 wo ROM patch. TODO: still not work */ - da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.y * 130; + // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.y * 130; // da2->bitblt.srcaddr += 2; // if (da2->bitblt.reg[0x12] < 0x100) // da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; // else // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; - da2->bitblt.size_x = da2->bitblt.reg[0x33]; - pclog("scr %x dest %x x %x y %x\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); + // da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; + // da2->bitblt.size_x = da2->bitblt.reg[0x33]; + // pclog("scr %x dest %x x %x y %x\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); if (da2->bitblt.y >= da2->bitblt.size_y) { da2->bitblt.exec = DA2_BLT_CDONE; } else { DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); } da2->bitblt.y++; - da2->bitblt.destaddr += 130; + da2->bitblt.destaddr += da2->bitblt.size_x * 2 + da2->bitblt.destpitch + 2; // } // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; ////da2->bitblt.srcaddr += 2; @@ -1189,10 +1203,9 @@ da2_bitblt_exec(void *p) // da2->bitblt.reg[i] = DA2_DEBUG_BLT_USEDRESET; // } // } else /* without init regs */ - da2->bitblt.reg[0x20] = 0; /* need to stop execution */ - if (da2->bitblt.indata) - da2->bitblt.exec = DA2_BLT_CLOAD; - else + // if (da2->bitblt.indata) + // da2->bitblt.exec = DA2_BLT_CLOAD; + // else da2->bitblt.exec = DA2_BLT_CIDLE; break; } @@ -1206,7 +1219,7 @@ da2_bitblt_dopayload(void *priv) if (da2->bitblt.exec != DA2_BLT_CIDLE) { while (da2->bitblt.exec != DA2_BLT_CIDLE) /* this disables async operation */ da2_bitblt_exec(da2); - } else if (da2->bitblt.indata && !(da2->ioctl[LS_MMIO] & 0x10) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { + } else if ((da2->bitblt.reg[0x20] & 0x01) && (da2->bitblt.exec == DA2_BLT_CIDLE)) { da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); } else { @@ -1532,13 +1545,7 @@ da2_in(uint16_t addr, void *p) // if (da2->bitblt.indata) /* for OS/2 J1.3 command prompt scrolling */ // da2_bitblt_dopayload(da2); if (da2->bitblt.exec != DA2_BLT_CIDLE) { - // da2_iolog("exec:%x\n", da2->bitblt.exec); - temp |= 0x01; /* wait (bit 3 + bit 0) ? need verify */ - // if (!da2->bitblt.timer.enabled) - //{ - // da2_iolog("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc); - // timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); - // } + temp |= 0x09; /* wait (bit 3 + bit 0) ? need verify */ } // if (da2->bitblt.indata) temp |= 0x08; #ifdef ENABLE_DA2_DEBUGMONWAIT @@ -2677,8 +2684,37 @@ da2_bitblt_addpayload(uint8_t val, void *p) if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) da2_log("da2_mmio_write payload overflow! addr %x, val %x\n", da2->bitblt.payload_addr, val); else { - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; + if (da2->bitblt.payload_addr == 0) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + switch (val) { + case 0x88: + case 0x89: + case 0x95: + da2->bitblt.payload_opsize = 3; + break; + case 0x91: + da2->bitblt.payload_opsize = 5; + break; + case 0x99: + da2->bitblt.payload_opsize = 7; + break; + case 0xa1: + da2->bitblt.payload_opsize = 9; + break; + default: + da2_log("addpayload: Unknown PreOP! %x\n", val); + da2->bitblt.payload_addr = 0; /* ignore input */ + break; + } + } else if (da2->bitblt.payload_addr < da2->bitblt.payload_opsize) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + } else if (da2->bitblt.payload_addr == da2->bitblt.payload_opsize) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_opsize = 0; /* reset */ + da2_bitblt_parse(da2); + } } } static void From b4f3e06c1ed4aa9d57768e548a6ce4c3d96acb7a Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 4 Apr 2025 08:23:32 +0900 Subject: [PATCH 0669/1190] PS55DA2: Fix some issues in DSPX and OS/2 dosbox --- src/video/vid_ps55da2.c | 96 +++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 613eb5888..52eccc575 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -307,7 +307,9 @@ typedef struct da2_t { uint8_t ioctl[16]; uint8_t fctl[32]; - uint16_t crtc[128]; + uint16_t crtc[32]; + uint16_t crtc_vpreg[128]; + uint8_t crtc_vpsel; uint8_t gdcreg[64]; uint8_t reg3ee[16]; int gdcaddr; @@ -420,6 +422,7 @@ typedef struct da2_t { int32_t maskl, maskr; int32_t count; int32_t d; + int8_t destoption; int octdir; int x, y, wx1, wx2, wy1, wy2; } bitblt; @@ -679,13 +682,17 @@ DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, ui srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } // pclog("putchar: %08X mask %04X\n", srcpx.p8[3], maskr); - DA2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); - for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font << 16 : 0; - srcpx.p8[i] |= (bg & (1 << i)) ? fontinv << 16 : 0; + if (da2->bitblt.destoption & 0x20) { + DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); + } else { + DA2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); + for (int i = 0; i < 8; i++) { + srcpx.p8[i] = (color & (1 << i)) ? font << 16 : 0; + srcpx.p8[i] |= (bg & (1 << i)) ? fontinv << 16 : 0; + } + // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[3], maskl, maskr); + DA2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); } - // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[3], maskl, maskr); - DA2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); } } #ifdef ENABLE_DA2_DEBUGBLT @@ -876,7 +883,8 @@ da2_bitblt_load(da2_t *da2) DOS/V Extension 1040x725 some DBCS uses 0xB0 others 0x90 B0: BitShift is 1-6 */ - if (da2->bitblt.reg[0x2F] & 0x10) /* destaddr -= 2, length += 1; */ + da2->bitblt.destoption = da2->bitblt.reg[0x2F]; + if (da2->bitblt.destoption & 0x10) /* destaddr -= 2, length += 1; */ { da2->bitblt.destaddr -= 2; da2->bitblt.size_x += 1; @@ -1336,14 +1344,6 @@ da2_out(uint16_t addr, uint16_t val, void *p) if (!(da2->ioctl[LS_MODE] & 0x01)) /* 16 or 256 color graphics mode */ val = 0; break; - case LC_START_ADDRESS_HIGH: - // if (val == 0xff) /* adjust (need to confirm) */ - // val = 0; - case LC_START_ADDRESS_LOW: - /* The DOS J4.0 MODE 4 command and OS/2 driver write 0xFF00. - OS/2 DOS MODE 1 setup reads this to set the base line, but it causes the screen glitch. */ - // val = 0; - break; case LC_VERTICAL_TOTALJ: /* Vertical Total */ case LC_VERTICAL_SYNC_START: /* Vertical Retrace Start Register */ case LC_V_DISPLAY_ENABLE_END: /* Vertical Display End Register */ @@ -1352,8 +1352,36 @@ da2_out(uint16_t addr, uint16_t val, void *p) val = 0x400; /* for debugging bitblt in Win 3.x */ #endif break; + // case LC_START_ADDRESS_HIGH: + // if (val == 0xff) /* adjust (need to confirm) */ + // val = 0; + // case LC_START_ADDRESS_LOW: + // val = 0; + // break; } da2->crtc[da2->crtcaddr] = val; + switch (da2->crtcaddr) { + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + /* The DOS J4.0 MODE 4 command and OS/2 driver write 0xFF00. + OS/2 DOS MODE 1 setup reads this to set the base line, but it causes the screen glitch. */ + outb(0x680, da2->crtc[LC_START_ADDRESS_LOW]); + outb(0x680, da2->crtc[LC_START_ADDRESS_HIGH]); + break; + case LC_VIEWPORT_SELECT: + /* backup some current crtc regs */ + for (int i = LC_START_ADDRESS_HIGH; i <= LC_START_ADDRESS_LOW; i++) { + da2->crtc_vpreg[(da2->crtc_vpsel * 0x20) + i] = da2->crtc[i]; + } + da2->crtc_vpsel = (val >> 6) & 3; + /* restore crtc regs */ + for (int i = LC_START_ADDRESS_HIGH; i <= LC_START_ADDRESS_LOW; i++) { + da2->crtc[i] = da2->crtc_vpreg[(da2->crtc_vpsel * 0x20) + i]; + } + break; + default: + break; + } switch (da2->crtcaddr) { case LC_H_DISPLAY_ENABLE_END: case LC_VERTICAL_TOTALJ: @@ -1363,10 +1391,11 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LC_VERTICAL_SYNC_START: case LC_V_DISPLAY_ENABLE_END: case LC_START_VERTICAL_BLANK: + case LC_LINE_COMPAREJ: case LC_START_H_DISPLAY_ENAB: case LC_START_V_DISPLAY_ENAB: + case LC_VIEWPORT_SELECT: case LC_VIEWPORT_PRIORITY: - case LC_LINE_COMPAREJ: da2->fullchange = changeframecount; da2_recalctimings(da2); break; @@ -1567,7 +1596,11 @@ da2_in(uint16_t addr, void *p) case LC_DATA: if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS16; - temp = da2->crtc[da2->crtcaddr]; + // if ((da2->crtcaddr == LC_START_ADDRESS_HIGH || da2->crtcaddr == LC_START_ADDRESS_LOW) + // & (da2->crtc[LC_VIEWPORT_SELECT] & 0x80)) + // temp = 0; + // else + temp = da2->crtc[da2->crtcaddr]; break; case LV_PORT: temp = da2->attraddr | da2->attr_palette_enable; @@ -2345,7 +2378,14 @@ da2_recalctimings(da2_t *da2) // da2->interlace = 0; - if (da2->crtc[LC_VIEWPORT_SELECT] & 0x80 || da2->split == 0) + // if (da2->crtc[LC_VIEWPORT_SELECT] & 0x80 || da2->split == 0) + if (da2->vtotal == 0) + da2->vtotal = da2->vsyncstart = da2->vblankstart = 256; + if (da2->htotal == 0) + da2->htotal = da2->dispend = da2->hdisp = 64; + if (da2->rowoffset == 0) + da2->rowoffset = 64 * 2; /* To avoid causing a DBZ error */ + if (da2->split == 0) da2->ma_latch = 0; else da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; // w + b @@ -2568,6 +2608,7 @@ static uint8_t da2_mmio_read(uint32_t addr, void *p) { da2_t *da2 = (da2_t *) p; + uint32_t index = 0; addr &= DA2_MASK_MMIO; if (da2->ioctl[LS_MMIO] & 0x10) { if (da2->fctl[LF_MMIO_SEL] == 0x80) @@ -2575,14 +2616,14 @@ da2_mmio_read(uint32_t addr, void *p) addr |= ((uint32_t) da2->fctl[LF_MMIO_ADDR] << 17); else { /* 64k bank switch access */ - uint32_t index = da2->fctl[LF_MMIO_MODE] & 0x0f; + index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; - addr += index * 0x80; } // da2_log("PS55_MemHnd: Read from mem %x, bank %x, addr %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr); switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { case 0xb0: /* Gaiji RAM */ + addr += index * 0x80; addr &= DA2_MASK_GAIJIRAM; /* safety access */ // da2_log("PS55_MemHnd_G: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 128, addr, da2->mmio.font[addr]); return da2->mmio.ram[addr]; @@ -2600,6 +2641,11 @@ da2_mmio_read(uint32_t addr, void *p) // da2_log("PS55_MemHnd: Read from mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return da2->mmio.font[addr]; break; + case 0x00: /* SBCS in Gaiji RAM (used in the downward writing mode of DOS/V Extension) */ + addr += DA2_GAIJIRAM_SBCS + index * 0x40; + addr &= DA2_MASK_GAIJIRAM; + return da2->mmio.ram[addr]; + break; default: da2_log("PS55_MemHnd: Invalid read mem %x, bank %x, chr %x (%x), val %x\n", da2->fctl[LF_MMIO_MODE], da2->fctl[LF_MMIO_ADDR], addr / 72, addr, da2->mmio.font[addr]); return DA2_INVALIDACCESS8; /* invalid memory access */ @@ -2741,8 +2787,8 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) index |= da2->fctl[LF_MMIO_ADDR]; // addr += index * 0x40; // addr += index * 0x80; - // da2_log("da2_mmio_w io %x, sl %x, 09 %x, ad %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO],da2->fctl[LF_MMIO_SEL], - // da2->fctl[LF_MMIO_09],da2->fctl[LF_MMIO_ADDR], da2->fctl[LF_MMIO_MODE], addr, val); + da2_log("da2_mmio_w io %x, sl %x, 09 %x, ad %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO],da2->fctl[LF_MMIO_SEL], + da2->fctl[LF_MMIO_09],da2->fctl[LF_MMIO_ADDR], da2->fctl[LF_MMIO_MODE], addr, val); } switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { case 0xb0: /* Gaiji RAM 1011 0000 */ @@ -3421,6 +3467,10 @@ da2_close(void *p) fprintf(f, "3eb(gcr) %02X: %4X\n", i, da2->gdcreg[i]); for (int i = 0; i < 0x10; i++) fprintf(f, "3ee(?) %02X: %4X\n", i, da2->reg3ee[i]); + for (int i = 0; i < 0x20; i++) { + fprintf(f, "vp %02X: %4X %4X %4X %4X\n", i, + da2->crtc_vpreg[0 + i], da2->crtc_vpreg[0x20 + i], da2->crtc_vpreg[0x40 + i], da2->crtc_vpreg[0x60 + i]); + } fclose(f); } f = fopen("ram_low.dmp", "wb"); From beb417cc85b8e4e1d42f040a58351a6ab4824fcd Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 4 Apr 2025 08:55:14 +0900 Subject: [PATCH 0670/1190] PS55DA2: cleanup, remove unused code --- src/video/vid_ps55da2.c | 162 +++++++--------------------------------- 1 file changed, 26 insertions(+), 136 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 52eccc575..09e3471a5 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -490,20 +490,6 @@ getFontIBMJ(int32_t code, int line, int x, void *p) font <<= 8; font |= da2->mmio.ram[code + 1]; font <<= 16; - return font; - } - if ((code >= 0x8000) && (code <= 0x8183)) - code -= 0x6000; /* shift for IBM extended characters */ - if ((code < (DA2_FONTROM_SIZE / 72)) && (fline >= 0) && (fline < 24)) { /* DBCS 24x24 */ - code = (code * 72) + (fline * 3) + x; - // font = da2->mmio.font[code]; /* 0000 0000 0000 0000 0000 0000 1111 1111 */ - // font <<= 8; /* 0000 0000 0000 0000 1111 1111 0000 0000 */ - // font |= da2->mmio.font[code + 1] & 0xf0; /* 0000 0000 0000 0000 1111 1111 2222 0000 */ - // font <<= 3; /* 0000 0000 0000 0111 1111 1222 2000 0000 */ - // font |= da2->mmio.font[code + 1] & 0x0f; /* 0000 0000 0000 0111 1111 1222 2000 2222 */ - // font <<= 8; /* 0000 0111 1111 1222 2000 2222 0000 0000 */ - // font |= da2->mmio.font[code + 2]; /* 0000 0111 1111 1222 2000 2222 3333 3333 */ - // font <<= 4; /* 0111 1111 1222 2000 2222 3333 3333 0000 */ } else if ((code >= 0xb000) && (code <= 0xb75f)) { /* DBCS 26x29 */ /* convert code->address in gaiji memory */ code -= 0xb000; @@ -515,9 +501,7 @@ getFontIBMJ(int32_t code, int line, int x, void *p) font |= da2->mmio.ram[code + 2]; font <<= 8; font |= da2->mmio.ram[code + 3]; - // font <<= 16; - } else if (code > (DA2_FONTROM_SIZE / 72)) - font = 0xffffffffu; + } else font = 0; return font; @@ -594,7 +578,7 @@ Param Desc 01 Color 03 Bit Shift 04 Select plane? -05 Dir(1000h or 1100h) + Command?(40 or 48) +05 Direction (1000h or 1100h) + Command? (40 or 48) 08 Mask Left 09 Mask Right 0A Plane Mask? @@ -607,15 +591,19 @@ Param Desc 0-3 Bit op (0 None, 1 AND, 2 OR, 3 XOR) 0D 20 Exec (1) or Exec without reset regs? (21h) -21 ? -22 ? +21 Dest Pitch +22 Src Pitch 23 Tile W 28 Tile H 29 Dest Addr 2A Src Addr 2B Tile Addr -33 Size W -35 Size H +2D Octant for line drawing +2F Dest Write Option +32 wx1, Dest X +33 wx2, Size W +34 wy1, Dest Y +35 wy2, Size H */ static void DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) @@ -642,55 +630,42 @@ static void DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, uint32_t destaddr, uint16_t maskl, uint16_t maskr, da2_t *da2) { pixel32 srcpx; - // if (codeIBMJ >= DA2_FONTROM_SIZE / 72) { - // da2_log("DA2 Putchar Addr Error %x\n", srcaddr); - // return; - // } - uint8_t color = (~attr >> 8) & 0x0f; - // color = IBGRtoIRGB(color); + uint8_t fg = (~attr >> 8) & 0x0f; uint8_t bg = (~attr >> 12) & 0x0f; - // bg = 0x00; - // bg = IBGRtoIRGB(bg); uint32_t font = getFontIBMJ(codeIBMJ, line, 0, da2); uint32_t fontinv; if (width <= 2) { fontinv = ~font; for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; + srcpx.p8[i] = (fg & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; } - // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font : 0; + srcpx.p8[i] = (fg & (1 << i)) ? font : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } - // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[0], maskl, maskr); DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); } else { font = (font & 0xfff80000) | ((font & 0x0000ffff) << 3); fontinv = ~font; - // pclog("putchar: ft %08X shftr %X\n", font, da2->bitblt.bitshift_destr); for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font >> 16 : 0; + srcpx.p8[i] = (fg & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; } - // pclog("putchar: %08X mask %04X\n", srcpx.p8[3], maskl); DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font : 0; + srcpx.p8[i] = (fg & (1 << i)) ? font : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } - // pclog("putchar: %08X mask %04X\n", srcpx.p8[3], maskr); if (da2->bitblt.destoption & 0x20) { DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); } else { DA2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); for (int i = 0; i < 8; i++) { - srcpx.p8[i] = (color & (1 << i)) ? font << 16 : 0; + srcpx.p8[i] = (fg & (1 << i)) ? font << 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv << 16 : 0; } - // pclog("putchar: %08X mask %04X %04X\n", srcpx.p8[3], maskl, maskr); DA2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); } } @@ -772,16 +747,6 @@ da2_bitblt_parse(da2_t *da2) { uint32_t value32; uint64_t value64; -#ifdef ENABLE_DA2_DEBUGBLT - // da2_log("bltload: loading params\n"); - // da2_log("BitBlt memory:\n"); - // if (da2->bitblt.payload[0] != 0) - // for (int j = 0; j < DA2_BLT_MEMSIZE / 8; j++) { - // int i = j * 8; - // da2_log("%02x %02x %02x %02x %02x %02x %02x %02x \n", da2->bitblt.payload[i], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], - // da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7]); - // } -#endif switch (da2->bitblt.payload[0]) { case 0x88: case 0x89: @@ -858,8 +823,6 @@ da2_bitblt_parse(da2_t *da2) static void da2_bitblt_load(da2_t *da2) { - /* [89] 20: 0001 (1) then execute payload */ - // if (da2->bitblt.reg[0x20] & 0x1) { da2->bitblt.reg[0x20] = 0; /* need to stop execution */ #ifdef ENABLE_DA2_DEBUGBLT for (int i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { @@ -878,10 +841,8 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.size_y = da2->bitblt.reg[0x35]; da2->bitblt.destpitch = da2->bitblt.reg[0x21]; da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; - /* 80h = 128d = 10000000b, 90h = 144d = 10010000b, B0h = 176d = 10110000 */ /* DOS/V Extension 1040x725 some DBCS uses 0xB0 others 0x90 - B0: BitShift is 1-6 */ da2->bitblt.destoption = da2->bitblt.reg[0x2F]; if (da2->bitblt.destoption & 0x10) /* destaddr -= 2, length += 1; */ @@ -898,21 +859,12 @@ da2_bitblt_load(da2_t *da2) da2->bitblt.y = 0; da2->bitblt.exec = DA2_BLT_CDONE; - /* Put DBCS char used by OS/2 (i'm not sure what the condition is) */ + /* Put DBCS char used by OS/2 and DOS/V Extension */ if (!(da2->bitblt.reg[0xb] & 0x08)) { da2->bitblt.exec = DA2_BLT_CPUTCHAR; - /* Todo: addressing */ - // if (da2->bitblt.reg[0x2F] == 0x90) /* destaddr -= 2, length += 1; */ - //{ - // da2->bitblt.destaddr += 2; - // da2->bitblt.size_x -= 1; - // da2->bitblt.destpitch += 2; - // da2->bitblt.srcpitch += 2; - // } da2->bitblt.fcolor = da2->bitblt.reg[0x1]; da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; da2->bitblt.destaddr += 2; - // da2->bitblt.srcpitch = 0; #ifdef ENABLE_DA2_DEBUGBLT uint8_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; uint8_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; @@ -1020,9 +972,7 @@ da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d\n", da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), da2->bitblt.size_x, da2->bitblt.size_y); - // da2_log(" mask8=%x, mask9=%x\n", da2->bitblt.reg[0x8], da2->bitblt.reg[0x9]); } - // } } static void da2_bitblt_exec(void *p) @@ -1046,7 +996,6 @@ da2_bitblt_exec(void *p) break; case DA2_BLT_CLINE: /* Draw a dot */ - // outb(0x680, da2->bitblt.octdir); da2_bltlog("point: %d %d %d %d %d\n", da2->bitblt.x, da2->bitblt.y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; int pixelmask = da2->bitblt.x % 16; @@ -1061,7 +1010,6 @@ da2_bitblt_exec(void *p) ; else DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); - // da2_log("draw: %x %x %x\n", destaddr, da2->bitblt.fcolor, pixelmask); da2->bitblt.count++; /* calculate the next position with Bresenham's line algorithm */ @@ -1182,26 +1130,14 @@ da2_bitblt_exec(void *p) da2->bitblt.srcaddr -= 2; break; case DA2_BLT_CPUTCHAR: /* used in OS/2 J1.3 wo ROM patch. TODO: still not work */ - // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.y * 130; - // da2->bitblt.srcaddr += 2; - // if (da2->bitblt.reg[0x12] < 0x100) - // da2->bitblt.srcaddr = DA2_FONTROM_BASESBCS + da2->bitblt.reg[0x12] * 64 + (da2->bitblt.x * 2) + (da2->bitblt.y * 2) - 2; - // else - // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2) + (da2->bitblt.y * 3) - 2; - // da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; - // da2->bitblt.size_x = da2->bitblt.reg[0x33]; // pclog("scr %x dest %x x %x y %x\n", da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); if (da2->bitblt.y >= da2->bitblt.size_y) { da2->bitblt.exec = DA2_BLT_CDONE; } else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); + DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); } - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.size_x * 2 + da2->bitblt.destpitch + 2; - // } - // da2->bitblt.destaddr = da2->bitblt.reg[0x29] + da2->bitblt.x + da2->bitblt.y * 130 + 2; - ////da2->bitblt.srcaddr += 2; - // da2->bitblt.srcaddr = da2->bitblt.reg[0x12] * 72 + (da2->bitblt.x * 2 ) + (da2->bitblt.y * 3) + 2; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.size_x * 2 + da2->bitblt.destpitch + 2; break; case DA2_BLT_CDONE: // if (!(da2->bitblt.reg[0x20] & 0x20)) { @@ -1352,12 +1288,6 @@ da2_out(uint16_t addr, uint16_t val, void *p) val = 0x400; /* for debugging bitblt in Win 3.x */ #endif break; - // case LC_START_ADDRESS_HIGH: - // if (val == 0xff) /* adjust (need to confirm) */ - // val = 0; - // case LC_START_ADDRESS_LOW: - // val = 0; - // break; } da2->crtc[da2->crtcaddr] = val; switch (da2->crtcaddr) { @@ -1406,7 +1336,6 @@ da2_out(uint16_t addr, uint16_t val, void *p) case LV_PORT: // da2_iolog("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc); if (!da2->attrff) { - // da2->attraddr = val & 31; da2->attraddr = val & 0x3f; if ((val & 0x20) != (da2->attr_palette_enable & 0x20)) { da2->fullchange = 3; @@ -1596,11 +1525,7 @@ da2_in(uint16_t addr, void *p) case LC_DATA: if (da2->crtcaddr > 0x1f) return DA2_INVALIDACCESS16; - // if ((da2->crtcaddr == LC_START_ADDRESS_HIGH || da2->crtcaddr == LC_START_ADDRESS_LOW) - // & (da2->crtc[LC_VIEWPORT_SELECT] & 0x80)) - // temp = 0; - // else - temp = da2->crtc[da2->crtcaddr]; + temp = da2->crtc[da2->crtcaddr]; break; case LV_PORT: temp = da2->attraddr | da2->attr_palette_enable; @@ -1699,9 +1624,6 @@ da2_outw(uint16_t addr, uint16_t val, void *p) break; case 0x3EC: // da2_iolog("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc); - da2_iolog(" "); - // val = rightRotate(val, 8); - // da2_out(LG_DATA, val, da2); da2_out(LG_DATA, val >> 8, da2); /* reset masks for compatibility with Win 3.1 solitaire */ if (da2->gdcaddr == LG_MODE) { @@ -2347,18 +2269,11 @@ da2_recalctimings(da2_t *da2) double crtcconst; double _dispontime, _dispofftime, disptime; - // /* if output disabled or VGA passthrough */ - // if (da2->ioctl[LS_MODE] & 0x02 || !(da2->attrc[LV_COMPATIBILITY] & 0x08)) { - // da2->render = da2_render_blank; - // return; - // } - da2->vtotal = da2->crtc[LC_VERTICAL_TOTALJ] & 0xfff; da2->dispend = da2->crtc[LC_V_DISPLAY_ENABLE_END] & 0xfff; da2->vsyncstart = da2->crtc[LC_VERTICAL_SYNC_START] & 0xfff; da2->split = da2->crtc[LC_LINE_COMPAREJ] & 0xfff; da2->split -= 1; - // da2->split = 0xfff; da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff; da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END]; @@ -2374,21 +2289,16 @@ da2_recalctimings(da2_t *da2) da2->clock = da2->da2const; - // da2->lowres = da2->attrc[LV_MODE_CONTROL] & 0x40; - - // da2->interlace = 0; - - // if (da2->crtc[LC_VIEWPORT_SELECT] & 0x80 || da2->split == 0) if (da2->vtotal == 0) da2->vtotal = da2->vsyncstart = da2->vblankstart = 256; if (da2->htotal == 0) da2->htotal = da2->dispend = da2->hdisp = 64; if (da2->rowoffset == 0) da2->rowoffset = 64 * 2; /* To avoid causing a DBZ error */ - if (da2->split == 0) + if (da2->split == 0) /* To avoid a glitch in MODE 1 of OS/2 J1.3 DOSBox. */ da2->ma_latch = 0; else - da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; // w + b + da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; da2->ca_adj = 0; da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; @@ -2427,15 +2337,6 @@ da2_recalctimings(da2_t *da2) da2->hdisp *= 13; da2->char_width = 13; } - // if (!da2->scrblank && da2->attr_palette_enable) - //{ - // da2->render = da2_draw_text; - //} - - // da2_log("da2_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", da2_render, da2_render_text_40, da2_render_text_80, da2_render_8bpp_lowres, da2_render_8bpp_highres, da2_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); - - // if (da2->recalctimings_ex) - // da2->recalctimings_ex(da2); if (da2->vblankstart < da2->dispend) da2->dispend = da2->vblankstart; @@ -2446,7 +2347,7 @@ da2_recalctimings(da2_t *da2) _dispontime = da2->hdisp_time; da2_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, da2->hdisp); - // if (da2->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; _dispontime *= crtcconst; _dispofftime *= crtcconst; @@ -2785,10 +2686,8 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) index = da2->fctl[LF_MMIO_MODE] & 0x0f; index <<= 8; index |= da2->fctl[LF_MMIO_ADDR]; - // addr += index * 0x40; - // addr += index * 0x80; - da2_log("da2_mmio_w io %x, sl %x, 09 %x, ad %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO],da2->fctl[LF_MMIO_SEL], - da2->fctl[LF_MMIO_09],da2->fctl[LF_MMIO_ADDR], da2->fctl[LF_MMIO_MODE], addr, val); + // da2_log("da2_mmio_w io %x, sl %x, 09 %x, ad %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO],da2->fctl[LF_MMIO_SEL], + // da2->fctl[LF_MMIO_09],da2->fctl[LF_MMIO_ADDR], da2->fctl[LF_MMIO_MODE], addr, val); } switch (da2->fctl[LF_MMIO_MODE] & 0xf0) { case 0xb0: /* Gaiji RAM 1011 0000 */ @@ -2802,12 +2701,6 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) addr += index * 0x40; da2->mmio.ram[(DA2_GAIJIRAM_SBCS + addr) & DA2_MASK_GAIJIRAM] = val; // da2_log("da2_mmio_write %x %x %04X:%04X\n", addr, val, CS, cpu_state.pc); - // addr &= 0x7f;/* OS/2 write addr 1cf80-1cfc3, val xx */ - // if (addr >= DA2_BLT_MEMSIZE) - //{ - // da2_log("da2_mmio_write failed mem %x, addr %x, val %x\n", da2->fctl[LF_MMIO_MODE], addr, val); - // return; - // } break; default: da2_log("da2_mmio_write failed io %x, mm %x, addr %x, val %x\n", da2->ioctl[LS_MMIO] ,da2->fctl[LF_MMIO_MODE], addr, val); @@ -3138,8 +3031,6 @@ da2_poll(void *priv) // da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); da2->displine++; - // if (da2->interlace) - // da2->displine++; if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) { // da2_log("Vsync off at line %i\n",displine); da2->cgastat &= ~8; @@ -3153,7 +3044,6 @@ da2_poll(void *priv) // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); timer_advance_u64(&da2->timer, da2->dispontime); - // if (output) printf("Display on %f\n",vidtime); if (da2->dispon) da2->cgastat &= ~1; da2->hdisp_on = 0; From 392e3156bb47fbf2f5857a248c093a04e7b22e4e Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:10:49 +0900 Subject: [PATCH 0671/1190] disable debug code --- src/video/vid_ps55da2.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 09e3471a5..ec25db7c7 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -260,7 +260,7 @@ #define LG_SET_RESET_2 0x10 #ifndef RELEASE_BUILD -#define ENABLE_DA2_LOG 1 +// #define ENABLE_DA2_LOG 1 #endif #ifdef ENABLE_DA2_LOG @@ -300,6 +300,7 @@ da2_log(const char *fmt, ...) # endif #else # define da2_bltlog(fmt, ...) +# define da2_bltreglog(fmt, ...) #endif typedef struct da2_t { @@ -1291,13 +1292,13 @@ da2_out(uint16_t addr, uint16_t val, void *p) } da2->crtc[da2->crtcaddr] = val; switch (da2->crtcaddr) { - case LC_START_ADDRESS_HIGH: - case LC_START_ADDRESS_LOW: + // case LC_START_ADDRESS_HIGH: + // case LC_START_ADDRESS_LOW: /* The DOS J4.0 MODE 4 command and OS/2 driver write 0xFF00. OS/2 DOS MODE 1 setup reads this to set the base line, but it causes the screen glitch. */ - outb(0x680, da2->crtc[LC_START_ADDRESS_LOW]); - outb(0x680, da2->crtc[LC_START_ADDRESS_HIGH]); - break; + // outb(0x680, da2->crtc[LC_START_ADDRESS_LOW]); + // outb(0x680, da2->crtc[LC_START_ADDRESS_HIGH]); + // break; case LC_VIEWPORT_SELECT: /* backup some current crtc regs */ for (int i = LC_START_ADDRESS_HIGH; i <= LC_START_ADDRESS_LOW; i++) { From 4a4a7a342a89e963046a3f4ddd40994995560736 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 4 Apr 2025 09:42:22 +0900 Subject: [PATCH 0672/1190] PS55DA2: formatting, sorting --- src/video/vid_ps55da2.c | 852 ++++++++++++++++++++-------------------- 1 file changed, 427 insertions(+), 425 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index ec25db7c7..39adc3607 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -449,12 +449,12 @@ static void da2_bitblt_exec(void *p); static void da2_updatevidselector(da2_t *da2); static void da2_reset_ioctl(da2_t *da2); static void da2_reset(void *priv); -static uint16_t rightRotate(uint16_t data, uint8_t count); +static uint16_t da2_rightrotate(uint16_t data, uint8_t count); typedef union { uint32_t d; uint8_t b[4]; -} DA2_VidSeq32; +} vidseq32; typedef struct { uint32_t p8[8]; @@ -462,7 +462,7 @@ typedef struct { /* safety read for internal functions */ static uint32_t -DA2_vram_r(uint32_t addr, da2_t *da2) +da2_vram_r(uint32_t addr, da2_t *da2) { if (addr & ~DA2_MASK_VRAM) return DA2_INVALIDACCESS32; @@ -470,110 +470,14 @@ DA2_vram_r(uint32_t addr, da2_t *da2) } /* safety write for internal functions */ static void -DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) +da2_vram_w(uint32_t addr, uint8_t val, da2_t *da2) { if (addr & ~DA2_MASK_VRAM) return; da2->vram[addr] = val; return; } -/* get font data for bitblt operation */ -static uint32_t -getFontIBMJ(int32_t code, int line, int x, void *p) -{ - da2_t *da2 = (da2_t *) p; - uint32_t font = 0; - int fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ - if (code < 0x100) { /* SBCS 13x29 */ - code *= 0x40; - code += DA2_GAIJIRAM_SBCS + (line * 2) + x; - font = da2->mmio.ram[code]; - font <<= 8; - font |= da2->mmio.ram[code + 1]; - font <<= 16; - } else if ((code >= 0xb000) && (code <= 0xb75f)) { /* DBCS 26x29 */ - /* convert code->address in gaiji memory */ - code -= 0xb000; - code = (code * 0x80) + (line * 4) + x; - font = da2->mmio.ram[code]; - font <<= 8; - font |= da2->mmio.ram[code + 1]; - font <<= 8; - font |= da2->mmio.ram[code + 2]; - font <<= 8; - font |= da2->mmio.ram[code + 3]; - } - else - font = 0; - return font; -} -/* write pixel data with rop (Note: bitmask must be in big endian) */ -static void -DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) -{ - uint32_t writepx[8]; - destaddr &= 0xfffffffe; /* align to word address to work bit shift correctly */ - // da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); - da2->changedvram[(DA2_MASK_VRAMPLANE & destaddr) >> 9] = changeframecount; - destaddr <<= 3; - /* read destination data with big endian order */ - for (int i = 0; i < 8; i++) - writepx[i] = DA2_vram_r((destaddr + 24) | i, da2) - | (DA2_vram_r((destaddr + 16) | i, da2) << 8) - | (DA2_vram_r((destaddr + 8) | i, da2) << 16) - | (DA2_vram_r((destaddr + 0) | i, da2) << 24); - - DA2_VidSeq32 mask32in; - mask32in.d = (uint32_t) mask; - DA2_VidSeq32 mask32; - mask32.b[3] = mask32in.b[0]; - mask32.b[2] = mask32in.b[1]; - mask32.d &= 0xffff0000; - for (int i = 0; i < 8; i++) { - if (da2->bitblt.bitshift_destr > 0) - srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; -// #ifdef ENABLE_DA2_DEBUGBLT -// if (i == 0) { -// pclog("writeplane: src %08X mask %08X dest %08X\n", srcpx->p8[i], mask32.d, writepx[i]); -// } -// #endif - if (da2->bitblt.raster_op & 0x2010) /* NOT Src or NOT Pattern */ - srcpx->p8[i] = ~srcpx->p8[i] & mask32.d; - if (da2->bitblt.raster_op & 0x20) /* Dest NOT */ - writepx[i] = (~writepx[i] & mask32.d) | (writepx[i] & ~mask32.d); - switch (da2->bitblt.raster_op & 0x03) { - case 0x00: /* None */ - writepx[i] &= ~mask32.d; - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x01: /* AND */ - writepx[i] &= srcpx->p8[i] | ~mask32.d; - break; - case 0x02: /* OR */ - writepx[i] |= srcpx->p8[i] & mask32.d; - break; - case 0x03: /* XOR */ - writepx[i] ^= srcpx->p8[i] & mask32.d; - break; - } - } - for (int i = 0; i < 8; i++) { - DA2_vram_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); - DA2_vram_w((destaddr + 8) | i, (writepx[i] >> 16) & 0xff, da2); - } -} - -static void -DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t *da2) -{ - pixel32 srcpx; - /* fill data with input color */ - for (int i = 0; i < 8; i++) - srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0; /* read in word */ - - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); -} /* Param Desc 01 Color @@ -606,19 +510,115 @@ Param Desc 34 wy1, Dest Y 35 wy2, Size H */ +/* write pixel data with rop (Note: bitmask must be in big endian) */ static void -DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) +da2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2) +{ + uint32_t writepx[8]; + destaddr &= 0xfffffffe; /* align to word address to work bit shift correctly */ + // da2_log("DA2_WPDWB addr %x mask %x rop %x shift %d\n", destaddr, mask, da2->bitblt.raster_op, da2->bitblt.bitshift_destr); + da2->changedvram[(DA2_MASK_VRAMPLANE & destaddr) >> 9] = changeframecount; + destaddr <<= 3; + /* read destination data with big endian order */ + for (int i = 0; i < 8; i++) + writepx[i] = da2_vram_r((destaddr + 24) | i, da2) + | (da2_vram_r((destaddr + 16) | i, da2) << 8) + | (da2_vram_r((destaddr + 8) | i, da2) << 16) + | (da2_vram_r((destaddr + 0) | i, da2) << 24); + + vidseq32 mask32in; + mask32in.d = (uint32_t) mask; + vidseq32 mask32; + mask32.b[3] = mask32in.b[0]; + mask32.b[2] = mask32in.b[1]; + mask32.d &= 0xffff0000; + for (int i = 0; i < 8; i++) { + if (da2->bitblt.bitshift_destr > 0) + srcpx->p8[i] <<= 16 - da2->bitblt.bitshift_destr; +// #ifdef ENABLE_DA2_DEBUGBLT +// if (i == 0) { +// pclog("writeplane: src %08X mask %08X dest %08X\n", srcpx->p8[i], mask32.d, writepx[i]); +// } +// #endif + if (da2->bitblt.raster_op & 0x2010) /* NOT Src or NOT Pattern */ + srcpx->p8[i] = ~srcpx->p8[i] & mask32.d; + if (da2->bitblt.raster_op & 0x20) /* Dest NOT */ + writepx[i] = (~writepx[i] & mask32.d) | (writepx[i] & ~mask32.d); + switch (da2->bitblt.raster_op & 0x03) { + case 0x00: /* None */ + writepx[i] &= ~mask32.d; + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x01: /* AND */ + writepx[i] &= srcpx->p8[i] | ~mask32.d; + break; + case 0x02: /* OR */ + writepx[i] |= srcpx->p8[i] & mask32.d; + break; + case 0x03: /* XOR */ + writepx[i] ^= srcpx->p8[i] & mask32.d; + break; + } + } + for (int i = 0; i < 8; i++) { + da2_vram_w(destaddr | i, (writepx[i] >> 24) & 0xff, da2); + da2_vram_w((destaddr + 8) | i, (writepx[i] >> 16) & 0xff, da2); + } +} + +static void +da2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t *da2) +{ + pixel32 srcpx; + /* fill data with input color */ + for (int i = 0; i < 8; i++) + srcpx.p8[i] = (color & (1 << i)) ? 0xffffffff : 0; /* read in word */ + + da2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +static void +da2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2) { pixel32 srcpx; srcaddr &= 0xfffffffe; srcaddr <<= 3; for (int i = 0; i < 8; i++) - srcpx.p8[i] = DA2_vram_r((srcaddr + 24) | i, da2) - | (DA2_vram_r((srcaddr + 16) | i, da2) << 8) - | (DA2_vram_r((srcaddr + 8) | i, da2) << 16) - | (DA2_vram_r((srcaddr + 0) | i, da2) << 24); + srcpx.p8[i] = da2_vram_r((srcaddr + 24) | i, da2) + | (da2_vram_r((srcaddr + 16) | i, da2) << 8) + | (da2_vram_r((srcaddr + 8) | i, da2) << 16) + | (da2_vram_r((srcaddr + 0) | i, da2) << 24); - DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2); +} +/* get font data for bitblt operation */ +static uint32_t +getRAMFont(int32_t code, int line, int x, void *p) +{ + da2_t *da2 = (da2_t *) p; + uint32_t font = 0; + int fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ + if (code < 0x100) { /* SBCS 13x29 */ + code *= 0x40; + code += DA2_GAIJIRAM_SBCS + (line * 2) + x; + font = da2->mmio.ram[code]; + font <<= 8; + font |= da2->mmio.ram[code + 1]; + font <<= 16; + } else if ((code >= 0xb000) && (code <= 0xb75f)) { /* DBCS 26x29 */ + /* convert code->address in gaiji memory */ + code -= 0xb000; + code = (code * 0x80) + (line * 4) + x; + font = da2->mmio.ram[code]; + font <<= 8; + font |= da2->mmio.ram[code + 1]; + font <<= 8; + font |= da2->mmio.ram[code + 2]; + font <<= 8; + font |= da2->mmio.ram[code + 3]; + } + else + font = 0; + return font; } /* Reverse the bit order of attribute code IBGR to IRGB(used in Mode 3 and Cursor Color) */ static int8_t @@ -628,12 +628,12 @@ IBGRtoIRGB(uint8_t attr) return attr >>= 4; } static void -DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, uint32_t destaddr, uint16_t maskl, uint16_t maskr, da2_t *da2) +da2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, uint32_t destaddr, uint16_t maskl, uint16_t maskr, da2_t *da2) { pixel32 srcpx; uint8_t fg = (~attr >> 8) & 0x0f; uint8_t bg = (~attr >> 12) & 0x0f; - uint32_t font = getFontIBMJ(codeIBMJ, line, 0, da2); + uint32_t font = getRAMFont(codeIBMJ, line, 0, da2); uint32_t fontinv; if (width <= 2) { fontinv = ~font; @@ -641,12 +641,12 @@ DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, ui srcpx.p8[i] = (fg & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; } - DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); for (int i = 0; i < 8; i++) { srcpx.p8[i] = (fg & (1 << i)) ? font : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } - DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); } else { font = (font & 0xfff80000) | ((font & 0x0000ffff) << 3); fontinv = ~font; @@ -654,20 +654,20 @@ DA2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, ui srcpx.p8[i] = (fg & (1 << i)) ? font >> 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv >> 16 : 0; } - DA2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr, maskl, &srcpx, da2); for (int i = 0; i < 8; i++) { srcpx.p8[i] = (fg & (1 << i)) ? font : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv : 0; } if (da2->bitblt.destoption & 0x20) { - DA2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr + 2, maskr, &srcpx, da2); } else { - DA2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr + 2, 0xffff, &srcpx, da2); for (int i = 0; i < 8; i++) { srcpx.p8[i] = (fg & (1 << i)) ? font << 16 : 0; srcpx.p8[i] |= (bg & (1 << i)) ? fontinv << 16 : 0; } - DA2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); + da2_WritePlaneDataWithBitmask(destaddr + 4, maskr, &srcpx, da2); } } } @@ -677,7 +677,7 @@ pixel1tohex(uint32_t addr, int index, da2_t *da2) { uint8_t pixeldata = 0; for (int j = 0; j < 8; j++) { - if (DA2_vram_r(((addr << 3) | j) & (1 << (7 - index)), da2)) + if (da2_vram_r(((addr << 3) | j) & (1 << (7 - index)), da2)) pixeldata++; } return pixeldata; @@ -748,69 +748,69 @@ da2_bitblt_parse(da2_t *da2) { uint32_t value32; uint64_t value64; - switch (da2->bitblt.payload[0]) { - case 0x88: - case 0x89: - case 0x95: - value32 = da2->bitblt.payload[3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[2]; - da2_bltreglog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[1]] = value32; - break; - case 0x91: - value32 = da2->bitblt.payload[5]; - value32 <<= 8; - value32 |= da2->bitblt.payload[4]; - value32 <<= 8; - value32 |= da2->bitblt.payload[3]; - value32 <<= 8; - value32 |= da2->bitblt.payload[2]; - da2_bltreglog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); - da2->bitblt.reg[da2->bitblt.payload[1]] = value32; - break; - case 0x99: - value64 = da2->bitblt.payload[7]; - value64 <<= 8; - value64 = da2->bitblt.payload[6]; - value64 <<= 8; - value64 = da2->bitblt.payload[5]; - value64 <<= 8; - value64 |= da2->bitblt.payload[4]; - value64 <<= 8; - value64 |= da2->bitblt.payload[3]; - value64 <<= 8; - value64 |= da2->bitblt.payload[2]; - da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], - da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7]); - da2->bitblt.reg[da2->bitblt.payload[1]] = value64; - break; - case 0xa1: - value64 = da2->bitblt.payload[9]; - value64 <<= 8; - value64 |= da2->bitblt.payload[8]; - value64 <<= 8; - value64 |= da2->bitblt.payload[7]; - value64 <<= 8; - value64 |= da2->bitblt.payload[6]; - value64 <<= 8; - value64 |= da2->bitblt.payload[5]; - value64 <<= 8; - value64 |= da2->bitblt.payload[4]; - value64 <<= 8; - value64 |= da2->bitblt.payload[3]; - value64 <<= 8; - value64 |= da2->bitblt.payload[2]; - da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], - da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7], da2->bitblt.payload[8], da2->bitblt.payload[9]); - da2->bitblt.reg[da2->bitblt.payload[1]] = value64; - break; - case 0x00: /* Win 3.0 Clock writes invalid zero data. */ - break; - default: - da2_log("bltload: Unknown PreOP!\n"); - break; - } + switch (da2->bitblt.payload[0]) { + case 0x88: + case 0x89: + case 0x95: + value32 = da2->bitblt.payload[3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %04x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[1]] = value32; + break; + case 0x91: + value32 = da2->bitblt.payload[5]; + value32 <<= 8; + value32 |= da2->bitblt.payload[4]; + value32 <<= 8; + value32 |= da2->bitblt.payload[3]; + value32 <<= 8; + value32 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %08x (%d)\n", da2->bitblt.payload[0], da2->bitblt.payload[1], value32, value32); + da2->bitblt.reg[da2->bitblt.payload[1]] = value32; + break; + case 0x99: + value64 = da2->bitblt.payload[7]; + value64 <<= 8; + value64 = da2->bitblt.payload[6]; + value64 <<= 8; + value64 = da2->bitblt.payload[5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], + da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7]); + da2->bitblt.reg[da2->bitblt.payload[1]] = value64; + break; + case 0xa1: + value64 = da2->bitblt.payload[9]; + value64 <<= 8; + value64 |= da2->bitblt.payload[8]; + value64 <<= 8; + value64 |= da2->bitblt.payload[7]; + value64 <<= 8; + value64 |= da2->bitblt.payload[6]; + value64 <<= 8; + value64 |= da2->bitblt.payload[5]; + value64 <<= 8; + value64 |= da2->bitblt.payload[4]; + value64 <<= 8; + value64 |= da2->bitblt.payload[3]; + value64 <<= 8; + value64 |= da2->bitblt.payload[2]; + da2_bltreglog("[%02x] %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", da2->bitblt.payload[0], da2->bitblt.payload[1], da2->bitblt.payload[2], da2->bitblt.payload[3], + da2->bitblt.payload[4], da2->bitblt.payload[5], da2->bitblt.payload[6], da2->bitblt.payload[7], da2->bitblt.payload[8], da2->bitblt.payload[9]); + da2->bitblt.reg[da2->bitblt.payload[1]] = value64; + break; + case 0x00: /* Win 3.0 Clock writes invalid zero data. */ + break; + default: + da2_log("bltload: Unknown PreOP!\n"); + break; + } if (da2->bitblt.reg[0x20] & 0x01) { /* Execute Bitblt immediately (for OS/2 J1.3) */ da2->bitblt.exec = DA2_BLT_CLOAD; da2_bitblt_exec(da2); @@ -818,162 +818,162 @@ da2_bitblt_parse(da2_t *da2) /* clear payload memory */ memset(da2->bitblt.payload, 0x00, DA2_BLT_MEMSIZE); da2->bitblt.payload_addr = 0; - da2->bitblt.indata = 0; + da2->bitblt.indata = 0; } static void da2_bitblt_load(da2_t *da2) { - da2->bitblt.reg[0x20] = 0; /* need to stop execution */ + da2->bitblt.reg[0x20] = 0; /* need to stop execution */ #ifdef ENABLE_DA2_DEBUGBLT - for (int i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { - da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; - } - da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; - da2->bitblt.debug_reg_ip++; - if ((DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip) >= DA2_DEBUG_BLTLOG_MAX) - da2->bitblt.debug_reg_ip = 0; - da2->bitblt.debug_exesteps = 0; + for (int i = 0; i < DA2_DEBUG_BLTLOG_SIZE; i++) { + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip + i] = da2->bitblt.reg[i]; + } + da2->bitblt.debug_reg[DA2_DEBUG_BLTLOG_SIZE * (da2->bitblt.debug_reg_ip + 1) - 1] = 0; + da2->bitblt.debug_reg_ip++; + if ((DA2_DEBUG_BLTLOG_SIZE * da2->bitblt.debug_reg_ip) >= DA2_DEBUG_BLTLOG_MAX) + da2->bitblt.debug_reg_ip = 0; + da2->bitblt.debug_exesteps = 0; #endif - da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x03] >> 4) & 0x0f); /* set bit shift */ - da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; - da2->bitblt.destaddr = da2->bitblt.reg[0x29]; - da2->bitblt.size_x = da2->bitblt.reg[0x33]; - da2->bitblt.size_y = da2->bitblt.reg[0x35]; - da2->bitblt.destpitch = da2->bitblt.reg[0x21]; - da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; - /* - DOS/V Extension 1040x725 some DBCS uses 0xB0 others 0x90 - */ - da2->bitblt.destoption = da2->bitblt.reg[0x2F]; - if (da2->bitblt.destoption & 0x10) /* destaddr -= 2, length += 1; */ - { - da2->bitblt.destaddr -= 2; - da2->bitblt.size_x += 1; - da2->bitblt.destpitch -= 2; - da2->bitblt.srcpitch -= 2; - } - da2->bitblt.fcolor = da2->bitblt.reg[0x0]; - da2->bitblt.maskl = da2->bitblt.reg[0x8]; - da2->bitblt.maskr = da2->bitblt.reg[0x9]; - da2->bitblt.x = 0; - da2->bitblt.y = 0; - da2->bitblt.exec = DA2_BLT_CDONE; + da2->bitblt.bitshift_destr = ((da2->bitblt.reg[0x03] >> 4) & 0x0f); /* set bit shift */ + da2->bitblt.raster_op = da2->bitblt.reg[0x0b]; + da2->bitblt.destaddr = da2->bitblt.reg[0x29]; + da2->bitblt.size_x = da2->bitblt.reg[0x33]; + da2->bitblt.size_y = da2->bitblt.reg[0x35]; + da2->bitblt.destpitch = da2->bitblt.reg[0x21]; + da2->bitblt.srcpitch = da2->bitblt.reg[0x22]; + /* + DOS/V Extension 1040x725 some DBCS uses 0xB0 others 0x90 + */ + da2->bitblt.destoption = da2->bitblt.reg[0x2F]; + if (da2->bitblt.destoption & 0x10) /* destaddr -= 2, length += 1; */ + { + da2->bitblt.destaddr -= 2; + da2->bitblt.size_x += 1; + da2->bitblt.destpitch -= 2; + da2->bitblt.srcpitch -= 2; + } + da2->bitblt.fcolor = da2->bitblt.reg[0x0]; + da2->bitblt.maskl = da2->bitblt.reg[0x8]; + da2->bitblt.maskr = da2->bitblt.reg[0x9]; + da2->bitblt.x = 0; + da2->bitblt.y = 0; + da2->bitblt.exec = DA2_BLT_CDONE; - /* Put DBCS char used by OS/2 and DOS/V Extension */ - if (!(da2->bitblt.reg[0xb] & 0x08)) { - da2->bitblt.exec = DA2_BLT_CPUTCHAR; - da2->bitblt.fcolor = da2->bitblt.reg[0x1]; - da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; - da2->bitblt.destaddr += 2; + /* Put DBCS char used by OS/2 and DOS/V Extension */ + if (!(da2->bitblt.reg[0xb] & 0x08)) { + da2->bitblt.exec = DA2_BLT_CPUTCHAR; + da2->bitblt.fcolor = da2->bitblt.reg[0x1]; + da2->bitblt.srcaddr = da2->bitblt.reg[0x12]; + da2->bitblt.destaddr += 2; #ifdef ENABLE_DA2_DEBUGBLT - uint8_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; - uint8_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; - if (da2->bitblt.reg[0x12] < 0x100) { - sjis_h = 0x20; - sjis_l = da2->bitblt.reg[0x12]; - } else { - if (!(isKanji1(sjis_h))) - sjis_h = 0x3f; - if (!(isKanji2(sjis_l))) - sjis_l = 0x3f; - } - da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); + uint8_t sjis_h = IBMJtoSJIS(da2->bitblt.reg[0x12]) >> 8; + uint8_t sjis_l = IBMJtoSJIS(da2->bitblt.reg[0x12]) & 0xff; + if (da2->bitblt.reg[0x12] < 0x100) { + sjis_h = 0x20; + sjis_l = da2->bitblt.reg[0x12]; + } else { + if (!(isKanji1(sjis_h))) + sjis_h = 0x3f; + if (!(isKanji2(sjis_l))) + sjis_l = 0x3f; + } + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d, c=%c%c\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, sjis_h, sjis_l); #else -da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); + da2_log("put char src=%x, dest=%x, x=%d, y=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); #endif - } - /* Draw a line */ - else if (da2->bitblt.reg[0x5] == 0x43) { - da2->bitblt.exec = DA2_BLT_CLINE; - da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0xffff); - da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0xffff); - da2->bitblt.wx1 = (da2->bitblt.reg[0x32]) >> 16; - da2->bitblt.wx2 = (da2->bitblt.reg[0x33]) >> 16; - da2->bitblt.wy1 = (da2->bitblt.reg[0x34]) >> 16; - da2->bitblt.wy2 = (da2->bitblt.reg[0x35]) >> 16; - da2->bitblt.size_x = abs((int16_t)(da2->bitblt.reg[0x33] & 0xffff) - da2->bitblt.dest_x); - da2->bitblt.size_y = abs((int16_t)(da2->bitblt.reg[0x35] & 0xffff) - da2->bitblt.dest_y); - da2->bitblt.count = 0; - da2->bitblt.octdir = da2->bitblt.reg[0x2D]; - da2->bitblt.bitshift_destr = 0; - if (da2->bitblt.octdir & 0x04) /* dX > dY */ - da2->bitblt.d = 2 * da2->bitblt.size_y - da2->bitblt.size_x; - else - da2->bitblt.d = 2 * da2->bitblt.size_x - da2->bitblt.size_y; - da2->bitblt.x = da2->bitblt.dest_x; - da2->bitblt.y = da2->bitblt.dest_y; - da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%dn", - da2->bitblt.dest_x, da2->bitblt.dest_y, - da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); - da2_log(" x1=%d, x2=%d, y1=%d, y2=%d\n", - da2->bitblt.reg[0x32] & 0x7ff, da2->bitblt.reg[0x33] & 0x7ff, - da2->bitblt.reg[0x34] & 0x7ff, da2->bitblt.reg[0x35] & 0x7ff); - da2_log(" ux1=%d,ux2=%d,uy1=%d,uy2=%d\n", - (da2->bitblt.reg[0x32] >> 16) & 0x7ff, (da2->bitblt.reg[0x33] >> 16) & 0x7ff, - (da2->bitblt.reg[0x34] >> 16) & 0x7ff, (da2->bitblt.reg[0x35] >> 16) & 0x7ff); - } - /* Fill a rectangle (or draw a horizontal / vertical line) */ - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { - da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); - da2->bitblt.exec = DA2_BLT_CFILLRECT; - da2->bitblt.destaddr += 2; - } - /* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) { - da2->bitblt.exec = DA2_BLT_CFILLTILE; - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; - da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - /* Tiling a rectangle (transfer tile data multiple times) */ - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) { - da2->bitblt.exec = DA2_BLT_CFILLTILE; - da2->bitblt.destaddr += 2; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; - da2->bitblt.tile_w = da2->bitblt.reg[0x28]; - da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - /* Block copy */ - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { - da2->bitblt.exec = DA2_BLT_CCOPYF; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; - da2->bitblt.destaddr += 2; - da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } - /* Block copy but reversed direction */ - else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) { - da2->bitblt.exec = DA2_BLT_CCOPYR; - da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; - da2->bitblt.destaddr -= 2; - da2->bitblt.srcaddr -= 2; - da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", - da2->bitblt.srcaddr, da2->bitblt.destaddr, - da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), - da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), - da2->bitblt.size_x, da2->bitblt.size_y); - } + } + /* Draw a line */ + else if (da2->bitblt.reg[0x5] == 0x43) { + da2->bitblt.exec = DA2_BLT_CLINE; + da2->bitblt.dest_x = (da2->bitblt.reg[0x32] & 0xffff); + da2->bitblt.dest_y = (da2->bitblt.reg[0x34] & 0xffff); + da2->bitblt.wx1 = (da2->bitblt.reg[0x32]) >> 16; + da2->bitblt.wx2 = (da2->bitblt.reg[0x33]) >> 16; + da2->bitblt.wy1 = (da2->bitblt.reg[0x34]) >> 16; + da2->bitblt.wy2 = (da2->bitblt.reg[0x35]) >> 16; + da2->bitblt.size_x = abs((int16_t) (da2->bitblt.reg[0x33] & 0xffff) - da2->bitblt.dest_x); + da2->bitblt.size_y = abs((int16_t) (da2->bitblt.reg[0x35] & 0xffff) - da2->bitblt.dest_y); + da2->bitblt.count = 0; + da2->bitblt.octdir = da2->bitblt.reg[0x2D]; + da2->bitblt.bitshift_destr = 0; + if (da2->bitblt.octdir & 0x04) /* dX > dY */ + da2->bitblt.d = 2 * da2->bitblt.size_y - da2->bitblt.size_x; + else + da2->bitblt.d = 2 * da2->bitblt.size_x - da2->bitblt.size_y; + da2->bitblt.x = da2->bitblt.dest_x; + da2->bitblt.y = da2->bitblt.dest_y; + da2_log("drawline x=%d, y=%d, dx=%d, dy=%d, oct=%dn", + da2->bitblt.dest_x, da2->bitblt.dest_y, + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.octdir); + da2_log(" x1=%d, x2=%d, y1=%d, y2=%d\n", + da2->bitblt.reg[0x32] & 0x7ff, da2->bitblt.reg[0x33] & 0x7ff, + da2->bitblt.reg[0x34] & 0x7ff, da2->bitblt.reg[0x35] & 0x7ff); + da2_log(" ux1=%d,ux2=%d,uy1=%d,uy2=%d\n", + (da2->bitblt.reg[0x32] >> 16) & 0x7ff, (da2->bitblt.reg[0x33] >> 16) & 0x7ff, + (da2->bitblt.reg[0x34] >> 16) & 0x7ff, (da2->bitblt.reg[0x35] >> 16) & 0x7ff); + } + /* Fill a rectangle (or draw a horizontal / vertical line) */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x40 && da2->bitblt.reg[0x3D] == 0) { + da2_log("fillrect x=%d, y=%d, w=%d, h=%d, c=%d, 2f=%x, rowcount=%x\n", + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y, da2->bitblt.reg[0x0], da2->bitblt.reg[0x2F], da2->rowoffset * 2); + da2->bitblt.exec = DA2_BLT_CFILLRECT; + da2->bitblt.destaddr += 2; + } + /* Tiling a rectangle ??(transfer tile data multiple times) os/2 only */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x0040 && da2->bitblt.reg[0x3D] == 0x40) { + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + /* Tiling a rectangle (transfer tile data multiple times) */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x40) { + da2->bitblt.exec = DA2_BLT_CFILLTILE; + da2->bitblt.destaddr += 2; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2B]; + da2->bitblt.tile_w = da2->bitblt.reg[0x28]; + da2_log("copy tile src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2B] % (da2->rowoffset * 2), da2->bitblt.reg[0x2B] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + /* Block copy */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1040 && da2->bitblt.reg[0x3D] == 0x00) { + da2->bitblt.exec = DA2_BLT_CCOPYF; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr += 2; + da2_log("copy block src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } + /* Block copy but reversed direction */ + else if ((da2->bitblt.reg[0x5] & 0xfff0) == 0x1140 && da2->bitblt.reg[0x3D] == 0x00) { + da2->bitblt.exec = DA2_BLT_CCOPYR; + da2->bitblt.srcaddr = da2->bitblt.reg[0x2A]; + da2->bitblt.destaddr -= 2; + da2->bitblt.srcaddr -= 2; + da2_log("copy blockR src=%x, dest=%x, x1=%d, y1=%d, x2=%d, y2=%d, w=%d, h=%d\n", + da2->bitblt.srcaddr, da2->bitblt.destaddr, + da2->bitblt.reg[0x2A] % (da2->rowoffset * 2), da2->bitblt.reg[0x2A] / (da2->rowoffset * 2), + da2->bitblt.reg[0x29] % (da2->rowoffset * 2), da2->bitblt.reg[0x29] / (da2->rowoffset * 2), + da2->bitblt.size_x, da2->bitblt.size_y); + } } static void da2_bitblt_exec(void *p) @@ -981,7 +981,7 @@ da2_bitblt_exec(void *p) da2_t *da2 = (da2_t *) p; // timer_set_delay_u64(&da2->bitblt.timer, da2->bitblt.timerspeed); #ifdef ENABLE_DA2_DEBUGBLT_DETAIL - if(!(da2->bitblt.debug_exesteps & 0xff)) + if (!(da2->bitblt.debug_exesteps & 0xff)) da2_log("bitblt_exec: %d %d\n", da2->bitblt.exec, da2->bitblt.debug_exesteps); da2->bitblt.debug_exesteps++; #else @@ -998,19 +998,19 @@ da2_bitblt_exec(void *p) case DA2_BLT_CLINE: /* Draw a dot */ da2_bltlog("point: %d %d %d %d %d\n", da2->bitblt.x, da2->bitblt.y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); - int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; + int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; int pixelmask = da2->bitblt.x % 16; if (pixelmask >= 8) pixelmask = (0x8000 >> (pixelmask - 8)); else pixelmask = (0x80 >> pixelmask); - + /* check the current position is inside the window */ if (da2->bitblt.x < da2->bitblt.wx1 || da2->bitblt.x > da2->bitblt.wx2 || da2->bitblt.y < da2->bitblt.wy1 || da2->bitblt.y > da2->bitblt.wy2) ; else - DA2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); + da2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); da2->bitblt.count++; /* calculate the next position with Bresenham's line algorithm */ @@ -1053,7 +1053,7 @@ da2_bitblt_exec(void *p) case DA2_BLT_CFILLRECT: // da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); + da2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskr, da2); if (da2->bitblt.y >= da2->bitblt.size_y - 1) { da2->bitblt.exec = DA2_BLT_CDONE; } @@ -1061,36 +1061,38 @@ da2_bitblt_exec(void *p) da2->bitblt.y++; da2->bitblt.destaddr += da2->bitblt.destpitch + 2; } else if (da2->bitblt.x == 0) { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); + da2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, da2->bitblt.maskl, da2); da2->bitblt.x++; } else { - DA2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); + da2_DrawColorWithBitmask(da2->bitblt.destaddr, da2->bitblt.fcolor, 0xffff, da2); da2->bitblt.x++; } da2->bitblt.destaddr += 2; break; - case DA2_BLT_CFILLTILE: { - int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; - if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); - if (da2->bitblt.y >= da2->bitblt.size_y - 1) { - da2->bitblt.exec = DA2_BLT_CDONE; + case DA2_BLT_CFILLTILE: + { + int32_t tileaddr = da2->bitblt.srcaddr + (da2->bitblt.y % da2->bitblt.tile_w) * 2; + if (da2->bitblt.x >= da2->bitblt.size_x - 1) { + da2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + if (da2->bitblt.y >= da2->bitblt.size_y - 1) { + da2->bitblt.exec = DA2_BLT_CDONE; + } + da2->bitblt.x = 0; + da2->bitblt.y++; + da2->bitblt.destaddr += da2->bitblt.destpitch + 2; + } else if (da2->bitblt.x == 0) { + da2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2->bitblt.x++; + } else { + da2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); + da2->bitblt.x++; } - da2->bitblt.x = 0; - da2->bitblt.y++; - da2->bitblt.destaddr += da2->bitblt.destpitch + 2; - } else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); - da2->bitblt.x++; - } else { - DA2_CopyPlaneDataWithBitmask(tileaddr, da2->bitblt.destaddr, 0xffff, da2); - da2->bitblt.x++; + da2->bitblt.destaddr += 2; + break; } - da2->bitblt.destaddr += 2; - break; - } case DA2_BLT_CCOPYF: + case DA2_BLT_CCOPYF: if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); if (da2->bitblt.y >= da2->bitblt.size_y - 1) { da2->bitblt.exec = DA2_BLT_CDONE; } @@ -1099,10 +1101,10 @@ da2_bitblt_exec(void *p) da2->bitblt.destaddr += da2->bitblt.destpitch + 2; da2->bitblt.srcaddr += da2->bitblt.srcpitch + 2; } else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); da2->bitblt.x++; } else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); da2->bitblt.x++; } da2->bitblt.destaddr += 2; @@ -1110,7 +1112,7 @@ da2_bitblt_exec(void *p) break; case DA2_BLT_CCOPYR: if (da2->bitblt.x >= da2->bitblt.size_x - 1) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskr, da2); if (da2->bitblt.y >= da2->bitblt.size_y - 1) { da2->bitblt.exec = DA2_BLT_CDONE; } @@ -1121,10 +1123,10 @@ da2_bitblt_exec(void *p) da2->bitblt.destaddr -= 2; da2->bitblt.srcaddr -= 2; } else if (da2->bitblt.x == 0) { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, da2->bitblt.maskl, da2); da2->bitblt.x++; } else { - DA2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); + da2_CopyPlaneDataWithBitmask(da2->bitblt.srcaddr, da2->bitblt.destaddr, 0xffff, da2); da2->bitblt.x++; } da2->bitblt.destaddr -= 2; @@ -1135,7 +1137,7 @@ da2_bitblt_exec(void *p) if (da2->bitblt.y >= da2->bitblt.size_y) { da2->bitblt.exec = DA2_BLT_CDONE; } else { - DA2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); + da2_PutcharWithBitmask(da2->bitblt.srcaddr, da2->bitblt.size_x, da2->bitblt.fcolor, da2->bitblt.y, da2->bitblt.destaddr, da2->bitblt.maskl, da2->bitblt.maskr, da2); } da2->bitblt.y++; da2->bitblt.destaddr += da2->bitblt.size_x * 2 + da2->bitblt.destpitch + 2; @@ -1151,7 +1153,7 @@ da2_bitblt_exec(void *p) // if (da2->bitblt.indata) // da2->bitblt.exec = DA2_BLT_CLOAD; // else - da2->bitblt.exec = DA2_BLT_CIDLE; + da2->bitblt.exec = DA2_BLT_CIDLE; break; } } @@ -1171,6 +1173,47 @@ da2_bitblt_dopayload(void *priv) // timer_disable(&da2->bitblt.timer); } } +static void +da2_bitblt_addpayload(uint8_t val, void *p) +{ + da2_t *da2 = (da2_t *) p; + da2->bitblt.indata = 1; + if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) + da2_log("da2_mmio_write payload overflow! addr %x, val %x\n", da2->bitblt.payload_addr, val); + else { + if (da2->bitblt.payload_addr == 0) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + switch (val) { + case 0x88: + case 0x89: + case 0x95: + da2->bitblt.payload_opsize = 3; + break; + case 0x91: + da2->bitblt.payload_opsize = 5; + break; + case 0x99: + da2->bitblt.payload_opsize = 7; + break; + case 0xa1: + da2->bitblt.payload_opsize = 9; + break; + default: + da2_log("addpayload: Unknown PreOP! %x\n", val); + da2->bitblt.payload_addr = 0; /* ignore input */ + break; + } + } else if (da2->bitblt.payload_addr < da2->bitblt.payload_opsize) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_addr++; + } else if (da2->bitblt.payload_addr == da2->bitblt.payload_opsize) { + da2->bitblt.payload[da2->bitblt.payload_addr] = val; + da2->bitblt.payload_opsize = 0; /* reset */ + da2_bitblt_parse(da2); + } + } +} static void da2_out(uint16_t addr, uint16_t val, void *p) @@ -2052,9 +2095,9 @@ da2_render_textm3(da2_t *da2) int chr_wide = 0; // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); for (x = 0; x < da2->hdisp; x += 13) { - chr = DA2_vram_r(DA2_VM03_BASECHR + da2->ma, da2); - attr = DA2_vram_r(DA2_VM03_BASECHR + da2->ma + 1, da2); - extattr = DA2_vram_r(DA2_VM03_BASEEXATTR + da2->ma + 1, da2); + chr = da2_vram_r(DA2_VM03_BASECHR + da2->ma, da2); + attr = da2_vram_r(DA2_VM03_BASECHR + da2->ma + 1, da2); + extattr = da2_vram_r(DA2_VM03_BASEEXATTR + da2->ma + 1, da2); // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->ma << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; // if (da2->blink) bg &= ~0x8; @@ -2072,7 +2115,7 @@ da2_render_textm3(da2_t *da2) /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = DA2_vram_r(DA2_VM03_BASECHR + da2->ma + 2, da2); + chr_dbcs = da2_vram_r(DA2_VM03_BASECHR + da2->ma + 2, da2); chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ @@ -2443,19 +2486,19 @@ da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) case 0: /*Set*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->gdcsrc[i] & ~bitmask); // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask); - DA2_vram_w(addr | i, (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); + da2_vram_w(addr | i, (da2->gdcinput[i] & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 1: /*AND*/ // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask) & da2->gdcsrc[i]; - DA2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); + da2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 2: /*OR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) | da2->gdcsrc[i]; - DA2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); + da2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; case 3: /*XOR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask) ^ da2->gdcsrc[i]; - DA2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); + da2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask) | (da2->vram[addr | i] & ~bitmask), da2); break; } } @@ -2465,8 +2508,8 @@ da2_gdcropB(uint32_t addr,uint8_t bitmask, da2_t *da2) static void da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) { - if((addr & 8) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = rightRotate(bitmask, 8); - // if((addr & 8)) bitmask = rightRotate(bitmask, 8); + if((addr & 8) && !(da2->gdcreg[LG_COMMAND] & 0x08)) bitmask = da2_rightrotate(bitmask, 8); + // if((addr & 8)) bitmask = da2_rightrotate(bitmask, 8); uint8_t bitmask_l = bitmask & 0xff; uint8_t bitmask_h = bitmask >> 8; for (int i = 0; i < 8; i++) { @@ -2476,29 +2519,29 @@ da2_gdcropW(uint32_t addr, uint16_t bitmask, da2_t *da2) case 0: /*Set*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | (da2->gdcsrc[i] & ~bitmask_l); // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | ((da2->gdcsrc[i] >> 8) & ~bitmask_h); - DA2_vram_w(addr | i, (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); - DA2_vram_w((addr + 8) | i, ((da2->gdcinput[i] >> 8) & bitmask_h) + da2_vram_w(addr | i, (da2->gdcinput[i] & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + da2_vram_w((addr + 8) | i, ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 1: /*AND*/ // da2->vram[addr | i] = (da2->gdcinput[i] | ~bitmask_l) & da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) | ~bitmask_h) & (da2->gdcsrc[i] >> 8); - DA2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); - DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) + da2_vram_w(addr | i, ((da2->gdcinput[i] & da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + da2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) & (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 2: /*OR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) | da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) | (da2->gdcsrc[i] >> 8); - DA2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); - DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) + da2_vram_w(addr | i, ((da2->gdcinput[i] | da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + da2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) | (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; case 3: /*XOR*/ // da2->vram[addr | i] = (da2->gdcinput[i] & bitmask_l) ^ da2->gdcsrc[i]; // da2->vram[(addr + 8) | i] = ((da2->gdcinput[i] >> 8) & bitmask_h) ^ (da2->gdcsrc[i] >> 8); - DA2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); - DA2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) + da2_vram_w(addr | i, ((da2->gdcinput[i] ^ da2->gdcsrc[i]) & bitmask_l) | (da2->vram[addr | i] & ~bitmask_l), da2); + da2_vram_w((addr + 8) | i, (((da2->gdcinput[i] >> 8) ^ (da2->gdcsrc[i] >> 8)) & bitmask_h) | (da2->vram[(addr + 8) | i] & ~bitmask_h), da2); break; } @@ -2625,47 +2668,6 @@ da2_mmio_readw(uint32_t addr, void *p) } } static void -da2_bitblt_addpayload(uint8_t val, void *p) -{ - da2_t *da2 = (da2_t *) p; - da2->bitblt.indata = 1; - if (da2->bitblt.payload_addr >= DA2_BLT_MEMSIZE) - da2_log("da2_mmio_write payload overflow! addr %x, val %x\n", da2->bitblt.payload_addr, val); - else { - if (da2->bitblt.payload_addr == 0) { - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; - switch (val) { - case 0x88: - case 0x89: - case 0x95: - da2->bitblt.payload_opsize = 3; - break; - case 0x91: - da2->bitblt.payload_opsize = 5; - break; - case 0x99: - da2->bitblt.payload_opsize = 7; - break; - case 0xa1: - da2->bitblt.payload_opsize = 9; - break; - default: - da2_log("addpayload: Unknown PreOP! %x\n", val); - da2->bitblt.payload_addr = 0; /* ignore input */ - break; - } - } else if (da2->bitblt.payload_addr < da2->bitblt.payload_opsize) { - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_addr++; - } else if (da2->bitblt.payload_addr == da2->bitblt.payload_opsize) { - da2->bitblt.payload[da2->bitblt.payload_addr] = val; - da2->bitblt.payload_opsize = 0; /* reset */ - da2_bitblt_parse(da2); - } - } -} -static void da2_mmio_write(uint32_t addr, uint8_t val, void *p) { da2_t *da2 = (da2_t *) p; @@ -2765,7 +2767,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) case 2: /* equiv to vga write mode 1 */ for (int i = 0; i < 8; i++) if (da2->planemask & (1 << i)) - DA2_vram_w(addr | i, da2->gdcsrc[i], da2); + da2_vram_w(addr | i, da2->gdcsrc[i], da2); break; case 0:/* equiv to vga write mode 0 */ if (da2->gdcreg[LG_DATA_ROTATION] & 7) @@ -2773,7 +2775,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) if (bitmask == 0xff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->planemask & (1 << i)) - DA2_vram_w(addr | i, val, da2); + da2_vram_w(addr | i, val, da2); } else { for (int i = 0; i < 8; i++) if (da2->gdcreg[LG_ENABLE_SRJ] & (1 << i)) @@ -2800,12 +2802,12 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p) } } else { /* mode 3h text */ cycles -= video_timing_write_b; - DA2_vram_w(addr, val, da2); + da2_vram_w(addr, val, da2); da2->fullchange = 2; } } static uint16_t -rightRotate(uint16_t data, uint8_t count) +da2_rightrotate(uint16_t data, uint8_t count) { return (data >> count) | (data << (sizeof(data) * 8 - count)); } @@ -2863,18 +2865,18 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) case 2: for (int i = 0; i < 8; i++) if (da2->planemask & (1 << i)) { - DA2_vram_w(addr | i, da2->gdcsrc[i] & 0xff, da2); - DA2_vram_w((addr + 8) | i, da2->gdcsrc[i] >> 8, da2); + da2_vram_w(addr | i, da2->gdcsrc[i] & 0xff, da2); + da2_vram_w((addr + 8) | i, da2->gdcsrc[i] >> 8, da2); } break; case 0: if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); + val = da2_rightrotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); if (bitmask == 0xffff && !(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) { for (int i = 0; i < 8; i++) if (da2->planemask & (1 << i)) { - DA2_vram_w(addr | i, val & 0xff, da2); - DA2_vram_w((addr + 8) | i, val >> 8, da2); + da2_vram_w(addr | i, val & 0xff, da2); + da2_vram_w((addr + 8) | i, val >> 8, da2); } } else { for (int i = 0; i < 8; i++) @@ -2893,7 +2895,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p) break; case 3: if (da2->gdcreg[LG_DATA_ROTATION] & 15) - val = rightRotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); + val = da2_rightrotate(val, da2->gdcreg[LG_DATA_ROTATION] & 15); bitmask &= val; for (int i = 0; i < 8; i++) From b484bf1b45fd8c3c177a4d6cdaa5eccd7e182784 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:04:43 +0900 Subject: [PATCH 0673/1190] PS55DA2: Add a bracket to avoid compile warning --- src/video/vid_ps55da2.c | 92 +++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 39adc3607..7abdae157 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -996,60 +996,62 @@ da2_bitblt_exec(void *p) // da2->bitblt.indata = 0; break; case DA2_BLT_CLINE: - /* Draw a dot */ - da2_bltlog("point: %d %d %d %d %d\n", da2->bitblt.x, da2->bitblt.y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); - int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; - int pixelmask = da2->bitblt.x % 16; - if (pixelmask >= 8) - pixelmask = (0x8000 >> (pixelmask - 8)); - else - pixelmask = (0x80 >> pixelmask); + { + /* Draw a dot */ + da2_bltlog("point: %d %d %d %d %d\n", da2->bitblt.x, da2->bitblt.y, da2->bitblt.d, da2->bitblt.x, da2->bitblt.y); + int destaddr = da2->bitblt.y * (da2->rowoffset * 2) + da2->bitblt.x / 8; + int pixelmask = da2->bitblt.x % 16; + if (pixelmask >= 8) + pixelmask = (0x8000 >> (pixelmask - 8)); + else + pixelmask = (0x80 >> pixelmask); - /* check the current position is inside the window */ - if (da2->bitblt.x < da2->bitblt.wx1 || da2->bitblt.x > da2->bitblt.wx2 - || da2->bitblt.y < da2->bitblt.wy1 || da2->bitblt.y > da2->bitblt.wy2) - ; - else - da2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); - da2->bitblt.count++; + /* check the current position is inside the window */ + if (da2->bitblt.x < da2->bitblt.wx1 || da2->bitblt.x > da2->bitblt.wx2 + || da2->bitblt.y < da2->bitblt.wy1 || da2->bitblt.y > da2->bitblt.wy2) + ; + else + da2_DrawColorWithBitmask(destaddr, da2->bitblt.fcolor, pixelmask, da2); + da2->bitblt.count++; - /* calculate the next position with Bresenham's line algorithm */ - if (da2->bitblt.octdir & 0x04) { /* dX > dY */ - if (da2->bitblt.octdir & 0x02) { - da2->bitblt.x++; - } else { - da2->bitblt.x--; - } - if (da2->bitblt.d >= 0) { - da2->bitblt.d -= (2 * da2->bitblt.size_x); - if (da2->bitblt.octdir & 0x01) { - da2->bitblt.y++; - } else { - da2->bitblt.y--; - } - } - da2->bitblt.d += (2 * da2->bitblt.size_y); - if (da2->bitblt.count >= da2->bitblt.size_x) - da2->bitblt.exec = DA2_BLT_CDONE; - } else { - if (da2->bitblt.octdir & 0x01) { - da2->bitblt.y++; - } else { - da2->bitblt.y--; - } - if (da2->bitblt.d >= 0) { - da2->bitblt.d -= (2 * da2->bitblt.size_y); + /* calculate the next position with Bresenham's line algorithm */ + if (da2->bitblt.octdir & 0x04) { /* dX > dY */ if (da2->bitblt.octdir & 0x02) { da2->bitblt.x++; } else { da2->bitblt.x--; } + if (da2->bitblt.d >= 0) { + da2->bitblt.d -= (2 * da2->bitblt.size_x); + if (da2->bitblt.octdir & 0x01) { + da2->bitblt.y++; + } else { + da2->bitblt.y--; + } + } + da2->bitblt.d += (2 * da2->bitblt.size_y); + if (da2->bitblt.count >= da2->bitblt.size_x) + da2->bitblt.exec = DA2_BLT_CDONE; + } else { + if (da2->bitblt.octdir & 0x01) { + da2->bitblt.y++; + } else { + da2->bitblt.y--; + } + if (da2->bitblt.d >= 0) { + da2->bitblt.d -= (2 * da2->bitblt.size_y); + if (da2->bitblt.octdir & 0x02) { + da2->bitblt.x++; + } else { + da2->bitblt.x--; + } + } + da2->bitblt.d += (2 * da2->bitblt.size_x); + if (da2->bitblt.count >= da2->bitblt.size_y) + da2->bitblt.exec = DA2_BLT_CDONE; } - da2->bitblt.d += (2 * da2->bitblt.size_x); - if (da2->bitblt.count >= da2->bitblt.size_y) - da2->bitblt.exec = DA2_BLT_CDONE; + break; } - break; case DA2_BLT_CFILLRECT: // da2_log("%x %x %x\n", da2->bitblt.destaddr, da2->bitblt.x, da2->bitblt.y); if (da2->bitblt.x >= da2->bitblt.size_x - 1) { From d3d5d3e7805d8c01b80d714057089b6deead4614 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 4 Apr 2025 18:19:28 +0200 Subject: [PATCH 0674/1190] Fix the calculation of the number of sectors per packet and stop the transfer when the total sector count has reached zero, fixes #5432. --- src/scsi/scsi_cdrom.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 9ae65be74..e5689dd76 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -1055,7 +1055,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int ret = -1; } else { ret = 1; - for (int i = 0; (i < num) && (ret > 0); i++) { + for (int i = 0; (i < num) && (ret > 0) && (dev->sector_len > 0); i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + dev->buffer_pos, dev->sector_pos, msf, type, flags, &temp_len, vendor_type); @@ -1070,7 +1070,11 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int if ((dev->drv->bus_type != CDROM_BUS_SCSI) && (scsi_cdrom_current_mode(dev) != 2)) { - num = (dev->packet_len / dev->block_len); + num = (dev->tf->request_length < dev->block_len) ? + dev->block_len : dev->tf->request_length; + num = (num / dev->block_len) * dev->block_len; + if (num > dev->sector_len) + num = dev->sector_len; } } From 1c38e059c4b9074ad17729a2dfe981e90d1a000c Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 4 Apr 2025 18:29:28 +0200 Subject: [PATCH 0675/1190] PS/55 DA2: Fix warnings. --- src/video/vid_ps55da2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 7abdae157..9a95e6ce6 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -596,7 +596,9 @@ getRAMFont(int32_t code, int line, int x, void *p) { da2_t *da2 = (da2_t *) p; uint32_t font = 0; +#ifdef RESERVED_FOR_FUTURE_USE int fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ +#endif if (code < 0x100) { /* SBCS 13x29 */ code *= 0x40; code += DA2_GAIJIRAM_SBCS + (line * 2) + x; @@ -620,6 +622,7 @@ getRAMFont(int32_t code, int line, int x, void *p) font = 0; return font; } +#ifdef RESERVED_FOR_FUTURE_USE /* Reverse the bit order of attribute code IBGR to IRGB(used in Mode 3 and Cursor Color) */ static int8_t IBGRtoIRGB(uint8_t attr) @@ -627,6 +630,7 @@ IBGRtoIRGB(uint8_t attr) attr = ((attr & 0x01) << 6) | ((attr & 0x02) << 4) | ((attr & 0x04) << 2) | ((attr & 0x08) << 4); return attr >>= 4; } +#endif static void da2_PutcharWithBitmask(uint32_t codeIBMJ, int width, uint16_t attr, int line, uint32_t destaddr, uint16_t maskl, uint16_t maskr, da2_t *da2) { From fd2214f54471c02bea2c99deda54ac138f5d4f43 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 4 Apr 2025 18:55:22 +0200 Subject: [PATCH 0676/1190] Intel Classic/PCI: Return input port (P1) bit 4 clear, fixes #5435. --- src/device/kbc_at.c | 59 +++++++++++++++++++++++++++++++----- src/machine/m_at_386dx_486.c | 5 +-- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index abb10d108..f8fd33e62 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1070,10 +1070,14 @@ write64_generic(void *priv, uint8_t val) fixed_bits |= 8; /* (B0 or F0) | (0x04 or 0x0c) */ kbc_delay_to_ob(dev, dev->p1 | fixed_bits, 0, 0x00); - } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) { /* (B0 or F0) | (0x08 or 0x0c) */ - kbc_delay_to_ob(dev, ((dev->p1 | fixed_bits) & 0xf0) | (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c), 0, 0x00); - else if (kbc_ven == KBC_VEN_COMPAQ) + uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c); + if (!strcmp(machine_get_internal_name(), "alfredo")) + p1_out &= 0xef; + kbc_delay_to_ob(dev, p1_out, 0, 0x00); + } else if (kbc_ven == KBC_VEN_COMPAQ) kbc_delay_to_ob(dev, dev->p1 | (hasfpu ? 0x00 : 0x04), 0, 0x00); else /* (B0 or F0) | (0x04 or 0x44) */ @@ -1578,8 +1582,13 @@ write64_phoenix(void *priv, uint8_t val) case 0xd5: /* Read MultiKey code revision level */ kbc_at_log("ATkbc: Phoenix - Read MultiKey code revision level\n"); if (dev->misc_flags & FLAG_PS2) { - kbc_at_queue_add(dev, 0x04); - kbc_at_queue_add(dev, 0x16); + if (dev->flags & DEVICE_PCI) { + kbc_at_queue_add(dev, 0x04); + kbc_at_queue_add(dev, 0x16); + } else { + kbc_at_queue_add(dev, 0x01); + kbc_at_queue_add(dev, 0x38); + } } else { kbc_at_queue_add(dev, 0x01); kbc_at_queue_add(dev, 0x29); @@ -1598,9 +1607,15 @@ write64_phoenix(void *priv, uint8_t val) case 0xd7: /* Read MultiKey model numbers */ kbc_at_log("ATkbc: Phoenix - Read MultiKey model numbers\n"); if (dev->misc_flags & FLAG_PS2) { - kbc_at_queue_add(dev, 0x02); - kbc_at_queue_add(dev, 0x87); - kbc_at_queue_add(dev, 0x02); + if (dev->flags & DEVICE_PCI) { + kbc_at_queue_add(dev, 0x02); + kbc_at_queue_add(dev, 0x87); + kbc_at_queue_add(dev, 0x02); + } else { + kbc_at_queue_add(dev, 0x99); + kbc_at_queue_add(dev, 0x75); + kbc_at_queue_add(dev, 0x01); + } } else { kbc_at_queue_add(dev, 0x90); kbc_at_queue_add(dev, 0x88); @@ -2608,6 +2623,20 @@ const device_t keyboard_ps2_ami_device = { .config = NULL }; +const device_t keyboard_ps2_compaq_device = { + .name = "PS/2 Keyboard (Compaq)", + .internal_name = "keyboard_at_compaq", + .flags = DEVICE_KBC, + .local = KBC_TYPE_PS2_1 | KBC_VEN_COMPAQ, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_holtek_device = { .name = "PS/2 Keyboard (Holtek)", .internal_name = "keyboard_ps2_holtek", @@ -2775,3 +2804,17 @@ const device_t keyboard_ps2_acer_pci_device = { .force_redraw = NULL, .config = NULL }; + +const device_t keyboard_ps2_phoenix_pci_device = { + .name = "PS/2 Keyboard (Phoenix)", + .internal_name = "keyboard_ps2_acer_pci", + .flags = DEVICE_KBC | DEVICE_PCI, + .local = KBC_TYPE_PS2_1 | KBC_VEN_PHOENIX, + .init = kbc_at_init, + .close = kbc_at_close, + .reset = kbc_at_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 7f285af65..4e659dd77 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1281,14 +1281,15 @@ machine_at_ninja_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x05, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 1, 2); pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 2, 1); pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 1, 2, 1); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_phoenix_device); device_add(&intel_flash_bxt_ami_device); device_add(&i420ex_device); From 14ffb89f4d01fe01353e97edf7b874d9f6944477 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 5 Apr 2025 01:49:54 +0600 Subject: [PATCH 0677/1190] SAASound filter fixes --- src/sound/saasound/SAAImpl.cpp | 1 - src/sound/saasound/SAAImpl.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp index f136eefc6..cb5d8f739 100644 --- a/src/sound/saasound/SAAImpl.cpp +++ b/src/sound/saasound/SAAImpl.cpp @@ -306,7 +306,6 @@ void scale_for_output(unsigned int left_input, unsigned int right_input, void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) { unsigned int left_mixed, right_mixed; - static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; #if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) BYTE* pBufferStart = pBuffer; diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h index 61fa79c58..6cd3048fe 100755 --- a/src/sound/saasound/SAAImpl.h +++ b/src/sound/saasound/SAAImpl.h @@ -36,6 +36,8 @@ private: unsigned int m_nSampleRate; unsigned int m_nOversample; bool m_bHighpass; + double filterout_z1_left_mixed = 0; + double filterout_z1_right_mixed = 0; #ifdef USE_CONFIG_FILE SAAConfig m_Config; #endif From 6d2128ab0573cfdc0cf5d31a4437d051de91123c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 5 Apr 2025 23:59:49 +0600 Subject: [PATCH 0678/1190] Make Qt shortcuts actually work in fullscreen Also removes hacks related to fullscreen. --- src/qt/qt_main.cpp | 4 --- src/qt/qt_mainwindow.cpp | 59 +++++++++++++++++++--------------------- src/qt/qt_mainwindow.hpp | 1 - 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 2ef797bd1..1f1dd6b49 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -194,8 +194,6 @@ win_keyboard_handle(uint32_t scancode, int up, int e0, int e1) it's not an invalid scan code. */ if (scancode != 0xFFFF) keyboard_input(!up, scancode); - - main_window->checkFullscreenHotkey(); } } @@ -370,8 +368,6 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) else if ((lpKdhs->scanCode == 0x3e) && (lpKdhs->flags & LLKHF_ALTDOWN) && !(lpKdhs->flags & (LLKHF_UP | LLKHF_EXTENDED))) ret = TRUE; - else if ((lpKdhs->scanCode == 0x49) && bCtrlDown && !(lpKdhs->flags & LLKHF_UP)) - ret = TRUE; else if ((lpKdhs->scanCode >= 0x5b) && (lpKdhs->scanCode <= 0x5d) && (lpKdhs->flags & LLKHF_EXTENDED)) ret = TRUE; else if (inhibit_multimedia_keys diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 4c04ce76e..806e8e0e6 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -674,6 +674,13 @@ MainWindow::MainWindow(QWidget *parent) /* Remove default Shift+F10 handler, which unfocuses keyboard input even with no context menu. */ connect(new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F10), this), &QShortcut::activated, this, [](){}); + auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this); + windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); + connect(windowedShortcut, &QShortcut::activated, this, [this] () { + if (video_fullscreen) + ui->actionFullscreen->trigger(); + }); + connect(this, &MainWindow::initRendererMonitor, this, &MainWindow::initRendererMonitorSlot); connect(this, &MainWindow::initRendererMonitorForNonQtThread, this, &MainWindow::initRendererMonitorSlot, Qt::BlockingQueuedConnection); connect(this, &MainWindow::destroyRendererMonitor, this, &MainWindow::destroyRendererMonitorSlot); @@ -696,6 +703,22 @@ MainWindow::MainWindow(QWidget *parent) }); #endif + QTimer::singleShot(0, this, [this]() { + for (auto curObj : this->menuBar()->children()) { + if (qobject_cast(curObj)) { + auto menu = qobject_cast(curObj); + for (auto curObj2 : menu->children()) { + if (qobject_cast(curObj2)) { + auto action = qobject_cast(curObj2); + if (!action->shortcut().isEmpty()) { + this->insertAction(nullptr, action); + } + } + } + } + } + }); + actGroup = new QActionGroup(this); actGroup->addAction(ui->actionCursor_Puck); actGroup->addAction(ui->actionPen); @@ -833,6 +856,11 @@ MainWindow::initRendererMonitorSlot(int monitor_index) }); secondaryRenderer->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); secondaryRenderer->setWindowTitle(QObject::tr("86Box Monitor #") + QString::number(monitor_index + 1)); + secondaryRenderer->setContextMenuPolicy(Qt::PreventContextMenu); + + for (int i = 0; i < this->actions().size(); i++) { + secondaryRenderer->addAction(this->actions()[i]); + } if (vid_resize == 2) secondaryRenderer->setFixedSize(fixed_size_x, fixed_size_y); @@ -1360,18 +1388,9 @@ MainWindow::keyPressEvent(QKeyEvent *event) #endif } - checkFullscreenHotkey(); - if (keyboard_ismsexit()) plat_mouse_capture(0); - if ((video_fullscreen > 0) && (keyboard_recv_ui(0x1D) || keyboard_recv_ui(0x11D))) { - if (keyboard_recv_ui(0x57)) - ui->actionTake_screenshot->trigger(); - else if (keyboard_recv_ui(0x58)) - pc_send_cad(); - } - event->accept(); } @@ -1403,28 +1422,6 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) processKeyboardInput(false, event->nativeScanCode()); #endif } - - checkFullscreenHotkey(); -} - -void -MainWindow::checkFullscreenHotkey() -{ - if (!fs_off_signal && video_fullscreen && keyboard_isfsexit()) { - /* Signal "exit fullscreen mode". */ - fs_off_signal = true; - } else if (fs_off_signal && video_fullscreen && keyboard_isfsexit_up()) { - ui->actionFullscreen->trigger(); - fs_off_signal = false; - } - - if (!fs_on_signal && !video_fullscreen && keyboard_isfsenter()) { - /* Signal "enter fullscreen mode". */ - fs_on_signal = true; - } else if (fs_on_signal && !video_fullscreen && keyboard_isfsenter_up()) { - ui->actionFullscreen->trigger(); - fs_on_signal = false; - } } QSize diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index f1c6cadf6..5c8bd388b 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -31,7 +31,6 @@ public: void blitToWidget(int x, int y, int w, int h, int monitor_index); QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); - void checkFullscreenHotkey(); void reloadAllRenderers(); std::array, 8> renderers; From 375590b93b0939154513e248d46d281bf0a3f0c9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Apr 2025 01:05:12 +0200 Subject: [PATCH 0679/1190] Bochs SVGA: Add some sanity check to avoid the LFB and BIOS being mapped to either at the very bottom or top of the memory space. --- src/video/vid_bochs_vbe.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index 84fb110c6..ac7bc00cb 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -686,7 +686,7 @@ bochs_vbe_pci_read(const int func, const int addr, void *priv) ret = dev->pci_rom_enable & 0x01; break; case 0x32: - ret = dev->rom_addr & 0xff; + ret = dev->rom_addr & 0xfc; break; case 0x33: ret = (dev->rom_addr & 0xff00) >> 8; @@ -743,6 +743,7 @@ bochs_vbe_pci_write(const int func, const int addr, const uint8_t val, void *pri mem_mapping_disable(&dev->linear_mapping_2); mem_mapping_disable(&dev->linear_mapping); mem_mapping_disable(&dev->svga.mapping); + mem_mapping_disable(&dev->bios_rom.mapping); if (dev->pci_conf_status & PCI_COMMAND_IO) { io_sethandler(0x03c0, 0x0020, bochs_vbe_in, NULL, NULL, bochs_vbe_out, NULL, NULL, dev); @@ -751,11 +752,13 @@ bochs_vbe_pci_write(const int func, const int addr, const uint8_t val, void *pri } if (dev->pci_conf_status & PCI_COMMAND_MEM) { mem_mapping_enable(&dev->svga.mapping); - if (dev->pci_regs[0x13] != 0x00) { + if ((dev->pci_regs[0x13] != 0x00) && (dev->pci_regs[0x13] != 0xff)) { mem_mapping_enable(&dev->linear_mapping); if (dev->pci_regs[0x13] != 0xe0) mem_mapping_enable(&dev->linear_mapping_2); } + if (dev->pci_rom_enable && (dev->rom_addr != 0x0000) && (dev->rom_addr < 0xfff8)) + mem_mapping_set_addr(&dev->bios_rom.mapping, dev->rom_addr << 16, 0x10000); } break; case 0x13: @@ -764,7 +767,7 @@ bochs_vbe_pci_write(const int func, const int addr, const uint8_t val, void *pri mem_mapping_disable(&dev->linear_mapping_2); mem_mapping_disable(&dev->linear_mapping); - if ((dev->pci_conf_status & PCI_COMMAND_MEM) && (val != 0x00)) { + if ((dev->pci_conf_status & PCI_COMMAND_MEM) && (val != 0x00) && (val != 0xff)) { mem_mapping_set_addr(&dev->linear_mapping, val << 24, 0x01000000); if (val != 0xe0) mem_mapping_set_addr(&dev->linear_mapping_2, 0xe0000000, 0x01000000); @@ -776,18 +779,26 @@ bochs_vbe_pci_write(const int func, const int addr, const uint8_t val, void *pri case 0x30: dev->pci_rom_enable = val & 0x01; mem_mapping_disable(&dev->bios_rom.mapping); - if (dev->pci_rom_enable) + if (dev->pci_rom_enable && (dev->pci_conf_status & PCI_COMMAND_MEM) && + (dev->rom_addr != 0x0000) && (dev->rom_addr < 0xfff8)) { mem_mapping_set_addr(&dev->bios_rom.mapping, dev->rom_addr << 16, 0x10000); + } break; case 0x32: dev->rom_addr = (dev->rom_addr & 0xff00) | (val & 0xfc); - if (dev->pci_rom_enable) + mem_mapping_disable(&dev->bios_rom.mapping); + if (dev->pci_rom_enable && (dev->pci_conf_status & PCI_COMMAND_MEM) && + (dev->rom_addr != 0x0000) && (dev->rom_addr < 0xfff8)) { mem_mapping_set_addr(&dev->bios_rom.mapping, dev->rom_addr << 16, 0x10000); + } break; case 0x33: dev->rom_addr = (dev->rom_addr & 0x00ff) | (val << 8); - if (dev->pci_rom_enable) + mem_mapping_disable(&dev->bios_rom.mapping); + if (dev->pci_rom_enable && (dev->pci_conf_status & PCI_COMMAND_MEM) && + (dev->rom_addr != 0x0000) && (dev->rom_addr < 0xfff8)) { mem_mapping_set_addr(&dev->bios_rom.mapping, dev->rom_addr << 16, 0x10000); + } break; } } From 06bacb6912be8688cb3f617a4e4edb02195ae3f0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 7 Apr 2025 01:01:26 +0600 Subject: [PATCH 0680/1190] Bochs SVGA: Buffer window switching now works properly --- src/video/vid_bochs_vbe.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index ac7bc00cb..6dc015fb0 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -338,20 +338,13 @@ bochs_vbe_recalctimings(svga_t* svga) svga->rowoffset = (dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] / 2) >> 3; svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] >> 3); + + svga->fullchange = 3; } else { svga->rowoffset = dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8)); svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + - (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); - } - if (svga->ma_latch != dev->ma_latch_old) { - if (svga->bpp == 4) { - svga->maback = (svga->maback - (dev->ma_latch_old << 2)) + - (svga->ma_latch << 2); - } else { - svga->maback = (svga->maback - (dev->ma_latch_old)) + - (svga->ma_latch); - dev->ma_latch_old = svga->ma_latch; - } + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); + svga->fullchange = 3; } if (svga->bpp == 4) @@ -482,18 +475,10 @@ bochs_vbe_outw(const uint16_t addr, const uint16_t val, void *priv) } else { svga->rowoffset = dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8)); svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + - (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); - } - if (svga->ma_latch != dev->ma_latch_old) { - if (svga->bpp == 4) { - svga->maback = (svga->maback - (dev->ma_latch_old << 2)) + - (svga->ma_latch << 2); - } else { - svga->maback = (svga->maback - (dev->ma_latch_old)) + - (svga->ma_latch); - dev->ma_latch_old = svga->ma_latch; - } + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); } + + svga->fullchange = 3; } else svga_recalctimings(&dev->svga); From 449c224ff7dd4640088321c3befa65c4a13ab5f7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 6 Apr 2025 21:23:53 +0200 Subject: [PATCH 0681/1190] SiS 471: Fix array out of bounds writes. --- src/chipset/sis_85c4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 6e26a4751..537675a85 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -375,7 +375,7 @@ sis_85c4xx_init(const device_t *info) dev->reg_base = info->local & 0xff; if (dev->is_471) { - dev->reg_last = dev->reg_base + 0x76; + dev->reg_last = 0x76; dev->smram = smram_add(); From e48d64de4572e8a42217f51e2c69327f0d1fec64 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 01:44:12 +0200 Subject: [PATCH 0682/1190] SCSI CD-ROM/Disk/MO/ZIP: Treat data commands with request length 0 in ATAPI PIO mode as non-data commands, also allow WIN_SRST to go through BSY, fixes the regressions introduced in build 6731 reported by JVERNET. --- src/disk/hdc_ide.c | 51 +++++++++++++++++++++++++++++++------------ src/disk/mo.c | 5 ++++- src/disk/zip.c | 5 ++++- src/scsi/scsi_cdrom.c | 20 ++++++++++++----- src/scsi/scsi_disk.c | 5 ++++- 5 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 01690cd70..04e580e72 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1208,7 +1208,9 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide->tf->atastat = BSY_STAT; if (ide->tf->pos >= dev->packet_len) { - ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); + // ide_log("%i bytes %s, command done\n", ide->tf->pos, out ? "written" : "read"); + ide_log("%i bytes %s, command done, %i sectors left\n", ide->tf->pos, out ? "written" : "read", + dev->sector_len); ide->tf->pos = dev->request_pos = 0; @@ -1262,13 +1264,12 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_atapi_callback(ide); ide_set_callback(ide, 0.0); } else { - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; - if (ide->phase_data_out != NULL) (void) ide->phase_data_out(dev); - ide_atapi_callback(ide); + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); } } } else { @@ -1280,10 +1281,9 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) if (ide->command_stop != NULL) ide->command_stop(dev); - ide->sc->packet_status = PHASE_COMPLETE; - ide->sc->callback = 0.0; - - ide_atapi_callback(ide); + if ((ide->sc->packet_status == PHASE_COMPLETE) && + (ide->sc->callback == 0.0)) + ide_atapi_callback(ide); } } else if (ide->read != NULL) ide->read(dev); @@ -1299,8 +1299,8 @@ ide_atapi_packet_read(ide_t *ide) uint16_t ret = 0; if (dev && dev->temp_buffer && (dev->packet_status == PHASE_DATA_IN)) { - ide_log("PHASE_DATA_IN read: %i, %i, %i, %i\n", - dev->request_pos, dev->max_transfer_len, ide->tf->pos, dev->packet_len); + /* ide_log("PHASE_DATA_IN read: %i, %i, %i, %i\n", + dev->request_pos, dev->max_transfer_len, ide->tf->pos, dev->packet_len); */ bufferw = (uint16_t *) dev->temp_buffer; @@ -1722,7 +1722,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) break; case 0x7: /* Command register */ - if (ide->tf->atastat & (BSY_STAT | DRQ_STAT)) + if ((ide->tf->atastat & (BSY_STAT | DRQ_STAT)) && + ((val != WIN_SRST) || (ide->type != IDE_ATAPI))) break; if ((ide->type == IDE_NONE) || ((ide->type & IDE_SHADOW) && (val != WIN_DRIVE_DIAGNOSTICS))) @@ -2158,7 +2159,8 @@ ide_read_alt_status(UNUSED(const uint16_t addr), void *priv) if (!(addr & 0x0001)) ret = ide_status(ide, ide_drives[ch ^ 1], ch); - ide_log("[%04X:%08X] ide_read_alt_status(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); + // ide_log("[%04X:%08X] ide_read_alt_status(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); + // ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", CS, cpu_state.pc, addr, priv, ret); return ret; } @@ -3159,6 +3161,13 @@ ide_init(const device_t *info) ide_board_init(1, HDC_SECONDARY_IRQ, HDC_SECONDARY_BASE, HDC_SECONDARY_SIDE, info->local, info->flags); break; + case 8 ... 0x0d: + ide_board_init(2, -1, 0, 0, info->local, info->flags); + + if (info->local & 1) + ide_board_init(3, -1, 0, 0, info->local, info->flags); + break; + default: break; } @@ -3540,7 +3549,7 @@ const device_t mcide_device = { .name = "MCA McIDE Controller", .internal_name = "ide_mcide", .flags = DEVICE_MCA, - .local = 3, + .local = 1, .init = mcide_init, .close = mcide_close, .reset = mcide_reset, @@ -3661,3 +3670,17 @@ const device_t ide_qua_pnp_device = { .force_redraw = NULL, .config = NULL }; + +const device_t ide_pci_ter_qua_2ch_device = { + .name = "PCI IDE Controller (Dual-Channel Tertiary/Quaternary)", + .internal_name = "ide_pci_ter_qua_2ch", + .flags = DEVICE_PCI, + .local = 0x0d, + .init = ide_init, + .close = ide_close, + .reset = ide_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/disk/mo.c b/src/disk/mo.c index f1cd3b983..a20333404 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -584,7 +584,10 @@ mo_data_command_finish(mo_t *dev, int len, const int block_len, mo_command_write_dma(dev); } else { mo_update_request_length(dev, len, block_len); - if (direction == 0) + if ((dev->drv->bus_type != MO_BUS_SCSI) && + (dev->tf->request_length == 0)) + mo_command_complete(dev); + else if (direction == 0) mo_command_read(dev); else mo_command_write(dev); diff --git a/src/disk/zip.c b/src/disk/zip.c index eecafb802..7a407c5fe 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -665,7 +665,10 @@ zip_data_command_finish(zip_t *dev, int len, const int block_len, zip_command_write_dma(dev); } else { zip_update_request_length(dev, len, block_len); - if (direction == 0) + if ((dev->drv->bus_type != ZIP_BUS_SCSI) && + (dev->tf->request_length == 0)) + zip_command_complete(dev); + else if (direction == 0) zip_command_read(dev); else zip_command_write(dev); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index e5689dd76..2b37eeaca 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,6 +15,7 @@ */ #include #include +#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -689,6 +690,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) bytes_per_second *= (double) dev->drv->cur_speed; } else { bytes_per_second = scsi_cdrom_bus_speed(dev); + pclog("%lf bytes per second\n", bytes_per_second); if (bytes_per_second == 0.0) { dev->callback = -1; /* Speed depends on SCSI controller */ return; @@ -698,19 +700,24 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) period = 1000000.0 / bytes_per_second; scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", (uint64_t) period); + pclog("Byte transfer period: %lf us (%i bytes)\n", period, dev->packet_len); if (dev->was_cached == -1) period *= (double) dev->packet_len; else { + int atapi_num = (dev->tf->request_length < dev->block_len) ? + dev->block_len : dev->tf->request_length; + atapi_num = (atapi_num / dev->block_len) * dev->block_len; + if (atapi_num > dev->sector_len) + atapi_num = dev->sector_len; const int num = ((dev->drv->bus_type == CDROM_BUS_SCSI) || - (dev->block_len == 0)) ? - dev->requested_blocks : - ((scsi_cdrom_current_mode(dev) == 2) ? 1 : - (dev->packet_len / dev->block_len)); + (dev->block_len == 0)) ? dev->requested_blocks : + ((scsi_cdrom_current_mode(dev) == 2) ? 1 : atapi_num); period *= ((double) num) * 2352.0; } scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", (uint64_t) period); + pclog("Data transfer period: %lf us\n", period); dev->callback += period; } scsi_cdrom_set_callback(dev); @@ -800,7 +807,10 @@ scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block_len, int al scsi_cdrom_command_write_dma(dev); } else { scsi_cdrom_update_request_length(dev, len, block_len); - if (direction == 0) + if ((dev->drv->bus_type != CDROM_BUS_SCSI) && + (dev->tf->request_length == 0)) + scsi_cdrom_command_complete(dev); + else if (direction == 0) scsi_cdrom_command_read(dev); else scsi_cdrom_command_write(dev); diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 8528db1fb..0a035a23d 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -570,7 +570,10 @@ scsi_disk_data_command_finish(scsi_disk_t *dev, int len, const int block_len, scsi_disk_command_write_dma(dev); } else { scsi_disk_update_request_length(dev, len, block_len); - if (direction == 0) + if ((dev->drv->bus_type != HDD_BUS_SCSI) && + (dev->tf->request_length == 0)) + scsi_disk_command_complete(dev); + else if (direction == 0) scsi_disk_command_read(dev); else scsi_disk_command_write(dev); From b93af353efc0f9a93690d4011ad0e4b456ae7412 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 01:46:09 +0200 Subject: [PATCH 0683/1190] SCSI CD-ROM: Remove leftover excess logging. --- src/scsi/scsi_cdrom.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 2b37eeaca..306eed884 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -15,7 +15,6 @@ */ #include #include -#define ENABLE_SCSI_CDROM_LOG 2 #ifdef ENABLE_SCSI_CDROM_LOG #include #endif @@ -681,8 +680,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); - scsi_cdrom_log(dev->log, "Seek period: %" PRIu64 " us\n", - (uint64_t) period); + scsi_cdrom_log(dev->log, "Seek period: %lf us\n", period); dev->callback += period; /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ @@ -690,7 +688,6 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) bytes_per_second *= (double) dev->drv->cur_speed; } else { bytes_per_second = scsi_cdrom_bus_speed(dev); - pclog("%lf bytes per second\n", bytes_per_second); if (bytes_per_second == 0.0) { dev->callback = -1; /* Speed depends on SCSI controller */ return; @@ -698,9 +695,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) } period = 1000000.0 / bytes_per_second; - scsi_cdrom_log(dev->log, "Byte transfer period: %" PRIu64 " us\n", - (uint64_t) period); - pclog("Byte transfer period: %lf us (%i bytes)\n", period, dev->packet_len); + scsi_cdrom_log(dev->log, "Byte transfer period: %lf us\n", period); if (dev->was_cached == -1) period *= (double) dev->packet_len; else { @@ -715,9 +710,7 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) period *= ((double) num) * 2352.0; } - scsi_cdrom_log(dev->log, "Sector transfer period: %" PRIu64 " us\n", - (uint64_t) period); - pclog("Data transfer period: %lf us\n", period); + scsi_cdrom_log(dev->log, "Sector transfer period: %lf us\n", period); dev->callback += period; } scsi_cdrom_set_callback(dev); From 018ff46253293e39dc6c7aa9140c3425b6609825 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 05:42:41 +0200 Subject: [PATCH 0684/1190] CD-ROM: Actually remember and use the correct number of sectors for the period, fixes... well, any kind of data reading. --- src/include/86box/scsi_cdrom.h | 1 + src/scsi/scsi_cdrom.c | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index 7bb39d9db..c01f347a8 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -70,6 +70,7 @@ typedef struct scsi_cdrom_t { int was_cached; int toc_cached; int media_access; + int sectors_num; uint8_t vendor_type; uint8_t ven_cmd_is_data[256]; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 306eed884..246f185e8 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -699,14 +699,9 @@ scsi_cdrom_set_period(scsi_cdrom_t *dev) if (dev->was_cached == -1) period *= (double) dev->packet_len; else { - int atapi_num = (dev->tf->request_length < dev->block_len) ? - dev->block_len : dev->tf->request_length; - atapi_num = (atapi_num / dev->block_len) * dev->block_len; - if (atapi_num > dev->sector_len) - atapi_num = dev->sector_len; const int num = ((dev->drv->bus_type == CDROM_BUS_SCSI) || - (dev->block_len == 0)) ? dev->requested_blocks : - ((scsi_cdrom_current_mode(dev) == 2) ? 1 : atapi_num); + (dev->block_len == 0)) ? dev->sectors_num : + ((scsi_cdrom_current_mode(dev) == 2) ? 1 : dev->sectors_num); period *= ((double) num) * 2352.0; } @@ -1051,6 +1046,8 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int int num = (dev->drv->bus_type == CDROM_BUS_SCSI) ? dev->requested_blocks : 1; + dev->sectors_num = 0; + if (dev->drv->cd_status == CD_STATUS_EMPTY) scsi_cdrom_not_ready(dev); else if (dev->sector_pos > dev->drv->cdrom_capacity) { @@ -1085,6 +1082,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, const int msf, const int type, const int dev->drv->seek_pos = dev->sector_pos; dev->sector_len--; + dev->sectors_num++; dev->buffer_pos += temp_len; } @@ -2423,6 +2421,7 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) int32_t *BufLen; dev->was_cached = -1; + dev->sectors_num = 1; if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; From 3b5966eb465830b4fdb367d89cd44a930cb098ea Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 06:03:19 +0200 Subject: [PATCH 0685/1190] LDS/LES/LFS/LGS/LSS: Fix segment wraparounds in 16-bit address mode. --- src/codegen/codegen_ops_x86-64.h | 7 ++++ src/codegen/codegen_ops_x86.h | 7 ++++ src/codegen_new/codegen_backend_arm64_uops.c | 2 + src/codegen_new/codegen_backend_arm_uops.c | 2 + src/codegen_new/codegen_backend_x86-64_uops.c | 9 +++- src/codegen_new/codegen_backend_x86_uops.c | 9 +++- src/codegen_new/codegen_ir_defs.h | 10 ++++- src/codegen_new/codegen_ops_misc.c | 8 ++-- src/codegen_new/codegen_reg.c | 2 + src/codegen_new/codegen_reg.h | 4 +- src/cpu/386_common.h | 26 ++++++++++++ src/cpu/cpu.h | 5 ++- src/cpu/x86_ops_mov_seg.h | 41 +++++++++++-------- src/cpu/x86_ops_ret.h | 2 +- src/cpu/x86_ops_ret_2386.h | 2 +- 15 files changed, 105 insertions(+), 31 deletions(-) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index e46f55a05..1be5dfdce 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -1054,6 +1054,13 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) addbyte(0x83); /*ADD EAX, offset*/ addbyte(0xc0); addbyte(offset); + if (!(op_32 & 0x200)) { + addbyte(0x25) /* AND EAX, ffffh */ + addbyte(0xff); + addbyte(0xff); + addbyte(0x00); + addbyte(0x00); + } MEM_LOAD_ADDR_EA_W(seg); } static __inline void diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index c48324c2a..7a56b5fe1 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -802,6 +802,13 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) addbyte(0x83); /*ADD EAX, offset*/ addbyte(0xc0); addbyte(offset); + if (!(op_32 & 0x200)) { + addbyte(0x25) /* AND EAX, ffffh */ + addbyte(0xff); + addbyte(0xff); + addbyte(0x00); + addbyte(0x00); + } addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ addlong(mem_load_addr_ea_w - (uint32_t) (&codeblock[block_current].data[block_pos + 4])); diff --git a/src/codegen_new/codegen_backend_arm64_uops.c b/src/codegen_new/codegen_backend_arm64_uops.c index deaf53c20..82cc79cfd 100644 --- a/src/codegen_new/codegen_backend_arm64_uops.c +++ b/src/codegen_new/codegen_backend_arm64_uops.c @@ -931,6 +931,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); if (uop->imm_data) host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + if (uop->is_a16) + host_arm64_AND_IMM(block, REG_X0, REG_X0, 0xffff); if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) { host_arm64_call(block, codegen_mem_load_byte); } else if (REG_IS_W(dest_size)) { diff --git a/src/codegen_new/codegen_backend_arm_uops.c b/src/codegen_new/codegen_backend_arm_uops.c index d8c223884..b6963562c 100644 --- a/src/codegen_new/codegen_backend_arm_uops.c +++ b/src/codegen_new/codegen_backend_arm_uops.c @@ -995,6 +995,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); if (uop->imm_data) host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + if (uop->is_a16) + host_arm_AND_IMM(block, REG_R0, REG_R0, 0xffff); if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) { host_arm_BL(block, (uintptr_t) codegen_mem_load_byte); } else if (REG_IS_W(dest_size)) { diff --git a/src/codegen_new/codegen_backend_x86-64_uops.c b/src/codegen_new/codegen_backend_x86-64_uops.c index 46af68e75..0233a4636 100644 --- a/src/codegen_new/codegen_backend_x86-64_uops.c +++ b/src/codegen_new/codegen_backend_x86-64_uops.c @@ -997,8 +997,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); - if (uop->imm_data) - host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (uop->imm_data) { + if (uop->is_a16) { + host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data); + } else { + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + } + } if (REG_IS_B(dest_size)) { host_x86_CALL(block, codegen_mem_load_byte); } else if (REG_IS_W(dest_size)) { diff --git a/src/codegen_new/codegen_backend_x86_uops.c b/src/codegen_new/codegen_backend_x86_uops.c index cd79b9b47..beaf85c17 100644 --- a/src/codegen_new/codegen_backend_x86_uops.c +++ b/src/codegen_new/codegen_backend_x86_uops.c @@ -981,8 +981,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); - if (uop->imm_data) - host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (uop->imm_data) { + if (uop->is_a16) { + host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data); + } else { + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + } + } if (REG_IS_B(dest_size)) { host_x86_CALL(block, codegen_mem_load_byte); } else if (REG_IS_W(dest_size)) { diff --git a/src/codegen_new/codegen_ir_defs.h b/src/codegen_new/codegen_ir_defs.h index 9bd2f9afe..ff84c7ccd 100644 --- a/src/codegen_new/codegen_ir_defs.h +++ b/src/codegen_new/codegen_ir_defs.h @@ -340,6 +340,7 @@ typedef struct uop_t { void *p; ir_host_reg_t dest_reg_a_real; ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real; + int is_a16; int jump_dest_uop; int jump_list_next; void *jump_dest; @@ -364,6 +365,8 @@ uop_alloc(ir_data_t *ir, uint32_t uop_type) uop = &ir->uops[ir->wr_pos++]; + uop->is_a16 = 0; + uop->dest_reg_a = invalid_ir_reg; uop->src_reg_a = invalid_ir_reg; uop->src_reg_b = invalid_ir_reg; @@ -489,7 +492,12 @@ uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); - uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->is_a16 = 0; + if (src_reg_b == IREG_eaa16) { + uop->src_reg_b = codegen_reg_read(IREG_eaaddr); + uop->is_a16 = 1; + } else + uop->src_reg_b = codegen_reg_read(src_reg_b); uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } diff --git a/src/codegen_new/codegen_ops_misc.c b/src/codegen_new/codegen_ops_misc.c index 91e0f5d63..33e01d951 100644 --- a/src/codegen_new/codegen_ops_misc.c +++ b/src/codegen_new/codegen_ops_misc.c @@ -533,8 +533,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 2); \ uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ \ @@ -556,8 +556,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ codegen_check_seg_read(block, ir, target_seg); \ - uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ - uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 4); \ uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ \ diff --git a/src/codegen_new/codegen_reg.c b/src/codegen_new/codegen_reg.c index a3f000826..de67fde5a 100644 --- a/src/codegen_new/codegen_reg.c +++ b/src/codegen_new/codegen_reg.c @@ -169,6 +169,8 @@ struct [IREG_GS_limit_high] = { REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT}, [IREG_SS_limit_high] = { REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_eaa16] = { REG_WORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT}, + /*Temporary registers are stored on the stack, and are not guaranteed to be preserved across uOPs. They will not be written back if they will not be read again.*/ diff --git a/src/codegen_new/codegen_reg.h b/src/codegen_new/codegen_reg.h index ebb90b42f..fd3cf279a 100644 --- a/src/codegen_new/codegen_reg.h +++ b/src/codegen_new/codegen_reg.h @@ -132,7 +132,9 @@ enum { IREG_GS_limit_high = 86, IREG_SS_limit_high = 87, - IREG_COUNT = 88, + IREG_eaa16 = 88, + + IREG_COUNT = 89, IREG_INVALID = 255, diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index ec40612ee..a4ea5802b 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -248,6 +248,19 @@ int checkio(uint32_t port, int mask); return 1; \ } +#define CHECK_READ_2OP(chseg, low, high, low2, high2) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || (low2 < (chseg)->limit_low) || (high2 > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !((chseg)->access & 0x80)) { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL, (chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + #define CHECK_READ_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \ x86gpf("Limit check (READ)", 0); \ @@ -277,6 +290,19 @@ int checkio(uint32_t port, int mask); #define CHECK_WRITE(chseg, low, high) \ CHECK_WRITE_COMMON(chseg, low, high) +#define CHECK_WRITE_2OP(chseg, low, high, low2, high2) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || (low2 < (chseg)->limit_low) || (high2 > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !((chseg)->access & 0x80)) { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL, (chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + #define CHECK_WRITE_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \ x86gpf("Limit check (WRITE REP)", 0); \ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 80097294d..0e49704fd 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -335,7 +335,10 @@ typedef struct { uint8_t tag[8]; x86seg *ea_seg; - uint32_t eaaddr; + union { + uint32_t eaaddr; + uint16_t eaa16[2]; + }; int flags_op; uint32_t flags_res; diff --git a/src/cpu/x86_ops_mov_seg.h b/src/cpu/x86_ops_mov_seg.h index 7fcc92312..a34bc0c70 100644 --- a/src/cpu/x86_ops_mov_seg.h +++ b/src/cpu/x86_ops_mov_seg.h @@ -272,9 +272,10 @@ opLDS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); - addr = readmemw(easeg, cpu_state.eaaddr); - seg = readmemw(easeg, cpu_state.eaaddr + 2); + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, + ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); + addr = readmemw(easeg, cpu_state.eaa16[0]); + seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ds); @@ -318,9 +319,10 @@ opLDS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); - addr = readmeml(easeg, cpu_state.eaaddr); - seg = readmemw(easeg, cpu_state.eaaddr + 4); + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, + ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); + addr = readmeml(easeg, cpu_state.eaa16[0]); + seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ds); @@ -365,9 +367,10 @@ opLSS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); - addr = readmemw(easeg, cpu_state.eaaddr); - seg = readmemw(easeg, cpu_state.eaaddr + 2); + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, + ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); + addr = readmemw(easeg, cpu_state.eaa16[0]); + seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ss); @@ -411,9 +414,11 @@ opLSS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); - addr = readmeml(easeg, cpu_state.eaaddr); - seg = readmemw(easeg, cpu_state.eaaddr + 4); + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, + ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 5) & 0xffff)); + addr = readmeml(easeg, cpu_state.eaa16[0]); + seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ss); @@ -457,9 +462,9 @@ opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); \ - addr = readmemw(easeg, cpu_state.eaaddr); \ - seg = readmemw(easeg, cpu_state.eaaddr + 2); \ + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); \ + addr = readmemw(easeg, cpu_state.eaa16[0]); \ + seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); \ if (cpu_state.abrt) \ return 1; \ op_loadseg(seg, &sel); \ @@ -502,9 +507,9 @@ opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ - CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 5); \ - addr = readmeml(easeg, cpu_state.eaaddr); \ - seg = readmemw(easeg, cpu_state.eaaddr + 4); \ + CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); \ + addr = readmeml(easeg, cpu_state.eaa16[0]); \ + seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); \ if (cpu_state.abrt) \ return 1; \ op_loadseg(seg, &sel); \ diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 935fb5aa0..8bf72e9ed 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -15,7 +15,7 @@ op_loadcs(readmemw(ss, ESP + 2)); \ } else { \ cpu_state.pc = readmemw(ss, SP); \ - op_loadcs(readmemw(ss, SP + 2)); \ + op_loadcs(readmemw(ss, (SP + 2) & 0xffff)); \ } \ if (cpu_state.abrt) \ return 1; \ diff --git a/src/cpu/x86_ops_ret_2386.h b/src/cpu/x86_ops_ret_2386.h index 155925dfe..02233fd1d 100644 --- a/src/cpu/x86_ops_ret_2386.h +++ b/src/cpu/x86_ops_ret_2386.h @@ -15,7 +15,7 @@ op_loadcs(readmemw(ss, ESP + 2)); \ } else { \ cpu_state.pc = readmemw(ss, SP); \ - op_loadcs(readmemw(ss, SP + 2)); \ + op_loadcs(readmemw(ss, (SP + 2) & 0xffff)); \ } \ if (cpu_state.abrt) \ return 1; \ From 6884dc573688c4e16b71c218ccc676d8e5796d50 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 06:23:22 +0200 Subject: [PATCH 0686/1190] Old recompiler: Fix compile-breaking mistakes. --- src/codegen/codegen_ops_x86-64.h | 2 +- src/codegen/codegen_ops_x86.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index 1be5dfdce..1d9b29de2 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -1055,7 +1055,7 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) addbyte(0xc0); addbyte(offset); if (!(op_32 & 0x200)) { - addbyte(0x25) /* AND EAX, ffffh */ + addbyte(0x25); /* AND EAX, ffffh */ addbyte(0xff); addbyte(0xff); addbyte(0x00); diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index 7a56b5fe1..5e7165939 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -803,7 +803,7 @@ MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) addbyte(0xc0); addbyte(offset); if (!(op_32 & 0x200)) { - addbyte(0x25) /* AND EAX, ffffh */ + addbyte(0x25); /* AND EAX, ffffh */ addbyte(0xff); addbyte(0xff); addbyte(0x00); From 576d643c4f655affdc0b5d041d3ec97263c64bb2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 06:29:57 +0200 Subject: [PATCH 0687/1190] And fix the op_32 stuff. --- src/codegen/codegen_ops_mov.h | 4 ++-- src/codegen/codegen_ops_x86-64.h | 2 +- src/codegen/codegen_ops_x86.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codegen/codegen_ops_mov.h b/src/codegen/codegen_ops_mov.h index 6a5054b81..eb2a0202c 100644 --- a/src/codegen/codegen_ops_mov.h +++ b/src/codegen/codegen_ops_mov.h @@ -600,12 +600,12 @@ ropMOV_seg_w(UNUSED(uint8_t opcode), uint32_t fetchdat, uint32_t op_32, uint32_t MEM_LOAD_ADDR_EA_L(target_seg); \ STORE_HOST_REG_ADDR((uintptr_t) &codegen_temp, 0); \ LOAD_EA(); \ - MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 4); \ + MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 4, op_32); \ } else { \ MEM_LOAD_ADDR_EA_W(target_seg); \ STORE_HOST_REG_ADDR_W((uintptr_t) &codegen_temp, 0); \ LOAD_EA(); \ - MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 2); \ + MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 2, op_32); \ } \ LOAD_SEG(0, &rseg); \ if (op_32 & 0x100) { \ diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index 1d9b29de2..129d9a740 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -1049,7 +1049,7 @@ MEM_LOAD_ADDR_EA_W(x86seg *seg) /*done:*/ } static __inline void -MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) +MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset, int op_32) { addbyte(0x83); /*ADD EAX, offset*/ addbyte(0xc0); diff --git a/src/codegen/codegen_ops_x86.h b/src/codegen/codegen_ops_x86.h index 5e7165939..3fbefdeaa 100644 --- a/src/codegen/codegen_ops_x86.h +++ b/src/codegen/codegen_ops_x86.h @@ -789,7 +789,7 @@ MEM_LOAD_ADDR_EA_W(x86seg *seg) host_reg_mapping[0] = 8; } static __inline void -MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) +MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset, int op_32) { if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ From fb449f39a44529f0cea0d1842145595f1425ee17 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 7 Apr 2025 07:41:59 +0200 Subject: [PATCH 0688/1190] Intel Premiere/PCI and Premiere/PCI II: Use a dual-channel IDE controller, fixes #5442. --- src/machine/m_at_socket4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 0d78c6de3..c747d8cc0 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -47,7 +47,7 @@ machine_at_premiere_common_init(const machine_t *model, int pci_switch) machine_at_common_init_ex(model, 2); device_add(&amstrad_megapc_nvr_device); - device_add(&ide_pci_device); + device_add(&ide_pci_2ch_device); pci_init(PCI_CONFIG_TYPE_2 | pci_switch); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); From 44db8bb478eba862d66acbc4f9cc90336ff5d35c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 7 Apr 2025 11:42:03 +0600 Subject: [PATCH 0689/1190] Fix compilation on Qt6 --- src/qt/qt_mainwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 806e8e0e6..e9ebdaad8 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -674,7 +674,11 @@ MainWindow::MainWindow(QWidget *parent) /* Remove default Shift+F10 handler, which unfocuses keyboard input even with no context menu. */ connect(new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F10), this), &QShortcut::activated, this, [](){}); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this); +#else auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this); +#endif windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); connect(windowedShortcut, &QShortcut::activated, this, [this] () { if (video_fullscreen) From ebf125082a951752f3b3a819daf6e115a2fc1175 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 7 Apr 2025 20:33:50 +0200 Subject: [PATCH 0690/1190] Revert a minor commit from Spock. (April 7th, 2025) This fixes OS/2 Warp on a PS/2 machine using the Spock/Tribble during the file copy phase (the bug was probably too many IRQ's being fired). --- src/scsi/scsi_spock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index c500abfbc..6f0b7aacb 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1050,7 +1050,7 @@ spock_callback(void *priv) spock_execute_cmd(scsi, scb); } - if (scsi->attention_wait) { + if (scsi->attention_wait && ((scsi->scb_state == 0) || (scsi->attention_pending & 0xf0) == 0xe0)) { scsi->attention_wait--; if (!scsi->attention_wait) { scsi->attention = scsi->attention_pending; From 9032af002de12ca93282f6c8778ce0a0089d6362 Mon Sep 17 00:00:00 2001 From: Torinde <97228894+Torinde@users.noreply.github.com> Date: Wed, 9 Apr 2025 12:17:50 +0200 Subject: [PATCH 0691/1190] VIA Cyrix III (Samuel) - add codename To distinguish from Cyrix-heritage Joshua CPUs. #5451 --- src/cpu/cpu_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index e5c91b1a8..8524306dc 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -7793,7 +7793,7 @@ const cpu_family_t cpu_families[] = { { .package = CPU_PKG_SOCKET370, .manufacturer = "VIA", - .name = "Cyrix III", + .name = "Cyrix III (Samuel)", .internal_name = "c3_samuel", .cpus = (const CPU[]) { { /* out of multiplier range */ From f5fcebfbaa7552fc5533a1752ab0f0ea8e953fb8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 9 Apr 2025 12:19:24 +0200 Subject: [PATCH 0692/1190] Default the language to the system language. --- src/config.c | 2 ++ src/include/86box/86box.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 8ff7d548c..f38b5aa2c 100644 --- a/src/config.c +++ b/src/config.c @@ -1840,6 +1840,8 @@ config_load(void) cassette_pcm = 0; cassette_ui_writeprot = 0; + lang_id = DEFAULT_LANGUAGE; + config_log("Config file not present or invalid!\n"); } else { load_general(); /* General */ diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 61de69cf3..ddca937f1 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -45,7 +45,7 @@ #define MAX_UUID_LEN 64 /* Default language 0xFFFF = from system, 0x409 = en-US */ -#define DEFAULT_LANGUAGE 0x0409 +#define DEFAULT_LANGUAGE 0xffff #define POSTCARDS_NUM 4 #define POSTCARD_MASK (POSTCARDS_NUM - 1) From 8ac9d5d9cf79f7f2bde419300b9a4687889a57ad Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 9 Apr 2025 17:39:26 +0200 Subject: [PATCH 0693/1190] Default language to system also when the configuration file is present and the language option is not. --- src/config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config.c b/src/config.c index f38b5aa2c..6f023cf67 100644 --- a/src/config.c +++ b/src/config.c @@ -185,6 +185,8 @@ load_general(void) p = ini_section_get_string(cat, "language", NULL); if (p != NULL) lang_id = plat_language_code(p); + else + lang_id = 0xffff; mouse_sensitivity = ini_section_get_double(cat, "mouse_sensitivity", 1.0); if (mouse_sensitivity < 0.1) From e2f8a58d957ccbb22e59fc48cf98c70c72385650 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 10 Apr 2025 01:08:21 +0200 Subject: [PATCH 0694/1190] Fix the LxS fix on the new recompiler. --- src/codegen_new/codegen_backend_x86-64_uops.c | 5 ++--- src/codegen_new/codegen_backend_x86_uops.c | 5 ++--- src/codegen_new/codegen_ir_defs.h | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64_uops.c b/src/codegen_new/codegen_backend_x86-64_uops.c index 0233a4636..655896b54 100644 --- a/src/codegen_new/codegen_backend_x86-64_uops.c +++ b/src/codegen_new/codegen_backend_x86-64_uops.c @@ -998,10 +998,9 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); if (uop->imm_data) { + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); if (uop->is_a16) { - host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data); - } else { - host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_AND32_REG_IMM(block, REG_ESI, 0x0000ffff); } } if (REG_IS_B(dest_size)) { diff --git a/src/codegen_new/codegen_backend_x86_uops.c b/src/codegen_new/codegen_backend_x86_uops.c index beaf85c17..02c441234 100644 --- a/src/codegen_new/codegen_backend_x86_uops.c +++ b/src/codegen_new/codegen_backend_x86_uops.c @@ -982,10 +982,9 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); if (uop->imm_data) { + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); if (uop->is_a16) { - host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data); - } else { - host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_AND32_REG_IMM(block, REG_ESI, 0x0000ffff); } } if (REG_IS_B(dest_size)) { diff --git a/src/codegen_new/codegen_ir_defs.h b/src/codegen_new/codegen_ir_defs.h index ff84c7ccd..d55e57f3d 100644 --- a/src/codegen_new/codegen_ir_defs.h +++ b/src/codegen_new/codegen_ir_defs.h @@ -491,13 +491,14 @@ uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; - uop->src_reg_a = codegen_reg_read(src_reg_a); uop->is_a16 = 0; + uop->src_reg_a = codegen_reg_read(src_reg_a); if (src_reg_b == IREG_eaa16) { uop->src_reg_b = codegen_reg_read(IREG_eaaddr); uop->is_a16 = 1; } else uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->is_a16 = 0; uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } From daca37aac926f7de5f11c9eba84730d65596a219 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 10 Apr 2025 23:46:38 +0200 Subject: [PATCH 0695/1190] Media historyy manager: Remove comment and fix the limits. --- src/qt/qt_mediahistorymanager.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_mediahistorymanager.cpp b/src/qt/qt_mediahistorymanager.cpp index d548c0779..5892c55cd 100644 --- a/src/qt/qt_mediahistorymanager.cpp +++ b/src/qt/qt_mediahistorymanager.cpp @@ -101,15 +101,20 @@ MediaHistoryManager::getImageForSlot(int index, int slot, ui::MediaType type) return image_name; } -// These are hardcoded since we can't include the various -// header files where they are defined (e.g., fdd.h, mo.h). -// However, all in ui::MediaType support 4 except cassette. int MediaHistoryManager::maxDevicesSupported(ui::MediaType type) { switch (type) { default: return 4; + case ui::MediaType::Optical: + return CDROM_NUM; + case ui::MediaType::Floppy: + return FDD_NUM; + case ui::MediaType::Zip: + return ZIP_NUM; + case ui::MediaType::Mo: + return MO_NUM; case ui::MediaType::Cassette: return 1; case ui::MediaType::Cartridge: From f41848bbee691d2cd9462bce2355799a7025ff14 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 11 Apr 2025 00:35:28 +0200 Subject: [PATCH 0696/1190] Settings: Recalculate CD-ROM model list on CD-ROM selection change and select the correct CD-ROM type. --- src/qt/qt_settingsfloppycdrom.cpp | 34 +++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index 52d737ae6..5e0ec7bed 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -200,7 +200,7 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) (cdrom_drive_types[j].bus_type == BUS_TYPE_BOTH))) { QString name = CDROMName(j); Models::AddEntry(modelType, name, j); - if ((cdrom[cdromIdx].bus_type == bus_type) && (cdrom[cdromIdx].type == j)) + if (cdrom[cdromIdx].type == j) selectedTypeRow = eligibleRows; ++eligibleRows; } @@ -256,9 +256,9 @@ SettingsFloppyCDROM::onFloppyRowChanged(const QModelIndex ¤t) void SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) { - uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); - uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); - int type = current.siblingAtColumn(2).data(Qt::UserRole).toInt(); + uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); + uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); + uint32_t type = current.siblingAtColumn(2).data(Qt::UserRole).toUInt(); ui->comboBoxBus->setCurrentIndex(-1); auto* model = ui->comboBoxBus->model(); @@ -279,7 +279,29 @@ SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) ui->comboBoxSpeed->setEnabled(false); ui->comboBoxSpeed->setCurrentIndex(speed == 0 ? 7 : speed - 1); - ui->comboBoxCDROMType->setCurrentIndex(type); + auto *modelType = ui->comboBoxCDROMType->model(); + int removeRows = modelType->rowCount(); + + uint32_t j = 0; + int selectedTypeRow = 0; + int eligibleRows = 0; + while (cdrom_drive_types[j].bus_type != BUS_TYPE_NONE) { + if (((bus == CDROM_BUS_ATAPI) || (bus == CDROM_BUS_SCSI)) && + ((cdrom_drive_types[j].bus_type == bus) || + (cdrom_drive_types[j].bus_type == BUS_TYPE_BOTH))) { + QString name = CDROMName(j); + Models::AddEntry(modelType, name, j); + if (type == j) + selectedTypeRow = eligibleRows; + ++eligibleRows; + } + ++j; + } + modelType->removeRows(0, removeRows); + ui->comboBoxCDROMType->setEnabled(eligibleRows > 1); + ui->comboBoxCDROMType->setCurrentIndex(-1); + ui->comboBoxCDROMType->setCurrentIndex(selectedTypeRow); + enableCurrentlySelectedChannel(); } @@ -371,7 +393,7 @@ SettingsFloppyCDROM::on_comboBoxBus_activated(int) (cdrom_drive_types[j].bus_type == BUS_TYPE_BOTH))) { QString name = CDROMName(j); Models::AddEntry(modelType, name, j); - if ((cdrom[cdromIdx].bus_type == bus_type) && (cdrom[cdromIdx].type == j)) + if (cdrom[cdromIdx].type == j) selectedTypeRow = eligibleRows; ++eligibleRows; } From 95a6aa0bdff59dd9352f171644054d178ac66c90 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 11 Apr 2025 19:29:40 +0200 Subject: [PATCH 0697/1190] Fix the LxS fix again. --- src/cpu/386_common.h | 13 ---------- src/cpu/x86_ops_mov_seg.h | 53 ++++++++++++++++++++++++++------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index a4ea5802b..83ef4e72b 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -248,19 +248,6 @@ int checkio(uint32_t port, int mask); return 1; \ } -#define CHECK_READ_2OP(chseg, low, high, low2, high2) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || (low2 < (chseg)->limit_low) || (high2 > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) { \ - x86gpf("Limit check (READ)", 0); \ - return 1; \ - } \ - if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !((chseg)->access & 0x80)) { \ - if ((chseg) == &cpu_state.seg_ss) \ - x86ss(NULL, (chseg)->seg & 0xfffc); \ - else \ - x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ - return 1; \ - } - #define CHECK_READ_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) { \ x86gpf("Limit check (READ)", 0); \ diff --git a/src/cpu/x86_ops_mov_seg.h b/src/cpu/x86_ops_mov_seg.h index a34bc0c70..f5bd02923 100644 --- a/src/cpu/x86_ops_mov_seg.h +++ b/src/cpu/x86_ops_mov_seg.h @@ -272,10 +272,13 @@ opLDS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, - ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); addr = readmemw(easeg, cpu_state.eaa16[0]); - seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); + if (cpu_state.abrt) + return 1; + cpu_state.eaa16[0] += 2; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); + seg = readmemw(easeg, cpu_state.eaa16[0]); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ds); @@ -319,10 +322,13 @@ opLDS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, - ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 3) & 0xffff)); addr = readmeml(easeg, cpu_state.eaa16[0]); - seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); + if (cpu_state.abrt) + return 1; + cpu_state.eaa16[0] += 4; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); + seg = readmemw(easeg, cpu_state.eaa16[0]); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ds); @@ -367,10 +373,13 @@ opLSS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, - ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); addr = readmemw(easeg, cpu_state.eaa16[0]); - seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); + if (cpu_state.abrt) + return 1; + cpu_state.eaa16[0] += 2; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); + seg = readmemw(easeg, cpu_state.eaa16[0]); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ss); @@ -414,11 +423,13 @@ opLSS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); SEG_CHECK_READ(cpu_state.ea_seg); - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, - ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); - CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 5) & 0xffff)); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 3) & 0xffff)); addr = readmeml(easeg, cpu_state.eaa16[0]); - seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); + if (cpu_state.abrt) + return 1; + cpu_state.eaa16[0] += 4; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); + seg = readmemw(easeg, cpu_state.eaa16[0]); if (cpu_state.abrt) return 1; op_loadseg(seg, &cpu_state.seg_ss); @@ -462,9 +473,13 @@ opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 1, ((cpu_state.eaa16[0] + 2) & 0xffff), ((cpu_state.eaa16[0] + 2) & 0xffff) + 1); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); \ addr = readmemw(easeg, cpu_state.eaa16[0]); \ - seg = readmemw(easeg, (cpu_state.eaa16[0] + 2) & 0xffff); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.eaa16[0] += 2; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); \ + seg = readmemw(easeg, cpu_state.eaa16[0]); \ if (cpu_state.abrt) \ return 1; \ op_loadseg(seg, &sel); \ @@ -507,9 +522,13 @@ opLSS_l_a32(uint32_t fetchdat) fetch_ea_16(fetchdat); \ SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ - CHECK_READ_2OP(cpu_state.ea_seg, cpu_state.eaa16[0], cpu_state.eaa16[0] + 3, ((cpu_state.eaa16[0] + 4) & 0xffff), ((cpu_state.eaa16[0] + 4) & 0xffff) + 1); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 3) & 0xffff)); \ addr = readmeml(easeg, cpu_state.eaa16[0]); \ - seg = readmemw(easeg, (cpu_state.eaa16[0] + 4) & 0xffff); \ + if (cpu_state.abrt) \ + return 1; \ + cpu_state.eaa16[0] += 4; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaa16[0], ((cpu_state.eaa16[0] + 1) & 0xffff)); \ + seg = readmemw(easeg, cpu_state.eaa16[0]); \ if (cpu_state.abrt) \ return 1; \ op_loadseg(seg, &sel); \ From e21c86d46cbd243fe68f909c94488d6e4c5e0cda Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 11 Apr 2025 19:58:30 +0200 Subject: [PATCH 0698/1190] PCI TRC Reset: Only zero the RAM on 686 systems, fixes #5462. --- src/acpi.c | 4 +--- src/pci.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 963f26ae6..ccd51ebca 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -1025,10 +1025,8 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p nvr_reg_write(0x000f, 0xff, dev->nvr); } - if (sus_typ & SUS_RESET_PCI) { + if (sus_typ & SUS_RESET_PCI) device_reset_all(DEVICE_PCI); - mem_zero(); - } if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; diff --git a/src/pci.c b/src/pci.c index c2e4ca237..c3020ca73 100644 --- a/src/pci.c +++ b/src/pci.c @@ -420,7 +420,8 @@ pci_trc_reset(uint8_t val) flushmmucache(); - mem_zero(); + if (is_p6) + mem_zero(); } #ifdef USE_DYNAREC From 8aa15fa21fd70ac01bcacfb12d69e9e01ba00edb Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 11 Apr 2025 20:27:41 +0200 Subject: [PATCH 0699/1190] The update value handler should be at Pentium Pro, not Cyrix Cx6x86. --- src/cpu/cpu.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index ffe582604..d13dfe041 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -2448,11 +2448,6 @@ cpu_CPUID(void) EAX = CPUID; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_DE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; - /* - Return anything non-zero in bits 32-63 of the BIOS signature MSR - to indicate there has been an update. - */ - msr.bbl_cr_dx[3] = 0xffffffff00000000ULL; } else EAX = EBX = ECX = EDX = 0; break; @@ -2467,6 +2462,11 @@ cpu_CPUID(void) EAX = CPUID; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CMPXCHG8B | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_SEP | CPUID_CMOV; + /* + Return anything non-zero in bits 32-63 of the BIOS signature MSR + to indicate there has been an update. + */ + msr.bbl_cr_dx[3] = 0xffffffff00000000ULL; } else if (EAX == 2) { EAX = 0x03020101; /* Instruction TLB: 4 KB pages, 4-way set associative, 32 entries Instruction TLB: 4 MB pages, fully associative, 2 entries @@ -3301,7 +3301,6 @@ pentium_invalid_rdmsr: case 0x88 ... 0x8b: EAX = msr.bbl_cr_dx[ECX - 0x88] & 0xffffffff; EDX = msr.bbl_cr_dx[ECX - 0x88] >> 32; - // EDX |= 0xffffffff; break; /* Unknown */ case 0xae: From 9b11091c8e282336dc8f9ac81355f81565ff0b48 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 7 Apr 2025 15:58:44 +0500 Subject: [PATCH 0700/1190] qt: Remove the keyboard shortcut translation hack No longer needed since the Win32 UI is gone and Qt can handle the key names since the base translations are embedded --- src/qt/languages/86box.pot | 10 +++++----- src/qt/languages/ca-ES.po | 20 ++++++++++---------- src/qt/languages/cs-CZ.po | 20 ++++++++++---------- src/qt/languages/de-DE.po | 20 ++++++++++---------- src/qt/languages/es-ES.po | 20 ++++++++++---------- src/qt/languages/fi-FI.po | 20 ++++++++++---------- src/qt/languages/fr-FR.po | 20 ++++++++++---------- src/qt/languages/hr-HR.po | 20 ++++++++++---------- src/qt/languages/hu-HU.po | 20 ++++++++++---------- src/qt/languages/it-IT.po | 20 ++++++++++---------- src/qt/languages/ja-JP.po | 20 ++++++++++---------- src/qt/languages/ko-KR.po | 20 ++++++++++---------- src/qt/languages/nl-NL.po | 20 ++++++++++---------- src/qt/languages/pl-PL.po | 20 ++++++++++---------- src/qt/languages/pt-BR.po | 20 ++++++++++---------- src/qt/languages/pt-PT.po | 20 ++++++++++---------- src/qt/languages/ru-RU.po | 20 ++++++++++---------- src/qt/languages/sk-SK.po | 20 ++++++++++---------- src/qt/languages/sl-SI.po | 20 ++++++++++---------- src/qt/languages/tr-TR.po | 20 ++++++++++---------- src/qt/languages/uk-UA.po | 20 ++++++++++---------- src/qt/languages/vi-VN.po | 20 ++++++++++---------- src/qt/languages/zh-CN.po | 20 ++++++++++---------- src/qt/languages/zh-TW.po | 20 ++++++++++---------- src/qt/qt_progsettings.hpp | 17 +---------------- 25 files changed, 236 insertions(+), 251 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 93a47a1cb..6e610d715 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -18,7 +18,7 @@ msgstr "" msgid "&Hard Reset..." msgstr "" -msgid "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" msgstr "" msgid "Ctrl+Alt+&Esc" @@ -111,7 +111,7 @@ msgstr "" msgid "Hi&DPI scaling" msgstr "" -msgid "&Fullscreen\tCtrl+Alt+PgUp" +msgid "&Fullscreen" msgstr "" msgid "Fullscreen &stretch mode" @@ -186,7 +186,7 @@ msgstr "" msgid "&Update status bar icons" msgstr "" -msgid "Take s&creenshot\tCtrl+F11" +msgid "Take s&creenshot" msgstr "" msgid "&Preferences..." @@ -198,10 +198,10 @@ msgstr "" msgid "Sound &gain..." msgstr "" -msgid "Begin trace\tCtrl+T" +msgid "Begin trace" msgstr "" -msgid "End trace\tCtrl+T" +msgid "End trace" msgstr "" msgid "&Help" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index cf3d5c7f7..8c89c6bad 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -18,8 +18,8 @@ msgstr "CTRL &dret és ALT esquerre" msgid "&Hard Reset..." msgstr "&Reinicialització completa ..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineal" msgid "Hi&DPI scaling" msgstr "&Escalat alta densitat" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Pantalla completa\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Pantalla completa" msgid "Fullscreen &stretch mode" msgstr "Escalat pantalla completa" @@ -186,8 +186,8 @@ msgstr "&Ajustaments ..." msgid "&Update status bar icons" msgstr "&Actualitzar icones a la barra d'estat" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Prendre c&aptura\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Prendre c&aptura" msgid "&Preferences..." msgstr "&Preferències ..." @@ -198,11 +198,11 @@ msgstr "Activar la integració amb el &Discord" msgid "Sound &gain..." msgstr "&Guany de so ..." -msgid "Begin trace\tCtrl+T" -msgstr "Començar traça\tCtrl+T" +msgid "Begin trace" +msgstr "Començar traça" -msgid "End trace\tCtrl+T" -msgstr "Acabar traça\tCtrl+T" +msgid "End trace" +msgstr "Acabar traça" msgid "&Help" msgstr "&Ajuda" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index e3d85dd09..2a26f7ef6 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -18,8 +18,8 @@ msgstr "&Pravý Ctrl je levý Alt" msgid "&Hard Reset..." msgstr "&Resetovat" -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineární" msgid "Hi&DPI scaling" msgstr "Š&kálování HiDPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Celá obrazovka\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Celá obrazovka" msgid "Fullscreen &stretch mode" msgstr "Režím roztá&hnutí při celé obrazovce" @@ -186,8 +186,8 @@ msgstr "&Nastavení..." msgid "&Update status bar icons" msgstr "&Aktualizovat ikony stavového řádku" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Pořídit &screenshot\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Pořídit &screenshot" msgid "&Preferences..." msgstr "&Předvolby..." @@ -198,11 +198,11 @@ msgstr "Povolit integraci s &Discordem" msgid "Sound &gain..." msgstr "&Zesílení zvuku" -msgid "Begin trace\tCtrl+T" -msgstr "Začít trace\tCtrl+T" +msgid "Begin trace" +msgstr "Začít trace" -msgid "End trace\tCtrl+T" -msgstr "Zastavit trace\tCtrl+T" +msgid "End trace" +msgstr "Zastavit trace" msgid "&Help" msgstr "Ná&pověda" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index c904cad0d..fbb97a990 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -18,8 +18,8 @@ msgstr "&Die rechte Strg-Taste ist die Linke Alt-Taste" msgid "&Hard Reset..." msgstr "&Kaltstart..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Strg+Alt+Entf\tStrg+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Strg+Alt+Entf" msgid "Ctrl+Alt+&Esc" msgstr "Strg+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linear" msgid "Hi&DPI scaling" msgstr "Hi&DPI-Skalierung" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Vollbild\tStrg+Alt+Bild auf" +msgid "&Fullscreen" +msgstr "&Vollbild" msgid "Fullscreen &stretch mode" msgstr "&Vollbild-Skalierungsmodus" @@ -186,8 +186,8 @@ msgstr "&Optionen..." msgid "&Update status bar icons" msgstr "&Statusleistenicons aktualisieren" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "S&creenshot aufnehmen\tStrg+F11" +msgid "Take s&creenshot" +msgstr "S&creenshot aufnehmen" msgid "&Preferences..." msgstr "&Einstellungen..." @@ -198,11 +198,11 @@ msgstr "&Discord-Integration einschalten" msgid "Sound &gain..." msgstr "&Klangverstärkung..." -msgid "Begin trace\tCtrl+T" -msgstr "Tracing starten\tStrg+T" +msgid "Begin trace" +msgstr "Tracing starten" -msgid "End trace\tCtrl+T" -msgstr "Tracing beenden\tStrg+T" +msgid "End trace" +msgstr "Tracing beenden" msgid "&Help" msgstr "&Hilfe" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index ca7a3ad53..1a5550065 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -18,8 +18,8 @@ msgstr "CTRL &derecho es ALT izquierdo" msgid "&Hard Reset..." msgstr "&Hard Reset..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineal" msgid "Hi&DPI scaling" msgstr "&Escalado alta densidad" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Pantalla completa\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Pantalla completa" msgid "Fullscreen &stretch mode" msgstr "Escalado pantalla completa" @@ -186,8 +186,8 @@ msgstr "&Configuraciones..." msgid "&Update status bar icons" msgstr "&Actualizar iconos en barra de estado" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Tomar c&aptura\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Tomar c&aptura" msgid "&Preferences..." msgstr "&Preferencias..." @@ -198,11 +198,11 @@ msgstr "Habilitar integración con &Discord" msgid "Sound &gain..." msgstr "&Ganancia de sonido..." -msgid "Begin trace\tCtrl+T" -msgstr "Comenzar traza\tCtrl+T" +msgid "Begin trace" +msgstr "Comenzar traza" -msgid "End trace\tCtrl+T" -msgstr "Terminar traza\tCtrl+T" +msgid "End trace" +msgstr "Terminar traza" msgid "&Help" msgstr "&Ayuda" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index f044365f0..5222ccc45 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -18,8 +18,8 @@ msgstr "&Oikea CTRL on vasen ALT" msgid "&Hard Reset..." msgstr "&Uudelleenkäynnistys (kylmä)..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "Li&neaarinen interpolaatio" msgid "Hi&DPI scaling" msgstr "&Suuri DPI-skaalaus" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Koko näytön tila\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Koko näytön tila" msgid "Fullscreen &stretch mode" msgstr "Koko näytön &skaalaustila" @@ -186,8 +186,8 @@ msgstr "&Kokoonpano..." msgid "&Update status bar icons" msgstr "&Päivitä tilapalkin kuvakkeita" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Ota &kuvakaappaus\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Ota &kuvakaappaus" msgid "&Preferences..." msgstr "&Sovellusasetukset..." @@ -198,11 +198,11 @@ msgstr "Käytä &Discord-integraatiota" msgid "Sound &gain..." msgstr "&Äänitasot..." -msgid "Begin trace\tCtrl+T" -msgstr "Aloita jäljitys\tCtrl+T" +msgid "Begin trace" +msgstr "Aloita jäljitys" -msgid "End trace\tCtrl+T" -msgstr "Lopeta jäljitys\tCtrl+T" +msgid "End trace" +msgstr "Lopeta jäljitys" msgid "&Help" msgstr "&Ohje" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 590674a29..9937cecd4 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -18,8 +18,8 @@ msgstr "CTRL &Droite devient ALT Gauche" msgid "&Hard Reset..." msgstr "&Hard Reset..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineaire" msgid "Hi&DPI scaling" msgstr "Mise à l'échelle Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Plein Ecran\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Plein Ecran" msgid "Fullscreen &stretch mode" msgstr "Mode &Elargi plein écran" @@ -186,8 +186,8 @@ msgstr "&Réglages..." msgid "&Update status bar icons" msgstr "Mettre à jour la barre de stat&us" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Copie &Ecran\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Copie &Ecran" msgid "&Preferences..." msgstr "&Préférences..." @@ -198,11 +198,11 @@ msgstr "Activer intégration &Discord" msgid "Sound &gain..." msgstr "&Gain Son..." -msgid "Begin trace\tCtrl+T" -msgstr "Démarrer traces\tCtrl+T" +msgid "Begin trace" +msgstr "Démarrer traces" -msgid "End trace\tCtrl+T" -msgstr "Finir traces\tCtrl+T" +msgid "End trace" +msgstr "Finir traces" msgid "&Help" msgstr "&Aide" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index ed4fdf621..7a8aa53e4 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -18,8 +18,8 @@ msgstr "&Desni CTRL je lijevi ALT" msgid "&Hard Reset..." msgstr "&Ponovno pokretanje..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linearna" msgid "Hi&DPI scaling" msgstr "&HiDPI skaliranje" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Cijelozaslonski način\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Cijelozaslonski način" msgid "Fullscreen &stretch mode" msgstr "&Način cijelozaslonskog rastezanja" @@ -186,8 +186,8 @@ msgstr "&Opcije..." msgid "&Update status bar icons" msgstr "&Ažuriraj ikone statusnog redka" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Napravi &snimku zaslona\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Napravi &snimku zaslona" msgid "&Preferences..." msgstr "&Postavke..." @@ -198,11 +198,11 @@ msgstr "Omogući integraciju sa programom &Discord" msgid "Sound &gain..." msgstr "&Pojačavanje zvuka..." -msgid "Begin trace\tCtrl+T" -msgstr "Z&apočni praćenje\tCtrl+T" +msgid "Begin trace" +msgstr "Z&apočni praćenje" -msgid "End trace\tCtrl+T" -msgstr "&Svrši praćenje\tCtrl+T" +msgid "End trace" +msgstr "&Svrši praćenje" msgid "&Help" msgstr "&Pomoć" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index b4afd8010..c777c6dd7 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -18,8 +18,8 @@ msgstr "A &jobb oldali CTRL a bal ALT" msgid "&Hard Reset..." msgstr "Hardveres &újraindítás..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineáris" msgid "Hi&DPI scaling" msgstr "Hi&DPI méretezés" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Teljes képernyő\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Teljes képernyő" msgid "Fullscreen &stretch mode" msgstr "Teljes képernyős &méretezés" @@ -186,8 +186,8 @@ msgstr "&Konfigurálás..." msgid "&Update status bar icons" msgstr "Állapotsori ikonok &frissítése" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "&Képernyőkép készítése\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "&Képernyőkép készítése" msgid "&Preferences..." msgstr "&Beállítások..." @@ -198,11 +198,11 @@ msgstr "&Discord integráció engedélyezése" msgid "Sound &gain..." msgstr "&Hangerőszabályzó..." -msgid "Begin trace\tCtrl+T" -msgstr "Nyomkövetés megkezdése\tCtrl+T" +msgid "Begin trace" +msgstr "Nyomkövetés megkezdése" -msgid "End trace\tCtrl+T" -msgstr "Nyomkövetés befejezése\tCtrl+T" +msgid "End trace" +msgstr "Nyomkövetés befejezése" msgid "&Help" msgstr "&Súgó" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 73ec57ec0..adf5b0471 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -18,8 +18,8 @@ msgstr "&CTRL destro è ALT sinistro" msgid "&Hard Reset..." msgstr "&Riavvia..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineare" msgid "Hi&DPI scaling" msgstr "Scala Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Schermo intero\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Schermo intero" msgid "Fullscreen &stretch mode" msgstr "Modalità adattamento &schermo intero" @@ -186,8 +186,8 @@ msgstr "&Impostazioni..." msgid "&Update status bar icons" msgstr "&Aggiorna icone della barra di stato" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Cattura schermata\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Cattura schermata" msgid "&Preferences..." msgstr "&Preferenze..." @@ -198,11 +198,11 @@ msgstr "Abilita &integrazione Discord" msgid "Sound &gain..." msgstr "Guadagno &suono..." -msgid "Begin trace\tCtrl+T" -msgstr "Inizia traccia\tCtrl+T" +msgid "Begin trace" +msgstr "Inizia traccia" -msgid "End trace\tCtrl+T" -msgstr "Ferma traccia\tCtrl+T" +msgid "End trace" +msgstr "Ferma traccia" msgid "&Help" msgstr "&?" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 6132a8db1..d51be2536 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -18,8 +18,8 @@ msgstr "右CTRLを左ALTへ変換(&R)" msgid "&Hard Reset..." msgstr "ハード リセット(&H)..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del(&C)" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+Esc(&E)" @@ -111,8 +111,8 @@ msgstr "線形補間(&L)" msgid "Hi&DPI scaling" msgstr "HiDPIスケーリング(&D)" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "全画面表示(&F)\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "全画面表示(&F)" msgid "Fullscreen &stretch mode" msgstr "全画面の拡大表示モード(&S)" @@ -186,8 +186,8 @@ msgstr "設定(&S)..." msgid "&Update status bar icons" msgstr "ステータスバーのアイコンを更新(&U)" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "スクリーンショットを撮る(&C)\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "スクリーンショットを撮る(&C)" msgid "&Preferences..." msgstr "環境設定(&P)..." @@ -198,11 +198,11 @@ msgstr "Discord連携機能(&D)" msgid "Sound &gain..." msgstr "音量調整(&G)..." -msgid "Begin trace\tCtrl+T" -msgstr "トレース開始\tCtrl+T" +msgid "Begin trace" +msgstr "トレース開始" -msgid "End trace\tCtrl+T" -msgstr "トレース終了\tCtrl+T" +msgid "End trace" +msgstr "トレース終了" msgid "&Help" msgstr "ヘルプ(&H)" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index ec4b20d0d..859183fc1 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -18,8 +18,8 @@ msgstr "우측CTRL로 좌측ALT 입력(&R)" msgid "&Hard Reset..." msgstr "재시작(&H)..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del(&C)" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+Esc(&E)" @@ -111,8 +111,8 @@ msgstr "선형 보간법(&L)" msgid "Hi&DPI scaling" msgstr "HiDPI 스케일링(&D)" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "전체 화면(&F)\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "전체 화면(&F)" msgid "Fullscreen &stretch mode" msgstr "전체 화면 비율(&S)" @@ -186,8 +186,8 @@ msgstr "설정(&S)..." msgid "&Update status bar icons" msgstr "상태 바 아이콘 갱신하기(&U)" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "스크린샷 찍기(&C)\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "스크린샷 찍기(&C)" msgid "&Preferences..." msgstr "환경설정(&P)..." @@ -198,11 +198,11 @@ msgstr "디스코드 연동 활성화하기(&D)" msgid "Sound &gain..." msgstr "음량 증폭(&G)..." -msgid "Begin trace\tCtrl+T" -msgstr "추적 시작하기\tCtrl+T" +msgid "Begin trace" +msgstr "추적 시작하기" -msgid "End trace\tCtrl+T" -msgstr "추적 끝내기\tCtrl+T" +msgid "End trace" +msgstr "추적 끝내기" msgid "&Help" msgstr "도움말(&H)" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index c601197ac..cce4dfdc9 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -18,8 +18,8 @@ msgstr "&Rechtse CTRL is linkse ALT" msgid "&Hard Reset..." msgstr "&Harde Reset..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineair" msgid "Hi&DPI scaling" msgstr "Hi&DPI-schaling" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Fullscreen\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Fullscreen" msgid "Fullscreen &stretch mode" msgstr "Volledig scherm &uitrekmodus" @@ -186,8 +186,8 @@ msgstr "&Instellingen..." msgid "&Update status bar icons" msgstr "&Statusbalkpictogrammen bijwerken" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Maak een schermafbeelding\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Maak een schermafbeelding" msgid "&Preferences..." msgstr "&Voorkeuren..." @@ -198,11 +198,11 @@ msgstr "&Discord integratie inschakelen" msgid "Sound &gain..." msgstr "&Geluidsversterking..." -msgid "Begin trace\tCtrl+T" -msgstr "Begin traceren\tCtrl+T" +msgid "Begin trace" +msgstr "Begin traceren" -msgid "End trace\tCtrl+T" -msgstr "Traceren beëindigen\tCtrl+T" +msgid "End trace" +msgstr "Traceren beëindigen" msgid "&Help" msgstr "&Help" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 78ded239f..26cc4bae6 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -18,8 +18,8 @@ msgstr "&Prawy CTRL to lewy Alt" msgid "&Hard Reset..." msgstr "&Twardy reset..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linear" msgid "Hi&DPI scaling" msgstr "Skalowanie Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Pełny ekran\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Pełny ekran" msgid "Fullscreen &stretch mode" msgstr "Tryb rozciągania na pełnym ekranie" @@ -186,8 +186,8 @@ msgstr "&Ustawienia..." msgid "&Update status bar icons" msgstr "&Aktualizuj ikony na pasku statusu" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Zrób &zrzut ekranu\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Zrób &zrzut ekranu" msgid "&Preferences..." msgstr "&Preferencje..." @@ -198,11 +198,11 @@ msgstr "Włącz integrację z &Discord" msgid "Sound &gain..." msgstr "Wzmocnienie &dźwięku..." -msgid "Begin trace\tCtrl+T" -msgstr "Rozpocznij śledzenie\tCtrl+T" +msgid "Begin trace" +msgstr "Rozpocznij śledzenie" -msgid "End trace\tCtrl+T" -msgstr "Zakończ śledzenie\tCtrl+T" +msgid "End trace" +msgstr "Zakończ śledzenie" msgid "&Help" msgstr "&Pomoc" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 1594e30ab..b453d0f97 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -18,8 +18,8 @@ msgstr "&CTRL direito é o ALT esquerdo" msgid "&Hard Reset..." msgstr "&Reinicialização completa..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linear" msgid "Hi&DPI scaling" msgstr "Escala Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Tela cheia\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Tela cheia" msgid "Fullscreen &stretch mode" msgstr "Modo de &redimensionamento da tela cheia" @@ -186,8 +186,8 @@ msgstr "&Configurações..." msgid "&Update status bar icons" msgstr "&Atualizar ícones da barra de status" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Capturar &tela\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Capturar &tela" msgid "&Preferences..." msgstr "&Preferências..." @@ -198,11 +198,11 @@ msgstr "Ativar integração com o &Discord" msgid "Sound &gain..." msgstr "&Ganho de som..." -msgid "Begin trace\tCtrl+T" -msgstr "Inicio do rastreamento\tCtrl+T" +msgid "Begin trace" +msgstr "Inicio do rastreamento" -msgid "End trace\tCtrl+T" -msgstr "Finalizar rastreamento\tCtrl+T" +msgid "End trace" +msgstr "Finalizar rastreamento" msgid "&Help" msgstr "&Ajuda" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index b31f020d4..d732532ed 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -18,8 +18,8 @@ msgstr "&CTRL direito é ALT esquerdo" msgid "&Hard Reset..." msgstr "&Reinicialização completa..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linear" msgid "Hi&DPI scaling" msgstr "Escala Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "E&crã cheio\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "E&crã cheio" msgid "Fullscreen &stretch mode" msgstr "Modo &de estiramento na tela cheia" @@ -186,8 +186,8 @@ msgstr "&Definições..." msgid "&Update status bar icons" msgstr "&Atualizar ícones da barra de estado" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Gravar imagem de ecrã\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Gravar imagem de ecrã" msgid "&Preferences..." msgstr "&Preferências..." @@ -198,11 +198,11 @@ msgstr "Ativar integração com &Discord" msgid "Sound &gain..." msgstr "&Ganho de som..." -msgid "Begin trace\tCtrl+T" -msgstr "Iniciar o rastreio\tCtrl+T" +msgid "Begin trace" +msgstr "Iniciar o rastreio" -msgid "End trace\tCtrl+T" -msgstr "Terminar o rastreio\tCtrl+T" +msgid "End trace" +msgstr "Terminar o rastreio" msgid "&Help" msgstr "&Ajuda" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index a8a4b7794..e68e6bb10 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -18,8 +18,8 @@ msgstr "&Правый CTRL - это левый ALT" msgid "&Hard Reset..." msgstr "&Холодная перезагрузка..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Линейный" msgid "Hi&DPI scaling" msgstr "Масштабирование Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Полноэкранный режим\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Полноэкранный режим" msgid "Fullscreen &stretch mode" msgstr "&Растягивание в полноэкранном режиме" @@ -186,8 +186,8 @@ msgstr "&Настройки машины..." msgid "&Update status bar icons" msgstr "&Обновление значков строки состояния" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Сделать с&криншот\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Сделать с&криншот" msgid "&Preferences..." msgstr "&Параметры..." @@ -198,11 +198,11 @@ msgstr "Включить интеграцию &Discord" msgid "Sound &gain..." msgstr "&Усиление звука..." -msgid "Begin trace\tCtrl+T" -msgstr "Начать трассировку\tCtrl+T" +msgid "Begin trace" +msgstr "Начать трассировку" -msgid "End trace\tCtrl+T" -msgstr "Завершить трассировку\tCtrl+T" +msgid "End trace" +msgstr "Завершить трассировку" msgid "&Help" msgstr "&Помощь" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index e789d9ef9..c091780c2 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -18,8 +18,8 @@ msgstr "&Pravý Ctrl je ľavý Alt" msgid "&Hard Reset..." msgstr "&Resetovať" -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Lineárny" msgid "Hi&DPI scaling" msgstr "Š&kálovanie HiDPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Celá obrazovka\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Celá obrazovka" msgid "Fullscreen &stretch mode" msgstr "Režim roztia&hnutia na celú obrazovku" @@ -186,8 +186,8 @@ msgstr "&Nastavenia..." msgid "&Update status bar icons" msgstr "&Aktualizovať ikony na stavovom riadku" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Urobiť snímku &obrazovky\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Urobiť snímku &obrazovky" msgid "&Preferences..." msgstr "&Predvoľby..." @@ -198,11 +198,11 @@ msgstr "Povolenie integrácie s &Discordem" msgid "Sound &gain..." msgstr "&Zosilnenie zvuku" -msgid "Begin trace\tCtrl+T" -msgstr "Začať trace\tCtrl+T" +msgid "Begin trace" +msgstr "Začať trace" -msgid "End trace\tCtrl+T" -msgstr "Zastaviť trace\tCtrl+T" +msgid "End trace" +msgstr "Zastaviť trace" msgid "&Help" msgstr "&Pomoc" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 1394a3635..15041a4aa 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -18,8 +18,8 @@ msgstr "&Desni CTRL je levi ALT" msgid "&Hard Reset..." msgstr "&Ponovni zagon..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Linearna" msgid "Hi&DPI scaling" msgstr "&Raztezanje za visok DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Celozaslonski način\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Celozaslonski način" msgid "Fullscreen &stretch mode" msgstr "&Način celozaslonskega raztezanja" @@ -186,8 +186,8 @@ msgstr "&Nastavitve..." msgid "&Update status bar icons" msgstr "&Posodabljaj ikone statusne vrstice" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "&Zajemi posnetek zaslona\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "&Zajemi posnetek zaslona" msgid "&Preferences..." msgstr "&Možnosti..." @@ -198,11 +198,11 @@ msgstr "Omogoči integracijo s programom &Discord" msgid "Sound &gain..." msgstr "&Ojačanje zvoka..." -msgid "Begin trace\tCtrl+T" -msgstr "Z&ačni sledenje\tCtrl+T" +msgid "Begin trace" +msgstr "Z&ačni sledenje" -msgid "End trace\tCtrl+T" -msgstr "&Končaj sledenje\tCtrl+T" +msgid "End trace" +msgstr "&Končaj sledenje" msgid "&Help" msgstr "&Pomoč" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 81866b3ce..c16cc12e4 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -18,8 +18,8 @@ msgstr "&Sağ CTRL tuşunu sol ALT tuşu olarak ayarla" msgid "&Hard Reset..." msgstr "Yeniden başlamaya &zorla" -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+&Alt+Esc" @@ -111,8 +111,8 @@ msgstr "Doğ&rusal" msgid "Hi&DPI scaling" msgstr "HiDPI ölçekle&mesi" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "Tam ekran\tCtrl+Alt+Pg&Up" +msgid "&Fullscreen" +msgstr "Tam ekran" msgid "Fullscreen &stretch mode" msgstr "Tam e&kran germe modu" @@ -186,8 +186,8 @@ msgstr "&Ayarlar..." msgid "&Update status bar icons" msgstr "Durum &çubuğu simgelerini güncelle" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "&Ekran görüntüsü al\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "&Ekran görüntüsü al" msgid "&Preferences..." msgstr "&Tercihler..." @@ -198,11 +198,11 @@ msgstr "&Discord entegrasyonunu etkinleştir" msgid "Sound &gain..." msgstr "&Ses düzeyi artışı..." -msgid "Begin trace\tCtrl+T" -msgstr "İzlemeyi başlat\tCtrl+T" +msgid "Begin trace" +msgstr "İzlemeyi başlat" -msgid "End trace\tCtrl+T" -msgstr "İzlemeyi bitir\tCtrl+T" +msgid "End trace" +msgstr "İzlemeyi bitir" msgid "&Help" msgstr "&Yardım" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 9b57ac03e..bde9a4f51 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -18,8 +18,8 @@ msgstr "&Правий CTRL - це лівий ALT" msgid "&Hard Reset..." msgstr "&Холодне перезавантаження..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "&Лінійний" msgid "Hi&DPI scaling" msgstr "Масштабування Hi&DPI" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "&Повноекранний режим\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "&Повноекранний режим" msgid "Fullscreen &stretch mode" msgstr "&Розстягування у повноекранному режимі" @@ -186,8 +186,8 @@ msgstr "&Налаштування машини..." msgid "&Update status bar icons" msgstr "&Обновлення значків рядка стану" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Зробити &знімок\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Зробити &знімок" msgid "&Preferences..." msgstr "&Параметри..." @@ -198,11 +198,11 @@ msgstr "Увімкнути інтеграцію &Discord" msgid "Sound &gain..." msgstr "&Посилення звуку..." -msgid "Begin trace\tCtrl+T" -msgstr "Почати трасування\tCtrl+T" +msgid "Begin trace" +msgstr "Почати трасування" -msgid "End trace\tCtrl+T" -msgstr "Завершити трасування\tCtrl+T" +msgid "End trace" +msgstr "Завершити трасування" msgid "&Help" msgstr "&Допомога" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index abf9a1dea..fa9384d8f 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -18,8 +18,8 @@ msgstr "Gắn ALT trái vào CTRL ph&ải" msgid "&Hard Reset..." msgstr "Buộc khởi độn&g lại" -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "&Ctrl+Alt+Del\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -111,8 +111,8 @@ msgstr "Tu&yến tính" msgid "Hi&DPI scaling" msgstr "Tỷ lệ hinh ảnh phân giải cao" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "Toàn màn &hình\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "Toàn màn &hình" msgid "Fullscreen &stretch mode" msgstr "&Chế độ kéo giãn hình" @@ -186,8 +186,8 @@ msgstr "&Cài đặt..." msgid "&Update status bar icons" msgstr "Cậ&p nhật biểu tượng thanh trạng thái" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "Chụp &màn hình\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "Chụp &màn hình" msgid "&Preferences..." msgstr "&Tùy biến..." @@ -198,11 +198,11 @@ msgstr "Bật trình trạng thái cho Discord" msgid "Sound &gain..." msgstr "Bộ &tăng âm..." -msgid "Begin trace\tCtrl+T" -msgstr "Bắt đầu dò\tCtrl+T" +msgid "Begin trace" +msgstr "Bắt đầu dò" -msgid "End trace\tCtrl+T" -msgstr "Ngưng dò\tCtrl+T" +msgid "End trace" +msgstr "Ngưng dò" msgid "&Help" msgstr "&Trợ giúp" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index ec5d2c252..4cccc071a 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -18,8 +18,8 @@ msgstr "将右 CTRL 键映射为左 ALT 键(&R)" msgid "&Hard Reset..." msgstr "硬重置(&H)..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del(&C)" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+Esc(&E)" @@ -111,8 +111,8 @@ msgstr "线性(&L)" msgid "Hi&DPI scaling" msgstr "HiDPI 缩放(&D)" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "全屏(&F)\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "全屏(&F)" msgid "Fullscreen &stretch mode" msgstr "全屏拉伸模式(&S)" @@ -186,8 +186,8 @@ msgstr "设置(&S)..." msgid "&Update status bar icons" msgstr "更新状态栏图标(&U)" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "截图(&C)\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "截图(&C)" msgid "&Preferences..." msgstr "首选项(&P)..." @@ -198,11 +198,11 @@ msgstr "启用 Discord 集成(&D)" msgid "Sound &gain..." msgstr "音量增益(&G)..." -msgid "Begin trace\tCtrl+T" -msgstr "开始追踪\tCtrl+T" +msgid "Begin trace" +msgstr "开始追踪" -msgid "End trace\tCtrl+T" -msgstr "结束追踪\tCtrl+T" +msgid "End trace" +msgstr "结束追踪" msgid "&Help" msgstr "帮助(&H)" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index b0d8163cb..92c6502ea 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -18,8 +18,8 @@ msgstr "將右 CTRL 鍵映射為左 ALT 鍵(&R)" msgid "&Hard Reset..." msgstr "硬重設(&H)..." -msgid "&Ctrl+Alt+Del\tCtrl+F12" -msgstr "Ctrl+Alt+Del(&C)\tCtrl+F12" +msgid "&Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del(&C)" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+Esc(&E)" @@ -111,8 +111,8 @@ msgstr "線性(&L)" msgid "Hi&DPI scaling" msgstr "HiDPI 縮放(&D)" -msgid "&Fullscreen\tCtrl+Alt+PgUp" -msgstr "全螢幕(&F)\tCtrl+Alt+PgUp" +msgid "&Fullscreen" +msgstr "全螢幕(&F)" msgid "Fullscreen &stretch mode" msgstr "全螢幕拉伸模式(&S)" @@ -186,8 +186,8 @@ msgstr "設定(&S)..." msgid "&Update status bar icons" msgstr "更新狀態列圖示(&U)" -msgid "Take s&creenshot\tCtrl+F11" -msgstr "擷圖(&C)\tCtrl+F11" +msgid "Take s&creenshot" +msgstr "擷圖(&C)" msgid "&Preferences..." msgstr "偏好設定(&P)..." @@ -198,11 +198,11 @@ msgstr "啟用 Discord 整合(&D)" msgid "Sound &gain..." msgstr "音量增益(&G)..." -msgid "Begin trace\tCtrl+T" -msgstr "開始追踪\tCtrl+T" +msgid "Begin trace" +msgstr "開始追踪" -msgid "End trace\tCtrl+T" -msgstr "結束追踪\tCtrl+T" +msgid "End trace" +msgstr "結束追踪" msgid "&Help" msgstr "說明(&H)" diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index b4e59e02d..1c7295f56 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -28,22 +28,7 @@ public: QString translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) const override { - if (strcmp(sourceText, "&Fullscreen") == 0) - sourceText = "&Fullscreen\tCtrl+Alt+PgUp"; - if (strcmp(sourceText, "&Ctrl+Alt+Del") == 0) - sourceText = "&Ctrl+Alt+Del\tCtrl+F12"; - if (strcmp(sourceText, "Take s&creenshot") == 0) - sourceText = "Take s&creenshot\tCtrl+F11"; - if (strcmp(sourceText, "Begin trace") == 0) - sourceText = "Begin trace\tCtrl+T"; - if (strcmp(sourceText, "End trace") == 0) - sourceText = "End trace\tCtrl+T"; - QString finalstr = QTranslator::translate("", sourceText, disambiguation, n); -#ifdef Q_OS_MACOS - if (finalstr.contains('\t')) - finalstr.truncate(finalstr.indexOf('\t')); -#endif - return finalstr; + return QTranslator::translate("", sourceText, disambiguation, n); } }; static CustomTranslator *translator; From 8f1fa1e5da5171912849b2830e260e9815d66181 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 7 Apr 2025 19:47:07 +0500 Subject: [PATCH 0701/1190] qt: Remove unused string translations --- src/qt/languages/86box.pot | 54 -------------------------------------- src/qt/languages/ca-ES.po | 54 -------------------------------------- src/qt/languages/cs-CZ.po | 54 -------------------------------------- src/qt/languages/de-DE.po | 54 -------------------------------------- src/qt/languages/en-GB.po | 12 --------- src/qt/languages/es-ES.po | 54 -------------------------------------- src/qt/languages/fi-FI.po | 51 ----------------------------------- src/qt/languages/fr-FR.po | 54 -------------------------------------- src/qt/languages/hr-HR.po | 54 -------------------------------------- src/qt/languages/hu-HU.po | 54 -------------------------------------- src/qt/languages/it-IT.po | 54 -------------------------------------- src/qt/languages/ja-JP.po | 54 -------------------------------------- src/qt/languages/ko-KR.po | 54 -------------------------------------- src/qt/languages/nl-NL.po | 54 -------------------------------------- src/qt/languages/pl-PL.po | 54 -------------------------------------- src/qt/languages/pt-BR.po | 54 -------------------------------------- src/qt/languages/pt-PT.po | 54 -------------------------------------- src/qt/languages/ru-RU.po | 54 -------------------------------------- src/qt/languages/sk-SK.po | 53 ------------------------------------- src/qt/languages/sl-SI.po | 54 -------------------------------------- src/qt/languages/tr-TR.po | 54 -------------------------------------- src/qt/languages/uk-UA.po | 54 -------------------------------------- src/qt/languages/vi-VN.po | 54 -------------------------------------- src/qt/languages/zh-CN.po | 54 -------------------------------------- src/qt/languages/zh-TW.po | 54 -------------------------------------- 25 files changed, 1304 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 6e610d715..15c605449 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -306,18 +306,12 @@ msgstr "" msgid "Cancel" msgstr "" -msgid "Save these settings as &global defaults" -msgstr "" - msgid "&Default" msgstr "" msgid "Language:" msgstr "" -msgid "Icon set:" -msgstr "" - msgid "Gain" msgstr "" @@ -753,9 +747,6 @@ msgstr "" msgid "KB" msgstr "" -msgid "Could not initialize the video renderer." -msgstr "" - msgid "Default" msgstr "" @@ -906,9 +897,6 @@ msgstr "" msgid "OpenGL Shaders" msgstr "" -msgid "OpenGL options" -msgstr "" - msgid "You are loading an unsupported configuration" msgstr "" @@ -930,12 +918,6 @@ msgstr "" msgid "Cartridge images" msgstr "" -msgid "Error initializing renderer" -msgstr "" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "" - msgid "Resume execution" msgstr "" @@ -1293,21 +1275,6 @@ msgstr "" msgid "NIC %02i (%ls) %ls" msgstr "" -msgid "Error opening \"%1\": %2" -msgstr "" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "" - -msgid "Error linking shader program in file \"%1\"" -msgstr "" - -msgid "OpenGL 3.0 renderer options" -msgstr "" - msgid "Render behavior" msgstr "" @@ -1320,9 +1287,6 @@ msgstr "" msgid "VSync" msgstr "" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "" - msgid "Synchronize with video" msgstr "" @@ -1332,21 +1296,9 @@ msgstr "" msgid "Remove" msgstr "" -msgid "No shader selected" -msgstr "" - msgid "Browse..." msgstr "" -msgid "Shader error" -msgstr "" - -msgid "Could not load shaders." -msgstr "" - -msgid "More information in details." -msgstr "" - msgid "Couldn't create OpenGL context." msgstr "" @@ -1356,18 +1308,12 @@ msgstr "" msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "" -msgid "OpenGL initialization failed. Error %1." -msgstr "" - msgid "Error initializing OpenGL" msgstr "" msgid "Falling back to software rendering.\n" msgstr "" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 8c89c6bad..26e51fe68 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -306,18 +306,12 @@ msgstr "D'acord" msgid "Cancel" msgstr "Anuŀlació" -msgid "Save these settings as &global defaults" -msgstr "Salvar aquests paràmetres com per &defecte globalment" - msgid "&Default" msgstr "&Per defecte" msgid "Language:" msgstr "Idioma:" -msgid "Icon set:" -msgstr "Conjunt d'icones:" - msgid "Gain" msgstr "Guany" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "No has estat possible inicialitzar el renderitzador de vídeo." - msgid "Default" msgstr "Per defecte" @@ -906,9 +897,6 @@ msgstr "Monitor en mode estalvi" msgid "OpenGL Shaders" msgstr "Shaders OpenGL" -msgid "OpenGL options" -msgstr "Opcions OpenGL" - msgid "You are loading an unsupported configuration" msgstr "S'està carregant una configuració no suportada" @@ -930,12 +918,6 @@ msgstr "Cartutx %i: %ls" msgid "Cartridge images" msgstr "Imatges de cartutx" -msgid "Error initializing renderer" -msgstr "Error en inicialitzar el renderitzador" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "No has estat possible inicialitzar el renderitzador OpenGL (3.0 Core). Utilitzar un altre renderitzador." - msgid "Resume execution" msgstr "Reprendre l'execució" @@ -1293,21 +1275,6 @@ msgstr "Controlador nul" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Error d'obertura \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Error en recopilar el vertex shader al fitxer \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Error en recopilar el fragment shader al fitxer \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Error en enllaçar el programa de shader al fitxer \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opcions del renderitzador OpenGL 3.0" - msgid "Render behavior" msgstr "Comportament del renderitzador" @@ -1320,9 +1287,6 @@ msgstr " fotogrames/s" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Feu que cada fotograma sigui immediatament, en sincronització amb la pantalla emulada.</p><p><span style=" font-style:italic;">Aquesta és l’opció recomanada si els shaders en ús no utilitzen FrameTime per a efectes animats.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sincronitzar amb vídeo" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Supressió" -msgid "No shader selected" -msgstr "Cap shader seleccionat" - msgid "Browse..." msgstr "Navegació..." -msgid "Shader error" -msgstr "Error del shader" - -msgid "Could not load shaders." -msgstr "No has estat possible carregar els shaders." - -msgid "More information in details." -msgstr "Més informació en els detalls." - msgid "Couldn't create OpenGL context." msgstr "No has estat possible crear un context d'OpenGL." @@ -1356,18 +1308,12 @@ msgstr "No has estat possible canviar al context d'OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Es requereix la versió 3.0 o superior d'OpenGL. La versió actual és %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "No has estat possible inicialitzar OpenGL. Error %1." - msgid "Error initializing OpenGL" msgstr "Error en inicialitzar OpenGL" msgid "Falling back to software rendering.\n" msgstr "Tornant al renderitzador software.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "No has estat possible assignar la memòria per a un buffer de desempaquetament.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Quan seleccioneu imatges de suports (CD-ROM, disquet, etc.), el diàleg obert s’iniciarà al mateix directori que el fitxer de configuració 86Box. Aquesta configuració només farà una diferència en les macOS.</p></body></html>" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 2a26f7ef6..099245033 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Storno" -msgid "Save these settings as &global defaults" -msgstr "Uložit toto nastavení jako &globální výchozí stav" - msgid "&Default" msgstr "&Výchozí" msgid "Language:" msgstr "Jazyk:" -msgid "Icon set:" -msgstr "Sada ikon:" - msgid "Gain" msgstr "Zesílení" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Nastala chyba při inicializaci video rendereru." - msgid "Default" msgstr "Výchozí" @@ -906,9 +897,6 @@ msgstr "Monitor je v režimu spánku" msgid "OpenGL Shaders" msgstr "Shadery OpenGL" -msgid "OpenGL options" -msgstr "Možnosti OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Pokoušíte se spustit nepodporovanou konfiguraci" @@ -930,12 +918,6 @@ msgstr "Cartridge %i: %ls" msgid "Cartridge images" msgstr "Obrazy cartridge" -msgid "Error initializing renderer" -msgstr "Chyba při inicializaci vykreslovače" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Vykreslovač OpenGL (3.0 Core) se nepodařilo inicializovat. Použijte jiný renderer." - msgid "Resume execution" msgstr "Obnovit" @@ -1293,21 +1275,6 @@ msgstr "Nulový ovladač" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Chyba při otevírání \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Chyba při kompilaci vertex shaderu v souboru \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Chyba při kompilaci fragment shaderu v souboru \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Chyba při linkování shader programu v souboru \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Možnosti vykreslovače OpenGL 3.0" - msgid "Render behavior" msgstr "Chování vykreslování" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Každý snímek se vykreslí okamžitě, synchronizovaně s emulovaným displejem.</p><p><span style=" font-style:italic;">Tuto možnost doporučujeme, pokud používané shadery nevyužívají frametime pro animované efekty.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synchronizovat s obrazem" @@ -1332,21 +1296,9 @@ msgstr "Shadery" msgid "Remove" msgstr "Odstraň" -msgid "No shader selected" -msgstr "Není vybrán žádný shader" - msgid "Browse..." msgstr "Prohlížejte..." -msgid "Shader error" -msgstr "Chyba shaderu" - -msgid "Could not load shaders." -msgstr "Nepodařilo se načíst shadery." - -msgid "More information in details." -msgstr "Více informací v podrobnostech." - msgid "Couldn't create OpenGL context." msgstr "Nepodařilo se vytvořit kontext OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Nepodařilo se přepnout na kontext OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Je vyžadována verze OpenGL 3.0 nebo vyšší. Aktuální verze je %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Inicializace OpenGL se nezdařila. Chyba %1." - msgid "Error initializing OpenGL" msgstr "Chyba při inicializaci OpenGL" msgid "Falling back to software rendering.\n" msgstr "Návrat k softwarovému vykreslování.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Alokace paměti pro rozbalovací vyrovnávací paměť se nezdařila.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Při výběru obrazů médií (CD-ROM, disketa atd.) se otevřené dialogové okno spustí ve stejném adresáři jako konfigurační soubor 86Box. Toto nastavení bude mít pravděpodobně význam pouze v systému MacOS.</p></body></html>" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index fbb97a990..eae29f084 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Abbrechen" -msgid "Save these settings as &global defaults" -msgstr "Einstellungen als &globalen Standard speichern" - msgid "&Default" msgstr "&Standard" msgid "Language:" msgstr "Sprache:" -msgid "Icon set:" -msgstr "Icon-Satz:" - msgid "Gain" msgstr "Verstärkung" @@ -756,9 +750,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Der Videorenderer konnte nicht initialisiert werden." - msgid "Default" msgstr "Standard" @@ -909,9 +900,6 @@ msgstr "Monitor im Standbymodus" msgid "OpenGL Shaders" msgstr "OpenGL-Shader" -msgid "OpenGL options" -msgstr "OpenGL-Optionen" - msgid "You are loading an unsupported configuration" msgstr "Zur Zeit wird eine nicht unterstützte Konfiguration geladen" @@ -933,12 +921,6 @@ msgstr "Cartridge %i: %ls" msgid "Cartridge images" msgstr "Cartridgeabbilder" -msgid "Error initializing renderer" -msgstr "Fehler bei der Initialisierung des Renderer" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Der OpenGL (3.0-Kern)-Renderer konnte nicht initialisiert werden. Benutze einen anderen Renderer." - msgid "Resume execution" msgstr "Fortsetzen" @@ -1296,21 +1278,6 @@ msgstr "Nulltreiber" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Fehler beim Öffnen \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Fehler beim Kompilieren des Vertex-Shaders in der Datei \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Fehler beim Kompilieren des Fragment-Shaders in der Datei \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Fehler beim Linken des Shader-Programms in der Datei \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 Renderer-Optionen" - msgid "Render behavior" msgstr "Rendering-Verhalten" @@ -1323,9 +1290,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Jedes Bild sofort rendern, synchron mit der emulierten Monitor.</p><p><span style=" font-style:italic;">Dies ist die empfohlene Option, wenn die verwendeten Shader die Bildzeit für animierte Effekte nicht nutzen.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Mit Videoausgabe synchronisieren" @@ -1335,21 +1299,9 @@ msgstr "Shader" msgid "Remove" msgstr "Entfernen" -msgid "No shader selected" -msgstr "Kein Shader ausgewählt" - msgid "Browse..." msgstr "Durchsuchen..." -msgid "Shader error" -msgstr "Shader-Fehler" - -msgid "Could not load shaders." -msgstr "Shader konnten nicht geladen werden." - -msgid "More information in details." -msgstr "Weitere Informationen im Einzelnen." - msgid "Couldn't create OpenGL context." msgstr "OpenGL-Kontext konnte nicht erstellt werden." @@ -1359,18 +1311,12 @@ msgstr "Konnte nicht in den OpenGL-Kontext wechseln." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL-Version 3.0 oder höher ist erforderlich. Die aktuelle Version ist %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL-Initialisierung fehlgeschlagen. Fehler %1." - msgid "Error initializing OpenGL" msgstr "Fehler beim Initialisieren von OpenGL" msgid "Falling back to software rendering.\n" msgstr "Rückgriff auf Software-Rendering.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Nicht genug Speicher zum Entpacken.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Bei der Auswahl von Medien-Abbildern (CD-ROM, Diskette usw.) wird der Öffnungsdialog im selben Verzeichnis wie die 86Box-Konfigurationsdatei gestartet. Diese Einstellung macht wahrscheinlich nur unter macOS einen Unterschied.</p></body></html>" diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index bd3a5ba99..b9f79882f 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -15,15 +15,6 @@ msgstr "&RGB Greyscale" msgid "Time synchronization" msgstr "Time synchronisation" -msgid "Could not initialize the video renderer." -msgstr "Could not initialise the video renderer." - -msgid "Error initializing renderer" -msgstr "Error initialising renderer" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core) renderer could not be initialised. Use another renderer." - msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." @@ -33,9 +24,6 @@ msgstr "Apply fullscreen stretch mode when maximised" msgid "Render behavior" msgstr "Render behaviour" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilise frametime for animated effects.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synchronise with video" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 1a5550065..14d6a6383 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -306,18 +306,12 @@ msgstr "Aceptar" msgid "Cancel" msgstr "Cancelar" -msgid "Save these settings as &global defaults" -msgstr "Salvar estos configuraciones como por &defecto globalmente" - msgid "&Default" msgstr "&Por defecto" msgid "Language:" msgstr "Idioma:" -msgid "Icon set:" -msgstr "Juego de iconos:" - msgid "Gain" msgstr "Ganancia" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "No fué posible inicializar el renderizador de vídeo." - msgid "Default" msgstr "Por defecto" @@ -906,9 +897,6 @@ msgstr "Monitor en modo ahorro" msgid "OpenGL Shaders" msgstr "Shaders OpenGL" -msgid "OpenGL options" -msgstr "Opciones OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Está cargando una configuración no soportada" @@ -930,12 +918,6 @@ msgstr "Cartucho %i: %ls" msgid "Cartridge images" msgstr "Imágenes de Cartucho" -msgid "Error initializing renderer" -msgstr "Error al inicializar el renderizador" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "No fué posible inicializar el renderizador OpenGL (3.0 Core). Utilice otro renderizador." - msgid "Resume execution" msgstr "Retomar la ejecución" @@ -1292,21 +1274,6 @@ msgstr "Controlador nulo" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Error al abrir \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Error al compilar el vertex shader en el archivo \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Error al compilar el fragmentshader en el archivo \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Error al enlazar el programa shader en el archivo \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opciones del renderizador OpenGL 3.0" - msgid "Render behavior" msgstr "Comportamiento del renderizador" @@ -1319,9 +1286,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderiza cada fotograma inmediatamente, en sincronía con la pantalla emulada.</p><p><span style=" font-style:italic;">Esta es la opción recomendada si los shaders en uso no utilizan frametime para efectos animados.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sincronizar con los gráficos" @@ -1331,21 +1295,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Eliminar" -msgid "No shader selected" -msgstr "Ningun shader seleccionado" - msgid "Browse..." msgstr "Buscar..." -msgid "Shader error" -msgstr "Error del shader" - -msgid "Could not load shaders." -msgstr "No ha sido posible carregar los shaders." - -msgid "More information in details." -msgstr "Más informaciones en los detalles." - msgid "Couldn't create OpenGL context." msgstr "No ha sido posible crear el contexto OpenGL." @@ -1355,18 +1307,12 @@ msgstr "No ha sido posible cambiar al contexto OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Es requerida la versión 3.0 o más alta de OpenGL. La versión actual es %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "La inicialización de OpenGL no tuvo éxito. Error %1." - msgid "Error initializing OpenGL" msgstr "Error al inicializar OpenGL" msgid "Falling back to software rendering.\n" msgstr "Recurrir al renderizado por software.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "La allocación de memoria para el búfer de desempaquetado no tuvo éxito.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Al seleccionar imágenes multimedia (CD-ROM, disquete, etc.), el diálogo de apertura se iniciará en el mismo directorio que el archivo de configuración de 86Box. Es probable que este ajuste sólo suponga una diferencia en macOS.</p></body></html>" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 5222ccc45..1408522fc 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Peruuta" -msgid "Save these settings as &global defaults" -msgstr "Tallenna nämä asetukset &globaaleiksi oletuksiksi" - msgid "&Default" msgstr "&Oletus" msgid "Language:" msgstr "Kieli:" -msgid "Icon set:" -msgstr "Kuvakkeet:" - msgid "Gain" msgstr "Taso" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "Kt" -msgid "Could not initialize the video renderer." -msgstr "Videorenderöijän alustus epäonnistui" - msgid "Default" msgstr "Oletus" @@ -906,9 +897,6 @@ msgstr "Näyttö lepotilassa" msgid "OpenGL Shaders" msgstr "OpenGL-varjostinohjelmat" -msgid "OpenGL options" -msgstr "OpenGL-asetukset" - msgid "You are loading an unsupported configuration" msgstr "Olet lataamassa ei-tuettuja määrittelyjä" @@ -930,12 +918,6 @@ msgstr "ROM-moduuli %i: %ls" msgid "Cartridge images" msgstr "ROM-moduulikuvat" -msgid "Error initializing renderer" -msgstr "Virhe renderöijän alustuksessa" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core)-renderöijän alustus epäonnistui. Käytä toista renderöijää." - msgid "Resume execution" msgstr "Jatka suoritusta" @@ -1293,21 +1275,6 @@ msgstr "Nolla-ajuri" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Virhe \"%1\" avaamisessa: %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Virhe vertex-shaderin kääntämisessä tiedostossa \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Virhe fragmenttivarjostimen kääntämisessä tiedostossa \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Virhe varjostinohjelman linkittämisessä tiedostoon \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0-alustusasetukset" - msgid "Render behavior" msgstr "Renderöintikäyttäytyminen" @@ -1320,9 +1287,6 @@ msgstr " ruutua/s" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderöi jokainen ruutu välittömästi synkronoidusti emuloidun näytön kanssa.</p><p><span style=" font-style:italic;">Tämä on suositeltava vaihtoehto, jos käytössä olevat varjostimet eivät käytä frametimeä animaatioefekteihin.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synkronisoi videoon" @@ -1338,15 +1302,6 @@ msgstr "Ei valittu varjostinohjelmatta" msgid "Browse..." msgstr "Selaa..." -msgid "Shader error" -msgstr "Varjostinohjelmatvirhe" - -msgid "Could not load shaders." -msgstr "Varjostinohjelmateita ei voitu ladata." - -msgid "More information in details." -msgstr "Lisätietoja yksityiskohtaisesti." - msgid "Couldn't create OpenGL context." msgstr "OpenGL-kontekstia ei voitu luoda." @@ -1356,18 +1311,12 @@ msgstr "Ei voitu siirtyä OpenGL-kontekstiin." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Tarvitaan OpenGL-versio 3.0 tai uudempi. Nykyinen versio on %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL:n alustaminen epäonnistui. Virhe %1." - msgid "Error initializing OpenGL" msgstr "Virhe OpenGL:n alustamisessa" msgid "Falling back to software rendering.\n" msgstr "Paluu ohjelmistoalustusöintiin.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Pakkauspuskurin muistin varaaminen epäonnistui.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Kun valitset mediakuvia (CD-ROM, levykkeet jne.), avausikkuna käynnistyy samaan hakemistoon kuin 86Boxin konfigurointitiedosto. Tällä asetuksella on todennäköisesti merkitystä vain macOS-käyttöjärjestelmässä.</p></body></html>" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 9937cecd4..829a9658b 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Annuler" -msgid "Save these settings as &global defaults" -msgstr "Sauvegarder ces paramètres comme valeurs par défaut &globales" - msgid "&Default" msgstr "&Défaut" msgid "Language:" msgstr "Langue:" -msgid "Icon set:" -msgstr "Ensemble d'icônes:" - msgid "Gain" msgstr "Gain" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "Ko" -msgid "Could not initialize the video renderer." -msgstr "Impossible d'initialiser le moteur de rendu vidéo." - msgid "Default" msgstr "Défaut" @@ -906,9 +897,6 @@ msgstr "Moniteur en mode veille" msgid "OpenGL Shaders" msgstr "Shaders OpenGL" -msgid "OpenGL options" -msgstr "Options OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Vous chargez une configuration non prise en charge" @@ -930,12 +918,6 @@ msgstr "Cartouche %i: %ls" msgid "Cartridge images" msgstr "Images cartouche" -msgid "Error initializing renderer" -msgstr "Erreur d'initialisation du moteur de rendu" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Le moteur de rendu OpenGL (3.0 Core) n'a pas pu être initialisé. Utilisez un autre moteur de rendu." - msgid "Resume execution" msgstr "Reprendre l'exécution" @@ -1293,21 +1275,6 @@ msgstr "Pilote nul" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Erreur d'ouverture de \"%1\" : %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Erreur de compilation du vertex shader dans le fichier \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Erreur de compilation du fragment shader dans le fichier \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Erreur de liaison du programme shader dans le fichier \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Options de rendu OpenGL 3.0" - msgid "Render behavior" msgstr "Comportement de rendu" @@ -1320,9 +1287,6 @@ msgstr " mages par seconde" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Rendre chaque image immédiatement, en synchronisation avec l'affichage émulé.</p><p><span style=" font-style:italic;">C'est l'option recommandée si les shaders utilisés n'utilisent pas le frametime pour les effets animés.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synchronisation avec la vidéo" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Retirer" -msgid "No shader selected" -msgstr "Pas de shader sélectionné" - msgid "Browse..." msgstr "Parcourir..." -msgid "Shader error" -msgstr "Erreur de shader" - -msgid "Could not load shaders." -msgstr "Impossible de charger les shaders." - -msgid "More information in details." -msgstr "Plus d'informations dans les détails." - msgid "Couldn't create OpenGL context." msgstr "Impossible de créer un contexte OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Impossible de passer au contexte OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "La version 3.0 ou supérieure d'OpenGL est requise. La version actuelle est %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "L'initialisation d'OpenGL a échoué. Erreur %1." - msgid "Error initializing OpenGL" msgstr "Erreur d'initialisation d'OpenGL" msgid "Falling back to software rendering.\n" msgstr "Se rabattre sur le rendu logiciel.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "L'allocation de mémoire pour le tampon de décompression a échoué.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Lors de la sélection d'images multimédia (CD-ROM, disquette, etc.), la boîte de dialogue d'ouverture démarrera dans le même répertoire que le fichier de configuration de 86Box. Ce paramètre ne fera probablement une différence que sur macOS.</p></body></html>" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 7a8aa53e4..6ca3ad8f5 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -306,18 +306,12 @@ msgstr "U redu" msgid "Cancel" msgstr "Otkaži" -msgid "Save these settings as &global defaults" -msgstr "Spremite ove postavke kao &globalne zadane postavke" - msgid "&Default" msgstr "Zadano" msgid "Language:" msgstr "Jezik:" -msgid "Icon set:" -msgstr "Paket ikona:" - msgid "Gain" msgstr "Pojačavanje" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Nije moguće inicijalizirati renderer." - msgid "Default" msgstr "Standard" @@ -906,9 +897,6 @@ msgstr "Ekran u stanju mirovanja" msgid "OpenGL Shaders" msgstr "OpenGL shaderi" -msgid "OpenGL options" -msgstr "OpenGL opcije" - msgid "You are loading an unsupported configuration" msgstr "Učitavate nepodržanu konfiguraciju" @@ -930,12 +918,6 @@ msgstr "Kaseta %i: %ls" msgid "Cartridge images" msgstr "Slike kasete" -msgid "Error initializing renderer" -msgstr "Nije moguće inicijalizirati renderer" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Nije moguće inicijalizirati OpenGL (3.0 jezgra) renderer. Molimte koristite drugi renderer." - msgid "Resume execution" msgstr "Nastavi" @@ -1293,21 +1275,6 @@ msgstr "Nulti upravljački program" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Nije moguće otvoriti \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Nije moguće sastaviti vertex shader u datoteci \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Nije moguće sastaviti framgent shader u datoteci \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Nije moguće povezati program shader u datoteci \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opcije renderera OpenGL 3.0" - msgid "Render behavior" msgstr "Ponašanje rendera" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Odmah napravi svaki okvir, sinkronizirano s emuliranim zaslonom.</p><p><span style=" font-style:italic;">Ovo je preporučena opcija, ako korišćeni shader ne koristi vreme okvira za animirane efekte.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sinkroniziraj s videom" @@ -1332,21 +1296,9 @@ msgstr "Shaderi" msgid "Remove" msgstr "Ukloni" -msgid "No shader selected" -msgstr "Bez odabranog shadera" - msgid "Browse..." msgstr "Pregledajte..." -msgid "Shader error" -msgstr "Greška shadera" - -msgid "Could not load shaders." -msgstr "Nije moguće učitati shadere." - -msgid "More information in details." -msgstr "Više informacija u detaljima." - msgid "Couldn't create OpenGL context." msgstr "Nije moguće stvoriti kontekst OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Nije se moguće prebaciti na kontekst OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Potrebna je OpenGL verzija 3.0 ili više. Trenutna verzija je %1. %2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Nije moguće inicijalizirati OpenGL. Greška %1." - msgid "Error initializing OpenGL" msgstr "Nije moguće inicijalizirati OpenGL" msgid "Falling back to software rendering.\n" msgstr "Vraća se na softverski renderer.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Nije moguće idodijeliti memoriju za međuspremnik za raspakiranje.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Prilikom odabira medijskih slika (CD-ROM, diskete itd.), otvoreni dijalog zopočet će u istom direktoriju kao i konfiguracijska datoteka 86Box-a. Razlika će vjerojatno biti primjetna samo na macOS-u.</p></body></html>" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index c777c6dd7..7d6a434f7 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Mégse" -msgid "Save these settings as &global defaults" -msgstr "Beállítások mentése &globális alapértékként" - msgid "&Default" msgstr "&Alapértelmezett" msgid "Language:" msgstr "Nyelv:" -msgid "Icon set:" -msgstr "Ikonkészlet:" - msgid "Gain" msgstr "Hangerő" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Nem sikerült inicializálni a videó megjelenítőt." - msgid "Default" msgstr "Alapértelmezett" @@ -906,9 +897,6 @@ msgstr "Képernyő alvó módban" msgid "OpenGL Shaders" msgstr "OpenGL Shaderek" -msgid "OpenGL options" -msgstr "OpenGL beállítások" - msgid "You are loading an unsupported configuration" msgstr "Egy nem támogatott konfigurációt tölt be" @@ -930,12 +918,6 @@ msgstr "ROM-kazetta %i: %ls" msgid "Cartridge images" msgstr "ROM-kazetta képek" -msgid "Error initializing renderer" -msgstr "Hiba történt a renderelő inicializálásakor" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Az OpenGL (3.0 Core) megjelenítő-motort nem sikerült inicializálni. Kérem használjon másik renderelőt." - msgid "Resume execution" msgstr "Folytassa a végrehajtást" @@ -1293,21 +1275,6 @@ msgstr "Null Driver" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Hiba a \"%1\" megnyitásakor: %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Hiba a vertex shader fordításában a \"%1\" fájlban" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Hiba a fragment shader fordításában a \"%1\" fájlban" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Hiba a shader program összekapcsolásában a \"%1\" fájlban" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 renderelési beállítások" - msgid "Render behavior" msgstr "Renderelési viselkedés" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Az egyes képkockák azonnali, az emulált kijelzővel szinkronizált megjelenítése.</p><p><span style=" font-style:italic;"">Ez az ajánlott opció, ha a használt shaderek nem használják a frametime-ot az animált effektusokhoz.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Szinkronizálás a videóval" @@ -1332,21 +1296,9 @@ msgstr "Shaderek" msgid "Remove" msgstr "Távolítsa el a" -msgid "No shader selected" -msgstr "Nincs shader kiválasztva" - msgid "Browse..." msgstr "Böngésszen..." -msgid "Shader error" -msgstr "Shader hiba" - -msgid "Could not load shaders." -msgstr "Nem sikerült betölteni a shadereket." - -msgid "More information in details." -msgstr "További információ a részletekről." - msgid "Couldn't create OpenGL context." msgstr "Nem sikerült OpenGL-kontextust létrehozni." @@ -1356,18 +1308,12 @@ msgstr "Nem tudott OpenGL-kontextusra váltani." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Az OpenGL 3.0 vagy magasabb verziója szükséges. Az aktuális verzió %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Az OpenGL inicializálása sikertelen. Hiba %1." - msgid "Error initializing OpenGL" msgstr "Hiba az OpenGL inicializálásában" msgid "Falling back to software rendering.\n" msgstr "Visszatérés a szoftveres rendereléshez.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "A memória kiosztása a kicsomagolási pufferhez sikertelen.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>A médiaképek (CD-ROM, floppy stb.) kiválasztásakor a megnyitási párbeszédpanel ugyanabban a könyvtárban indul, mint a 86Box konfigurációs fájl. Ez a beállítás valószínűleg csak a macOS rendszerben jelent különbséget.</p></body></html>" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index adf5b0471..256337a0d 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Annulla" -msgid "Save these settings as &global defaults" -msgstr "Salva queste impostazioni come &predefinite globali" - msgid "&Default" msgstr "&Predefinito" msgid "Language:" msgstr "Lingua:" -msgid "Icon set:" -msgstr "Pacchetto di icone:" - msgid "Gain" msgstr "Guadagno" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Impossibile inizializzare il renderer video." - msgid "Default" msgstr "Predefinito" @@ -906,9 +897,6 @@ msgstr "Monitor in modalità riposo" msgid "OpenGL Shaders" msgstr "Shader OpenGL" -msgid "OpenGL options" -msgstr "Impostazioni OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Stai caricando una configurazione non supportata" @@ -930,12 +918,6 @@ msgstr "Cartuccia %i: %ls" msgid "Cartridge images" msgstr "Immagini cartuccia" -msgid "Error initializing renderer" -msgstr "Errore nell'inizializzazione del renderer" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Non è stato possibile inizializzare il renderer OpenGL (3.0 Core). Utilizzare un altro renderer." - msgid "Resume execution" msgstr "Riprendere l'esecuzione" @@ -1293,21 +1275,6 @@ msgstr "Driver nullo" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Errore nell'apertura di \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Errore nella compilazione di vertex shader nel file \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Errore nella compilazione dello shader dei frammenti nel file \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Errore nel collegamento del programma shader nel file \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opzioni del renderer OpenGL 3.0" - msgid "Render behavior" msgstr "Comportamento di rendering" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderizza ogni fotogramma immediatamente, in sincronia con la visualizzazione emulata.</p><p><span style=" font-style:italic;">Questa è l'opzione consigliata se gli shader in uso non utilizzano il frametime per gli effetti animati.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sincronizza col video" @@ -1332,21 +1296,9 @@ msgstr "Shader" msgid "Remove" msgstr "Rimuovere" -msgid "No shader selected" -msgstr "Nessuno shader selezionato" - msgid "Browse..." msgstr "Sfoglia..." -msgid "Shader error" -msgstr "Errore dello shader" - -msgid "Could not load shaders." -msgstr "Impossibile caricare gli shader." - -msgid "More information in details." -msgstr "Maggiori informazioni in dettaglio." - msgid "Couldn't create OpenGL context." msgstr "Impossibile creare un contesto OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Impossibile passare al contesto OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "È richiesta la versione OpenGL 3.0 o superiore. La versione attuale è %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Inizializzazione OpenGL non riuscita. Errore %1." - msgid "Error initializing OpenGL" msgstr "Errore nell'inizializzazione di OpenGL" msgid "Falling back to software rendering.\n" msgstr "Ricaduta sul rendering software." -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "L'allocazione della memoria per il buffer di disimballaggio non è riuscita." - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Quando si selezionano immagini multimediali (CD-ROM, floppy, ecc.) la finestra di dialogo di apertura si avvia nella stessa directory del file di configurazione di 86Box. Questa impostazione probabilmente farà la differenza solo su macOS.</p></body></html>" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index d51be2536..d38760f15 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "キャンセル" -msgid "Save these settings as &global defaults" -msgstr "これらの設定をグローバル既定値として保存(&G)" - msgid "&Default" msgstr "既定値(&D)" msgid "Language:" msgstr "言語:" -msgid "Icon set:" -msgstr "アイコンセット:" - msgid "Gain" msgstr "音量" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "ビデオレンダラーが初期化できません。" - msgid "Default" msgstr "既定値" @@ -906,9 +897,6 @@ msgstr "モニターのスリープモード" msgid "OpenGL Shaders" msgstr "OpenGLシェーダー" -msgid "OpenGL options" -msgstr "OpenGL設定" - msgid "You are loading an unsupported configuration" msgstr "サポートされていないコンフィグを読み込んでいます" @@ -930,12 +918,6 @@ msgstr "カートリッジ %i: %ls" msgid "Cartridge images" msgstr "カートリッジイメージ" -msgid "Error initializing renderer" -msgstr "レンダラーの初期化エラー" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core) レンダラーが初期化できません。別のレンダラーを使用してください。" - msgid "Resume execution" msgstr "実行を再開" @@ -1293,21 +1275,6 @@ msgstr "ヌル・ドライバー" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "\"%1\"を開く際にエラーが発生しました: %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "ファイル\"%1\"の頂点シェーダのコンパイルエラー。" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "ファイル\"%1\"のフラグメント・シェーダのコンパイル・エラー。" - -msgid "Error linking shader program in file \"%1\"" -msgstr "ファイル\"%1\"のシェーダープログラムのリンクエラー。" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0レンダラー設定" - msgid "Render behavior" msgstr "レンダリング動作" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSシンク" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>エミュレートされたディスプレイと同期して、各フレームを即座にレンダリングします。</p><p><span style=" font-style:italic;">これは、使用中のシェーダがアニメーション効果のためにフレームタイムを利用しない場合に推奨されるオプションです。</span></p></body></html>" - msgid "Synchronize with video" msgstr "ビデオと同期" @@ -1332,21 +1296,9 @@ msgstr "シェーダー" msgid "Remove" msgstr "削除" -msgid "No shader selected" -msgstr "シェーダーが選択されていない" - msgid "Browse..." msgstr "ブラウズ..." -msgid "Shader error" -msgstr "シェーダーエラー" - -msgid "Could not load shaders." -msgstr "シェーダーをロードできませんでした。" - -msgid "More information in details." -msgstr "詳細はこちら。" - msgid "Couldn't create OpenGL context." msgstr "OpenGLコンテキストを作成できませんでした。" @@ -1356,18 +1308,12 @@ msgstr "OpenGLコンテキストに切り替えられなかった。" msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGLのバージョン3.0以上が必要です。現在のバージョンは %1.%2 です。" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL の初期化に失敗しました。エラー %1。" - msgid "Error initializing OpenGL" msgstr "OpenGLの初期化エラー" msgid "Falling back to software rendering.\n" msgstr "ソフトウェアレンダリングに逆戻り。" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "アンパックバッファのメモリ確保に失敗しました。" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>メディアイメージ(CD-ROM、フロッピーなど)を選択するとき、オープンダイアログは86Box設定ファイルと同じディレクトリで開始します。この設定は、おそらく macOS でのみ違いがあります。</p></body></html>" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 859183fc1..dbf77106b 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -306,18 +306,12 @@ msgstr "확인" msgid "Cancel" msgstr "취소" -msgid "Save these settings as &global defaults" -msgstr "이 설정들을 전역 기본값으로 저장하기(&G)" - msgid "&Default" msgstr "기본값(&D)" msgid "Language:" msgstr "언어:" -msgid "Icon set:" -msgstr "아이콘셋:" - msgid "Gain" msgstr "증가값" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "비디오 렌더러를 초기화할 수 없습니다." - msgid "Default" msgstr "기본값" @@ -906,9 +897,6 @@ msgstr "모니터 절전 모드" msgid "OpenGL Shaders" msgstr "OpenGL 쉐이더" -msgid "OpenGL options" -msgstr "OpenGL 설정" - msgid "You are loading an unsupported configuration" msgstr "지원하지 않는 설정입니다" @@ -930,12 +918,6 @@ msgstr "카트리지 %i: %ls" msgid "Cartridge images" msgstr "카트리지 이미지" -msgid "Error initializing renderer" -msgstr "렌더러 초기화 오류" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core) 렌더러를 초기화할 수 없습니다. 다른 렌더러를 사용하십시오." - msgid "Resume execution" msgstr "실행 재개" @@ -1293,21 +1275,6 @@ msgstr "Null 드라이버" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "열기 오류 \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "파일 \"%1\"에서 버텍스 셰이더를 컴파일하는 동안 오류가 발생했습니다." - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "파일에서 조각 셰이더 컴파일 중 오류 발생 \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "파일에서 셰이더 프로그램 연결 중 오류 \"%1\"\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 렌더러 옵션" - msgid "Render behavior" msgstr "렌더링 동작" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>;에뮬레이트된 디스플레이와 동기화하여 각 프레임을 즉시 렌더링합니다.</p><p><span style=" font-style:italic;">사용 중인 셰이더가 애니메이션 효과에 프레임 시간을 활용하지 않는 경우 권장되는 옵션입니다.</span></p></body></html>" - msgid "Synchronize with video" msgstr "비디오와 동기" @@ -1332,21 +1296,9 @@ msgstr "셰이더" msgid "Remove" msgstr "제거" -msgid "No shader selected" -msgstr "셰이더를 선택하지 않음" - msgid "Browse..." msgstr "찾아보기..." -msgid "Shader error" -msgstr "셰이더 오류" - -msgid "Could not load shaders." -msgstr "셰이더를 로드할 수 없습니다." - -msgid "More information in details." -msgstr "자세한 내용은 자세히 알아보세요." - msgid "Couldn't create OpenGL context." msgstr "OpenGL 컨텍스트를 만들 수 없습니다." @@ -1356,18 +1308,12 @@ msgstr "OpenGL 컨텍스트로 전환할 수 없습니다." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL 버전 3.0 이상이 필요합니다. 현재 버전은 %1.%2입니다." -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL 초기화에 실패했습니다. 오류 %1입니다." - msgid "Error initializing OpenGL" msgstr "OpenGL 초기화 중 오류 발생" msgid "Falling back to software rendering.\n" msgstr "소프트웨어 렌더링으로 돌아가기.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "압축 해제 버퍼에 메모리를 할당하지 못했습니다.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>미디어 이미지(CD-ROM, 플로피 등)를 선택하면 86Box 구성 파일과 동일한 디렉터리에서 열기 대화 상자가 시작됩니다. 이 설정은 macOS에서만 차이가 있을 수 있습니다.</p></body></html>" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index cce4dfdc9..65e59331b 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Annuleren" -msgid "Save these settings as &global defaults" -msgstr "Sla deze instellingen op als &globale standaardinstellingen" - msgid "&Default" msgstr "&Standaard" msgid "Language:" msgstr "Taal:" -msgid "Icon set:" -msgstr "Pictogrammenset:" - msgid "Gain" msgstr "Versterking" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Kan de videorenderer niet initialiseren." - msgid "Default" msgstr "Standaard" @@ -906,9 +897,6 @@ msgstr "Monitor in slaapstand" msgid "OpenGL Shaders" msgstr "OpenGL Shaders" -msgid "OpenGL options" -msgstr "OpenGL-opties" - msgid "You are loading an unsupported configuration" msgstr "U laadt een configuratie die niet wordt ondersteund" @@ -930,12 +918,6 @@ msgstr "Cartridge %i: %ls" msgid "Cartridge images" msgstr "Cartridge-images" -msgid "Error initializing renderer" -msgstr "Fout bij het initialiseren van renderer" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core) renderer kon niet worden geïnitialiseerd. Gebruik een andere renderer." - msgid "Resume execution" msgstr "Hervat executie" @@ -1293,21 +1275,6 @@ msgstr "Null Driver" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Fout bij het openen van \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Fout bij het compileren van vertex shader in bestand \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Fout bij het compileren van fragment shader in bestand \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Fout bij koppelen shaderprogramma in bestand \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 renderer opties" - msgid "Render behavior" msgstr "Rendergedrag" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Onmiddellijk elk frame synchroon met het geëmuleerde beeldscherm renderen.</p><p><span style=" font-style:italic;">Dit is de aanbevolen optie als de gebruikte shaders geen frametime gebruiken voor geanimeerde effecten.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synchroniseren met video" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Verwijderen" -msgid "No shader selected" -msgstr "Geen shader geselecteerd" - msgid "Browse..." msgstr "Bladeren..." -msgid "Shader error" -msgstr "Shader-fout" - -msgid "Could not load shaders." -msgstr "Kan shaders niet laden." - -msgid "More information in details." -msgstr "Meer informatie in details." - msgid "Couldn't create OpenGL context." msgstr "Kan OpenGL context niet maken." @@ -1356,18 +1308,12 @@ msgstr "Kan niet overschakelen naar OpenGL context." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL versie 3.0 of hoger is vereist. De huidige versie is %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL initialisatie mislukt. Fout %1." - msgid "Error initializing OpenGL" msgstr "Fout bij het initialiseren van OpenGL" msgid "Falling back to software rendering.\n" msgstr "Terugvallen op software rendering.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Toewijzen van geheugen voor uitpakbuffer mislukt.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Bij het selecteren van media-images (CD-ROM, floppy, etc.) zal de \"open dialoog\" starten in dezelfde map als het 86Box configuratiebestand. Deze instelling is doet er waarschijnlijk alleen toe op macOS.</p></body></html>" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 26cc4bae6..bed21af24 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Anuluj" -msgid "Save these settings as &global defaults" -msgstr "Zapisz ustawienia jako &globalne ustawienia domyślne" - msgid "&Default" msgstr "&Domyślny" msgid "Language:" msgstr "Język:" -msgid "Icon set:" -msgstr "Zestaw ikon:" - msgid "Gain" msgstr "Wzmacniacz" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Nie można zainicjować renderera wideo." - msgid "Default" msgstr "Domyślny" @@ -906,9 +897,6 @@ msgstr "Monitor w trybie czuwania" msgid "OpenGL Shaders" msgstr "Shadery OpenGL" -msgid "OpenGL options" -msgstr "Opcje OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Ładujesz nieobsługiwaną konfigurację" @@ -930,12 +918,6 @@ msgstr "Kartrydż %i: %ls" msgid "Cartridge images" msgstr "Obrazy kartrydżu" -msgid "Error initializing renderer" -msgstr "Błąd inicjalizacji renderera" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Nie można zainicjować renderera OpenGL (3.0 Core). Użyj innego." - msgid "Resume execution" msgstr "Wznów wykonywanie" @@ -1293,21 +1275,6 @@ msgstr "Null Driver" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Błąd otwarcia \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Błąd kompilacji shadera wierzchołków w pliku \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Błąd kompilacji shadera fragmentów w pliku \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Błąd łączenia programu shader w pliku \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opcje renderowania OpenGL 3.0" - msgid "Render behavior" msgstr "Zachowanie renderowania" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderuj każdą klatkę natychmiast, w synchronizacji z emulowanym wyświetlaczem.</p><p><span style=" font-style:italic;">Jest to zalecana opcja, jeśli używane shadery nie wykorzystują frametime do animowanych efektów.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Zsynchronizuj z wideo" @@ -1332,21 +1296,9 @@ msgstr "Shadery" msgid "Remove" msgstr "Usuń" -msgid "No shader selected" -msgstr "Nie wybrano shadera" - msgid "Browse..." msgstr "Przeglądaj..." -msgid "Shader error" -msgstr "Błąd shadera" - -msgid "Could not load shaders." -msgstr "Nie można załadować shaderów." - -msgid "More information in details." -msgstr "Więcej informacji w szczegółach." - msgid "Couldn't create OpenGL context." msgstr "Nie można utworzyć kontekstu OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Nie można przełączyć na kontekst OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Wymagana jest wersja OpenGL 3.0 lub wyższa. Aktualna wersja to %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Inicjalizacja OpenGL nie powiodła się. Błąd %1." - msgid "Error initializing OpenGL" msgstr "Błąd inicjalizacji OpenGL" msgid "Falling back to software rendering.\n" msgstr "Powrót do renderowania oprogramowania.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Przydzielenie pamięci dla bufora rozpakowywania nie powiodło się.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Podczas wybierania obrazów nośników (CD-ROM, dyskietka itp.) otwarte okno dialogowe rozpocznie się w tym samym katalogu, co plik konfiguracyjny 86Box. To ustawienie prawdopodobnie będzie miało znaczenie tylko na macOS.</p></body></html>" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index b453d0f97..df606a635 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Cancelar" -msgid "Save these settings as &global defaults" -msgstr "Salvar estas configurações como &padrões globais" - msgid "&Default" msgstr "&Padrão" msgid "Language:" msgstr "Idioma:" -msgid "Icon set:" -msgstr "Conjunto de ícones:" - msgid "Gain" msgstr "Ganho" @@ -753,9 +747,6 @@ msgstr "SE" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Não foi possível inicializar o renderizador de vídeo." - msgid "Default" msgstr "Padrão" @@ -906,9 +897,6 @@ msgstr "Monitor em modo de suspensão" msgid "OpenGL Shaders" msgstr "Shaders OpenGL" -msgid "OpenGL options" -msgstr "Opções do OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Você está carregando uma configuração não suportada" @@ -930,12 +918,6 @@ msgstr "Cartucho %i: %ls" msgid "Cartridge images" msgstr "Imagens de cartucho" -msgid "Error initializing renderer" -msgstr "Erro ao inicializar o renderizador" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "O renderizador OpenGL (Núcleo 3.0) não pôde ser inicializado. Use outro renderizador." - msgid "Resume execution" msgstr "Continuar a execução" @@ -1293,21 +1275,6 @@ msgstr "Driver nulo" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Erro ao abrir \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Erro ao compilar o sombreador de vértice no arquivo \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Erro ao compilar o fragment shader no arquivo \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Erro ao vincular o programa de shader no arquivo \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opções do renderizador OpenGL 3.0" - msgid "Render behavior" msgstr "Comportamento de renderização" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderize cada quadro imediatamente, em sincronia com a tela emulada.</p><p><span style=" font-style:italic;">Essa é a opção recomendada se os shaders em uso não utilizarem o frametime para efeitos animados.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sincronizar com o vídeo" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Remover" -msgid "No shader selected" -msgstr "Nenhum shader selecionado" - msgid "Browse..." msgstr "Procurar..." -msgid "Shader error" -msgstr "Erro do sombreador" - -msgid "Could not load shaders." -msgstr "Não foi possível carregar os shaders." - -msgid "More information in details." -msgstr "Mais informações em detalhes." - msgid "Couldn't create OpenGL context." msgstr "Não foi possível criar o contexto OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Não foi possível alternar para o contexto OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "É necessária a versão 3.0 ou superior do OpenGL. A versão atual é %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Falha na inicialização do OpenGL. Erro %1." - msgid "Error initializing OpenGL" msgstr "Erro ao inicializar o OpenGL" msgid "Falling back to software rendering.\n" msgstr "Voltando à renderização de software.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Falha na alocação de memória para o buffer de descompactação.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Ao selecionar imagens de mídia (CD-ROM, disquete, etc.), a caixa de diálogo de abertura será iniciada no mesmo diretório do arquivo de configuração do 86Box. Essa configuração provavelmente só fará diferença no macOS.</p></body></html>" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index d732532ed..b3458bcdf 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Cancelar" -msgid "Save these settings as &global defaults" -msgstr "Guardar estas definições como padrões &globais" - msgid "&Default" msgstr "&Padrão" msgid "Language:" msgstr "Idioma:" -msgid "Icon set:" -msgstr "Pacote de ícones:" - msgid "Gain" msgstr "Ganho" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Não foi possível inicializar o renderizador vídeo." - msgid "Default" msgstr "Padrão" @@ -906,9 +897,6 @@ msgstr "Ecrã em modo de sono" msgid "OpenGL Shaders" msgstr "Shaders OpenGL" -msgid "OpenGL options" -msgstr "Opções de OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Está a carregar uma configuração sem suporte!" @@ -930,12 +918,6 @@ msgstr "Cartucho %i: %ls" msgid "Cartridge images" msgstr "Imagens de cartucho" -msgid "Error initializing renderer" -msgstr "Erro na inicialização do renderizador" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Não foi possível inicializar o renderizador OpenGL (3.0 Core). Utilize outro renderizador." - msgid "Resume execution" msgstr "Retomar execução" @@ -1293,21 +1275,6 @@ msgstr "Condutor nulo" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Erro ao abrir \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Erro ao compilar o sombreador de vértice no ficheiro \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Erro ao compilar o shader de fragmento no ficheiro \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Erro ao ligar o programa de shader no ficheiro \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Opções do renderizador OpenGL 3.0" - msgid "Render behavior" msgstr "Comportamento de renderização" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Renderiza cada frame imediatamente, em sincronia com o ecrã emulado.</p><p><span style=" font-style:italic;">Esta é a opção recomendada se os shaders em uso não utilizam frametime para efeitos animados.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sincronizar com vídeo" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Remover" -msgid "No shader selected" -msgstr "Nenhum sombreador selecionado" - msgid "Browse..." msgstr "Navegar..." -msgid "Shader error" -msgstr "Erro de shader" - -msgid "Could not load shaders." -msgstr "Não foi possível carregar os shaders." - -msgid "More information in details." -msgstr "Mais informações em pormenor." - msgid "Couldn't create OpenGL context." msgstr "Não foi possível criar o contexto OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Não foi possível mudar para o contexto OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "É necessária a versão 3.0 ou superior do OpenGL. A versão atual é %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Falha na inicialização do OpenGL. Erro %1." - msgid "Error initializing OpenGL" msgstr "Erro ao inicializar o OpenGL" msgid "Falling back to software rendering.\n" msgstr "Recuando para a renderização de software." -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Falha na atribuição de memória para a memória intermédia de descompactação.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Ao selecionar imagens multimédia (CD-ROM, disquete, etc.) a caixa de diálogo de abertura irá começar no mesmo diretório que o ficheiro de configuração da 86Box. Esta configuração provavelmente só fará diferença no macOS.</p></body></html>" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index e68e6bb10..6104d064f 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Отмена" -msgid "Save these settings as &global defaults" -msgstr "Сохранить эти параметры как &глобальные по умолчанию" - msgid "&Default" msgstr "&По умолчанию" msgid "Language:" msgstr "Язык:" -msgid "Icon set:" -msgstr "Набор иконок:" - msgid "Gain" msgstr "Усиление" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "КБ" -msgid "Could not initialize the video renderer." -msgstr "Не удалось инициализировать рендерер видео." - msgid "Default" msgstr "По умолчанию" @@ -906,9 +897,6 @@ msgstr "Монитор в спящем режиме" msgid "OpenGL Shaders" msgstr "Шейдеры OpenGL" -msgid "OpenGL options" -msgstr "Параметры OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Вы загружаете неподдерживаемую конфигурацию" @@ -930,12 +918,6 @@ msgstr "Картридж %i: %ls" msgid "Cartridge images" msgstr "Образы картриджей" -msgid "Error initializing renderer" -msgstr "Ошибка инициализации рендерера" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Невозможно инициализировать рендерер OpenGL (3.0). Пожалуйста, используйте другой рендерер." - msgid "Resume execution" msgstr "Возобновить выполнение" @@ -1293,21 +1275,6 @@ msgstr "Нулевой драйвер" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Ошибка при открытии \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Ошибка компиляции вершинного шейдера в файле \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Ошибка компиляции фрагментного шейдера в файле \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Ошибка компоновки программы шейдера в файле \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Параметры рендеринга OpenGL 3.0" - msgid "Render behavior" msgstr "Режим рендеринга" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "Вертикальная синхронизация" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Рендерить каждый кадр немедленно, синхронно с эмулируемым дисплеем.</p><p><span style="font-style:italic;">Это рекомендуемый вариант, если используемые шейдеры не используют время кадров для анимированных эффектов.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Синхронизация с видео" @@ -1332,21 +1296,9 @@ msgstr "Шейдеры" msgid "Remove" msgstr "Удалить" -msgid "No shader selected" -msgstr "Шейдер не выбран" - msgid "Browse..." msgstr "Обзор..." -msgid "Shader error" -msgstr "Ошибка шейдера" - -msgid "Could not load shaders." -msgstr "Не удалось загрузить шейдеры." - -msgid "More information in details." -msgstr "Более подробная информация в деталях." - msgid "Couldn't create OpenGL context." msgstr "Не удалось создать контекст OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Не удалось переключиться на контекст Ope msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Требуется OpenGL версии 3.0 или выше. Текущая версия %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Не удалось выполнить инициализацию OpenGL. Ошибка %1." - msgid "Error initializing OpenGL" msgstr "Ошибка инициализации OpenGL" msgid "Falling back to software rendering.\n" msgstr "Переключение на программный рендеринг.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Выделение памяти для буфера распаковки не удалось.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>При выборе образов носителей (CD-ROM, дискет и т. д.) диалог открытия будет запускаться в том же каталоге, что и файл конфигурации 86Box. Эта настройка, скорее всего, будет иметь значение только на macOS.</p></body></html>" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index c091780c2..9e6532267 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Storno" -msgid "Save these settings as &global defaults" -msgstr "Uložiť toto nastavenie ako &globálny východiskový stav" - msgid "&Default" msgstr "&Východiskové" msgid "Language:" msgstr "Jazyk:" -msgid "Icon set:" -msgstr "Súprava ikon:" - msgid "Gain" msgstr "Zosilnenie" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Nastala chyba pri inicializácii video renderera." - msgid "Default" msgstr "Východiskové" @@ -906,9 +897,6 @@ msgstr "Monitor je v režime spánku" msgid "OpenGL Shaders" msgstr "Shadery OpenGL" -msgid "OpenGL options" -msgstr "Možnosti OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Pokúšate sa spustiť nepodporovanú konfiguráciu" @@ -930,12 +918,6 @@ msgstr "Cartridge %i: %ls" msgid "Cartridge images" msgstr "Obrazy cartridge" -msgid "Error initializing renderer" -msgstr "Chyba pri inicializácii vykresľovača" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Vykresľovač OpenGL (3.0 Core) sa nepodarilo inicializovať. Použite iný renderer." - msgid "Resume execution" msgstr "Obnoviť" @@ -1293,20 +1275,6 @@ msgstr "Nulový ovládač" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Chyba pri otváraní \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Chyba kompilácie vertex shadera v súbore \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Chyba kompilácie fragment shadera v súbore \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Chyba pri prepojení shader programu v súbore \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Možnosti vykresľovania OpenGL 3.0" msgid "Render behavior" msgstr "Správanie pri vykresľovaní" @@ -1320,9 +1288,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Okamžite vykresliť každú snímku v synchronizácii s emulovaným displejom.</p><p><span style=" font-style:italic;">Toto je odporúčaná možnosť, ak používané shadery nevyužívajú frametime pre animované efekty.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Synchronizovať s obrazom" @@ -1332,21 +1297,9 @@ msgstr "Shadery" msgid "Remove" msgstr "Odstránenie stránky" -msgid "No shader selected" -msgstr "Nie je vybraný žiadny tieňovač" - msgid "Browse..." msgstr "Prehľadávať..." -msgid "Shader error" -msgstr "Chyba shadera" - -msgid "Could not load shaders." -msgstr "Nepodarilo sa načítať shadery." - -msgid "More information in details." -msgstr "Viac informácií v detailoch." - msgid "Couldn't create OpenGL context." msgstr "Nepodarilo sa vytvoriť kontext OpenGL." @@ -1356,18 +1309,12 @@ msgstr "Nepodarilo sa prepnúť na kontext OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Vyžaduje sa verzia OpenGL 3.0 alebo vyššia. Aktuálna verzia je %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Inicializácia OpenGL zlyhala. Chyba %1." - msgid "Error initializing OpenGL" msgstr "Chyba pri inicializácii OpenGL" msgid "Falling back to software rendering.\n" msgstr "Návrat k softvérovému vykresľovaniu.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Alokácia pamäte pre rozbaľovaciu vyrovnávaciu pamäť zlyhala.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Pri výbere multimediálnych obrazov (CD-ROM, disketa atď.) sa dialógové okno otvorenia spustí v rovnakom adresári ako konfiguračný súbor 86Box. Toto nastavenie bude mať pravdepodobne význam len v systéme MacOS.</p></body></html>" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 15041a4aa..efb62153a 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -306,18 +306,12 @@ msgstr "V redu" msgid "Cancel" msgstr "Prekliči" -msgid "Save these settings as &global defaults" -msgstr "Shrani te nastavitve kot globalne privzete" - msgid "&Default" msgstr "Privzeto" msgid "Language:" msgstr "Jezik:" -msgid "Icon set:" -msgstr "Komplet ikon:" - msgid "Gain" msgstr "Ojačanje" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Ne morem inicializirati sistema za upodabljanje." - msgid "Default" msgstr "Privzeto" @@ -906,9 +897,6 @@ msgstr "Zaslon v načinu spanja" msgid "OpenGL Shaders" msgstr "Senčilniki OpenGL" -msgid "OpenGL options" -msgstr "Možnosti OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Nalagate nepodprto konfiguracijo" @@ -930,12 +918,6 @@ msgstr "Spominski vložek %i: %ls" msgid "Cartridge images" msgstr "Slike spominskega vložka" -msgid "Error initializing renderer" -msgstr "Napaka pri zagonu sistema za upodabljanje" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Sistema za upodabljanje OpenGL (3.0 Core) ni bilo mogoče zagnati. Uporabite drug sistem za upodabljanje." - msgid "Resume execution" msgstr "Nadaljuj izvajanje" @@ -1293,21 +1275,6 @@ msgstr "Ničelni gonilnik" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Napaka pri odpiranju \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Napaka pri sestavljanju senčilnika vrhov v datoteki \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Napaka pri sestavljanju shaderja fragmentov v datoteki \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Napaka pri povezovanju programa shader v datoteki \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Možnosti sistema za upodabljanje OpenGL 3.0" - msgid "Render behavior" msgstr "Obnašanje pri upodabljanju" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Vsako sličico prikažite takoj, sinhronizirano z emuliranim zaslonom.</p><p><span style=" font-style:italic;">To je priporočljiva možnost, če uporabljeni senčilniki ne uporabljajo časa okvirja za animirane učinke.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Sinhroniziraj z videom" @@ -1332,21 +1296,9 @@ msgstr "Senčilniki" msgid "Remove" msgstr "Odstrani" -msgid "No shader selected" -msgstr "Ni izbran noben senčnik" - msgid "Browse..." msgstr "Brskaj..." -msgid "Shader error" -msgstr "Napaka senčilnika" - -msgid "Could not load shaders." -msgstr "Ni bilo mogoče naložiti senčilnikov." - -msgid "More information in details." -msgstr "Več informacij v podrobnostih." - msgid "Couldn't create OpenGL context." msgstr "Ni bilo mogoče ustvariti konteksta OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Ni bilo mogoče preklopiti na kontekst OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Zahteva se različica OpenGL 3.0 ali novejša. Trenutna različica je %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Inicializacija OpenGL ni uspela. Napaka %1." - msgid "Error initializing OpenGL" msgstr "Napaka pri inicializaciji OpenGL" msgid "Falling back to software rendering.\n" msgstr "Vrnitev k programskemu upodabljanju.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Dodelitev pomnilnika za razpakirni predpomnilnik ni uspela.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Pri izbiri medijskih slik (CD-ROM, disketa itd.) se bo odprto pogovorno okno začelo v istem imeniku kot konfiguracijska datoteka 86Box. Ta nastavitev bo verjetno imela pomen le v operacijskem sistemu MacOS.</p></body></html>" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index c16cc12e4..e3d692537 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -306,18 +306,12 @@ msgstr "Tamam" msgid "Cancel" msgstr "İptal" -msgid "Save these settings as &global defaults" -msgstr "Ayarları &varsayılan olarak kaydet" - msgid "&Default" msgstr "&Varsayılan" msgid "Language:" msgstr "Dil:" -msgid "Icon set:" -msgstr "Simge seti:" - msgid "Gain" msgstr "Artış" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Video işleyici başlatılamadı." - msgid "Default" msgstr "Varsayılan" @@ -906,9 +897,6 @@ msgstr "Monitör uyku modunda" msgid "OpenGL Shaders" msgstr "OpenGL gölgelendiricileri" -msgid "OpenGL options" -msgstr "OpenGL ayarları" - msgid "You are loading an unsupported configuration" msgstr "Desteklenmeyen bir konfigürasyon kullanıyorsunuz" @@ -930,12 +918,6 @@ msgstr "Kartuş %i: %ls" msgid "Cartridge images" msgstr "Kartuş imajları" -msgid "Error initializing renderer" -msgstr "İşleyici başlatılırken hata oluştu" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "OpenGL (3.0 Core) işleyici başlatılamadı. Başka bir görüntüleyici kullanın." - msgid "Resume execution" msgstr "Çalıştırmaya devam et" @@ -1293,21 +1275,6 @@ msgstr "Null sürücü" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "\"%1\": %2 açılırken hata oluştu" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "\"%1\" dosyasında tepe gölgelendirici derlenirken hata oluştu" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "\"%1\" dosyasında parça gölgelendirici derlenirken hata oluştu" - -msgid "Error linking shader program in file \"%1\"" -msgstr "\"%1\" dosyasında gölgelendirici programı bağlanırken hata oluştu" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 işleyici seçenekleri" - msgid "Render behavior" msgstr "İşleyiş davranışı" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Emüle edilen ekranla senkronize olarak her kareyi hemen işleyin.</p><p><span style=" font-style:italic;">Kullanılan gölgelendiriciler animasyonlu efektler için kare zamanını kullanmıyorsa bu önerilen seçenektir.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Video ile senkronize et" @@ -1332,21 +1296,9 @@ msgstr "Gölgelendiriciler" msgid "Remove" msgstr "Kaldır" -msgid "No shader selected" -msgstr "Gölgelendirici seçili değil" - msgid "Browse..." msgstr "Göz at..." -msgid "Shader error" -msgstr "Gölgelendirici hatası" - -msgid "Could not load shaders." -msgstr "Gölgelendiriciler yüklenemedi." - -msgid "More information in details." -msgstr "Daha fazla bilgi detaylardadır." - msgid "Couldn't create OpenGL context." msgstr "OpenGL bağlamı oluşturulamadı." @@ -1356,18 +1308,12 @@ msgstr "OpenGL bağlamına geçilemedi." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL sürüm 3.0 veya üstü gereklidir. Geçerli sürüm %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL başlatılamadı. Hata %1." - msgid "Error initializing OpenGL" msgstr "OpenGL başlatılırken hata oluştu" msgid "Falling back to software rendering.\n" msgstr "Yazılım işleyicisine geri dönülüyor.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Paket açma arabelleği için bellek ayırma başarısız oldu.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Medya görüntüsü (CD-ROM, disket, vb.) seçme diyaloğu 86Box yapılandırma dosyasıyla aynı dizinde başlayacaktır. Bu ayar muhtemelen sadece macOS üzerinde bir fark meydana getirecektir.</p></body></html>" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index bde9a4f51..687186f56 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -306,18 +306,12 @@ msgstr "OK" msgid "Cancel" msgstr "Відміна" -msgid "Save these settings as &global defaults" -msgstr "Зберегти ці параметри як &глобальні за замовчуванням" - msgid "&Default" msgstr "&За замовчуванням" msgid "Language:" msgstr "Мова:" -msgid "Icon set:" -msgstr "Набір іконок:" - msgid "Gain" msgstr "Посилення" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "КБ" -msgid "Could not initialize the video renderer." -msgstr "Не вдалося ініціалізувати рендер відео." - msgid "Default" msgstr "За замовчуванням" @@ -906,9 +897,6 @@ msgstr "Монітор у сплячому режимі" msgid "OpenGL Shaders" msgstr "Шейдери OpenGL" -msgid "OpenGL options" -msgstr "Параметри OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Ви завантажуєте непідтримувану конфігурацію" @@ -930,12 +918,6 @@ msgstr "Картридж %i: %ls" msgid "Cartridge images" msgstr "Образи картриджів" -msgid "Error initializing renderer" -msgstr "Помилка ініціалізації рендерера" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Неможливо ініціалізувати рендерер OpenGL (3.0). Будь ласка, використовуйте інший рендерер." - msgid "Resume execution" msgstr "Відновити виконання" @@ -1293,21 +1275,6 @@ msgstr "Нульовий драйвер" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Помилка відкриття \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Помилка компіляції вершинного шейдера у файлі \"%1\"." - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Помилка компіляції фрагментного шейдера у файлі \"%1\"." - -msgid "Error linking shader program in file \"%1\"" -msgstr "Помилка зв'язування шейдерної програми у файлі \"%1\"." - -msgid "OpenGL 3.0 renderer options" -msgstr "Параметри рендерингу OpenGL 3.0" - msgid "Render behavior" msgstr "Поведінка рендерингу" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Відображати кожен кадр миттєво, синхронно з емульованим дисплеєм.</p><p><span style=" font-style:italic;">Це рекомендований варіант, якщо використовувані шейдери не використовують час кадру для анімованих ефектів.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Синхронізація з відео" @@ -1332,21 +1296,9 @@ msgstr "Шейдери" msgid "Remove" msgstr "Видалити" -msgid "No shader selected" -msgstr "Не вибрано шейдер" - msgid "Browse..." msgstr "Переглянути..." -msgid "Shader error" -msgstr "Помилка шейдеру" - -msgid "Could not load shaders." -msgstr "Не вдалося завантажити шейдери." - -msgid "More information in details." -msgstr "Більше інформації в деталях." - msgid "Couldn't create OpenGL context." msgstr "Не вдалося створити контекст OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Не вдалося переключитися на контекст Ope msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "Потрібна версія OpenGL 3.0 або новіша. Поточна версія %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Не вдалося ініціалізувати OpenGL. Помилка %1." - msgid "Error initializing OpenGL" msgstr "Помилка ініціалізації OpenGL" msgid "Falling back to software rendering.\n" msgstr "Повернення до програмного рендерингу.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Не вдалося виділити пам'ять для буфера розпакування.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>При виборі медіа-образів (CD-ROM, дискета і т.д.) діалогове вікно буде відкриватися в тому ж каталозі, що і файл конфігурації 86Box. Цей параметр, швидше за все, матиме значення лише на macOS.</p></body></html>" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index fa9384d8f..55a70991c 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -306,18 +306,12 @@ msgstr "Đồng ý" msgid "Cancel" msgstr "Thôi" -msgid "Save these settings as &global defaults" -msgstr "Lưu cài đặt làm mặc định chung" - msgid "&Default" msgstr "&Mặc định" msgid "Language:" msgstr "Ngôn ngữ:" -msgid "Icon set:" -msgstr "Bộ biểu tượng:" - msgid "Gain" msgstr "Tăng" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "Không thể khởi tạo trình kết xuất (renderer) video ." - msgid "Default" msgstr "Mặc định" @@ -906,9 +897,6 @@ msgstr "Màn hình chế độ chờ/ngủ" msgid "OpenGL Shaders" msgstr "Shader OpenGL" -msgid "OpenGL options" -msgstr "Tùy chọn OpenGL" - msgid "You are loading an unsupported configuration" msgstr "Bạn đang load tinh chỉnh không được hỗ trợ." @@ -930,12 +918,6 @@ msgstr "Băng cartridge %i: %ls" msgid "Cartridge images" msgstr "Ảnh đĩa băng cartridge" -msgid "Error initializing renderer" -msgstr "Lỗi khởi tạo renderer (trình kết xuất)" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "Không khởi tạo được renderer OpenGL (3.0 Core). Hãy dùng renderer khác." - msgid "Resume execution" msgstr "Tiếp tục chạy thực thi" @@ -1293,21 +1275,6 @@ msgstr "Trình điều khiển NULL" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i ( %ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "Mở lỗi \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "Lỗi biên dịch shader đỉnh trong tệp \"%1\"" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "Lỗi biên dịch shader fragment trong tệp \"%1\"" - -msgid "Error linking shader program in file \"%1\"" -msgstr "Lỗi liên kết chương trình shader trong tệp \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "Tùy chọn kết xuất OpenGL 3.0" - msgid "Render behavior" msgstr "Hành vi kết xuất" @@ -1320,9 +1287,6 @@ msgstr " khung hình / giây" msgid "VSync" msgstr "Vsync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>Kết xuất mỗi khung ngay lập tức, đồng bộ với màn hình mô phỏng.</p><p><span style=" font-style:italic;">Đây là tùy chọn được đề xuất nếu các shader đang sử dụng không tối ưu frametime cho các hiệu ứng động.</span></p></body></html>" - msgid "Synchronize with video" msgstr "Đồng bộ với video" @@ -1332,21 +1296,9 @@ msgstr "Shaders" msgid "Remove" msgstr "Loại bỏ" -msgid "No shader selected" -msgstr "Không có shader được chọn" - msgid "Browse..." msgstr "Duyệt..." -msgid "Shader error" -msgstr "Lỗi shader" - -msgid "Could not load shaders." -msgstr "Không thể tải shader." - -msgid "More information in details." -msgstr "Thêm thông tin chi tiết." - msgid "Couldn't create OpenGL context." msgstr "Không thể tạo bối cảnh OpenGL." @@ -1356,18 +1308,12 @@ msgstr "Không thể chuyển sang bối cảnh OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL phiên bản 3.0 trở lên là bắt buộc. Phiên bản hiện tại là %1. %2" -msgid "OpenGL initialization failed. Error %1." -msgstr "Khởi tạo OpenGL không thành công. Lỗi %1." - msgid "Error initializing OpenGL" msgstr "Lỗi khởi tạo OpenGL" msgid "Falling back to software rendering.\n" msgstr "Quay trở lại kết xuất phần mềm.\n" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "Phân bổ bộ nhớ cho bộ đệm giải nén không thành công.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 4cccc071a..cd720c0ee 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -306,18 +306,12 @@ msgstr "确定" msgid "Cancel" msgstr "取消" -msgid "Save these settings as &global defaults" -msgstr "将以上设置存储为全局默认值(&G)" - msgid "&Default" msgstr "默认(&D)" msgid "Language:" msgstr "语言:" -msgid "Icon set:" -msgstr "图标集:" - msgid "Gain" msgstr "增益" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "无法初始化视频渲染器。" - msgid "Default" msgstr "默认" @@ -906,9 +897,6 @@ msgstr "显示器处在睡眠状态" msgid "OpenGL Shaders" msgstr "OpenGL 着色器" -msgid "OpenGL options" -msgstr "OpenGL 选项" - msgid "You are loading an unsupported configuration" msgstr "正在载入一个不受支持的配置" @@ -930,12 +918,6 @@ msgstr "卡带 %i: %ls" msgid "Cartridge images" msgstr "卡带映像" -msgid "Error initializing renderer" -msgstr "初始化渲染器时出错" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "无法初始化 OpenGL (3.0 Core) 渲染器。请使用其他渲染器。" - msgid "Resume execution" msgstr "恢复执行" @@ -1293,21 +1275,6 @@ msgstr "空驱动程序" msgid "NIC %02i (%ls) %ls" msgstr "NIC %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "打开 \"%1\": %2 时出错" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "文件 \"%1\" 中的顶点着色器编译出错" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "文件 \"%1\" 中的片段着色器编译出错" - -msgid "Error linking shader program in file \"%1\"" -msgstr "文件 \"%1\" 中的着色器程序链接出错" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 渲染器选项" - msgid "Render behavior" msgstr "渲染行为" @@ -1320,9 +1287,6 @@ msgstr " fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>与模拟显示同步,即时渲染每一帧。</p><p><span style=" font-style:italic;">如果使用的着色器不使用帧时间来产生动画效果,则建议使用此选项。</span></p></body></html>" - msgid "Synchronize with video" msgstr "与视频同步" @@ -1332,21 +1296,9 @@ msgstr "着色器" msgid "Remove" msgstr "移除" -msgid "No shader selected" -msgstr "未选择着色器" - msgid "Browse..." msgstr "浏览..." -msgid "Shader error" -msgstr "着色器错误" - -msgid "Could not load shaders." -msgstr "无法加载着色器。" - -msgid "More information in details." -msgstr "更多详细信息。" - msgid "Couldn't create OpenGL context." msgstr "无法创建 OpenGL 上下文。" @@ -1356,18 +1308,12 @@ msgstr "无法切换到 OpenGL 上下文。" msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "需要 OpenGL 3.0 或更高版本。当前版本为 %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL 初始化失败。错误 %1." - msgid "Error initializing OpenGL" msgstr "初始化 OpenGL 时出错" msgid "Falling back to software rendering.\n" msgstr "回到软件渲染。" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "为解包缓冲区分配内存失败.\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。</p></body></html>;" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 92c6502ea..a11ef8d44 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -306,18 +306,12 @@ msgstr "確定" msgid "Cancel" msgstr "取消" -msgid "Save these settings as &global defaults" -msgstr "將以上設定存儲為全局預設值(&G)" - msgid "&Default" msgstr "預設(&D)" msgid "Language:" msgstr "語言:" -msgid "Icon set:" -msgstr "圖示集:" - msgid "Gain" msgstr "增益" @@ -753,9 +747,6 @@ msgstr "S" msgid "KB" msgstr "KB" -msgid "Could not initialize the video renderer." -msgstr "無法初始化視訊渲染器。" - msgid "Default" msgstr "預設" @@ -906,9 +897,6 @@ msgstr "顯示器處在睡眠狀態" msgid "OpenGL Shaders" msgstr "OpenGL 著色器" -msgid "OpenGL options" -msgstr "OpenGL 選項" - msgid "You are loading an unsupported configuration" msgstr "正在載入一個不受支援的設定" @@ -930,12 +918,6 @@ msgstr "卡帶 %i: %ls" msgid "Cartridge images" msgstr "卡帶映像" -msgid "Error initializing renderer" -msgstr "初始化渲染器時出錯" - -msgid "OpenGL (3.0 Core) renderer could not be initialized. Use another renderer." -msgstr "無法初始化 OpenGL (3.0 Core) 渲染器。請使用其他渲染器。" - msgid "Resume execution" msgstr "恢復執行" @@ -1293,21 +1275,6 @@ msgstr "空驅動程式" msgid "NIC %02i (%ls) %ls" msgstr "網路卡 %02i (%ls) %ls" -msgid "Error opening \"%1\": %2" -msgstr "錯誤開啟 \"%1\": %2" - -msgid "Error compiling vertex shader in file \"%1\"" -msgstr "編譯檔案 \"%1\" 中的頂點著色器時發生錯誤" - -msgid "Error compiling fragment shader in file \"%1\"" -msgstr "編譯檔案 \"%1\" 中的片段著色器出錯" - -msgid "Error linking shader program in file \"%1\"" -msgstr "在檔案中連結shader程式出錯 \"%1\"" - -msgid "OpenGL 3.0 renderer options" -msgstr "OpenGL 3.0 渲染器選項" - msgid "Render behavior" msgstr "渲染行為" @@ -1320,9 +1287,6 @@ msgstr "fps" msgid "VSync" msgstr "VSync" -msgid "<html><head/><body><p>Render each frame immediately, in sync with the emulated display.</p><p><span style=" font-style:italic;">This is the recommended option if the shaders in use don't utilize frametime for animated effects.</span></p></body></html>" -msgstr "<html><head/><body><p>立即渲染每個畫面,與模擬顯示同步。</p><p><span style=" font-style:italic;">如果使用中的著色器不利用影格時間製作動畫效果,建議使用此選項。</span></p></body></html>" - msgid "Synchronize with video" msgstr "與視訊同步" @@ -1332,21 +1296,9 @@ msgstr "著色器" msgid "Remove" msgstr "移除" -msgid "No shader selected" -msgstr "未選擇著色器" - msgid "Browse..." msgstr "瀏覽..." -msgid "Shader error" -msgstr "著色器錯誤" - -msgid "Could not load shaders." -msgstr "無法載入著色器。" - -msgid "More information in details." -msgstr "更多詳細資訊。" - msgid "Couldn't create OpenGL context." msgstr "無法建立 OpenGL 上下文。" @@ -1356,18 +1308,12 @@ msgstr "無法切換至 OpenGL 上下文。" msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "需要 OpenGL 版本 3.0 或更高。目前版本為 %1.%2" -msgid "OpenGL initialization failed. Error %1." -msgstr "OpenGL 初始化失敗。錯誤 %1." - msgid "Error initializing OpenGL" msgstr "初始化 OpenGL 出錯" msgid "Falling back to software rendering.\n" msgstr "回退到軟體渲染。" -msgid "Allocating memory for unpack buffer failed.\n" -msgstr "為解除封包緩衝區分配記憶體失敗。\n" - msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>當選擇媒體映像 (CD-ROM、軟碟等) 時,開啟對話方塊會在與 86Box 設定檔相同的目錄中開始。此設定可能只會在 macOS 上有所影響。</p></body></html>" From c08775becfd721f587c3196b2a3b4d1378646e99 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 7 Apr 2025 19:50:42 +0500 Subject: [PATCH 0702/1190] qt: Use `util::DlgFilter` for the shader picker Also fix the translation for its filter --- src/qt/languages/86box.pot | 2 +- src/qt/languages/ca-ES.po | 4 ++-- src/qt/languages/cs-CZ.po | 4 ++-- src/qt/languages/de-DE.po | 4 ++-- src/qt/languages/es-ES.po | 4 ++-- src/qt/languages/fi-FI.po | 4 ++-- src/qt/languages/fr-FR.po | 4 ++-- src/qt/languages/hr-HR.po | 4 ++-- src/qt/languages/hu-HU.po | 4 ++-- src/qt/languages/it-IT.po | 4 ++-- src/qt/languages/ja-JP.po | 4 ++-- src/qt/languages/ko-KR.po | 4 ++-- src/qt/languages/nl-NL.po | 4 ++-- src/qt/languages/pl-PL.po | 4 ++-- src/qt/languages/pt-BR.po | 4 ++-- src/qt/languages/pt-PT.po | 4 ++-- src/qt/languages/ru-RU.po | 4 ++-- src/qt/languages/sk-SK.po | 4 ++-- src/qt/languages/sl-SI.po | 4 ++-- src/qt/languages/tr-TR.po | 4 ++-- src/qt/languages/uk-UA.po | 4 ++-- src/qt/languages/vi-VN.po | 4 ++-- src/qt/languages/zh-CN.po | 4 ++-- src/qt/languages/zh-TW.po | 4 ++-- src/qt/qt_openglshadermanagerdialog.cpp | 5 ++++- 25 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 15c605449..264060afe 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -894,7 +894,7 @@ msgstr "" msgid "Monitor in sleep mode" msgstr "" -msgid "OpenGL Shaders" +msgid "GLSL shaders" msgstr "" msgid "You are loading an unsupported configuration" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 26e51fe68..1d03316b6 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -894,8 +894,8 @@ msgstr "Configuració de Dispositiu %1" msgid "Monitor in sleep mode" msgstr "Monitor en mode estalvi" -msgid "OpenGL Shaders" -msgstr "Shaders OpenGL" +msgid "GLSL shaders" +msgstr "Shaders GLSL" msgid "You are loading an unsupported configuration" msgstr "S'està carregant una configuració no suportada" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 099245033..a5378a978 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -894,8 +894,8 @@ msgstr "Nastavení zařízení %1" msgid "Monitor in sleep mode" msgstr "Monitor je v režimu spánku" -msgid "OpenGL Shaders" -msgstr "Shadery OpenGL" +msgid "GLSL shaders" +msgstr "Shadery GLSL" msgid "You are loading an unsupported configuration" msgstr "Pokoušíte se spustit nepodporovanou konfiguraci" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index eae29f084..c3ca0953a 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -897,8 +897,8 @@ msgstr "%1-Gerätekonfiguration" msgid "Monitor in sleep mode" msgstr "Monitor im Standbymodus" -msgid "OpenGL Shaders" -msgstr "OpenGL-Shader" +msgid "GLSL shaders" +msgstr "GLSL-Shader" msgid "You are loading an unsupported configuration" msgstr "Zur Zeit wird eine nicht unterstützte Konfiguration geladen" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 14d6a6383..20a6eb351 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -894,8 +894,8 @@ msgstr "%1 Configuración de Dispositivo" msgid "Monitor in sleep mode" msgstr "Monitor en modo ahorro" -msgid "OpenGL Shaders" -msgstr "Shaders OpenGL" +msgid "GLSL shaders" +msgstr "Shaders GLSL" msgid "You are loading an unsupported configuration" msgstr "Está cargando una configuración no soportada" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 1408522fc..e12e27db4 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -894,8 +894,8 @@ msgstr "%1 - Laitteen määritykset" msgid "Monitor in sleep mode" msgstr "Näyttö lepotilassa" -msgid "OpenGL Shaders" -msgstr "OpenGL-varjostinohjelmat" +msgid "GLSL shaders" +msgstr "GLSL-varjostinohjelmat" msgid "You are loading an unsupported configuration" msgstr "Olet lataamassa ei-tuettuja määrittelyjä" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 829a9658b..8900dbf2d 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -894,8 +894,8 @@ msgstr "Configuration du dispositif %1" msgid "Monitor in sleep mode" msgstr "Moniteur en mode veille" -msgid "OpenGL Shaders" -msgstr "Shaders OpenGL" +msgid "GLSL shaders" +msgstr "Shaders GLSL" msgid "You are loading an unsupported configuration" msgstr "Vous chargez une configuration non prise en charge" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 6ca3ad8f5..ffa21efd1 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -894,8 +894,8 @@ msgstr "Konfiguracija uređaja %1" msgid "Monitor in sleep mode" msgstr "Ekran u stanju mirovanja" -msgid "OpenGL Shaders" -msgstr "OpenGL shaderi" +msgid "GLSL shaders" +msgstr "GLSL shaderi" msgid "You are loading an unsupported configuration" msgstr "Učitavate nepodržanu konfiguraciju" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 7d6a434f7..bbcfbd814 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -894,8 +894,8 @@ msgstr "%1 eszközkonfiguráció" msgid "Monitor in sleep mode" msgstr "Képernyő alvó módban" -msgid "OpenGL Shaders" -msgstr "OpenGL Shaderek" +msgid "GLSL shaders" +msgstr "GLSL shaderek" msgid "You are loading an unsupported configuration" msgstr "Egy nem támogatott konfigurációt tölt be" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 256337a0d..8c2322bb0 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -894,8 +894,8 @@ msgstr "Configurazione del dispositivo %1" msgid "Monitor in sleep mode" msgstr "Monitor in modalità riposo" -msgid "OpenGL Shaders" -msgstr "Shader OpenGL" +msgid "GLSL shaders" +msgstr "Shader GLSL" msgid "You are loading an unsupported configuration" msgstr "Stai caricando una configurazione non supportata" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index d38760f15..03c1f5fdc 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -894,8 +894,8 @@ msgstr "%1 のデバイス設定" msgid "Monitor in sleep mode" msgstr "モニターのスリープモード" -msgid "OpenGL Shaders" -msgstr "OpenGLシェーダー" +msgid "GLSL shaders" +msgstr "GLSLシェーダー" msgid "You are loading an unsupported configuration" msgstr "サポートされていないコンフィグを読み込んでいます" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index dbf77106b..ee2e5db5f 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -894,8 +894,8 @@ msgstr "%1 장치 설정" msgid "Monitor in sleep mode" msgstr "모니터 절전 모드" -msgid "OpenGL Shaders" -msgstr "OpenGL 쉐이더" +msgid "GLSL shaders" +msgstr "GLSL 쉐이더" msgid "You are loading an unsupported configuration" msgstr "지원하지 않는 설정입니다" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 65e59331b..3e95f69de 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -894,8 +894,8 @@ msgstr "%1 Apparaatconfiguratie" msgid "Monitor in sleep mode" msgstr "Monitor in slaapstand" -msgid "OpenGL Shaders" -msgstr "OpenGL Shaders" +msgid "GLSL shaders" +msgstr "GLSL Shaders" msgid "You are loading an unsupported configuration" msgstr "U laadt een configuratie die niet wordt ondersteund" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index bed21af24..472c29d41 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -894,8 +894,8 @@ msgstr "Konfiguracja urządzenia %1" msgid "Monitor in sleep mode" msgstr "Monitor w trybie czuwania" -msgid "OpenGL Shaders" -msgstr "Shadery OpenGL" +msgid "GLSL shaders" +msgstr "Shadery GLSL" msgid "You are loading an unsupported configuration" msgstr "Ładujesz nieobsługiwaną konfigurację" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index df606a635..b9c391083 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -894,8 +894,8 @@ msgstr "Configuração do dispositivo %1" msgid "Monitor in sleep mode" msgstr "Monitor em modo de suspensão" -msgid "OpenGL Shaders" -msgstr "Shaders OpenGL" +msgid "GLSL shaders" +msgstr "Shaders GLSL" msgid "You are loading an unsupported configuration" msgstr "Você está carregando uma configuração não suportada" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index b3458bcdf..a9c6a6810 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -894,8 +894,8 @@ msgstr "Configuração de dispositivo %1" msgid "Monitor in sleep mode" msgstr "Ecrã em modo de sono" -msgid "OpenGL Shaders" -msgstr "Shaders OpenGL" +msgid "GLSL shaders" +msgstr "Shaders GLSL" msgid "You are loading an unsupported configuration" msgstr "Está a carregar uma configuração sem suporte!" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 6104d064f..9bf253eca 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -894,8 +894,8 @@ msgstr "Конфигурация устройства %1" msgid "Monitor in sleep mode" msgstr "Монитор в спящем режиме" -msgid "OpenGL Shaders" -msgstr "Шейдеры OpenGL" +msgid "GLSL shaders" +msgstr "Шейдеры GLSL" msgid "You are loading an unsupported configuration" msgstr "Вы загружаете неподдерживаемую конфигурацию" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 9e6532267..172332178 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -894,8 +894,8 @@ msgstr "Konfigurácia zariadenia %1" msgid "Monitor in sleep mode" msgstr "Monitor je v režime spánku" -msgid "OpenGL Shaders" -msgstr "Shadery OpenGL" +msgid "GLSL shaders" +msgstr "Shadery GLSL" msgid "You are loading an unsupported configuration" msgstr "Pokúšate sa spustiť nepodporovanú konfiguráciu" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index efb62153a..3ca041b7c 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -894,8 +894,8 @@ msgstr "Konfiguracija naprave %1" msgid "Monitor in sleep mode" msgstr "Zaslon v načinu spanja" -msgid "OpenGL Shaders" -msgstr "Senčilniki OpenGL" +msgid "GLSL shaders" +msgstr "Senčilniki GLSL" msgid "You are loading an unsupported configuration" msgstr "Nalagate nepodprto konfiguracijo" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index e3d692537..0408a5cbe 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -894,8 +894,8 @@ msgstr "%1 cihaz konfigürasyonu" msgid "Monitor in sleep mode" msgstr "Monitör uyku modunda" -msgid "OpenGL Shaders" -msgstr "OpenGL gölgelendiricileri" +msgid "GLSL shaders" +msgstr "GLSL gölgelendiricileri" msgid "You are loading an unsupported configuration" msgstr "Desteklenmeyen bir konfigürasyon kullanıyorsunuz" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 687186f56..641c454ce 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -894,8 +894,8 @@ msgstr "Конфігурація пристрою %1" msgid "Monitor in sleep mode" msgstr "Монітор у сплячому режимі" -msgid "OpenGL Shaders" -msgstr "Шейдери OpenGL" +msgid "GLSL shaders" +msgstr "Шейдери GLSL" msgid "You are loading an unsupported configuration" msgstr "Ви завантажуєте непідтримувану конфігурацію" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 55a70991c..ce2967007 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -894,8 +894,8 @@ msgstr "Tinh chỉnh thiết bị %1" msgid "Monitor in sleep mode" msgstr "Màn hình chế độ chờ/ngủ" -msgid "OpenGL Shaders" -msgstr "Shader OpenGL" +msgid "GLSL shaders" +msgstr "Shader GLSL" msgid "You are loading an unsupported configuration" msgstr "Bạn đang load tinh chỉnh không được hỗ trợ." diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index cd720c0ee..f30dc48f3 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -894,8 +894,8 @@ msgstr "%1 设备配置" msgid "Monitor in sleep mode" msgstr "显示器处在睡眠状态" -msgid "OpenGL Shaders" -msgstr "OpenGL 着色器" +msgid "GLSL shaders" +msgstr "GLSL 着色器" msgid "You are loading an unsupported configuration" msgstr "正在载入一个不受支持的配置" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index a11ef8d44..9116bf09d 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -894,8 +894,8 @@ msgstr "%1 裝置設定" msgid "Monitor in sleep mode" msgstr "顯示器處在睡眠狀態" -msgid "OpenGL Shaders" -msgstr "OpenGL 著色器" +msgid "GLSL shaders" +msgstr "GLSL 著色器" msgid "You are loading an unsupported configuration" msgstr "正在載入一個不受支援的設定" diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 72f58f9cb..2a03b46f7 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -2,6 +2,7 @@ #include "ui_qt_openglshadermanagerdialog.h" #include "qt_mainwindow.hpp" +#include "qt_util.hpp" extern MainWindow* main_window; #include "qt_openglshaderconfig.hpp" @@ -9,6 +10,7 @@ extern MainWindow* main_window; #include #include #include +#include extern "C" { #include <86box/86box.h> @@ -166,7 +168,8 @@ void OpenGLShaderManagerDialog::on_buttonMoveDown_clicked() void OpenGLShaderManagerDialog::on_buttonAdd_clicked() { - auto res = QFileDialog::getOpenFileName(this, QString(), QString(), "GLSL Shaders (*.glslp *.glsl);;All files (*.*)"); + auto res = QFileDialog::getOpenFileName(this, QString(), QString(), + tr("GLSL shaders") % util::DlgFilter({ "glslp", "glsl" }) % tr("All files") % util::DlgFilter({ "*" }, true)); if (!res.isEmpty()) { auto glslp_file = res.toUtf8(); glslp_t* shaderfile = glslp_parse(glslp_file.data()); From f16265e2a418cab4f10ffc63527aaa5944c4faee Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 7 Apr 2025 19:55:07 +0500 Subject: [PATCH 0703/1190] qt: Remove the translation for the LBA Enhancer It wasn't supposed to be translated due to being a company name and a product name --- src/qt/languages/86box.pot | 3 --- src/qt/languages/ca-ES.po | 3 --- src/qt/languages/cs-CZ.po | 3 --- src/qt/languages/de-DE.po | 3 --- src/qt/languages/es-ES.po | 3 --- src/qt/languages/fi-FI.po | 3 --- src/qt/languages/fr-FR.po | 3 --- src/qt/languages/hr-HR.po | 3 --- src/qt/languages/hu-HU.po | 3 --- src/qt/languages/it-IT.po | 3 --- src/qt/languages/ja-JP.po | 3 --- src/qt/languages/ko-KR.po | 3 --- src/qt/languages/nl-NL.po | 3 --- src/qt/languages/pl-PL.po | 3 --- src/qt/languages/pt-BR.po | 3 --- src/qt/languages/pt-PT.po | 3 --- src/qt/languages/ru-RU.po | 3 --- src/qt/languages/sk-SK.po | 3 --- src/qt/languages/sl-SI.po | 3 --- src/qt/languages/tr-TR.po | 3 --- src/qt/languages/uk-UA.po | 3 --- src/qt/languages/vi-VN.po | 3 --- src/qt/languages/zh-CN.po | 3 --- src/qt/languages/zh-TW.po | 3 --- 24 files changed, 72 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 264060afe..a2eb3c4c3 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -1380,9 +1380,6 @@ msgstr "" msgid "Serial port passthrough 4" msgstr "" -msgid "Vision Systems LBA Enhancer" -msgstr "" - msgid "Renderer options..." msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 1d03316b6..64e314124 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -1380,9 +1380,6 @@ msgstr "Pas del port sèrie 3" msgid "Serial port passthrough 4" msgstr "Pas del port sèrie 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opcions del renderitzador ..." diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index a5378a978..fcc6e7baf 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -1380,9 +1380,6 @@ msgstr "Průchod sériového portu 3" msgid "Serial port passthrough 4" msgstr "Průchod sériového portu 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Možnosti vykreslovače..." diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index c3ca0953a..12ec816be 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -1383,9 +1383,6 @@ msgstr "Durchreichung der Serielle Schnittstelle 3" msgid "Serial port passthrough 4" msgstr "Durchreichung der Serielle Schnittstelle 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Renderer-Optionen..." diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 20a6eb351..9eb413d12 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1379,9 +1379,6 @@ msgstr "Paso de puerto serie 3" msgid "Serial port passthrough 4" msgstr "Paso de puerto serie 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opciones del renderizador..." diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index e12e27db4..19b0c1ae1 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1383,9 +1383,6 @@ msgstr "Sarjaportin läpivienti 3" msgid "Serial port passthrough 4" msgstr "Sarjaportin läpivienti 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Alustusasetukset..." diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 8900dbf2d..1636356e2 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -1380,9 +1380,6 @@ msgstr "Passage du port série 3" msgid "Serial port passthrough 4" msgstr "Passage du port série 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Options de rendu..." diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index ffa21efd1..f30d973e2 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -1380,9 +1380,6 @@ msgstr "Prolaz serijskih vrata 3" msgid "Serial port passthrough 4" msgstr "Prolaz serijskih vrata 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opcije rendera..." diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index bbcfbd814..7dc86fd66 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -1380,9 +1380,6 @@ msgstr "Soros port áthaladás 3" msgid "Serial port passthrough 4" msgstr "Soros port áthaladás 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Renderer opciók..." diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 8c2322bb0..7e91d6f8f 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -1380,9 +1380,6 @@ msgstr "Passaggio della porta seriale 3" msgid "Serial port passthrough 4" msgstr "Passaggio della porta seriale 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opzioni del renderer..." diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 03c1f5fdc..7bd0eb2db 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -1380,9 +1380,6 @@ msgstr "シリアル・ポート・パススルー 3" msgid "Serial port passthrough 4" msgstr "シリアル・ポート・パススルー 4" -msgid "Vision Systems LBA Enhancer" -msgstr "ビジョン・システムズ LBAエンハンサー" - msgid "Renderer options..." msgstr "レンダラー設定..." diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index ee2e5db5f..3650bd39e 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -1380,9 +1380,6 @@ msgstr "직렬 포트 패스스루 3" msgid "Serial port passthrough 4" msgstr "직렬 포트 패스스루 4" -msgid "Vision Systems LBA Enhancer" -msgstr "비전 시스템 LBA 인핸서" - msgid "Renderer options..." msgstr "렌더러 옵션..." diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 3e95f69de..54e3422ea 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -1380,9 +1380,6 @@ msgstr "Seriële poort doorvoer 3" msgid "Serial port passthrough 4" msgstr "Seriële poort doorvoer 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Renderer-opties..." diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 472c29d41..0e00ea6be 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -1380,9 +1380,6 @@ msgstr "Przełączanie portu szeregowego 3" msgid "Serial port passthrough 4" msgstr "Przełączanie portu szeregowego 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opcje renderowania..." diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index b9c391083..d7092c6d0 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -1380,9 +1380,6 @@ msgstr "Passagem de porta serial 3" msgid "Serial port passthrough 4" msgstr "Passagem de porta serial 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Opções do renderizador..." diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index a9c6a6810..e04d93c54 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -1380,9 +1380,6 @@ msgstr "Passagem da porta de série 3" msgid "Serial port passthrough 4" msgstr "Passagem da porta de série 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Sistemas de visão Melhorador LBA" - msgid "Renderer options..." msgstr "Opções do renderizador..." diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 9bf253eca..a67583a74 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1380,9 +1380,6 @@ msgstr "Сквозной последовательный порт COM3" msgid "Serial port passthrough 4" msgstr "Сквозной последовательный порт COM4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Параметры рендеринга..." diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 172332178..f976147b8 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -1381,9 +1381,6 @@ msgstr "Priechod sériového portu 3" msgid "Serial port passthrough 4" msgstr "Priechod cez sériový port 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Možnosti vykresľovača..." diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 3ca041b7c..7022ad7b0 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -1380,9 +1380,6 @@ msgstr "Prepust za serijska vrata 3" msgid "Serial port passthrough 4" msgstr "Prepust za serijska vrata 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Možnosti sistema za upodabljanje..." diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 0408a5cbe..6f8359823 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -1380,9 +1380,6 @@ msgstr "Seri port geçişi 3" msgid "Serial port passthrough 4" msgstr "Seri port geçişi 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "İşleyici seçenekleri..." diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 641c454ce..c42e72e2b 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -1380,9 +1380,6 @@ msgstr "Пропуск послідовного порту 3" msgid "Serial port passthrough 4" msgstr "Пропуск послідовного порту 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Параметри рендерингу..." diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index ce2967007..dacd8efac 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -1380,9 +1380,6 @@ msgstr "Thông qua cổng serial 3" msgid "Serial port passthrough 4" msgstr "Thông qua cổng serial 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "Tùy chọn kết xuất ..." diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index f30dc48f3..1a78b8abc 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1380,9 +1380,6 @@ msgstr "串行端口直通 3" msgid "Serial port passthrough 4" msgstr "串行端口直通 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA 增强器" - msgid "Renderer options..." msgstr "渲染器选项..." diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 9116bf09d..a9e73c563 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -1380,9 +1380,6 @@ msgstr "序列埠的直通 3" msgid "Serial port passthrough 4" msgstr "序列埠的直通 4" -msgid "Vision Systems LBA Enhancer" -msgstr "Vision Systems LBA Enhancer" - msgid "Renderer options..." msgstr "渲染器選項..." From bc8aae429ec6398b4f79a18cfe294192756f4357 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 7 Apr 2025 19:57:18 +0500 Subject: [PATCH 0704/1190] qt: Update the British English translation More ize -> ise spelling changes --- src/qt/languages/en-GB.po | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index b9f79882f..6043c10d9 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -15,18 +15,30 @@ msgstr "&RGB Greyscale" msgid "Time synchronization" msgstr "Time synchronisation" +msgid "Unable to initialize Ghostscript" +msgstr "Unable to initialise Ghostscript" + +msgid "Unable to initialize GhostPCL" +msgstr "Unable to initialise GhostPCL" + msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgid "Apply fullscreen stretch mode when maximized" msgstr "Apply fullscreen stretch mode when maximised" +msgid "Failed to initialize network driver" +msgstr "Failed to initialise network driver" + msgid "Render behavior" msgstr "Render behaviour" msgid "Synchronize with video" msgstr "Synchronise with video" +msgid "Error initializing OpenGL" +msgstr "Error initialising OpenGL" + msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialogue will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" From 890362131d1953f108a74dcf34a119732d26f334 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Tue, 8 Apr 2025 11:57:33 +0500 Subject: [PATCH 0705/1190] qt: Fix translations for "Falling back to software renderer" --- src/qt/languages/86box.pot | 2 +- src/qt/languages/ca-ES.po | 4 ++-- src/qt/languages/cs-CZ.po | 4 ++-- src/qt/languages/de-DE.po | 4 ++-- src/qt/languages/es-ES.po | 4 ++-- src/qt/languages/fi-FI.po | 4 ++-- src/qt/languages/fr-FR.po | 4 ++-- src/qt/languages/hr-HR.po | 4 ++-- src/qt/languages/hu-HU.po | 4 ++-- src/qt/languages/it-IT.po | 4 ++-- src/qt/languages/ja-JP.po | 4 ++-- src/qt/languages/ko-KR.po | 4 ++-- src/qt/languages/nl-NL.po | 4 ++-- src/qt/languages/pl-PL.po | 4 ++-- src/qt/languages/pt-BR.po | 4 ++-- src/qt/languages/pt-PT.po | 4 ++-- src/qt/languages/ru-RU.po | 4 ++-- src/qt/languages/sk-SK.po | 4 ++-- src/qt/languages/sl-SI.po | 4 ++-- src/qt/languages/tr-TR.po | 4 ++-- src/qt/languages/uk-UA.po | 4 ++-- src/qt/languages/vi-VN.po | 4 ++-- src/qt/languages/zh-CN.po | 4 ++-- src/qt/languages/zh-TW.po | 4 ++-- src/qt/qt_rendererstack.cpp | 2 +- 25 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index a2eb3c4c3..83e021d2a 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -1311,7 +1311,7 @@ msgstr "" msgid "Error initializing OpenGL" msgstr "" -msgid "Falling back to software rendering.\n" +msgid "\nFalling back to software rendering." msgstr "" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 64e314124..48c2a777d 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -1311,8 +1311,8 @@ msgstr "Es requereix la versió 3.0 o superior d'OpenGL. La versió actual és % msgid "Error initializing OpenGL" msgstr "Error en inicialitzar OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Tornant al renderitzador software.\n" +msgid "\nFalling back to software rendering." +msgstr "\nTornant al renderitzador software." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Quan seleccioneu imatges de suports (CD-ROM, disquet, etc.), el diàleg obert s’iniciarà al mateix directori que el fitxer de configuració 86Box. Aquesta configuració només farà una diferència en les macOS.</p></body></html>" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index fcc6e7baf..bcb7cc714 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -1311,8 +1311,8 @@ msgstr "Je vyžadována verze OpenGL 3.0 nebo vyšší. Aktuální verze je %1.% msgid "Error initializing OpenGL" msgstr "Chyba při inicializaci OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Návrat k softwarovému vykreslování.\n" +msgid "\nFalling back to software rendering." +msgstr "\nNávrat k softwarovému vykreslování." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Při výběru obrazů médií (CD-ROM, disketa atd.) se otevřené dialogové okno spustí ve stejném adresáři jako konfigurační soubor 86Box. Toto nastavení bude mít pravděpodobně význam pouze v systému MacOS.</p></body></html>" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 12ec816be..6255deef7 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -1314,8 +1314,8 @@ msgstr "OpenGL-Version 3.0 oder höher ist erforderlich. Die aktuelle Version is msgid "Error initializing OpenGL" msgstr "Fehler beim Initialisieren von OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Rückgriff auf Software-Rendering.\n" +msgid "\nFalling back to software rendering." +msgstr "\nRückgriff auf Software-Rendering." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Bei der Auswahl von Medien-Abbildern (CD-ROM, Diskette usw.) wird der Öffnungsdialog im selben Verzeichnis wie die 86Box-Konfigurationsdatei gestartet. Diese Einstellung macht wahrscheinlich nur unter macOS einen Unterschied.</p></body></html>" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 9eb413d12..285809cc5 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1310,8 +1310,8 @@ msgstr "Es requerida la versión 3.0 o más alta de OpenGL. La versión actual e msgid "Error initializing OpenGL" msgstr "Error al inicializar OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Recurrir al renderizado por software.\n" +msgid "\nFalling back to software rendering." +msgstr "\nRecurrir al renderizado por software." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Al seleccionar imágenes multimedia (CD-ROM, disquete, etc.), el diálogo de apertura se iniciará en el mismo directorio que el archivo de configuración de 86Box. Es probable que este ajuste sólo suponga una diferencia en macOS.</p></body></html>" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 19b0c1ae1..5419b9c5a 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1314,8 +1314,8 @@ msgstr "Tarvitaan OpenGL-versio 3.0 tai uudempi. Nykyinen versio on %1.%2" msgid "Error initializing OpenGL" msgstr "Virhe OpenGL:n alustamisessa" -msgid "Falling back to software rendering.\n" -msgstr "Paluu ohjelmistoalustusöintiin.\n" +msgid "\nFalling back to software rendering." +msgstr "\nPaluu ohjelmistoalustusöintiin." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Kun valitset mediakuvia (CD-ROM, levykkeet jne.), avausikkuna käynnistyy samaan hakemistoon kuin 86Boxin konfigurointitiedosto. Tällä asetuksella on todennäköisesti merkitystä vain macOS-käyttöjärjestelmässä.</p></body></html>" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 1636356e2..39479b40f 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -1311,8 +1311,8 @@ msgstr "La version 3.0 ou supérieure d'OpenGL est requise. La version actuelle msgid "Error initializing OpenGL" msgstr "Erreur d'initialisation d'OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Se rabattre sur le rendu logiciel.\n" +msgid "\nFalling back to software rendering." +msgstr "\nSe rabattre sur le rendu logiciel." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Lors de la sélection d'images multimédia (CD-ROM, disquette, etc.), la boîte de dialogue d'ouverture démarrera dans le même répertoire que le fichier de configuration de 86Box. Ce paramètre ne fera probablement une différence que sur macOS.</p></body></html>" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index f30d973e2..634523c5c 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -1311,8 +1311,8 @@ msgstr "Potrebna je OpenGL verzija 3.0 ili više. Trenutna verzija je %1. %2" msgid "Error initializing OpenGL" msgstr "Nije moguće inicijalizirati OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Vraća se na softverski renderer.\n" +msgid "\nFalling back to software rendering." +msgstr "\nVraća se na softverski renderer." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Prilikom odabira medijskih slika (CD-ROM, diskete itd.), otvoreni dijalog zopočet će u istom direktoriju kao i konfiguracijska datoteka 86Box-a. Razlika će vjerojatno biti primjetna samo na macOS-u.</p></body></html>" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 7dc86fd66..db6354680 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -1311,8 +1311,8 @@ msgstr "Az OpenGL 3.0 vagy magasabb verziója szükséges. Az aktuális verzió msgid "Error initializing OpenGL" msgstr "Hiba az OpenGL inicializálásában" -msgid "Falling back to software rendering.\n" -msgstr "Visszatérés a szoftveres rendereléshez.\n" +msgid "\nFalling back to software rendering." +msgstr "\nVisszatérés a szoftveres rendereléshez." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>A médiaképek (CD-ROM, floppy stb.) kiválasztásakor a megnyitási párbeszédpanel ugyanabban a könyvtárban indul, mint a 86Box konfigurációs fájl. Ez a beállítás valószínűleg csak a macOS rendszerben jelent különbséget.</p></body></html>" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 7e91d6f8f..effbee5bd 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -1311,8 +1311,8 @@ msgstr "È richiesta la versione OpenGL 3.0 o superiore. La versione attuale è msgid "Error initializing OpenGL" msgstr "Errore nell'inizializzazione di OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Ricaduta sul rendering software." +msgid "\nFalling back to software rendering." +msgstr "\nRicaduta sul rendering software." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Quando si selezionano immagini multimediali (CD-ROM, floppy, ecc.) la finestra di dialogo di apertura si avvia nella stessa directory del file di configurazione di 86Box. Questa impostazione probabilmente farà la differenza solo su macOS.</p></body></html>" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 7bd0eb2db..4ef8d01de 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -1311,8 +1311,8 @@ msgstr "OpenGLのバージョン3.0以上が必要です。現在のバージョ msgid "Error initializing OpenGL" msgstr "OpenGLの初期化エラー" -msgid "Falling back to software rendering.\n" -msgstr "ソフトウェアレンダリングに逆戻り。" +msgid "\nFalling back to software rendering." +msgstr "\nソフトウェアレンダリングに逆戻り。" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>メディアイメージ(CD-ROM、フロッピーなど)を選択するとき、オープンダイアログは86Box設定ファイルと同じディレクトリで開始します。この設定は、おそらく macOS でのみ違いがあります。</p></body></html>" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 3650bd39e..e9e4b99e6 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -1311,8 +1311,8 @@ msgstr "OpenGL 버전 3.0 이상이 필요합니다. 현재 버전은 %1.%2입 msgid "Error initializing OpenGL" msgstr "OpenGL 초기화 중 오류 발생" -msgid "Falling back to software rendering.\n" -msgstr "소프트웨어 렌더링으로 돌아가기.\n" +msgid "\nFalling back to software rendering." +msgstr "\n소프트웨어 렌더링으로 돌아가기." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>미디어 이미지(CD-ROM, 플로피 등)를 선택하면 86Box 구성 파일과 동일한 디렉터리에서 열기 대화 상자가 시작됩니다. 이 설정은 macOS에서만 차이가 있을 수 있습니다.</p></body></html>" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 54e3422ea..10e4c2bd2 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -1311,8 +1311,8 @@ msgstr "OpenGL versie 3.0 of hoger is vereist. De huidige versie is %1.%2" msgid "Error initializing OpenGL" msgstr "Fout bij het initialiseren van OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Terugvallen op software rendering.\n" +msgid "\nFalling back to software rendering." +msgstr "\nTerugvallen op software rendering." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Bij het selecteren van media-images (CD-ROM, floppy, etc.) zal de \"open dialoog\" starten in dezelfde map als het 86Box configuratiebestand. Deze instelling is doet er waarschijnlijk alleen toe op macOS.</p></body></html>" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 0e00ea6be..f8367176d 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -1311,8 +1311,8 @@ msgstr "Wymagana jest wersja OpenGL 3.0 lub wyższa. Aktualna wersja to %1.%2" msgid "Error initializing OpenGL" msgstr "Błąd inicjalizacji OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Powrót do renderowania oprogramowania.\n" +msgid "\nFalling back to software rendering." +msgstr "\nPowrót do renderowania oprogramowania." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Podczas wybierania obrazów nośników (CD-ROM, dyskietka itp.) otwarte okno dialogowe rozpocznie się w tym samym katalogu, co plik konfiguracyjny 86Box. To ustawienie prawdopodobnie będzie miało znaczenie tylko na macOS.</p></body></html>" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index d7092c6d0..9f0370f5e 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -1311,8 +1311,8 @@ msgstr "É necessária a versão 3.0 ou superior do OpenGL. A versão atual é % msgid "Error initializing OpenGL" msgstr "Erro ao inicializar o OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Voltando à renderização de software.\n" +msgid "\nFalling back to software rendering." +msgstr "\nVoltando à renderização de software." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Ao selecionar imagens de mídia (CD-ROM, disquete, etc.), a caixa de diálogo de abertura será iniciada no mesmo diretório do arquivo de configuração do 86Box. Essa configuração provavelmente só fará diferença no macOS.</p></body></html>" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index e04d93c54..f665424e0 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -1311,8 +1311,8 @@ msgstr "É necessária a versão 3.0 ou superior do OpenGL. A versão atual é % msgid "Error initializing OpenGL" msgstr "Erro ao inicializar o OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Recuando para a renderização de software." +msgid "\nFalling back to software rendering." +msgstr "\nRecuando para a renderização de software." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Ao selecionar imagens multimédia (CD-ROM, disquete, etc.) a caixa de diálogo de abertura irá começar no mesmo diretório que o ficheiro de configuração da 86Box. Esta configuração provavelmente só fará diferença no macOS.</p></body></html>" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index a67583a74..92542b70d 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1311,8 +1311,8 @@ msgstr "Требуется OpenGL версии 3.0 или выше. Текуща msgid "Error initializing OpenGL" msgstr "Ошибка инициализации OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Переключение на программный рендеринг.\n" +msgid "\nFalling back to software rendering." +msgstr "\nПереключение на программный рендеринг." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>При выборе образов носителей (CD-ROM, дискет и т. д.) диалог открытия будет запускаться в том же каталоге, что и файл конфигурации 86Box. Эта настройка, скорее всего, будет иметь значение только на macOS.</p></body></html>" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index f976147b8..36298269d 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -1312,8 +1312,8 @@ msgstr "Vyžaduje sa verzia OpenGL 3.0 alebo vyššia. Aktuálna verzia je %1.%2 msgid "Error initializing OpenGL" msgstr "Chyba pri inicializácii OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Návrat k softvérovému vykresľovaniu.\n" +msgid "\nFalling back to software rendering." +msgstr "\nNávrat k softvérovému vykresľovaniu." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Pri výbere multimediálnych obrazov (CD-ROM, disketa atď.) sa dialógové okno otvorenia spustí v rovnakom adresári ako konfiguračný súbor 86Box. Toto nastavenie bude mať pravdepodobne význam len v systéme MacOS.</p></body></html>" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 7022ad7b0..0eeca62f8 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -1311,8 +1311,8 @@ msgstr "Zahteva se različica OpenGL 3.0 ali novejša. Trenutna različica je %1 msgid "Error initializing OpenGL" msgstr "Napaka pri inicializaciji OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Vrnitev k programskemu upodabljanju.\n" +msgid "\nFalling back to software rendering." +msgstr "\nVrnitev k programskemu upodabljanju." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Pri izbiri medijskih slik (CD-ROM, disketa itd.) se bo odprto pogovorno okno začelo v istem imeniku kot konfiguracijska datoteka 86Box. Ta nastavitev bo verjetno imela pomen le v operacijskem sistemu MacOS.</p></body></html>" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 6f8359823..41930bd96 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -1311,8 +1311,8 @@ msgstr "OpenGL sürüm 3.0 veya üstü gereklidir. Geçerli sürüm %1.%2" msgid "Error initializing OpenGL" msgstr "OpenGL başlatılırken hata oluştu" -msgid "Falling back to software rendering.\n" -msgstr "Yazılım işleyicisine geri dönülüyor.\n" +msgid "\nFalling back to software rendering." +msgstr "\nYazılım işleyicisine geri dönülüyor." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Medya görüntüsü (CD-ROM, disket, vb.) seçme diyaloğu 86Box yapılandırma dosyasıyla aynı dizinde başlayacaktır. Bu ayar muhtemelen sadece macOS üzerinde bir fark meydana getirecektir.</p></body></html>" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index c42e72e2b..4632d001b 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -1311,8 +1311,8 @@ msgstr "Потрібна версія OpenGL 3.0 або новіша. Поточ msgid "Error initializing OpenGL" msgstr "Помилка ініціалізації OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Повернення до програмного рендерингу.\n" +msgid "\nFalling back to software rendering." +msgstr "\nПовернення до програмного рендерингу." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>При виборі медіа-образів (CD-ROM, дискета і т.д.) діалогове вікно буде відкриватися в тому ж каталозі, що і файл конфігурації 86Box. Цей параметр, швидше за все, матиме значення лише на macOS.</p></body></html>" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index dacd8efac..b8322d600 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -1311,8 +1311,8 @@ msgstr "OpenGL phiên bản 3.0 trở lên là bắt buộc. Phiên bản hiện msgid "Error initializing OpenGL" msgstr "Lỗi khởi tạo OpenGL" -msgid "Falling back to software rendering.\n" -msgstr "Quay trở lại kết xuất phần mềm.\n" +msgid "\nFalling back to software rendering." +msgstr "\nQuay trở lại kết xuất phần mềm." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 1a78b8abc..308cbe5b3 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1311,8 +1311,8 @@ msgstr "需要 OpenGL 3.0 或更高版本。当前版本为 %1.%2" msgid "Error initializing OpenGL" msgstr "初始化 OpenGL 时出错" -msgid "Falling back to software rendering.\n" -msgstr "回到软件渲染。" +msgid "\nFalling back to software rendering." +msgstr "\n回到软件渲染。" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。</p></body></html>;" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index a9e73c563..1ffb9843e 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -1311,8 +1311,8 @@ msgstr "需要 OpenGL 版本 3.0 或更高。目前版本為 %1.%2" msgid "Error initializing OpenGL" msgstr "初始化 OpenGL 出錯" -msgid "Falling back to software rendering.\n" -msgstr "回退到軟體渲染。" +msgid "\nFalling back to software rendering." +msgstr "\n回退到軟體渲染。" msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>當選擇媒體映像 (CD-ROM、軟碟等) 時,開啟對話方塊會在與 86Box 設定檔相同的目錄中開始。此設定可能只會在 macOS 上有所影響。</p></body></html>" diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index aed932e92..610d89d17 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -375,7 +375,7 @@ RendererStack::createRenderer(Renderer renderer) try { hw = new VulkanWindowRenderer(this); } catch (std::runtime_error &e) { - auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", e.what() + QString("\nFalling back to software rendering."), QMessageBox::Ok); + auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", e.what() + tr("\nFalling back to software rendering."), QMessageBox::Ok); msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->show(); imagebufs = {}; From ba6694f9f2c102876aa7f1b9d49cecdd57c6d7c1 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Tue, 8 Apr 2025 12:01:05 +0500 Subject: [PATCH 0706/1190] qt: Make "Failed to init Vulkan" error translatable --- src/qt/languages/86box.pot | 3 +++ src/qt/languages/en-GB.po | 3 +++ src/qt/qt_rendererstack.cpp | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 83e021d2a..6327cf1f3 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2087,3 +2087,6 @@ msgstr "" msgid "Inhibit multimedia keys on Windows" msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index 6043c10d9..8cc29a71a 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -71,3 +71,6 @@ msgstr "Grey" msgid "Color" msgstr "Colour" + +msgid "Failed to initialize Vulkan renderer." +msgstr "Failed to initialise Vulkan renderer." diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 610d89d17..b5b910fe9 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef __APPLE__ # include @@ -393,7 +394,7 @@ RendererStack::createRenderer(Renderer renderer) }); connect(hw, &VulkanWindowRenderer::errorInitializing, [=]() { /* Renderer could not initialize, fallback to software. */ - auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", QString("Failed to initialize Vulkan renderer.\nFalling back to software rendering."), QMessageBox::Ok); + auto msgBox = new QMessageBox(QMessageBox::Critical, "86Box", tr("Failed to initialize Vulkan renderer.") % tr("\nFalling back to software rendering."), QMessageBox::Ok); msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->show(); imagebufs = {}; From 377381a8fadf5fc358712925561a44e55e662fde Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Tue, 8 Apr 2025 15:28:09 +0500 Subject: [PATCH 0707/1190] qt: Fix an error with the "%i Wait state(s)" string --- src/qt/languages/86box.pot | 2 +- src/qt/languages/ca-ES.po | 2 +- src/qt/languages/nl-NL.po | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 6327cf1f3..856888d7c 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -750,7 +750,7 @@ msgstr "" msgid "Default" msgstr "" -msgid "%i estat(s) d'espera" +msgid "%i Wait state(s)" msgstr "" msgid "Type" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 48c2a777d..ae9a22622 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -750,7 +750,7 @@ msgstr "KB" msgid "Default" msgstr "Per defecte" -msgid "%i estat(s) d'espera" +msgid "%i Wait state(s)" msgstr "%i estado(s) de Espera" msgid "Type" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 10e4c2bd2..8326ef49d 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Standaard" -msgid "%i estat(s) d'espera" -msgstr "%i estat(s) d'espera" +msgid "%i Wait state(s)" +msgstr "%i Wachttoestand(en)" msgid "Type" msgstr "Type" From 0a2d15db9bbb9a69327b5f40b5bd86c10d9f5d92 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Tue, 8 Apr 2025 15:29:07 +0500 Subject: [PATCH 0708/1190] qt: Reword some error messages slightly --- src/qt/languages/86box.pot | 2 +- src/qt/qt_glsl_parser.cpp | 2 +- src/qt/qt_openglrenderer.cpp | 2 +- src/qt/qt_openglshadermanagerdialog.cpp | 2 +- src/qt/qt_progsettings.cpp | 2 +- src/qt/qt_progsettings.ui | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 856888d7c..382e00835 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2085,7 +2085,7 @@ msgstr "" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "" -msgid "Inhibit multimedia keys on Windows" +msgid "Inhibit multimedia keys" msgstr "" msgid "Failed to initialize Vulkan renderer." diff --git a/src/qt/qt_glsl_parser.cpp b/src/qt/qt_glsl_parser.cpp index fa45267a7..6e107bc19 100644 --- a/src/qt/qt_glsl_parser.cpp +++ b/src/qt/qt_glsl_parser.cpp @@ -214,7 +214,7 @@ static glslp_t *glsl_parse(const char *f) { strcpy(shader->shader_fn, f); shader->shader_program = load_file(f); if (!shader->shader_program) { - QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader %1").arg(shader->shader_fn)); + QMessageBox::critical((QWidget *) qApp->findChild(), QObject::tr("GLSL error"), QObject::tr("Could not load shader: %1").arg(shader->shader_fn)); //wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); glslp_free(glslp); return 0; diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index cc48ca06e..2e8869c09 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -633,7 +633,7 @@ OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) if (!load_texture(file, &tex->texture)) { //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %1").arg(file)); pclog("Could not load texture %s!\n", file); failed = 1; break; diff --git a/src/qt/qt_openglshadermanagerdialog.cpp b/src/qt/qt_openglshadermanagerdialog.cpp index 2a03b46f7..90f38f40f 100644 --- a/src/qt/qt_openglshadermanagerdialog.cpp +++ b/src/qt/qt_openglshadermanagerdialog.cpp @@ -184,7 +184,7 @@ void OpenGLShaderManagerDialog::on_buttonAdd_clicked() ui->buttonAdd->setDisabled(ui->shaderListWidget->count() >= MAX_USER_SHADERS); } } else { - QMessageBox::critical(this, tr("GLSL error"), tr("Could not load filename %1").arg(res)); + QMessageBox::critical(this, tr("GLSL error"), tr("Could not load file %1").arg(res)); } } } diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 2fd108186..0fce0d705 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -80,7 +80,7 @@ ProgSettings::accept() confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; confirm_reset = ui->checkBoxConfirmHardReset->isChecked() ? 1 : 0; video_fullscreen_first = ui->checkBoxFullscreenFirst->isChecked() ? 1 : 0; - inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked(); + inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked() ? 1 : 0; loadTranslators(QCoreApplication::instance()); reloadStrings(); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index d3ebf8c85..b01199dfd 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -140,7 +140,7 @@ - Inhibit multimedia keys on Windows + Inhibit multimedia keys From 0fd0c9adee4ce712b7c11520736c024f5290de3c Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 10 Apr 2025 02:05:50 +0500 Subject: [PATCH 0709/1190] qt: Miscellaneous translation corrections --- src/qt/languages/fr-FR.po | 4 ++-- src/qt/languages/hu-HU.po | 2 +- src/qt/languages/it-IT.po | 4 ++-- src/qt/languages/nl-NL.po | 2 +- src/qt/languages/pl-PL.po | 2 +- src/qt/languages/sk-SK.po | 2 +- src/qt/languages/zh-CN.po | 2 +- src/qt/languages/zh-TW.po | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 39479b40f..b0afd8ae2 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -220,7 +220,7 @@ msgid "&Existing image..." msgstr "Image &Existante..." msgid "Existing image (&Write-protected)..." -msgstr "Image Existante(&Lecture seule)..." +msgstr "Image Existante (&Lecture seule)..." msgid "&Record" msgstr "En®istrer" @@ -235,7 +235,7 @@ msgid "&Fast forward to the end" msgstr "Aller à la &Fin" msgid "E&ject" -msgstr "E&jecter" +msgstr "É&jecter" msgid "&Image..." msgstr "&Image..." diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index db6354680..8c9dc67dd 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -1252,7 +1252,7 @@ msgid "Host CD/DVD Drive (%1:)" msgstr "Gazdag CD/DVD-meghajtó (%1:)" msgid "&Connected" -msgstr "&Connected" +msgstr "" msgid "Clear image history" msgstr "Törölje a kép előzményeit" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index effbee5bd..4f9137d77 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -1267,7 +1267,7 @@ msgid "Host CD/DVD Drive (%1)" msgstr "Unità CD/DVD host (%1)" msgid "Unknown Bus" -msgstr "Autobus sconosciuto" +msgstr "Bus sconosciuto" msgid "Null Driver" msgstr "Driver nullo" @@ -2062,7 +2062,7 @@ msgid "RAM Disk (max. speed)" msgstr "Disco RAM (velocità massima)" msgid "IBM 8514/A clone (ISA)" -msgstr "Clone IBM 8514/A(ISA)" +msgstr "Clone IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricante" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 8326ef49d..f7d64a413 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -235,7 +235,7 @@ msgid "&Fast forward to the end" msgstr "&Snel vooruit naar het einde" msgid "E&ject" -msgstr "E&ject" +msgstr "&Uitwerpen" msgid "&Image..." msgstr "&Image..." diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index f8367176d..3b29c3415 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -1252,7 +1252,7 @@ msgid "Host CD/DVD Drive (%1:)" msgstr "Napęd CD/DVD hosta (%1:)" msgid "&Connected" -msgstr "&Connected" +msgstr "" msgid "Clear image history" msgstr "Wyczyść historię obrazów" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 36298269d..1d8768dd8 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -1252,7 +1252,7 @@ msgid "Host CD/DVD Drive (%1:)" msgstr "Hostiteľská jednotka CD/DVD (%1:)" msgid "&Connected" -msgstr "&Connected" +msgstr "" msgid "Clear image history" msgstr "Vymazanie histórie obrázkov" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 308cbe5b3..32358584e 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1252,7 +1252,7 @@ msgid "Host CD/DVD Drive (%1:)" msgstr "主机 CD/DVD 驱动器 (%1:)" msgid "&Connected" -msgstr "&Connected" +msgstr "" msgid "Clear image history" msgstr "清除映像历史记录" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 1ffb9843e..6b7420bc7 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2050,7 +2050,7 @@ msgid "Eject %s" msgstr "退出 %s" msgid "&Unmute" -msgstr "解除靜音 (&U)" +msgstr "解除靜音(&U)" msgid "Softfloat FPU" msgstr "Softfloat FPU" From cc01d7c3b8ee0b837feb59467eea1678642e63eb Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 10 Apr 2025 02:51:04 +0500 Subject: [PATCH 0710/1190] =?UTF-8?q?qt=5Fmediamenu.cpp:=20Get=20rid=20of?= =?UTF-8?q?=20pointless=20QString=20=E2=86=94=20C=20string=20conversions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/qt/qt_mediamenu.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index f7abebdf1..478f64c2a 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -263,7 +263,7 @@ void MediaMenu::cassetteMenuSelect(int slot) { QString filename = mhm.getImageForSlot(0, slot, ui::MediaType::Cassette); - cassetteMount(filename.toUtf8().constData(), 0); + cassetteMount(filename, 0); cassetteUpdateMenu(); ui_sb_update_tip(SB_CASSETTE); } @@ -365,7 +365,7 @@ void MediaMenu::cartridgeMenuSelect(int index, int slot) { QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Cartridge); - cartridgeMount(index, filename.toUtf8().constData()); + cartridgeMount(index, filename); cartridgeUpdateMenu(index); ui_sb_update_tip(SB_CARTRIDGE | index); } @@ -507,7 +507,7 @@ void MediaMenu::floppyMenuSelect(int index, int slot) { QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Floppy); - floppyMount(index, filename.toUtf8().constData(), false); + floppyMount(index, filename, false); floppyUpdateMenu(index); ui_sb_update_tip(SB_FLOPPY | index); } @@ -594,7 +594,7 @@ void MediaMenu::cdromReload(int index, int slot) { const QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Optical); - cdromMount(index, filename.toUtf8().constData()); + cdromMount(index, filename); cdromUpdateMenu(index); ui_sb_update_tip(SB_CDROM | index); } @@ -630,7 +630,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) switch (type) { default: - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); return; case ui::MediaType::Cassette: if (!MachineStatus::hasCassette()) @@ -639,7 +639,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cassetteImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); break; case ui::MediaType::Cartridge: if (!machine_has_cartridge(machine)) @@ -648,7 +648,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cartridgeImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); break; case ui::MediaType::Floppy: if (!floppyMenus.contains(index)) @@ -657,7 +657,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[floppyImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); break; case ui::MediaType::Optical: if (!cdromMenus.contains(index)) @@ -668,14 +668,14 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) if (fn.left(8) == "ioctl://") { menu_icon = QIcon(":/settings/qt/icons/cdrom_host.ico"); #ifdef Q_OS_WINDOWS - menu_item_name = tr("Host CD/DVD Drive (%1)").arg(fn.right(2)).toUtf8().constData(); + menu_item_name = tr("Host CD/DVD Drive (%1)").arg(fn.right(2)); #else menu_item_name = tr("Host CD/DVD Drive (%1)").arg(fn.right(fn.length() - 8)); #endif } else { fi.setFile(fn); menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); - menu_item_name = fn.isEmpty() ? tr("previous image").toUtf8().constData() : fn.toUtf8().constData(); + menu_item_name = fn.isEmpty() ? tr("previous image") : fn; } imageHistoryUpdatePos->setIcon(menu_icon); break; @@ -686,7 +686,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[zipImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); break; case ui::MediaType::Mo: if (!moMenus.contains(index)) @@ -695,11 +695,11 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[moImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); break; } - imageHistoryUpdatePos->setText(QString::asprintf(tr("%s").toUtf8().constData(), menu_item_name.toUtf8().constData())); + imageHistoryUpdatePos->setText(menu_item_name); if (fn.left(8) == "ioctl://") imageHistoryUpdatePos->setVisible(true); @@ -735,7 +735,7 @@ MediaMenu::cdromUpdateMenu(int i) QString menu_item_name; if (name.left(8) == "ioctl://") { #ifdef Q_OS_WINDOWS - menu_item_name = tr("Host CD/DVD Drive (%1)").arg(name.right(2)).toUtf8().constData(); + menu_item_name = tr("Host CD/DVD Drive (%1)").arg(name.right(2)); #else menu_item_name = tr("Host CD/DVD Drive (%1)").arg(name.right(name.length() - 8)); #endif @@ -744,7 +744,7 @@ MediaMenu::cdromUpdateMenu(int i) } else { QFileInfo fi(cdrom[i].image_path); - menu_item_name = name.isEmpty() ? QString().toUtf8().constData() : name.toUtf8().constData(); + menu_item_name = name.isEmpty() ? QString() : name; name2 = name; menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); } From 5ff206e493153471088aa96755d76c2b44bc6f17 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 10 Apr 2025 04:34:37 +0500 Subject: [PATCH 0711/1190] qt: Get rid of most uses of `QString::asprintf()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the Win32 UI is out of the way, we can rewrite the strings to use QString::arg() instead and avoid even more QString ↔ C string conversions --- src/qt/languages/86box.pot | 20 +++++++++--------- src/qt/languages/ca-ES.po | 40 +++++++++++++++++------------------ src/qt/languages/cs-CZ.po | 40 +++++++++++++++++------------------ src/qt/languages/de-DE.po | 40 +++++++++++++++++------------------ src/qt/languages/es-ES.po | 40 +++++++++++++++++------------------ src/qt/languages/fi-FI.po | 40 +++++++++++++++++------------------ src/qt/languages/fr-FR.po | 40 +++++++++++++++++------------------ src/qt/languages/hr-HR.po | 40 +++++++++++++++++------------------ src/qt/languages/hu-HU.po | 40 +++++++++++++++++------------------ src/qt/languages/it-IT.po | 40 +++++++++++++++++------------------ src/qt/languages/ja-JP.po | 38 ++++++++++++++++----------------- src/qt/languages/ko-KR.po | 40 +++++++++++++++++------------------ src/qt/languages/nl-NL.po | 40 +++++++++++++++++------------------ src/qt/languages/pl-PL.po | 40 +++++++++++++++++------------------ src/qt/languages/pt-BR.po | 40 +++++++++++++++++------------------ src/qt/languages/pt-PT.po | 40 +++++++++++++++++------------------ src/qt/languages/ru-RU.po | 40 +++++++++++++++++------------------ src/qt/languages/sk-SK.po | 40 +++++++++++++++++------------------ src/qt/languages/sl-SI.po | 40 +++++++++++++++++------------------ src/qt/languages/tr-TR.po | 40 +++++++++++++++++------------------ src/qt/languages/uk-UA.po | 40 +++++++++++++++++------------------ src/qt/languages/vi-VN.po | 40 +++++++++++++++++------------------ src/qt/languages/zh-CN.po | 40 +++++++++++++++++------------------ src/qt/languages/zh-TW.po | 40 +++++++++++++++++------------------ src/qt/qt_harddiskdialog.cpp | 3 +-- src/qt/qt_mediamenu.cpp | 36 ++++++++++++++----------------- src/qt/qt_settingsmachine.cpp | 2 +- 27 files changed, 487 insertions(+), 492 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 382e00835..a778f9f6d 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -642,7 +642,7 @@ msgstr "" msgid "Speed" msgstr "" -msgid "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" msgstr "" msgid "ZIP images" @@ -750,7 +750,7 @@ msgstr "" msgid "Default" msgstr "" -msgid "%i Wait state(s)" +msgid "%1 Wait state(s)" msgstr "" msgid "Type" @@ -795,10 +795,10 @@ msgstr "" msgid "None" msgstr "" -msgid "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" msgstr "" -msgid "Floppy %i (%s): %ls" +msgid "Floppy %1 (%2): %3" msgstr "" msgid "Advanced sector images" @@ -819,7 +819,7 @@ msgstr "" msgid "Unable to initialize GhostPCL" msgstr "" -msgid "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" msgstr "" msgid "MO images" @@ -906,13 +906,13 @@ msgstr "" msgid "Continue" msgstr "" -msgid "Cassette: %s" +msgid "Cassette: %1" msgstr "" msgid "Cassette images" msgstr "" -msgid "Cartridge %i: %ls" +msgid "Cartridge %1: %2" msgstr "" msgid "Cartridge images" @@ -1080,7 +1080,7 @@ msgstr "" msgid "ATAPI" msgstr "" -msgid "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" msgstr "" msgid "160 KB" @@ -1272,7 +1272,7 @@ msgstr "" msgid "Null Driver" msgstr "" -msgid "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" msgstr "" msgid "Render behavior" @@ -2046,7 +2046,7 @@ msgstr "" msgid "Host Serial Passthrough" msgstr "" -msgid "Eject %s" +msgid "E&ject %1" msgstr "" msgid "&Unmute" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index ae9a22622..808799859 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -642,8 +642,8 @@ msgstr "Premeu Ctrl+Alt+PgDn per tornar al mode de finestra." msgid "Speed" msgstr "Velocitat" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Imatges ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Per defecte" -msgid "%i Wait state(s)" -msgstr "%i estado(s) de Espera" +msgid "%1 Wait state(s)" +msgstr "%1 estado(s) de Espera" msgid "Type" msgstr "Tipus" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Cap" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disquet %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disquet %1 (%2): %3" msgid "Advanced sector images" msgstr "Imatges avançates del sector" @@ -819,8 +819,8 @@ msgstr "No es pot inicialitzar Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "No es pot inicialitzar GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Imatges MO" @@ -906,14 +906,14 @@ msgstr "El Filtratge de tipus de CPU basat en màquina seleccionada està deshab msgid "Continue" msgstr "Continuar" -msgid "Cassette: %s" -msgstr "Casset: %s" +msgid "Cassette: %1" +msgstr "Casset: %1" msgid "Cassette images" msgstr "Imatges de casset" -msgid "Cartridge %i: %ls" -msgstr "Cartutx %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartutx %1: %2" msgid "Cartridge images" msgstr "Imatges de cartutx" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Bus desconegut" msgid "Null Driver" msgstr "Controlador nul" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportament del renderitzador" @@ -2046,8 +2046,8 @@ msgstr "Pipe anomenat (servidor)" msgid "Host Serial Passthrough" msgstr "Pas del port sèrie amfitrió" -msgid "Eject %s" -msgstr "Extreure %s" +msgid "E&ject %1" +msgstr "E&xtreure %1" msgid "&Unmute" msgstr "&Saver" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index bcb7cc714..d3985b67a 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -642,8 +642,8 @@ msgstr "Stiskněte Ctrl+Alt+PgDn pro návrat z režimu celé obrazovky." msgid "Speed" msgstr "Rychlost" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Obrazy ZIP disků" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Výchozí" -msgid "%i Wait state(s)" -msgstr "%i čekací stav(y)" +msgid "%1 Wait state(s)" +msgstr "%1 čekací stav(y)" msgid "Type" msgstr "Typ" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Žadné" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disketová mechanika %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disketová mechanika %1 (%2): %3" msgid "Advanced sector images" msgstr "Rozšířené sektorové obrazy" @@ -819,8 +819,8 @@ msgstr "Nastala chyba při inicializaci knihovny Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Nastala chyba při inicializaci knihovny GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Obrazy MO" @@ -906,14 +906,14 @@ msgstr "Pro tuto konfiguraci bylo vypnuto filtrování procesorů podle zvolené msgid "Continue" msgstr "Pokračovat" -msgid "Cassette: %s" -msgstr "Kazeta: %s" +msgid "Cassette: %1" +msgstr "Kazeta: %1" msgid "Cassette images" msgstr "Kazetové nahrávky" -msgid "Cartridge %i: %ls" -msgstr "Cartridge %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartridge %1: %2" msgid "Cartridge images" msgstr "Obrazy cartridge" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Neznámá sběrnice" msgid "Null Driver" msgstr "Nulový ovladač" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Chování vykreslování" @@ -2046,8 +2046,8 @@ msgstr "Pojmenované potrubí (server)" msgid "Host Serial Passthrough" msgstr "Průchod sériového portu hostitele" -msgid "Eject %s" -msgstr "Vyjmout %s" +msgid "E&ject %1" +msgstr "&Vyjmout %1" msgid "&Unmute" msgstr "&Roztišit" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 6255deef7..781269af9 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -642,8 +642,8 @@ msgstr "Strg+Alt+Bild ab, zur Rückkehr in den Fenstermodus." msgid "Speed" msgstr "Geschwindigkeit" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP-Abbilder" @@ -753,8 +753,8 @@ msgstr "KB" msgid "Default" msgstr "Standard" -msgid "%i Wait state(s)" -msgstr "%i Wartezustände" +msgid "%1 Wait state(s)" +msgstr "%1 Wartezustände" msgid "Type" msgstr "Typ" @@ -798,11 +798,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Ohne" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Diskette %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Diskette %1 (%2): %3" msgid "Advanced sector images" msgstr "Fortgeschrittene Sektorabbilder" @@ -822,8 +822,8 @@ msgstr "Ghostscript konnte nicht initialisiert werden" msgid "Unable to initialize GhostPCL" msgstr "GhostPCL konnte nicht initialisiert werden" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO-Abbilder" @@ -909,14 +909,14 @@ msgstr "Das Filtern der CPU-Typen basierend auf dem ausgewählten System ist fü msgid "Continue" msgstr "Fortfahren" -msgid "Cassette: %s" -msgstr "Kassette: %s" +msgid "Cassette: %1" +msgstr "Kassette: %1" msgid "Cassette images" msgstr "Kassettenabbilder" -msgid "Cartridge %i: %ls" -msgstr "Cartridge %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartridge %1: %2" msgid "Cartridge images" msgstr "Cartridgeabbilder" @@ -1083,8 +1083,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1275,8 +1275,8 @@ msgstr "Unbekannter Bus" msgid "Null Driver" msgstr "Nulltreiber" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Rendering-Verhalten" @@ -2049,8 +2049,8 @@ msgstr "Benanntes Pipe (Server)" msgid "Host Serial Passthrough" msgstr "Durchreichung der seriellen Schnittstelle des Hosts" -msgid "Eject %s" -msgstr "Auswerfen %s" +msgid "E&ject %1" +msgstr "A&uswerfen %1" msgid "&Unmute" msgstr "&Ton einschalten" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 285809cc5..3cdcedd98 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -642,8 +642,8 @@ msgstr "Pulsa Ctrl+Alt+PgDn para volver a modo ventana." msgid "Speed" msgstr "Velocidad" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Imagenes ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Por defecto" -msgid "%i Wait state(s)" -msgstr "%i estado(s) de Espera" +msgid "%1 Wait state(s)" +msgstr "%1 estado(s) de Espera" msgid "Type" msgstr "Tipo" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Ninguno" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disquete %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disquete %1 (%2): %3" msgid "Advanced sector images" msgstr "Imágenes avanzadas de sector" @@ -819,8 +819,8 @@ msgstr "No fué posible inicializar Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "No fué posible inicializar GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Imágenes de MO" @@ -906,14 +906,14 @@ msgstr "El Filtrado de tipo de CPU basado en máquina seleccionada está deshabi msgid "Continue" msgstr "Continuar" -msgid "Cassette: %s" -msgstr "Cassette: %s" +msgid "Cassette: %1" +msgstr "Cassette: %1" msgid "Cassette images" msgstr "Imágenes de Cassette" -msgid "Cartridge %i: %ls" -msgstr "Cartucho %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartucho %1: %2" msgid "Cartridge images" msgstr "Imágenes de Cartucho" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1271,8 +1271,8 @@ msgstr "Bus desconocido" msgid "Null Driver" msgstr "Controlador nulo" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportamiento del renderizador" @@ -2045,8 +2045,8 @@ msgstr "Tubería con nombre (servidor)" msgid "Host Serial Passthrough" msgstr "Paso del puerto serie del host" -msgid "Eject %s" -msgstr "Extraer %s" +msgid "E&ject %1" +msgstr "E&xtraer %1" msgid "&Unmute" msgstr "&Reactivar sonido" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 5419b9c5a..ddae5c2ba 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -642,8 +642,8 @@ msgstr "Paina Ctrl+Alt+PgDn palataksesi ikkunoituun tilaan." msgid "Speed" msgstr "Nopeus" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP-levykuvat" @@ -750,8 +750,8 @@ msgstr "Kt" msgid "Default" msgstr "Oletus" -msgid "%i Wait state(s)" -msgstr "%i odotustilaa" +msgid "%1 Wait state(s)" +msgstr "%1 odotustilaa" msgid "Type" msgstr "Tyyppi" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Ei mikään" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u Mt (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 Mt (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Levyke %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Levyke %1 (%2): %3" msgid "Advanced sector images" msgstr "Kehittyneet sektorilevykuvat" @@ -819,8 +819,8 @@ msgstr "Ghostscriptin alustus epäonnistui" msgid "Unable to initialize GhostPCL" msgstr "GhostPCLin alustus epäonnistui" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO-levykuvat" @@ -906,14 +906,14 @@ msgstr "Valittuun tietokoneeseen perustuva suoritintyypin suodatus ei ole käyt msgid "Continue" msgstr "Jatka" -msgid "Cassette: %s" -msgstr "Kasetti: %s" +msgid "Cassette: %1" +msgstr "Kasetti: %1" msgid "Cassette images" msgstr "Kasettitiedostot" -msgid "Cartridge %i: %ls" -msgstr "ROM-moduuli %i: %ls" +msgid "Cartridge %1: %2" +msgstr "ROM-moduuli %1: %2" msgid "Cartridge images" msgstr "ROM-moduulikuvat" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 Kt" @@ -1272,8 +1272,8 @@ msgstr "Tuntematon väylä" msgid "Null Driver" msgstr "Nolla-ajuri" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Renderöintikäyttäytyminen" @@ -2049,8 +2049,8 @@ msgstr "Nimetty putki (palvelin)" msgid "Host Serial Passthrough" msgstr "Isännän sarjaportin läpivienti" -msgid "Eject %s" -msgstr "Poista kasettipesästä %s" +msgid "E&ject %1" +msgstr "&Poista kasettipesästä %1" msgid "&Unmute" msgstr "&Poista mykistys" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index b0afd8ae2..df5bf7ef6 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -642,8 +642,8 @@ msgstr "Appuyez sur Ctrl+Alt+PgDn pour revenir au mode fenêtré." msgid "Speed" msgstr "Vitesse" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Images ZIP" @@ -750,8 +750,8 @@ msgstr "Ko" msgid "Default" msgstr "Défaut" -msgid "%i Wait state(s)" -msgstr "%i état(s) d'attente" +msgid "%1 Wait state(s)" +msgstr "%1 état(s) d'attente" msgid "Type" msgstr "Type" @@ -795,11 +795,11 @@ msgstr "Système de contrôle de vol Thrustmaster" msgid "None" msgstr "Aucun" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u Mo (CTS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 Mo (CTS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disquette %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disquette %1 (%2): %3" msgid "Advanced sector images" msgstr "Images du secteur avancés" @@ -819,8 +819,8 @@ msgstr "Impossible d'initialiser Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Impossible d'initialiser GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "Magnéto-optique %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "Magnéto-optique %1 (%2): %3" msgid "MO images" msgstr "Images magnéto-optiques" @@ -906,14 +906,14 @@ msgstr "La filtrage du type du processeur sur la base de la machine sélectionn msgid "Continue" msgstr "Continuer" -msgid "Cassette: %s" -msgstr "Cassette: %s" +msgid "Cassette: %1" +msgstr "Cassette: %1" msgid "Cassette images" msgstr "Images cassette" -msgid "Cartridge %i: %ls" -msgstr "Cartouche %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartouche %1: %2" msgid "Cartridge images" msgstr "Images cartouche" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 Ko" @@ -1272,8 +1272,8 @@ msgstr "Bus inconnu" msgid "Null Driver" msgstr "Pilote nul" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportement de rendu" @@ -2046,8 +2046,8 @@ msgstr "Tuyau nommé (serveur)" msgid "Host Serial Passthrough" msgstr "Passage du port série de l'hôte" -msgid "Eject %s" -msgstr "Éjecter %s" +msgid "E&ject %1" +msgstr "É&jecter %1" msgid "&Unmute" msgstr "&Réactiver son" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 634523c5c..ecfd0c696 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -642,8 +642,8 @@ msgstr "Pritisnite Ctrl+Alt+PgDn za povratak u prozorski način rada." msgid "Speed" msgstr "Brzina" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP slike" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Standard" -msgid "%i Wait state(s)" -msgstr "%i stanje čekanja" +msgid "%1 Wait state(s)" +msgstr "%1 stanje čekanja" msgid "Type" msgstr "Tip" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Bez" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disketa %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disketa %1 (%2): %3" msgid "Advanced sector images" msgstr "Napredne sektorske slike" @@ -819,8 +819,8 @@ msgstr "Nije moguće inicijalizirati GhostScript" msgid "Unable to initialize GhostPCL" msgstr "Nije moguće inicijalizirati GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO slike" @@ -906,14 +906,14 @@ msgstr "Filtriranje tipa CPU-a na temelju odabranog sistema onemogućeno je za o msgid "Continue" msgstr "Nastavi" -msgid "Cassette: %s" -msgstr "Audio kaseta: %s" +msgid "Cassette: %1" +msgstr "Audio kaseta: %1" msgid "Cassette images" msgstr "Slike audio kasete" -msgid "Cartridge %i: %ls" -msgstr "Kaseta %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Kaseta %1: %2" msgid "Cartridge images" msgstr "Slike kasete" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Nepoznata sabirnica" msgid "Null Driver" msgstr "Nulti upravljački program" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Ponašanje rendera" @@ -2046,8 +2046,8 @@ msgstr "Imenovani vod (server)" msgid "Host Serial Passthrough" msgstr "Prolaz serijskih vrata nositelja" -msgid "Eject %s" -msgstr "Izbaci %s" +msgid "E&ject %1" +msgstr "&Izbaci %1" msgid "&Unmute" msgstr "&Uključi zvuk" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 8c9dc67dd..79e0dd5e6 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -642,8 +642,8 @@ msgstr "Használja a Ctrl+Alt+PgDn gombokat az ablakhoz való visszatéréshez." msgid "Speed" msgstr "Sebesség" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP-lemezképek" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Alapértelmezett" -msgid "%i Wait state(s)" -msgstr "%i várakozási ciklus(ok)" +msgid "%1 Wait state(s)" +msgstr "%1 várakozási ciklus(ok)" msgid "Type" msgstr "Típus" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Nincs" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Floppy %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Floppy %1 (%2): %3" msgid "Advanced sector images" msgstr "Továbbfejlesztett szektor képek" @@ -819,8 +819,8 @@ msgstr "Nem sikerült inicializálni a Ghostscript-et" msgid "Unable to initialize GhostPCL" msgstr "Nem sikerült inicializálni a GhostPCL-et" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO-képfájlok" @@ -906,14 +906,14 @@ msgstr "A kiválasztott gépen alapuló CPU-típusszűrés le van tiltva ezen az msgid "Continue" msgstr "Folytatás" -msgid "Cassette: %s" -msgstr "Magnókazetta: %s" +msgid "Cassette: %1" +msgstr "Magnókazetta: %1" msgid "Cassette images" msgstr "Magnókazetta-képek" -msgid "Cartridge %i: %ls" -msgstr "ROM-kazetta %i: %ls" +msgid "Cartridge %1: %2" +msgstr "ROM-kazetta %1: %2" msgid "Cartridge images" msgstr "ROM-kazetta képek" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Ismeretlen busz" msgid "Null Driver" msgstr "Null Driver" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Renderelési viselkedés" @@ -2046,8 +2046,8 @@ msgstr "Megnevezett cső (kiszolgáló)" msgid "Host Serial Passthrough" msgstr "Az állomás soros portjának áthaladása" -msgid "Eject %s" -msgstr "%s kiadás" +msgid "E&ject %1" +msgstr "%1 &kiadás" msgid "&Unmute" msgstr "&Hang újra bekapcsolása" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 4f9137d77..832c5b3fc 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -642,8 +642,8 @@ msgstr "Usa Ctrl+Alt+PgDn per tornare alla modalità finestra." msgid "Speed" msgstr "Velocità" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Immagini ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Predefinito" -msgid "%i Wait state(s)" -msgstr "%i stati d'attesa" +msgid "%1 Wait state(s)" +msgstr "%1 stati d'attesa" msgid "Type" msgstr "Tipo" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Nessuno" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Floppy %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Floppy %1 (%2): %3" msgid "Advanced sector images" msgstr "Immagini da settori avanzati" @@ -819,8 +819,8 @@ msgstr "Impossibile inizializzare Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Impossibile inizializzare GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Immagini MO" @@ -906,14 +906,14 @@ msgstr "Il filtraggio della tipologia di CPU è disabilitato per la macchina sel msgid "Continue" msgstr "Continua" -msgid "Cassette: %s" -msgstr "Cassetta: %s" +msgid "Cassette: %1" +msgstr "Cassetta: %1" msgid "Cassette images" msgstr "Immagini cassetta" -msgid "Cartridge %i: %ls" -msgstr "Cartuccia %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartuccia %1: %2" msgid "Cartridge images" msgstr "Immagini cartuccia" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Bus sconosciuto" msgid "Null Driver" msgstr "Driver nullo" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportamento di rendering" @@ -2046,8 +2046,8 @@ msgstr "Tubo denominato (Server)" msgid "Host Serial Passthrough" msgstr "Passaggio della porta seriale host" -msgid "Eject %s" -msgstr "Espelli %s" +msgid "E&ject %1" +msgstr "&Espelli %1" msgid "&Unmute" msgstr "&Riattiva l'audio" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 4ef8d01de..4bf10f7fc 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -642,8 +642,8 @@ msgstr "Ctrl+Alt+PgDnでウィンドウ モードに戻ります。" msgid "Speed" msgstr "速度" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIPイメージ" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "既定値" -msgid "%i Wait state(s)" -msgstr "%iつのウェイト ステート" +msgid "%1 Wait state(s)" +msgstr "%1つのウェイト ステート" msgid "Type" msgstr "タイプ" @@ -795,11 +795,11 @@ msgstr "Thrustmaster飛行制御システム" msgid "None" msgstr "なし" -msgid "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" msgstr "%u MB (CHS値: %i、%i、%i)" -msgid "Floppy %i (%s): %ls" -msgstr "フロッピー %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "フロッピー %1 (%2): %3" msgid "Advanced sector images" msgstr "アドバンスドセクターイメージ" @@ -819,8 +819,8 @@ msgstr "Ghostscriptが初期化できません" msgid "Unable to initialize GhostPCL" msgstr "GhostPCLが初期化できません" -msgid "MO %i (%ls): %ls" -msgstr "光磁気 %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "光磁気 %1 (%2): %3" msgid "MO images" msgstr "光磁気イメージ" @@ -906,14 +906,14 @@ msgstr "選択したマシンに基づくCPUタイプのフィルター機能は msgid "Continue" msgstr "続行" -msgid "Cassette: %s" -msgstr "カセット: %s" +msgid "Cassette: %1" +msgstr "カセット: %1" msgid "Cassette images" msgstr "カセットイメージ" -msgid "Cartridge %i: %ls" -msgstr "カートリッジ %i: %ls" +msgid "Cartridge %1: %2" +msgstr "カートリッジ %1: %2" msgid "Cartridge images" msgstr "カートリッジイメージ" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "不明なバス" msgid "Null Driver" msgstr "ヌル・ドライバー" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "レンダリング動作" @@ -2046,8 +2046,8 @@ msgstr "名前付きパイプ(サーバー)" msgid "Host Serial Passthrough" msgstr "ホストシリアルポートのパススルー" -msgid "Eject %s" -msgstr "%sを取り出す" +msgid "E&ject %1" +msgstr "%1を取り出す(&J)" msgid "&Unmute" msgstr "ミュート解除(&U)" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index e9e4b99e6..d6a0c234a 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -642,8 +642,8 @@ msgstr "Ctrl+Alt+PgDn 키를 누르면 창 모드로 전환합니다." msgid "Speed" msgstr "속도" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP 이미지" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "기본값" -msgid "%i Wait state(s)" -msgstr "%i 대기 상태" +msgid "%1 Wait state(s)" +msgstr "%1 대기 상태" msgid "Type" msgstr "형식" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "없음" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "플로피 %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "플로피 %1 (%2): %3" msgid "Advanced sector images" msgstr "어드밴스드 섹터 이미지" @@ -819,8 +819,8 @@ msgstr "Ghostscript를 초기화할 수 없습니다" msgid "Unable to initialize GhostPCL" msgstr "GhostPCL를 초기화할 수 없습니다" -msgid "MO %i (%ls): %ls" -msgstr "광자기 %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "광자기 %1 (%2): %3" msgid "MO images" msgstr "광자기 이미지" @@ -906,14 +906,14 @@ msgstr "이 에뮬레이트된 기종에 대해 선택한 기종을 기반으로 msgid "Continue" msgstr "계속" -msgid "Cassette: %s" -msgstr "카세트: %s" +msgid "Cassette: %1" +msgstr "카세트: %1" msgid "Cassette images" msgstr "카세트 이미지" -msgid "Cartridge %i: %ls" -msgstr "카트리지 %i: %ls" +msgid "Cartridge %1: %2" +msgstr "카트리지 %1: %2" msgid "Cartridge images" msgstr "카트리지 이미지" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "알 수 없는 버스" msgid "Null Driver" msgstr "Null 드라이버" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "렌더링 동작" @@ -2046,8 +2046,8 @@ msgstr "네임드 파이프(서버)" msgid "Host Serial Passthrough" msgstr "호스트 직렬 포트 패스스루" -msgid "Eject %s" -msgstr "%s 꺼내기" +msgid "E&ject %1" +msgstr "%1 꺼내기(&J)" msgid "&Unmute" msgstr "음소거 해제(&U)" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index f7d64a413..d57c389e1 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -642,8 +642,8 @@ msgstr "Druk op Ctrl+Alt+PgDn om terug te gaan naar de venstermodus." msgid "Speed" msgstr "Snelheid" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP-images" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Standaard" -msgid "%i Wait state(s)" -msgstr "%i Wachttoestand(en)" +msgid "%1 Wait state(s)" +msgstr "%1 Wachttoestand(en)" msgid "Type" msgstr "Type" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control systeem" msgid "None" msgstr "Geen" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Floppy %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Floppy %1 (%2): %3" msgid "Advanced sector images" msgstr "Geavanceerde sector-images" @@ -819,8 +819,8 @@ msgstr "Kan Ghostscript niet initialiseren" msgid "Unable to initialize GhostPCL" msgstr "Kan GhostPCL niet initialiseren" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO-images" @@ -906,14 +906,14 @@ msgstr "Filteren op CPU type voor de geselecteerde machine is niet mogelijk met msgid "Continue" msgstr "Doorgaan" -msgid "Cassette: %s" -msgstr "Cassette: %s" +msgid "Cassette: %1" +msgstr "Cassette: %1" msgid "Cassette images" msgstr "Cassette-images" -msgid "Cartridge %i: %ls" -msgstr "Cartridge %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartridge %1: %2" msgid "Cartridge images" msgstr "Cartridge-images" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Onbekende bus" msgid "Null Driver" msgstr "Null Driver" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Rendergedrag" @@ -2046,8 +2046,8 @@ msgstr "Named Pipe (Server)" msgid "Host Serial Passthrough" msgstr "Host seriële doorgave" -msgid "Eject %s" -msgstr "Uitwerpen %s" +msgid "E&ject %1" +msgstr "&Uitwerpen %1" msgid "&Unmute" msgstr "&Geluid aanzetten" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 3b29c3415..a72810b01 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -642,8 +642,8 @@ msgstr "Naciśnij klawisze Ctrl+Alt+PgDn aby wrócić to trybu okna." msgid "Speed" msgstr "Szybkość" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Obrazy ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Domyślny" -msgid "%i Wait state(s)" -msgstr "%i Stany oczekiwania" +msgid "%1 Wait state(s)" +msgstr "%1 Stany oczekiwania" msgid "Type" msgstr "Rodzaj" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Żaden" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Dyskietka %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Dyskietka %1 (%2): %3" msgid "Advanced sector images" msgstr "Zaawansowane obrazy sektorów" @@ -819,8 +819,8 @@ msgstr "Nie można zainicjować Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Nie można zainicjować GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Obrazy MO" @@ -906,14 +906,14 @@ msgstr "Wybór rodzaju procesora oparty na wybranej maszynie jest wyłączony dl msgid "Continue" msgstr "Kontynuuj" -msgid "Cassette: %s" -msgstr "Kaseta: %s" +msgid "Cassette: %1" +msgstr "Kaseta: %1" msgid "Cassette images" msgstr "Obrazy kaset" -msgid "Cartridge %i: %ls" -msgstr "Kartrydż %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Kartrydż %1: %2" msgid "Cartridge images" msgstr "Obrazy kartrydżu" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Nieznana magistrala" msgid "Null Driver" msgstr "Null Driver" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Zachowanie renderowania" @@ -2046,8 +2046,8 @@ msgstr "Nazwana rura (serwer)" msgid "Host Serial Passthrough" msgstr "Przejście przez port szeregowy hosta" -msgid "Eject %s" -msgstr "Wyjmij %s" +msgid "E&ject %1" +msgstr "W&yjmij %1" msgid "&Unmute" msgstr "&Wycisz" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 9f0370f5e..3535f63b9 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -642,8 +642,8 @@ msgstr "Use Ctrl+Alt+PgDn para retornar ao modo janela" msgid "Speed" msgstr "Velocidade" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Imagens ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Padrão" -msgid "%i Wait state(s)" -msgstr "%i estado(s) de espera" +msgid "%1 Wait state(s)" +msgstr "%1 estado(s) de espera" msgid "Type" msgstr "Tipo" @@ -795,11 +795,11 @@ msgstr "Sistema de Controle de Voo Thrustmaster" msgid "None" msgstr "Nenhum" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CCS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CCS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disquete %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disquete %1 (%2): %3" msgid "Advanced sector images" msgstr "Imagens de setor avançado" @@ -819,8 +819,8 @@ msgstr "Não foi possível inicializar o Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Não foi possível inicializar o GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "Magneto-óptico %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "Magneto-óptico %1 (%2): %3" msgid "MO images" msgstr "Imagens magneto-ópticas" @@ -906,14 +906,14 @@ msgstr "A filtragem do tipo de CPU baseada na máquina selecionada está desativ msgid "Continue" msgstr "Continuar" -msgid "Cassette: %s" -msgstr "Cassete: %s" +msgid "Cassette: %1" +msgstr "Cassete: %1" msgid "Cassette images" msgstr "Imagens de cassete" -msgid "Cartridge %i: %ls" -msgstr "Cartucho %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartucho %1: %2" msgid "Cartridge images" msgstr "Imagens de cartucho" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Barramento desconhecido" msgid "Null Driver" msgstr "Driver nulo" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportamento de renderização" @@ -2046,8 +2046,8 @@ msgstr "Tubo nomeado (servidor)" msgid "Host Serial Passthrough" msgstr "Passagem da porta serial do host" -msgid "Eject %s" -msgstr "Ejetar %s" +msgid "E&ject %1" +msgstr "E&jetar %1" msgid "&Unmute" msgstr "&Reativar som" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index f665424e0..ea6856347 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -642,8 +642,8 @@ msgstr "Pressione Ctrl+Alt+PgDn para voltar ao modo de janela." msgid "Speed" msgstr "Velocidade" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Imagens ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Padrão" -msgid "%i Wait state(s)" -msgstr "%i estado(s) de espera" +msgid "%1 Wait state(s)" +msgstr "%1 estado(s) de espera" msgid "Type" msgstr "Tipo" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Nenhum" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CCS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CCS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disquete %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disquete %1 (%2): %3" msgid "Advanced sector images" msgstr "Imagens avançadas de sector" @@ -819,8 +819,8 @@ msgstr "Não foi possível inicializar o Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Não foi possível inicializar o GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "Magneto-óptico %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "Magneto-óptico %1 (%2): %3" msgid "MO images" msgstr "Imagens magneto-ópticas" @@ -906,14 +906,14 @@ msgstr "A filtragem do tipo de CPU baseada na máquina escolhida está desativad msgid "Continue" msgstr "Continuar" -msgid "Cassette: %s" -msgstr "Cassete: %s" +msgid "Cassette: %1" +msgstr "Cassete: %1" msgid "Cassette images" msgstr "Imagens de cassete" -msgid "Cartridge %i: %ls" -msgstr "Cartucho %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartucho %1: %2" msgid "Cartridge images" msgstr "Imagens de cartucho" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Autocarro desconhecido" msgid "Null Driver" msgstr "Condutor nulo" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Comportamento de renderização" @@ -2046,8 +2046,8 @@ msgstr "Tubo nomeado (servidor)" msgid "Host Serial Passthrough" msgstr "Passagem da porta de série do anfitrião" -msgid "Eject %s" -msgstr "Ejetar %s" +msgid "E&ject %1" +msgstr "E&jetar %1" msgid "&Unmute" msgstr "&Reativar som" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 92542b70d..fd6a1d72a 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -642,8 +642,8 @@ msgstr "Нажмите Ctrl+Alt+PgDn для возврата в оконный msgid "Speed" msgstr "Скорость" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Образы ZIP" @@ -750,8 +750,8 @@ msgstr "КБ" msgid "Default" msgstr "По умолчанию" -msgid "%i Wait state(s)" -msgstr "%i WS" +msgid "%1 Wait state(s)" +msgstr "%1 WS" msgid "Type" msgstr "Тип" @@ -795,11 +795,11 @@ msgstr "Система управления полётом Thrustmaster" msgid "None" msgstr "Нет" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u МБ (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 МБ (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Дисковод %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Дисковод %1 (%2): %3" msgid "Advanced sector images" msgstr "Расширенные образы секторов" @@ -819,8 +819,8 @@ msgstr "Невозможно инициализировать Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Невозможно инициализировать GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "Магнитооптический %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "Магнитооптический %1 (%2): %3" msgid "MO images" msgstr "Образы магнитооптических дисков" @@ -906,14 +906,14 @@ msgstr "Выбор типов ЦП для этой системной платы msgid "Continue" msgstr "Продолжить" -msgid "Cassette: %s" -msgstr "Кассета: %s" +msgid "Cassette: %1" +msgstr "Кассета: %1" msgid "Cassette images" msgstr "Образы кассет" -msgid "Cartridge %i: %ls" -msgstr "Картридж %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Картридж %1: %2" msgid "Cartridge images" msgstr "Образы картриджей" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 КБ" @@ -1272,8 +1272,8 @@ msgstr "Неизвестная шина" msgid "Null Driver" msgstr "Нулевой драйвер" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Режим рендеринга" @@ -2046,8 +2046,8 @@ msgstr "Именованный пайп (Сервер)" msgid "Host Serial Passthrough" msgstr "Последовательный порт хоста" -msgid "Eject %s" -msgstr "Извлечь %s" +msgid "E&ject %1" +msgstr "И&звлечь %1" msgid "&Unmute" msgstr "В&ключить звук" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 1d8768dd8..b77ff5695 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -642,8 +642,8 @@ msgstr "Stlačte Ctrl+Alt+PgDn pre návrat z režimu celej obrazovky." msgid "Speed" msgstr "Rýchlosť" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Obrazy ZIP diskov" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Východiskové" -msgid "%i Wait state(s)" -msgstr "%i čakací stav(y)" +msgid "%1 Wait state(s)" +msgstr "%1 čakací stav(y)" msgid "Type" msgstr "Typ" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Žiadne" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disketová mechanika %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disketová mechanika %1 (%2): %3" msgid "Advanced sector images" msgstr "Rozšírené sektorové obrazy" @@ -819,8 +819,8 @@ msgstr "Nastala chyba pri inicializácii knižnice Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Nastala chyba pri inicializácii knižnice GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Obrazy MO" @@ -906,14 +906,14 @@ msgstr "Pre túto konfiguráciu bolo vypnuté filtrovanie procesorov podľa zvol msgid "Continue" msgstr "Pokračovať" -msgid "Cassette: %s" -msgstr "Kazeta: %s" +msgid "Cassette: %1" +msgstr "Kazeta: %1" msgid "Cassette images" msgstr "Kazetové nahrávky" -msgid "Cartridge %i: %ls" -msgstr "Cartridge %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Cartridge %1: %2" msgid "Cartridge images" msgstr "Obrazy cartridge" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Neznáma zbernica" msgid "Null Driver" msgstr "Nulový ovládač" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" @@ -2047,8 +2047,8 @@ msgstr "Pomenované potrubie (server)" msgid "Host Serial Passthrough" msgstr "Priechod sériového portu hostiteľa" -msgid "Eject %s" -msgstr "Vystrihnúť %s" +msgid "E&ject %1" +msgstr "&Vystrihnúť %1" msgid "&Unmute" msgstr "&Roztíšiť" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 0eeca62f8..9bedaa6cf 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -642,8 +642,8 @@ msgstr "Pritisnite Ctrl+Alt+PgDn za povratek iz celozaslonskega načina." msgid "Speed" msgstr "Hitrost" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP slike" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Privzeto" -msgid "%i Wait state(s)" -msgstr "%i stanj čakanja" +msgid "%1 Wait state(s)" +msgstr "%1 stanj čakanja" msgid "Type" msgstr "Vrsta" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Brez" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disketa %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disketa %1 (%2): %3" msgid "Advanced sector images" msgstr "Napredne sektorske slike" @@ -819,8 +819,8 @@ msgstr "Ghostscript-a ni bilo mogoče inicializirati" msgid "Unable to initialize GhostPCL" msgstr "GhostPCL-ja ni bilo mogoče inicializirati" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Slike MO" @@ -906,14 +906,14 @@ msgstr "Filtriranje vrste procesorja glede na izbran sistem je onemogočeno za t msgid "Continue" msgstr "Nadaljuj" -msgid "Cassette: %s" -msgstr "Kaseta: %s" +msgid "Cassette: %1" +msgstr "Kaseta: %1" msgid "Cassette images" msgstr "Slike kaset" -msgid "Cartridge %i: %ls" -msgstr "Spominski vložek %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Spominski vložek %1: %2" msgid "Cartridge images" msgstr "Slike spominskega vložka" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Neznano vodilo" msgid "Null Driver" msgstr "Ničelni gonilnik" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Obnašanje pri upodabljanju" @@ -2046,8 +2046,8 @@ msgstr "Poimenovana cev (Strežnik)" msgid "Host Serial Passthrough" msgstr "Prepustno serijskih vrat gostitelja" -msgid "Eject %s" -msgstr "Izvrzi %s" +msgid "E&ject %1" +msgstr "I&zvrzi %1" msgid "&Unmute" msgstr "&Vklopi zvok" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 41930bd96..5936f39c9 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -642,8 +642,8 @@ msgstr "Pencere moduna geri dönmek için Ctrl+Alt+PgDn tuşlarına basın." msgid "Speed" msgstr "Hız" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP imajları" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Varsayılan" -msgid "%i Wait state(s)" -msgstr "%i Bekleme durumları" +msgid "%1 Wait state(s)" +msgstr "%1 Bekleme durumları" msgid "Type" msgstr "Tür" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Hiçbiri" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Disket %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Disket %1 (%2): %3" msgid "Advanced sector images" msgstr "Gelişmiş sektör imajları" @@ -819,8 +819,8 @@ msgstr "Ghostscript başlatılamadı" msgid "Unable to initialize GhostPCL" msgstr "GhostPCL başlatılamadı" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "MO imajları" @@ -906,14 +906,14 @@ msgstr "Seçtiğiniz makineye uygun işlemci türü filtrelemesi bu emüle edile msgid "Continue" msgstr "Devam et" -msgid "Cassette: %s" -msgstr "Kaset: %s" +msgid "Cassette: %1" +msgstr "Kaset: %1" msgid "Cassette images" msgstr "Kaset imajları" -msgid "Cartridge %i: %ls" -msgstr "Kartuş %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Kartuş %1: %2" msgid "Cartridge images" msgstr "Kartuş imajları" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Bilinmeyen veri yolu" msgid "Null Driver" msgstr "Null sürücü" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "İşleyiş davranışı" @@ -2046,8 +2046,8 @@ msgstr "Adlandırılmış boru (Sunucu)" msgid "Host Serial Passthrough" msgstr "Ana bilgisayar seri port geçişi" -msgid "Eject %s" -msgstr "%s diskini çıkar" +msgid "E&ject %1" +msgstr "%1 diskini &çıkar" msgid "&Unmute" msgstr "&Sesi aç" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 4632d001b..36e227d6f 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -642,8 +642,8 @@ msgstr "Натисніть Ctrl+Alt+PgDn для повернення у віко msgid "Speed" msgstr "Швидкість" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Образи ZIP" @@ -750,8 +750,8 @@ msgstr "КБ" msgid "Default" msgstr "За замовчуванням" -msgid "%i Wait state(s)" -msgstr "%i WS" +msgid "%1 Wait state(s)" +msgstr "%1 WS" msgid "Type" msgstr "Тип" @@ -795,11 +795,11 @@ msgstr "Система управління польотом Thrustmaster" msgid "None" msgstr "Ні" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u МБ (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 МБ (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Дисковод %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Дисковод %1 (%2): %3" msgid "Advanced sector images" msgstr "Розширені образи секторів" @@ -819,8 +819,8 @@ msgstr "Неможливо ініціалізувати Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Неможливо ініціалізувати GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "Магнітооптичний %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "Магнітооптичний %1 (%2): %3" msgid "MO images" msgstr "Образи магнітооптичних дисків" @@ -906,14 +906,14 @@ msgstr "Вибір типів ЦП для цієї системної плати msgid "Continue" msgstr "Продовжити" -msgid "Cassette: %s" -msgstr "Касета: %s" +msgid "Cassette: %1" +msgstr "Касета: %1" msgid "Cassette images" msgstr "Образи касет" -msgid "Cartridge %i: %ls" -msgstr "Картридж %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Картридж %1: %2" msgid "Cartridge images" msgstr "Образи картриджів" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 КБ" @@ -1272,8 +1272,8 @@ msgstr "Невідома шина" msgid "Null Driver" msgstr "Нульовий драйвер" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Поведінка рендерингу" @@ -2046,8 +2046,8 @@ msgstr "Іменований пайп (сервер)" msgid "Host Serial Passthrough" msgstr "Пропуск послідовного порту хоста" -msgid "Eject %s" -msgstr "Вилучити %s" +msgid "E&ject %1" +msgstr "&Вилучити %1" msgid "&Unmute" msgstr "&Увімкнути звук" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index b8322d600..1d1a3697e 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -642,8 +642,8 @@ msgstr "Bấm Ctrl+Alt+PgDn để quay lại chế độ cửa sổ." msgid "Speed" msgstr "Vận tốc" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "Ảnh đĩa ZIP" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "Mặc định" -msgid "%i Wait state(s)" -msgstr "%i trạng thái chờ" +msgid "%1 Wait state(s)" +msgstr "%1 trạng thái chờ" msgid "Type" msgstr "Loại" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "Không có" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "Đĩa mềm %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "Đĩa mềm %1 (%2): %3" msgid "Advanced sector images" msgstr "Ảnh (đĩa) sector nâng cao" @@ -819,8 +819,8 @@ msgstr "Không thể khởi tạo Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Không thể khởi tạo GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "MO %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" msgid "MO images" msgstr "Ảnh đĩa MO" @@ -906,14 +906,14 @@ msgstr "Phần chọn loại CPU dựa trên mẫu máy đã chọn bị vô hi msgid "Continue" msgstr "Tiếp tục" -msgid "Cassette: %s" -msgstr "Cassette: %s" +msgid "Cassette: %1" +msgstr "Cassette: %1" msgid "Cassette images" msgstr "Ảnh đĩa Cassette" -msgid "Cartridge %i: %ls" -msgstr "Băng cartridge %i: %ls" +msgid "Cartridge %1: %2" +msgstr "Băng cartridge %1: %2" msgid "Cartridge images" msgstr "Ảnh đĩa băng cartridge" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "CD-ROM %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "Bus không xác định" msgid "Null Driver" msgstr "Trình điều khiển NULL" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i ( %ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "Hành vi kết xuất" @@ -2046,8 +2046,8 @@ msgstr "Đường ống có tên (máy chủ)" msgid "Host Serial Passthrough" msgstr "Thông qua cổng serial của máy chủ" -msgid "Eject %s" -msgstr "Đẩy đĩa ra %s" +msgid "E&ject %1" +msgstr "Đẩy đĩ&a ra %1" msgid "&Unmute" msgstr "&Mở tiếng" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 32358584e..b39c64563 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -642,8 +642,8 @@ msgstr "按下 Ctrl+Alt+PgDn 返回到窗口模式。" msgid "Speed" msgstr "速度" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP 映像" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "默认" -msgid "%i Wait state(s)" -msgstr "%i 等待状态 (WS)" +msgid "%1 Wait state(s)" +msgstr "%1 等待状态 (WS)" msgid "Type" msgstr "类型" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "无" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "软盘 %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "软盘 %1 (%2): %3" msgid "Advanced sector images" msgstr "高级扇区映像" @@ -819,8 +819,8 @@ msgstr "无法初始化 Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "无法初始化 GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "磁光盘 %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "磁光盘 %1 (%2): %3" msgid "MO images" msgstr "磁光盘映像" @@ -906,14 +906,14 @@ msgstr "此模拟计算机禁用了基于选定计算机的 CPU 类型过滤。\ msgid "Continue" msgstr "继续" -msgid "Cassette: %s" -msgstr "磁带: %s" +msgid "Cassette: %1" +msgstr "磁带: %1" msgid "Cassette images" msgstr "磁带映像" -msgid "Cartridge %i: %ls" -msgstr "卡带 %i: %ls" +msgid "Cartridge %1: %2" +msgstr "卡带 %1: %2" msgid "Cartridge images" msgstr "卡带映像" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "光盘 %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "光盘 %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "未知总线" msgid "Null Driver" msgstr "空驱动程序" -msgid "NIC %02i (%ls) %ls" -msgstr "NIC %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" msgid "Render behavior" msgstr "渲染行为" @@ -2046,8 +2046,8 @@ msgstr "命名管道(服务器)" msgid "Host Serial Passthrough" msgstr "主机串行端口直通" -msgid "Eject %s" -msgstr "弹出 %s" +msgid "E&ject %1" +msgstr "弹出 %1(&J)" msgid "&Unmute" msgstr "解除静音(&U)" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 6b7420bc7..3526f696d 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -642,8 +642,8 @@ msgstr "按下 Ctrl+Alt+PgDn 返回到視窗模式。" msgid "Speed" msgstr "速度" -msgid "ZIP %03i %i (%s): %ls" -msgstr "ZIP %03i %i (%s): %ls" +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" msgid "ZIP images" msgstr "ZIP 映像" @@ -750,8 +750,8 @@ msgstr "KB" msgid "Default" msgstr "預設" -msgid "%i Wait state(s)" -msgstr "%i 等待狀態 (WS)" +msgid "%1 Wait state(s)" +msgstr "%1 等待狀態 (WS)" msgid "Type" msgstr "類型" @@ -795,11 +795,11 @@ msgstr "Thrustmaster Flight Control System" msgid "None" msgstr "無" -msgid "%u MB (CHS: %i, %i, %i)" -msgstr "%u MB (CHS: %i, %i, %i)" +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %i (%s): %ls" -msgstr "軟碟 %i (%s): %ls" +msgid "Floppy %1 (%2): %3" +msgstr "軟碟 %1 (%2): %3" msgid "Advanced sector images" msgstr "進階磁區映像" @@ -819,8 +819,8 @@ msgstr "無法初始化 Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "無法初始化 GhostPCL" -msgid "MO %i (%ls): %ls" -msgstr "磁光碟 %i (%ls): %ls" +msgid "MO %1 (%2): %3" +msgstr "磁光碟 %1 (%2): %3" msgid "MO images" msgstr "磁光碟映像" @@ -906,14 +906,14 @@ msgstr "此模擬電腦停用了基於選定電腦的 CPU 類型過濾。\n\n能 msgid "Continue" msgstr "繼續" -msgid "Cassette: %s" -msgstr "磁帶: %s" +msgid "Cassette: %1" +msgstr "磁帶: %1" msgid "Cassette images" msgstr "磁帶映像" -msgid "Cartridge %i: %ls" -msgstr "卡帶 %i: %ls" +msgid "Cartridge %1: %2" +msgstr "卡帶 %1: %2" msgid "Cartridge images" msgstr "卡帶映像" @@ -1080,8 +1080,8 @@ msgstr "IDE" msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %i (%s): %s" -msgstr "光碟 %i (%s): %s" +msgid "CD-ROM %1 (%2): %3" +msgstr "光碟 %1 (%2): %3" msgid "160 KB" msgstr "160 KB" @@ -1272,8 +1272,8 @@ msgstr "未知匯流排" msgid "Null Driver" msgstr "空驅動程式" -msgid "NIC %02i (%ls) %ls" -msgstr "網路卡 %02i (%ls) %ls" +msgid "NIC %1 (%2) %3" +msgstr "網路卡 %1 (%2) %3" msgid "Render behavior" msgstr "渲染行為" @@ -2046,8 +2046,8 @@ msgstr "已命名管道 (伺服器)" msgid "Host Serial Passthrough" msgstr "主機序列埠的直通" -msgid "Eject %s" -msgstr "退出 %s" +msgid "E&ject %1" +msgstr "退出 %1(&J)" msgid "&Unmute" msgstr "解除靜音(&U)" diff --git a/src/qt/qt_harddiskdialog.cpp b/src/qt/qt_harddiskdialog.cpp index 2acaaeacc..9e5563536 100644 --- a/src/qt/qt_harddiskdialog.cpp +++ b/src/qt/qt_harddiskdialog.cpp @@ -77,8 +77,7 @@ HarddiskDialog::HarddiskDialog(bool existing, QWidget *parent) for (int i = 0; i < 127; i++) { uint64_t size = ((uint64_t) hdd_table[i][0]) * hdd_table[i][1] * hdd_table[i][2]; uint32_t size_mb = size >> 11LL; - // QString text = QString("%1 MiB (CHS: %2, %3, %4)").arg(size_mb).arg(hdd_table[i][0]).arg(hdd_table[i][1]).arg(hdd_table[i][2]); - QString text = QString::asprintf(tr("%u MB (CHS: %i, %i, %i)").toUtf8().constData(), size_mb, (hdd_table[i][0]), (hdd_table[i][1]), (hdd_table[i][2])); + QString text = tr("%1 MB (CHS: %2, %3, %4)").arg(size_mb).arg(hdd_table[i][0]).arg(hdd_table[i][1]).arg(hdd_table[i][2]); Models::AddEntry(model, text, i); } Models::AddEntry(model, tr("Custom..."), 127); diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 478f64c2a..3e7c84ca7 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -93,7 +93,7 @@ MediaMenu::refresh(QMenu *parentMenu) cassetteMenu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cassetteImageHistoryPos[slot] = cassetteMenu->children().count(); - cassetteMenu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, slot]() { cassetteMenuSelect(slot); })->setCheckable(false); + cassetteMenu->addAction(tr("Image %1").arg(slot), [this, slot]() { cassetteMenuSelect(slot); })->setCheckable(false); } cassetteMenu->addSeparator(); cassetteRecordPos = cassetteMenu->children().count(); @@ -118,7 +118,7 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cartridgeImageHistoryPos[slot] = menu->children().count(); - menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { cartridgeMenuSelect(i, slot); })->setCheckable(false); + menu->addAction(tr("Image %1").arg(slot), [this, i, slot]() { cartridgeMenuSelect(i, slot); })->setCheckable(false); } menu->addSeparator(); cartridgeEjectPos = menu->children().count(); @@ -138,7 +138,7 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { floppyImageHistoryPos[slot] = menu->children().count(); - menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { floppyMenuSelect(i, slot); })->setCheckable(false); + menu->addAction(tr("Image %1").arg(slot), [this, i, slot]() { floppyMenuSelect(i, slot); })->setCheckable(false); } menu->addSeparator(); floppyExportPos = menu->children().count(); @@ -161,7 +161,7 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cdromImageHistoryPos[slot] = menu->children().count(); - menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { cdromReload(i, slot); })->setCheckable(false); + menu->addAction(tr("Image %1").arg(slot), [this, i, slot]() { cdromReload(i, slot); })->setCheckable(false); } menu->addSeparator(); #ifdef Q_OS_WINDOWS @@ -191,7 +191,7 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { zipImageHistoryPos[slot] = menu->children().count(); - menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { zipReload(i, slot); })->setCheckable(false); + menu->addAction(tr("Image %1").arg(slot), [this, i, slot]() { zipReload(i, slot); })->setCheckable(false); } menu->addSeparator(); zipEjectPos = menu->children().count(); @@ -210,7 +210,7 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { moImageHistoryPos[slot] = menu->children().count(); - menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { moReload(i, slot); })->setCheckable(false); + menu->addAction(tr("Image %1").arg(slot), [this, i, slot]() { moReload(i, slot); })->setCheckable(false); } menu->addSeparator(); moEjectPos = menu->children().count(); @@ -323,8 +323,7 @@ MediaMenu::cassetteUpdateMenu() recordMenu->setChecked(isSaving); playMenu->setChecked(!isSaving); - cassetteMenu->setTitle(QString::asprintf(tr("Cassette: %s").toUtf8().constData(), - (name.isEmpty() ? tr("(empty)") : name).toUtf8().constData())); + cassetteMenu->setTitle(tr("Cassette: %1").arg(name.isEmpty() ? tr("(empty)") : name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { updateImageHistory(0, slot, ui::MediaType::Cassette); @@ -389,8 +388,7 @@ MediaMenu::cartridgeUpdateMenu(int i) auto childs = menu->children(); auto *ejectMenu = dynamic_cast(childs[cartridgeEjectPos]); ejectMenu->setEnabled(!name.isEmpty()); - // menu->setTitle(tr("Cartridge %1: %2").arg(QString::number(i+1), name.isEmpty() ? tr("(empty)") : name)); - menu->setTitle(QString::asprintf(tr("Cartridge %i: %ls").toUtf8().constData(), i + 1, name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + menu->setTitle(tr("Cartridge %1: %2").arg(QString::number(i + 1), name.isEmpty() ? tr("(empty)") : name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { updateImageHistory(i, slot, ui::MediaType::Cartridge); @@ -491,7 +489,7 @@ MediaMenu::floppyUpdateMenu(int i) auto *ejectMenu = dynamic_cast(childs[floppyEjectPos]); auto *exportMenu = dynamic_cast(childs[floppyExportPos]); ejectMenu->setEnabled(!name.isEmpty()); - ejectMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), name.isEmpty() ? QString().toUtf8().constData() : fi.fileName().toUtf8().constData())); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(fi.fileName())); exportMenu->setEnabled(!name.isEmpty()); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { @@ -499,8 +497,8 @@ MediaMenu::floppyUpdateMenu(int i) } int type = fdd_get_type(i); - // floppyMenus[i]->setTitle(tr("Floppy %1 (%2): %3").arg(QString::number(i+1), fdd_getname(type), name.isEmpty() ? tr("(empty)") : name)); - floppyMenus[i]->setTitle(QString::asprintf(tr("Floppy %i (%s): %ls").toUtf8().constData(), i + 1, fdd_getname(type), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + floppyMenus[i]->setTitle(tr("Floppy %1 (%2): %3").arg(QString::number(i + 1), fdd_getname(type), name.isEmpty() ? tr("(empty)") : name)); + } void @@ -749,7 +747,7 @@ MediaMenu::cdromUpdateMenu(int i) menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); } imageMenu->setIcon(menu_icon); - imageMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), menu_item_name.toUtf8().constData())); + imageMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(menu_item_name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) updateImageHistory(i, slot, ui::MediaType::Optical); @@ -769,8 +767,7 @@ MediaMenu::cdromUpdateMenu(int i) break; } - // menu->setTitle(tr("CD-ROM %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); - menu->setTitle(QString::asprintf(tr("CD-ROM %i (%s): %s").toUtf8().constData(), i + 1, busName.toUtf8().data(), name.isEmpty() ? tr("(empty)").toUtf8().data() : name2.toUtf8().data())); + menu->setTitle(tr("CD-ROM %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name2)); } void @@ -899,8 +896,7 @@ MediaMenu::zipUpdateMenu(int i) break; } - // menu->setTitle(tr("ZIP %1 %2 (%3): %4").arg((zip_drives[i].is_250 > 0) ? "250" : "100", QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); - menu->setTitle(QString::asprintf(tr("ZIP %03i %i (%s): %ls").toUtf8().constData(), (zip_drives[i].is_250 > 0) ? 250 : 100, i + 1, busName.toUtf8().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + menu->setTitle(tr("ZIP %1 %2 (%3): %4").arg((zip_drives[i].is_250 > 0) ? QString("250") : QString("100"), QString::number(i + 1), busName, name.isEmpty() ? tr("(empty)") : name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) updateImageHistory(i, slot, ui::MediaType::Zip); @@ -1035,7 +1031,7 @@ MediaMenu::moUpdateMenu(int i) break; } - menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + menu->setTitle(tr("MO %1 (%2): %3").arg(QString::number(i + 1), busName, name.isEmpty() ? tr("(empty)") : name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) updateImageHistory(i, slot, ui::MediaType::Mo); @@ -1087,7 +1083,7 @@ MediaMenu::nicUpdateMenu(int i) auto *connectedAction = dynamic_cast(childs[netDisconnPos]); connectedAction->setChecked(network_is_connected(i)); - menu->setTitle(QString::asprintf(tr("NIC %02i (%ls) %ls").toUtf8().constData(), i + 1, netType.toStdU16String().data(), devName.toStdU16String().data())); + menu->setTitle(tr("NIC %1 (%2) %3").arg(QString::number(i + 1), netType, devName)); } QString diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp index 34968b288..939cd9eb2 100644 --- a/src/qt/qt_settingsmachine.cpp +++ b/src/qt/qt_settingsmachine.cpp @@ -69,7 +69,7 @@ SettingsMachine::SettingsMachine(QWidget *parent) waitStatesModel->setData(idx, 0, Qt::UserRole); for (int i = 0; i < 8; ++i) { idx = waitStatesModel->index(i + 1, 0); - waitStatesModel->setData(idx, QString::asprintf(tr("%i Wait state(s)").toUtf8().constData(), i), Qt::DisplayRole); + waitStatesModel->setData(idx, tr("%1 Wait state(s)").arg(i), Qt::DisplayRole); waitStatesModel->setData(idx, i + 1, Qt::UserRole); } From 1819539c976659fb5ba24bd32be5e5d39ad9f8df Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 05:16:39 +0500 Subject: [PATCH 0712/1190] qt: Make filename/path display consistent across media menus - All media history entries now display the full path - All "Eject" menu items now display the file name --- src/qt/languages/86box.pot | 5 +---- src/qt/languages/ca-ES.po | 7 ++----- src/qt/languages/cs-CZ.po | 7 ++----- src/qt/languages/de-DE.po | 7 ++----- src/qt/languages/es-ES.po | 7 ++----- src/qt/languages/fi-FI.po | 7 ++----- src/qt/languages/fr-FR.po | 7 ++----- src/qt/languages/hr-HR.po | 7 ++----- src/qt/languages/hu-HU.po | 7 ++----- src/qt/languages/it-IT.po | 7 ++----- src/qt/languages/ja-JP.po | 7 ++----- src/qt/languages/ko-KR.po | 7 ++----- src/qt/languages/nl-NL.po | 7 ++----- src/qt/languages/pl-PL.po | 7 ++----- src/qt/languages/pt-BR.po | 7 ++----- src/qt/languages/pt-PT.po | 7 ++----- src/qt/languages/ru-RU.po | 7 ++----- src/qt/languages/sk-SK.po | 7 ++----- src/qt/languages/sl-SI.po | 7 ++----- src/qt/languages/tr-TR.po | 7 ++----- src/qt/languages/uk-UA.po | 7 ++----- src/qt/languages/vi-VN.po | 7 ++----- src/qt/languages/zh-CN.po | 7 ++----- src/qt/languages/zh-TW.po | 7 ++----- src/qt/qt_mediamenu.cpp | 43 ++++++++++++++++++++++---------------- src/qt/qt_mediamenu.hpp | 3 +-- 26 files changed, 73 insertions(+), 139 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index a778f9f6d..07dfb7cc5 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -249,7 +249,7 @@ msgstr "" msgid "E&mpty" msgstr "" -msgid "&Reload previous image" +msgid "Reload previous image" msgstr "" msgid "&Folder..." @@ -1260,9 +1260,6 @@ msgstr "" msgid "Create..." msgstr "" -msgid "previous image" -msgstr "" - msgid "Host CD/DVD Drive (%1)" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 808799859..dc0a9df2a 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -249,8 +249,8 @@ msgstr "&Silenciar" msgid "E&mpty" msgstr "E&xtreure disc" -msgid "&Reload previous image" -msgstr "&Recarregar imatge anterior" +msgid "Reload previous image" +msgstr "Recarregar imatge anterior" msgid "&Folder..." msgstr "&Carpeta ..." @@ -1260,9 +1260,6 @@ msgstr "Esborrar la història de imatges" msgid "Create..." msgstr "Crear ..." -msgid "previous image" -msgstr "imatge anterior" - msgid "Host CD/DVD Drive (%1)" msgstr "Unitat CD/DVD d'amfitrió (%1)" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index d3985b67a..7e76d3760 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -249,8 +249,8 @@ msgstr "&Ztišit" msgid "E&mpty" msgstr "&Vyjmout" -msgid "&Reload previous image" -msgstr "&Načíst znova předchozí obraz" +msgid "Reload previous image" +msgstr "Načíst znova předchozí obraz" msgid "&Folder..." msgstr "&Složka..." @@ -1260,9 +1260,6 @@ msgstr "Vymaž historie snímků" msgid "Create..." msgstr "Vytvoř..." -msgid "previous image" -msgstr "předchozí obraz" - msgid "Host CD/DVD Drive (%1)" msgstr "Jednotka CD/DVD hostitele (%1)" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 781269af9..f545729a8 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -249,8 +249,8 @@ msgstr "&Stummschalten" msgid "E&mpty" msgstr "L&eer" -msgid "&Reload previous image" -msgstr "&Voriges Abbild neu laden" +msgid "Reload previous image" +msgstr "Voriges Abbild neu laden" msgid "&Folder..." msgstr "&Verzeichnis..." @@ -1263,9 +1263,6 @@ msgstr "Abbildverlauf löschen" msgid "Create..." msgstr "Erstellen..." -msgid "previous image" -msgstr "Vorheriges Abbild" - msgid "Host CD/DVD Drive (%1)" msgstr "Host-CD/DVD-Laufwerk (%1)" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 3cdcedd98..0733f46ec 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -249,8 +249,8 @@ msgstr "&Silenciar" msgid "E&mpty" msgstr "E&xtraer disco" -msgid "&Reload previous image" -msgstr "&Recargar imagen previa" +msgid "Reload previous image" +msgstr "Recargar imagen previa" msgid "&Folder..." msgstr "&Carpeta..." @@ -1259,9 +1259,6 @@ msgstr "Eliminar historia de imágenes" msgid "Create..." msgstr "Crear..." -msgid "previous image" -msgstr "imagen previa" - msgid "Host CD/DVD Drive (%1)" msgstr "Unidad de CD/DVD anfitriona (%1)" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index ddae5c2ba..a7ac64eff 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -249,8 +249,8 @@ msgstr "&Mykistä" msgid "E&mpty" msgstr "&Tyhjä" -msgid "&Reload previous image" -msgstr "&Lataa edellinen levykuva uudelleen" +msgid "Reload previous image" +msgstr "Lataa edellinen levykuva uudelleen" msgid "&Folder..." msgstr "&Kansio..." @@ -1260,9 +1260,6 @@ msgstr "Tyhjennä kuvahistoria" msgid "Create..." msgstr "Luo..." -msgid "previous image" -msgstr "edellinen levykuva" - msgid "Host CD/DVD Drive (%1)" msgstr "Isäntä CD/DVD-asema (%1)" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index df5bf7ef6..434e8c31b 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -249,8 +249,8 @@ msgstr "&Couper" msgid "E&mpty" msgstr "E&jecter" -msgid "&Reload previous image" -msgstr "&Recharger image précedente" +msgid "Reload previous image" +msgstr "Recharger image précedente" msgid "&Folder..." msgstr "&Dossier..." @@ -1260,9 +1260,6 @@ msgstr "Effacer l'historique de l'image" msgid "Create..." msgstr "Créer..." -msgid "previous image" -msgstr "image précedente" - msgid "Host CD/DVD Drive (%1)" msgstr "Lecteur CD/DVD hôte (%1)" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index ecfd0c696..b202b39b5 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -249,8 +249,8 @@ msgstr "&Isključi zvuk" msgid "E&mpty" msgstr "&Prazno" -msgid "&Reload previous image" -msgstr "&Ponovo učitaj prethodnu sliku" +msgid "Reload previous image" +msgstr "Ponovo učitaj prethodnu sliku" msgid "&Folder..." msgstr "&Mapa..." @@ -1260,9 +1260,6 @@ msgstr "Očisti povijest slika" msgid "Create..." msgstr "Stvori..." -msgid "previous image" -msgstr "prethodna slika" - msgid "Host CD/DVD Drive (%1)" msgstr "CD/DVD pogon nositelja (%1)" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 79e0dd5e6..e9aa6a4ff 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -249,8 +249,8 @@ msgstr "&Némítás" msgid "E&mpty" msgstr "&Kiadás" -msgid "&Reload previous image" -msgstr "Előző képfájl &újratöltése" +msgid "Reload previous image" +msgstr "Előző képfájl újratöltése" msgid "&Folder..." msgstr "&Mappa..." @@ -1260,9 +1260,6 @@ msgstr "Törölje a kép előzményeit" msgid "Create..." msgstr "Hozzon létre..." -msgid "previous image" -msgstr "előző képfájl" - msgid "Host CD/DVD Drive (%1)" msgstr "Gazdag CD/DVD-meghajtó (%1)" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 832c5b3fc..2f31a9dba 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -249,8 +249,8 @@ msgstr "&Muto" msgid "E&mpty" msgstr "&Espelli" -msgid "&Reload previous image" -msgstr "&Ricarica l'immagine precedente" +msgid "Reload previous image" +msgstr "Ricarica l'immagine precedente" msgid "&Folder..." msgstr "&Cartella..." @@ -1260,9 +1260,6 @@ msgstr "Cancella la cronologia delle immagini" msgid "Create..." msgstr "Creare..." -msgid "previous image" -msgstr "immagine precedente" - msgid "Host CD/DVD Drive (%1)" msgstr "Unità CD/DVD host (%1)" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 4bf10f7fc..318d0dca5 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -249,8 +249,8 @@ msgstr "ミュート(&M)" msgid "E&mpty" msgstr "なし(&M)" -msgid "&Reload previous image" -msgstr "前のイメージを再読み込み(&R)" +msgid "Reload previous image" +msgstr "前のイメージを再読み込み" msgid "&Folder..." msgstr "フォルダ(&F)..." @@ -1260,9 +1260,6 @@ msgstr "クリア画像履歴" msgid "Create..." msgstr "作成..." -msgid "previous image" -msgstr "前の画像" - msgid "Host CD/DVD Drive (%1)" msgstr "ホスト CD/DVD ドライブ (%1)" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index d6a0c234a..027c5a778 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -249,8 +249,8 @@ msgstr "음소거(&M)" msgid "E&mpty" msgstr "비었음(&M)" -msgid "&Reload previous image" -msgstr "이전 이미지 다시 불러오기(&R)" +msgid "Reload previous image" +msgstr "이전 이미지 다시 불러오기" msgid "&Folder..." msgstr "폴더(&F)..." @@ -1260,9 +1260,6 @@ msgstr "이미지 기록 지우기" msgid "Create..." msgstr "만들기..." -msgid "previous image" -msgstr "이전 이미지" - msgid "Host CD/DVD Drive (%1)" msgstr "호스트 CD/DVD 드라이브 (%1)" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index d57c389e1..65e589b2b 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -249,8 +249,8 @@ msgstr "&Mute" msgid "E&mpty" msgstr "E&mpty" -msgid "&Reload previous image" -msgstr "&Herlaad vorige image" +msgid "Reload previous image" +msgstr "Herlaad vorige image" msgid "&Folder..." msgstr "&Map..." @@ -1260,9 +1260,6 @@ msgstr "Imagegeschiedenis verwijderen" msgid "Create..." msgstr "Creëer..." -msgid "previous image" -msgstr "vorige image" - msgid "Host CD/DVD Drive (%1)" msgstr "Host CD/DVD-station (%1)" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index a72810b01..4e93f9dd1 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -249,8 +249,8 @@ msgstr "&Ścisz" msgid "E&mpty" msgstr "P&usty" -msgid "&Reload previous image" -msgstr "&Przeładuj poprzedni obraz" +msgid "Reload previous image" +msgstr "Przeładuj poprzedni obraz" msgid "&Folder..." msgstr "&Teczka..." @@ -1260,9 +1260,6 @@ msgstr "Wyczyść historię obrazów" msgid "Create..." msgstr "Stwórz..." -msgid "previous image" -msgstr "poprzedni obraz" - msgid "Host CD/DVD Drive (%1)" msgstr "Napęd CD/DVD hosta (%1)" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 3535f63b9..3e0ec7ff1 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -249,8 +249,8 @@ msgstr "&Silenciar" msgid "E&mpty" msgstr "&Vazio" -msgid "&Reload previous image" -msgstr "&Recarregar imagem anterior" +msgid "Reload previous image" +msgstr "Recarregar imagem anterior" msgid "&Folder..." msgstr "&Pasta..." @@ -1260,9 +1260,6 @@ msgstr "Limpar histórico de imagens" msgid "Create..." msgstr "Criar..." -msgid "previous image" -msgstr "imagem anterior" - msgid "Host CD/DVD Drive (%1)" msgstr "Unidade de CD/DVD do anfitrião (%1)" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index ea6856347..9fb1ce342 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -249,8 +249,8 @@ msgstr "&Desativar som" msgid "E&mpty" msgstr "&CDROM vazio" -msgid "&Reload previous image" -msgstr "&Recarregar imagem anterior" +msgid "Reload previous image" +msgstr "Recarregar imagem anterior" msgid "&Folder..." msgstr "&Pasta..." @@ -1260,9 +1260,6 @@ msgstr "Limpar o histórico de imagens" msgid "Create..." msgstr "Criar..." -msgid "previous image" -msgstr "imagem anterior" - msgid "Host CD/DVD Drive (%1)" msgstr "Unidade de CD/DVD do anfitrião (%1)" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index fd6a1d72a..725f7adf6 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -249,8 +249,8 @@ msgstr "О&тключить звук" msgid "E&mpty" msgstr "П&устой" -msgid "&Reload previous image" -msgstr "&Снова загрузить предыдущий образ" +msgid "Reload previous image" +msgstr "Загрузить предыдущий образ" msgid "&Folder..." msgstr "&Папка..." @@ -1260,9 +1260,6 @@ msgstr "Очистить историю образов" msgid "Create..." msgstr "Создайте..." -msgid "previous image" -msgstr "предыдущее изображение" - msgid "Host CD/DVD Drive (%1)" msgstr "Главный CD/DVD-привод (%1)" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index b77ff5695..937b067fe 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -249,8 +249,8 @@ msgstr "&Stíšiť" msgid "E&mpty" msgstr "&Vystrihnúť" -msgid "&Reload previous image" -msgstr "&Načítať znova predchádzajúci obraz" +msgid "Reload previous image" +msgstr "Načítať znova predchádzajúci obraz" msgid "&Folder..." msgstr "&Zložka..." @@ -1260,9 +1260,6 @@ msgstr "Vymazanie histórie obrázkov" msgid "Create..." msgstr "Vytvorte..." -msgid "previous image" -msgstr "predchádzajúca snímka" - msgid "Host CD/DVD Drive (%1)" msgstr "Hostiteľská jednotka CD/DVD (%1)" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 9bedaa6cf..b28954b19 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -249,8 +249,8 @@ msgstr "&Utišaj" msgid "E&mpty" msgstr "&Prazen" -msgid "&Reload previous image" -msgstr "&Naloži zadnjo sliko" +msgid "Reload previous image" +msgstr "Naloži zadnjo sliko" msgid "&Folder..." msgstr "&Mapa..." @@ -1260,9 +1260,6 @@ msgstr "Jasna zgodovina slik" msgid "Create..." msgstr "Ustvari..." -msgid "previous image" -msgstr "zadnja slika" - msgid "Host CD/DVD Drive (%1)" msgstr "Pogon CD/DVD gostitelja (%1)" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 5936f39c9..54bdac06e 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -249,8 +249,8 @@ msgstr "&Sesi kapat" msgid "E&mpty" msgstr "İmajı &çıkar" -msgid "&Reload previous image" -msgstr "&Önceki imajı yeniden seç" +msgid "Reload previous image" +msgstr "Önceki imajı yeniden seç" msgid "&Folder..." msgstr "&Klasör..." @@ -1260,9 +1260,6 @@ msgstr "İmaj geçmişini temizleyin" msgid "Create..." msgstr "Oluştur..." -msgid "previous image" -msgstr "önceki imaj" - msgid "Host CD/DVD Drive (%1)" msgstr "Ana bilgisayar CD/DVD sürücüsü (%1)" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 36e227d6f..b78bb0661 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -249,8 +249,8 @@ msgstr "&Відключити звук" msgid "E&mpty" msgstr "&Пустий" -msgid "&Reload previous image" -msgstr "&Знову завантажити попередній образ" +msgid "Reload previous image" +msgstr "Знову завантажити попередній образ" msgid "&Folder..." msgstr "&Тека..." @@ -1260,9 +1260,6 @@ msgstr "Очистити історію образів" msgid "Create..." msgstr "Створити..." -msgid "previous image" -msgstr "попередній образ" - msgid "Host CD/DVD Drive (%1)" msgstr "CD/DVD привід хоста (%1)" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 1d1a3697e..e4b15a971 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -249,8 +249,8 @@ msgstr "Tắt tiến&g" msgid "E&mpty" msgstr "Làm trố&ng đĩa" -msgid "&Reload previous image" -msgstr "Load đĩ&a trước đó" +msgid "Reload previous image" +msgstr "Load đĩa trước đó" msgid "&Folder..." msgstr "Thư mụ&c" @@ -1260,9 +1260,6 @@ msgstr "Xóa lịch sử ảnh đĩa" msgid "Create..." msgstr "Tạo..." -msgid "previous image" -msgstr "đĩa trước đó" - msgid "Host CD/DVD Drive (%1)" msgstr "Máy chủ CD/DVD Drive (%1)" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index b39c64563..b02f41bbb 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -249,8 +249,8 @@ msgstr "静音(&M)" msgid "E&mpty" msgstr "空置驱动器(&M)" -msgid "&Reload previous image" -msgstr "载入上一个映像(&R)" +msgid "Reload previous image" +msgstr "载入上一个映像" msgid "&Folder..." msgstr "文件夹(&F)..." @@ -1260,9 +1260,6 @@ msgstr "清除映像历史记录" msgid "Create..." msgstr "创建..." -msgid "previous image" -msgstr "上一张" - msgid "Host CD/DVD Drive (%1)" msgstr "主机 CD/DVD 驱动器 (%1)" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 3526f696d..2662770b8 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -249,8 +249,8 @@ msgstr "靜音(&M)" msgid "E&mpty" msgstr "空置光碟機(&M)" -msgid "&Reload previous image" -msgstr "載入上一個映像(&R)" +msgid "Reload previous image" +msgstr "載入上一個映像" msgid "&Folder..." msgstr "資料夾(&F)..." @@ -1260,9 +1260,6 @@ msgstr "清除映像歷史記錄" msgid "Create..." msgstr "建立..." -msgid "previous image" -msgstr "上一個映像" - msgid "Host CD/DVD Drive (%1)" msgstr "主機 CD/DVD 光碟機 (%1)" diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 3e7c84ca7..351012d1e 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -174,8 +174,7 @@ MediaMenu::refresh(QMenu *parentMenu) } menu->addSeparator(); #endif // Q_OS_WINDOWS - cdromImagePos = menu->children().count(); - cdromDirPos = menu->children().count(); + cdromEjectPos = menu->children().count(); menu->addAction(tr("E&ject"), [this, i]() { cdromEject(i); })->setCheckable(false); cdromMenus[i] = menu; cdromUpdateMenu(i); @@ -304,7 +303,8 @@ MediaMenu::cassetteEject() void MediaMenu::cassetteUpdateMenu() { - QString name = cassette_fname; + QString name = cassette_fname; + QFileInfo fi(cassette_fname); const QString mode = cassette_mode; auto childs = cassetteMenu->children(); auto *recordMenu = dynamic_cast(childs[cassetteRecordPos]); @@ -318,6 +318,7 @@ MediaMenu::cassetteUpdateMenu() rewindMenu->setEnabled(!name.isEmpty()); fastFwdMenu->setEnabled(!name.isEmpty()); ejectMenu->setEnabled(!name.isEmpty()); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(fi.fileName())); const bool isSaving = (mode == QStringLiteral("save")); recordMenu->setChecked(isSaving); @@ -384,10 +385,12 @@ void MediaMenu::cartridgeUpdateMenu(int i) { const QString name = cart_fns[i]; - auto *menu = cartridgeMenus[i]; + QFileInfo fi(cart_fns[i]); + auto *menu = cartridgeMenus[i]; auto childs = menu->children(); auto *ejectMenu = dynamic_cast(childs[cartridgeEjectPos]); ejectMenu->setEnabled(!name.isEmpty()); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(fi.fileName())); menu->setTitle(tr("Cartridge %1: %2").arg(QString::number(i + 1), name.isEmpty() ? tr("(empty)") : name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { @@ -628,7 +631,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) switch (type) { default: - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; return; case ui::MediaType::Cassette: if (!MachineStatus::hasCassette()) @@ -637,7 +640,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cassetteImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; break; case ui::MediaType::Cartridge: if (!machine_has_cartridge(machine)) @@ -646,7 +649,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cartridgeImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; break; case ui::MediaType::Floppy: if (!floppyMenus.contains(index)) @@ -655,7 +658,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[floppyImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; break; case ui::MediaType::Optical: if (!cdromMenus.contains(index)) @@ -673,7 +676,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) } else { fi.setFile(fn); menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); - menu_item_name = fn.isEmpty() ? tr("previous image") : fn; + menu_item_name = fn.isEmpty() ? tr("Reload previous image") : fn; } imageHistoryUpdatePos->setIcon(menu_icon); break; @@ -684,7 +687,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[zipImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; break; case ui::MediaType::Mo: if (!moMenus.contains(index)) @@ -693,7 +696,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[moImageHistoryPos[slot]]); fi.setFile(fn); - menu_item_name = fi.fileName().isEmpty() ? tr("previous image") : fi.fileName(); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; break; } @@ -728,8 +731,8 @@ MediaMenu::cdromUpdateMenu(int i) muteMenu->setIcon(QIcon((cdrom[i].sound_on == 0) ? ":/settings/qt/icons/cdrom_unmute.ico" : ":/settings/qt/icons/cdrom_mute.ico")); muteMenu->setText((cdrom[i].sound_on == 0) ? tr("&Unmute") : tr("&Mute")); - auto *imageMenu = dynamic_cast(childs[cdromImagePos]); - imageMenu->setEnabled(!name.isEmpty()); + auto *ejectMenu = dynamic_cast(childs[cdromEjectPos]); + ejectMenu->setEnabled(!name.isEmpty()); QString menu_item_name; if (name.left(8) == "ioctl://") { #ifdef Q_OS_WINDOWS @@ -742,12 +745,12 @@ MediaMenu::cdromUpdateMenu(int i) } else { QFileInfo fi(cdrom[i].image_path); - menu_item_name = name.isEmpty() ? QString() : name; + menu_item_name = name.isEmpty() ? QString() : fi.fileName(); name2 = name; menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico"); } - imageMenu->setIcon(menu_icon); - imageMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(menu_item_name)); + ejectMenu->setIcon(menu_icon); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(menu_item_name)); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) updateImageHistory(i, slot, ui::MediaType::Optical); @@ -876,6 +879,7 @@ MediaMenu::zipUpdateMenu(int i) { const QString name = zip_drives[i].image_path; const QString prev_name = zip_drives[i].prev_image_path; + QFileInfo fi(zip_drives[i].image_path); if (!zipMenus.contains(i)) return; auto *menu = zipMenus[i]; @@ -883,6 +887,7 @@ MediaMenu::zipUpdateMenu(int i) auto *ejectMenu = dynamic_cast(childs[zipEjectPos]); ejectMenu->setEnabled(!name.isEmpty()); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(fi.fileName())); QString busName = tr("Unknown Bus"); switch (zip_drives[i].bus_type) { @@ -1009,8 +1014,9 @@ MediaMenu::moReload(int index, int slot) void MediaMenu::moUpdateMenu(int i) { - QString name = mo_drives[i].image_path; - QString prev_name = mo_drives[i].prev_image_path; + QString name = mo_drives[i].image_path; + QString prev_name = mo_drives[i].prev_image_path; + QFileInfo fi(mo_drives[i].image_path); if (!moMenus.contains(i)) return; auto *menu = moMenus[i]; @@ -1018,6 +1024,7 @@ MediaMenu::moUpdateMenu(int i) auto *ejectMenu = dynamic_cast(childs[moEjectPos]); ejectMenu->setEnabled(!name.isEmpty()); + ejectMenu->setText(name.isEmpty() ? tr("E&ject") : tr("E&ject %1").arg(fi.fileName())); QString busName = tr("Unknown Bus"); switch (mo_drives[i].bus_type) { diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index b069c67d9..ed97a0a50 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -108,8 +108,7 @@ private: int floppyImageHistoryPos[MAX_PREV_IMAGES]; int cdromMutePos; - int cdromImagePos; - int cdromDirPos; + int cdromEjectPos; int cdromImageHistoryPos[MAX_PREV_IMAGES]; int zipEjectPos; From 40ee98d6f3837b311c4573d1daf1b9d98143ebb1 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 05:26:01 +0500 Subject: [PATCH 0713/1190] qt: The sound icon's menu is now a submenu of the Tools menu Replaces (and includes) the standalone Sound gain option --- src/qt/languages/86box.pot | 3 +++ src/qt/languages/ca-ES.po | 3 +++ src/qt/languages/cs-CZ.po | 3 +++ src/qt/languages/de-DE.po | 3 +++ src/qt/languages/es-ES.po | 3 +++ src/qt/languages/fi-FI.po | 3 +++ src/qt/languages/fr-FR.po | 3 +++ src/qt/languages/hr-HR.po | 3 +++ src/qt/languages/hu-HU.po | 3 +++ src/qt/languages/it-IT.po | 3 +++ src/qt/languages/ja-JP.po | 3 +++ src/qt/languages/ko-KR.po | 3 +++ src/qt/languages/nl-NL.po | 3 +++ src/qt/languages/pl-PL.po | 3 +++ src/qt/languages/pt-BR.po | 3 +++ src/qt/languages/pt-PT.po | 3 +++ src/qt/languages/ru-RU.po | 3 +++ src/qt/languages/sk-SK.po | 3 +++ src/qt/languages/sl-SI.po | 3 +++ src/qt/languages/tr-TR.po | 3 +++ src/qt/languages/uk-UA.po | 3 +++ src/qt/languages/vi-VN.po | 3 +++ src/qt/languages/zh-CN.po | 3 +++ src/qt/languages/zh-TW.po | 3 +++ src/qt/qt_machinestatus.cpp | 36 +++++++++--------------------------- src/qt/qt_machinestatus.hpp | 5 ++--- src/qt/qt_mainwindow.cpp | 14 ++++++++++++-- src/qt/qt_mainwindow.hpp | 1 + src/qt/qt_mainwindow.ui | 15 ++++++++++++++- 29 files changed, 110 insertions(+), 33 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 07dfb7cc5..066e98167 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -189,6 +189,9 @@ msgstr "" msgid "Take s&creenshot" msgstr "" +msgid "S&ound" +msgstr "" + msgid "&Preferences..." msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index dc0a9df2a..93ad884bd 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -189,6 +189,9 @@ msgstr "&Actualitzar icones a la barra d'estat" msgid "Take s&creenshot" msgstr "Prendre c&aptura" +msgid "S&ound" +msgstr "S&o" + msgid "&Preferences..." msgstr "&Preferències ..." diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 7e76d3760..9205839aa 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -189,6 +189,9 @@ msgstr "&Aktualizovat ikony stavového řádku" msgid "Take s&creenshot" msgstr "Pořídit &screenshot" +msgid "S&ound" +msgstr "&Zvuk" + msgid "&Preferences..." msgstr "&Předvolby..." diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index f545729a8..a90c29ac0 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -189,6 +189,9 @@ msgstr "&Statusleistenicons aktualisieren" msgid "Take s&creenshot" msgstr "S&creenshot aufnehmen" +msgid "S&ound" +msgstr "S&ound" + msgid "&Preferences..." msgstr "&Einstellungen..." diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 0733f46ec..3b90772c0 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -189,6 +189,9 @@ msgstr "&Actualizar iconos en barra de estado" msgid "Take s&creenshot" msgstr "Tomar c&aptura" +msgid "S&ound" +msgstr "S&onido" + msgid "&Preferences..." msgstr "&Preferencias..." diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index a7ac64eff..6460ce286 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -189,6 +189,9 @@ msgstr "&Päivitä tilapalkin kuvakkeita" msgid "Take s&creenshot" msgstr "Ota &kuvakaappaus" +msgid "S&ound" +msgstr "&Ääni" + msgid "&Preferences..." msgstr "&Sovellusasetukset..." diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 434e8c31b..d83bd81a3 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -189,6 +189,9 @@ msgstr "Mettre à jour la barre de stat&us" msgid "Take s&creenshot" msgstr "Copie &Ecran" +msgid "S&ound" +msgstr "S&on" + msgid "&Preferences..." msgstr "&Préférences..." diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index b202b39b5..1bc6d4d25 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -189,6 +189,9 @@ msgstr "&Ažuriraj ikone statusnog redka" msgid "Take s&creenshot" msgstr "Napravi &snimku zaslona" +msgid "S&ound" +msgstr "&Zvuk" + msgid "&Preferences..." msgstr "&Postavke..." diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index e9aa6a4ff..23229893a 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -189,6 +189,9 @@ msgstr "Állapotsori ikonok &frissítése" msgid "Take s&creenshot" msgstr "&Képernyőkép készítése" +msgid "S&ound" +msgstr "&Hang" + msgid "&Preferences..." msgstr "&Beállítások..." diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 2f31a9dba..690af0a68 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -189,6 +189,9 @@ msgstr "&Aggiorna icone della barra di stato" msgid "Take s&creenshot" msgstr "Cattura schermata" +msgid "S&ound" +msgstr "A&udio" + msgid "&Preferences..." msgstr "&Preferenze..." diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 318d0dca5..502ccda20 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -189,6 +189,9 @@ msgstr "ステータスバーのアイコンを更新(&U)" msgid "Take s&creenshot" msgstr "スクリーンショットを撮る(&C)" +msgid "S&ound" +msgstr "サウンド(&O)" + msgid "&Preferences..." msgstr "環境設定(&P)..." diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 027c5a778..b149b62bb 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -189,6 +189,9 @@ msgstr "상태 바 아이콘 갱신하기(&U)" msgid "Take s&creenshot" msgstr "스크린샷 찍기(&C)" +msgid "S&ound" +msgstr "사운드(&O)" + msgid "&Preferences..." msgstr "환경설정(&P)..." diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 65e589b2b..0fe316550 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -189,6 +189,9 @@ msgstr "&Statusbalkpictogrammen bijwerken" msgid "Take s&creenshot" msgstr "Maak een schermafbeelding" +msgid "S&ound" +msgstr "&Geluid" + msgid "&Preferences..." msgstr "&Voorkeuren..." diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 4e93f9dd1..81b9f9b04 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -189,6 +189,9 @@ msgstr "&Aktualizuj ikony na pasku statusu" msgid "Take s&creenshot" msgstr "Zrób &zrzut ekranu" +msgid "S&ound" +msgstr "Dź&więk" + msgid "&Preferences..." msgstr "&Preferencje..." diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 3e0ec7ff1..0b1ab46e4 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -189,6 +189,9 @@ msgstr "&Atualizar ícones da barra de status" msgid "Take s&creenshot" msgstr "Capturar &tela" +msgid "S&ound" +msgstr "&Som" + msgid "&Preferences..." msgstr "&Preferências..." diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 9fb1ce342..c83ac3655 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -189,6 +189,9 @@ msgstr "&Atualizar ícones da barra de estado" msgid "Take s&creenshot" msgstr "Gravar imagem de ecrã" +msgid "S&ound" +msgstr "&Som" + msgid "&Preferences..." msgstr "&Preferências..." diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 725f7adf6..b466c6624 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -189,6 +189,9 @@ msgstr "&Обновление значков строки состояния" msgid "Take s&creenshot" msgstr "Сделать с&криншот" +msgid "S&ound" +msgstr "&Звук" + msgid "&Preferences..." msgstr "&Параметры..." diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 937b067fe..d70d14e56 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -189,6 +189,9 @@ msgstr "&Aktualizovať ikony na stavovom riadku" msgid "Take s&creenshot" msgstr "Urobiť snímku &obrazovky" +msgid "S&ound" +msgstr "&Zvuk" + msgid "&Preferences..." msgstr "&Predvoľby..." diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index b28954b19..419d7dcc5 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -189,6 +189,9 @@ msgstr "&Posodabljaj ikone statusne vrstice" msgid "Take s&creenshot" msgstr "&Zajemi posnetek zaslona" +msgid "S&ound" +msgstr "Z&vok" + msgid "&Preferences..." msgstr "&Možnosti..." diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 54bdac06e..d134be6d0 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -195,6 +195,9 @@ msgstr "&Tercihler..." msgid "Enable &Discord integration" msgstr "&Discord entegrasyonunu etkinleştir" +msgid "S&ound" +msgstr "&Ses" + msgid "Sound &gain..." msgstr "&Ses düzeyi artışı..." diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index b78bb0661..d475fa201 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -189,6 +189,9 @@ msgstr "&Обновлення значків рядка стану" msgid "Take s&creenshot" msgstr "Зробити &знімок" +msgid "S&ound" +msgstr "&Звук" + msgid "&Preferences..." msgstr "&Параметри..." diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index e4b15a971..b4c72ec26 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -189,6 +189,9 @@ msgstr "Cậ&p nhật biểu tượng thanh trạng thái" msgid "Take s&creenshot" msgstr "Chụp &màn hình" +msgid "S&ound" +msgstr "&Thanh âm" + msgid "&Preferences..." msgstr "&Tùy biến..." diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index b02f41bbb..8e5dd1a4b 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -189,6 +189,9 @@ msgstr "更新状态栏图标(&U)" msgid "Take s&creenshot" msgstr "截图(&C)" +msgid "S&ound" +msgstr "声音(&O)" + msgid "&Preferences..." msgstr "首选项(&P)..." diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 2662770b8..584c18dc9 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -189,6 +189,9 @@ msgstr "更新狀態列圖示(&U)" msgid "Take s&creenshot" msgstr "擷圖(&C)" +msgid "S&ound" +msgstr "聲音(&O)" + msgid "&Preferences..." msgstr "偏好設定(&P)..." diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index aba7fc1d4..d86dae7b9 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -270,7 +270,6 @@ MachineStatus::MachineStatus(QObject *parent) , refreshTimer(new QTimer(this)) { d = std::make_unique(this); - muteUnmuteAction = nullptr; soundMenu = nullptr; connect(refreshTimer, &QTimer::timeout, this, &MachineStatus::refreshIcons); refreshTimer->start(75); @@ -279,9 +278,9 @@ MachineStatus::MachineStatus(QObject *parent) MachineStatus::~MachineStatus() = default; void -MachineStatus::setSoundGainAction(QAction* action) +MachineStatus::setSoundMenu(QMenu* menu) { - soundGainAction = action; + soundMenu = menu; } bool @@ -519,28 +518,6 @@ MachineStatus::refresh(QStatusBar *sbar) } sbar->removeWidget(d->sound.get()); - if (!muteUnmuteAction) { - muteUnmuteAction = new QAction; - connect(muteUnmuteAction, &QAction::triggered, this, [this]() { - sound_muted ^= 1; - config_save(); - if (d->sound) - d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal); - - muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); - }); - } - - if (!soundMenu) { - soundMenu = new QMenu((QWidget*)parent()); - - soundMenu->addAction(muteUnmuteAction); - soundMenu->addSeparator(); - soundMenu->addAction(soundGainAction); - - muteUnmuteAction->setParent(soundMenu); - } - if (cassette_enable) { d->cassette.label = std::make_unique(); d->cassette.setEmpty(QString(cassette_fname).isEmpty()); @@ -710,8 +687,6 @@ MachineStatus::refresh(QStatusBar *sbar) d->sound = std::make_unique(); d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal); - if (muteUnmuteAction) - muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); connect(d->sound.get(), &ClickableLabel::clicked, this, [this](QPoint pos) { this->soundMenu->popup(pos - QPoint(0, this->soundMenu->sizeHint().height())); @@ -727,6 +702,13 @@ MachineStatus::refresh(QStatusBar *sbar) refreshEmptyIcons(); } +void +MachineStatus::updateSoundIcon() +{ + if (d->sound) + d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal); +} + void MachineStatus::message(const QString &msg) { diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp index 90b420763..ad6425b5a 100644 --- a/src/qt/qt_machinestatus.hpp +++ b/src/qt/qt_machinestatus.hpp @@ -73,20 +73,19 @@ public: QString getMessage(); void clearActivity(); - void setSoundGainAction(QAction* action); + void setSoundMenu(QMenu* menu); public slots: void refresh(QStatusBar *sbar); void message(const QString &msg); void updateTip(int tag); void refreshEmptyIcons(); void refreshIcons(); + void updateSoundIcon(); private: struct States; std::unique_ptr d; QTimer *refreshTimer; - QAction *soundGainAction; - QAction *muteUnmuteAction; QMenu *soundMenu; }; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index e9ebdaad8..886f84dcd 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -180,7 +180,8 @@ MainWindow::MainWindow(QWidget *parent) extern MainWindow *main_window; main_window = this; ui->setupUi(this); - status->setSoundGainAction(ui->actionSound_gain); + status->setSoundMenu(ui->menuSound); + ui->actionMute_Unmute->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); ui->menuEGA_S_VGA_settings->menuAction()->setMenuRole(QAction::NoRole); ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); @@ -1334,7 +1335,7 @@ void MainWindow::refreshMediaMenu() { mm->refresh(ui->menuMedia); - status->setSoundGainAction(ui->actionSound_gain); + status->setSoundMenu(ui->menuSound); status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); @@ -1937,6 +1938,15 @@ MainWindow::on_actionTake_screenshot_triggered() device_force_redraw(); } +void +MainWindow::on_actionMute_Unmute_triggered() +{ + sound_muted ^= 1; + config_save(); + status->updateSoundIcon(); + ui->actionMute_Unmute->setText(sound_muted ? tr("&Unmute") : tr("&Mute")); +} + void MainWindow::on_actionSound_gain_triggered() { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 5c8bd388b..4b3f9ecae 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -116,6 +116,7 @@ private slots: void on_actionHide_tool_bar_triggered(); void on_actionUpdate_status_bar_icons_triggered(); void on_actionTake_screenshot_triggered(); + void on_actionMute_Unmute_triggered(); void on_actionSound_gain_triggered(); void on_actionPreferences_triggered(); void on_actionEnable_Discord_integration_triggered(bool checked); diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index ef3cf16c6..83a80342b 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -87,13 +87,21 @@ &Tools + + + S&ound + + + + + - + @@ -725,6 +733,11 @@ false + + + &Mute + + Sound &gain... From 91531529903a4295b254bd4241b1d58d83dd25ca Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 06:35:18 +0500 Subject: [PATCH 0714/1190] qt: Redesign hard disk dialog to accommodate drive models --- src/disk/hdd.c | 16 +-- src/qt/languages/86box.pot | 26 +++- src/qt/languages/ca-ES.po | 4 +- src/qt/languages/cs-CZ.po | 4 +- src/qt/languages/de-DE.po | 4 +- src/qt/languages/es-ES.po | 4 +- src/qt/languages/fi-FI.po | 4 +- src/qt/languages/fr-FR.po | 4 +- src/qt/languages/hr-HR.po | 4 +- src/qt/languages/hu-HU.po | 4 +- src/qt/languages/it-IT.po | 4 +- src/qt/languages/ja-JP.po | 4 +- src/qt/languages/ko-KR.po | 4 +- src/qt/languages/nl-NL.po | 4 +- src/qt/languages/pl-PL.po | 4 +- src/qt/languages/pt-BR.po | 4 +- src/qt/languages/pt-PT.po | 4 +- src/qt/languages/ru-RU.po | 7 +- src/qt/languages/sk-SK.po | 4 +- src/qt/languages/sl-SI.po | 4 +- src/qt/languages/tr-TR.po | 4 +- src/qt/languages/uk-UA.po | 4 +- src/qt/languages/vi-VN.po | 4 +- src/qt/languages/zh-CN.po | 4 +- src/qt/languages/zh-TW.po | 4 +- src/qt/qt_harddiskdialog.ui | 232 ++++++++++++++++----------------- src/qt/qt_settingsharddisks.ui | 2 +- 27 files changed, 199 insertions(+), 172 deletions(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 8292dc472..8a02173ce 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -407,14 +407,14 @@ hdd_zones_init(hard_disk_t *hdd) static hdd_preset_t hdd_speed_presets[] = { // clang-format off - { .name = "RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[1989] 3500 RPM", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[1992] 3600 RPM", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[1994] 4500 RPM", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 }, - { .name = "[1996] 5400 RPM", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[1997] 5400 RPM", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, - { .name = "[1998] 5400 RPM", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[2000] 7200 RPM", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[Generic] RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[Generic] 1989 (3500 RPM)", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[Generic] 1992 (3600 RPM)", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[Generic] 1994 (4500 RPM)", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 }, + { .name = "[Generic] 1996 (5400 RPM)", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[Generic] 1997 (5400 RPM)", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, + { .name = "[Generic] 1998 (5400 RPM)", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[Generic] 2000 (7200 RPM)", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, { .name = "[PIO IDE] IBM WDA-L42", .internal_name = "WDAL42", .model = "WDA-L42", .zones = 1, .avg_spt = 85, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 2.5, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 1 }, { .name = "[ATA-1] Conner CP3024", .internal_name = "CP3024", .model = "Conner Peripherals 20MB - CP3024", .zones = 1, .avg_spt = 33, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work { .name = "[ATA-1] Conner CP3044", .internal_name = "CP3044", .model = "Conner Peripherals 40MB - CP3044", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 066e98167..fde3f921c 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2058,7 +2058,28 @@ msgstr "" msgid "High performance impact" msgstr "" -msgid "RAM Disk (max. speed)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "" + +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" msgstr "" msgid "IBM 8514/A clone (ISA)" @@ -2088,5 +2109,8 @@ msgstr "" msgid "Inhibit multimedia keys" msgstr "" +msgid "Model:" +msgstr "" + msgid "Failed to initialize Vulkan renderer." msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 93ad884bd..f39be48ca 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Alt impact en el rendiment" -msgid "RAM Disk (max. speed)" -msgstr "Disc RAM (velocitat màxima)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disc RAM (velocitat màxima)" msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 9205839aa..34b5dfa6d 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Vysoký dopad na výkon" -msgid "RAM Disk (max. speed)" -msgstr "Disk RAM (max. rychlost)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disk RAM (max. rychlost)" msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index a90c29ac0..e69d496a7 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2061,8 +2061,8 @@ msgstr "Softfloat-FPU" msgid "High performance impact" msgstr "Hohe Auswirkung auf die Leistung" -msgid "RAM Disk (max. speed)" -msgstr "RAM-Diskette (maximale Geschwindigkeit)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM-Diskette (maximale Geschwindigkeit)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-Klon (ISA)" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 3b90772c0..1e9bc1c23 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -2057,8 +2057,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Alto impact en el rendimiento" -msgid "RAM Disk (max. speed)" -msgstr "Disco RAM (velocidad máxima)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disco RAM (velocidad máxima)" msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 6460ce286..d35e45b21 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -2061,8 +2061,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Suuri vaikutus suorituskykyyn" -msgid "RAM Disk (max. speed)" -msgstr "RAM-levy (maksiminopeus)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM-levy (maksiminopeus)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-klooni (ISA)" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index d83bd81a3..50de1f001 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Impact important sur la performance" -msgid "RAM Disk (max. speed)" -msgstr "Disque RAM (vitesse maximale)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disque RAM (vitesse maximale)" msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 1bc6d4d25..93c247319 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Visoki učinak na brzinu izvršavanja" -msgid "RAM Disk (max. speed)" -msgstr "Disk RAM (najviša brzina)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disk RAM (najviša brzina)" msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 23229893a..b92b9c11b 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Nagy hatással van a teljesítményre" -msgid "RAM Disk (max. speed)" -msgstr "RAM lemez (max. sebesség)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM lemez (max. sebesség)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A klón (ISA)" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 690af0a68..b85bb64bd 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Impatto elevato sulla prestazione" -msgid "RAM Disk (max. speed)" -msgstr "Disco RAM (velocità massima)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disco RAM (velocità massima)" msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 502ccda20..07c783dd1 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "パフォーマンスへの影響が大きい" -msgid "RAM Disk (max. speed)" -msgstr "RAMディスク(最高速度)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAMディスク(最高速度)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A クローン(ISA)" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index b149b62bb..cea372b7f 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -2058,8 +2058,8 @@ msgstr "소프트플로트 FPU" msgid "High performance impact" msgstr "성능에 미치는 영향" -msgid "RAM Disk (max. speed)" -msgstr "RAM 디스크(최대 속도)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM 디스크(최대 속도)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 클론(ISA)" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 0fe316550..97634842b 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Hoge prestatie-impact" -msgid "RAM Disk (max. speed)" -msgstr "RAM-schijf (max. snelheid)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM-schijf (max. snelheid)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-kloon (ISA)" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 81b9f9b04..980ee69f1 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Wysoki wpływ na wydajność" -msgid "RAM Disk (max. speed)" -msgstr "Dysk RAM (maks. prędkość)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Dysk RAM (maks. prędkość)" msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 0b1ab46e4..c48e7a07f 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Alto impacto no desempenho" -msgid "RAM Disk (max. speed)" -msgstr "Disco RAM (velocidade máxima)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disco RAM (velocidade máxima)" msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index c83ac3655..1900a42d9 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Elevado impacto no desempenho" -msgid "RAM Disk (max. speed)" -msgstr "Disco RAM (velocidade máxima)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disco RAM (velocidade máxima)" msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index b466c6624..afc4c72a4 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Сильное влияние на производительность" -msgid "RAM Disk (max. speed)" -msgstr "RAM-диск (макс. скорость)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Стандартный] RAM-диск (макс. скорость)" msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" @@ -2084,3 +2084,6 @@ msgstr "Невозможно найти матричные шрифты" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Шрифты TrueType в каталоге \"roms/printer/fonts\" необходимы для эмуляции стандартного матричного принтера ESC/P." + +msgid "Model:" +msgstr "Модель:" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index d70d14e56..f1a6144a6 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -2059,8 +2059,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Vysoký vplyv na výkon" -msgid "RAM Disk (max. speed)" -msgstr "Disk RAM (max. rýchlosť)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Disk RAM (max. rýchlosť)" msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 419d7dcc5..94c241dea 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Visok učinek na hitrost delovanja" -msgid "RAM Disk (max. speed)" -msgstr "Pogon RAM (največja hitrost)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Pogon RAM (največja hitrost)" msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index d134be6d0..1be214342 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Ciddi performans düşüklüğüne neden olabilir" -msgid "RAM Disk (max. speed)" -msgstr "RAM Disk (maks. hız)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM Disk (maks. hız)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A klonu (ISA)" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index d475fa201..6acb947cf 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -2058,8 +2058,8 @@ msgstr "FPU Softfloat" msgid "High performance impact" msgstr "Високий вплив на продуктивність" -msgid "RAM Disk (max. speed)" -msgstr "Диск оперативної пам'яті (макс. швидкість)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Диск оперативної пам'яті (макс. швидкість)" msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index b4c72ec26..c1d461fb7 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "Ảnh hưởng lớn đến hiệu suất" -msgid "RAM Disk (max. speed)" -msgstr "Đĩa RAM (tốc độ tối đa)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] Đĩa RAM (tốc độ tối đa)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A bản nhái (ISA)" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 8e5dd1a4b..0ce76cff9 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "重大性能影响" -msgid "RAM Disk (max. speed)" -msgstr "RAM 磁盘 (最大速度)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM 磁盘 (最大速度)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 克隆 (ISA)" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 584c18dc9..d50449aa2 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2058,8 +2058,8 @@ msgstr "Softfloat FPU" msgid "High performance impact" msgstr "對效能影響大" -msgid "RAM Disk (max. speed)" -msgstr "RAM 磁碟 (最大速度)" +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Generic] RAM 磁碟 (最大速度)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 克隆 (ISA)" diff --git a/src/qt/qt_harddiskdialog.ui b/src/qt/qt_harddiskdialog.ui index 91499d2cb..cba835134 100644 --- a/src/qt/qt_harddiskdialog.ui +++ b/src/qt/qt_harddiskdialog.ui @@ -32,27 +32,16 @@ Dialog - - - - - - - Channel: + + + + false - - - - - - Speed: + + 0 - - - - - - 30 + + true @@ -63,86 +52,34 @@ - - + + - Type: + Image Format: - - - - - 0 - 0 - - - - - 64 - 16777215 - - - - - - - - - 0 - 0 - - - - - 64 - 16777215 - - - - - - - - Size (MB): - - - - - + + 30 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + Bus: - - - - Qt::Vertical - - - - 20 - 20 - - - + + - - + + - Cylinders: + Type: @@ -165,10 +102,29 @@ - - - - Image Format: + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + 0 + 0 + + + + + 64 + 16777215 + @@ -179,31 +135,47 @@ - - + + + + + 0 + 0 + + + + + 64 + 16777215 + + + + + + 30 - - + + - Bus: + Cylinders: - - - - 30 + + + + File name: - - - - 30 + + + + Size (MB): @@ -226,37 +198,65 @@ - - + + + + Channel: + + + + + 30 - + Block Size: - - + + + + Qt::Vertical + + + + 20 + 20 + + + + + + - File name: + Model: - - - - false + + + + 30 - - 0 + + + + + + 30 - - true + + + + + + 30 diff --git a/src/qt/qt_settingsharddisks.ui b/src/qt/qt_settingsharddisks.ui index 3ae20fee1..ea69edc5b 100644 --- a/src/qt/qt_settingsharddisks.ui +++ b/src/qt/qt_settingsharddisks.ui @@ -78,7 +78,7 @@ - Speed: + Model: From bfec519a015839e9a901d9e11dfd23970ad2d2a0 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 06:36:18 +0500 Subject: [PATCH 0715/1190] nl-NL.po: Remove trailing whitespace --- src/qt/languages/nl-NL.po | 1376 ++++++++++++++++++------------------- 1 file changed, 688 insertions(+), 688 deletions(-) diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 97634842b..20c193afe 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -6,2071 +6,2071 @@ msgstr "" "X-Language: nl_NL\n" "X-Source-Language: en_US\n" -msgid "&Action" +msgid "&Action" msgstr "&Actie" -msgid "&Keyboard requires capture" +msgid "&Keyboard requires capture" msgstr "&Keyboard vereist vastleggen" -msgid "&Right CTRL is left ALT" +msgid "&Right CTRL is left ALT" msgstr "&Rechtse CTRL is linkse ALT" -msgid "&Hard Reset..." +msgid "&Hard Reset..." msgstr "&Harde Reset..." -msgid "&Ctrl+Alt+Del" +msgid "&Ctrl+Alt+Del" msgstr "&Ctrl+Alt+Del" -msgid "Ctrl+Alt+&Esc" +msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" -msgid "&Pause" +msgid "&Pause" msgstr "&Pauze" -msgid "E&xit..." +msgid "E&xit..." msgstr "&Afsluiten..." -msgid "&View" +msgid "&View" msgstr "&Beeld" -msgid "&Hide status bar" +msgid "&Hide status bar" msgstr "&Statusbalk verbergen" -msgid "Hide &toolbar" +msgid "Hide &toolbar" msgstr "Verberg &toolbar" -msgid "&Resizeable window" +msgid "&Resizeable window" msgstr "&Venster met aanpasbare grootte" -msgid "R&emember size && position" +msgid "R&emember size && position" msgstr "&Onthoud grootte && positie" -msgid "Re&nderer" +msgid "Re&nderer" msgstr "Re&nderer" -msgid "&Qt (Software)" +msgid "&Qt (Software)" msgstr "&Qt (software)" -msgid "Qt (&OpenGL)" +msgid "Qt (&OpenGL)" msgstr "Qt (&OpenGL)" -msgid "Open&GL (3.0 Core)" +msgid "Open&GL (3.0 Core)" msgstr "Open&GL (3.0 Core)" -msgid "&VNC" +msgid "&VNC" msgstr "&VNC" -msgid "Specify dimensions..." +msgid "Specify dimensions..." msgstr "Afmetingen opgeven..." -msgid "F&orce 4:3 display ratio" +msgid "F&orce 4:3 display ratio" msgstr "F&orceer 4:3 beeldverhouding" -msgid "&Window scale factor" +msgid "&Window scale factor" msgstr "&Venster schaalfactor" -msgid "&0.5x" +msgid "&0.5x" msgstr "&0,5x" -msgid "&1x" +msgid "&1x" msgstr "&1x" -msgid "1.&5x" +msgid "1.&5x" msgstr "1,&5x" -msgid "&2x" +msgid "&2x" msgstr "&2x" -msgid "&3x" +msgid "&3x" msgstr "&3x" -msgid "&4x" +msgid "&4x" msgstr "&4x" -msgid "&5x" +msgid "&5x" msgstr "&5x" -msgid "&6x" +msgid "&6x" msgstr "&6x" -msgid "&7x" +msgid "&7x" msgstr "&7x" -msgid "&8x" +msgid "&8x" msgstr "&8x" -msgid "Filter method" +msgid "Filter method" msgstr "Filtermethode" -msgid "&Nearest" +msgid "&Nearest" msgstr "&Dichtsbijzijnde" -msgid "&Linear" +msgid "&Linear" msgstr "&Lineair" -msgid "Hi&DPI scaling" +msgid "Hi&DPI scaling" msgstr "Hi&DPI-schaling" -msgid "&Fullscreen" +msgid "&Fullscreen" msgstr "&Fullscreen" -msgid "Fullscreen &stretch mode" +msgid "Fullscreen &stretch mode" msgstr "Volledig scherm &uitrekmodus" -msgid "&Full screen stretch" +msgid "&Full screen stretch" msgstr "&Volledig scherm uitrekken" -msgid "&4:3" +msgid "&4:3" msgstr "&4:3" -msgid "&Square pixels (Keep ratio)" +msgid "&Square pixels (Keep ratio)" msgstr "&Vierkante pixels (behoud verhouding)" -msgid "&Integer scale" +msgid "&Integer scale" msgstr "&Integerschaal" -msgid "4:&3 Integer scale" +msgid "4:&3 Integer scale" msgstr "4:&3 integerschaal" -msgid "E&GA/(S)VGA settings" +msgid "E&GA/(S)VGA settings" msgstr "E&GA/(S)VGA-instellingen" -msgid "&Inverted VGA monitor" +msgid "&Inverted VGA monitor" msgstr "Ge&ïnverteerde VGA-monitor" -msgid "VGA screen &type" +msgid "VGA screen &type" msgstr "VGA-scherm &type" -msgid "RGB &Color" +msgid "RGB &Color" msgstr "RGB &Kleur" -msgid "&RGB Grayscale" +msgid "&RGB Grayscale" msgstr "&RGB grijstinten" -msgid "&Amber monitor" +msgid "&Amber monitor" msgstr "&Amber monitor" -msgid "&Green monitor" +msgid "&Green monitor" msgstr "&Groene monitor" -msgid "&White monitor" +msgid "&White monitor" msgstr "&Witte monitor" -msgid "Grayscale &conversion type" +msgid "Grayscale &conversion type" msgstr "Grijstinten &conversietype" -msgid "BT&601 (NTSC/PAL)" +msgid "BT&601 (NTSC/PAL)" msgstr "BT&601 (NTSC/PAL)" -msgid "BT&709 (HDTV)" +msgid "BT&709 (HDTV)" msgstr "BT&709 (HDTV)" -msgid "&Average" +msgid "&Average" msgstr "&Gemiddelde" -msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" -msgid "Change contrast for &monochrome display" +msgid "Change contrast for &monochrome display" msgstr "Contrast wijzigen voor &monochroom beeldscherm" -msgid "&Media" +msgid "&Media" msgstr "&Media" -msgid "&Tools" +msgid "&Tools" msgstr "&Tools" -msgid "&Settings..." +msgid "&Settings..." msgstr "&Instellingen..." -msgid "&Update status bar icons" +msgid "&Update status bar icons" msgstr "&Statusbalkpictogrammen bijwerken" -msgid "Take s&creenshot" +msgid "Take s&creenshot" msgstr "Maak een schermafbeelding" -msgid "S&ound" +msgid "S&ound" msgstr "&Geluid" -msgid "&Preferences..." +msgid "&Preferences..." msgstr "&Voorkeuren..." -msgid "Enable &Discord integration" +msgid "Enable &Discord integration" msgstr "&Discord integratie inschakelen" -msgid "Sound &gain..." +msgid "Sound &gain..." msgstr "&Geluidsversterking..." -msgid "Begin trace" +msgid "Begin trace" msgstr "Begin traceren" -msgid "End trace" +msgid "End trace" msgstr "Traceren beëindigen" -msgid "&Help" +msgid "&Help" msgstr "&Help" -msgid "&Documentation..." +msgid "&Documentation..." msgstr "&Documentatie..." -msgid "&About 86Box..." +msgid "&About 86Box..." msgstr "&Over 86Box..." -msgid "&New image..." +msgid "&New image..." msgstr "&Nieuw image..." -msgid "&Existing image..." +msgid "&Existing image..." msgstr "&Bestaande image..." -msgid "Existing image (&Write-protected)..." +msgid "Existing image (&Write-protected)..." msgstr "Bestaande image (&Schrijfbeveiligd)..." -msgid "&Record" +msgid "&Record" msgstr "&Opnemen" -msgid "&Play" +msgid "&Play" msgstr "&Play" -msgid "&Rewind to the beginning" +msgid "&Rewind to the beginning" msgstr "&Terugspoelen naar het begin" -msgid "&Fast forward to the end" +msgid "&Fast forward to the end" msgstr "&Snel vooruit naar het einde" -msgid "E&ject" +msgid "E&ject" msgstr "&Uitwerpen" -msgid "&Image..." +msgid "&Image..." msgstr "&Image..." -msgid "E&xport to 86F..." +msgid "E&xport to 86F..." msgstr "E&xporteer naar 86F..." -msgid "&Mute" +msgid "&Mute" msgstr "&Mute" -msgid "E&mpty" +msgid "E&mpty" msgstr "E&mpty" -msgid "Reload previous image" +msgid "Reload previous image" msgstr "Herlaad vorige image" -msgid "&Folder..." +msgid "&Folder..." msgstr "&Map..." -msgid "Target &framerate" +msgid "Target &framerate" msgstr "Doel &framerate" -msgid "&Sync with video" +msgid "&Sync with video" msgstr "&Synchroniseer met video" -msgid "&25 fps" +msgid "&25 fps" msgstr "&25 fps" -msgid "&30 fps" +msgid "&30 fps" msgstr "&30 fps" -msgid "&50 fps" +msgid "&50 fps" msgstr "&50 fps" -msgid "&60 fps" +msgid "&60 fps" msgstr "&60 fps" -msgid "&75 fps" +msgid "&75 fps" msgstr "&75 fps" -msgid "&VSync" +msgid "&VSync" msgstr "&VSync" -msgid "&Select shader..." +msgid "&Select shader..." msgstr "&Selecteer shader..." -msgid "&Remove shader" +msgid "&Remove shader" msgstr "&Remove shader" -msgid "Preferences" +msgid "Preferences" msgstr "Voorkeuren" -msgid "Sound Gain" +msgid "Sound Gain" msgstr "Geluidsversterking" -msgid "New Image" +msgid "New Image" msgstr "Nieuw image" -msgid "Settings" +msgid "Settings" msgstr "Instellingen" -msgid "Specify Main Window Dimensions" +msgid "Specify Main Window Dimensions" msgstr "Afmetingen hoofdvenster opgeven" -msgid "OK" +msgid "OK" msgstr "OK" -msgid "Cancel" +msgid "Cancel" msgstr "Annuleren" -msgid "&Default" +msgid "&Default" msgstr "&Standaard" -msgid "Language:" +msgid "Language:" msgstr "Taal:" -msgid "Gain" +msgid "Gain" msgstr "Versterking" -msgid "File name:" +msgid "File name:" msgstr "Bestandsnaam:" -msgid "Disk size:" +msgid "Disk size:" msgstr "Schijfgrootte:" -msgid "RPM mode:" +msgid "RPM mode:" msgstr "RPM-modus:" -msgid "Progress:" +msgid "Progress:" msgstr "Vooruitgang:" -msgid "Width:" +msgid "Width:" msgstr "Breedte:" -msgid "Height:" +msgid "Height:" msgstr "Hoogte:" -msgid "Lock to this size" +msgid "Lock to this size" msgstr "Leg vast op deze grootte" -msgid "Machine type:" +msgid "Machine type:" msgstr "Machinetype:" -msgid "Machine:" +msgid "Machine:" msgstr "Machine:" -msgid "Configure" +msgid "Configure" msgstr "Configureren" -msgid "CPU type:" +msgid "CPU type:" msgstr "CPU type:" -msgid "Speed:" +msgid "Speed:" msgstr "Snelheid:" -msgid "Frequency:" +msgid "Frequency:" msgstr "Frequentie:" -msgid "FPU:" +msgid "FPU:" msgstr "FPU:" -msgid "Wait states:" +msgid "Wait states:" msgstr "Wachttoestanden:" -msgid "MB" +msgid "MB" msgstr "MB" -msgid "Memory:" +msgid "Memory:" msgstr "Geheugen:" -msgid "Time synchronization" +msgid "Time synchronization" msgstr "Tijdsynchronisatie" -msgid "Disabled" +msgid "Disabled" msgstr "Uitgeschakeld" -msgid "Enabled (local time)" +msgid "Enabled (local time)" msgstr "Ingeschakeld (lokale tijd)" -msgid "Enabled (UTC)" +msgid "Enabled (UTC)" msgstr "Ingeschakeld (UTC)" -msgid "Dynamic Recompiler" +msgid "Dynamic Recompiler" msgstr "Dynamische Recompiler" -msgid "Video:" +msgid "Video:" msgstr "Video:" -msgid "Video #2:" +msgid "Video #2:" msgstr "Video #2:" -msgid "Voodoo 1 or 2 Graphics" +msgid "Voodoo 1 or 2 Graphics" msgstr "Voodoo 1 of 2 graphics" -msgid "IBM 8514/A Graphics" +msgid "IBM 8514/A Graphics" msgstr "IBM 8514/A-graphics" -msgid "XGA Graphics" +msgid "XGA Graphics" msgstr "XGA Graphics" -msgid "Mouse:" +msgid "Mouse:" msgstr "Muis:" -msgid "Joystick:" +msgid "Joystick:" msgstr "Joystick:" -msgid "Joystick 1..." +msgid "Joystick 1..." msgstr "Joystick 1..." -msgid "Joystick 2..." +msgid "Joystick 2..." msgstr "Joystick 2..." -msgid "Joystick 3..." +msgid "Joystick 3..." msgstr "Joystick 3..." -msgid "Joystick 4..." +msgid "Joystick 4..." msgstr "Joystick 4..." -msgid "Sound card #1:" +msgid "Sound card #1:" msgstr "Geluidskaart #1:" -msgid "Sound card #2:" +msgid "Sound card #2:" msgstr "Geluidskaart #2:" -msgid "Sound card #3:" +msgid "Sound card #3:" msgstr "Geluidskaart #3:" -msgid "Sound card #4:" +msgid "Sound card #4:" msgstr "Geluidskaart #4:" -msgid "MIDI Out Device:" +msgid "MIDI Out Device:" msgstr "MIDI Out-apparaat:" -msgid "MIDI In Device:" +msgid "MIDI In Device:" msgstr "MIDI In-apparaat:" -msgid "Standalone MPU-401" +msgid "Standalone MPU-401" msgstr "Standalone MPU-401" -msgid "Use FLOAT32 sound" +msgid "Use FLOAT32 sound" msgstr "Gebruik FLOAT32-geluid" -msgid "FM synth driver" +msgid "FM synth driver" msgstr "FM-synthesizer" -msgid "Nuked (more accurate)" +msgid "Nuked (more accurate)" msgstr "Nuked (nauwkeuriger)" -msgid "YMFM (faster)" +msgid "YMFM (faster)" msgstr "YMFM (sneller)" -msgid "Network type:" +msgid "Network type:" msgstr "Type netwerk:" -msgid "PCap device:" +msgid "PCap device:" msgstr "PCap-apparaat:" -msgid "Network adapter:" +msgid "Network adapter:" msgstr "Netwerkadapter:" -msgid "COM1 Device:" +msgid "COM1 Device:" msgstr "COM1-apparaat:" -msgid "COM2 Device:" +msgid "COM2 Device:" msgstr "COM2-apparaat:" -msgid "COM3 Device:" +msgid "COM3 Device:" msgstr "COM3-apparaat:" -msgid "COM4 Device:" +msgid "COM4 Device:" msgstr "COM4-apparaat:" -msgid "LPT1 Device:" +msgid "LPT1 Device:" msgstr "LPT1-apparaat:" -msgid "LPT2 Device:" +msgid "LPT2 Device:" msgstr "LPT2-apparaat:" -msgid "LPT3 Device:" +msgid "LPT3 Device:" msgstr "LPT3-apparaat:" -msgid "LPT4 Device:" +msgid "LPT4 Device:" msgstr "LPT4-apparaat:" -msgid "Serial port 1" +msgid "Serial port 1" msgstr "Seriële poort 1" -msgid "Serial port 2" +msgid "Serial port 2" msgstr "Seriële poort 2" -msgid "Serial port 3" +msgid "Serial port 3" msgstr "Seriële poort 3" -msgid "Serial port 4" +msgid "Serial port 4" msgstr "Seriële poort 4" -msgid "Parallel port 1" +msgid "Parallel port 1" msgstr "Parallelle poort 1" -msgid "Parallel port 2" +msgid "Parallel port 2" msgstr "Parallelle poort 2" -msgid "Parallel port 3" +msgid "Parallel port 3" msgstr "Parallelle poort 3" -msgid "Parallel port 4" +msgid "Parallel port 4" msgstr "Parallelle poort 4" -msgid "HD Controller:" +msgid "HD Controller:" msgstr "HD-controller:" -msgid "FD Controller:" +msgid "FD Controller:" msgstr "FD-Controller:" -msgid "Tertiary IDE Controller" +msgid "Tertiary IDE Controller" msgstr "Tertiaire IDE-controller" -msgid "Quaternary IDE Controller" +msgid "Quaternary IDE Controller" msgstr "Quaternaire IDE-controller" -msgid "SCSI" +msgid "SCSI" msgstr "SCSI" -msgid "Controller 1:" +msgid "Controller 1:" msgstr "Controller 1:" -msgid "Controller 2:" +msgid "Controller 2:" msgstr "Controller 2:" -msgid "Controller 3:" +msgid "Controller 3:" msgstr "Controller 3:" -msgid "Controller 4:" +msgid "Controller 4:" msgstr "Controller 4:" -msgid "Cassette" +msgid "Cassette" msgstr "Cassette" -msgid "Hard disks:" +msgid "Hard disks:" msgstr "Harde schijven:" -msgid "&New..." +msgid "&New..." msgstr "&Nieuw..." -msgid "&Existing..." +msgid "&Existing..." msgstr "&Bestaande..." -msgid "&Remove" +msgid "&Remove" msgstr "&Verwijderen" -msgid "Bus:" +msgid "Bus:" msgstr "Bus:" -msgid "Channel:" +msgid "Channel:" msgstr "Kanaal:" -msgid "ID:" +msgid "ID:" msgstr "ID:" -msgid "&Specify..." +msgid "&Specify..." msgstr "&Specificeer..." -msgid "Sectors:" +msgid "Sectors:" msgstr "Sectoren:" -msgid "Heads:" +msgid "Heads:" msgstr "Heads:" -msgid "Cylinders:" +msgid "Cylinders:" msgstr "Cilinders:" -msgid "Size (MB):" +msgid "Size (MB):" msgstr "Grootte (MB):" -msgid "Type:" +msgid "Type:" msgstr "Type:" -msgid "Image Format:" +msgid "Image Format:" msgstr "Imageformaat:" -msgid "Block Size:" +msgid "Block Size:" msgstr "Blokgrootte:" -msgid "Floppy drives:" +msgid "Floppy drives:" msgstr "Floppy-schijfstations:" -msgid "Turbo timings" +msgid "Turbo timings" msgstr "Turbo timings" -msgid "Check BPB" +msgid "Check BPB" msgstr "Controleer BPB" -msgid "CD-ROM drives:" +msgid "CD-ROM drives:" msgstr "CD-ROM-stations:" -msgid "MO drives:" +msgid "MO drives:" msgstr "MO-schijven:" -msgid "ZIP drives:" +msgid "ZIP drives:" msgstr "ZIP-schijven:" -msgid "ZIP 250" +msgid "ZIP 250" msgstr "ZIP 250" -msgid "ISA RTC:" +msgid "ISA RTC:" msgstr "ISA RTC:" -msgid "ISA Memory Expansion" +msgid "ISA Memory Expansion" msgstr "ISA-geheugenuitbreiding" -msgid "Card 1:" +msgid "Card 1:" msgstr "Kaart 1:" -msgid "Card 2:" +msgid "Card 2:" msgstr "Kaart 2:" -msgid "Card 3:" +msgid "Card 3:" msgstr "Kaart 3:" -msgid "Card 4:" +msgid "Card 4:" msgstr "Kaart 4:" -msgid "ISABugger device" +msgid "ISABugger device" msgstr "ISABugger-apparaat" -msgid "POST card" +msgid "POST card" msgstr "POST-kaart" -msgid "86Box" +msgid "86Box" msgstr "86Box" -msgid "Error" +msgid "Error" msgstr "Fout" -msgid "Fatal error" +msgid "Fatal error" msgstr "Fatale fout" -msgid " - PAUSED" +msgid " - PAUSED" msgstr " - GEPAUZEERD" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." msgstr "Druk op Ctrl+Alt+PgDn om terug te gaan naar de venstermodus." -msgid "Speed" +msgid "Speed" msgstr "Snelheid" -msgid "ZIP %1 %2 (%3): %4" +msgid "ZIP %1 %2 (%3): %4" msgstr "ZIP %1 %2 (%3): %4" -msgid "ZIP images" +msgid "ZIP images" msgstr "ZIP-images" -msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." msgstr "86Box kon geen bruikbare ROM images vinden.\n\nDownload een ROM set en pak deze uit in de map \"roms\"." -msgid "(empty)" +msgid "(empty)" msgstr "(leeg)" -msgid "All files" +msgid "All files" msgstr "Alle bestanden" -msgid "Turbo" +msgid "Turbo" msgstr "Turbo" -msgid "On" +msgid "On" msgstr "Aan" -msgid "Off" +msgid "Off" msgstr "Uit" -msgid "All images" +msgid "All images" msgstr "Alle schijfimages" -msgid "Basic sector images" +msgid "Basic sector images" msgstr "Basissectorimages" -msgid "Surface images" +msgid "Surface images" msgstr "Oppervlakte-images" -msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." msgstr "Machine \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/machines. Overschakelen naar een beschikbare machine." -msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." msgstr "Videokaart \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Overschakel over naar een beschikbare videokaart." -msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." msgstr "Videokaart #2 \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Uitschakel de tweede videokaart." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." msgstr "Het apparaat \"%hs\" is niet beschikbaar door ontbrekende ROMs. Negeer het apparaat." -msgid "Machine" +msgid "Machine" msgstr "Machine" -msgid "Display" +msgid "Display" msgstr "Scherm" -msgid "Input devices" +msgid "Input devices" msgstr "Invoerapparaten" -msgid "Sound" +msgid "Sound" msgstr "Geluid" -msgid "Network" +msgid "Network" msgstr "Netwerk" -msgid "Ports (COM & LPT)" +msgid "Ports (COM & LPT)" msgstr "Poorten (COM & LPT)" -msgid "Storage controllers" +msgid "Storage controllers" msgstr "Opslagcontrollers" -msgid "Hard disks" +msgid "Hard disks" msgstr "Harde schijven" -msgid "Floppy & CD-ROM drives" +msgid "Floppy & CD-ROM drives" msgstr "Floppy- en CD-ROM-stations" -msgid "Other removable devices" +msgid "Other removable devices" msgstr "Andere verwijderbare apparaten" -msgid "Other peripherals" +msgid "Other peripherals" msgstr "Andere randapparatuur" -msgid "Click to capture mouse" +msgid "Click to capture mouse" msgstr "Klik om muis vast te leggen" -msgid "Press %1 to release mouse" +msgid "Press %1 to release mouse" msgstr "Druk op %1 om de muis los te laten" -msgid "Press %1 or middle button to release mouse" +msgid "Press %1 or middle button to release mouse" msgstr "Druk op %1 of middelste knop om de muis los te laten" -msgid "Bus" +msgid "Bus" msgstr "Bus" -msgid "File" +msgid "File" msgstr "Bestand" -msgid "C" +msgid "C" msgstr "C" -msgid "H" +msgid "H" msgstr "H" -msgid "S" +msgid "S" msgstr "S" -msgid "KB" +msgid "KB" msgstr "KB" -msgid "Default" +msgid "Default" msgstr "Standaard" -msgid "%1 Wait state(s)" +msgid "%1 Wait state(s)" msgstr "%1 Wachttoestand(en)" -msgid "Type" +msgid "Type" msgstr "Type" -msgid "No PCap devices found" +msgid "No PCap devices found" msgstr "Geen PCap-apparaten gevonden" -msgid "Invalid PCap device" +msgid "Invalid PCap device" msgstr "Ongeldig PCap-apparaat" -msgid "2-axis, 2-button joystick(s)" +msgid "2-axis, 2-button joystick(s)" msgstr "Joystick(s) met 2 assen en 2 knoppen" -msgid "2-axis, 4-button joystick" +msgid "2-axis, 4-button joystick" msgstr "Joystick met 2 assen en 4 knoppen" -msgid "2-axis, 6-button joystick" +msgid "2-axis, 6-button joystick" msgstr "Joystick met 2 assen en 6 knoppen" -msgid "2-axis, 8-button joystick" +msgid "2-axis, 8-button joystick" msgstr "Joystick met 2 assen en 8 knoppen" -msgid "3-axis, 2-button joystick" +msgid "3-axis, 2-button joystick" msgstr "Joystick met 3 assen en 2 knoppen" -msgid "3-axis, 4-button joystick" +msgid "3-axis, 4-button joystick" msgstr "Joystick met 3 assen en 4 knoppen" -msgid "4-axis, 4-button joystick" +msgid "4-axis, 4-button joystick" msgstr "Joystick met 4 assen en 4 knoppen" -msgid "CH Flightstick Pro" +msgid "CH Flightstick Pro" msgstr "CH Flightstick Pro" -msgid "Microsoft SideWinder Pad" +msgid "Microsoft SideWinder Pad" msgstr "Microsoft SideWinder Pad" -msgid "Thrustmaster Flight Control System" +msgid "Thrustmaster Flight Control System" msgstr "Thrustmaster Flight Control systeem" -msgid "None" +msgid "None" msgstr "Geen" -msgid "%1 MB (CHS: %2, %3, %4)" +msgid "%1 MB (CHS: %2, %3, %4)" msgstr "%1 MB (CHS: %2, %3, %4)" -msgid "Floppy %1 (%2): %3" +msgid "Floppy %1 (%2): %3" msgstr "Floppy %1 (%2): %3" -msgid "Advanced sector images" +msgid "Advanced sector images" msgstr "Geavanceerde sector-images" -msgid "Flux images" +msgid "Flux images" msgstr "Flux images" -msgid "Are you sure you want to hard reset the emulated machine?" +msgid "Are you sure you want to hard reset the emulated machine?" msgstr "Weet je zeker dat je de geëmuleerde machine wilt resetten?" -msgid "Are you sure you want to exit 86Box?" +msgid "Are you sure you want to exit 86Box?" msgstr "Weet je zeker dat je 86Box wilt verlaten?" -msgid "Unable to initialize Ghostscript" +msgid "Unable to initialize Ghostscript" msgstr "Kan Ghostscript niet initialiseren" -msgid "Unable to initialize GhostPCL" +msgid "Unable to initialize GhostPCL" msgstr "Kan GhostPCL niet initialiseren" -msgid "MO %1 (%2): %3" +msgid "MO %1 (%2): %3" msgstr "MO %1 (%2): %3" -msgid "MO images" +msgid "MO images" msgstr "MO-images" -msgid "Welcome to 86Box!" +msgid "Welcome to 86Box!" msgstr "Welkom bij 86Box!" -msgid "Internal device" +msgid "Internal device" msgstr "Intern apparaat" -msgid "Exit" +msgid "Exit" msgstr "&Afsluiten" -msgid "No ROMs found" +msgid "No ROMs found" msgstr "Geen ROMs gevonden" -msgid "Do you want to save the settings?" +msgid "Do you want to save the settings?" msgstr "Wil je de instellingen opslaan?" -msgid "This will hard reset the emulated machine." +msgid "This will hard reset the emulated machine." msgstr "Dit zal de geëmuleerde machine een hard reset geven." -msgid "Save" +msgid "Save" msgstr "Opslaan" -msgid "About 86Box" +msgid "About 86Box" msgstr "Over 86Box" -msgid "86Box v" +msgid "86Box v" msgstr "86Box v" -msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." msgstr "Een emulator van oude computers\n\nAuteurs: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nMet eerdere bijdragen van Sarah Walker, leilei, JohnElliott, greatpsycho en anderen.\n\nUitgebracht onder de GNU General Public License versie 2 of later. Zie LICENSE voor meer informatie." -msgid "Hardware not available" +msgid "Hardware not available" msgstr "Hardware niet beschikbaar" -msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." +msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." msgstr "Zorg ervoor dat %1 is geïnstalleerd en dat je een %1-compatibele netwerkverbinding hebt." -msgid "Invalid configuration" +msgid "Invalid configuration" msgstr "Ongeldige configuratie" -msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." msgstr "%1 is vereist voor automatische conversie van PostScript-bestanden naar PDF.\n\nAlle documenten die naar de generieke PostScript-printer worden gestuurd, worden opgeslagen als PostScript-bestanden (.ps)." -msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." +msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 is vereist voor automatische conversie van PCL-bestanden naar PDF.\n\nAlle documenten die naar de generieke PCL-printer worden gestuurd, worden opgeslagen als Printer Command Language (.pcl) bestanden." -msgid "Entering fullscreen mode" +msgid "Entering fullscreen mode" msgstr "Volledig scherm modus openen" -msgid "Don't show this message again" +msgid "Don't show this message again" msgstr "Dit bericht niet meer tonen" -msgid "Don't exit" +msgid "Don't exit" msgstr "Niet afsluiten" -msgid "Reset" +msgid "Reset" msgstr "Reset" -msgid "Don't reset" +msgid "Don't reset" msgstr "Niet resetten" -msgid "CD-ROM images" +msgid "CD-ROM images" msgstr "CD-ROM-images" -msgid "%1 Device Configuration" +msgid "%1 Device Configuration" msgstr "%1 Apparaatconfiguratie" -msgid "Monitor in sleep mode" +msgid "Monitor in sleep mode" msgstr "Monitor in slaapstand" -msgid "GLSL shaders" +msgid "GLSL shaders" msgstr "GLSL Shaders" -msgid "You are loading an unsupported configuration" +msgid "You are loading an unsupported configuration" msgstr "U laadt een configuratie die niet wordt ondersteund" -msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." msgstr "Filteren op CPU type voor de geselecteerde machine is niet mogelijk met de geselecteerde machine.\n\nDit maakt het mogelijk een CPU te kunnen kiezen die anders niet compatible zou zijn met de geselecteerde machine. Je kunt hiermee echter compatibiliteitsproblemen krijgen met de BIOS van de machine of met andere software.\n\nHet inschakelen van deze instelling wordt niet officieel ondersteund en bugrapporten die worden ingediend kunnen als ongeldig worden gesloten." -msgid "Continue" +msgid "Continue" msgstr "Doorgaan" -msgid "Cassette: %1" +msgid "Cassette: %1" msgstr "Cassette: %1" -msgid "Cassette images" +msgid "Cassette images" msgstr "Cassette-images" -msgid "Cartridge %1: %2" +msgid "Cartridge %1: %2" msgstr "Cartridge %1: %2" -msgid "Cartridge images" +msgid "Cartridge images" msgstr "Cartridge-images" -msgid "Resume execution" +msgid "Resume execution" msgstr "Hervat executie" -msgid "Pause execution" +msgid "Pause execution" msgstr "Pauze executie" -msgid "Press Ctrl+Alt+Del" +msgid "Press Ctrl+Alt+Del" msgstr "Druk op Ctrl+Alt+Del" -msgid "Press Ctrl+Alt+Esc" +msgid "Press Ctrl+Alt+Esc" msgstr "Druk op Ctrl+Alt+Esc" -msgid "Hard reset" +msgid "Hard reset" msgstr "Harde reset" -msgid "ACPI shutdown" +msgid "ACPI shutdown" msgstr "ACPI uitschakeling" -msgid "Hard disk (%1)" +msgid "Hard disk (%1)" msgstr "Harde schijf (%1)" -msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL of ESDI CD-ROM-stations hebben nooit bestaan" -msgid "Custom..." +msgid "Custom..." msgstr "Aangepast..." -msgid "Custom (large)..." +msgid "Custom (large)..." msgstr "Aangepast (groot)..." -msgid "Add New Hard Disk" +msgid "Add New Hard Disk" msgstr "Nieuwe harde schijf toevoegen" -msgid "Add Existing Hard Disk" +msgid "Add Existing Hard Disk" msgstr "Bestaande harde schijf toevoegen" -msgid "HDI disk images cannot be larger than 4 GB." +msgid "HDI disk images cannot be larger than 4 GB." msgstr "HDI-schijfimages kunnen niet groter zijn dan 4 GB." -msgid "Disk images cannot be larger than 127 GB." +msgid "Disk images cannot be larger than 127 GB." msgstr "Schijfimages kunnen niet groter zijn dan 127 GB." -msgid "Hard disk images" +msgid "Hard disk images" msgstr "Harde schijf-image" -msgid "Unable to read file" +msgid "Unable to read file" msgstr "Kan bestand niet lezen" -msgid "Unable to write file" +msgid "Unable to write file" msgstr "Kan bestand niet schrijven" -msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgid "HDI or HDX images with a sector size other than 512 are not supported." msgstr "HDI- of HDX-image met een andere sectorgrootte dan 512 worden niet ondersteund." -msgid "Disk image file already exists" +msgid "Disk image file already exists" msgstr "Schijfimagebestand bestaat al" -msgid "Please specify a valid file name." +msgid "Please specify a valid file name." msgstr "Geef een geldige bestandsnaam op." -msgid "Disk image created" +msgid "Disk image created" msgstr "Schijfimage gemaakt" -msgid "Make sure the file exists and is readable." +msgid "Make sure the file exists and is readable." msgstr "Controleer of het bestand bestaat en leesbaar is." -msgid "Make sure the file is being saved to a writable directory." +msgid "Make sure the file is being saved to a writable directory." msgstr "Zorg ervoor dat het bestand wordt opgeslagen in een schrijfbare map." -msgid "Disk image too large" +msgid "Disk image too large" msgstr "Schijfimage te groot" -msgid "Remember to partition and format the newly-created drive." +msgid "Remember to partition and format the newly-created drive." msgstr "Vergeet niet om de nieuw aangemaakte schijf te partitioneren en te formatteren." -msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgid "The selected file will be overwritten. Are you sure you want to use it?" msgstr "Het geselecteerde bestand wordt overschreven. Weet u zeker dat u het wilt gebruiken?" -msgid "Unsupported disk image" +msgid "Unsupported disk image" msgstr "Niet-ondersteunde schijfimage" -msgid "Overwrite" +msgid "Overwrite" msgstr "Overschrijven" -msgid "Don't overwrite" +msgid "Don't overwrite" msgstr "Niet overschrijven" -msgid "Raw image" +msgid "Raw image" msgstr "Ruw image" -msgid "HDI image" +msgid "HDI image" msgstr "HDI-image" -msgid "HDX image" +msgid "HDX image" msgstr "HDX-image" -msgid "Fixed-size VHD" +msgid "Fixed-size VHD" msgstr "VHD met vaste grootte" -msgid "Dynamic-size VHD" +msgid "Dynamic-size VHD" msgstr "VHD met dynamisch grootte" -msgid "Differencing VHD" +msgid "Differencing VHD" msgstr "Verschil-VHD" -msgid "(N/A)" +msgid "(N/A)" msgstr "(N/A)" -msgid "Raw image (.img)" +msgid "Raw image (.img)" msgstr "Ruw image (.img)" -msgid "HDI image (.hdi)" +msgid "HDI image (.hdi)" msgstr "HDI-image (.hdi)" -msgid "HDX image (.hdx)" +msgid "HDX image (.hdx)" msgstr "HDX-image (.hdx)" -msgid "Fixed-size VHD (.vhd)" +msgid "Fixed-size VHD (.vhd)" msgstr "VHD met vaste grootte (.vhd)" -msgid "Dynamic-size VHD (.vhd)" +msgid "Dynamic-size VHD (.vhd)" msgstr "VHD met dynamisch grootte (.vhd)" -msgid "Differencing VHD (.vhd)" +msgid "Differencing VHD (.vhd)" msgstr "Verschil-VHD (.vhd)" -msgid "Large blocks (2 MB)" +msgid "Large blocks (2 MB)" msgstr "Grote blokken (2 MB)" -msgid "Small blocks (512 KB)" +msgid "Small blocks (512 KB)" msgstr "Kleine blokken (512 KB)" -msgid "VHD files" +msgid "VHD files" msgstr "VHD-bestanden" -msgid "Select the parent VHD" +msgid "Select the parent VHD" msgstr "Selecteer de bovenliggende VHD" -msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" msgstr "Dit kan betekenen dat de bovenliggende image is gewijzigd nadat de verschil-image is gemaakt.\n\nDit kan ook gebeuren als de imagebestanden zijn verplaatst of gekopieerd, of door een fout in het programma waarmee deze schijf is gemaakt.\n\nWil je de tijdstempels herstellen?" -msgid "Parent and child disk timestamps do not match" +msgid "Parent and child disk timestamps do not match" msgstr "Bovenliggende en onderliggende schijf tijdstempels komen niet overeen" -msgid "Could not fix VHD timestamp." +msgid "Could not fix VHD timestamp." msgstr "Kan VHD tijdstempel niet herstellen." -msgid "MFM/RLL" +msgid "MFM/RLL" msgstr "MFM/RLL" -msgid "XTA" +msgid "XTA" msgstr "XTA" -msgid "ESDI" +msgid "ESDI" msgstr "ESDI" -msgid "IDE" +msgid "IDE" msgstr "IDE" -msgid "ATAPI" +msgid "ATAPI" msgstr "ATAPI" -msgid "CD-ROM %1 (%2): %3" +msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" -msgid "160 KB" +msgid "160 KB" msgstr "160 KB" -msgid "180 KB" +msgid "180 KB" msgstr "180 KB" -msgid "320 KB" +msgid "320 KB" msgstr "320 KB" -msgid "360 KB" +msgid "360 KB" msgstr "360 KB" -msgid "640 KB" +msgid "640 KB" msgstr "640 KB" -msgid "720 KB" +msgid "720 KB" msgstr "720 KB" -msgid "1.2 MB" +msgid "1.2 MB" msgstr "1,2 MB" -msgid "1.25 MB" +msgid "1.25 MB" msgstr "1,25 MB" -msgid "1.44 MB" +msgid "1.44 MB" msgstr "1,44 MB" -msgid "DMF (cluster 1024)" +msgid "DMF (cluster 1024)" msgstr "DMF (cluster 1024)" -msgid "DMF (cluster 2048)" +msgid "DMF (cluster 2048)" msgstr "DMF (cluster 2048)" -msgid "2.88 MB" +msgid "2.88 MB" msgstr "2,88 MB" -msgid "ZIP 100" +msgid "ZIP 100" msgstr "ZIP 100" -msgid "3.5\" 128 MB (ISO 10090)" +msgid "3.5\" 128 MB (ISO 10090)" msgstr "3,5\" 128 MB (ISO 10090)" -msgid "3.5\" 230 MB (ISO 13963)" +msgid "3.5\" 230 MB (ISO 13963)" msgstr "3,5\" 230 MB (ISO 13963)" -msgid "3.5\" 540 MB (ISO 15498)" +msgid "3.5\" 540 MB (ISO 15498)" msgstr "3,5\" 540 MB (ISO 15498)" -msgid "3.5\" 640 MB (ISO 15498)" +msgid "3.5\" 640 MB (ISO 15498)" msgstr "3,5\" 640 MB (ISO 15498)" -msgid "3.5\" 1.3 GB (GigaMO)" +msgid "3.5\" 1.3 GB (GigaMO)" msgstr "3,5\" 1,3 GB (GigaMO)" -msgid "3.5\" 2.3 GB (GigaMO 2)" +msgid "3.5\" 2.3 GB (GigaMO 2)" msgstr "3,5\" 2,3 GB (GigaMO 2)" -msgid "5.25\" 600 MB" +msgid "5.25\" 600 MB" msgstr "5,25\" 600 MB" -msgid "5.25\" 650 MB" +msgid "5.25\" 650 MB" msgstr "5,25\" 650 MB" -msgid "5.25\" 1 GB" +msgid "5.25\" 1 GB" msgstr "5,25\" 1 GB" -msgid "5.25\" 1.3 GB" +msgid "5.25\" 1.3 GB" msgstr "5,25\" 1,3 GB" -msgid "Perfect RPM" +msgid "Perfect RPM" msgstr "Perfecte RPM" -msgid "1% below perfect RPM" +msgid "1% below perfect RPM" msgstr "1% onder perfecte RPM" -msgid "1.5% below perfect RPM" +msgid "1.5% below perfect RPM" msgstr "1,5% onder perfecte RPM" -msgid "2% below perfect RPM" +msgid "2% below perfect RPM" msgstr "2% onder perfecte RPM" -msgid "(System Default)" +msgid "(System Default)" msgstr "(Systeemstandaard)" -msgid "Failed to initialize network driver" +msgid "Failed to initialize network driver" msgstr "Netwerkstuurprogramma niet geïnitialiseerd" -msgid "The network configuration will be switched to the null driver" +msgid "The network configuration will be switched to the null driver" msgstr "De netwerkconfiguratie wordt overgeschakeld naar de nul-driver" -msgid "Mouse sensitivity:" +msgid "Mouse sensitivity:" msgstr "Muisgevoeligheid:" -msgid "Select media images from program working directory" +msgid "Select media images from program working directory" msgstr "Selecteer media-images uit de werkmap van het programma" -msgid "PIT mode:" +msgid "PIT mode:" msgstr "PIT-modus:" -msgid "Auto" +msgid "Auto" msgstr "Auto" -msgid "Slow" +msgid "Slow" msgstr "Langzaam" -msgid "Fast" +msgid "Fast" msgstr "Snel" -msgid "&Auto-pause on focus loss" +msgid "&Auto-pause on focus loss" msgstr "&Autopauze bij focusverlies" -msgid "WinBox is no longer supported" +msgid "WinBox is no longer supported" msgstr "WinBox wordt niet langer ondersteund" -msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgstr "De ontwikkeling van de WinBox manager is gestopt in 2022 door een gebrek aan beheerders. Omdat we onze inspanningen richten op het nog beter maken van 86Box, hebben we de beslissing genomen om WinBox niet langer te ondersteunen als een manager.\n\nEr zullen geen verdere updates worden geleverd door WinBox. Je kunt onjuist gedrag tegenkomen als je het blijft gebruiken met nieuwere versies van 86Box. Alle bugrapporten gerelateerd aan het gedrag van WinBox zullen worden gesloten als ongeldig.\n\nGa naar 86box.net voor een lijst van andere managers die je kunt gebruiken." -msgid "Generate" +msgid "Generate" msgstr "Genereren" -msgid "Joystick configuration" +msgid "Joystick configuration" msgstr "Joystick configuratie " -msgid "Device" +msgid "Device" msgstr "Apparaat" -msgid "%1 (X axis)" +msgid "%1 (X axis)" msgstr "%1 (X-as)" -msgid "%1 (Y axis)" +msgid "%1 (Y axis)" msgstr "%1 (Y-as)" -msgid "MCA devices" +msgid "MCA devices" msgstr "MCA-apparaten" -msgid "List of MCA devices:" +msgid "List of MCA devices:" msgstr "Lijst van MCA-apparaten:" -msgid "Tablet tool" +msgid "Tablet tool" msgstr "Tablet-hulpmiddel" -msgid "Qt (OpenGL &ES)" +msgid "Qt (OpenGL &ES)" msgstr "Qt (OpenGL &ES)" -msgid "About Qt" +msgid "About Qt" msgstr "Over Qt" -msgid "MCA devices..." +msgid "MCA devices..." msgstr "MCA-apparaten..." -msgid "Show non-primary monitors" +msgid "Show non-primary monitors" msgstr "Toon niet-primaire monitors" -msgid "Open screenshots folder..." +msgid "Open screenshots folder..." msgstr "Map met schermafbeeldingen openen..." -msgid "Apply fullscreen stretch mode when maximized" +msgid "Apply fullscreen stretch mode when maximized" msgstr "Pas fullscreen stretchmodus toe wanneer gemaximaliseerd" -msgid "Cursor/Puck" +msgid "Cursor/Puck" msgstr "Cursor/Puck" -msgid "Pen" +msgid "Pen" msgstr "Pen" -msgid "Host CD/DVD Drive (%1:)" +msgid "Host CD/DVD Drive (%1:)" msgstr "Host cd/dvd-station (%1:)" -msgid "&Connected" +msgid "&Connected" msgstr "&Verbonden" -msgid "Clear image history" +msgid "Clear image history" msgstr "Imagegeschiedenis verwijderen" -msgid "Create..." +msgid "Create..." msgstr "Creëer..." -msgid "Host CD/DVD Drive (%1)" +msgid "Host CD/DVD Drive (%1)" msgstr "Host CD/DVD-station (%1)" -msgid "Unknown Bus" +msgid "Unknown Bus" msgstr "Onbekende bus" -msgid "Null Driver" +msgid "Null Driver" msgstr "Null Driver" -msgid "NIC %1 (%2) %3" +msgid "NIC %1 (%2) %3" msgstr "NIC %1 (%2) %3" -msgid "Render behavior" +msgid "Render behavior" msgstr "Rendergedrag" -msgid "Use target framerate:" +msgid "Use target framerate:" msgstr "Gebruik doelframerate:" -msgid " fps" +msgid " fps" msgstr " fps" -msgid "VSync" +msgid "VSync" msgstr "VSync" -msgid "Synchronize with video" +msgid "Synchronize with video" msgstr "Synchroniseren met video" -msgid "Shaders" +msgid "Shaders" msgstr "Shaders" -msgid "Remove" +msgid "Remove" msgstr "Verwijderen" -msgid "Browse..." +msgid "Browse..." msgstr "Bladeren..." -msgid "Couldn't create OpenGL context." +msgid "Couldn't create OpenGL context." msgstr "Kan OpenGL context niet maken." -msgid "Couldn't switch to OpenGL context." +msgid "Couldn't switch to OpenGL context." msgstr "Kan niet overschakelen naar OpenGL context." -msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" +msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" msgstr "OpenGL versie 3.0 of hoger is vereist. De huidige versie is %1.%2" -msgid "Error initializing OpenGL" +msgid "Error initializing OpenGL" msgstr "Fout bij het initialiseren van OpenGL" -msgid "\nFalling back to software rendering." +msgid "\nFalling back to software rendering." msgstr "\nTerugvallen op software rendering." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" +msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Bij het selecteren van media-images (CD-ROM, floppy, etc.) zal de \"open dialoog\" starten in dezelfde map als het 86Box configuratiebestand. Deze instelling is doet er waarschijnlijk alleen toe op macOS.</p></body></html>" -msgid "This machine might have been moved or copied." +msgid "This machine might have been moved or copied." msgstr "Deze machine is misschien verplaatst of gekopieerd." -msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." +msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." msgstr "Om een goede netwerkfunctionaliteit te garanderen, moet 86Box weten of deze machine verplaatst of gekopieerd is.\n\nSelecteer \"Ik heb het gekopieerd\" als u het niet zeker weet." -msgid "I Moved It" +msgid "I Moved It" msgstr "Ik heb het verplaatst" -msgid "I Copied It" +msgid "I Copied It" msgstr "Ik heb het gekopieerd" -msgid "86Box Monitor #" +msgid "86Box Monitor #" msgstr "86Box Monitor #" -msgid "No MCA devices." +msgid "No MCA devices." msgstr "Geen MCA-apparaten." -msgid "MiB" +msgid "MiB" msgstr "MiB" -msgid "Network Card #1" +msgid "Network Card #1" msgstr "Netwerkkaart #1" -msgid "Network Card #2" +msgid "Network Card #2" msgstr "Netwerkkaart #2" -msgid "Network Card #3" +msgid "Network Card #3" msgstr "Netwerkkaart #3" -msgid "Network Card #4" +msgid "Network Card #4" msgstr "Netwerkkaart #4" -msgid "Mode" +msgid "Mode" msgstr "Modus" -msgid "Interface" +msgid "Interface" msgstr "Interface" -msgid "Adapter" +msgid "Adapter" msgstr "Adapter" -msgid "VDE Socket" +msgid "VDE Socket" msgstr "VDE-socket" -msgid "86Box Unit Tester" +msgid "86Box Unit Tester" msgstr "86Box apparaattester" -msgid "Novell NetWare 2.x Key Card" +msgid "Novell NetWare 2.x Key Card" msgstr "Novell NetWare 2.x Key Card" -msgid "Serial port passthrough 1" +msgid "Serial port passthrough 1" msgstr "Seriële poort doorvoer 1" -msgid "Serial port passthrough 2" +msgid "Serial port passthrough 2" msgstr "Seriële poort doorvoer 2" -msgid "Serial port passthrough 3" +msgid "Serial port passthrough 3" msgstr "Seriële poort doorvoer 3" -msgid "Serial port passthrough 4" +msgid "Serial port passthrough 4" msgstr "Seriële poort doorvoer 4" -msgid "Renderer options..." +msgid "Renderer options..." msgstr "Renderer-opties..." -msgid "Logitech/Microsoft Bus Mouse" +msgid "Logitech/Microsoft Bus Mouse" msgstr "Logitech/Microsoft busmuis" -msgid "Microsoft Bus Mouse (InPort)" +msgid "Microsoft Bus Mouse (InPort)" msgstr "Microsoft busmuis (InPort)" -msgid "Mouse Systems Serial Mouse" +msgid "Mouse Systems Serial Mouse" msgstr "Mouse Systems seriële muis" -msgid "Microsoft Serial Mouse" +msgid "Microsoft Serial Mouse" msgstr "Microsoft seriële muis" -msgid "Logitech Serial Mouse" +msgid "Logitech Serial Mouse" msgstr "Logitech seriële muis" -msgid "PS/2 Mouse" +msgid "PS/2 Mouse" msgstr "PS/2-muis" -msgid "3M MicroTouch (Serial)" +msgid "3M MicroTouch (Serial)" msgstr "3M MicroTouch (serieel)" -msgid "[COM] Standard Hayes-compliant Modem" +msgid "[COM] Standard Hayes-compliant Modem" msgstr "COM] Standaard Hayes-compatibele modem " -msgid "Roland MT-32 Emulation" +msgid "Roland MT-32 Emulation" msgstr "Roland MT-32-emulatie" -msgid "Roland MT-32 (New) Emulation" +msgid "Roland MT-32 (New) Emulation" msgstr "Roland MT-32 (nieuwe) emulatie" -msgid "Roland CM-32L Emulation" +msgid "Roland CM-32L Emulation" msgstr "Roland CM-32L-emulatie" -msgid "Roland CM-32LN Emulation" +msgid "Roland CM-32LN Emulation" msgstr "Roland CM-32LN-emulatie" -msgid "OPL4-ML Daughterboard" +msgid "OPL4-ML Daughterboard" msgstr "OPL4-ML-dochterbord" -msgid "System MIDI" +msgid "System MIDI" msgstr "Systeem MIDI" -msgid "MIDI Input Device" +msgid "MIDI Input Device" msgstr "MIDI-ingangsapparaat" -msgid "BIOS Address" +msgid "BIOS Address" msgstr "BIOS-adres" -msgid "Enable BIOS extension ROM Writes" +msgid "Enable BIOS extension ROM Writes" msgstr "BIOS-extensie ROM Writes inschakelen" -msgid "Address" +msgid "Address" msgstr "Adres" -msgid "IRQ" +msgid "IRQ" msgstr "IRQ" -msgid "BIOS Revision" +msgid "BIOS Revision" msgstr "BIOS Revisie" -msgid "Translate 26 -> 17" +msgid "Translate 26 -> 17" msgstr "Vertaal 26 -> 17" -msgid "Language" +msgid "Language" msgstr "Taal" -msgid "Enable backlight" +msgid "Enable backlight" msgstr "Backlight inschakelen" -msgid "Invert colors" +msgid "Invert colors" msgstr "Kleuren omkeren" -msgid "BIOS size" +msgid "BIOS size" msgstr "BIOS-grootte" -msgid "Map C0000-C7FFF as UMB" +msgid "Map C0000-C7FFF as UMB" msgstr "Geheugenadres C0000-C7FFF toewijzen aan UMB" -msgid "Map C8000-CFFFF as UMB" +msgid "Map C8000-CFFFF as UMB" msgstr "Geheugenadres C8000-CFFFF toewijzen aan UMB" -msgid "Map D0000-D7FFF as UMB" +msgid "Map D0000-D7FFF as UMB" msgstr "Geheugenadres D0000-D7FFF toewijzen aan UMB" -msgid "Map D8000-DFFFF as UMB" +msgid "Map D8000-DFFFF as UMB" msgstr "Geheugenadres D8000-DFFFF toewijzen aan UMB" -msgid "Map E0000-E7FFF as UMB" +msgid "Map E0000-E7FFF as UMB" msgstr "Geheugenadres E0000-E7FFF toewijzen aan UMB" -msgid "Map E8000-EFFFF as UMB" +msgid "Map E8000-EFFFF as UMB" msgstr "Geheugenadres E8000-EFFFF toewijzen aan UMB" -msgid "JS9 Jumper (JIM)" +msgid "JS9 Jumper (JIM)" msgstr "JS9 Jumper (JIM)" -msgid "MIDI Output Device" +msgid "MIDI Output Device" msgstr "MIDI-uitgangsapparaat" -msgid "MIDI Real time" +msgid "MIDI Real time" msgstr "MIDI real-time" -msgid "MIDI Thru" +msgid "MIDI Thru" msgstr "MIDI doorvoer" -msgid "MIDI Clockout" +msgid "MIDI Clockout" msgstr "MIDI Clockout" -msgid "SoundFont" +msgid "SoundFont" msgstr "SoundFont" -msgid "Output Gain" +msgid "Output Gain" msgstr "Output Gain" -msgid "Chorus" +msgid "Chorus" msgstr "Chorus" -msgid "Chorus Voices" +msgid "Chorus Voices" msgstr "Chorus-stemmen" -msgid "Chorus Level" +msgid "Chorus Level" msgstr "Chorus-niveau" -msgid "Chorus Speed" +msgid "Chorus Speed" msgstr "Chorus-snelheid" -msgid "Chorus Depth" +msgid "Chorus Depth" msgstr "Chorus-diepte" -msgid "Chorus Waveform" +msgid "Chorus Waveform" msgstr "Chorus-golfvorm" -msgid "Reverb" +msgid "Reverb" msgstr "Reverb" -msgid "Reverb Room Size" +msgid "Reverb Room Size" msgstr "Reverbkamer afmetingen" -msgid "Reverb Damping" +msgid "Reverb Damping" msgstr "Reverbdemping" -msgid "Reverb Width" +msgid "Reverb Width" msgstr "Reverbbreedte" -msgid "Reverb Level" +msgid "Reverb Level" msgstr "Reverbniveau" -msgid "Interpolation Method" +msgid "Interpolation Method" msgstr "Interpolatiemethode" -msgid "Reverb Output Gain" +msgid "Reverb Output Gain" msgstr "Reverbuitgang Versterking" -msgid "Reversed stereo" +msgid "Reversed stereo" msgstr "Omgekeerde stereo" -msgid "Nice ramp" +msgid "Nice ramp" msgstr "Mooie helling" -msgid "Hz" +msgid "Hz" msgstr "Hz" -msgid "Buttons" +msgid "Buttons" msgstr "Knoppen" -msgid "Serial Port" +msgid "Serial Port" msgstr "Seriële poort" -msgid "RTS toggle" +msgid "RTS toggle" msgstr "RTS toggle" -msgid "Revision" +msgid "Revision" msgstr "Revisie" -msgid "Controller" +msgid "Controller" msgstr "Controller" -msgid "Show Crosshair" +msgid "Show Crosshair" msgstr "Toon dradenkruis" -msgid "DMA" +msgid "DMA" msgstr "DMA" -msgid "MAC Address" +msgid "MAC Address" msgstr "MAC-adres" -msgid "MAC Address OUI" +msgid "MAC Address OUI" msgstr "MAC-adres OUI" -msgid "Enable BIOS" +msgid "Enable BIOS" msgstr "BIOS inschakelen" -msgid "Baud Rate" +msgid "Baud Rate" msgstr "Baud-snelheid" -msgid "TCP/IP listening port" +msgid "TCP/IP listening port" msgstr "TCP/IP-luisterpoort" -msgid "Phonebook File" +msgid "Phonebook File" msgstr "Telefoonboekbestand" -msgid "Telnet emulation" +msgid "Telnet emulation" msgstr "Telnet-emulatie" -msgid "RAM Address" +msgid "RAM Address" msgstr "RAM-adres" -msgid "RAM size" +msgid "RAM size" msgstr "RAM-grootte" -msgid "Initial RAM size" +msgid "Initial RAM size" msgstr "Oorspronkelijke RAM-grootte" -msgid "Serial Number" +msgid "Serial Number" msgstr "Serienummer" -msgid "Host ID" +msgid "Host ID" msgstr "Host-ID" -msgid "FDC Address" +msgid "FDC Address" msgstr "FDC Adres" -msgid "MPU-401 Address" +msgid "MPU-401 Address" msgstr "MPU-401 Adres" -msgid "MPU-401 IRQ" +msgid "MPU-401 IRQ" msgstr "MPU-401 IRQ" -msgid "Receive MIDI input" +msgid "Receive MIDI input" msgstr "MIDI-ingang ontvangen" -msgid "Low DMA" +msgid "Low DMA" msgstr "Lage DMA" -msgid "Enable Game port" +msgid "Enable Game port" msgstr "Game-poort inschakelen" -msgid "Surround module" +msgid "Surround module" msgstr "Surroundmodule" -msgid "CODEC" +msgid "CODEC" msgstr "Codec" -msgid "Raise CODEC interrupt on CODEC setup (needed by some drivers)" +msgid "Raise CODEC interrupt on CODEC setup (needed by some drivers)" msgstr "Verhoog CODEC interrupt bij CODEC setup (nodig voor sommige stuurprogramma's)" -msgid "SB Address" +msgid "SB Address" msgstr "SB-adres" -msgid "WSS IRQ" +msgid "WSS IRQ" msgstr "WSS IRQ" -msgid "WSS DMA" +msgid "WSS DMA" msgstr "WSS DMA" -msgid "Enable OPL" +msgid "Enable OPL" msgstr "OPL inschakelen" -msgid "Receive MIDI input (MPU-401)" +msgid "Receive MIDI input (MPU-401)" msgstr "MIDI-ingang ontvangen (MPU-401)" -msgid "SB low DMA" +msgid "SB low DMA" msgstr "SB lage DMA" -msgid "6CH variant (6-channel)" +msgid "6CH variant (6-channel)" msgstr "6CH-variant (6-kanaals)" -msgid "Enable CMS" +msgid "Enable CMS" msgstr "CMS inschakelen" -msgid "Mixer" +msgid "Mixer" msgstr "Mixer" -msgid "High DMA" +msgid "High DMA" msgstr "Hoge DMA" -msgid "Control PC speaker" +msgid "Control PC speaker" msgstr "Bestuur pc-luidspreker" -msgid "Memory size" +msgid "Memory size" msgstr "Geheugengrootte" -msgid "EMU8000 Address" +msgid "EMU8000 Address" msgstr "EMU8000 Adres" -msgid "IDE Controller" +msgid "IDE Controller" msgstr "IDE-controller" -msgid "Codec" +msgid "Codec" msgstr "Codec" -msgid "GUS type" +msgid "GUS type" msgstr "GUS-type" -msgid "Enable 0x04 \"Exit 86Box\" command" +msgid "Enable 0x04 \"Exit 86Box\" command" msgstr "Schakel het commando 0x04 \"Exit 86Box\" in" -msgid "Display type" +msgid "Display type" msgstr "Scherm type" -msgid "Composite type" +msgid "Composite type" msgstr "Composite type" -msgid "RGB type" +msgid "RGB type" msgstr "RGB-type" -msgid "Line doubling type" +msgid "Line doubling type" msgstr "Type lijnverdubbeling" -msgid "Snow emulation" +msgid "Snow emulation" msgstr "Sneeuwemulatie" -msgid "Monitor type" +msgid "Monitor type" msgstr "Type monitor" -msgid "Character set" +msgid "Character set" msgstr "Tekenset" -msgid "XGA type" +msgid "XGA type" msgstr "XGA-type" -msgid "Instance" +msgid "Instance" msgstr "Instantie" -msgid "MMIO Address" +msgid "MMIO Address" msgstr "MMIO-adres" -msgid "RAMDAC type" +msgid "RAMDAC type" msgstr "RAMDAC type" -msgid "Blend" +msgid "Blend" msgstr "Mengen" -msgid "Bilinear filtering" +msgid "Bilinear filtering" msgstr "Bilineaire filtering" -msgid "Dithering" +msgid "Dithering" msgstr "Dithering" -msgid "Enable NMI for CGA emulation" +msgid "Enable NMI for CGA emulation" msgstr "NMI inschakelen voor CGA-emulatie" -msgid "Voodoo type" +msgid "Voodoo type" msgstr "Voodoo-type" -msgid "Framebuffer memory size" +msgid "Framebuffer memory size" msgstr "Framebuffer geheugengrootte" -msgid "Texture memory size" +msgid "Texture memory size" msgstr "Grootte textuurgeheugen" -msgid "Dither subtraction" +msgid "Dither subtraction" msgstr "Dither aftrekken" -msgid "Screen Filter" +msgid "Screen Filter" msgstr "Schermfilter" -msgid "Render threads" +msgid "Render threads" msgstr "Render threads" -msgid "SLI" +msgid "SLI" msgstr "SLI" -msgid "Start Address" +msgid "Start Address" msgstr "Startadres" -msgid "Contiguous Size" +msgid "Contiguous Size" msgstr "Aaneengesloten grootte" -msgid "I/O Width" +msgid "I/O Width" msgstr "I/O-breedte" -msgid "Transfer Speed" +msgid "Transfer Speed" msgstr "Overdrachtssnelheid" -msgid "EMS mode" +msgid "EMS mode" msgstr "EMS-modus" -msgid "Address for > 2 MB" +msgid "Address for > 2 MB" msgstr "Adres voor > 2 MB" -msgid "Frame Address" +msgid "Frame Address" msgstr "Frameadres" -msgid "USA" +msgid "USA" msgstr "USA" -msgid "Danish" +msgid "Danish" msgstr "Deens" -msgid "Always at selected speed" +msgid "Always at selected speed" msgstr "Altijd op geselecteerde snelheid" -msgid "BIOS setting + Hotkeys (off during POST)" +msgid "BIOS setting + Hotkeys (off during POST)" msgstr "BIOS-instelling + Sneltoetsen (niet actief tijdens POST)" -msgid "64 kB starting from F0000" +msgid "64 kB starting from F0000" msgstr "64 kB vanaf F0000" -msgid "128 kB starting from E0000 (address MSB inverted, last 64KB first)" +msgid "128 kB starting from E0000 (address MSB inverted, last 64KB first)" msgstr "128 kB vanaf E0000 (geïnverteerd MSB adres, laatste 64KB eerst)" -msgid "Sine" +msgid "Sine" msgstr "Sinus" -msgid "Triangle" +msgid "Triangle" msgstr "Driehoek" -msgid "Linear" +msgid "Linear" msgstr "Lineair" -msgid "4th Order" +msgid "4th Order" msgstr "4e Orde" -msgid "7th Order" +msgid "7th Order" msgstr "7e Orde" -msgid "Non-timed (original)" +msgid "Non-timed (original)" msgstr "Niet-getimed (origineel)" -msgid "45 Hz (JMP2 not populated)" +msgid "45 Hz (JMP2 not populated)" msgstr "45 Hz (JMP2 niet gezet)" -msgid "Two" +msgid "Two" msgstr "Twee" -msgid "Three" +msgid "Three" msgstr "Drie" -msgid "Wheel" +msgid "Wheel" msgstr "Wiel" -msgid "Five + Wheel" +msgid "Five + Wheel" msgstr "Vijf + Wiel" -msgid "A3 - SMT2 Serial / SMT3(R)V" +msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serieel / SMT3(R)V" -msgid "Q1 - SMT3(R) Serial" +msgid "Q1 - SMT3(R) Serial" msgstr "Q1 - SMT3(R) Serieel" -msgid "8 KB" +msgid "8 KB" msgstr "8 KB" -msgid "32 KB" +msgid "32 KB" msgstr "32 KB" -msgid "16 KB" +msgid "16 KB" msgstr "16 KB" -msgid "64 KB" +msgid "64 KB" msgstr "64 KB" -msgid "Disable BIOS" +msgid "Disable BIOS" msgstr "BIOS uitschakelen" -msgid "512 KB" +msgid "512 KB" msgstr "512 KB" -msgid "2 MB" +msgid "2 MB" msgstr "2 MB" -msgid "8 MB" +msgid "8 MB" msgstr "8 MB" -msgid "28 MB" +msgid "28 MB" msgstr "28 MB" -msgid "1 MB" +msgid "1 MB" msgstr "1 MB" -msgid "4 MB" +msgid "4 MB" msgstr "4 MB" -msgid "12 MB" +msgid "12 MB" msgstr "12 MB" -msgid "16 MB" +msgid "16 MB" msgstr "16 MB" -msgid "20 MB" +msgid "20 MB" msgstr "20 MB" -msgid "24 MB" +msgid "24 MB" msgstr "24 MB" -msgid "SigmaTel STAC9721T (stereo)" +msgid "SigmaTel STAC9721T (stereo)" msgstr "SigmaTel STAC9721T (stereo)" -msgid "Classic" +msgid "Classic" msgstr "Klassiek" -msgid "256 KB" +msgid "256 KB" msgstr "256 KB" -msgid "Composite" +msgid "Composite" msgstr "Composite" -msgid "Old" +msgid "Old" msgstr "Oud" -msgid "New" +msgid "New" msgstr "Nieuw" -msgid "Color (generic)" +msgid "Color (generic)" msgstr "Kleur (algemeen)" -msgid "Green Monochrome" +msgid "Green Monochrome" msgstr "Groen monochroom" -msgid "Amber Monochrome" +msgid "Amber Monochrome" msgstr "Amber Monochroom" -msgid "Gray Monochrome" +msgid "Gray Monochrome" msgstr "Grijs monochroom" -msgid "Color (no brown)" +msgid "Color (no brown)" msgstr "Kleur (geen bruin)" -msgid "Color (IBM 5153)" +msgid "Color (IBM 5153)" msgstr "Kleur (IBM 5153)" -msgid "Simple doubling" +msgid "Simple doubling" msgstr "Eenvoudige verdubbeling" -msgid "sRGB interpolation" +msgid "sRGB interpolation" msgstr "sRGB-interpolatie" -msgid "Linear interpolation" +msgid "Linear interpolation" msgstr "Lineaire interpolatie" -msgid "128 KB" +msgid "128 KB" msgstr "128 KB" -msgid "Monochrome (5151/MDA) (white)" +msgid "Monochrome (5151/MDA) (white)" msgstr "Monochroom (5151/MDA) (wit)" -msgid "Monochrome (5151/MDA) (green)" +msgid "Monochrome (5151/MDA) (green)" msgstr "Monochroom (5151/MDA) (groen)" -msgid "Monochrome (5151/MDA) (amber)" +msgid "Monochrome (5151/MDA) (amber)" msgstr "Monochroom (5151/MDA) (amber)" -msgid "Color 40x25 (5153/CGA)" +msgid "Color 40x25 (5153/CGA)" msgstr "Kleur 40x25 (5153/CGA)" -msgid "Color 80x25 (5153/CGA)" +msgid "Color 80x25 (5153/CGA)" msgstr "Kleur 80x25 (5153/CGA)" -msgid "Enhanced Color - Normal Mode (5154/ECD)" +msgid "Enhanced Color - Normal Mode (5154/ECD)" msgstr "Verbeterde kleur - normale modus (5154/ECD)" -msgid "Enhanced Color - Enhanced Mode (5154/ECD)" +msgid "Enhanced Color - Enhanced Mode (5154/ECD)" msgstr "Verbeterde kleur - Verbeterde modus (5154/ECD)" -msgid "Green" +msgid "Green" msgstr "Groen" -msgid "Amber" +msgid "Amber" msgstr "Amber" -msgid "Gray" +msgid "Gray" msgstr "Grijs" -msgid "Color" +msgid "Color" msgstr "Kleur" -msgid "U.S. English" +msgid "U.S. English" msgstr "Amerikaans Engels" -msgid "Scandinavian" +msgid "Scandinavian" msgstr "Scandinavisch" -msgid "Other languages" +msgid "Other languages" msgstr "Andere talen" -msgid "Bochs latest" +msgid "Bochs latest" msgstr "Bochs nieuwste" -msgid "Mono Non-Interlaced" +msgid "Mono Non-Interlaced" msgstr "Mono Non-Interlaced" -msgid "Color Interlaced" +msgid "Color Interlaced" msgstr "Kleur interlaced" -msgid "Color Non-Interlaced" +msgid "Color Non-Interlaced" msgstr "Kleur non-interlaced" -msgid "3Dfx Voodoo Graphics" +msgid "3Dfx Voodoo Graphics" msgstr "3Dfx Voodoo Graphics" -msgid "Obsidian SB50 + Amethyst (2 TMUs)" +msgid "Obsidian SB50 + Amethyst (2 TMUs)" msgstr "Obsidian SB50 + Amethyst (2 TMU's)" -msgid "8-bit" +msgid "8-bit" msgstr "8-bit" -msgid "16-bit" +msgid "16-bit" msgstr "16-bit" -msgid "Standard (150ns)" +msgid "Standard (150ns)" msgstr "Standaard (150ns)" -msgid "High-Speed (120ns)" +msgid "High-Speed (120ns)" msgstr "Hoge snelheid (120ns)" -msgid "Enabled" +msgid "Enabled" msgstr "Ingeschakeld" -msgid "Standard" +msgid "Standard" msgstr "Standaard" -msgid "High-Speed" +msgid "High-Speed" msgstr "Hoge snelheid" -msgid "Stereo LPT DAC" +msgid "Stereo LPT DAC" msgstr "Stereo LPT DAC" -msgid "Generic Text Printer" +msgid "Generic Text Printer" msgstr "Generieke tekstprinter" -msgid "Generic ESC/P Dot-Matrix Printer" +msgid "Generic ESC/P Dot-Matrix Printer" msgstr "Generieke ESC/P dot-matrix-printer" -msgid "Generic PostScript Printer" +msgid "Generic PostScript Printer" msgstr "Generieke PostScript-printer" -msgid "Generic PCL5e Printer" +msgid "Generic PCL5e Printer" msgstr "Generieke PCL5e-printer" -msgid "Parallel Line Internet Protocol" +msgid "Parallel Line Internet Protocol" msgstr "Internetprotocol voor parallelle lijnen" -msgid "Protection Dongle for Savage Quest" +msgid "Protection Dongle for Savage Quest" msgstr "Beschermingsdongle voor Savage Quest" -msgid "Serial Passthrough Device" +msgid "Serial Passthrough Device" msgstr "Serieel doorvoerapparaat" -msgid "Passthrough Mode" +msgid "Passthrough Mode" msgstr "Doorgeefmodus" -msgid "Host Serial Device" +msgid "Host Serial Device" msgstr "Host Serieel Apparaat" -msgid "Name of pipe" +msgid "Name of pipe" msgstr "Naam van de pipe" -msgid "Data bits" +msgid "Data bits" msgstr "Databits" -msgid "Stop bits" +msgid "Stop bits" msgstr "Stopbits" -msgid "Baud Rate of Passthrough" +msgid "Baud Rate of Passthrough" msgstr "Baud-snelheid van doorvoer" -msgid "Named Pipe (Server)" +msgid "Named Pipe (Server)" msgstr "Named Pipe (Server)" -msgid "Host Serial Passthrough" +msgid "Host Serial Passthrough" msgstr "Host seriële doorgave" -msgid "E&ject %1" +msgid "E&ject %1" msgstr "&Uitwerpen %1" -msgid "&Unmute" +msgid "&Unmute" msgstr "&Geluid aanzetten" -msgid "Softfloat FPU" +msgid "Softfloat FPU" msgstr "Softfloat FPU" -msgid "High performance impact" +msgid "High performance impact" msgstr "Hoge prestatie-impact" -msgid "[Generic] RAM Disk (max. speed)" +msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM-schijf (max. snelheid)" -msgid "IBM 8514/A clone (ISA)" +msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-kloon (ISA)" -msgid "Vendor" +msgid "Vendor" msgstr "Verkoper" -msgid "Generic PC/XT Memory Expansion" +msgid "Generic PC/XT Memory Expansion" msgstr "Generieke PC/XT geheugenuitbreiding" -msgid "Generic PC/AT Memory Expansion" +msgid "Generic PC/AT Memory Expansion" msgstr "Generieke PC/AT geheugenuitbreiding" msgid "Unable to find Dot-Matrix fonts" From d0d2ba29ec71d8de86def03f9f363f16d54ff165 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 06:37:01 +0500 Subject: [PATCH 0716/1190] qt: Add the remaining untranslated strings to the template --- src/qt/languages/86box.pot | 51 ++++++++++++++++++++++++ src/qt/languages/ca-ES.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/cs-CZ.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/de-DE.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/es-ES.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/fi-FI.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/fr-FR.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/hr-HR.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/hu-HU.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/it-IT.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/ja-JP.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/ko-KR.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/nl-NL.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/pl-PL.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/pt-BR.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/pt-PT.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/ru-RU.po | 78 ++++++++++++++++++++++++++++++++++++ src/qt/languages/sk-SK.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/sl-SI.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/tr-TR.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/uk-UA.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/vi-VN.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/zh-CN.po | 81 ++++++++++++++++++++++++++++++++++++++ src/qt/languages/zh-TW.po | 81 ++++++++++++++++++++++++++++++++++++++ 24 files changed, 1911 insertions(+) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index fde3f921c..1d151a9d9 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2109,8 +2109,59 @@ msgstr "" msgid "Inhibit multimedia keys" msgstr "" +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + msgid "Model:" msgstr "" msgid "Failed to initialize Vulkan renderer." msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index f39be48ca..9dec41c32 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -2061,6 +2061,27 @@ msgstr "Alt impact en el rendiment" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disc RAM (velocitat màxima)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "No es pot trobar tipus de lletra de matriu de punts" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Els tipus de lletra TrueType al directori \"roms/printer/fonts\" són necessaris per a l'emulació de la impressora de matriu de punts ESC/P genèrica." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 34b5dfa6d..2098fe018 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -2061,6 +2061,27 @@ msgstr "Vysoký dopad na výkon" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disk RAM (max. rychlost)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Nastala chyba při nachození jehličkových písem" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Pro emulaci obecné jehličkové tiskárny ESC/P jsou vyžadována písma TrueType ve složce \"roms/printer/fonts\"." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index e69d496a7..2088e4141 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2064,6 +2064,27 @@ msgstr "Hohe Auswirkung auf die Leistung" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM-Diskette (maximale Geschwindigkeit)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-Klon (ISA)" @@ -2081,3 +2102,63 @@ msgstr "Nadel-Schriften konnten nicht gefunden werden" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "TrueType-Schriften in das \"roms/printer/fonts\"-Verzeichnis sind für die Allgemeines ESC/P Nadel-Druckers erforderlich." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 1e9bc1c23..bc11a4d4c 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -2060,6 +2060,27 @@ msgstr "Alto impact en el rendimiento" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disco RAM (velocidad máxima)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" @@ -2077,3 +2098,63 @@ msgstr "No fué posible encontrar las fuentes matriciales" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Las fuentes TrueType en el directorio \"roms/printer/fonts\" son necesarias para la emulación de la impresora matricial ESC/P genérica." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index d35e45b21..34e9aeead 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -2064,6 +2064,27 @@ msgstr "Suuri vaikutus suorituskykyyn" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM-levy (maksiminopeus)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-klooni (ISA)" @@ -2081,3 +2102,63 @@ msgstr "Pistematriisifontteja ei löydy" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "TrueType-fontteja kansiossa \"roms/printer/fonts\"-hakemistoon yleinen ESC/P pistematriisitulostin emulointiin." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 50de1f001..ebb181a30 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -2061,6 +2061,27 @@ msgstr "Impact important sur la performance" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disque RAM (vitesse maximale)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Impossible de trouver les polices à matrice à points" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Les polices TrueType dans le répertoire \"roms/printer/fonts\" sont nécessaires à l'émulation de l'imprimante générique ESC/P à matrice à points." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 93c247319..c1f6480c2 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -2061,6 +2061,27 @@ msgstr "Visoki učinak na brzinu izvršavanja" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disk RAM (najviša brzina)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Nije moguće pronaći matrične fontove" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "TrueType fontovi u mapi \"roms/printer/fonts\" potrebni su za emulaciju generičnog matričnog pisača ESC/P." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index b92b9c11b..09f914860 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -2061,6 +2061,27 @@ msgstr "Nagy hatással van a teljesítményre" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM lemez (max. sebesség)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A klón (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Nem találja a Dot-Matrix betűtípusokat" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Az általános ESC/P pontmátrixnyomtató emulációjához a \"roms/printer/fonts\" könyvtárban található TrueType betűtípusok szükségesek." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index b85bb64bd..c9694c3be 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -2061,6 +2061,27 @@ msgstr "Impatto elevato sulla prestazione" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disco RAM (velocità massima)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Impossibile trovare i font a matrice di punti" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "I font TrueType presenti nella directory \"roms/printer/fonts\" sono necessari per l'emulazione della stampante a matrice di punti ESC/P generica." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 07c783dd1..1c139aaec 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2061,6 +2061,27 @@ msgstr "パフォーマンスへの影響が大きい" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAMディスク(最高速度)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A クローン(ISA)" @@ -2078,3 +2099,63 @@ msgstr "ドットマトリクスフォントが見つかりません" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "汎用ESC/Pドットマトリクスプリンタのエミュレーションには、roms/printer/fontsディレクトリ内のTrueTypeフォントが必要です。" + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index cea372b7f..941bd740a 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -2061,6 +2061,27 @@ msgstr "성능에 미치는 영향" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM 디스크(최대 속도)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 클론(ISA)" @@ -2078,3 +2099,63 @@ msgstr "도트 매트릭스 글꼴을 찾을 수 없습니다" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "일반 ESC/P 도트 매트릭스 프린터의 에뮬레이션을 사용하려면 \"roms/printer/fonts\" 디렉터리에 있는 트루타입 글꼴이 필요합니다." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 20c193afe..fd2b66245 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -2061,6 +2061,27 @@ msgstr "Hoge prestatie-impact" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM-schijf (max. snelheid)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-kloon (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Dot-matrix-lettertypen niet gevonden" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "TrueType lettertypen in de map \"roms/printer/fonts\" zijn nodig voor de emulatie van de generieke ESC/P dot-matrix-printer." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 980ee69f1..ab50711f6 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -2061,6 +2061,27 @@ msgstr "Wysoki wpływ na wydajność" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Dysk RAM (maks. prędkość)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Nie można znaleźć czcionek igłowych" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Czcionki TrueType w katalogu \"roms/printer/fonts\" są wymagane do emulacji generyczniej drukarki igłowej ESC/P." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index c48e7a07f..db07a69ae 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2061,6 +2061,27 @@ msgstr "Alto impacto no desempenho" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disco RAM (velocidade máxima)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Não foi possível localizar os fontes matriciais de pontos" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "As fontes TrueType no diretório \"roms/printer/fonts\" são necessárias para a emulação da impressora matricial de pontos ESC/P genérica." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 1900a42d9..f67ddbdf8 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2061,6 +2061,27 @@ msgstr "Elevado impacto no desempenho" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disco RAM (velocidade máxima)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Não foi possível encontrar os fontes matriciais de pontos" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "As fontes TrueType no diretório \"roms/printer/fonts\" são necessárias para a emulação da impressora matricial de pontos ESC/P genérica" + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index afc4c72a4..a8cd0295a 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2061,6 +2061,27 @@ msgstr "Сильное влияние на производительность" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Стандартный] RAM-диск (макс. скорость)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" @@ -2085,5 +2106,62 @@ msgstr "Невозможно найти матричные шрифты" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Шрифты TrueType в каталоге \"roms/printer/fonts\" необходимы для эмуляции стандартного матричного принтера ESC/P." +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + msgid "Model:" msgstr "Модель:" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index f1a6144a6..5080c49b5 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -2062,6 +2062,27 @@ msgstr "Vysoký vplyv na výkon" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disk RAM (max. rýchlosť)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" @@ -2079,3 +2100,63 @@ msgstr "Nastala chyba pri hľadaní ihličkových písem" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Písma TrueType v adresári \"roms/printer/fonts\" sú potrebné na emuláciu generickej ihličkovej tlačiarne ESC/P." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 94c241dea..c34fb6f7e 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -2061,6 +2061,27 @@ msgstr "Visok učinek na hitrost delovanja" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Pogon RAM (največja hitrost)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Klon IBM 8514/A (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Matričnih pisav ni bilo mogoče najti" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Matrične pisave v imeniku \"roms/printer/fonts\" so potrebne za emulacijo generičnega matričnega tiskalnika ESC/P." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 1be214342..b7a59b620 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -2061,6 +2061,27 @@ msgstr "Ciddi performans düşüklüğüne neden olabilir" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM Disk (maks. hız)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A klonu (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Dot Matrix yazı tipleri bulunamıyor" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Sıradan ESC/P Dot Matrix Yazıcının emülasyonu için \"roms/printer/fonts\" dizinindeki TrueType yazı tipleri gereklidir." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 6acb947cf..3145f5e34 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -2061,6 +2061,27 @@ msgstr "Високий вплив на продуктивність" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Диск оперативної пам'яті (макс. швидкість)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" @@ -2084,3 +2105,63 @@ msgstr "Неможливо знайти матричні шрифти" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Шрифти TrueType у каталозі \"roms/printer/fonts\" потрібні для емуляції загального матричного принтера Generic ESC/P." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index c1d461fb7..932150f7b 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -2061,6 +2061,27 @@ msgstr "Ảnh hưởng lớn đến hiệu suất" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Đĩa RAM (tốc độ tối đa)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A bản nhái (ISA)" @@ -2078,3 +2099,63 @@ msgstr "Không tìm thấy phông chữ ma trận chấm" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "Cần có phông chữ TrueType trong thư mục \"roms/printer/fonts\" để mô phỏng máy in generic ESC/P ma trận chấm." + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 0ce76cff9..18f5a8fb8 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -2061,6 +2061,27 @@ msgstr "重大性能影响" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM 磁盘 (最大速度)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 克隆 (ISA)" @@ -2078,3 +2099,63 @@ msgstr "无法找到点阵字体" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "仿真通用 ESC/P 点阵打印机需要使用 \"roms/printer/fonts\" 目录中的 TrueType 字体。" + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index d50449aa2..9dbf51c70 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2061,6 +2061,27 @@ msgstr "對效能影響大" msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM 磁碟 (最大速度)" +msgid "[Generic] 1989 (3500 RPM)" +msgstr "" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "" + msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 克隆 (ISA)" @@ -2078,3 +2099,63 @@ msgstr "無法找到點矩陣字型" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." msgstr "通用 ESC/P 點矩陣印表機的模擬需要 \"roms/printer/fonts\" 目錄中的 TrueType 字體。" + +msgid "Inhibit multimedia keys" +msgstr "" + +msgid "Ask for confirmation before saving settings" +msgstr "" + +msgid "Ask for confirmation before hard resetting" +msgstr "" + +msgid "Ask for confirmation before quitting" +msgstr "" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "" + +msgid "Options" +msgstr "" + +msgid "Model:" +msgstr "" + +msgid "Failed to initialize Vulkan renderer." +msgstr "" + +msgid "GLSL Error" +msgstr "" + +msgid "Could not load shader: %1" +msgstr "" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "" + +msgid "Could not load texture: %1" +msgstr "" + +msgid "Could not compile shader:\n\n%1" +msgstr "" + +msgid "Program not linked:\n\n%1" +msgstr "" + +msgid "Shader Manager" +msgstr "" + +msgid "Shader Configuration" +msgstr "" + +msgid "Add" +msgstr "" + +msgid "Move up" +msgstr "" + +msgid "Move down" +msgstr "" + +msgid "Could not load file %1" +msgstr "" From 12eefc9519a8882da723389d9cc5ff6e13fade25 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 11 Apr 2025 06:38:46 +0500 Subject: [PATCH 0717/1190] qt: Update the Russian translation --- src/qt/languages/ru-RU.po | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index a8cd0295a..fb1908f60 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1252,19 +1252,19 @@ msgid "Pen" msgstr "Ручка" msgid "Host CD/DVD Drive (%1:)" -msgstr "Главный CD/DVD-привод (%1:)" +msgstr "CD/DVD-привод хоста (%1:)" msgid "&Connected" -msgstr "&Connected" +msgstr "&Кабель подключен" msgid "Clear image history" msgstr "Очистить историю образов" msgid "Create..." -msgstr "Создайте..." +msgstr "Создать..." msgid "Host CD/DVD Drive (%1)" -msgstr "Главный CD/DVD-привод (%1)" +msgstr "CD/DVD-привод хоста (%1)" msgid "Unknown Bus" msgstr "Неизвестная шина" @@ -1288,7 +1288,7 @@ msgid "VSync" msgstr "Вертикальная синхронизация" msgid "Synchronize with video" -msgstr "Синхронизация с видео" +msgstr "Синхронизировать с видео" msgid "Shaders" msgstr "Шейдеры" @@ -1384,25 +1384,25 @@ msgid "Renderer options..." msgstr "Параметры рендеринга..." msgid "Logitech/Microsoft Bus Mouse" -msgstr "Шинная мышь Logitech/Microsoft" +msgstr "Bus-мышь Logitech/Microsoft" msgid "Microsoft Bus Mouse (InPort)" -msgstr "Шинная мышь Microsoft (InPort)" +msgstr "Bus-мышь Microsoft (InPort)" msgid "Mouse Systems Serial Mouse" -msgstr "Последовательная мышь Mouse Systems" +msgstr "COM-мышь Mouse Systems" msgid "Microsoft Serial Mouse" -msgstr "Последовательная мышь Microsoft" +msgstr "COM-мышь Microsoft" msgid "Logitech Serial Mouse" -msgstr "Последовательная мышь Logitech" +msgstr "COM-мышь Logitech" msgid "PS/2 Mouse" msgstr "Мышь PS/2" msgid "3M MicroTouch (Serial)" -msgstr "3M MicroTouch (последовательная)" +msgstr "3M MicroTouch (последовательный)" msgid "[COM] Standard Hayes-compliant Modem" msgstr "[COM] Стандартный Hayes-совместимый модем" @@ -2062,25 +2062,25 @@ msgid "[Generic] RAM Disk (max. speed)" msgstr "[Стандартный] RAM-диск (макс. скорость)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "" +msgstr "[Стандартный] 1989 (3500 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" @@ -2107,61 +2107,61 @@ msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for t msgstr "Шрифты TrueType в каталоге \"roms/printer/fonts\" необходимы для эмуляции стандартного матричного принтера ESC/P." msgid "Inhibit multimedia keys" -msgstr "" +msgstr "Перехватывать мультимедиа-клавиши" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "Спрашивать подтверждения перед сохранением настроек" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "Спрашивать подтверждения перед холодной перезагрузкой" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "Спрашивать подтвержждения перед выходом" msgid "Display hotkey message when entering full-screen mode" -msgstr "" +msgstr "Показывать сообщение о горячих клавишах при включении полноэкранного режима" msgid "Options" -msgstr "" +msgstr "Параметры" msgid "Model:" msgstr "Модель:" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Не удалось инициализировать рендерер Vulkan." msgid "GLSL Error" -msgstr "" +msgstr "Ошибка GLSL" msgid "Could not load shader: %1" -msgstr "" +msgstr "Не удалось загрузить шейдер: %1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "Требуется OpenGL версии 3.0 или выше. Текущая версия GLSL %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "Не удалось загрузить текстуру: %1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "Не удалось скомпилировать шейдер:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "Не удалось скомпоновать шейдер:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "Управление шейдерами" msgid "Shader Configuration" -msgstr "" +msgstr "Конфигурация шейдера" msgid "Add" -msgstr "" +msgstr "Добавить" msgid "Move up" -msgstr "" +msgstr "Вверх" msgid "Move down" -msgstr "" +msgstr "Вниз" msgid "Could not load file %1" -msgstr "" +msgstr "Не удалось загрузить файл %1" From a0f0c42f4aec8d8ae2a4f427d54113b0a01ced7d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 12 Apr 2025 14:34:36 +0600 Subject: [PATCH 0718/1190] Microtouch touch points now work properly in fullscreen/maximized with scaling changes --- src/qt/qt_renderercommon.cpp | 3 ++ src/qt/qt_renderercommon.hpp | 2 + src/qt/qt_rendererstack.cpp | 85 ++++++++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_renderercommon.cpp b/src/qt/qt_renderercommon.cpp index 3a34452e6..56217b611 100644 --- a/src/qt/qt_renderercommon.cpp +++ b/src/qt/qt_renderercommon.cpp @@ -132,6 +132,9 @@ RendererCommon::onResize(int width, int height) monitors[r_monitor_index].mon_res_x = (double) destination.width(); monitors[r_monitor_index].mon_res_y = (double) destination.height(); + + destinationF.setRect((double)destination.x() / (double)width, (double)destination.y() / (double)height, + (double)destination.width() / (double)width, (double)destination.height() / (double)height); } bool diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index 333b9df0a..6bfa51a8d 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ public: virtual bool rendererTakeScreenshot() { return false; } int r_monitor_index = 0; + QRectF destinationF = QRectF(0, 0, 1, 1); /* normalized to 0.0-1.0 range. */ protected: bool eventDelegate(QEvent *event, bool &result); diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index b5b910fe9..431b3609b 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -488,6 +488,17 @@ RendererStack::event(QEvent* event) mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); if (!mouse_tablet_in_proximity) mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; } return QStackedWidget::event(event); } @@ -496,12 +507,34 @@ RendererStack::event(QEvent* event) if (mouse_input_mode == 0) { mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; return QStackedWidget::event(event); } #endif mouse_x_abs = (mouse_event->localPos().x()) / (double)width(); mouse_y_abs = (mouse_event->localPos().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; mouse_tablet_in_proximity = mousedata.mouse_tablet_in_proximity; } else switch (event->type()) { case QEvent::TouchBegin: @@ -511,8 +544,19 @@ RendererStack::event(QEvent* event) QTouchEvent* touchevent = (QTouchEvent*)event; if (mouse_input_mode == 0) break; if (touchevent->touchPoints().count()) { - mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); - mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); + mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; } mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); touchevent->accept(); @@ -521,8 +565,19 @@ RendererStack::event(QEvent* event) QTouchEvent* touchevent = (QTouchEvent*)event; if (mouse_input_mode == 0) break; if (touchevent->pointCount()) { - mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); - mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); + mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; } mouse_set_buttons_ex(mouse_get_buttons_ex() | 1); touchevent->accept(); @@ -538,6 +593,17 @@ RendererStack::event(QEvent* event) if (touchevent->touchPoints().count()) { mouse_x_abs = (touchevent->touchPoints()[0].pos().x()) / (double)width(); mouse_y_abs = (touchevent->touchPoints()[0].pos().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; } mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); touchevent->accept(); @@ -548,6 +614,17 @@ RendererStack::event(QEvent* event) if (touchevent->pointCount()) { mouse_x_abs = (touchevent->point(0).position().x()) / (double)width(); mouse_y_abs = (touchevent->point(0).position().y()) / (double)height(); + mouse_x_abs -= rendererWindow->destinationF.left(); + mouse_y_abs -= rendererWindow->destinationF.top(); + + if (mouse_x_abs < 0) mouse_x_abs = 0; + if (mouse_y_abs < 0) mouse_y_abs = 0; + + mouse_x_abs /= rendererWindow->destinationF.width(); + mouse_y_abs /= rendererWindow->destinationF.height(); + + if (mouse_x_abs > 1) mouse_x_abs = 1; + if (mouse_y_abs > 1) mouse_y_abs = 1; } mouse_set_buttons_ex(mouse_get_buttons_ex() & ~1); touchevent->accept(); From 1f9f0a0d6e3703ff111395d8210e1001466debf4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 12 Apr 2025 14:54:35 +0200 Subject: [PATCH 0719/1190] NEAT: The chipset has its own A20 toggle, it cannot alter the external one as that's an input to the chipset, fixes #5332. --- src/chipset/neat.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/neat.c b/src/chipset/neat.c index 1146ecbff..0661f89ee 100644 --- a/src/chipset/neat.c +++ b/src/chipset/neat.c @@ -956,8 +956,9 @@ neat_write(uint16_t port, uint8_t val, void *priv) dev->ems_size); } - mem_a20_key = !(val & RB12_GA20); + mem_a20_alt = !(val & RB12_GA20); mem_a20_recalc(); + flushmmucache(); break; default: @@ -987,7 +988,7 @@ neat_read(uint16_t port, void *priv) if ((dev->indx >= 0x60) && (dev->indx <= 0x6e)) ret = dev->regs[dev->indx]; else if (dev->indx == 0x6f) - ret = (dev->regs[dev->indx] & 0xfd) | (mem_a20_key & 2); + ret = (dev->regs[dev->indx] & 0xfd) | ~(mem_a20_alt & 0x02); break; default: From b91986499daabb9a96f1cdb9f986c135af2102e2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 12 Apr 2025 17:54:36 +0200 Subject: [PATCH 0720/1190] The forgotten keyboard.h. --- src/include/86box/keyboard.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 9142fbfe1..e495cb0df 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -245,6 +245,7 @@ extern const device_t keyboard_ps2_ps1_device; extern const device_t keyboard_ps2_ps1_pci_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; +extern const device_t keyboard_ps2_compaq_device; extern const device_t keyboard_ps2_holtek_device; extern const device_t keyboard_ps2_mca_1_device; extern const device_t keyboard_ps2_mca_2_device; @@ -258,6 +259,7 @@ extern const device_t keyboard_ps2_ami_pci_device; extern const device_t keyboard_ps2_intel_ami_pci_device; extern const device_t keyboard_ps2_acer_pci_device; extern const device_t keyboard_ps2_ali_pci_device; +extern const device_t keyboard_ps2_phoenix_pci_device; extern const device_t keyboard_ps2_tg_ami_pci_device; extern const device_t keyboard_at_generic_device; @@ -284,6 +286,7 @@ extern int keyboard_isfsexit_up(void); extern int keyboard_ismsexit(void); extern void keyboard_set_is_amstrad(int ams); extern void kbc_at_set_ps2(void *priv, uint8_t ps2); +extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val); extern void kbc_at_set_fast_reset(uint8_t new_fast_reset); extern void kbc_at_handler(int set, void *priv); From 08437a4d335530fc0b7c6e115b2a37cc40f4a099 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 13 Apr 2025 16:53:03 +0200 Subject: [PATCH 0721/1190] WD76C10: Implement the interleave modes complete with row and column calculation, fixes #5465. --- src/chipset/wd76c10.c | 425 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 404 insertions(+), 21 deletions(-) diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c index a375c8eb6..48bb56483 100644 --- a/src/chipset/wd76c10.c +++ b/src/chipset/wd76c10.c @@ -65,9 +65,10 @@ wd76c10_log(const char *fmt, ...) #endif typedef struct { - uint32_t enable; + uint32_t phys_on, enable; uint32_t virt_addr, phys_addr; uint32_t virt_size, phys_size; + uint32_t adj_virt_addr, adj_virt_size; } ram_bank_t; typedef struct { @@ -103,6 +104,7 @@ typedef struct int locked; uint32_t mem_top, hmwp_base; + uint32_t fast; ram_bank_t ram_banks[5]; @@ -121,6 +123,40 @@ static uint32_t bank_sizes[4] = { 0x00020000, /* 64 Kbit X 16 = 1024 Kbit 0x00200000, /* 1 Mbit X 16 = 16 Mbit = 2 MB, 10x10 */ 0x00800000 }; /* 4 Mbit X 16 = 64 Mbit = 8 MB, 11x11 */ +static uint32_t +wd76c10_calc_phys(uint32_t row, uint32_t col, uint32_t size, uint32_t a0) +{ + uint32_t ret = WD76C10_ADDR_INVALID; + + switch (size) { + default: + ret = WD76C10_ADDR_INVALID; + break; + case 0x00020000: + row = (row & 0x0000ff) << 9; + col = (col & 0x0000ff) << 1; + ret = row | col | a0; + break; + case 0x00080000: + row = (row & 0x0001ff) << 10; + col = (col & 0x0001ff) << 1; + ret = row | col | a0; + break; + case 0x00200000: + row = (row & 0x0003ff) << 11; + col = (col & 0x0003ff) << 1; + ret = row | col | a0; + break; + case 0x00800000: + row = (row & 0x0007ff) << 12; + col = (col & 0x0007ff) << 1; + ret = row | col | a0; + break; + } + + return ret; +} + static uint32_t wd76c10_calc_addr(wd76c10_t *dev, uint32_t addr) { @@ -159,20 +195,303 @@ wd76c10_calc_addr(wd76c10_t *dev, uint32_t addr) ret = WD76C10_ADDR_INVALID; /* Then, handle the physical memory banks. */ + int ilv4 = (dev->mem_ctl >> 8) & 4; + int8_t add = 0; + uint32_t pg = (dev->mem_ctl & 0x0800); + uint32_t nrt = WD76C10_ADDR_INVALID; + + if (ret != WD76C10_ADDR_INVALID) { + if (dev->fast) for (int8_t i = 0; i < 4; i++) { + rb = &(dev->ram_banks[i]); + + uint32_t ret2 = ret - rb->phys_addr; + + if (rb->phys_on && (ret >= rb->phys_addr) && + (ret < (rb->phys_addr + rb->phys_size))) { + if (ret2 < rb->phys_size) + nrt = ret2 + rb->phys_addr; + break; + } + } else for (int8_t i = 0; i < 4; i++) { + rb = &(dev->ram_banks[i]); + + int ilv2 = (dev->mem_ctl >> 8) & (1 << (i >> 1)); + uint32_t size = rb->virt_size; + uint32_t ret2 = ret - rb->virt_addr; + uint32_t ret4 = ret2; + uint32_t row = WD76C10_ADDR_INVALID; + uint32_t col = WD76C10_ADDR_INVALID; + uint32_t rb_or = 0; + + if (ilv4) { + size <<= 2; + switch (rb->virt_size) { + default: + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00020000: + if (pg) { + row = (ret2 >> 9) & 0x0000fc; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 9) & 0x000003; + } else + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00080000: + if (pg) { + row = (ret2 >> 9) & 0x0000f8; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 10) & 0x000003; + } else + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00200000: + if (pg) { + row = (ret2 >> 9) & 0x0000f0; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 23) & 0x000001) << 3; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 11) & 0x000003; + } else + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00800000: + if (pg) { + row = (ret2 >> 9) & 0x0000e0; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 23) & 0x000001) << 3; + row |= ((ret2 >> 24) & 0x000001) << 4; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 12) & 0x000003; + } else + ret4 = WD76C10_ADDR_INVALID; + break; + } + add = 3; + } else if (ilv2) { + size <<= 1; + switch (rb->virt_size) { + default: + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00020000: + if (pg) { + row = (ret2 >> 9) & 0x0000fe; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 9) & 0x000001; + } else { + row = (ret2 >> 1) & 0x0007fe; + row |= (ret2 >> 13) & 0x000001; + col = (ret2 >> 9) & 0x0000ef; + col |= ((ret2 >> 17) & 0x000001) << 4; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + rb_or = (ret2 >> 1) & 0x000001; + } + break; + case 0x00080000: + if (pg) { + row = (ret2 >> 9) & 0x0000fc; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 10) & 0x000001; + } else { + row = (ret2 >> 1) & 0x0007fe; + row |= (ret2 >> 13) & 0x000001; + col = (ret2 >> 9) & 0x0000ee; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 19) & 0x000001) << 4; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + rb_or = (ret2 >> 1) & 0x000001; + } + break; + case 0x00200000: + if (pg) { + row = (ret2 >> 9) & 0x0000f8; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 11) & 0x000001; + } else { + row = (ret2 >> 1) & 0x0007fe; + row |= (ret2 >> 13) & 0x000001; + col = (ret2 >> 9) & 0x0000ec; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 19) & 0x000001) << 1; + col |= ((ret2 >> 21) & 0x000001) << 4; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + rb_or = (ret2 >> 1) & 0x000001; + } + break; + case 0x00800000: + if (pg) { + row = (ret2 >> 9) & 0x0000f0; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 23) & 0x000001) << 3; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x000007ff; + rb_or = (ret2 >> 12) & 0x000001; + } else { + row = (ret2 >> 1) & 0x0007fe; + row |= (ret2 >> 13) & 0x000001; + col = (ret2 >> 9) & 0x0000e0; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 19) & 0x000001) << 1; + col |= ((ret2 >> 21) & 0x000001) << 2; + col |= ((ret2 >> 23) & 0x000001) << 3; + col |= ((ret2 >> 12) & 0x000001) << 4; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + rb_or = (ret2 >> 1) & 0x000001; + } + break; + } + add = 1; + } else if (pg) switch (rb->virt_size) { + default: + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00020000: + row = (ret2 >> 9) & 0x0000ff; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x0007ff; + break; + case 0x00080000: + row = (ret2 >> 9) & 0x0000fe; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x0007ff; + break; + case 0x00200000: + row = (ret2 >> 9) & 0x0000fc; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x0007ff; + break; + case 0x00800000: + row = (ret2 >> 9) & 0x0000f8; + row |= (ret2 >> 17) & 0x000001; + row |= ((ret2 >> 19) & 0x000001) << 1; + row |= ((ret2 >> 21) & 0x000001) << 2; + row |= ((ret2 >> 18) & 0x000001) << 8; + row |= ((ret2 >> 20) & 0x000001) << 9; + row |= ((ret2 >> 22) & 0x000001) << 10; + col = (ret2 >> 1) & 0x0007ff; + break; + } else switch (rb->virt_size) { + default: + ret4 = WD76C10_ADDR_INVALID; + break; + case 0x00020000: + row = (ret2 >> 1) & 0x0007ff; + col = (ret2 >> 9) & 0x0000ff; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + break; + case 0x00080000: + row = (ret2 >> 1) & 0x0007ff; + col = (ret2 >> 9) & 0x0000fe; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + break; + case 0x00200000: + row = (ret2 >> 1) & 0x0007ff; + col = (ret2 >> 9) & 0x0000fc; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 19) & 0x000001) << 1; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + break; + case 0x00800000: + row = (ret2 >> 1) & 0x0007ff; + col = (ret2 >> 9) & 0x0000f8; + col |= (ret2 >> 17) & 0x000001; + col |= ((ret2 >> 19) & 0x000001) << 1; + col |= ((ret2 >> 21) & 0x000001) << 2; + col |= ((ret2 >> 18) & 0x000001) << 8; + col |= ((ret2 >> 20) & 0x000001) << 9; + col |= ((ret2 >> 22) & 0x000001) << 10; + break; + } + + if (row != WD76C10_ADDR_INVALID) { + ret4 = wd76c10_calc_phys(row & 0x0007ff, col & 0x0007ff, + rb->phys_size, ret2 & 0x000001); + + if (ilv4 || ilv2) + rb = &(dev->ram_banks[i | rb_or]); + + i += add; + } + + if (rb->enable && (ret >= rb->virt_addr) && + (ret < (rb->virt_addr + size))) { + if ((ret4 != WD76C10_ADDR_INVALID) && (rb->phys_size > 0x00000000)) + nrt = ret4 + rb->phys_addr; + break; + } + } + + ret = nrt; + } + if (ret >= (mem_size << 10)) /* The physical memory address is too high or disabled, which is invalid. */ ret = WD76C10_ADDR_INVALID; - /* Otherwise, map it to the correct bank so the BIOS can auto-size it correctly. */ - else for (uint8_t i = 0; i < 4; i++) { - rb = &(dev->ram_banks[i]); - if (rb->enable && (ret >= rb->virt_addr) && (ret < (rb->virt_addr + rb->virt_size))) { - if (rb->phys_size == 0x00000000) - ret = WD76C10_ADDR_INVALID; - else - ret = ((ret - rb->virt_addr) % rb->phys_size) + rb->phys_addr; - break; - } - } return ret; } @@ -185,8 +504,12 @@ wd76c10_read_ram(uint32_t addr, void *priv) addr = wd76c10_calc_addr(dev, addr); - if (addr != WD76C10_ADDR_INVALID) - ret = mem_read_ram(addr, priv); + if (addr != WD76C10_ADDR_INVALID) { + if (dev->fast) + ret = mem_read_ram(addr, priv); + else + ret = ram[addr]; + } return ret; } @@ -199,8 +522,12 @@ wd76c10_read_ramw(uint32_t addr, void *priv) addr = wd76c10_calc_addr(dev, addr); - if (addr != WD76C10_ADDR_INVALID) - ret = mem_read_ramw(addr, priv); + if (addr != WD76C10_ADDR_INVALID) { + if (dev->fast) + ret = mem_read_ramw(addr, priv); + else + ret = *(uint16_t *) &(ram[addr]); + } return ret; } @@ -212,8 +539,12 @@ wd76c10_write_ram(uint32_t addr, uint8_t val, void *priv) addr = wd76c10_calc_addr(dev, addr); - if (addr != WD76C10_ADDR_INVALID) - mem_write_ram(addr, val, priv); + if (addr != WD76C10_ADDR_INVALID) { + if (dev->fast) + mem_write_ram(addr, val, priv); + else + ram[addr] = val; + } } static void @@ -223,8 +554,12 @@ wd76c10_write_ramw(uint32_t addr, uint16_t val, void *priv) addr = wd76c10_calc_addr(dev, addr); - if (addr != WD76C10_ADDR_INVALID) - mem_write_ramw(addr, val, priv); + if (addr != WD76C10_ADDR_INVALID) { + if (dev->fast) + mem_write_ramw(addr, val, priv); + else + *(uint16_t *) &(ram[addr]) = val; + } } static void @@ -258,6 +593,9 @@ wd76c10_recalc_exec(wd76c10_t *dev, uint32_t base, uint32_t size) static void wd76c10_banks_recalc(wd76c10_t *dev) { + int match = 0; + dev->fast = 0; + for (uint8_t i = 0; i < 4; i++) { ram_bank_t *rb = &(dev->ram_banks[i]); uint8_t bit = i << 1; @@ -266,8 +604,42 @@ wd76c10_banks_recalc(wd76c10_t *dev) rb->enable = (dev->split_sa >> bit) & 0x01; rb->virt_addr = ((uint32_t) dev->bank_bases[i]) << 17; + if (rb->enable) { + rb->adj_virt_addr = rb->virt_addr; + rb->adj_virt_size = rb->virt_size; + + if (dev->mem_ctl & 0x0400) + rb->adj_virt_addr += (i * rb->adj_virt_size); + else if ((dev->mem_ctl >> 8) & (1 << (i >> 1))) + rb->adj_virt_addr += ((i & 1) * rb->adj_virt_size); + } else { + rb->adj_virt_addr = WD76C10_ADDR_INVALID; + rb->adj_virt_size = 0x00000000; + } + + if ((rb->enable == rb->phys_on) && + (rb->adj_virt_addr == rb->phys_addr) && + (rb->adj_virt_size == rb->phys_size)) + match++; + } + + dev->fast = (match == 4); + + for (uint8_t i = 0; i < 4; i++) { + ram_bank_t *rb = &(dev->ram_banks[i]); + if (cpu_use_exec) wd76c10_recalc_exec(dev, rb->virt_addr, rb->virt_size); + + wd76c10_log("Bank %i (%s), physical: %i, %08X-%08X, " + "virtual: %i, %08X-%08X, adj.: %i, %08X-%08X\n", + i, dev->fast ? "FAST" : "SLOW", + rb->phys_on, + rb->phys_addr, rb->phys_addr + rb->phys_size - 1, + rb->enable, + rb->virt_addr, rb->virt_addr + rb->virt_size - 1, + rb->enable, + rb->adj_virt_addr, rb->adj_virt_addr + rb->adj_virt_size - 1); } } @@ -899,11 +1271,22 @@ wd76c10_init(UNUSED(const device_t *info)) } } if (size != 0x00000000) { + rb->phys_on = 1; rb->phys_addr = accum_mem; rb->phys_size = size; + wd76c10_log("Bank %i size: %5i KiB, starting at %5i KiB\n", i, rb->phys_size >> 10, rb->phys_addr >> 10); total_mem -= size; accum_mem += size; - } + } else + rb->phys_addr = WD76C10_ADDR_INVALID; + } + + if (mem_size == 3072) { + /* Reorganize the banks a bit so, we have 2048, 0, 512, 512. */ + ram_bank_t rt = dev->ram_banks[3]; + dev->ram_banks[3] = dev->ram_banks[2]; + dev->ram_banks[2] = dev->ram_banks[1]; + dev->ram_banks[1] = rt; } rb = &(dev->ram_banks[4]); From d07038961fa6e428f58493660484d0d3e0849907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:15:42 +0200 Subject: [PATCH 0722/1190] Add win11arm job --- .github/workflows/cmake_windows_msys2.yml | 35 +++++++---------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index abe25b949..495937b10 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -18,7 +18,6 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** - .github/workflows/cmake_windows_msys2.yml - vcpkg.json - "!**/Makefile*" @@ -26,9 +25,9 @@ on: jobs: msys2: - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" + name: "${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" - runs-on: windows-2022 + runs-on: ${{ matrix.environment.runner }} env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed @@ -41,8 +40,6 @@ jobs: fail-fast: true matrix: build: -# - name: Regular -# preset: regular - name: Debug preset: dev_debug slug: -Debug @@ -56,26 +53,15 @@ jobs: - name: NDR new: on slug: -NDR - ui: - - name: Qt GUI - qt: on - static: on - slug: -Qt - packages: >- - qt5-static:p - vulkan-headers:p environment: -# - msystem: MSYS -# toolchain: ./cmake/flags-gcc-x86_64.cmake - msystem: MINGW64 - prefix: mingw-w64-x86_64 toolchain: ./cmake/flags-gcc-x86_64.cmake -# - msystem: CLANG64 -# prefix: mingw-w64-clang-x86_64 -# toolchain: ./cmake/llvm-win32-x86_64.cmake -# - msystem: UCRT64 -# prefix: mingw-w64-ucrt-x86_64 -# toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: -x64 + runner: windows-2022 + - msystem: CLANGARM64 + toolchain: ./cmake/flags-gcc-aarch64.cmake + slug: -ARM64 + runner: windows-11-arm steps: - name: Prepare MSYS2 environment @@ -98,7 +84,8 @@ jobs: libslirp:p fluidsynth:p libserialport:p - ${{ matrix.ui.packages }} + qt5-static:p + vulkan-headers:p - name: Checkout repository uses: actions/checkout@v4 @@ -114,8 +101,6 @@ jobs: --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} -D CMAKE_INSTALL_PREFIX=./build/artifacts - -D QT=${{ matrix.ui.qt }} - -D STATIC_BUILD=${{ matrix.ui.static }} - name: Build run: | From 775c7bd3d61c356d74fa51b7dd865fd77559a861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:26:14 +0200 Subject: [PATCH 0723/1190] Try to fix the job --- .github/workflows/cmake_windows_msys2.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index 495937b10..f3262c4d5 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -40,11 +40,10 @@ jobs: fail-fast: true matrix: build: - - name: Debug - preset: dev_debug - slug: -Debug + - name: Regular + preset: regular - name: Dev - preset: development + preset: dev_debug slug: -Dev dynarec: - name: ODR @@ -60,14 +59,19 @@ jobs: runner: windows-2022 - msystem: CLANGARM64 toolchain: ./cmake/flags-gcc-aarch64.cmake - slug: -ARM64 + slug: -arm64 runner: windows-11-arm + exclude: + - dynarec: + new: off + environment: + msystem: CLANGARM64 steps: - name: Prepare MSYS2 environment uses: msys2/setup-msys2@v2 with: - release: false + release: true update: true msystem: ${{ matrix.environment.msystem }} pacboy: >- From 1080389bfd403b561935b8fe8ae43bd99f680f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:35:48 +0200 Subject: [PATCH 0724/1190] Fix number 2 --- .github/workflows/cmake_windows_msys2.yml | 26 ++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index f3262c4d5..b2bb9b3a6 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -96,8 +96,8 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v3 + # - name: Install sonar-scanner and build-wrapper + # uses: SonarSource/sonarcloud-github-c-cpp@v3 - name: Configure CMake run: >- @@ -106,17 +106,19 @@ jobs: -D NEW_DYNAREC=${{ matrix.dynarec.new }} -D CMAKE_INSTALL_PREFIX=./build/artifacts - - name: Build - run: | - .sonar/build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + # - name: Build + # run: | + # .sonar/build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - - name: Run sonar-scanner - if: 0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - .sonar/sonar-scanner-5.0.1.3006-windows/bin/sonar-scanner.bat --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" + - name: Build + run: cmake --build build + + # - name: Run sonar-scanner + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + # run: | + # .sonar/sonar-scanner-5.0.1.3006-windows/bin/sonar-scanner.bat --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - name: Generate package run: cmake --install build From 52458f78439c255886b8e54de95beb9d0c7e4770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:43:11 +0200 Subject: [PATCH 0725/1190] Fix number 3 --- .github/workflows/cmake_windows_msys2.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index b2bb9b3a6..f94853279 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -90,6 +90,7 @@ jobs: libserialport:p qt5-static:p vulkan-headers:p + openmp:p - name: Checkout repository uses: actions/checkout@v4 From fe9f6a7f1daafa8cf7747f4270bb6af8baf1bef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:54:21 +0200 Subject: [PATCH 0726/1190] Artifact names in line with Jenkins --- .github/workflows/cmake_windows_msys2.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index f94853279..d9cd37d0d 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -48,14 +48,13 @@ jobs: dynarec: - name: ODR new: off - slug: -ODR - name: NDR new: on slug: -NDR environment: - msystem: MINGW64 toolchain: ./cmake/flags-gcc-x86_64.cmake - slug: -x64 + slug: "-64" runner: windows-2022 - msystem: CLANGARM64 toolchain: ./cmake/flags-gcc-aarch64.cmake @@ -127,5 +126,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-Windows-${{ matrix.environment.msystem }}-gha${{ github.run_number }}' + name: '86Box${{ matrix.dynarec.slug }}${{ matrix.build.slug }}${{ matrix.environment.slug }}-gha${{ github.run_number }}' path: build/artifacts/** From 1b61f58bf00ce333c7baf4d6235b1cfd0816f486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:55:11 +0200 Subject: [PATCH 0727/1190] Fix --- .github/workflows/cmake_windows_msys2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index d9cd37d0d..44d982e16 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -126,5 +126,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: '86Box${{ matrix.dynarec.slug }}${{ matrix.build.slug }}${{ matrix.environment.slug }}-gha${{ github.run_number }}' + name: '86Box${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-Windows${{ matrix.environment.slug }}-gha${{ github.run_number }}' path: build/artifacts/** From e4d7911f857695cd956280b9050173d14d03c5ab Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 15 Apr 2025 14:06:02 -0300 Subject: [PATCH 0728/1190] Fix Conner name in one model preset --- src/disk/hdd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 8a02173ce..e051cc841 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -469,7 +469,7 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 210, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[ATA-3] Connor CFS1275A", .internal_name = "CFS1275A", .model = "Connor Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 + { .name = "[ATA-3] Conner CFS1275A", .internal_name = "CFS1275A", .model = "Conner Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, From 9b54021061a09ebf5588425279f95d2428faefb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:10:18 +0200 Subject: [PATCH 0729/1190] Use debug instead of release --- .github/workflows/cmake_windows_msys2.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index 44d982e16..9dda6a695 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -40,8 +40,9 @@ jobs: fail-fast: true matrix: build: - - name: Regular - preset: regular + - name: Debug + preset: debug + slug: -Debug - name: Dev preset: dev_debug slug: -Dev From 90134095b95b36f9635d036bb8aababcb784256a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:16:59 +0200 Subject: [PATCH 0730/1190] Fix the presets once again --- .github/workflows/cmake_windows_msys2.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index 9dda6a695..98aae1883 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -40,11 +40,11 @@ jobs: fail-fast: true matrix: build: - - name: Debug + - name: Dev Debug preset: debug - slug: -Debug + slug: -Dev-Debug - name: Dev - preset: dev_debug + preset: development slug: -Dev dynarec: - name: ODR From bb0b8f254de968e9b0de8918467dea741f83a7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:19:39 +0200 Subject: [PATCH 0731/1190] ... --- .github/workflows/cmake_windows_msys2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index 98aae1883..ca48599a0 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -41,7 +41,7 @@ jobs: matrix: build: - name: Dev Debug - preset: debug + preset: dev_debug slug: -Dev-Debug - name: Dev preset: development From 245619674d160e092bd0d54ed50a5edb06294094 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 15 Apr 2025 22:05:11 +0200 Subject: [PATCH 0732/1190] PAS16/Plus change of the day (April 15th, 2025) Actually make the DMA transfer speed normal in when in 16-bit stereo mode with System Configuration 1 bit 1 (Master Clock) cleared. Fixes audio being too quick with said configuration. --- src/sound/snd_pas16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index dd95eac4c..cfefc8df5 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -1756,7 +1756,7 @@ static uint16_t pas16_readdmaw_stereo(pas16_t *pas16) { uint16_t ret; - uint16_t ticks = (pas16->sys_conf_1 & 0x02) ? (1 + (pas16->dma < 5)) : 2; + uint16_t ticks = (pas16->sys_conf_1 & 0x02) ? (1 + (pas16->dma < 5)) : 1; ret = pas16_dma_readw(pas16, ticks); From 2c3fc6ec1ad25ea206c3f96822487645f4f3844b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 16 Apr 2025 22:09:27 +0200 Subject: [PATCH 0733/1190] Bump version to 5.0. --- CMakeLists.txt | 2 +- debian/changelog | 4 ++-- src/unix/assets/86Box.spec | 4 ++-- src/unix/assets/net.86box.86Box.metainfo.xml | 2 +- vcpkg.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a94321038..007c1ffd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if(MUNT_EXTERNAL) endif() project(86Box - VERSION 4.3 + VERSION 5.0 DESCRIPTION "Emulator of x86-based systems" HOMEPAGE_URL "https://86box.net" LANGUAGES C CXX) diff --git a/debian/changelog b/debian/changelog index 5665ff968..079fba5dd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -86box (4.3) UNRELEASED; urgency=medium +86box (5.0) UNRELEASED; urgency=medium * Bump release. - -- Jasmine Iwanek Wed, 13 Nov 2024 06:31:46 +0100 + -- Jasmine Iwanek Wed, 16 Apr 2025 22:08:04 +0200 diff --git a/src/unix/assets/86Box.spec b/src/unix/assets/86Box.spec index 86f380d22..bb9b85b12 100644 --- a/src/unix/assets/86Box.spec +++ b/src/unix/assets/86Box.spec @@ -15,7 +15,7 @@ %global romver 4.1 Name: 86Box -Version: 4.3 +Version: 5.0 Release: 1%{?dist} Summary: Classic PC emulator License: GPLv2+ @@ -121,5 +121,5 @@ popd %{_datadir}/%{name}/roms %changelog -* Sat Aug 31 Jasmine Iwanek 4.3-1 +* Sat Aug 31 Jasmine Iwanek 5.0-1 - Bump release diff --git a/src/unix/assets/net.86box.86Box.metainfo.xml b/src/unix/assets/net.86box.86Box.metainfo.xml index 6618f21d2..4c6a795a7 100644 --- a/src/unix/assets/net.86box.86Box.metainfo.xml +++ b/src/unix/assets/net.86box.86Box.metainfo.xml @@ -11,7 +11,7 @@ net.86box.86Box.desktop - + diff --git a/vcpkg.json b/vcpkg.json index 87859869b..20b783add 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "86box", - "version-string": "4.3", + "version-string": "5.0", "homepage": "https://86box.net/", "documentation": "https://86box.readthedocs.io/", "license": "GPL-2.0-or-later", From 90265546e6bb75ac5e4dac25925458e5198e6cd4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 17 Apr 2025 00:18:38 +0200 Subject: [PATCH 0734/1190] CD-ROM: Do not stop playing on a READ command that immediately terminates with an "illegal mode for this track" error, fixes track skipping in the Windows 95 CD Player. --- src/cdrom/cdrom.c | 89 +++++++++++++++++++++++++++------------ src/include/86box/cdrom.h | 2 + src/scsi/scsi_cdrom.c | 17 ++++++++ 3 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index b30d93812..644a8e245 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2274,6 +2274,65 @@ cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, return ret; } +static uint32_t +cdrom_msf_to_lba(const int sector, const int ismsf, + int cdrom_sector_type, const uint8_t vendor_type) +{ + int pos = sector; + uint32_t lba; + + if ((cdrom_sector_type & 0x0f) >= 0x08) { + mult = cdrom_sector_type >> 4; + pos /= mult; + } + + if (ismsf) { + const int m = (pos >> 16) & 0xff; + const int s = (pos >> 8) & 0xff; + const int f = pos & 0xff; + + lba = MSFtoLBA(m, s, f) - 150; + } else { + switch (vendor_type) { + case 0x00: + lba = pos; + break; + case 0x40: { + const int m = bcd2bin((pos >> 24) & 0xff); + const int s = bcd2bin((pos >> 16) & 0xff); + const int f = bcd2bin((pos >> 8) & 0xff); + + lba = MSFtoLBA(m, s, f) - 150; + break; + } case 0x80: + lba = bcd2bin((pos >> 24) & 0xff); + break; + /* Never used values but the compiler complains. */ + default: + lba = 0; + } + } + + return lba; +} + +int +cdrom_is_track_audio(cdrom_t *dev, const int sector, + const int ismsf, int cdrom_sector_type, + const uint8_t vendor_type) +{ + int audio = 0; + uint32_t lba = cdrom_msf_to_lba(sector, ismsf, + cdrom_sector_type, vendor_type); + + if (dev->ops->get_track_type) + audio = dev->ops->get_track_type(dev->local, lba); + + audio &= CD_TRACK_AUDIO; + + return audio; +} + int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, int cdrom_sector_type, const int cdrom_sector_flags, @@ -2298,38 +2357,12 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int uint8_t *temp_b; uint8_t *b = temp_b = buffer; int audio = 0; - uint32_t lba; + uint32_t lba = cdrom_msf_to_lba(sector, ismsf, + cdrom_sector_type, vendor_type); int mode2 = 0; *len = 0; - if (ismsf) { - const int m = (pos >> 16) & 0xff; - const int s = (pos >> 8) & 0xff; - const int f = pos & 0xff; - - lba = MSFtoLBA(m, s, f) - 150; - } else { - switch (vendor_type) { - case 0x00: - lba = pos; - break; - case 0x40: { - const int m = bcd2bin((pos >> 24) & 0xff); - const int s = bcd2bin((pos >> 16) & 0xff); - const int f = bcd2bin((pos >> 8) & 0xff); - - lba = MSFtoLBA(m, s, f) - 150; - break; - } case 0x80: - lba = bcd2bin((pos >> 24) & 0xff); - break; - /* Never used values but the compiler complains. */ - default: - lba = 0; - } - } - if (dev->ops->get_track_type) audio = dev->ops->get_track_type(dev->local, lba); diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 30c6476fb..5ff4170a2 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -425,6 +425,8 @@ extern uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint #endif extern uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, uint8_t *b, const uint8_t track, const int type); +extern int cdrom_is_track_audio(cdrom_t *dev, const int sector, const int ismsf, + int cdrom_sector_type, const uint8_t vendor_type); extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int ismsf, int cdrom_sector_type, const int cdrom_sector_flags, int *len, const uint8_t vendor_type); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 246f185e8..95c8c3640 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -2610,6 +2610,11 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->sector_len = 256; dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + if (cdrom_is_track_audio(dev->drv, dev->sector_pos, msf, + dev->sector_type, 0x00)) { + scsi_cdrom_illegal_mode(dev); + ret = 0; + } scsi_cdrom_log(dev->log, "READ (6): Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; @@ -2617,6 +2622,12 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + if (cdrom_is_track_audio(dev->drv, dev->sector_pos, msf, + dev->sector_type, dev->use_cdb_9 ? + (cdb[9] & 0xc0) : 0x00)) { + scsi_cdrom_illegal_mode(dev); + ret = 0; + } scsi_cdrom_log(dev->log, "READ (10): Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; @@ -2627,6 +2638,12 @@ scsi_cdrom_command(scsi_common_t *sc, const uint8_t *cdb) dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + if (cdrom_is_track_audio(dev->drv, dev->sector_pos, msf, + dev->sector_type, dev->use_cdb_9 ? + (cdb[9] & 0xc0) : 0x00)) { + scsi_cdrom_illegal_mode(dev); + ret = 0; + } scsi_cdrom_log(dev->log, "READ (12): Length: %i, LBA: %i\n", dev->sector_len, dev->sector_pos); break; From 18aea4e19f2abe96ce40d84b07da2464dfc3e151 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 17 Apr 2025 00:30:12 +0200 Subject: [PATCH 0735/1190] CD-ROM: Fix a newly introduced accidental division by zero. --- src/cdrom/cdrom.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 644a8e245..0f468bba0 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -2338,8 +2338,9 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int int cdrom_sector_type, const int cdrom_sector_flags, int *len, const uint8_t vendor_type) { - int pos = sector; - int ret = 0; + int pos = sector; + int ret = 0; + const int old_type = cdrom_sector_type; if ((cdrom_sector_type & 0x0f) >= 0x08) { mult = cdrom_sector_type >> 4; @@ -2358,7 +2359,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int uint8_t *b = temp_b = buffer; int audio = 0; uint32_t lba = cdrom_msf_to_lba(sector, ismsf, - cdrom_sector_type, vendor_type); + old_type, vendor_type); int mode2 = 0; *len = 0; From 37ed6662dc2c45cf8099b3170768c1ff7a103c30 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 17 Apr 2025 01:10:04 +0200 Subject: [PATCH 0736/1190] Serial mouse: do not attempt to transmit a byte if none is queued, fixes #5475. --- src/device/mouse_serial.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 96d3a867c..b50a3c987 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -146,7 +146,11 @@ sermouse_transmit_byte(mouse_t *dev, int do_next) serial_write_fifo(dev->serial, dev->buf[dev->buf_pos]); if (do_next) { - dev->buf_pos = (dev->buf_pos + 1) % dev->buf_len; + /* If we have a buffer length of 0, pretend the state is STATE_SKIP_PACKET. */ + if (dev->buf_len == 0) + dev->buf_pos = 0; + else + dev->buf_pos = (dev->buf_pos + 1) % dev->buf_len; if (dev->buf_pos != 0) sermouse_set_period(dev, dev->transmit_period); @@ -374,6 +378,7 @@ sermouse_report(mouse_t *dev) break; default: + pclog("unknown dev->format = %02X\n", dev->format); break; } @@ -747,7 +752,7 @@ sermouse_timer(void *priv) if (!dev->prompt && !dev->continuous) sermouse_transmit_report(dev, (dev->state == STATE_TRANSMIT_REPORT)); else - dev->state = STATE_IDLE; + dev->state = STATE_IDLE; break; case STATE_TRANSMIT_REPORT: case STATE_TRANSMIT: From 6ab7f61c744611fa62284e2792698c8b51d1d499 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 17 Apr 2025 01:12:39 +0200 Subject: [PATCH 0737/1190] Serial mouse: Remove the excess logging line. --- src/device/mouse_serial.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index b50a3c987..8ed4865cd 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -378,7 +378,6 @@ sermouse_report(mouse_t *dev) break; default: - pclog("unknown dev->format = %02X\n", dev->format); break; } From 629d976f8ea85e08b6049bbd2f4a492ee4f00106 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 17 Apr 2025 13:31:28 +0600 Subject: [PATCH 0738/1190] Disable OpenGL 3.x logs --- src/qt/qt_openglrenderer.cpp | 48 +++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 2e8869c09..53d29f9a8 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -145,6 +145,24 @@ const char* fragment_shader_default_color_src = " outColor.a = 1.0;\n" "}\n"; +#ifdef ENABLE_OGL3_LOG +int ogl3_do_log = ENABLE_OGL3_LOG; + +static void +ogl3_log(const char *fmt, ...) +{ + va_list ap; + + if (ogl3_do_log) { + va_start(ap, fmt); + ogl3_log_ex(fmt, ap); + va_end(ap); + } +} +#else +# define ogl3_log(fmt, ...) +#endif + static inline int next_pow2(unsigned int n) { @@ -232,8 +250,8 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log).replace("\n", "
")); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); - pclog("Could not compile shader: %s\n", log); - // pclog("Shader: %s\n", program); + ogl3_log("Could not compile shader: %s\n", log); + // ogl3_log("Shader: %s\n", program); free(log); return 0; @@ -348,7 +366,7 @@ OpenGLRenderer::create_texture(struct shader_texture *tex) tex->width = max_texture_size; if (tex->height > max_texture_size) tex->height = max_texture_size; - pclog("Create texture with size %dx%d\n", tex->width, tex->height); + ogl3_log("Create texture with size %dx%d\n", tex->width, tex->height); glw.glGenTextures(1, (GLuint *) &tex->id); glw.glBindTexture(GL_TEXTURE_2D, tex->id); glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex->wrap_mode); @@ -452,7 +470,7 @@ OpenGLRenderer::create_fbo(struct shader_fbo *fbo) glw.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->texture.id, 0); if (glw.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - pclog("Could not create framebuffer!\n"); + ogl3_log("Could not create framebuffer!\n"); glw.glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -629,12 +647,12 @@ OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) struct shader_lut_texture *tex = &gshader->lut_textures[i]; strcpy(tex->name, texture->name); - pclog("Load texture %s...\n", file); + ogl3_log("Load texture %s...\n", file); if (!load_texture(file, &tex->texture)) { //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %1").arg(file)); - pclog("Could not load texture %s!\n", file); + ogl3_log("Could not load texture %s!\n", file); failed = 1; break; } @@ -676,16 +694,16 @@ OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) if (!strlen(pass->alias)) sprintf(pass->alias, "Pass %u", (i + 1)); - pclog("Creating pass %u (%s)\n", (i + 1), pass->alias); - pclog("Loading shader %s...\n", shader->shader_fn); + ogl3_log("Creating pass %u (%s)\n", (i + 1), pass->alias); + ogl3_log("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); - pclog("Could not load shader %s\n", shader->shader_fn); + ogl3_log("Could not load shader %s\n", shader->shader_fn); failed = 1; break; } else - pclog("Shader %s loaded\n", shader->shader_fn); + ogl3_log("Shader %s loaded\n", shader->shader_fn); failed = !compile_shader(GL_VERTEX_SHADER, "#define VERTEX\n#define PARAMETER_UNIFORM\n", shader->shader_program, &pass->program.vertex_shader) || !compile_shader(GL_FRAGMENT_SHADER, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", @@ -856,15 +874,15 @@ OpenGLRenderer::initialize() glw.initializeOpenGLFunctions(); - pclog("OpenGL information: [%s] %s (%s)\n", glw.glGetString(GL_VENDOR), glw.glGetString(GL_RENDERER), glw.glGetString(GL_VERSION)); + ogl3_log("OpenGL information: [%s] %s (%s)\n", glw.glGetString(GL_VENDOR), glw.glGetString(GL_RENDERER), glw.glGetString(GL_VERSION)); glsl_version[0] = glsl_version[1] = -1; glw.glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); glw.glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); if (glsl_version[0] < 3) { throw opengl_init_error(tr("OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2").arg(glsl_version[0]).arg(glsl_version[1])); } - pclog("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); - pclog("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); + ogl3_log("Using OpenGL %s\n", glw.glGetString(GL_VERSION)); + ogl3_log("Using Shading Language %s\n", glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); glslVersion = reinterpret_cast(glw.glGetString(GL_SHADING_LANGUAGE_VERSION)); glslVersion.truncate(4); @@ -876,7 +894,7 @@ OpenGLRenderer::initialize() glslVersion.append(" core"); glw.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); + ogl3_log("Max texture size: %dx%d\n", max_texture_size, max_texture_size); glw.glEnable(GL_TEXTURE_2D); @@ -1218,7 +1236,7 @@ OpenGLRenderer::render_pass(struct render_data *data) int i; GLuint texture_unit = 0; - // pclog("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], + // ogl3_log("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], // pass->state.input_size[1], pass->state.input_texture_size[0], pass->state.input_texture_size[1], // pass->state.output_size[0], pass->state.output_size[1], pass->state.output_texture_size[0], // pass->state.output_texture_size[1], output_size[0], output_size[1]); From 05f4906eb30c11745e30bf563883594084ad835c Mon Sep 17 00:00:00 2001 From: GH Cao Date: Fri, 18 Apr 2025 00:36:04 +0800 Subject: [PATCH 0739/1190] win_dynld: use LoadLibraryA specifically --- src/qt/win_dynld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/win_dynld.c b/src/qt/win_dynld.c index 88fb632bc..e4d9d5a13 100644 --- a/src/qt/win_dynld.c +++ b/src/qt/win_dynld.c @@ -51,7 +51,7 @@ dynld_module(const char *name, dllimp_t *table) void *func; /* See if we can load the desired module. */ - if ((h = LoadLibrary(name)) == NULL) { + if ((h = LoadLibraryA(name)) == NULL) { dynld_log("DynLd(\"%s\"): library not found! (%08X)\n", name, GetLastError()); return (NULL); } From 46978a808c7e0309ca4a88f0028669d49eb177a7 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 19:56:48 +0500 Subject: [PATCH 0740/1190] Disable rich text for `ui_msgbox()`-generated dialogs No strings that gets passed to `ui_msgbox()` use HTML, and it causes newlines to be ignored unless replaced by
`MainWindow::showMessage()` can still accept rich text, but it's now optional and disabled by default --- src/network/network.c | 2 +- src/qt/qt_mainwindow.cpp | 13 +++++++------ src/qt/qt_mainwindow.hpp | 6 +++--- src/qt/qt_openglrenderer.cpp | 10 +++++----- src/qt/qt_ui.cpp | 3 +-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/network/network.c b/src/network/network.c index 047642085..52b686c7e 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -501,7 +501,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin if(net_cards_conf[net_card_current].net_type != NET_TYPE_NONE) { // We're here because of a failure - swprintf(tempmsg, sizeof_w(tempmsg), L"%ls:

%s

%ls", plat_get_string(STRING_NET_ERROR), net_drv_error, plat_get_string(STRING_NET_ERROR_DESC)); + swprintf(tempmsg, sizeof_w(tempmsg), L"%ls:\n\n%s\n\n%ls", plat_get_string(STRING_NET_ERROR), net_drv_error, plat_get_string(STRING_NET_ERROR_DESC)); ui_msgbox(MBX_ERROR, tempmsg); net_cards_conf[net_card_current].net_type = NET_TYPE_NONE; } diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 886f84dcd..760ca7d9b 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1342,17 +1342,17 @@ MainWindow::refreshMediaMenu() } void -MainWindow::showMessage(int flags, const QString &header, const QString &message) +MainWindow::showMessage(int flags, const QString &header, const QString &message, bool richText) { if (QThread::currentThread() == this->thread()) { if (!cpu_thread_running) { - showMessageForNonQtThread(flags, header, message, nullptr); + showMessageForNonQtThread(flags, header, message, richText, nullptr); } else - showMessage_(flags, header, message); + showMessage_(flags, header, message, richText); } else { std::atomic_bool done = false; - emit showMessageForNonQtThread(flags, header, message, &done); + emit showMessageForNonQtThread(flags, header, message, richText, &done); while (!done) { QThread::msleep(1); } @@ -1360,7 +1360,7 @@ MainWindow::showMessage(int flags, const QString &header, const QString &message } void -MainWindow::showMessage_(int flags, const QString &header, const QString &message, std::atomic_bool *done) +MainWindow::showMessage_(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool *done) { if (done) { *done = false; @@ -1372,7 +1372,8 @@ MainWindow::showMessage_(int flags, const QString &header, const QString &messag } else if (!(flags & (MBX_ERROR | MBX_WARNING))) { box.setIcon(QMessageBox::Warning); } - box.setTextFormat(Qt::TextFormat::RichText); + if (richText) + box.setTextFormat(Qt::TextFormat::RichText); box.exec(); if (done) { *done = true; diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 4b3f9ecae..739d179ff 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -26,7 +26,7 @@ public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); - void showMessage(int flags, const QString &header, const QString &message); + void showMessage(int flags, const QString &header, const QString &message, bool richText); void getTitle(wchar_t *title); void blitToWidget(int x, int y, int w, int h, int monitor_index); QSize getRenderWidgetSize(); @@ -55,7 +55,7 @@ signals: void setFullscreen(bool state); void setMouseCapture(bool state); - void showMessageForNonQtThread(int flags, const QString &header, const QString &message, std::atomic_bool* done); + void showMessageForNonQtThread(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool* done); void getTitleForNonQtThread(wchar_t *title); public slots: void showSettings(); @@ -123,7 +123,7 @@ private slots: void on_actionRenderer_options_triggered(); void refreshMediaMenu(); - void showMessage_(int flags, const QString &header, const QString &message, std::atomic_bool* done = nullptr); + void showMessage_(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool* done = nullptr); void getTitle_(wchar_t *title); void on_actionMCA_devices_triggered(); diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 53d29f9a8..45bae6ea7 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -200,7 +200,7 @@ OpenGLRenderer::create_program(struct shader_program *program) glw.glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); char *log = (char *) malloc(maxLength); glw.glGetProgramInfoLog(program->id, maxLength, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log).replace("\n", "
")); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Program not linked:\n\n%1").arg(log), false); // wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); free(log); return 0; @@ -247,7 +247,7 @@ OpenGLRenderer::compile_shader(GLenum shader_type, const char *prepend, const ch glw.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); char *log = (char *) malloc(length); glw.glGetShaderInfoLog(shader, length, &length, log); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log).replace("\n", "
")); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not compile shader:\n\n%1").arg(log), false); // wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); ogl3_log("Could not compile shader: %s\n", log); @@ -651,7 +651,7 @@ OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) if (!load_texture(file, &tex->texture)) { //QMessageBox::critical(main_window, tr("GLSL Error"), tr("Could not load texture: %s").arg(file)); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %1").arg(file)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load texture: %1").arg(file), false); ogl3_log("Could not load texture %s!\n", file); failed = 1; break; @@ -697,7 +697,7 @@ OpenGLRenderer::load_glslp(glsl_t *glsl, int num_shader, const char *f) ogl3_log("Creating pass %u (%s)\n", (i + 1), pass->alias); ogl3_log("Loading shader %s...\n", shader->shader_fn); if (!shader->shader_program) { - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn)); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("GLSL Error"), tr("Could not load shader: %1").arg(shader->shader_fn), false); // wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); ogl3_log("Could not load shader %s\n", shader->shader_fn); failed = 1; @@ -1115,7 +1115,7 @@ OpenGLRenderer::initialize() for (auto &flag : buf_usage) flag.test_and_set(); - main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering.")); + main_window->showMessage(MBX_ERROR | MBX_FATAL, tr("Error initializing OpenGL"), e.what() + tr("\nFalling back to software rendering."), false); context->doneCurrent(); isFinalized = true; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index b9253663b..57f8001dc 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -142,11 +142,10 @@ ui_msgbox_header(int flags, void *header, void *message) // any error in early init if (main_window == nullptr) { QMessageBox msgBox(QMessageBox::Icon::Critical, hdr, msg); - msgBox.setTextFormat(Qt::TextFormat::RichText); msgBox.exec(); } else { // else scope it to main_window - main_window->showMessage(flags, hdr, msg); + main_window->showMessage(flags, hdr, msg, false); } return 0; } From d5cc259d65c65069fb438ffd1e33116ebe2af610 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 20:47:13 +0500 Subject: [PATCH 0741/1190] Dev branch: Enable Mitsumi CD-ROM in the UI --- src/cdrom/cdrom.c | 6 ++++++ src/qt/CMakeLists.txt | 4 ++++ src/qt/qt_harddrive_common.cpp | 6 +++--- src/qt/qt_settingsstoragecontrollers.cpp | 9 +++++++++ src/qt/qt_settingsstoragecontrollers.ui | 9 --------- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 0f468bba0..44bf2811c 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -29,6 +29,9 @@ #include <86box/cdrom.h> #include <86box/cdrom_image.h> #include <86box/cdrom_interface.h> +#ifdef USE_CDROM_MITSUMI +#include <86box/cdrom_mitsumi.h> +#endif #include <86box/log.h> #include <86box/plat.h> #include <86box/plat_cdrom_ioctl.h> @@ -117,6 +120,9 @@ static const struct { } controllers[] = { // clang-format off { &cdrom_interface_none_device }, +#ifdef USE_CDROM_MITSUMI + { &mitsumi_cdrom_device }, +#endif { NULL } // clang-format on }; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index e6e45fc25..f02e3708a 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -207,6 +207,10 @@ if(WACOM) target_compile_definitions(ui PRIVATE USE_WACOM) endif() +if(CDROM_MITSUMI) + target_compile_definitions(ui PRIVATE USE_CDROM_MITSUMI) +endif() + if(WIN32) enable_language(RC) target_sources(86Box PUBLIC 86Box-qt.rc) diff --git a/src/qt/qt_harddrive_common.cpp b/src/qt/qt_harddrive_common.cpp index e0b0233f1..52ae10a98 100644 --- a/src/qt/qt_harddrive_common.cpp +++ b/src/qt/qt_harddrive_common.cpp @@ -51,7 +51,7 @@ void Harddrives::populateRemovableBuses(QAbstractItemModel *model) { model->removeRows(0, model->rowCount()); -#if 0 +#ifdef USE_CDROM_MITSUMI model->insertRows(0, 4); #else model->insertRows(0, 3); @@ -59,14 +59,14 @@ Harddrives::populateRemovableBuses(QAbstractItemModel *model) model->setData(model->index(0, 0), QObject::tr("Disabled")); model->setData(model->index(1, 0), QObject::tr("ATAPI")); model->setData(model->index(2, 0), QObject::tr("SCSI")); -#if 0 +#ifdef USE_CDROM_MITSUMI model->setData(model->index(3, 0), QObject::tr("Mitsumi")); #endif model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole); model->setData(model->index(1, 0), HDD_BUS_ATAPI, Qt::UserRole); model->setData(model->index(2, 0), HDD_BUS_SCSI, Qt::UserRole); -#if 0 +#ifdef USE_CDROM_MITSUMI model->setData(model->index(3, 0), CDROM_BUS_MITSUMI, Qt::UserRole); #endif } diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index 9bd1bda6f..6fa5906b5 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -142,6 +142,15 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxFD->setCurrentIndex(selectedRow); /*CD interface controller config*/ +#ifdef USE_CDROM_MITSUMI + ui->label_7->setVisible(true); + ui->comboBoxCDInterface->setVisible(true); + ui->pushButtonCDInterface->setVisible(true); +#else + ui->label_7->setVisible(false); + ui->comboBoxCDInterface->setVisible(false); + ui->pushButtonCDInterface->setVisible(false); +#endif c = 0; model = ui->comboBoxCDInterface->model(); removeRows = model->rowCount(); diff --git a/src/qt/qt_settingsstoragecontrollers.ui b/src/qt/qt_settingsstoragecontrollers.ui index 16d6e2494..a167e5bc1 100644 --- a/src/qt/qt_settingsstoragecontrollers.ui +++ b/src/qt/qt_settingsstoragecontrollers.ui @@ -51,9 +51,6 @@
- - false - CD-ROM Controller: @@ -61,9 +58,6 @@ - - false - 30 @@ -71,9 +65,6 @@ - - false - Configure From a4a26f8b56c1f39ef0356032bd2c6657ae3872c9 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 22:04:14 +0500 Subject: [PATCH 0742/1190] qt: Fix HDD model still being speed in the HDD list --- src/qt/qt_settingsharddisks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp index ded50ac34..32b677888 100644 --- a/src/qt/qt_settingsharddisks.cpp +++ b/src/qt/qt_settingsharddisks.cpp @@ -116,7 +116,7 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) model->setHeaderData(ColumnHeads, Qt::Horizontal, tr("H")); model->setHeaderData(ColumnSectors, Qt::Horizontal, tr("S")); model->setHeaderData(ColumnSize, Qt::Horizontal, tr("MiB")); - model->setHeaderData(ColumnSpeed, Qt::Horizontal, tr("Speed")); + model->setHeaderData(ColumnSpeed, Qt::Horizontal, tr("Model")); ui->tableView->setModel(model); for (int i = 0; i < HDD_NUM; i++) { From 4160fd6a5a00e649e57d2639ef97fbff757ef8c6 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 22:23:52 +0500 Subject: [PATCH 0743/1190] qt: Add colons to dropdown labels on the network settings page For consistency purposes --- src/qt/qt_settingsnetwork.ui | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/qt/qt_settingsnetwork.ui b/src/qt/qt_settingsnetwork.ui index 741b60648..8fb048f71 100644 --- a/src/qt/qt_settingsnetwork.ui +++ b/src/qt/qt_settingsnetwork.ui @@ -58,7 +58,7 @@
- Adapter + Adapter:
@@ -84,7 +84,7 @@ - Mode + Mode:
@@ -124,14 +124,14 @@ - Interface + Interface:
- VDE Socket + VDE Socket: @@ -197,7 +197,7 @@ - Interface + Interface:
@@ -217,7 +217,7 @@ - Mode + Mode:
@@ -237,7 +237,7 @@ - VDE Socket + VDE Socket: @@ -257,7 +257,7 @@ - Adapter + Adapter:
@@ -326,7 +326,7 @@ - VDE Socket + VDE Socket: @@ -362,7 +362,7 @@ - Interface + Interface:
@@ -382,7 +382,7 @@ - Mode + Mode:
@@ -408,7 +408,7 @@ - Adapter + Adapter:
@@ -461,7 +461,7 @@ - Mode + Mode:
@@ -481,7 +481,7 @@ - VDE Socket + VDE Socket: @@ -494,7 +494,7 @@ - Adapter + Adapter:
@@ -514,7 +514,7 @@ - Interface + Interface:
From de35961bb4a14911f64d862448754a245d310d1d Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 17:20:08 +0500 Subject: [PATCH 0744/1190] qt: Use Yu Gothic UI as the Japanese font on Windows 10 and later --- src/qt/qt_progsettings.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 0fce0d705..aa9bbe97b 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -26,6 +26,10 @@ #include #include #include +#ifdef Q_OS_WINDOWS +# include +# include +#endif extern "C" { #include <86box/86box.h> @@ -115,7 +119,11 @@ ProgSettings::getFontName(uint32_t lcid) case 0x0404: /* zh-TW */ return "Microsoft JhengHei"; case 0x0411: /* ja-JP */ - return "Meiryo UI"; + /* Check for Windows 10 or later to choose the appropriate system font */ + if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) + return "Yu Gothic UI"; + else + return "Meiryo UI"; case 0x0412: /* ko-KR */ return "Malgun Gothic"; case 0x0804: /* zh-CN */ From e1007d2377f572639ac9d847cfca371d2fffac20 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 21:52:32 +0500 Subject: [PATCH 0745/1190] Get rid of Windows LCIDs as numeric language IDs --- src/86box.c | 3 +- src/config.c | 6 +-- src/include/86box/86box.h | 8 ++- src/include/86box/plat.h | 4 +- src/qt/qt_platform.cpp | 53 +++--------------- src/qt/qt_progsettings.cpp | 108 ++++++++++++++++++++++++++----------- src/qt/qt_progsettings.hpp | 16 +++--- src/unix/unix.c | 10 ++-- 8 files changed, 106 insertions(+), 102 deletions(-) diff --git a/src/86box.c b/src/86box.c index ad1cfc519..168e8a8dc 100644 --- a/src/86box.c +++ b/src/86box.c @@ -160,6 +160,7 @@ int window_remember; int vid_resize; /* (C) allow resizing */ int invert_display = 0; /* (C) invert the display */ int suppress_overscan = 0; /* (C) suppress overscans */ +int lang_id = 0; /* (C) language id */ int scale = 0; /* (C) screen scale factor */ int dpi_scale = 0; /* (C) DPI scaling of the emulated screen */ @@ -584,7 +585,7 @@ pc_init(int argc, char *argv[]) uint32_t *uid; uint32_t *shwnd; #endif - uint32_t lang_init = 0; + int lang_init = 0; /* Grab the executable's full path. */ plat_get_exe_name(exe_path, sizeof(exe_path) - 1); diff --git a/src/config.c b/src/config.c index 6f023cf67..b3de77d71 100644 --- a/src/config.c +++ b/src/config.c @@ -186,7 +186,7 @@ load_general(void) if (p != NULL) lang_id = plat_language_code(p); else - lang_id = 0xffff; + lang_id = plat_language_code(DEFAULT_LANGUAGE); mouse_sensitivity = ini_section_get_double(cat, "mouse_sensitivity", 1.0); if (mouse_sensitivity < 0.1) @@ -1842,7 +1842,7 @@ config_load(void) cassette_pcm = 0; cassette_ui_writeprot = 0; - lang_id = DEFAULT_LANGUAGE; + lang_id = plat_language_code(DEFAULT_LANGUAGE); config_log("Config file not present or invalid!\n"); } else { @@ -2029,7 +2029,7 @@ save_general(void) else ini_section_delete_var(cat, "mouse_sensitivity"); - if (lang_id == DEFAULT_LANGUAGE) + if (lang_id == plat_language_code(DEFAULT_LANGUAGE)) ini_section_delete_var(cat, "language"); else { plat_language_code_r(lang_id, buffer, 511); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index ddca937f1..c85311688 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -44,8 +44,8 @@ /* Max UUID Length */ #define MAX_UUID_LEN 64 -/* Default language 0xFFFF = from system, 0x409 = en-US */ -#define DEFAULT_LANGUAGE 0xffff +/* Default language code */ +#define DEFAULT_LANGUAGE "system" #define POSTCARDS_NUM 4 #define POSTCARD_MASK (POSTCARDS_NUM - 1) @@ -84,8 +84,6 @@ extern "C" { #endif /* Global variables. */ -extern uint32_t lang_sys; /* (-) system language code */ - extern int dump_on_exit; /* (O) dump regs on exit*/ extern int start_in_fullscreen; /* (O) start in fullscreen */ #ifdef _WIN32 @@ -117,7 +115,7 @@ extern int window_remember; extern int vid_resize; /* (C) allow resizing */ extern int invert_display; /* (C) invert the display */ extern int suppress_overscan; /* (C) suppress overscans */ -extern uint32_t lang_id; /* (C) language code identifier */ +extern int lang_id; /* (C) language id */ extern int scale; /* (C) screen scale factor */ extern int dpi_scale; /* (C) DPI scaling of the emulated screen */ extern int vid_api; /* (C) video renderer */ diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 7ed6e80d4..bbc673dcf 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -160,8 +160,8 @@ extern int plat_vidapi(const char *name); extern char *plat_vidapi_name(int api); extern void plat_resize(int x, int y, int monitor_index); extern void plat_resize_request(int x, int y, int monitor_index); -extern uint32_t plat_language_code(char *langcode); -extern void plat_language_code_r(uint32_t lcid, char *outbuf, int len); +extern int plat_language_code(char *langcode); +extern void plat_language_code_r(int id, char *outbuf, int len); extern void plat_get_cpu_string(char *outbuf, uint8_t len); extern void plat_set_thread_name(void *thread, const char *name); extern void plat_break(void); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index e8a02fc3b..0f792feda 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -140,7 +140,6 @@ int update_icons = 1; int kbd_req_capture = 0; int hide_status_bar = 0; int hide_tool_bar = 0; -uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US int stricmp(const char *s1, const char *s2) @@ -461,58 +460,18 @@ plat_power_off(void) QTimer::singleShot(0, (const QWidget *) main_window, &QMainWindow::close); } -extern "C++" { -QMap> ProgSettings::lcid_langcode = { - { 0x0403, { "ca-ES", "Catalan (Spain)" } }, - { 0x0804, { "zh-CN", "Chinese (Simplified)" } }, - { 0x0404, { "zh-TW", "Chinese (Traditional)" } }, - { 0x041A, { "hr-HR", "Croatian (Croatia)" } }, - { 0x0405, { "cs-CZ", "Czech (Czech Republic)" } }, - { 0x0407, { "de-DE", "German (Germany)" } }, - { 0x0809, { "en-GB", "English (United Kingdom)" }}, - { 0x0409, { "en-US", "English (United States)" } }, - { 0x040B, { "fi-FI", "Finnish (Finland)" } }, - { 0x040C, { "fr-FR", "French (France)" } }, - { 0x040E, { "hu-HU", "Hungarian (Hungary)" } }, - { 0x0410, { "it-IT", "Italian (Italy)" } }, - { 0x0411, { "ja-JP", "Japanese (Japan)" } }, - { 0x0412, { "ko-KR", "Korean (Korea)" } }, - { 0x0413, { "nl-NL", "Dutch (Netherlands)" } }, - { 0x0415, { "pl-PL", "Polish (Poland)" } }, - { 0x0416, { "pt-BR", "Portuguese (Brazil)" } }, - { 0x0816, { "pt-PT", "Portuguese (Portugal)" } }, - { 0x0419, { "ru-RU", "Russian (Russia)" } }, - { 0x041B, { "sk-SK", "Slovak (Slovakia)" } }, - { 0x0424, { "sl-SI", "Slovenian (Slovenia)" } }, - { 0x0C0A, { "es-ES", "Spanish (Spain, Modern Sort)" } }, - { 0x041F, { "tr-TR", "Turkish (Turkey)" } }, - { 0x0422, { "uk-UA", "Ukrainian (Ukraine)" } }, - { 0x042A, { "vi-VN", "Vietnamese (Vietnam)" } }, - { 0xFFFF, { "system", "(System Default)" } }, -}; -} - -/* Sets up the program language before initialization. */ -uint32_t +/* Converts the language code string to a numeric language ID */ +int plat_language_code(char *langcode) { - for (auto &curKey : ProgSettings::lcid_langcode.keys()) { - if (ProgSettings::lcid_langcode[curKey].first == langcode) { - return curKey; - } - } - return 0xFFFF; + return ProgSettings::languageCodeToId(QString(langcode)); } -/* Converts back the language code to LCID */ +/* Converts the numeric language ID to a language code string */ void -plat_language_code_r(uint32_t lcid, char *outbuf, int len) +plat_language_code_r(int id, char *outbuf, int len) { - if (!ProgSettings::lcid_langcode.contains(lcid)) { - qstrncpy(outbuf, "system", len); - return; - } - qstrncpy(outbuf, ProgSettings::lcid_langcode[lcid].first.toUtf8().constData(), len); + qstrncpy(outbuf, ProgSettings::languageIdToCode(id).toUtf8().constData(), len); return; } diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index aa9bbe97b..3903c9d9f 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -45,18 +45,45 @@ extern MainWindow *main_window; ProgSettings::CustomTranslator *ProgSettings::translator = nullptr; QTranslator *ProgSettings::qtTranslator = nullptr; +QVector> ProgSettings::languages = { + { "system", "(System Default)" }, + { "ca-ES", "Catalan (Spain)" }, + { "zh-CN", "Chinese (Simplified)" }, + { "zh-TW", "Chinese (Traditional)" }, + { "hr-HR", "Croatian (Croatia)" }, + { "cs-CZ", "Czech (Czech Republic)" }, + { "de-DE", "German (Germany)" }, + { "en-GB", "English (United Kingdom)" }, + { "en-US", "English (United States)" }, + { "fi-FI", "Finnish (Finland)" }, + { "fr-FR", "French (France)" }, + { "hu-HU", "Hungarian (Hungary)" }, + { "it-IT", "Italian (Italy)" }, + { "ja-JP", "Japanese (Japan)" }, + { "ko-KR", "Korean (Korea)" }, + { "nl-NL", "Dutch (Netherlands)" }, + { "pl-PL", "Polish (Poland)" }, + { "pt-BR", "Portuguese (Brazil)" }, + { "pt-PT", "Portuguese (Portugal)" }, + { "ru-RU", "Russian (Russia)" }, + { "sk-SK", "Slovak (Slovakia)" }, + { "sl-SI", "Slovenian (Slovenia)" }, + { "es-ES", "Spanish (Spain)" }, + { "tr-TR", "Turkish (Turkey)" }, + { "uk-UA", "Ukrainian (Ukraine)" }, + { "vi-VN", "Vietnamese (Vietnam)" }, +}; + ProgSettings::ProgSettings(QWidget *parent) : QDialog(parent) , ui(new Ui::ProgSettings) { ui->setupUi(this); - ui->comboBoxLanguage->setItemData(0, 0xFFFF); - for (auto i = lcid_langcode.begin(); i != lcid_langcode.end(); i++) { - if (i.key() == 0xFFFF) - continue; - ui->comboBoxLanguage->addItem(lcid_langcode[i.key()].second, i.key()); - if (i.key() == lang_id) { - ui->comboBoxLanguage->setCurrentIndex(ui->comboBoxLanguage->findData(i.key())); + ui->comboBoxLanguage->setItemData(0, 0); + for (int i = 1; i < languages.length(); i++) { + ui->comboBoxLanguage->addItem(languages[i].second, i); + if (i == lang_id) { + ui->comboBoxLanguage->setCurrentIndex(ui->comboBoxLanguage->findData(i)); } } ui->comboBoxLanguage->model()->sort(Qt::AscendingOrder); @@ -78,7 +105,7 @@ ProgSettings::ProgSettings(QWidget *parent) void ProgSettings::accept() { - lang_id = ui->comboBoxLanguage->currentData().toUInt(); + lang_id = ui->comboBoxLanguage->currentData().toInt(); open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0; confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; @@ -113,27 +140,46 @@ ProgSettings::~ProgSettings() /* Return the standard font name on Windows, which is overridden per-language to prevent CJK fonts with embedded bitmaps being chosen as a fallback. */ QString -ProgSettings::getFontName(uint32_t lcid) +ProgSettings::getFontName(int langId) { - switch (lcid) { - case 0x0404: /* zh-TW */ - return "Microsoft JhengHei"; - case 0x0411: /* ja-JP */ - /* Check for Windows 10 or later to choose the appropriate system font */ - if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) - return "Yu Gothic UI"; - else - return "Meiryo UI"; - case 0x0412: /* ko-KR */ - return "Malgun Gothic"; - case 0x0804: /* zh-CN */ - return "Microsoft YaHei"; - default: - return "Segoe UI"; - } + QString langCode = languageIdToCode(lang_id); + if (langCode == "ja-JP") { + /* Check for Windows 10 or later to choose the appropriate system font */ + if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) + return "Yu Gothic UI"; + else + return "Meiryo UI"; + } else if (langCode == "ko-KR") + return "Malgun Gothic"; + else if (langCode == "zh-CN") + return "Microsoft YaHei"; + else if (langCode == "zh-TW") + return "Microsoft JhengHei"; + else + return "Segoe UI"; } #endif +int +ProgSettings::languageCodeToId(QString langCode) +{ + for (int i = 0; i < languages.length(); i++) { + if (languages[i].first == langCode) { + return i; + } + } + return 0; +} + +QString +ProgSettings::languageIdToCode(int id) +{ + if ((id == 0) || (id >= languages.length())) { + return "system"; + } + return languages[id].first; +} + void ProgSettings::loadTranslators(QObject *parent) { @@ -148,7 +194,7 @@ ProgSettings::loadTranslators(QObject *parent) qtTranslator = new QTranslator(parent); translator = new CustomTranslator(parent); QString localetofilename = ""; - if (lang_id == 0xFFFF || lcid_langcode.contains(lang_id) == false) { + if (lang_id == 0 || lang_id >= languages.length()) { for (int i = 0; i < QLocale::system().uiLanguages().size(); i++) { localetofilename = QLocale::system().uiLanguages()[i]; if (translator->load(QLatin1String("86box_") + localetofilename, QLatin1String(":/"))) { @@ -166,12 +212,12 @@ ProgSettings::loadTranslators(QObject *parent) } } } else { - translator->load(QLatin1String("86box_") + lcid_langcode[lang_id].first, QLatin1String(":/")); + translator->load(QLatin1String("86box_") + languages[lang_id].first, QLatin1String(":/")); QCoreApplication::installTranslator(translator); - if (!qtTranslator->load(QLatin1String("qtbase_") + QString(lcid_langcode[lang_id].first).replace('-', '_'), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) - if (!qtTranslator->load(QLatin1String("qtbase_") + QString(lcid_langcode[lang_id].first).left(QString(lcid_langcode[lang_id].first).indexOf('-')), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) - if(!qtTranslator->load(QLatin1String("qt_") + QString(lcid_langcode[lang_id].first).replace('-', '_'), QApplication::applicationDirPath() + "/./translations/")) - qtTranslator->load(QLatin1String("qt_") + QString(lcid_langcode[lang_id].first).replace('-', '_'), QLatin1String(":/")); + if (!qtTranslator->load(QLatin1String("qtbase_") + QString(languages[lang_id].first).replace('-', '_'), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + if (!qtTranslator->load(QLatin1String("qtbase_") + QString(languages[lang_id].first).left(QString(languages[lang_id].first).indexOf('-')), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + if(!qtTranslator->load(QLatin1String("qt_") + QString(languages[lang_id].first).replace('-', '_'), QApplication::applicationDirPath() + "/./translations/")) + qtTranslator->load(QLatin1String("qt_") + QString(languages[lang_id].first).replace('-', '_'), QLatin1String(":/")); QCoreApplication::installTranslator(qtTranslator); } diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 1c7295f56..31600e7f1 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -15,10 +15,12 @@ public: explicit ProgSettings(QWidget *parent = nullptr); ~ProgSettings(); #ifdef Q_OS_WINDOWS - static QString getFontName(uint32_t lcid); + static QString getFontName(int langId); #endif - static void loadTranslators(QObject *parent = nullptr); - static void reloadStrings(); + static int languageCodeToId(QString langCode); + static QString languageIdToCode(int id); + static void loadTranslators(QObject *parent = nullptr); + static void reloadStrings(); class CustomTranslator : public QTranslator { public: CustomTranslator(QObject *parent = nullptr) @@ -31,10 +33,10 @@ public: return QTranslator::translate("", sourceText, disambiguation, n); } }; - static CustomTranslator *translator; - static QTranslator *qtTranslator; - static QMap> lcid_langcode; - static QMap translatedstrings; + static CustomTranslator *translator; + static QTranslator *qtTranslator; + static QVector> languages; + static QMap translatedstrings; protected slots: void accept() override; diff --git a/src/unix/unix.c b/src/unix/unix.c index c41aee2a4..395e6f540 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -71,8 +71,6 @@ SDL_mutex *blitmtx; SDL_threadID eventthread; static int exit_event = 0; static int fullscreen_pending = 0; -uint32_t lang_id = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US -uint32_t lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US static const uint16_t sdl_to_xt[0x200] = { [SDL_SCANCODE_ESCAPE] = 0x01, @@ -1378,8 +1376,8 @@ plat_vidapi_name(UNUSED(int i)) return "default"; } -/* Sets up the program language before initialization. */ -uint32_t +/* Converts the language code string to a numeric language ID */ +int plat_language_code(UNUSED(char *langcode)) { /* or maybe not */ @@ -1419,9 +1417,9 @@ plat_set_thread_name(void *thread, const char *name) #endif } -/* Converts back the language code to LCID */ +/* Converts the numeric language ID to a language code string */ void -plat_language_code_r(UNUSED(uint32_t lcid), UNUSED(char *outbuf), UNUSED(int len)) +plat_language_code_r(UNUSED(int id), UNUSED(char *outbuf), UNUSED(int len)) { /* or maybe not */ return; From b6483a20cf023b71ff0781eae403085dfff1033f Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 21:54:39 +0500 Subject: [PATCH 0746/1190] languages: French translation updates by jvernet Co-Authored-by: jvernet --- src/qt/languages/fr-FR.po | 138 +++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index ebb181a30..0701a188e 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -40,7 +40,7 @@ msgid "Hide &toolbar" msgstr "Masquer la &barre d'outils" msgid "&Resizeable window" -msgstr "Fenètre &Retaillable" +msgstr "Fenêtre &Redimensionnable" msgid "R&emember size && position" msgstr "S&auvegarder taille && position" @@ -61,7 +61,7 @@ msgid "&VNC" msgstr "&VNC" msgid "Specify dimensions..." -msgstr "Specifier dimensions..." +msgstr "Spécifier dimensions..." msgid "F&orce 4:3 display ratio" msgstr "F&orcer 4:3" @@ -100,7 +100,7 @@ msgid "&8x" msgstr "&8x" msgid "Filter method" -msgstr "Methode Filtre" +msgstr "Méthode Filtre" msgid "&Nearest" msgstr "&Plus proche" @@ -157,7 +157,7 @@ msgid "&White monitor" msgstr "Moniteur &Blanc" msgid "Grayscale &conversion type" -msgstr "Grayscale &conversion type" +msgstr "Mode &Conversion tons de gris" msgid "BT&601 (NTSC/PAL)" msgstr "BT&601 (NTSC/PAL)" @@ -169,7 +169,7 @@ msgid "&Average" msgstr "&Moyenne" msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" -msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan CGA/PCjr/Tandy/E&GA/(S)VGA" msgid "Change contrast for &monochrome display" msgstr "Modifier contraste affichage &monochrome" @@ -205,7 +205,7 @@ msgid "Begin trace" msgstr "Démarrer traces" msgid "End trace" -msgstr "Finir traces" +msgstr "Arrêter traces" msgid "&Help" msgstr "&Aide" @@ -244,7 +244,7 @@ msgid "&Image..." msgstr "&Image..." msgid "E&xport to 86F..." -msgstr "E&xport vers 86F..." +msgstr "E&xporter vers 86F..." msgid "&Mute" msgstr "&Couper" @@ -301,7 +301,7 @@ msgid "Settings" msgstr "Réglages" msgid "Specify Main Window Dimensions" -msgstr "Spécifier le détournement de la fenêtre principale" +msgstr "Spécifier les dimensions de la fenêtre principale" msgid "OK" msgstr "OK" @@ -349,7 +349,7 @@ msgid "Configure" msgstr "Configurer" msgid "CPU type:" -msgstr "Type du processeur:" +msgstr "Type de processeur:" msgid "Speed:" msgstr "Vitesse:" @@ -403,7 +403,7 @@ msgid "Mouse:" msgstr "Souris:" msgid "Joystick:" -msgstr "Manette de commande:" +msgstr "Manette:" msgid "Joystick 1..." msgstr "Manette 1..." @@ -607,7 +607,7 @@ msgid "ISA RTC:" msgstr "Horloge temps réel ISA:" msgid "ISA Memory Expansion" -msgstr "Expansion de la mémoire ISA" +msgstr "Extension de mémoire ISA" msgid "Card 1:" msgstr "Carte 1:" @@ -670,7 +670,7 @@ msgid "Off" msgstr "Désactivé" msgid "All images" -msgstr "Tous les images" +msgstr "Toutes les images" msgid "Basic sector images" msgstr "Images basiques du secteur" @@ -862,16 +862,16 @@ msgid "Hardware not available" msgstr "Matériel non disponible" msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." -msgstr "Assurez-vous que %1 est installé et que vou utilisez une connexion réseau compatible avec %1." +msgstr "Assurez-vous que %1 est installé et que vous utilisez une connexion réseau compatible avec %1." msgid "Invalid configuration" msgstr "Configuration non valide" msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." -msgstr "%1 est nécessair pour la conversion automatique des fichiers PostScript dans PDF.\n\nTous les documents envoyés à l'imprimante générique PostScript seront sauvés comme des fichiers PostScript (.ps)." +msgstr "%1 est nécessaire pour la conversion automatique des fichiers PostScript en PDF.\n\nTous les documents envoyés à l'imprimante générique PostScript seront sauvés en tant que fichiers PostScript (.ps)." msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." -msgstr "%1 est nécessair pour la conversion automatique des fichiers PCL dans PDF.\n\nTous les documents envoyés à l'imprimante générique PCL seront sauvés comme des fichiers Printer Command Language (.pcl)." +msgstr "%1 est nécessaire pour la conversion automatique des fichiers PCL en PDF.\n\nTous les documents envoyés à l'imprimante générique PCL seront sauvés en tant quefichiers Printer Command Language (.pcl)." msgid "Entering fullscreen mode" msgstr "Entrer en mode plein écran" @@ -904,7 +904,7 @@ msgid "You are loading an unsupported configuration" msgstr "Vous chargez une configuration non prise en charge" msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." -msgstr "La filtrage du type du processeur sur la base de la machine sélectionné est désactivé pur cette machine émulée.\n\nCela permet de sélectionner une processeur que est sinon incompatible avec la machine sélectionné. Cependant, il pourrait y avoir des incompatibilités avec le BIOS de la machine ou autres logiciels.\n\nL'activatione de cette configuration non est officiellement prise en charge et tout rapport de bogue peut être fermé comme étant invalide." +msgstr "Le filtrage du type du processeur sur la base de la machine sélectionnée est désactivé pur cette machine émulée.\n\nCela permet de sélectionner un processeur qui est sinon incompatible avec la machine sélectionné. Cependant, il pourrait y avoir des incompatibilités avec le BIOS de la machine ou autres logiciels.\n\nL'activation de cette configuration non officiellement prise en charge implique que tout rapport de bogue peut être fermé comme étant invalide." msgid "Continue" msgstr "Continuer" @@ -928,7 +928,7 @@ msgid "Pause execution" msgstr "Pause de l'exécution" msgid "Press Ctrl+Alt+Del" -msgstr "Appuyer sur Ctrl+Alt+Suppr." +msgstr "Appuyer sur Ctrl+Alt+Suppr" msgid "Press Ctrl+Alt+Esc" msgstr "Appuyer sur Ctrl+Alt+Esc" @@ -958,13 +958,13 @@ msgid "Add Existing Hard Disk" msgstr "Ajouter un disque dur existant" msgid "HDI disk images cannot be larger than 4 GB." -msgstr "Les images de disque HDI ne peuvent pas avoir une taille supériure à Go." +msgstr "Les images de disque HDI ne peuvent pas avoir une taille supérieure à 4 Go." msgid "Disk images cannot be larger than 127 GB." -msgstr "Les images de disque ne peuvent pas avoir un taille supérieure à 127 Go." +msgstr "Les images de disque ne peuvent pas avoir une taille supérieure à 127 Go." msgid "Hard disk images" -msgstr "Images de dique dur" +msgstr "Images de disque dur" msgid "Unable to read file" msgstr "Impossible de lire le fichier" @@ -973,10 +973,10 @@ msgid "Unable to write file" msgstr "Impossible d'écrire le fichier" msgid "HDI or HDX images with a sector size other than 512 are not supported." -msgstr "Les images HDI ou HDX avec une taille de secteur différente de 512 non sont pas prises en charge." +msgstr "Les images HDI ou HDX avec une taille de secteur différente de 512 ne sont pas prises en charge." msgid "Disk image file already exists" -msgstr "Le fichier de l'image disque existe déjà." +msgstr "Le fichier de l'image disque existe déjà" msgid "Please specify a valid file name." msgstr "Veuillez spécifier un nom de fichier valide." @@ -1048,10 +1048,10 @@ msgid "Differencing VHD (.vhd)" msgstr "VHD à différenciation (.vhd)" msgid "Large blocks (2 MB)" -msgstr "Blocs grands (2 Mo)" +msgstr "Grands Blocs (2 Mo)" msgid "Small blocks (512 KB)" -msgstr "Blocs petits (512 Ko)" +msgstr "Petits Blocs (512 Ko)" msgid "VHD files" msgstr "Fichiers VHD" @@ -1060,10 +1060,10 @@ msgid "Select the parent VHD" msgstr "Sélectionnez le VHD parent" msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" -msgstr "Il est possible que l'image parente a été modifié après la création de l'image à différenciation.\n\nIl est même possible que les fichiers de l'mage ont été déplacés ou copiés ou il existe un bogue dans le programme que a créé ce disque.\n\nVoulez-vous réparer l'horodatage?" +msgstr "Il est possible que l'image parente ai été modifiée après la création de l'image à différenciation.\n\nIl est même possible que les fichiers de l’image ont été déplacés ou copiés ou il existe un bogue dans le programme qui a créé ce disque.\n\nVoulez-vous réparer l'horodatage?" msgid "Parent and child disk timestamps do not match" -msgstr "Les horodatages des disques parent et enfant ne correspondent pas" +msgstr "Les horodatages des disques parents et enfants ne correspondent pas" msgid "Could not fix VHD timestamp." msgstr "Impossible de réparer l'horodatage du VHD." @@ -1174,7 +1174,7 @@ msgid "Failed to initialize network driver" msgstr "Échec de l'initialisation du pilote réseau" msgid "The network configuration will be switched to the null driver" -msgstr "La configuration du réseau passera au pilote nul" +msgstr "La configuration du réseau passera au pilote NULL" msgid "Mouse sensitivity:" msgstr "Sensibilité de la souris:" @@ -1195,7 +1195,7 @@ msgid "Fast" msgstr "Rapide" msgid "&Auto-pause on focus loss" -msgstr "&Pause automatique à perte de mise au point" +msgstr "&Pause automatique à perte de focus" msgid "WinBox is no longer supported" msgstr "WinBox n'est plus pris en charge" @@ -1225,13 +1225,13 @@ msgid "List of MCA devices:" msgstr "Liste des dispositifs MCA :" msgid "Tablet tool" -msgstr "Nástroj pro tablety" +msgstr "Outil Tablette" msgid "Qt (OpenGL &ES)" msgstr "Qt (OpenGL &ES)" msgid "About Qt" -msgstr "O programu Qt" +msgstr "A propos de Qt" msgid "MCA devices..." msgstr "Dispositifs MCA..." @@ -1270,7 +1270,7 @@ msgid "Unknown Bus" msgstr "Bus inconnu" msgid "Null Driver" -msgstr "Pilote nul" +msgstr "Pilote NULL" msgid "NIC %1 (%2) %3" msgstr "NIC %1 (%2) %3" @@ -1282,7 +1282,7 @@ msgid "Use target framerate:" msgstr "Utiliser le taux de rafraîchissement cible:" msgid " fps" -msgstr " mages par seconde" +msgstr " Images par seconde" msgid "VSync" msgstr "VSync" @@ -1330,7 +1330,7 @@ msgid "I Copied It" msgstr "Je l'ai copié" msgid "86Box Monitor #" -msgstr "Moniteur 86Box " +msgstr "Moniteur 86Box" msgid "No MCA devices." msgstr "Pas de dispositifs MCA." @@ -1621,7 +1621,7 @@ msgid "Enable Game port" msgstr "Activer le port de jeu" msgid "Surround module" -msgstr "Module d'ambiance" +msgstr "Module Surround" msgid "CODEC" msgstr "CODEC" @@ -1846,7 +1846,7 @@ msgid "2 MB" msgstr "2 Mo" msgid "8 MB" -msgstr " 8 Mo" +msgstr "8 Mo" msgid "28 MB" msgstr "28 Mo" @@ -2002,10 +2002,10 @@ msgid "Stereo LPT DAC" msgstr "Convertisseur numérique stéréo LPT" msgid "Generic Text Printer" -msgstr "Imprimante de texte générique" +msgstr "Imprimante Texte générique" msgid "Generic ESC/P Dot-Matrix Printer" -msgstr "Imprimant générique ESC/P à matrice à points" +msgstr "Imprimante matricielle générique ESC/P" msgid "Generic PostScript Printer" msgstr "Imprimante PostScript générique" @@ -2062,100 +2062,100 @@ msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] Disque RAM (vitesse maximale)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "" +msgstr "[Generic] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "" +msgstr "[Generic] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "" +msgstr "[Generic] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "" +msgstr "[Generic] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" -msgstr "Clon IBM 8514/A (ISA)" +msgstr "Clone IBM 8514/A (ISA)" msgid "Vendor" msgstr "Fabricant" msgid "Generic PC/XT Memory Expansion" -msgstr "Expansion de la mémoire générique PC/XT" +msgstr "Extension de mémoire générique PC/XT" msgid "Generic PC/AT Memory Expansion" -msgstr "Expansion de la mémoire générique PC/AT" +msgstr "Extension de mémoire générique PC/AT" msgid "Unable to find Dot-Matrix fonts" -msgstr "Impossible de trouver les polices à matrice à points" +msgstr "Impossible de trouver les polices matricielles" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." -msgstr "Les polices TrueType dans le répertoire \"roms/printer/fonts\" sont nécessaires à l'émulation de l'imprimante générique ESC/P à matrice à points." +msgstr "Les polices TrueType dans le répertoire \"roms/printer/fonts\" sont nécessaires à l'émulation de l'imprimante générique ESC/P matricielle." msgid "Inhibit multimedia keys" -msgstr "" +msgstr "Désactiver les touches multimédia" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "Demander confirmation avant de sauvegarder les réglages" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "Demander confirmation avant Hard Reset" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "Demander confirmation avant de quitter" msgid "Display hotkey message when entering full-screen mode" -msgstr "" +msgstr "Afficher Raccourcis Clavier avant de passer en plein écran" msgid "Options" -msgstr "" +msgstr "Options" msgid "Model:" -msgstr "" +msgstr "Modèle:" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Impossible d’initialiser le moteur de rendu Vulkan." msgid "GLSL Error" -msgstr "" +msgstr "Erreur GLSL" msgid "Could not load shader: %1" -msgstr "" +msgstr "Impossible de charger le shaker %1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "OpenGL version 3.0 ou supérieur requis. Version installée: %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "Impossible de charger la texture %1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "Impossible de compiler le shader:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "Programme non linké:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "Gestionnaire de shader" msgid "Shader Configuration" -msgstr "" +msgstr "Configuration Shader" msgid "Add" -msgstr "" +msgstr "Ajouter" msgid "Move up" -msgstr "" +msgstr "Monter" msgid "Move down" -msgstr "" +msgstr "Descendre" msgid "Could not load file %1" -msgstr "" +msgstr "Impossible de charger le fichier %1" From 0d1f3a61cd271fc091d32570c525d6504590e4bb Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 16 Apr 2025 22:03:06 +0500 Subject: [PATCH 0747/1190] languages: Fix HDD model still being speed in the HDD list --- src/qt/languages/86box.pot | 3 +++ src/qt/languages/ca-ES.po | 3 +++ src/qt/languages/cs-CZ.po | 3 +++ src/qt/languages/de-DE.po | 3 +++ src/qt/languages/es-ES.po | 3 +++ src/qt/languages/fi-FI.po | 3 +++ src/qt/languages/fr-FR.po | 3 +++ src/qt/languages/hr-HR.po | 3 +++ src/qt/languages/hu-HU.po | 3 +++ src/qt/languages/it-IT.po | 3 +++ src/qt/languages/ja-JP.po | 3 +++ src/qt/languages/ko-KR.po | 3 +++ src/qt/languages/nl-NL.po | 3 +++ src/qt/languages/pl-PL.po | 3 +++ src/qt/languages/pt-BR.po | 3 +++ src/qt/languages/pt-PT.po | 3 +++ src/qt/languages/ru-RU.po | 3 +++ src/qt/languages/sk-SK.po | 3 +++ src/qt/languages/sl-SI.po | 3 +++ src/qt/languages/tr-TR.po | 3 +++ src/qt/languages/uk-UA.po | 3 +++ src/qt/languages/vi-VN.po | 3 +++ src/qt/languages/zh-CN.po | 3 +++ src/qt/languages/zh-TW.po | 3 +++ 24 files changed, 72 insertions(+) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 1d151a9d9..74481e068 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -2124,6 +2124,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 9dec41c32..94b17adb3 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 2098fe018..e6a172e66 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 2088e4141..eead942eb 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2121,6 +2121,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index bc11a4d4c..269d2f75e 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -2117,6 +2117,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 34e9aeead..6f4efd607 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -2121,6 +2121,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 0701a188e..d24f21c8d 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -2118,6 +2118,9 @@ msgstr "Afficher Raccourcis Clavier avant de passer en plein écran" msgid "Options" msgstr "Options" +msgid "Model" +msgstr "Modèle" + msgid "Model:" msgstr "Modèle:" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index c1f6480c2..346346687 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 09f914860..113591409 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index c9694c3be..028d86f40 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 1c139aaec..e66c8b2c1 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 941bd740a..61f65ad98 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index fd2b66245..5e0670385 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index ab50711f6..1a4ddda37 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index db07a69ae..cfc7fa42b 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index f67ddbdf8..564932890 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index fb1908f60..3c0eb619a 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2124,6 +2124,9 @@ msgstr "Показывать сообщение о горячих клавиша msgid "Options" msgstr "Параметры" +msgid "Model" +msgstr "Модель" + msgid "Model:" msgstr "Модель:" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 5080c49b5..1121aefb6 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -2119,6 +2119,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index c34fb6f7e..e3e8dba95 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index b7a59b620..2abe174ee 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 3145f5e34..7514e2fff 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -2124,6 +2124,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 932150f7b..d05396430 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 18f5a8fb8..450f148cf 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 9dbf51c70..c53753d28 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -2118,6 +2118,9 @@ msgstr "" msgid "Options" msgstr "" +msgid "Model" +msgstr "" + msgid "Model:" msgstr "" From ab9e1eae5f3f3dc9a9c6a4f687e1a9d007f79c57 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 00:18:15 +0500 Subject: [PATCH 0748/1190] languages: Remove more unused strings --- src/qt/languages/86box.pot | 9 --------- src/qt/languages/ca-ES.po | 9 --------- src/qt/languages/cs-CZ.po | 9 --------- src/qt/languages/de-DE.po | 9 --------- src/qt/languages/es-ES.po | 9 --------- src/qt/languages/fi-FI.po | 9 --------- src/qt/languages/fr-FR.po | 9 --------- src/qt/languages/hr-HR.po | 9 --------- src/qt/languages/hu-HU.po | 9 --------- src/qt/languages/it-IT.po | 9 --------- src/qt/languages/ja-JP.po | 9 --------- src/qt/languages/ko-KR.po | 9 --------- src/qt/languages/nl-NL.po | 9 --------- src/qt/languages/pl-PL.po | 9 --------- src/qt/languages/pt-BR.po | 9 --------- src/qt/languages/pt-PT.po | 9 --------- src/qt/languages/ru-RU.po | 9 --------- src/qt/languages/sk-SK.po | 9 --------- src/qt/languages/sl-SI.po | 9 --------- src/qt/languages/tr-TR.po | 9 --------- src/qt/languages/uk-UA.po | 9 --------- src/qt/languages/vi-VN.po | 9 --------- src/qt/languages/zh-CN.po | 9 --------- src/qt/languages/zh-TW.po | 9 --------- 24 files changed, 216 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 74481e068..81b639b7d 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -450,15 +450,6 @@ msgstr "" msgid "YMFM (faster)" msgstr "" -msgid "Network type:" -msgstr "" - -msgid "PCap device:" -msgstr "" - -msgid "Network adapter:" -msgstr "" - msgid "COM1 Device:" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 94b17adb3..63b9b7a9b 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -450,15 +450,6 @@ msgstr "Nuked (més acurat)" msgid "YMFM (faster)" msgstr "YMFM (més ràpid)" -msgid "Network type:" -msgstr "Tipus de xarxa:" - -msgid "PCap device:" -msgstr "Dispositiu PCap:" - -msgid "Network adapter:" -msgstr "Adaptador de xarxa:" - msgid "COM1 Device:" msgstr "Dispositiu COM1:" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index e6a172e66..fd9769479 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -450,15 +450,6 @@ msgstr "Nuked (přesnější)" msgid "YMFM (faster)" msgstr "YMFM (rychlejší)" -msgid "Network type:" -msgstr "Druh sítě:" - -msgid "PCap device:" -msgstr "PCap zařízení:" - -msgid "Network adapter:" -msgstr "Síťový adaptér:" - msgid "COM1 Device:" msgstr "Zařízení na COM1:" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index eead942eb..cc734cb8b 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -450,15 +450,6 @@ msgstr "Nuked (genauer)" msgid "YMFM (faster)" msgstr "YMFM (schneller)" -msgid "Network type:" -msgstr "Netzwerktyp:" - -msgid "PCap device:" -msgstr "PCap-Gerät:" - -msgid "Network adapter:" -msgstr "Netzwerkadapter:" - msgid "COM1 Device:" msgstr "COM1-Gerät:" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 269d2f75e..cf349cd6d 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -450,15 +450,6 @@ msgstr "Nuked (más preciso)" msgid "YMFM (faster)" msgstr "YMFM (más rápido)" -msgid "Network type:" -msgstr "Tipo de red:" - -msgid "PCap device:" -msgstr "Dispositivo PCap:" - -msgid "Network adapter:" -msgstr "Adaptador de red:" - msgid "COM1 Device:" msgstr "Dispositivo COM1:" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 6f4efd607..3835165c0 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -450,15 +450,6 @@ msgstr "Nuked (tarkempi)" msgid "YMFM (faster)" msgstr "YMFM (nopeampi)" -msgid "Network type:" -msgstr "Verkon tyyppi:" - -msgid "PCap device:" -msgstr "PCap-laite:" - -msgid "Network adapter:" -msgstr "Verkkokortti:" - msgid "COM1 Device:" msgstr "COM1-laite:" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index d24f21c8d..8c53a7264 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -450,15 +450,6 @@ msgstr "Nuked (plus précis)" msgid "YMFM (faster)" msgstr "YMFM (plus rapide)" -msgid "Network type:" -msgstr "Type de réseau:" - -msgid "PCap device:" -msgstr "Dispositif PCap:" - -msgid "Network adapter:" -msgstr "Adaptateur de réseau:" - msgid "COM1 Device:" msgstr "Dispositif COM1:" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 346346687..f55ad7f53 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -450,15 +450,6 @@ msgstr "Nuked (precizniji)" msgid "YMFM (faster)" msgstr "YMFM (brži)" -msgid "Network type:" -msgstr "Tip mreže:" - -msgid "PCap device:" -msgstr "Uređaj PCap:" - -msgid "Network adapter:" -msgstr "Mrežna kartica:" - msgid "COM1 Device:" msgstr "Uređaj COM1:" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 113591409..009b6345e 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -450,15 +450,6 @@ msgstr "Nuked (pontosabb)" msgid "YMFM (faster)" msgstr "YMFM (gyorsabb)" -msgid "Network type:" -msgstr "Hálózati típusa:" - -msgid "PCap device:" -msgstr "PCap eszköz:" - -msgid "Network adapter:" -msgstr "Hálózati kártya:" - msgid "COM1 Device:" msgstr "COM1 eszköz:" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 028d86f40..75614e309 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -450,15 +450,6 @@ msgstr "Nuked (più accurato)" msgid "YMFM (faster)" msgstr "YMFM (più veloce)" -msgid "Network type:" -msgstr "Tipo di rete:" - -msgid "PCap device:" -msgstr "Dispositivo PCap:" - -msgid "Network adapter:" -msgstr "Scheda di rete:" - msgid "COM1 Device:" msgstr "Dispositivo COM1:" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index e66c8b2c1..7cf3e660e 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -450,15 +450,6 @@ msgstr "Nuked(高精度化)" msgid "YMFM (faster)" msgstr "YMFM(より速く)" -msgid "Network type:" -msgstr "ネットワーク タイプ:" - -msgid "PCap device:" -msgstr "PCapデバイス:" - -msgid "Network adapter:" -msgstr "ネットワークアダプター:" - msgid "COM1 Device:" msgstr "COM1デバイス:" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 61f65ad98..266a4c581 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -450,15 +450,6 @@ msgstr "Nuked (더 정확한)" msgid "YMFM (faster)" msgstr "YMFM (더 빠르게)" -msgid "Network type:" -msgstr "네트워크 종류:" - -msgid "PCap device:" -msgstr "PCap 장치:" - -msgid "Network adapter:" -msgstr "네트워크 어댑터:" - msgid "COM1 Device:" msgstr "COM1 장치:" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 5e0670385..bb2613d4e 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -450,15 +450,6 @@ msgstr "Nuked (nauwkeuriger)" msgid "YMFM (faster)" msgstr "YMFM (sneller)" -msgid "Network type:" -msgstr "Type netwerk:" - -msgid "PCap device:" -msgstr "PCap-apparaat:" - -msgid "Network adapter:" -msgstr "Netwerkadapter:" - msgid "COM1 Device:" msgstr "COM1-apparaat:" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 1a4ddda37..13904e627 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -450,15 +450,6 @@ msgstr "Nuked (dokładniejszy)" msgid "YMFM (faster)" msgstr "YMFM (szybszy)" -msgid "Network type:" -msgstr "Rodzaj sieci:" - -msgid "PCap device:" -msgstr "Urządzenie PCap:" - -msgid "Network adapter:" -msgstr "Karta sieciowa:" - msgid "COM1 Device:" msgstr "Urządzenie COM1:" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index cfc7fa42b..9466d25df 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -450,15 +450,6 @@ msgstr "Nuked (mais preciso)" msgid "YMFM (faster)" msgstr "YMFM (mais rápido)" -msgid "Network type:" -msgstr "Tipo de rede:" - -msgid "PCap device:" -msgstr "Dispositivo PCap:" - -msgid "Network adapter:" -msgstr "Adaptador de rede:" - msgid "COM1 Device:" msgstr "Dispositivo COM1:" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 564932890..8d212b67f 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -450,15 +450,6 @@ msgstr "Nuked (mais exacto)" msgid "YMFM (faster)" msgstr "YMFM (mais rápido)" -msgid "Network type:" -msgstr "Tipo de rede:" - -msgid "PCap device:" -msgstr "Dispositivo PCap:" - -msgid "Network adapter:" -msgstr "Placa de rede:" - msgid "COM1 Device:" msgstr "Dispositivo COM1:" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 3c0eb619a..9795638d0 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -450,15 +450,6 @@ msgstr "Nuked (более точный)" msgid "YMFM (faster)" msgstr "YMFM (быстрее)" -msgid "Network type:" -msgstr "Тип сети:" - -msgid "PCap device:" -msgstr "Устройство PCap:" - -msgid "Network adapter:" -msgstr "Сетевая карта:" - msgid "COM1 Device:" msgstr "Устройство COM1:" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 1121aefb6..c7855d823 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -450,15 +450,6 @@ msgstr "Nuked (presnejší)" msgid "YMFM (faster)" msgstr "YMFM (rýchlejší)" -msgid "Network type:" -msgstr "Druh siete:" - -msgid "PCap device:" -msgstr "PCap zariadenia:" - -msgid "Network adapter:" -msgstr "Sieťový adaptér:" - msgid "COM1 Device:" msgstr "Zariadenie na COM1:" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index e3e8dba95..3e5b35c6a 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -450,15 +450,6 @@ msgstr "Nuked (točnejši)" msgid "YMFM (faster)" msgstr "YMFM (hitrejši)" -msgid "Network type:" -msgstr "Vrsta omrežja:" - -msgid "PCap device:" -msgstr "Naprava PCap:" - -msgid "Network adapter:" -msgstr "Omrežna kartica:" - msgid "COM1 Device:" msgstr "Naprava COM1:" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 2abe174ee..879277f20 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -450,15 +450,6 @@ msgstr "Nuked (daha doğru)" msgid "YMFM (faster)" msgstr "YMFM (daha hızlı)" -msgid "Network type:" -msgstr "Ağ türü:" - -msgid "PCap device:" -msgstr "PCap cihazı:" - -msgid "Network adapter:" -msgstr "Ağ cihazı:" - msgid "COM1 Device:" msgstr "COM1 cihazı:" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 7514e2fff..0cb04da38 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -450,15 +450,6 @@ msgstr "Nuked (більш точний)" msgid "YMFM (faster)" msgstr "YMFM (швидший)" -msgid "Network type:" -msgstr "Тип мережі:" - -msgid "PCap device:" -msgstr "Пристрій PCap:" - -msgid "Network adapter:" -msgstr "Мережевий адаптер:" - msgid "COM1 Device:" msgstr "Пристрій COM1:" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index d05396430..8776ad40d 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -450,15 +450,6 @@ msgstr "Nuked (chính xác hơn)" msgid "YMFM (faster)" msgstr "YMFM (nhanh hơn)" -msgid "Network type:" -msgstr "Kiểu loại mạng:" - -msgid "PCap device:" -msgstr "Thiết bị PCap:" - -msgid "Network adapter:" -msgstr "Bộ thích ứng (adapter) mạng:" - msgid "COM1 Device:" msgstr "Thiết bị COM1:" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 450f148cf..787925f3b 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -450,15 +450,6 @@ msgstr "Nuked (更准确)" msgid "YMFM (faster)" msgstr "YMFM (更快)" -msgid "Network type:" -msgstr "网络类型:" - -msgid "PCap device:" -msgstr "PCap 设备:" - -msgid "Network adapter:" -msgstr "网络适配器:" - msgid "COM1 Device:" msgstr "COM1 设备:" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index c53753d28..6bf3ddd28 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -450,15 +450,6 @@ msgstr "Nuked (更準確)" msgid "YMFM (faster)" msgstr "YMFM (更快)" -msgid "Network type:" -msgstr "網路類型:" - -msgid "PCap device:" -msgstr "PCap 裝置:" - -msgid "Network adapter:" -msgstr "網路配接器:" - msgid "COM1 Device:" msgstr "COM1 裝置:" From ff0889c1a74a3e259ab2c04016713d0054966f03 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 00:34:01 +0500 Subject: [PATCH 0749/1190] languages: Add colons to dropdown labels on the network settings page --- src/qt/languages/86box.pot | 8 ++++---- src/qt/languages/ca-ES.po | 16 ++++++++-------- src/qt/languages/cs-CZ.po | 16 ++++++++-------- src/qt/languages/de-DE.po | 16 ++++++++-------- src/qt/languages/es-ES.po | 16 ++++++++-------- src/qt/languages/fi-FI.po | 16 ++++++++-------- src/qt/languages/fr-FR.po | 16 ++++++++-------- src/qt/languages/hr-HR.po | 16 ++++++++-------- src/qt/languages/hu-HU.po | 16 ++++++++-------- src/qt/languages/it-IT.po | 16 ++++++++-------- src/qt/languages/ja-JP.po | 16 ++++++++-------- src/qt/languages/ko-KR.po | 16 ++++++++-------- src/qt/languages/nl-NL.po | 16 ++++++++-------- src/qt/languages/pl-PL.po | 16 ++++++++-------- src/qt/languages/pt-BR.po | 16 ++++++++-------- src/qt/languages/pt-PT.po | 16 ++++++++-------- src/qt/languages/ru-RU.po | 16 ++++++++-------- src/qt/languages/sk-SK.po | 16 ++++++++-------- src/qt/languages/sl-SI.po | 16 ++++++++-------- src/qt/languages/tr-TR.po | 16 ++++++++-------- src/qt/languages/uk-UA.po | 16 ++++++++-------- src/qt/languages/vi-VN.po | 16 ++++++++-------- src/qt/languages/zh-CN.po | 16 ++++++++-------- src/qt/languages/zh-TW.po | 16 ++++++++-------- 24 files changed, 188 insertions(+), 188 deletions(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 81b639b7d..71dc7572a 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -1341,16 +1341,16 @@ msgstr "" msgid "Network Card #4" msgstr "" -msgid "Mode" +msgid "Mode:" msgstr "" -msgid "Interface" +msgid "Interface:" msgstr "" -msgid "Adapter" +msgid "Adapter:" msgstr "" -msgid "VDE Socket" +msgid "VDE Socket:" msgstr "" msgid "86Box Unit Tester" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 63b9b7a9b..e3bb805a0 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -1341,17 +1341,17 @@ msgstr "Targeta de xarxa 3" msgid "Network Card #4" msgstr "Targeta de xarxa 4" -msgid "Mode" -msgstr "Mode" +msgid "Mode:" +msgstr "Mode:" -msgid "Interface" -msgstr "Interfície" +msgid "Interface:" +msgstr "Interfície:" -msgid "Adapter" -msgstr "Adaptador" +msgid "Adapter:" +msgstr "Adaptador:" -msgid "VDE Socket" -msgstr "Socket de VDE" +msgid "VDE Socket:" +msgstr "Socket de VDE:" msgid "86Box Unit Tester" msgstr "Test de la unitat de 86 Box" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index fd9769479..84c2cb94f 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -1341,17 +1341,17 @@ msgstr "Síťová karta 3" msgid "Network Card #4" msgstr "Síťová karta 4" -msgid "Mode" -msgstr "Režim" +msgid "Mode:" +msgstr "Režim:" -msgid "Interface" -msgstr "Rozhraní" +msgid "Interface:" +msgstr "Rozhraní:" -msgid "Adapter" -msgstr "Adaptér" +msgid "Adapter:" +msgstr "Adaptér:" -msgid "VDE Socket" -msgstr "Zásuvka VDE" +msgid "VDE Socket:" +msgstr "Zásuvka VDE:" msgid "86Box Unit Tester" msgstr "86Box Unit Tester" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index cc734cb8b..588a2b5cd 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -1344,17 +1344,17 @@ msgstr "Netzwerkkarte 3" msgid "Network Card #4" msgstr "Netzwerkkarte 4" -msgid "Mode" -msgstr "Modus" +msgid "Mode:" +msgstr "Modus:" -msgid "Interface" -msgstr "Schnittstelle" +msgid "Interface:" +msgstr "Schnittstelle:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "VDE Port" +msgid "VDE Socket:" +msgstr "VDE Port:" msgid "86Box Unit Tester" msgstr "86Box-Gerätetester" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index cf349cd6d..ac22a4d5c 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1340,17 +1340,17 @@ msgstr "Tarjeta de red 3" msgid "Network Card #4" msgstr "Tarjeta de red 4" -msgid "Mode" -msgstr "Modalidad" +msgid "Mode:" +msgstr "Modalidad:" -msgid "Interface" -msgstr "Interfaz" +msgid "Interface:" +msgstr "Interfaz:" -msgid "Adapter" -msgstr "Adaptador" +msgid "Adapter:" +msgstr "Adaptador:" -msgid "VDE Socket" -msgstr "Toma VDE" +msgid "VDE Socket:" +msgstr "Toma VDE:" msgid "86Box Unit Tester" msgstr "Comprobador de unidad 86Box" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 3835165c0..8b8ca8374 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1344,17 +1344,17 @@ msgstr "Verkkokortti 3" msgid "Network Card #4" msgstr "Verkkokortti 4" -msgid "Mode" -msgstr "Tila" +msgid "Mode:" +msgstr "Tila:" -msgid "Interface" -msgstr "Liitäntä" +msgid "Interface:" +msgstr "Liitäntä:" -msgid "Adapter" -msgstr "Sovitin" +msgid "Adapter:" +msgstr "Sovitin:" -msgid "VDE Socket" -msgstr "VDE-pistorasia" +msgid "VDE Socket:" +msgstr "VDE-pistorasia:" msgid "86Box Unit Tester" msgstr "86Box Unit Tester" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 8c53a7264..cc2d8c310 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -1341,17 +1341,17 @@ msgstr "Carte réseau 3" msgid "Network Card #4" msgstr "Carte réseau 4" -msgid "Mode" -msgstr "Mode" +msgid "Mode:" +msgstr "Mode:" -msgid "Interface" -msgstr "Interface" +msgid "Interface:" +msgstr "Interface:" -msgid "Adapter" -msgstr "Adaptateur" +msgid "Adapter:" +msgstr "Adaptateur:" -msgid "VDE Socket" -msgstr "Prise VDE" +msgid "VDE Socket:" +msgstr "Prise VDE:" msgid "86Box Unit Tester" msgstr "Testeur d'unité de 86Box" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index f55ad7f53..d074401a2 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -1341,17 +1341,17 @@ msgstr "Mrežna kartica 3" msgid "Network Card #4" msgstr "Mrežna kartica 4" -msgid "Mode" -msgstr "Način" +msgid "Mode:" +msgstr "Način:" -msgid "Interface" -msgstr "Sučelje" +msgid "Interface:" +msgstr "Sučelje:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "VDE utičnica" +msgid "VDE Socket:" +msgstr "VDE utičnica:" msgid "86Box Unit Tester" msgstr "Jedinični ispitivač 86Box-a" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 009b6345e..841ed5e81 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -1341,17 +1341,17 @@ msgstr "Hálózati kártya 3" msgid "Network Card #4" msgstr "Hálózati kártya 4" -msgid "Mode" -msgstr "Mód" +msgid "Mode:" +msgstr "Mód:" -msgid "Interface" -msgstr "Interfész" +msgid "Interface:" +msgstr "Interfész:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "VDE aljzat" +msgid "VDE Socket:" +msgstr "VDE aljzat:" msgid "86Box Unit Tester" msgstr "86Box Unit Tester" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 75614e309..8de67d28b 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -1341,17 +1341,17 @@ msgstr "Scheda di rete n. 3" msgid "Network Card #4" msgstr "Scheda di rete n. 4" -msgid "Mode" -msgstr "Modalità" +msgid "Mode:" +msgstr "Modalità:" -msgid "Interface" -msgstr "Interfaccia" +msgid "Interface:" +msgstr "Interfaccia:" -msgid "Adapter" -msgstr "Adattatore" +msgid "Adapter:" +msgstr "Adattatore:" -msgid "VDE Socket" -msgstr "Presa VDE" +msgid "VDE Socket:" +msgstr "Presa VDE:" msgid "86Box Unit Tester" msgstr "Tester di unità 86Box" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 7cf3e660e..6add03617 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -1341,17 +1341,17 @@ msgstr "ネットワークカード 3" msgid "Network Card #4" msgstr "ネットワークカード 4" -msgid "Mode" -msgstr "モード" +msgid "Mode:" +msgstr "モード:" -msgid "Interface" -msgstr "インターフェース" +msgid "Interface:" +msgstr "インターフェース:" -msgid "Adapter" -msgstr "アダプター" +msgid "Adapter:" +msgstr "アダプター:" -msgid "VDE Socket" -msgstr "VDEソケット" +msgid "VDE Socket:" +msgstr "VDEソケット:" msgid "86Box Unit Tester" msgstr "86Boxユニットテスター" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 266a4c581..f32a23ec4 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -1341,17 +1341,17 @@ msgstr "네트워크 카드 3" msgid "Network Card #4" msgstr "네트워크 카드 4" -msgid "Mode" -msgstr "모드" +msgid "Mode:" +msgstr "모드:" -msgid "Interface" -msgstr "인터페이스" +msgid "Interface:" +msgstr "인터페이스:" -msgid "Adapter" -msgstr "어댑터" +msgid "Adapter:" +msgstr "어댑터:" -msgid "VDE Socket" -msgstr "VDE 소켓" +msgid "VDE Socket:" +msgstr "VDE 소켓:" msgid "86Box Unit Tester" msgstr "86Box 유닛 테스터" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index bb2613d4e..f1b4eed91 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -1341,17 +1341,17 @@ msgstr "Netwerkkaart #3" msgid "Network Card #4" msgstr "Netwerkkaart #4" -msgid "Mode" -msgstr "Modus" +msgid "Mode:" +msgstr "Modus:" -msgid "Interface" -msgstr "Interface" +msgid "Interface:" +msgstr "Interface:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "VDE-socket" +msgid "VDE Socket:" +msgstr "VDE-socket:" msgid "86Box Unit Tester" msgstr "86Box apparaattester" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 13904e627..1ad5dcf88 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -1341,17 +1341,17 @@ msgstr "Karta sieciowa 3" msgid "Network Card #4" msgstr "Karta sieciowa 4" -msgid "Mode" -msgstr "Tryb" +msgid "Mode:" +msgstr "Tryb:" -msgid "Interface" -msgstr "Interfejs" +msgid "Interface:" +msgstr "Interfejs:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "Gniazdo VDE" +msgid "VDE Socket:" +msgstr "Gniazdo VDE:" msgid "86Box Unit Tester" msgstr "Tester urządzeń 86Box" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 9466d25df..3eead12fe 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -1341,17 +1341,17 @@ msgstr "Placa de rede 3" msgid "Network Card #4" msgstr "Placa de rede 4" -msgid "Mode" -msgstr "Modo" +msgid "Mode:" +msgstr "Modo:" -msgid "Interface" -msgstr "Interface" +msgid "Interface:" +msgstr "Interface:" -msgid "Adapter" -msgstr "Adaptador" +msgid "Adapter:" +msgstr "Adaptador:" -msgid "VDE Socket" -msgstr "Soquete VDE" +msgid "VDE Socket:" +msgstr "Soquete VDE:" msgid "86Box Unit Tester" msgstr "Testador de unidade 86Box" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 8d212b67f..1ffcf0c3b 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -1341,17 +1341,17 @@ msgstr "Placa de rede 3" msgid "Network Card #4" msgstr "Placa de rede 4" -msgid "Mode" -msgstr "Modo" +msgid "Mode:" +msgstr "Modo:" -msgid "Interface" -msgstr "Interface" +msgid "Interface:" +msgstr "Interface:" -msgid "Adapter" -msgstr "Adaptador" +msgid "Adapter:" +msgstr "Adaptador:" -msgid "VDE Socket" -msgstr "Tomada VDE" +msgid "VDE Socket:" +msgstr "Tomada VDE:" msgid "86Box Unit Tester" msgstr "Testador de unidades 86Box" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 9795638d0..f1c250a51 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1341,17 +1341,17 @@ msgstr "Сетевая карта 3" msgid "Network Card #4" msgstr "Сетевая карта 4" -msgid "Mode" -msgstr "Режим" +msgid "Mode:" +msgstr "Режим:" -msgid "Interface" -msgstr "Интерфейс" +msgid "Interface:" +msgstr "Интерфейс:" -msgid "Adapter" -msgstr "Адаптер" +msgid "Adapter:" +msgstr "Адаптер:" -msgid "VDE Socket" -msgstr "VDE сокет" +msgid "VDE Socket:" +msgstr "VDE сокет:" msgid "86Box Unit Tester" msgstr "Модульный Тестер 86Box" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index c7855d823..9ce9abc2f 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -1342,17 +1342,17 @@ msgstr "Sieťová karta 3" msgid "Network Card #4" msgstr "Sieťová karta 4" -msgid "Mode" -msgstr "Režim" +msgid "Mode:" +msgstr "Režim:" -msgid "Interface" -msgstr "Rozhranie" +msgid "Interface:" +msgstr "Rozhranie:" -msgid "Adapter" -msgstr "Adaptér" +msgid "Adapter:" +msgstr "Adaptér:" -msgid "VDE Socket" -msgstr "Zásuvka VDE" +msgid "VDE Socket:" +msgstr "Zásuvka VDE:" msgid "86Box Unit Tester" msgstr "86Box Unit Tester" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 3e5b35c6a..af5fd1fc1 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -1341,17 +1341,17 @@ msgstr "Omrežna kartica 3" msgid "Network Card #4" msgstr "Omrežna kartica 4" -msgid "Mode" -msgstr "Način" +msgid "Mode:" +msgstr "Način:" -msgid "Interface" -msgstr "Vmesnik" +msgid "Interface:" +msgstr "Vmesnik:" -msgid "Adapter" -msgstr "Adapter" +msgid "Adapter:" +msgstr "Adapter:" -msgid "VDE Socket" -msgstr "Vtičnica VDE" +msgid "VDE Socket:" +msgstr "Vtičnica VDE:" msgid "86Box Unit Tester" msgstr "Tester enote 86Box" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 879277f20..d3c1871e9 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -1341,17 +1341,17 @@ msgstr "Ağ kartı 3" msgid "Network Card #4" msgstr "Ağ kartı 4" -msgid "Mode" -msgstr "Mod" +msgid "Mode:" +msgstr "Mod:" -msgid "Interface" -msgstr "Arayüz" +msgid "Interface:" +msgstr "Arayüz:" -msgid "Adapter" -msgstr "Adaptör" +msgid "Adapter:" +msgstr "Adaptör:" -msgid "VDE Socket" -msgstr "VDE soketi" +msgid "VDE Socket:" +msgstr "VDE soketi:" msgid "86Box Unit Tester" msgstr "86Box birim test cihazı" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 0cb04da38..d4b4c7847 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -1341,17 +1341,17 @@ msgstr "Мережева карта 3" msgid "Network Card #4" msgstr "Мережева карта 4" -msgid "Mode" -msgstr "Режим" +msgid "Mode:" +msgstr "Режим:" -msgid "Interface" -msgstr "Інтерфейс" +msgid "Interface:" +msgstr "Інтерфейс:" -msgid "Adapter" -msgstr "Адаптер" +msgid "Adapter:" +msgstr "Адаптер:" -msgid "VDE Socket" -msgstr "VDE сокет" +msgid "VDE Socket:" +msgstr "VDE сокет:" msgid "86Box Unit Tester" msgstr "Тестер блоків 86Box" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 8776ad40d..9dcbf01ca 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -1341,17 +1341,17 @@ msgstr "Thẻ mạng 3" msgid "Network Card #4" msgstr "Thẻ mạng 4" -msgid "Mode" -msgstr "Chế độ" +msgid "Mode:" +msgstr "Chế độ:" -msgid "Interface" -msgstr "Giao diện" +msgid "Interface:" +msgstr "Giao diện:" -msgid "Adapter" -msgstr "Bộ chuyển đổi" +msgid "Adapter:" +msgstr "Bộ chuyển đổi:" -msgid "VDE Socket" -msgstr "Ổ cắm VDE" +msgid "VDE Socket:" +msgstr "Ổ cắm VDE:" msgid "86Box Unit Tester" msgstr "Trình kiểm tra đơn vị 86box" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 787925f3b..041b7bb6b 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1341,17 +1341,17 @@ msgstr "网卡 3" msgid "Network Card #4" msgstr "网卡 4" -msgid "Mode" -msgstr "模式" +msgid "Mode:" +msgstr "模式:" -msgid "Interface" -msgstr "界面" +msgid "Interface:" +msgstr "界面:" -msgid "Adapter" -msgstr "适配器" +msgid "Adapter:" +msgstr "适配器:" -msgid "VDE Socket" -msgstr "VDE 套接字" +msgid "VDE Socket:" +msgstr "VDE 套接字:" msgid "86Box Unit Tester" msgstr "86Box 装置测试仪" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 6bf3ddd28..c3e3fb4d5 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -1341,17 +1341,17 @@ msgstr "網路卡 3" msgid "Network Card #4" msgstr "網路卡 4" -msgid "Mode" -msgstr "模式" +msgid "Mode:" +msgstr "模式:" -msgid "Interface" -msgstr "介面" +msgid "Interface:" +msgstr "介面:" -msgid "Adapter" -msgstr "配接器" +msgid "Adapter:" +msgstr "配接器:" -msgid "VDE Socket" -msgstr "VDE 插座" +msgid "VDE Socket:" +msgstr "VDE 插座:" msgid "86Box Unit Tester" msgstr "86Box 單元測試器" From 0559d803a7cb7c3d86513c93e7055b559483ea34 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 11:03:41 +0500 Subject: [PATCH 0750/1190] languages: update the Russian translation Co-Authored-by: usergithub64 <58270614+usergithub64@users.noreply.github.com> --- src/qt/languages/ru-RU.po | 56 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index f1c250a51..42ad1716c 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -55,7 +55,7 @@ msgid "Qt (&OpenGL)" msgstr "Qt (&OpenGL)" msgid "Open&GL (3.0 Core)" -msgstr "Open&GL (3.0)" +msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" @@ -214,7 +214,7 @@ msgid "&Documentation..." msgstr "&Документация..." msgid "&About 86Box..." -msgstr "&О программе 86Box..." +msgstr "&О 86Box..." msgid "&New image..." msgstr "&Новый образ..." @@ -253,7 +253,7 @@ msgid "E&mpty" msgstr "П&устой" msgid "Reload previous image" -msgstr "Загрузить предыдущий образ" +msgstr "Перезагрузить предыдущий образ" msgid "&Folder..." msgstr "&Папка..." @@ -430,10 +430,10 @@ msgid "Sound card #4:" msgstr "Звуковая карта 4:" msgid "MIDI Out Device:" -msgstr "MIDI Out устройство:" +msgstr "Устройство вывода MIDI:" msgid "MIDI In Device:" -msgstr "MIDI In устройство:" +msgstr "Устройство ввода MIDI:" msgid "Standalone MPU-401" msgstr "Отдельный MPU-401" @@ -1435,7 +1435,7 @@ msgid "BIOS Revision" msgstr "Версия BIOS" msgid "Translate 26 -> 17" -msgstr "Перевести 26 -> 17" +msgstr "Переводить 26 -> 17" msgid "Language" msgstr "Язык" @@ -1531,7 +1531,7 @@ msgid "Reversed stereo" msgstr "Реверс стерео" msgid "Nice ramp" -msgstr "Nice ramp" +msgstr "Улучшение рампы" msgid "Hz" msgstr "Гц" @@ -1582,7 +1582,7 @@ msgid "RAM Address" msgstr "Адрес оперативной памяти" msgid "RAM size" -msgstr "Объем оперативной памяти" +msgstr "Размер оперативной памяти" msgid "Initial RAM size" msgstr "Начальный размер оперативной памяти" @@ -1615,10 +1615,10 @@ msgid "Surround module" msgstr "Модуль объемного звучания" msgid "CODEC" -msgstr "КОДЕК" +msgstr "Кодек" msgid "Raise CODEC interrupt on CODEC setup (needed by some drivers)" -msgstr "Поднимать прерывание CODEC при настройке CODEC (необходимо некоторым драйверам)." +msgstr "Поднимать прерывание кодека при настройке кодека (необходимо некоторым драйверам)." msgid "SB Address" msgstr "Адрес SB" @@ -1645,7 +1645,7 @@ msgid "Enable CMS" msgstr "Включить CMS" msgid "Mixer" -msgstr "Смеситель" +msgstr "Микшер" msgid "High DMA" msgstr "Высокий DMA" @@ -1654,7 +1654,7 @@ msgid "Control PC speaker" msgstr "Управление динамиком ПК" msgid "Memory size" -msgstr "Объем памяти" +msgstr "Размер памяти" msgid "EMU8000 Address" msgstr "Адрес EMU8000" @@ -1669,7 +1669,7 @@ msgid "GUS type" msgstr "Тип GUS" msgid "Enable 0x04 \"Exit 86Box\" command" -msgstr "Включить команду 0x04 \"Выход 86Box\"." +msgstr "Включить команду 0x04 \"Выход из 86Box\"" msgid "Display type" msgstr "Тип дисплея" @@ -1711,13 +1711,13 @@ msgid "Bilinear filtering" msgstr "Билинейная фильтрация" msgid "Dithering" -msgstr "Dithering" +msgstr "Дизеринг" msgid "Enable NMI for CGA emulation" msgstr "Включение NMI для эмуляции CGA" msgid "Voodoo type" -msgstr "Тип Вуду" +msgstr "Тип Voodoo" msgid "Framebuffer memory size" msgstr "Размер памяти фреймбуфера" @@ -1726,10 +1726,10 @@ msgid "Texture memory size" msgstr "Размер памяти текстур" msgid "Dither subtraction" -msgstr "Вычитание с вычитанием" +msgstr "Вычитание дизеринга" msgid "Screen Filter" -msgstr "Фильтр экрана" +msgstr "Экранный фильтр" msgid "Render threads" msgstr "Потоки рендеринга" @@ -1912,7 +1912,7 @@ msgid "Monochrome (5151/MDA) (white)" msgstr "Монохромный (5151/MDA) (белый)" msgid "Monochrome (5151/MDA) (green)" -msgstr "Монохромный (5151/MDA) (зеленый)" +msgstr "Монохромный (5151/MDA) (зелёный)" msgid "Monochrome (5151/MDA) (amber)" msgstr "Монохромный (5151/MDA) (янтарный)" @@ -1930,7 +1930,7 @@ msgid "Enhanced Color - Enhanced Mode (5154/ECD)" msgstr "Улучшенный цветной - улучшенный режим (5154/ECD)" msgid "Green" -msgstr "Зеленый" +msgstr "Зелёный" msgid "Amber" msgstr "Янтарный" @@ -1954,13 +1954,13 @@ msgid "Bochs latest" msgstr "Bochs последний" msgid "Mono Non-Interlaced" -msgstr "Монохромный без чересстрочной развертки" +msgstr "Монохромный без чересстрочной развёртки" msgid "Color Interlaced" -msgstr "Цветной с чересстрочной разверткой" +msgstr "Цветной с чересстрочной развёрткой" msgid "Color Non-Interlaced" -msgstr "Цветной без чересстрочной развертки" +msgstr "Цветной без чересстрочной развёртки" msgid "3Dfx Voodoo Graphics" msgstr "Ускоритель 3Dfx Voodoo" @@ -2011,10 +2011,10 @@ msgid "Protection Dongle for Savage Quest" msgstr "Защитный донгл для Savage Quest" msgid "Serial Passthrough Device" -msgstr "Устройство прохода через последовательный порт" +msgstr "Устройство проброса через последовательный порт" msgid "Passthrough Mode" -msgstr "Проходной режим" +msgstr "Режим проброса" msgid "Host Serial Device" msgstr "Последовательное устройство хоста" @@ -2101,16 +2101,16 @@ msgid "Inhibit multimedia keys" msgstr "Перехватывать мультимедиа-клавиши" msgid "Ask for confirmation before saving settings" -msgstr "Спрашивать подтверждения перед сохранением настроек" +msgstr "Запрашивать подтверждение перед сохранением настроек" msgid "Ask for confirmation before hard resetting" -msgstr "Спрашивать подтверждения перед холодной перезагрузкой" +msgstr "Запрашивать подтверждение перед холодной перезагрузкой" msgid "Ask for confirmation before quitting" -msgstr "Спрашивать подтвержждения перед выходом" +msgstr "Запрашивать подтверждение перед выходом" msgid "Display hotkey message when entering full-screen mode" -msgstr "Показывать сообщение о горячих клавишах при включении полноэкранного режима" +msgstr "Показывать сообщение о горячей клавише при входе в полноэкранный режим" msgid "Options" msgstr "Параметры" From ed4820b798482a5de53ac82971404a00fd8cf197 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 17 Apr 2025 11:08:04 +0500 Subject: [PATCH 0751/1190] languages: Add string for the 5-button 2-wheel mouse --- src/qt/languages/86box.pot | 3 +++ src/qt/languages/ca-ES.po | 3 +++ src/qt/languages/cs-CZ.po | 3 +++ src/qt/languages/de-DE.po | 3 +++ src/qt/languages/es-ES.po | 3 +++ src/qt/languages/fi-FI.po | 3 +++ src/qt/languages/fr-FR.po | 3 +++ src/qt/languages/hr-HR.po | 3 +++ src/qt/languages/hu-HU.po | 3 +++ src/qt/languages/it-IT.po | 3 +++ src/qt/languages/ja-JP.po | 3 +++ src/qt/languages/ko-KR.po | 3 +++ src/qt/languages/nl-NL.po | 3 +++ src/qt/languages/pl-PL.po | 5 ++++- src/qt/languages/pt-BR.po | 3 +++ src/qt/languages/pt-PT.po | 3 +++ src/qt/languages/ru-RU.po | 3 +++ src/qt/languages/sk-SK.po | 3 +++ src/qt/languages/sl-SI.po | 3 +++ src/qt/languages/tr-TR.po | 3 +++ src/qt/languages/uk-UA.po | 3 +++ src/qt/languages/vi-VN.po | 3 +++ src/qt/languages/zh-CN.po | 3 +++ src/qt/languages/zh-TW.po | 3 +++ 24 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 71dc7572a..6e6dd3fc3 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -1809,6 +1809,9 @@ msgstr "" msgid "Five + Wheel" msgstr "" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index e3bb805a0..847cc0138 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -1809,6 +1809,9 @@ msgstr "Roda" msgid "Five + Wheel" msgstr "Cinc + roda" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 sèrie / SMT3(R)V" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 84c2cb94f..ea492f0b6 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -1809,6 +1809,9 @@ msgstr "Kolečko" msgid "Five + Wheel" msgstr "Pět + kolečko" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 sériová / SMT3(R)V" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 588a2b5cd..95d1b0249 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -1812,6 +1812,9 @@ msgstr "Rad" msgid "Five + Wheel" msgstr "Fünf + Rad" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Seriell / SMT3(R)V" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index ac22a4d5c..57474ae53 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1808,6 +1808,9 @@ msgstr "Rueda" msgid "Five + Wheel" msgstr "Cinco + rueda" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 serie / SMT3(R)V" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 8b8ca8374..187a423f6 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1812,6 +1812,9 @@ msgstr "Pyörä" msgid "Five + Wheel" msgstr "Viisi + pyörä" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 sarja / SMT3(R)V" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index cc2d8c310..8456baf2f 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -1809,6 +1809,9 @@ msgstr "Molette" msgid "Five + Wheel" msgstr "Cinq + molette" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 série / SMT3(R)V" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index d074401a2..0fd342f88 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -1809,6 +1809,9 @@ msgstr "Kotač" msgid "Five + Wheel" msgstr "Pet + kotač" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 serijski / SMT3(R)V" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 841ed5e81..cbb753890 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -1809,6 +1809,9 @@ msgstr "Kerék" msgid "Five + Wheel" msgstr "Öt + kerék" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 soros / SMT3(R)V" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 8de67d28b..c505b9eaa 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -1809,6 +1809,9 @@ msgstr "Ruota" msgid "Five + Wheel" msgstr "Cinque + ruota" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 seriale / SMT3(R)V" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 6add03617..cff667239 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -1809,6 +1809,9 @@ msgstr "ホイール" msgid "Five + Wheel" msgstr "五つ+ホイール" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 シリアル / SMT3(R)V" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index f32a23ec4..55f47be27 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -1809,6 +1809,9 @@ msgstr "휠" msgid "Five + Wheel" msgstr "5개 + 휠" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 직렬/SMT3(R)V" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index f1b4eed91..e854ea3f3 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -1809,6 +1809,9 @@ msgstr "Wiel" msgid "Five + Wheel" msgstr "Vijf + Wiel" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serieel / SMT3(R)V" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 1ad5dcf88..3fc731e5f 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -1807,7 +1807,10 @@ msgid "Wheel" msgstr "Koło" msgid "Five + Wheel" -msgstr "Five + Wheel" +msgstr "" + +msgid "Five + 2 Wheels" +msgstr "" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 szeregowa / SMT3(R)V" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 3eead12fe..02abe2321 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -1809,6 +1809,9 @@ msgstr "Roda" msgid "Five + Wheel" msgstr "Cinco + roda" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 1ffcf0c3b..42550a266 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -1809,6 +1809,9 @@ msgstr "Roda" msgid "Five + Wheel" msgstr "Cinco + Roda" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 série / SMT3(R)V" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 42ad1716c..dde5387a7 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1809,6 +1809,9 @@ msgstr "Колесо" msgid "Five + Wheel" msgstr "Пять + колесо" +msgid "Five + 2 Wheels" +msgstr "Пять + 2 колеса" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 последовательная / SMT3(R)V" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 9ce9abc2f..6039adedc 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -1810,6 +1810,9 @@ msgstr "Koleso" msgid "Five + Wheel" msgstr "Päť + koleso" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 sériová / SMT3(R)V" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index af5fd1fc1..b6641f8a1 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -1809,6 +1809,9 @@ msgstr "Kolesa" msgid "Five + Wheel" msgstr "Pet + kolo" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 serijska / SMT3(R)V" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index d3c1871e9..e9a42a896 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -1809,6 +1809,9 @@ msgstr "Tekerlek" msgid "Five + Wheel" msgstr "Beş + tekerlek" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 seri / SMT3(R)V" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index d4b4c7847..bceb7bea5 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -1809,6 +1809,9 @@ msgstr "Колесо" msgid "Five + Wheel" msgstr "П'ять + колесо" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 послідовна / SMT3(R)V" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 9dcbf01ca..e14386bf8 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -1809,6 +1809,9 @@ msgstr "Con lăn" msgid "Five + Wheel" msgstr "Năm + con lăn" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 041b7bb6b..9f6cc0328 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1809,6 +1809,9 @@ msgstr "滚轮" msgid "Five + Wheel" msgstr "五键+滚轮" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 串行 / SMT3(R)V" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index c3e3fb4d5..aefa89d5f 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -1809,6 +1809,9 @@ msgstr "滾輪" msgid "Five + Wheel" msgstr "五鍵 + 滾輪" +msgid "Five + 2 Wheels" +msgstr "" + msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 序列 / SMT3(R)V" From 48903bb48ecd8ea842e6395efec18158571717be Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 18 Apr 2025 03:32:16 +0500 Subject: [PATCH 0752/1190] qt: Add Swedish translation Contributed by toshineon on Discord --- src/qt/languages/sv-SE.po | 2164 +++++++++++++++++++++++++++++++++ src/qt/qt_progsettings.cpp | 1 + src/qt/qt_translations.qrc.in | 1 + 3 files changed, 2166 insertions(+) create mode 100644 src/qt/languages/sv-SE.po diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po new file mode 100644 index 000000000..a47997225 --- /dev/null +++ b/src/qt/languages/sv-SE.po @@ -0,0 +1,2164 @@ +msgid "" +msgstr "" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: sv_SE\n" +"X-Source-Language: en_US\n" + +msgid "&Action" +msgstr "" + +msgid "&Keyboard requires capture" +msgstr "Tangentbord behöver uppfångas" + +msgid "&Right CTRL is left ALT" +msgstr "&Höger CTRL är vänster ALT" + +msgid "&Hard Reset..." +msgstr "&Hård omstart..." + +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausa" + +msgid "E&xit..." +msgstr "A&vsluta..." + +msgid "&View" +msgstr "&Visa" + +msgid "&Hide status bar" +msgstr "&Dölj statusfältet" + +msgid "Hide &toolbar" +msgstr "Dölj &verktygsfältet" + +msgid "&Resizeable window" +msgstr "&Ändringsbar fönsterstorlek" + +msgid "R&emember size && position" +msgstr "K&om ihåg storlek && position" + +msgid "Re&nderer" +msgstr "Re&nderare" + +msgid "&Qt (Software)" +msgstr "&Qt (Mjukvara)" + +msgid "Qt (&OpenGL)" +msgstr "Qt (&OpenGL)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify dimensions..." +msgstr "Ange mått..." + +msgid "F&orce 4:3 display ratio" +msgstr "T&vinga 4:3 bildförhållande" + +msgid "&Window scale factor" +msgstr "&Skalningsfaktor för fönster" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "&3x" +msgstr "&3x" + +msgid "&4x" +msgstr "&4x" + +msgid "&5x" +msgstr "&5x" + +msgid "&6x" +msgstr "&6x" + +msgid "&7x" +msgstr "&7x" + +msgid "&8x" +msgstr "&8x" + +msgid "Filter method" +msgstr "Filtermetod" + +msgid "&Nearest" +msgstr "&Närmsta" + +msgid "&Linear" +msgstr "&Linjär" + +msgid "Hi&DPI scaling" +msgstr "Hög&DPI-skalning" + +msgid "&Fullscreen" +msgstr "&Helskärm" + +msgid "Fullscreen &stretch mode" +msgstr "Sträckningsläge för &helskärm" + +msgid "&Full screen stretch" +msgstr "&Sträck till helskärm" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Fyrkantiga pixlar (Behåll bildförhållande)" + +msgid "&Integer scale" +msgstr "&Skala till heltal" + +msgid "4:&3 Integer scale" +msgstr "Skala till heltal i 4:&3" + +msgid "E&GA/(S)VGA settings" +msgstr "E&GA/(S)VGA-inställningar" + +msgid "&Inverted VGA monitor" +msgstr "&Inverterad VGA-skärm" + +msgid "VGA screen &type" +msgstr "Skärmtyp för &VGA" + +msgid "RGB &Color" +msgstr "RGB &färg" + +msgid "&RGB Grayscale" +msgstr "&RGB gråskala" + +msgid "&Amber monitor" +msgstr "&Bärnstensfärgad skärm" + +msgid "&Green monitor" +msgstr "&Grön skärm" + +msgid "&White monitor" +msgstr "&Vit skärm" + +msgid "Grayscale &conversion type" +msgstr "Konverteringstyp till &gråskala" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Genomsnittlig" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "CGA/PCjr/Tandy/E&GA/(S)VGA överskanning" + +msgid "Change contrast for &monochrome display" +msgstr "Ändra kontrast för &svartvita skärmar" + +msgid "&Media" +msgstr "&Media" + +msgid "&Tools" +msgstr "&Verktyg" + +msgid "&Settings..." +msgstr "&Inställningar..." + +msgid "&Update status bar icons" +msgstr "&Uppdatera statusfältets ikoner" + +msgid "Take s&creenshot" +msgstr "Tag s&kärmbild" + +msgid "S&ound" +msgstr "L&jud" + +msgid "&Preferences..." +msgstr "&Preferenser..." + +msgid "Enable &Discord integration" +msgstr "Aktivera &integration med Discord" + +msgid "Sound &gain..." +msgstr "Ljud&förstärkning..." + +msgid "Begin trace" +msgstr "Börja spårning" + +msgid "End trace" +msgstr "Avsluta spårning" + +msgid "&Help" +msgstr "&Hjälp" + +msgid "&Documentation..." +msgstr "&Dokumentation..." + +msgid "&About 86Box..." +msgstr "&Om 86Box..." + +msgid "&New image..." +msgstr "&Ny avbildning..." + +msgid "&Existing image..." +msgstr "&Befintlig avbildning..." + +msgid "Existing image (&Write-protected)..." +msgstr "Befintlig avbildning (&skrivskyddad)..." + +msgid "&Record" +msgstr "&Spela in" + +msgid "&Play" +msgstr "&Spela upp" + +msgid "&Rewind to the beginning" +msgstr "&Spola tillbaka till början" + +msgid "&Fast forward to the end" +msgstr "&Spola fram till slutet" + +msgid "E&ject" +msgstr "M&ata ut" + +msgid "&Image..." +msgstr "&Avbildning..." + +msgid "E&xport to 86F..." +msgstr "E&xportera till 86F..." + +msgid "&Mute" +msgstr "&Tysta" + +msgid "E&mpty" +msgstr "T&om" + +msgid "Reload previous image" +msgstr "Ladda om föregående avbildning" + +msgid "&Folder..." +msgstr "&Mapp..." + +msgid "Target &framerate" +msgstr "Mål för &bildhastighet" + +msgid "&Sync with video" +msgstr "&Synkronisera med bild" + +msgid "&25 fps" +msgstr "&25 fps" + +msgid "&30 fps" +msgstr "&30 fps" + +msgid "&50 fps" +msgstr "&50 fps" + +msgid "&60 fps" +msgstr "&60 fps" + +msgid "&75 fps" +msgstr "&75 fps" + +msgid "&VSync" +msgstr "&VSync" + +msgid "&Select shader..." +msgstr "&Välj shader..." + +msgid "&Remove shader" +msgstr "&Ta bort shader" + +msgid "Preferences" +msgstr "Preferenser" + +msgid "Sound Gain" +msgstr "Ljudförstärkning" + +msgid "New Image" +msgstr "Ny avbildning" + +msgid "Settings" +msgstr "Inställningar" + +msgid "Specify Main Window Dimensions" +msgstr "Ange mått för huvudfönster" + +msgid "OK" +msgstr "Okej" + +msgid "Cancel" +msgstr "Avbryt" + +msgid "&Default" +msgstr "&Standard" + +msgid "Language:" +msgstr "Språk:" + +msgid "Gain" +msgstr "Förstärkning" + +msgid "File name:" +msgstr "Filnamn:" + +msgid "Disk size:" +msgstr "Storlek på disk:" + +msgid "RPM mode:" +msgstr "Varvtalsläge:" + +msgid "Progress:" +msgstr "Framsteg:" + +msgid "Width:" +msgstr "Bredd:" + +msgid "Height:" +msgstr "Höjd:" + +msgid "Lock to this size" +msgstr "Lås till denna storlek" + +msgid "Machine type:" +msgstr "Maskintyp:" + +msgid "Machine:" +msgstr "Maskin:" + +msgid "Configure" +msgstr "Konfigurera" + +msgid "CPU type:" +msgstr "Processortyp:" + +msgid "Speed:" +msgstr "Hastighet:" + +msgid "Frequency:" +msgstr "Frekvens:" + +msgid "FPU:" +msgstr "Flyttalsprocessor:" + +msgid "Wait states:" +msgstr "Väntcykler:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Minne:" + +msgid "Time synchronization" +msgstr "Synkronisera tid" + +msgid "Disabled" +msgstr "Inaktiverad" + +msgid "Enabled (local time)" +msgstr "Aktiverad (lokal tid)" + +msgid "Enabled (UTC)" +msgstr "Aktiverad (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamisk omkompilering" + +msgid "Video:" +msgstr "Bildskärmskort:" + +msgid "Video #2:" +msgstr "Bildskärmskort #2:" + +msgid "Voodoo 1 or 2 Graphics" +msgstr "Voodoo 1 eller 2-grafik" + +msgid "IBM 8514/A Graphics" +msgstr "IBM 8514/A-grafik" + +msgid "XGA Graphics" +msgstr "XGA-grafik" + +msgid "Mouse:" +msgstr "Mus:" + +msgid "Joystick:" +msgstr "Styrspak:" + +msgid "Joystick 1..." +msgstr "Styrspak 1..." + +msgid "Joystick 2..." +msgstr "Styrspak 2..." + +msgid "Joystick 3..." +msgstr "Styrspak 3..." + +msgid "Joystick 4..." +msgstr "Styrspak 4..." + +msgid "Sound card #1:" +msgstr "Ljudkort #1:" + +msgid "Sound card #2:" +msgstr "Ljudkort #2:" + +msgid "Sound card #3:" +msgstr "Ljudkort #3:" + +msgid "Sound card #4:" +msgstr "Ljudkort #4:" + +msgid "MIDI Out Device:" +msgstr "Enhet för MIDI-utdata:" + +msgid "MIDI In Device:" +msgstr "Enhet för MIDI-indata:" + +msgid "Standalone MPU-401" +msgstr "Fristående MPU-401" + +msgid "Use FLOAT32 sound" +msgstr "Använd FLOAT32-ljud" + +msgid "FM synth driver" +msgstr "Drivrutin för FM-synt" + +msgid "Nuked (more accurate)" +msgstr "Nuked (mer exakt)" + +msgid "YMFM (faster)" +msgstr "YMFM (snabbare)" + +msgid "COM1 Device:" +msgstr "COM1-enhet:" + +msgid "COM2 Device:" +msgstr "COM2-enhet:" + +msgid "COM3 Device:" +msgstr "COM3-enhet:" + +msgid "COM4 Device:" +msgstr "COM4-enhet:" + +msgid "LPT1 Device:" +msgstr "LPT1-enhet:" + +msgid "LPT2 Device:" +msgstr "LPT2-enhet:" + +msgid "LPT3 Device:" +msgstr "LPT3-enhet:" + +msgid "LPT4 Device:" +msgstr "LPT4-enhet:" + +msgid "Serial port 1" +msgstr "Serieport 1" + +msgid "Serial port 2" +msgstr "Serieport 2" + +msgid "Serial port 3" +msgstr "Serieport 3" + +msgid "Serial port 4" +msgstr "Serieport 4" + +msgid "Parallel port 1" +msgstr "Parallellport 1" + +msgid "Parallel port 2" +msgstr "Parallellport 2" + +msgid "Parallel port 3" +msgstr "Parallellport 3" + +msgid "Parallel port 4" +msgstr "Parallellport 4" + +msgid "HD Controller:" +msgstr "Styrenhet för hårddisk:" + +msgid "FD Controller:" +msgstr "Styrenhet för diskett:" + +msgid "Tertiary IDE Controller" +msgstr "Tertiär IDE-kontroller" + +msgid "Quaternary IDE Controller" +msgstr "Kvartär IDE-kontroller" + +msgid "SCSI" +msgstr "SCSI" + +msgid "Controller 1:" +msgstr "Styrenhet 1:" + +msgid "Controller 2:" +msgstr "Styrenhet 2:" + +msgid "Controller 3:" +msgstr "Styrenhet 3:" + +msgid "Controller 4:" +msgstr "Styrenhet 4:" + +msgid "Cassette" +msgstr "Kassettband" + +msgid "Hard disks:" +msgstr "Hårddiskar:" + +msgid "&New..." +msgstr "&Ny..." + +msgid "&Existing..." +msgstr "&Befintlig..." + +msgid "&Remove" +msgstr "&Ta bort" + +msgid "Bus:" +msgstr "Buss:" + +msgid "Channel:" +msgstr "Kanal:" + +msgid "ID:" +msgstr "ID:" + +msgid "&Specify..." +msgstr "&Specificera..." + +msgid "Sectors:" +msgstr "Sektorer:" + +msgid "Heads:" +msgstr "Läshuvuden:" + +msgid "Cylinders:" +msgstr "Cylindrar:" + +msgid "Size (MB):" +msgstr "Storlek (MB):" + +msgid "Type:" +msgstr "Typ:" + +msgid "Image Format:" +msgstr "Avbildningsformat:" + +msgid "Block Size:" +msgstr "Blockstorlek:" + +msgid "Floppy drives:" +msgstr "Diskettenhet:" + +msgid "Turbo timings" +msgstr "Turbo timings" + +msgid "Check BPB" +msgstr "Kontrollera BPB" + +msgid "CD-ROM drives:" +msgstr "CD-ROM-enheter:" + +msgid "MO drives:" +msgstr "MO-enheter:" + +msgid "ZIP drives:" +msgstr "Zip-enheter:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA realtidsklocka:" + +msgid "ISA Memory Expansion" +msgstr "ISA minnesexpansion" + +msgid "Card 1:" +msgstr "Kort 1:" + +msgid "Card 2:" +msgstr "Kort 2:" + +msgid "Card 3:" +msgstr "Kort 3:" + +msgid "Card 4:" +msgstr "Kort 4:" + +msgid "ISABugger device" +msgstr "ISABugger-enhet" + +msgid "POST card" +msgstr "POST-kort" + +msgid "86Box" +msgstr "86Box" + +msgid "Error" +msgstr "Fel" + +msgid "Fatal error" +msgstr "Allvarligt fel" + +msgid " - PAUSED" +msgstr " - PAUSAD" + +msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgstr "Tryck på Ctrl+Alt+PgDn för att återvända till fönsterläge." + +msgid "Speed" +msgstr "Hastighet" + +msgid "ZIP %1 %2 (%3): %4" +msgstr "ZIP %1 %2 (%3): %4" + +msgid "ZIP images" +msgstr "Zip-avbildningar" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "86Box kunde inte hitta några användbara ROM-avbildningar.\n\nVänligen ladda ner en ROM-uppsättning och extrahera den till mappen \"roms\"." + +msgid "(empty)" +msgstr "(tom)" + +msgid "All files" +msgstr "Alla filer" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "På" + +msgid "Off" +msgstr "Av" + +msgid "All images" +msgstr "Alla avbildningar" + +msgid "Basic sector images" +msgstr "Grundläggande sektoravbildningar" + +msgid "Surface images" +msgstr "Ytavbildningar" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Maskinen \"%hs\" är inte tillgänglig på grund av saknade ROM-avbildningar i mappen roms/machines. Byter till en tillgänglig maskin." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Bildskärmskortet \"%hs\" är inte tillgängligt på grund av saknade ROM-avbildningar i mappen roms/video. Byter till ett tillgängligt bildskärmskort." + +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Bildskärmskort #2 \"%hs\" är inte tillgängligt på grund av saknade ROM-avbildningar i mappen roms/video. Avaktiverar det andra bildskärmskortet." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Enheten \"%hs\" är inte tillgänglig på grund av saknade ROM-avbildningar. Ignorerar enheten." + +msgid "Machine" +msgstr "Maskin" + +msgid "Display" +msgstr "Bildskärm" + +msgid "Input devices" +msgstr "Inmatningsenheter" + +msgid "Sound" +msgstr "Ljud" + +msgid "Network" +msgstr "Nätverk" + +msgid "Ports (COM & LPT)" +msgstr "Portar (COM & LPT)" + +msgid "Storage controllers" +msgstr "Styrenheter för lagring" + +msgid "Hard disks" +msgstr "Hårddiskar" + +msgid "Floppy & CD-ROM drives" +msgstr "Diskett- och CD-ROM-enheter" + +msgid "Other removable devices" +msgstr "Andra flyttbara enheter" + +msgid "Other peripherals" +msgstr "Andra tillbehör" + +msgid "Click to capture mouse" +msgstr "Klicka för att fånga upp musen" + +msgid "Press %1 to release mouse" +msgstr "Tryck på %1 för att släppa musen" + +msgid "Press %1 or middle button to release mouse" +msgstr "Tryck på %1 eller mellersta musknappen för att släppa musen" + +msgid "Bus" +msgstr "Buss" + +msgid "File" +msgstr "Fil" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Default" +msgstr "Standard" + +msgid "%1 Wait state(s)" +msgstr "" + +msgid "Type" +msgstr "Typ" + +msgid "No PCap devices found" +msgstr "Inga PCap-enheter hittade" + +msgid "Invalid PCap device" +msgstr "Ogiltig PCap-enhet" + +msgid "2-axis, 2-button joystick(s)" +msgstr "Styrspak med 2 axlar och 2 knappar" + +msgid "2-axis, 4-button joystick" +msgstr "Styrspak med 2 axlar och 4 knappar" + +msgid "2-axis, 6-button joystick" +msgstr "Styrspak med 2 axlar och 6 knappar" + +msgid "2-axis, 8-button joystick" +msgstr "Styrspak med 2 axlar och 8 knappar" + +msgid "3-axis, 2-button joystick" +msgstr "Styrspak med 3 axlar och 2 knappar" + +msgid "3-axis, 4-button joystick" +msgstr "Styrspak med 3 axlar och 4 knappar" + +msgid "4-axis, 4-button joystick" +msgstr "Styrspak med 4 axlar och 4 knappar" + +msgid "CH Flightstick Pro" +msgstr "CH Flightstick Pro" + +msgid "Microsoft SideWinder Pad" +msgstr "Microsoft SideWinder Pad" + +msgid "Thrustmaster Flight Control System" +msgstr "Thrustmaster Flight Control System" + +msgid "None" +msgstr "Ingen" + +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" + +msgid "Floppy %1 (%2): %3" +msgstr "Diskett %1 (%2): %3" + +msgid "Advanced sector images" +msgstr "Avancerade sektoravbildningar" + +msgid "Flux images" +msgstr "Flux-avbildningar" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Är du säker på att du vill göra en hård omstart av den emulerade maskinen?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Är du säker på att du vill avsluta 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "Ej möjligt att initialisera Ghostscript" + +msgid "Unable to initialize GhostPCL" +msgstr "Ej möjligt att initialisera GhostPCL" + +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" + +msgid "MO images" +msgstr "MO-avbildningar" + +msgid "Welcome to 86Box!" +msgstr "Välkommen till 86Box!" + +msgid "Internal device" +msgstr "Intern enhet" + +msgid "Exit" +msgstr "Avsluta" + +msgid "No ROMs found" +msgstr "Inga ROM-avbildningar hittades" + +msgid "Do you want to save the settings?" +msgstr "Vill du spara inställningarna?" + +msgid "This will hard reset the emulated machine." +msgstr "Detta kommer att göra en hård omstart av den emulerade maskinen." + +msgid "Save" +msgstr "Spara" + +msgid "About 86Box" +msgstr "Om 86Box" + +msgid "86Box v" +msgstr "86Box v" + +msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "En emulator av gamla datorer\n\nUpphovsmän: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, med flera.\n\nMed tidigare grundbidrag från Sarah Walker, leilei, JohnElliott, greatpsycho, med flera.\n\nSläppt under GNU General Public License upplaga 2 eller senare. Se LICENSE för mer information." + +msgid "Hardware not available" +msgstr "Hårdvara ej tillgänglig" + +msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." +msgstr "Säkerställ att %1 är installerad och att du använder en %1-kompatibel nätverksanslutning." + +msgid "Invalid configuration" +msgstr "Ogiltig konfiguration" + +msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr "%1 krävs för automatisk omvandling av PostScript-filer till PDF.\n\nAlla dokument som skickats till den allmänna PostScript-skrivaren kommer att sparas som PostScript-filer (.ps)." + +msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." +msgstr "%1 krävs för automatisk omvandling av PCL-filer till PDF.\n\nAlla dokument som skickas till den allmänna PCL-skrivaren kommer att sparas som Printer Command Language-filer (.pcl)." + +msgid "Entering fullscreen mode" +msgstr "Startar helskärmsläge" + +msgid "Don't show this message again" +msgstr "Visa inte detta meddelande igen" + +msgid "Don't exit" +msgstr "Avsluta inte" + +msgid "Reset" +msgstr "Starta om" + +msgid "Don't reset" +msgstr "Starta inte om" + +msgid "CD-ROM images" +msgstr "CD-ROM-avbildningar" + +msgid "%1 Device Configuration" +msgstr "%1 Enhetskonfiguration" + +msgid "Monitor in sleep mode" +msgstr "Skärm i viloläge" + +msgid "GLSL shaders" +msgstr "GLSL shaders" + +msgid "You are loading an unsupported configuration" +msgstr "Du laddar en konfiguration som inte stöds" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "Filtrering av processortyp grundat på den valda maskinen är avaktiverat för denna emulerade maskin.\n\nDetta gör det möjligt att välja en processor som annars är oförenlig med den valda maskinen. Detta kan dock leda till oförenligheter med maskinens BIOS eller annan mjukvara\n\nAtt aktivera denna inställning stöds inte officiellt, och alla felrapporter som lämnas in kan komma att stängas som ogiltiga." + +msgid "Continue" +msgstr "Fortsätt" + +msgid "Cassette: %1" +msgstr "Kassettband: %1" + +msgid "Cassette images" +msgstr "Kassettbandsavbildningar" + +msgid "Cartridge %1: %2" +msgstr "Kassett %1: %2" + +msgid "Cartridge images" +msgstr "Kassettavbildningar" + +msgid "Resume execution" +msgstr "Fortsätt exekvering" + +msgid "Pause execution" +msgstr "Pausa exekvering" + +msgid "Press Ctrl+Alt+Del" +msgstr "Tryck på Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Tryck på Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Hård omstart" + +msgid "ACPI shutdown" +msgstr "ACPI-avstängning" + +msgid "Hard disk (%1)" +msgstr "Hårddisk (%1)" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "MFM/RLL eller ESDI CD-ROM-enheter fanns aldrig" + +msgid "Custom..." +msgstr "Egen..." + +msgid "Custom (large)..." +msgstr "Egen (stor)..." + +msgid "Add New Hard Disk" +msgstr "Lägg till ny hårddisk" + +msgid "Add Existing Hard Disk" +msgstr "Lägg till befintlig hårddisk" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Avbildningar i HDI-format kan inte vara större än 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Avbildningar kan inte vara större än 127 GB." + +msgid "Hard disk images" +msgstr "Hårddiskavbilningar" + +msgid "Unable to read file" +msgstr "Kan inte läsa fil" + +msgid "Unable to write file" +msgstr "Kan inte skriva till fil" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "HDI- eller HDX-avbildningar med en sektorstorlek annat än 512 stöds inte." + +msgid "Disk image file already exists" +msgstr "Avbildningsfil finns redan" + +msgid "Please specify a valid file name." +msgstr "Vänligen ange ett giltigt filnamn." + +msgid "Disk image created" +msgstr "Avbildning skapad" + +msgid "Make sure the file exists and is readable." +msgstr "Säkerställ att filen finns och är läsbar." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Säkerställ att filen sparas till en skrivbar mapp." + +msgid "Disk image too large" +msgstr "Avbildning för stor" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Kom ihåg att partitionera och formatera den skapade enheten." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Den valda filen kommer att skrivas över. Är du säker på att du vill använda den?" + +msgid "Unsupported disk image" +msgstr "Avbildning stöds inte" + +msgid "Overwrite" +msgstr "Skriv över" + +msgid "Don't overwrite" +msgstr "Skriv inte över" + +msgid "Raw image" +msgstr "Rå avbildning" + +msgid "HDI image" +msgstr "HDI-avbildning" + +msgid "HDX image" +msgstr "HDX-avbildning" + +msgid "Fixed-size VHD" +msgstr "VHD med fastställd storlek" + +msgid "Dynamic-size VHD" +msgstr "VHD med dynamisk storlek" + +msgid "Differencing VHD" +msgstr "Differencing-avbildning av VHD" + +msgid "(N/A)" +msgstr "(ej)" + +msgid "Raw image (.img)" +msgstr "Rå avbildning (.img)" + +msgid "HDI image (.hdi)" +msgstr "HDI-avbildning (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "HDX-avbildning (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD med fastställd storlek (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD med dynamisk storlek (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differencing-avbildning av VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Stora block (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Små block (512 KB)" + +msgid "VHD files" +msgstr "VHD-filer" + +msgid "Select the parent VHD" +msgstr "Välj moders-VHDn" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Detta kan betyda att modersavbildningen har ändrats efter att skillnadsavbildningen skapades.\n\nDet kan också hända om avbildningarna har flyttats eller kopierats, eller av en bugg i programmet som skapade denna disk.\n\nVill du laga tidsstämplarna?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Tidsstämpeln på moders- och dotterdisken stämmer inte överens" + +msgid "Could not fix VHD timestamp." +msgstr "Kunde inte laga tidsstämpeln på VHDn." + +msgid "MFM/RLL" +msgstr "MFM/RLL" + +msgid "XTA" +msgstr "XTA" + +msgid "ESDI" +msgstr "ESDI" + +msgid "IDE" +msgstr "IDE" + +msgid "ATAPI" +msgstr "ATAPI" + +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" + +msgid "160 KB" +msgstr "160 KB" + +msgid "180 KB" +msgstr "180 KB" + +msgid "320 KB" +msgstr "320 KB" + +msgid "360 KB" +msgstr "360 KB" + +msgid "640 KB" +msgstr "640 KB" + +msgid "720 KB" +msgstr "720 KB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (kluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (kluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Perfekt varv/min" + +msgid "1% below perfect RPM" +msgstr "1% under perfekt varv/min" + +msgid "1.5% below perfect RPM" +msgstr "1.5% under perfekt varv/min" + +msgid "2% below perfect RPM" +msgstr "2& under perfekt varm/min" + +msgid "(System Default)" +msgstr "(Systemstandard)" + +msgid "Failed to initialize network driver" +msgstr "Kunde inte initialisera drivrutiner för nätverk" + +msgid "The network configuration will be switched to the null driver" +msgstr "Nätverkskonfigurationen kommer att bytas till den tomma drivrutinen" + +msgid "Mouse sensitivity:" +msgstr "Muskänslighet:" + +msgid "Select media images from program working directory" +msgstr "Välj medieavbildningar från programmets arbetsmapp" + +msgid "PIT mode:" +msgstr "PIT-läge:" + +msgid "Auto" +msgstr "Automatisk" + +msgid "Slow" +msgstr "Långsam" + +msgid "Fast" +msgstr "Snabb" + +msgid "&Auto-pause on focus loss" +msgstr "&Pausa automatiskt när fokus tappas" + +msgid "WinBox is no longer supported" +msgstr "WinBox stöds inte längre" + +msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgstr "Utvecklingen av hanteraren WinBox stoppades under 2022 på grund av avsaknad av underhållare. När vi nu riktar våra ansträngningar till att göra 86Box ännu bättre så har vi fattat beslutet att inte längre stödja WinBox som en hanterare.\n\nInga framtida uppdateringar kommer att tillhandahållas genom WinBox, och du kan stöta på felaktiga beteenden om du skulle fortsätta att använda det med nyare versioner av 86Box. Alla felrapporter som har att göra med WinBox kommer att stängas som ogiltiga.\n\nGå till 86Box.net för en lista med andra hanterare som du kan använda." + +msgid "Generate" +msgstr "Generera" + +msgid "Joystick configuration" +msgstr "Konfiguration av styrspak" + +msgid "Device" +msgstr "Enhet" + +msgid "%1 (X axis)" +msgstr "%1 (X-axeln)" + +msgid "%1 (Y axis)" +msgstr "%1 (Y-axeln)" + +msgid "MCA devices" +msgstr "MCA-enheter" + +msgid "List of MCA devices:" +msgstr "Lista på MCA-enheter:" + +msgid "Tablet tool" +msgstr "Plattverktyg" + +msgid "Qt (OpenGL &ES)" +msgstr "Qt (OpenGL &ES)" + +msgid "About Qt" +msgstr "Om Qt" + +msgid "MCA devices..." +msgstr "MCA-enheter..." + +msgid "Show non-primary monitors" +msgstr "Visa icke-primära skärmar" + +msgid "Open screenshots folder..." +msgstr "Öppna skärmbildsmappen..." + +msgid "Apply fullscreen stretch mode when maximized" +msgstr "Tillämpa sträckläge för helskärm när den är maximerad" + +msgid "Cursor/Puck" +msgstr "Pekare/puck" + +msgid "Pen" +msgstr "Penna" + +msgid "Host CD/DVD Drive (%1:)" +msgstr "Värdenhet för CD/DVD (%1:)" + +msgid "&Connected" +msgstr "&Ansluten" + +msgid "Clear image history" +msgstr "Rensa historik för avbildningar" + +msgid "Create..." +msgstr "Skapa..." + +msgid "Host CD/DVD Drive (%1)" +msgstr "Värdenhet för CD/DVD (%1)" + +msgid "Unknown Bus" +msgstr "Okänd buss" + +msgid "Null Driver" +msgstr "Tom drivrutin" + +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" + +msgid "Render behavior" +msgstr "Renderingsbeteende" + +msgid "Use target framerate:" +msgstr "Använd målbildhatighet:" + +msgid " fps" +msgstr " Bildhastighet" + +msgid "VSync" +msgstr "VSync" + +msgid "Synchronize with video" +msgstr "Synkronisera med bild" + +msgid "Shaders" +msgstr "" + +msgid "Remove" +msgstr "Ta bort" + +msgid "Browse..." +msgstr "Bläddra..." + +msgid "Couldn't create OpenGL context." +msgstr "Kunde inte skapa OpenGL-sammanhang." + +msgid "Couldn't switch to OpenGL context." +msgstr "Kunde inte växla till OpenGL-sammanhang." + +msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" +msgstr "OpenGL version 3.0 eller högre krävs. Nuvarande version är %1.%2" + +msgid "Error initializing OpenGL" +msgstr "Fel vid initialisering av OpenGL" + +msgid "\nFalling back to software rendering." +msgstr "\nFaller tillbaka på mjukvarurendering." + +msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" +msgstr "<html><head/><body><p>Vid val av medieavbildningar (CD-ROM, diskett, osv.) så kommer fönstret att börja i samma mapp som 86Box konfigurationsfil. Denna inställning kommer troligtvis endast göra en skillnad på macOS.</p></body></html>" + +msgid "This machine might have been moved or copied." +msgstr "Denna maskin kan ha flyttats eller kopierats." + +msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." +msgstr "För att säkerställa korrekt funktionalitet av nätverk så behöver 86Box veta om denna maskin har flyttats eller kopierats.\n\nVälj \"Jag kopierade den\" om du är osäker." + +msgid "I Moved It" +msgstr "Jag flyttade den" + +msgid "I Copied It" +msgstr "Jag kopierade den" + +msgid "86Box Monitor #" +msgstr "86Box skärm #" + +msgid "No MCA devices." +msgstr "Inga MCA-enheter." + +msgid "MiB" +msgstr "MiB" + +msgid "Network Card #1" +msgstr "Nätverkskort #1" + +msgid "Network Card #2" +msgstr "Nätverkskort #2" + +msgid "Network Card #3" +msgstr "Nätverkskort #3" + +msgid "Network Card #4" +msgstr "Nätverkskort #4" + +msgid "Mode:" +msgstr "Läge:" + +msgid "Interface:" +msgstr "Gränssnitt:" + +msgid "Adapter:" +msgstr "Adapter:" + +msgid "VDE Socket:" +msgstr "VDE-sockel:" + +msgid "86Box Unit Tester" +msgstr "86Box enhetsprövare" + +msgid "Novell NetWare 2.x Key Card" +msgstr "Novell NetWare 2.x nyckelkort" + +msgid "Serial port passthrough 1" +msgstr "Serieport passthrough 1" + +msgid "Serial port passthrough 2" +msgstr "Serieport passthrough 2" + +msgid "Serial port passthrough 3" +msgstr "Serieport passthrough 3" + +msgid "Serial port passthrough 4" +msgstr "Serieport passthrough 4" + +msgid "Renderer options..." +msgstr "Renderingsalternativ..." + +msgid "Logitech/Microsoft Bus Mouse" +msgstr "Logitech/Microsoft-buss-mus" + +msgid "Microsoft Bus Mouse (InPort)" +msgstr "Microsoft-buss-mus (InPort)" + +msgid "Mouse Systems Serial Mouse" +msgstr "Mouse Systems seriemus" + +msgid "Microsoft Serial Mouse" +msgstr "Microsoft seriemus" + +msgid "Logitech Serial Mouse" +msgstr "Logitech seriemus" + +msgid "PS/2 Mouse" +msgstr "PS/2-mus" + +msgid "3M MicroTouch (Serial)" +msgstr "3M MicroTouch (serie)" + +msgid "[COM] Standard Hayes-compliant Modem" +msgstr "[COM] Standard Hayes-kompatibelt modem" + +msgid "Roland MT-32 Emulation" +msgstr "Roland MT-32 emulering" + +msgid "Roland MT-32 (New) Emulation" +msgstr "Roland MT-32 (ny) emulering" + +msgid "Roland CM-32L Emulation" +msgstr "Roland CM-32L emulering" + +msgid "Roland CM-32LN Emulation" +msgstr "Roland CM-32LN emulering" + +msgid "OPL4-ML Daughterboard" +msgstr "OPL4-ML dotterkort" + +msgid "System MIDI" +msgstr "System-MIDI" + +msgid "MIDI Input Device" +msgstr "Indataenhet för MIDI" + +msgid "BIOS Address" +msgstr "BIOS-adress" + +msgid "Enable BIOS extension ROM Writes" +msgstr "Aktivera ROM-skrivningar för utökat BIOS" + +msgid "Address" +msgstr "Adress" + +msgid "IRQ" +msgstr "IRQ" + +msgid "BIOS Revision" +msgstr "BIOS revision" + +msgid "Translate 26 -> 17" +msgstr "Översätt 26 -> 17" + +msgid "Language" +msgstr "Språk" + +msgid "Enable backlight" +msgstr "Aktivera bakgrundsbelysning" + +msgid "Invert colors" +msgstr "Invertera färger" + +msgid "BIOS size" +msgstr "Storlek på BIOS" + +msgid "Map C0000-C7FFF as UMB" +msgstr "Kartlägg C0000-C7FFF som UMB" + +msgid "Map C8000-CFFFF as UMB" +msgstr "Kartlägg C8000-CFFFF som UMB" + +msgid "Map D0000-D7FFF as UMB" +msgstr "Kartlägg D0000-D7FFF som UMB" + +msgid "Map D8000-DFFFF as UMB" +msgstr "Kartlägg D8000-DFFFF som UMB" + +msgid "Map E0000-E7FFF as UMB" +msgstr "Kartlägg E0000-E7FFF som UMB" + +msgid "Map E8000-EFFFF as UMB" +msgstr "Kartlägg E8000-EFFFF som UMB" + +msgid "JS9 Jumper (JIM)" +msgstr "JS9-bygel (JIM)" + +msgid "MIDI Output Device" +msgstr "Utdataenhet för MIDI" + +msgid "MIDI Real time" +msgstr "Realtid för MIDI" + +msgid "MIDI Thru" +msgstr "MIDI genom" + +msgid "MIDI Clockout" +msgstr "MIDI utklockning" + +msgid "SoundFont" +msgstr "Ljudsnitt" + +msgid "Output Gain" +msgstr "Förstärkning av utmatning" + +msgid "Chorus" +msgstr "Chorus" + +msgid "Chorus Voices" +msgstr "Chorus voices" + +msgid "Chorus Level" +msgstr "Chorus nivå" + +msgid "Chorus Speed" +msgstr "Chorus hastighet" + +msgid "Chorus Depth" +msgstr "Chorus djup" + +msgid "Chorus Waveform" +msgstr "Chorus vågform" + +msgid "Reverb" +msgstr "Reverb" + +msgid "Reverb Room Size" +msgstr "Reverb rumsstorlek" + +msgid "Reverb Damping" +msgstr "Reverb dämpning" + +msgid "Reverb Width" +msgstr "Reverb bredd" + +msgid "Reverb Level" +msgstr "Reverb nivå" + +msgid "Interpolation Method" +msgstr "Interpoleringsmetod" + +msgid "Reverb Output Gain" +msgstr "Reverb utmatningsförstärkning" + +msgid "Reversed stereo" +msgstr "Omvänd stereo" + +msgid "Nice ramp" +msgstr "Nice ramp" + +msgid "Hz" +msgstr "Hz" + +msgid "Buttons" +msgstr "Knappar" + +msgid "Serial Port" +msgstr "Serieport" + +msgid "RTS toggle" +msgstr "RTS-brytare" + +msgid "Revision" +msgstr "Revision" + +msgid "Controller" +msgstr "Styrenhet" + +msgid "Show Crosshair" +msgstr "Visa hårkors" + +msgid "DMA" +msgstr "DMA" + +msgid "MAC Address" +msgstr "MAC-adress" + +msgid "MAC Address OUI" +msgstr "MAC-adress OUI" + +msgid "Enable BIOS" +msgstr "Aktivera BIOS" + +msgid "Baud Rate" +msgstr "Baudhastighet" + +msgid "TCP/IP listening port" +msgstr "TCP/IP lyssningsport" + +msgid "Phonebook File" +msgstr "Telefonsboksfil" + +msgid "Telnet emulation" +msgstr "Telnet-emulering" + +msgid "RAM Address" +msgstr "RAM-adress" + +msgid "RAM size" +msgstr "RAM-storlek" + +msgid "Initial RAM size" +msgstr "Ursprunglig RAM-storlek" + +msgid "Serial Number" +msgstr "Serienummer" + +msgid "Host ID" +msgstr "Värd-ID" + +msgid "FDC Address" +msgstr "Adress till diskettstyrenhet" + +msgid "MPU-401 Address" +msgstr "Adress till MPU-401" + +msgid "MPU-401 IRQ" +msgstr "MPU-401 IRQ" + +msgid "Receive MIDI input" +msgstr "Ta emot MIDI-indata" + +msgid "Low DMA" +msgstr "Låg DMA" + +msgid "Enable Game port" +msgstr "Aktivera spelport" + +msgid "Surround module" +msgstr "Sorround-modul" + +msgid "CODEC" +msgstr "CODEC" + +msgid "Raise CODEC interrupt on CODEC setup (needed by some drivers)" +msgstr "Öka avbrottsnummer för CODEC vid CODEC-installation (krävs av vissa drivrutiner)" + +msgid "SB Address" +msgstr "Adress för SB" + +msgid "WSS IRQ" +msgstr "WSS IRQ" + +msgid "WSS DMA" +msgstr "WSS DMA" + +msgid "Enable OPL" +msgstr "Aktivera OPL" + +msgid "Receive MIDI input (MPU-401)" +msgstr "Ta emot MIDI-indata (MPU-401)" + +msgid "SB low DMA" +msgstr "Låg DMA för SB" + +msgid "6CH variant (6-channel)" +msgstr "6CH-variant (6-kanals)" + +msgid "Enable CMS" +msgstr "Aktivera CMS" + +msgid "Mixer" +msgstr "Mixer" + +msgid "High DMA" +msgstr "Hög DMA" + +msgid "Control PC speaker" +msgstr "Styr PC-speaker" + +msgid "Memory size" +msgstr "Minnesstorlek" + +msgid "EMU8000 Address" +msgstr "Adress till EMU8000" + +msgid "IDE Controller" +msgstr "IDE-styrenhet" + +msgid "Codec" +msgstr "Kodek" + +msgid "GUS type" +msgstr "GUS-typ" + +msgid "Enable 0x04 \"Exit 86Box\" command" +msgstr "Aktivera kommandot 0x04 \"Avsluta 86Box\"" + +msgid "Display type" +msgstr "Skärmtyp" + +msgid "Composite type" +msgstr "Komposittyp" + +msgid "RGB type" +msgstr "RGB-typ" + +msgid "Line doubling type" +msgstr "Linjefördubblingstyp" + +msgid "Snow emulation" +msgstr "Snöemulering" + +msgid "Monitor type" +msgstr "Bildskärmstyp" + +msgid "Character set" +msgstr "Teckenuppsättning" + +msgid "XGA type" +msgstr "XGA-typ" + +msgid "Instance" +msgstr "Instans" + +msgid "MMIO Address" +msgstr "Adress för MMIO" + +msgid "RAMDAC type" +msgstr "RAMDAC-typ" + +msgid "Blend" +msgstr "Blanda" + +msgid "Bilinear filtering" +msgstr "Bilinjär filtrering" + +msgid "Dithering" +msgstr "Dithering" + +msgid "Enable NMI for CGA emulation" +msgstr "Aktivera NMI till CGA-emulering" + +msgid "Voodoo type" +msgstr "Voodoo-typ" + +msgid "Framebuffer memory size" +msgstr "Minnesstorlek för videobuffert" + +msgid "Texture memory size" +msgstr "Minnesstorlek för texturer" + +msgid "Dither subtraction" +msgstr "Dither subtraktion" + +msgid "Screen Filter" +msgstr "Skärmfilter" + +msgid "Render threads" +msgstr "Renderingstrådar" + +msgid "SLI" +msgstr "SLI" + +msgid "Start Address" +msgstr "Startadress" + +msgid "Contiguous Size" +msgstr "Angränsande storlek" + +msgid "I/O Width" +msgstr "I/O-bredd" + +msgid "Transfer Speed" +msgstr "Överföringshastighet" + +msgid "EMS mode" +msgstr "EMS-läge" + +msgid "Address for > 2 MB" +msgstr "Adress till > 2 MB" + +msgid "Frame Address" +msgstr "Bildadress" + +msgid "USA" +msgstr "Förenta staterna" + +msgid "Danish" +msgstr "Danska" + +msgid "Always at selected speed" +msgstr "Alltid vid den valda hastigheten" + +msgid "BIOS setting + Hotkeys (off during POST)" +msgstr "BIOS-inställningar + Snabbtangenter (av under POST)" + +msgid "64 kB starting from F0000" +msgstr "64 kB som börjar från F0000" + +msgid "128 kB starting from E0000 (address MSB inverted, last 64KB first)" +msgstr "128 kB som börjar från E0000 (adress MSB inverterad, de sista 64KB först)" + +msgid "Sine" +msgstr "Sinus" + +msgid "Triangle" +msgstr "Triangel" + +msgid "Linear" +msgstr "Linjär" + +msgid "4th Order" +msgstr "Fjärde ordningen" + +msgid "7th Order" +msgstr "Sjunde ordningen" + +msgid "Non-timed (original)" +msgstr "Ej tajmad (ursprunglig)" + +msgid "45 Hz (JMP2 not populated)" +msgstr "45 Hz (JMP2 ej byglad)" + +msgid "Two" +msgstr "Två" + +msgid "Three" +msgstr "Tre" + +msgid "Wheel" +msgstr "Hjul" + +msgid "Five + Wheel" +msgstr "Fem med hjul" + +msgid "Five + 2 Wheels" +msgstr "" + +msgid "A3 - SMT2 Serial / SMT3(R)V" +msgstr "A3 - SMT2 serie / SMT3(R)V" + +msgid "Q1 - SMT3(R) Serial" +msgstr "Q1 - SMT3(R) serie" + +msgid "8 KB" +msgstr "8 KB" + +msgid "32 KB" +msgstr "32 KB" + +msgid "16 KB" +msgstr "16 KB" + +msgid "64 KB" +msgstr "64 KB" + +msgid "Disable BIOS" +msgstr "Avaktivera BIOS" + +msgid "512 KB" +msgstr "512 KB" + +msgid "2 MB" +msgstr "2 MB" + +msgid "8 MB" +msgstr "8 MB" + +msgid "28 MB" +msgstr "28 MB" + +msgid "1 MB" +msgstr "1 MB" + +msgid "4 MB" +msgstr "4 MB" + +msgid "12 MB" +msgstr "12 MB" + +msgid "16 MB" +msgstr "16 MB" + +msgid "20 MB" +msgstr "20 MB" + +msgid "24 MB" +msgstr "24 MB" + +msgid "SigmaTel STAC9721T (stereo)" +msgstr "SigmaTel STAC9721T (stereo)" + +msgid "Classic" +msgstr "Klassisk" + +msgid "256 KB" +msgstr "256 KB" + +msgid "Composite" +msgstr "Komposit" + +msgid "Old" +msgstr "Gammal" + +msgid "New" +msgstr "Ny" + +msgid "Color (generic)" +msgstr "Färg (allmän)" + +msgid "Green Monochrome" +msgstr "Grön monokrom" + +msgid "Amber Monochrome" +msgstr "Bärnstensfärgad monokrom" + +msgid "Gray Monochrome" +msgstr "Grå monokrom" + +msgid "Color (no brown)" +msgstr "Färg (utan brun)" + +msgid "Color (IBM 5153)" +msgstr "Färg (IBM 5153)" + +msgid "Simple doubling" +msgstr "Enkel fördubbling" + +msgid "sRGB interpolation" +msgstr "sRGB-interpolering" + +msgid "Linear interpolation" +msgstr "Linjär interpolering" + +msgid "128 KB" +msgstr "128 KB" + +msgid "Monochrome (5151/MDA) (white)" +msgstr "Monokrom (5151/MDA) (vit)" + +msgid "Monochrome (5151/MDA) (green)" +msgstr "Monokrom (5151/MDA) (grön)" + +msgid "Monochrome (5151/MDA) (amber)" +msgstr "Monokrom (5151/MDA) (bärnstensfärgad)" + +msgid "Color 40x25 (5153/CGA)" +msgstr "Färg 40x25 (5153/CGA)" + +msgid "Color 80x25 (5153/CGA)" +msgstr "Färg 80x25 (5153/CGA)" + +msgid "Enhanced Color - Normal Mode (5154/ECD)" +msgstr "Utökad färg - normalt läge (5154/ECD)" + +msgid "Enhanced Color - Enhanced Mode (5154/ECD)" +msgstr "Utökad färg - utökat läge (5154/ECD)" + +msgid "Green" +msgstr "Grön" + +msgid "Amber" +msgstr "Bärnstensfärgad" + +msgid "Gray" +msgstr "Grå" + +msgid "Color" +msgstr "Färg" + +msgid "U.S. English" +msgstr "Amerikansk engelska" + +msgid "Scandinavian" +msgstr "Skandinaviska" + +msgid "Other languages" +msgstr "Andra språk" + +msgid "Bochs latest" +msgstr "Bochs senaste" + +msgid "Mono Non-Interlaced" +msgstr "Ej sammanflätad monokrom" + +msgid "Color Interlaced" +msgstr "Sammanflätad färg" + +msgid "Color Non-Interlaced" +msgstr "Ej sammanflätad färg" + +msgid "3Dfx Voodoo Graphics" +msgstr "3Dfx Voodoo-grafik" + +msgid "Obsidian SB50 + Amethyst (2 TMUs)" +msgstr "Obsidian SB50 + Amethyst (2 TMUs)" + +msgid "8-bit" +msgstr "8-bitar" + +msgid "16-bit" +msgstr "16-bitar" + +msgid "Standard (150ns)" +msgstr "Standard (150ns)" + +msgid "High-Speed (120ns)" +msgstr "Höghastighet (120ns)" + +msgid "Enabled" +msgstr "Aktiverad" + +msgid "Standard" +msgstr "Standard" + +msgid "High-Speed" +msgstr "Höghastighet" + +msgid "Stereo LPT DAC" +msgstr "Stereo LPT DAC" + +msgid "Generic Text Printer" +msgstr "Allmän textskrivare" + +msgid "Generic ESC/P Dot-Matrix Printer" +msgstr "Allmän ESC/P punktmatrisskrivare" + +msgid "Generic PostScript Printer" +msgstr "Allmän PostScript-skrivare" + +msgid "Generic PCL5e Printer" +msgstr "Allmän PCL5e-skrivare" + +msgid "Parallel Line Internet Protocol" +msgstr "Parallel Line Internet Protocol" + +msgid "Protection Dongle for Savage Quest" +msgstr "Skyddsdongel till Savage Quest" + +msgid "Serial Passthrough Device" +msgstr "Seriepassthrough-enhet" + +msgid "Passthrough Mode" +msgstr "Passthrough-läge" + +msgid "Host Serial Device" +msgstr "Värd-serieenhet" + +msgid "Name of pipe" +msgstr "Namn på pipe" + +msgid "Data bits" +msgstr "Databitar" + +msgid "Stop bits" +msgstr "Stopbitar" + +msgid "Baud Rate of Passthrough" +msgstr "Passthroughns Baudhastighet" + +msgid "Named Pipe (Server)" +msgstr "Namngiven pipe (server)" + +msgid "Host Serial Passthrough" +msgstr "Värd-seriepassthrough" + +msgid "E&ject %1" +msgstr "M&ata ut %1" + +msgid "&Unmute" +msgstr "&Avtysta" + +msgid "Softfloat FPU" +msgstr "Softfloat flyttalsprocessor" + +msgid "High performance impact" +msgstr "Hög påverkan på prestanda" + +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Allmän] RAM-disk (max hastighet)" + +msgid "[Generic] 1989 (3500 RPM)" +msgstr "[Allmän] 1989 (3500 varv/min)" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "[Allmän] 1992 (3600 varv/min)" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "[Allmän] 1994 (4500 varv/min)" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "[Allmän] 1996 (5400 varv/min)" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "[Allmän] 1997 (5400 varv/min)" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "[Allmän] 1998 (5400 varv/min)" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "[Allmän] 2000 (7200 varv/min)" + +msgid "IBM 8514/A clone (ISA)" +msgstr "IBM 8514/A-klon (ISA)" + +msgid "Vendor" +msgstr "Leverantör" + +msgid "30 Hz (JMP2 = 1)" +msgstr "30 Hz (JMP2 = 1)" + +msgid "60 Hz (JMP2 = 2)" +msgstr "60 Hz (JMP2 = 2)" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Allmän minnesexpansion för PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Allmän minnesexpansion PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Kunde inte hitta typsnitt för punktmatris" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." +msgstr "TrueType-typsnitt i mappen \"roms/printer/fonts\" krävs för emulering av den allmänna ESC/P punktmatrisskrivaren." + +msgid "Inhibit multimedia keys" +msgstr "Hindra multimediatangenter" + +msgid "Ask for confirmation before saving settings" +msgstr "Bekräfta innan inställningarna sparas" + +msgid "Ask for confirmation before hard resetting" +msgstr "Bekräfta innan hård omstart" + +msgid "Ask for confirmation before quitting" +msgstr "Bekräfta innan avslut" + +msgid "Display hotkey message when entering full-screen mode" +msgstr "Visa meddelande om snabbtangenter när helskärmsläget startas" + +msgid "Options" +msgstr "Alternativ" + +msgid "Model" +msgstr "Modell" + +msgid "Model:" +msgstr "Modell:" + +msgid "Failed to initialize Vulkan renderer." +msgstr "Kunde inte initialisera Vulkan-renderaren" + +msgid "GLSL Error" +msgstr "GLSL-fel" + +msgid "Could not load shader: %1" +msgstr "Kunde inte ladda shader: %1" + +msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" +msgstr "OpenGL version 3.0 eller högre krävs. Nuvarande GLSL-version är %1.%2" + +msgid "Could not load texture: %1" +msgstr "Kunde inte ladda textur: %1" + +msgid "Could not compile shader:\n\n%1" +msgstr "Kunde inte kompilera shader:\n\n%1" + +msgid "Program not linked:\n\n%1" +msgstr "Program inte länkat:\n\n%1" + +msgid "Shader Manager" +msgstr "Shader-hanterare" + +msgid "Shader Configuration" +msgstr "Shader-inställningar" + +msgid "Add" +msgstr "Lägg till" + +msgid "Move up" +msgstr "Flytta upp" + +msgid "Move down" +msgstr "Flytta ner" + +msgid "Could not load file %1" +msgstr "Kunde inte ladda fil %1" diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 3903c9d9f..4894b99c0 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -68,6 +68,7 @@ QVector> ProgSettings::languages = { { "ru-RU", "Russian (Russia)" }, { "sk-SK", "Slovak (Slovakia)" }, { "sl-SI", "Slovenian (Slovenia)" }, + { "sv-SE", "Swedish (Sweden)" }, { "es-ES", "Spanish (Spain)" }, { "tr-TR", "Turkish (Turkey)" }, { "uk-UA", "Ukrainian (Ukraine)" }, diff --git a/src/qt/qt_translations.qrc.in b/src/qt/qt_translations.qrc.in index 655323563..c050747c0 100644 --- a/src/qt/qt_translations.qrc.in +++ b/src/qt/qt_translations.qrc.in @@ -20,6 +20,7 @@ 86box_ru-RU.qm 86box_sk-SK.qm 86box_sl-SI.qm + 86box_sv-SE.qm 86box_tr-TR.qm 86box_uk-UA.qm 86box_vi-VN.qm From 38389579c4b89fa9817c56f27490443f17dc1043 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:23:23 +0200 Subject: [PATCH 0753/1190] Add Acer P3 (SiS 496). --- src/machine/m_at_386dx_486.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 4e659dd77..ef30a5aa4 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1182,6 +1182,39 @@ machine_at_ms4144_init(const machine_t *model) return ret; } +int +machine_at_acerp3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerp3/Acer Mate 600 P3 BIOS U13 V2.0R02-J3 ACR8DE00-S00-950911-R02-J3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + machine_at_sis_85c496_common_init(model); + device_add(&sis_85c496_device); + pci_register_slot(0x09, PCI_CARD_VIDEO, 0, 0, 0, 0); + pci_register_slot(0x0A, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&fdc37c665_ide_device); + device_add(&keyboard_ps2_acer_pci_device); + device_add(&ide_cmd640_pci_legacy_only_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(&gd5434_onboard_pci_device); + + device_add(&intel_flash_bxt_device); + + return ret; +} + int machine_at_486sp3c_init(const machine_t *model) { From 658a00b4c7e3bfea85f095705275c73151220633 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:25:16 +0200 Subject: [PATCH 0754/1190] Add Acer P3 machine table entry. --- src/machine/machine_table.c | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 42ac79417..39d9cc9ff 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8357,6 +8357,45 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[SiS 496] Acer P3", + .internal_name = "acerp3", + .type = MACHINE_TYPE_486_S3_PCI, + .chipset = MACHINE_CHIPSET_SIS_496, + .init = machine_at_acerp3_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, + .ram = { + .min = 2048, + .max = 131072, + .step = 1024 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ { .name = "[SiS 496] ASUS PVI-486SP3C", From 40eaeb6ed5897ce9314f5e23ea4be24c422763a4 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:26:16 +0200 Subject: [PATCH 0755/1190] Add Acer P3 machine definition. --- src/include/86box/machine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 5a552d6eb..4469b55c2 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -571,6 +571,7 @@ extern int machine_at_r418_init(const machine_t *); extern int machine_at_ls486e_init(const machine_t *); extern int machine_at_4dps_init(const machine_t *); extern int machine_at_ms4144_init(const machine_t *); +extern int machine_at_acerp3_init(const machine_t *); extern int machine_at_4saw2_init(const machine_t *); extern int machine_at_m4li_init(const machine_t *); extern int machine_at_alfredo_init(const machine_t *); From af908dadc65ff09f4abf0bbe4ec603ba6cc78ba1 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Fri, 18 Apr 2025 22:32:37 +0700 Subject: [PATCH 0756/1190] Fixed internal_name for Phoenix PS/2 PCI KBC --- src/device/kbc_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index f8fd33e62..447c07780 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2807,7 +2807,7 @@ const device_t keyboard_ps2_acer_pci_device = { const device_t keyboard_ps2_phoenix_pci_device = { .name = "PS/2 Keyboard (Phoenix)", - .internal_name = "keyboard_ps2_acer_pci", + .internal_name = "keyboard_ps2_phoenix_pci", .flags = DEVICE_KBC | DEVICE_PCI, .local = KBC_TYPE_PS2_1 | KBC_VEN_PHOENIX, .init = kbc_at_init, From 13ac57da95999fa58b5cf2a899abd86e76446816 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Sat, 19 Apr 2025 13:48:22 +0500 Subject: [PATCH 0757/1190] workflows: Don't rebuild libsndfile on macOS --- .github/workflows/cmake_macos.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/cmake_macos.yml b/.github/workflows/cmake_macos.yml index 5a0454385..2ae417e13 100644 --- a/.github/workflows/cmake_macos.yml +++ b/.github/workflows/cmake_macos.yml @@ -56,22 +56,13 @@ jobs: - name: SDL GUI qt: off static: on - src-packages: >- - libsndfile - name: Qt GUI qt: on slug: -Qt packages: >- qt@5 - src-packages: >- - libsndfile steps: - - name: Install source dependencies - run: >- - brew reinstall -s - ${{ matrix.ui.src-packages }} - - name: Install dependencies run: >- brew install @@ -158,22 +149,13 @@ jobs: - name: SDL GUI qt: off static: on - src-packages: >- - libsndfile - name: Qt GUI qt: on slug: -Qt packages: >- qt@5 - src-packages: >- - libsndfile steps: - - name: Install source dependencies - run: >- - brew reinstall -s - ${{ matrix.ui.src-packages }} - - name: Install dependencies run: >- brew install From bfb3ff8460395219d752f2893cf550e8824258b9 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 19 Apr 2025 18:53:20 -0300 Subject: [PATCH 0758/1190] 7sbb: Fix AGP bridge IRQ links --- src/machine/m_at_socket370.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index b2e311166..3f8db4e8c 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -561,11 +561,11 @@ machine_at_7sbb_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x02, PCI_CARD_AGPBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x02, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&sis_5600_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&it8661f_device); device_add(&sst_flash_29ee020_device); /* assumed */ return ret; -} \ No newline at end of file +} From 7f5d1b86c76c7afb401ec865617366670556a793 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 19 Apr 2025 19:44:47 -0700 Subject: [PATCH 0759/1190] Added keybind customization system --- CMakeLists.txt | 2 +- src/86box.c | 24 ++++-- src/config.c | 84 +++++++++++++++++++ src/device/keyboard.c | 21 ----- src/include/86box/86box.h | 18 ++-- src/qt/CMakeLists.txt | 5 ++ src/qt/qt.c | 2 +- src/qt/qt_mainwindow.cpp | 70 ++++++++++++++-- src/qt/qt_mainwindow.hpp | 6 +- src/qt/qt_settingsinput.cpp | 159 +++++++++++++++++++++++++++++++++++- src/qt/qt_settingsinput.hpp | 11 +++ src/qt/qt_settingsinput.ui | 118 ++++++++++++++++---------- 12 files changed, 429 insertions(+), 91 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 007c1ffd8..a6ffa89e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ if(WIN32) # Default value for the `WIN32` target property, which specifies whether # to build the application for the Windows GUI or console subsystem - option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" ON) + option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" OFF) else() # Prefer dynamic builds everywhere else set(PREFER_STATIC OFF) diff --git a/src/86box.c b/src/86box.c index 168e8a8dc..d8c05c8bb 100644 --- a/src/86box.c +++ b/src/86box.c @@ -222,6 +222,9 @@ int other_ide_present = 0; /* IDE control int other_scsi_present = 0; /* SCSI controllers from non-SCSI cards are present */ +// Accelerator key array +struct accelKey acc_keys[NUM_ACCELS]; + /* Statistics. */ extern int mmuflush; extern int readlnum; @@ -654,7 +657,6 @@ usage: #ifdef USE_INSTRUMENT printf("-J or --instrument name - set 'name' to be the profiling instrument\n"); #endif - printf("-K or --keycodes codes - set 'codes' to be the uncapture combination\n"); printf("-L or --logfile path - set 'path' to be the logfile\n"); printf("-M or --missing - dump missing machines and video cards\n"); printf("-N or --noconfirm - do not ask for confirmation on quit\n"); @@ -745,13 +747,6 @@ usage: do_nothing = 1; } else if (!strcasecmp(argv[c], "--nohook") || !strcasecmp(argv[c], "-W")) { hook_enabled = 0; - } else if (!strcasecmp(argv[c], "--keycodes") || !strcasecmp(argv[c], "-K")) { - if ((c + 1) == argc) - goto usage; - - sscanf(argv[++c], "%03hX,%03hX,%03hX,%03hX,%03hX,%03hX", - &key_prefix_1_1, &key_prefix_1_2, &key_prefix_2_1, &key_prefix_2_2, - &key_uncapture_1, &key_uncapture_2); } else if (!strcasecmp(argv[c], "--clearboth") || !strcasecmp(argv[c], "-X")) { if ((c + 1) == argc) goto usage; @@ -1789,3 +1784,16 @@ do_pause(int p) } atomic_store(&pause_ack, 0); } + +// Helper to find an accelerator key and return it's index in acc_keys +int FindAccelerator(const char *name) { + for(int x=0;x= QT_VERSION_CHECK(6, 0, 0) - auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this); + windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this); #else - auto windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this); + windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this); #endif windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); connect(windowedShortcut, &QShortcut::activated, this, [this] () { @@ -761,6 +762,8 @@ MainWindow::MainWindow(QWidget *parent) }); } #endif + + updateShortcuts(); } void @@ -826,6 +829,56 @@ MainWindow::closeEvent(QCloseEvent *event) event->accept(); } + +void MainWindow::updateShortcuts() +{ + // Update menu shortcuts from accelerator table + // Note that the "Release mouse" shortcut is hardcoded elsewhere + // This section only applies to shortcuts anchored to UI elements + + ui->actionTake_screenshot->setShortcut(QKeySequence()); + ui->actionCtrl_Alt_Del->setShortcut(QKeySequence()); + ui->actionCtrl_Alt_Esc->setShortcut(QKeySequence()); + ui->actionFullscreen->setShortcut(QKeySequence()); + ui->actionHard_Reset->setShortcut(QKeySequence()); + + int accID; + QKeySequence seq; + + accID = FindAccelerator("screenshot"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionTake_screenshot->setShortcut(seq); + + accID = FindAccelerator("send_ctrl_alt_del"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionCtrl_Alt_Del->setShortcut(seq); + + accID = FindAccelerator("send_ctrl_alt_esc"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionCtrl_Alt_Esc->setShortcut(seq); + + accID = FindAccelerator("fullscreen"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + //printf("shortcut: %s\n", qPrintable(ui->actionFullscreen->shortcut().toString())); + ui->actionFullscreen->setShortcut(seq); + + accID = FindAccelerator("hard_reset"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionHard_Reset->setShortcut(seq); + + // To rebind leave_fullscreen we have to disconnect the existing signal, + // build a new shortcut, then connect it. + accID = FindAccelerator("leave_fullscreen"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + disconnect(windowedShortcut,0,0,0); + windowedShortcut = new QShortcut(seq, this); + windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); + connect(windowedShortcut, &QShortcut::activated, this, [this] () { + if (video_fullscreen) + ui->actionFullscreen->trigger(); + }); +} + void MainWindow::resizeEvent(QResizeEvent *event) { @@ -1026,6 +1079,8 @@ MainWindow::on_actionSettings_triggered() case QDialog::Accepted: settings.save(); config_changed = 2; + printf("about to try\n"); + updateShortcuts(); pc_reset_hard(); break; case QDialog::Rejected: @@ -1394,9 +1449,14 @@ MainWindow::keyPressEvent(QKeyEvent *event) #endif } - if (keyboard_ismsexit()) - plat_mouse_capture(0); - + // Check if mouse release combo has been entered + int accID = FindAccelerator("release_mouse"); + QKeySequence seq = QKeySequence::fromString(acc_keys[accID].seq); + if (seq[0] == (event->key() | event->modifiers())) + plat_mouse_capture(0); + + // TODO: Other accelerators should probably be here? + event->accept(); } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 739d179ff..99b0021c2 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,8 @@ public: QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); void reloadAllRenderers(); - + QShortcut *windowedShortcut; + std::array, 8> renderers; signals: void paint(const QImage &image); @@ -159,6 +161,7 @@ private: std::unique_ptr status; std::shared_ptr mm; + void updateShortcuts(); void processKeyboardInput(bool down, uint32_t keycode); #ifdef Q_OS_MACOS uint32_t last_modifiers = 0; @@ -184,7 +187,6 @@ private: friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. - bool isShowMessage = false; }; diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index d7c61e8d2..924594083 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -16,8 +16,11 @@ */ #include "qt_settingsinput.hpp" #include "ui_qt_settingsinput.h" +#include "qt_mainwindow.hpp" #include +#include +#include extern "C" { #include <86box/86box.h> @@ -25,11 +28,18 @@ extern "C" { #include <86box/machine.h> #include <86box/mouse.h> #include <86box/gameport.h> +#include <86box/ui.h> } #include "qt_models_common.hpp" #include "qt_deviceconfig.hpp" #include "qt_joystickconfiguration.hpp" +#include "qt_keybind.hpp" + +extern MainWindow *main_window; + +// Temporary working copy of key list +accelKey acc_keys_t[NUM_ACCELS]; SettingsInput::SettingsInput(QWidget *parent) : QWidget(parent) @@ -37,9 +47,55 @@ SettingsInput::SettingsInput(QWidget *parent) { ui->setupUi(this); + QStandardItemModel *model; + QStringList horizontalHeader; + QStringList verticalHeader; + + horizontalHeader.append("Action"); + horizontalHeader.append("Keybind"); + + QTableWidget *keyTable = ui->tableKeys; + keyTable->setRowCount(10); + keyTable->setColumnCount(3); + keyTable->setColumnHidden(2, true); + keyTable->setColumnWidth(0, 200); + keyTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + QStringList headers; + headers << "Action" << "Bound key"; + keyTable->setHorizontalHeaderLabels(headers); + keyTable->verticalHeader()->setVisible(false); + keyTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + keyTable->setSelectionBehavior(QAbstractItemView::SelectRows); + keyTable->setSelectionMode(QAbstractItemView::SingleSelection); + keyTable->setShowGrid(true); + keyTable->setStyleSheet("QTableWidget::item:hover { }"); + keyTable->setFocusPolicy(Qt::NoFocus); + keyTable->setSelectionMode(QAbstractItemView::NoSelection); + + // Make a working copy of acc_keys so we can check for dupes later without getting + // confused + printf("Instantiating list\n"); + for(int x=0;xtableKeys, &QTableWidget::cellDoubleClicked, + this, &SettingsInput::on_tableKeys_doubleClicked); + + connect(ui->pushButtonBind, &QPushButton::clicked, + this, &SettingsInput::on_pushButtonBind_Clicked); + + connect(ui->pushButtonClearBind, &QPushButton::clicked, + this, &SettingsInput::on_pushButtonClearBind_Clicked); + onCurrentMachineChanged(machine); } + SettingsInput::~SettingsInput() { delete ui; @@ -50,8 +106,15 @@ SettingsInput::save() { mouse_type = ui->comboBoxMouse->currentData().toInt(); joystick_type = ui->comboBoxJoystick->currentData().toInt(); + + // Copy accelerators from working set to global set + for(int x=0;xcomboBoxJoystick->setCurrentIndex(selectedRow); } +void +SettingsInput::refreshInputList() +{ + + for (int x=0;xtableKeys->setItem(x, 0, new QTableWidgetItem(acc_keys_t[x].desc)); + ui->tableKeys->setItem(x, 1, new QTableWidgetItem(acc_keys_t[x].seq)); + ui->tableKeys->setItem(x, 2, new QTableWidgetItem(acc_keys_t[x].name)); + } +} + +void +SettingsInput::on_tableKeys_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn) +{ + // Enable/disable bind/clear buttons if user clicked valid row + QTableWidgetItem *cell = ui->tableKeys->item(currentRow,1); + if (!cell) + { + ui->pushButtonBind->setEnabled(false); + ui->pushButtonClearBind->setEnabled(false); + } + else + { + ui->pushButtonBind->setEnabled(true); + ui->pushButtonClearBind->setEnabled(true); + } +} + +void +SettingsInput::on_tableKeys_doubleClicked(int row, int col) +{ + // Edit bind + QTableWidgetItem *cell = ui->tableKeys->item(row,1); + if (!cell) return; + + QKeySequence keyseq = KeyBinder::BindKey(cell->text()); + if (keyseq != false) { + // If no change was made, don't change anything. + if (keyseq.toString(QKeySequence::NativeText) == cell->text()) return; + + // Otherwise, check for conflicts. + // Check against the *working* copy - NOT the one in use by the app, + // so we don't test against shortcuts the user already changed. + for(int x=0;xshowMessage(MBX_ANSI & MBX_INFO, "Bind conflict", "This key combo is already in use", false); + return; + } + } + // If we made it here, there were no conflicts. + // Go ahead and apply the bind. + + // Find the correct accelerator key entry + int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(row,2)->text())); + if (!accKeyID) return; // this should never happen + + // Make the change + cell->setText(keyseq.toString(QKeySequence::NativeText)); + strcpy(acc_keys_t[accKeyID].seq, qPrintable(keyseq.toString(QKeySequence::NativeText))); + + refreshInputList(); + } +} + +void +SettingsInput::on_pushButtonBind_Clicked() +{ + // Edit bind + QTableWidgetItem *cell = ui->tableKeys->currentItem(); + if (!cell) return; + + on_tableKeys_doubleClicked(cell->row(), cell->column()); +} + +void +SettingsInput::on_pushButtonClearBind_Clicked() +{ + // Wipe bind + QTableWidgetItem *cell = ui->tableKeys->currentItem(); + if (!cell) return; + + cell->setText(""); + // Find the correct accelerator key entry + int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(cell->row(),2)->text())); + if (!accKeyID) return; // this should never happen + + // Make the change + cell->setText(""); + strcpy(acc_keys_t[accKeyID].seq, ""); +} + void SettingsInput::on_comboBoxMouse_currentIndexChanged(int index) { diff --git a/src/qt/qt_settingsinput.hpp b/src/qt/qt_settingsinput.hpp index 0b8b665aa..ec7dc393b 100644 --- a/src/qt/qt_settingsinput.hpp +++ b/src/qt/qt_settingsinput.hpp @@ -2,6 +2,12 @@ #define QT_SETTINGSINPUT_HPP #include +#include +#include +#include +#include +#include +#include namespace Ui { class SettingsInput; @@ -27,10 +33,15 @@ private slots: void on_pushButtonJoystick2_clicked(); void on_pushButtonJoystick3_clicked(); void on_pushButtonJoystick4_clicked(); + void on_tableKeys_doubleClicked(int row, int col); + void on_tableKeys_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn); + void on_pushButtonBind_Clicked(); + void on_pushButtonClearBind_Clicked(); private: Ui::SettingsInput *ui; int machineId = 0; + void refreshInputList(); }; #endif // QT_SETTINGSINPUT_HPP diff --git a/src/qt/qt_settingsinput.ui b/src/qt/qt_settingsinput.ui index 839461119..b7074eeaa 100644 --- a/src/qt/qt_settingsinput.ui +++ b/src/qt/qt_settingsinput.ui @@ -23,17 +23,16 @@ 0 - - - - Joystick 2... + + + + + 0 + 0 + - - - - - - Joystick: + + 30 @@ -44,13 +43,6 @@ - - - - Mouse: - - - @@ -58,21 +50,15 @@ - - - - Qt::Vertical + + + + false - - QSizePolicy::Expanding + + Bind - - - 20 - 40 - - - + @@ -81,6 +67,44 @@ + + + + 30 + + + + + + + Mouse: + + + + + + + false + + + Clear binding + + + + + + + Joystick: + + + + + + + Joystick 2... + + + @@ -94,23 +118,29 @@ - - - - 30 - - - - 0 - 0 - + + + + Key Bindings: - - - - 30 + + + + QAbstractItemView::EditTrigger::NoEditTriggers + + + false + + + false + + + true + + + QAbstractItemView::SelectionBehavior::SelectRows From f199fa5ce4b4b58ba0b857921b8f492ba3f10faa Mon Sep 17 00:00:00 2001 From: = Date: Sat, 19 Apr 2025 19:50:45 -0700 Subject: [PATCH 0760/1190] Added new UI files --- src/qt/qt_keybind.cpp | 95 ++++++++++++++++++++++++++++++++++ src/qt/qt_keybind.hpp | 32 ++++++++++++ src/qt/qt_keybind.ui | 85 ++++++++++++++++++++++++++++++ src/qt/qt_singlekeyseqedit.cpp | 20 +++++++ src/qt/qt_singlekeyseqedit.hpp | 16 ++++++ 5 files changed, 248 insertions(+) create mode 100644 src/qt/qt_keybind.cpp create mode 100644 src/qt/qt_keybind.hpp create mode 100644 src/qt/qt_keybind.ui create mode 100644 src/qt/qt_singlekeyseqedit.cpp create mode 100644 src/qt/qt_singlekeyseqedit.hpp diff --git a/src/qt/qt_keybind.cpp b/src/qt/qt_keybind.cpp new file mode 100644 index 000000000..dcfe424d9 --- /dev/null +++ b/src/qt/qt_keybind.cpp @@ -0,0 +1,95 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Device configuration UI code. + * + * + * + * Authors: Joakim L. Gilje + * Cacodemon345 + * + * Copyright 2021 Joakim L. Gilje + * Copyright 2022 Cacodemon345 + */ +#include "qt_keybind.hpp" +#include "ui_qt_keybind.h" +#include "qt_settings.hpp" +#include "qt_singlekeyseqedit.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include <86box/86box.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/device.h> +#include <86box/midi_rtmidi.h> +#include <86box/mem.h> +#include <86box/random.h> +#include <86box/rom.h> +} + +#include "qt_filefield.hpp" +#include "qt_models_common.hpp" +#ifdef Q_OS_LINUX +# include +# include +#endif +#ifdef Q_OS_WINDOWS +#include +#endif + +KeyBinder::KeyBinder(QWidget *parent) + : QDialog(parent) + , ui(new Ui::KeyBinder) +{ + ui->setupUi(this); + singleKeySequenceEdit *seq = new singleKeySequenceEdit(); + ui->formLayout->addRow(seq); + seq->setObjectName("keySequence"); +} + +KeyBinder::~KeyBinder() +{ + delete ui; +} + + +bool KeyBinder::eventFilter(QObject *obj, QEvent *event) +{ + return QObject::eventFilter(obj, event); +} + +QKeySequence +KeyBinder::BindKey(QString CurValue) +{ + KeyBinder kb; + kb.setWindowTitle("Bind Key"); + kb.setFixedSize(kb.minimumSizeHint()); + kb.findChild()->setKeySequence(QKeySequence::fromString(CurValue)); + + if (kb.exec() == QDialog::Accepted) { + QKeySequenceEdit *seq = kb.findChild(); + return (seq->keySequence()); + } else { + return (false); + } +} \ No newline at end of file diff --git a/src/qt/qt_keybind.hpp b/src/qt/qt_keybind.hpp new file mode 100644 index 000000000..afb750794 --- /dev/null +++ b/src/qt/qt_keybind.hpp @@ -0,0 +1,32 @@ +#ifndef QT_KeyBinder_HPP +#define QT_KeyBinder_HPP + +#include + +#include "qt_settings.hpp" + +extern "C" { +struct _device_; +} + +namespace Ui { +class KeyBinder; +} + +class Settings; + +class KeyBinder : public QDialog { + Q_OBJECT + +public: + explicit KeyBinder(QWidget *parent = nullptr); + ~KeyBinder() override; + + static QKeySequence BindKey(QString CurValue); + +private: + Ui::KeyBinder *ui; + bool eventFilter(QObject *obj, QEvent *event); +}; + +#endif // QT_KeyBinder_HPP diff --git a/src/qt/qt_keybind.ui b/src/qt/qt_keybind.ui new file mode 100644 index 000000000..835e12020 --- /dev/null +++ b/src/qt/qt_keybind.ui @@ -0,0 +1,85 @@ + + + KeyBinder + + + + 0 + 0 + 400 + 103 + + + + Dialog + + + + + + + + Enter key combo: + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + + Qt::Orientation::Horizontal + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + + + buttonBox + accepted() + KeyBinder + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + KeyBinder + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_singlekeyseqedit.cpp b/src/qt/qt_singlekeyseqedit.cpp new file mode 100644 index 000000000..f17d2164f --- /dev/null +++ b/src/qt/qt_singlekeyseqedit.cpp @@ -0,0 +1,20 @@ +#include "qt_singlekeyseqedit.hpp" + +/* + This subclass of QKeySequenceEdit restricts the input to only a single + shortcut instead of an unlimited number with a fixed timeout. +*/ + +singleKeySequenceEdit::singleKeySequenceEdit(QWidget *parent) : QKeySequenceEdit(parent) {} + +void singleKeySequenceEdit::keyPressEvent(QKeyEvent *event) +{ + QKeySequenceEdit::keyPressEvent(event); + if (this->keySequence().count() > 0) { + QKeySequenceEdit::setKeySequence(this->keySequence()); + + // This could have unintended consequences since it will happen + // every single time the user presses a key. + emit editingFinished(); + } +} \ No newline at end of file diff --git a/src/qt/qt_singlekeyseqedit.hpp b/src/qt/qt_singlekeyseqedit.hpp new file mode 100644 index 000000000..43ebe70b2 --- /dev/null +++ b/src/qt/qt_singlekeyseqedit.hpp @@ -0,0 +1,16 @@ +#ifndef SINGLEKEYSEQUENCEEDIT_H +#define SINGLEKEYSEQUENCEEDIT_H + +#include +#include + +class singleKeySequenceEdit : public QKeySequenceEdit +{ + Q_OBJECT +public: + singleKeySequenceEdit(QWidget *parent = nullptr); + + void keyPressEvent(QKeyEvent *) override; +}; + +#endif // SINGLEKEYSEQUENCEEDIT_H From 34620f3246c6b31713fd0ced517dd68c2ef8b900 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 19 Apr 2025 20:04:00 -0700 Subject: [PATCH 0761/1190] Auto-set focus on keybind dialog --- src/config.c | 2 -- src/qt/qt_keybind.cpp | 6 ++++++ src/qt/qt_keybind.hpp | 1 + src/qt/qt_mainwindow.cpp | 1 - src/qt/qt_settingsinput.cpp | 1 - 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/config.c b/src/config.c index d537711d9..2bea312a9 100644 --- a/src/config.c +++ b/src/config.c @@ -2558,10 +2558,8 @@ save_keybinds(void) for(int x=0;xformLayout->addRow(seq); seq->setObjectName("keySequence"); + this->setTabOrder(seq, ui->buttonBox); } KeyBinder::~KeyBinder() @@ -72,6 +73,11 @@ KeyBinder::~KeyBinder() delete ui; } +void +KeyBinder::showEvent( QShowEvent* event ) { + QWidget::showEvent( event ); + this->findChild()->setFocus(); +} bool KeyBinder::eventFilter(QObject *obj, QEvent *event) { diff --git a/src/qt/qt_keybind.hpp b/src/qt/qt_keybind.hpp index afb750794..e8e7b6e5e 100644 --- a/src/qt/qt_keybind.hpp +++ b/src/qt/qt_keybind.hpp @@ -27,6 +27,7 @@ public: private: Ui::KeyBinder *ui; bool eventFilter(QObject *obj, QEvent *event); + void showEvent( QShowEvent* event ); }; #endif // QT_KeyBinder_HPP diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ed9bf92a7..9fa38bfb1 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1079,7 +1079,6 @@ MainWindow::on_actionSettings_triggered() case QDialog::Accepted: settings.save(); config_changed = 2; - printf("about to try\n"); updateShortcuts(); pc_reset_hard(); break; diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 924594083..aa232df67 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -74,7 +74,6 @@ SettingsInput::SettingsInput(QWidget *parent) // Make a working copy of acc_keys so we can check for dupes later without getting // confused - printf("Instantiating list\n"); for(int x=0;x Date: Sat, 19 Apr 2025 20:11:17 -0700 Subject: [PATCH 0762/1190] Fixed bug in keybind UI --- src/qt/qt_mainwindow.cpp | 1 - src/qt/qt_settingsinput.cpp | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 9fa38bfb1..dc97c6294 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -859,7 +859,6 @@ void MainWindow::updateShortcuts() accID = FindAccelerator("fullscreen"); seq = QKeySequence::fromString(acc_keys[accID].seq); - //printf("shortcut: %s\n", qPrintable(ui->actionFullscreen->shortcut().toString())); ui->actionFullscreen->setShortcut(seq); accID = FindAccelerator("hard_reset"); diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index aa232df67..3be460a4a 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -68,9 +68,6 @@ SettingsInput::SettingsInput(QWidget *parent) keyTable->setSelectionBehavior(QAbstractItemView::SelectRows); keyTable->setSelectionMode(QAbstractItemView::SingleSelection); keyTable->setShowGrid(true); - keyTable->setStyleSheet("QTableWidget::item:hover { }"); - keyTable->setFocusPolicy(Qt::NoFocus); - keyTable->setSelectionMode(QAbstractItemView::NoSelection); // Make a working copy of acc_keys so we can check for dupes later without getting // confused @@ -224,7 +221,7 @@ SettingsInput::on_tableKeys_doubleClicked(int row, int col) // Find the correct accelerator key entry int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(row,2)->text())); - if (!accKeyID) return; // this should never happen + if (accKeyID < 0) return; // this should never happen // Make the change cell->setText(keyseq.toString(QKeySequence::NativeText)); @@ -254,7 +251,7 @@ SettingsInput::on_pushButtonClearBind_Clicked() cell->setText(""); // Find the correct accelerator key entry int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(cell->row(),2)->text())); - if (!accKeyID) return; // this should never happen + if (accKeyID < 0) return; // this should never happen // Make the change cell->setText(""); From 4c20994d5962c654e13285b524e40468a0cae68b Mon Sep 17 00:00:00 2001 From: = Date: Sat, 19 Apr 2025 23:50:03 -0700 Subject: [PATCH 0763/1190] Removed broken refs to fix -nix build --- src/config.c | 3 +-- src/include/86box/keyboard.h | 1 - src/unix/unix.c | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/config.c b/src/config.c index 2bea312a9..dcabcd922 100644 --- a/src/config.c +++ b/src/config.c @@ -1807,7 +1807,7 @@ load_keybinds(void) { p = ini_section_get_string(cat, acc_keys[x].name, "none"); // If there's no binding in the file, leave it alone. - if (p != "none") + if (strcmp(p, "none") != 0) { // It would be ideal to validate whether the user entered a // valid combo at this point, but the Qt method for testing that is @@ -2553,7 +2553,6 @@ static void save_keybinds(void) { ini_section_t cat = ini_find_or_create_section(config, "Keybinds"); - char temp[512]; for(int x=0;x Date: Sun, 20 Apr 2025 14:04:23 +0200 Subject: [PATCH 0764/1190] BusLogic SCSI controllers: Add a proper device reset functions, fixes POST error on Intel AMI BIOS'es after exiting AUTO-SCSI using the Esc key. --- src/scsi/scsi_buslogic.c | 57 +++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 9fe34380b..352232e34 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -256,6 +256,8 @@ buslogic_log(const char *fmt, ...) # define buslogic_log(fmt, ...) #endif +static x54x_t reset_state = { 0 }; + static char * BuslogicGetNVRFileName(buslogic_data_t *bl) { @@ -1084,7 +1086,7 @@ buslogic_interrupt_type(void *priv) } static void -buslogic_reset(void *priv) +buslogic_ven_reset(void *priv) { x54x_t *dev = (x54x_t *) priv; buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; @@ -1525,6 +1527,39 @@ BuslogicDeviceReset(void *priv) BuslogicInitializeAutoSCSIRam(dev); } +static void +buslogic_reset(void *priv) +{ + x54x_t *dev = (x54x_t *) priv; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + x54x_io_remove(dev, dev->Base, 4); + + if (bl->chip == CHIP_BUSLOGIC_PCI_958D_1995_12_30) { + x54x_mem_init(dev, 0xfffd0000); + x54x_mem_disable(dev); + } + + timer_disable(&dev->timer); + timer_disable(&dev->ResetCB); + + reset_state.mmio_mapping = dev->mmio_mapping; + + reset_state.bios.mapping = dev->bios.mapping; + reset_state.uppersck.mapping = dev->uppersck.mapping; + + reset_state.timer = dev->timer; + reset_state.ResetCB = dev->ResetCB; + + memcpy(dev, &reset_state, sizeof(x54x_t)); + + dev->timer.period = 10.0; + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->timer.period * ((double) TIMER_USEC))); + + if ((dev->Base != 0) && !(dev->card_bus & DEVICE_MCA) && !(dev->card_bus & DEVICE_PCI)) + x54x_io_set(dev, dev->Base, 4); +} + static void * buslogic_init(const device_t *info) { @@ -1586,7 +1621,7 @@ buslogic_init(const device_t *info) dev->interrupt_type = buslogic_interrupt_type; dev->is_aggressive_mode = buslogic_is_aggressive_mode; dev->get_ven_data = buslogic_setup_data; - dev->ven_reset = buslogic_reset; + dev->ven_reset = buslogic_ven_reset; strcpy(dev->vendor, "BusLogic"); @@ -1774,6 +1809,8 @@ buslogic_init(const device_t *info) BuslogicInitializeAutoSCSIRam(dev); } + memcpy(&reset_state, dev, sizeof(x54x_t)); + return dev; } @@ -1876,7 +1913,7 @@ const device_t buslogic_542b_device = { .local = CHIP_BUSLOGIC_ISA_542B_1991_12_14, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1890,7 +1927,7 @@ const device_t buslogic_545s_device = { .local = CHIP_BUSLOGIC_ISA_545S_1992_10_05, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1904,7 +1941,7 @@ const device_t buslogic_542bh_device = { .local = CHIP_BUSLOGIC_ISA_542BH_1993_05_23, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1918,7 +1955,7 @@ const device_t buslogic_545c_device = { .local = CHIP_BUSLOGIC_ISA_545C_1994_12_01, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1932,7 +1969,7 @@ const device_t buslogic_640a_device = { .local = CHIP_BUSLOGIC_MCA_640A_1993_05_23, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1946,7 +1983,7 @@ const device_t buslogic_445s_device = { .local = CHIP_BUSLOGIC_VLB_445S_1993_11_16, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1960,7 +1997,7 @@ const device_t buslogic_445c_device = { .local = CHIP_BUSLOGIC_VLB_445C_1994_12_01, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -1974,7 +2011,7 @@ const device_t buslogic_958d_pci_device = { .local = CHIP_BUSLOGIC_PCI_958D_1995_12_30, .init = buslogic_init, .close = x54x_close, - .reset = NULL, + .reset = buslogic_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, From aefcdc9e01ebdd7bac314f0a2c3fabdff6b2df8e Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 13:43:14 -0700 Subject: [PATCH 0765/1190] Merged fullscreen combos. Fixed bug when config file can't be loaded. --- src/86box.c | 30 +++++++++++++++++++++++++ src/config.c | 30 ------------------------- src/include/86box/86box.h | 3 ++- src/qt/qt_mainwindow.cpp | 46 +++++++++++++++++---------------------- 4 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/86box.c b/src/86box.c index d8c05c8bb..d650b8432 100644 --- a/src/86box.c +++ b/src/86box.c @@ -225,6 +225,28 @@ int other_scsi_present = 0; /* SCSI contro // Accelerator key array struct accelKey acc_keys[NUM_ACCELS]; +// Default accelerator key values +struct accelKey def_acc_keys[NUM_ACCELS] = { + { .name="send_ctrl_alt_del", .desc="Send Control+Alt+Del", + .seq="Ctrl+F12" }, + + { .name="send_ctrl_alt_esc", .desc="Send Control+Alt+Escape", + .seq="Ctrl+F10" }, + + { .name="fullscreen", .desc="Toggle fullscreen", + .seq="Ctrl+Alt+PgUp" }, + + { .name="screenshot", .desc="Screenshot", + .seq="Ctrl+F11" }, + + { .name="release_mouse", .desc="Release mouse pointer", + .seq="Ctrl+End" }, + + { .name="hard_reset", .desc="Hard reset", + .seq="Ctrl+Alt+F12" } +}; + + /* Statistics. */ extern int mmuflush; extern int readlnum; @@ -998,6 +1020,14 @@ usage: gdbstub_init(); + // Initialize the keyboard accelerator list with default values + for(int x=0;x= QT_VERSION_CHECK(6, 0, 0) - windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_PageDown), this); -#else - windowedShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_PageDown), this); -#endif - windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); - connect(windowedShortcut, &QShortcut::activated, this, [this] () { - if (video_fullscreen) - ui->actionFullscreen->trigger(); - }); - connect(this, &MainWindow::initRendererMonitor, this, &MainWindow::initRendererMonitorSlot); connect(this, &MainWindow::initRendererMonitorForNonQtThread, this, &MainWindow::initRendererMonitorSlot, Qt::BlockingQueuedConnection); connect(this, &MainWindow::destroyRendererMonitor, this, &MainWindow::destroyRendererMonitorSlot); @@ -836,10 +825,11 @@ void MainWindow::updateShortcuts() // Note that the "Release mouse" shortcut is hardcoded elsewhere // This section only applies to shortcuts anchored to UI elements + // First we need to wipe all existing accelerators, otherwise Qt will + // run into conflicts with old ones. ui->actionTake_screenshot->setShortcut(QKeySequence()); ui->actionCtrl_Alt_Del->setShortcut(QKeySequence()); ui->actionCtrl_Alt_Esc->setShortcut(QKeySequence()); - ui->actionFullscreen->setShortcut(QKeySequence()); ui->actionHard_Reset->setShortcut(QKeySequence()); int accID; @@ -857,25 +847,13 @@ void MainWindow::updateShortcuts() seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionCtrl_Alt_Esc->setShortcut(seq); - accID = FindAccelerator("fullscreen"); - seq = QKeySequence::fromString(acc_keys[accID].seq); - ui->actionFullscreen->setShortcut(seq); - accID = FindAccelerator("hard_reset"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionHard_Reset->setShortcut(seq); - // To rebind leave_fullscreen we have to disconnect the existing signal, - // build a new shortcut, then connect it. - accID = FindAccelerator("leave_fullscreen"); + accID = FindAccelerator("fullscreen"); seq = QKeySequence::fromString(acc_keys[accID].seq); - disconnect(windowedShortcut,0,0,0); - windowedShortcut = new QShortcut(seq, this); - windowedShortcut->setContext(Qt::ShortcutContext::ApplicationShortcut); - connect(windowedShortcut, &QShortcut::activated, this, [this] () { - if (video_fullscreen) - ui->actionFullscreen->trigger(); - }); + ui->actionFullscreen->setShortcut(seq); } void @@ -1361,6 +1339,20 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) if (event->type() == QEvent::KeyPress) { event->accept(); this->keyPressEvent((QKeyEvent *) event); + + // Detect fullscreen shortcut when menubar is hidden + int accID = FindAccelerator("fullscreen"); + QKeySequence seq = QKeySequence::fromString(acc_keys[accID].seq); + + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *ke = (QKeyEvent *) event; + if ((QKeySequence)(ke->key() | ke->modifiers()) == seq && video_fullscreen != 0) + { + ui->actionFullscreen->trigger(); + } + } + return true; } if (event->type() == QEvent::KeyRelease) { @@ -1380,6 +1372,8 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) plat_pause(curdopause); } } + + return QMainWindow::eventFilter(receiver, event); } From 24a4ed445e3b1805c4f230bdd3b394b85fba0a1d Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 13:59:52 -0700 Subject: [PATCH 0766/1190] All shortcuts now work in fullscreen --- src/qt/qt_mainwindow.cpp | 45 +++++++++++++++++++++++++++++++++------- src/qt/qt_mainwindow.hpp | 2 ++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index e57c7b96f..2b3eda4af 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1325,6 +1325,19 @@ MainWindow::getTitle(wchar_t *title) } } + +// Helper to find an accelerator key and return it's sequence +// TODO: Is there a more central place to put this? +QKeySequence +MainWindow::FindAcceleratorSeq(const char *name) +{ + int accID = FindAccelerator(name); + if(accID == -1) + return false; + + return(QKeySequence::fromString(acc_keys[accID].seq)); +} + bool MainWindow::eventFilter(QObject *receiver, QEvent *event) { @@ -1337,22 +1350,40 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) } } if (event->type() == QEvent::KeyPress) { - event->accept(); this->keyPressEvent((QKeyEvent *) event); - // Detect fullscreen shortcut when menubar is hidden - int accID = FindAccelerator("fullscreen"); - QKeySequence seq = QKeySequence::fromString(acc_keys[accID].seq); + // Detect shortcuts when menubar is hidden + // TODO: Could this be simplified by proxying the event and manually + // shoving it into the menubar? + QKeySequence accKey; - if (event->type() == QEvent::KeyPress) + if (event->type() == QEvent::KeyPress && video_fullscreen != 0) { QKeyEvent *ke = (QKeyEvent *) event; - if ((QKeySequence)(ke->key() | ke->modifiers()) == seq && video_fullscreen != 0) + + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("screenshot")) { - ui->actionFullscreen->trigger(); + ui->actionTake_screenshot->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_del")) + { + ui->actionCtrl_Alt_Del->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_esc")) + { + ui->actionCtrl_Alt_Esc->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("hard_reset")) + { + ui->actionHard_Reset->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("fullscreen")) + { + ui->actionFullscreen->trigger(); } } + event->accept(); return true; } if (event->type() == QEvent::KeyRelease) { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 99b0021c2..5811ac36a 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -34,6 +34,8 @@ public: void setSendKeyboardInput(bool enabled); void reloadAllRenderers(); QShortcut *windowedShortcut; + QKeySequence FindAcceleratorSeq(const char *name); + std::array, 8> renderers; signals: From ba19b8af895fab71442dbeaf1932c0a48c2abb26 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 20 Apr 2025 23:19:17 +0200 Subject: [PATCH 0767/1190] x86_64 new recompile: fix registers clean-up on block exit. --- src/codegen_new/codegen_backend_x86-64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64.c b/src/codegen_new/codegen_backend_x86-64.c index 6242ea40b..20d02a8db 100644 --- a/src/codegen_new/codegen_backend_x86-64.c +++ b/src/codegen_new/codegen_backend_x86-64.c @@ -329,7 +329,7 @@ codegen_backend_init(void) host_x86_POP(block, REG_RSI); #endif host_x86_POP(block, REG_RBP); - host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RBX); host_x86_RET(block); block_write_data = NULL; @@ -392,7 +392,7 @@ codegen_backend_epilogue(codeblock_t *block) host_x86_POP(block, REG_RSI); #endif host_x86_POP(block, REG_RBP); - host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RBX); host_x86_RET(block); } #endif From 9febdd1510346744e0edc114054a92353117acb2 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 14:28:10 -0700 Subject: [PATCH 0768/1190] Added pause shortcut. --- src/86box.c | 5 +- src/include/86box/86box.h | 2 +- src/qt/qt_mainwindow.cpp | 105 ++++++++++++++++++++++---------------- 3 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/86box.c b/src/86box.c index d650b8432..e3d1e785c 100644 --- a/src/86box.c +++ b/src/86box.c @@ -243,7 +243,10 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { .seq="Ctrl+End" }, { .name="hard_reset", .desc="Hard reset", - .seq="Ctrl+Alt+F12" } + .seq="Ctrl+Alt+F12" }, + + { .name="pause", .desc="Toggle pause", + .seq="Ctrl+Alt+F1" } }; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 4dcd521e0..51f1dbcbc 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -242,7 +242,7 @@ struct accelKey { char desc[64]; char seq[64]; }; -#define NUM_ACCELS 6 +#define NUM_ACCELS 7 extern struct accelKey acc_keys[NUM_ACCELS]; extern struct accelKey def_acc_keys[NUM_ACCELS]; extern int FindAccelerator(const char *name); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 2b3eda4af..ad1c0e2a0 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -821,9 +821,13 @@ MainWindow::closeEvent(QCloseEvent *event) void MainWindow::updateShortcuts() { - // Update menu shortcuts from accelerator table - // Note that the "Release mouse" shortcut is hardcoded elsewhere - // This section only applies to shortcuts anchored to UI elements + /* + Update menu shortcuts from accelerator table + Note that the "Release mouse" shortcut is hardcoded elsewhere + This section only applies to shortcuts anchored to UI elements + + MainWindow::eventFilter + */ // First we need to wipe all existing accelerators, otherwise Qt will // run into conflicts with old ones. @@ -831,6 +835,7 @@ void MainWindow::updateShortcuts() ui->actionCtrl_Alt_Del->setShortcut(QKeySequence()); ui->actionCtrl_Alt_Esc->setShortcut(QKeySequence()); ui->actionHard_Reset->setShortcut(QKeySequence()); + ui->actionPause->setShortcut(QKeySequence()); int accID; QKeySequence seq; @@ -854,6 +859,10 @@ void MainWindow::updateShortcuts() accID = FindAccelerator("fullscreen"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionFullscreen->setShortcut(seq); + + accID = FindAccelerator("pause"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionPause->setShortcut(seq); } void @@ -1341,6 +1350,54 @@ MainWindow::FindAcceleratorSeq(const char *name) bool MainWindow::eventFilter(QObject *receiver, QEvent *event) { + // Detect shortcuts when menubar is hidden + // TODO: Could this be simplified by proxying the event and manually + // shoving it into the menubar? + + // Note: This section should ONLY contain shortcuts that are valid + // when the emulator + if (event->type() == QEvent::KeyPress) + { + this->keyPressEvent((QKeyEvent *) event); + + if (event->type() == QEvent::KeyPress && video_fullscreen != 0) + { + QKeyEvent *ke = (QKeyEvent *) event; + + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("release_mouse")) + { + qDebug() << ke; + plat_mouse_capture(0); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("screenshot")) + { + ui->actionTake_screenshot->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("fullscreen")) + { + ui->actionFullscreen->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("hard_reset")) + { + ui->actionHard_Reset->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_del")) + { + ui->actionCtrl_Alt_Del->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_esc")) + { + ui->actionCtrl_Alt_Esc->trigger(); + } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("pause")) + { + ui->actionPause->trigger(); + } + return true; + } + } + + if (!dopause) { if (event->type() == QEvent::Shortcut) { auto shortcutEvent = (QShortcutEvent *) event; @@ -1350,40 +1407,8 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) } } if (event->type() == QEvent::KeyPress) { - this->keyPressEvent((QKeyEvent *) event); - - // Detect shortcuts when menubar is hidden - // TODO: Could this be simplified by proxying the event and manually - // shoving it into the menubar? - QKeySequence accKey; - - if (event->type() == QEvent::KeyPress && video_fullscreen != 0) - { - QKeyEvent *ke = (QKeyEvent *) event; - - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("screenshot")) - { - ui->actionTake_screenshot->trigger(); - } - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_del")) - { - ui->actionCtrl_Alt_Del->trigger(); - } - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_esc")) - { - ui->actionCtrl_Alt_Esc->trigger(); - } - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("hard_reset")) - { - ui->actionHard_Reset->trigger(); - } - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("fullscreen")) - { - ui->actionFullscreen->trigger(); - } - } - event->accept(); + return true; } if (event->type() == QEvent::KeyRelease) { @@ -1471,14 +1496,6 @@ MainWindow::keyPressEvent(QKeyEvent *event) processKeyboardInput(true, event->nativeScanCode()); #endif } - - // Check if mouse release combo has been entered - int accID = FindAccelerator("release_mouse"); - QKeySequence seq = QKeySequence::fromString(acc_keys[accID].seq); - if (seq[0] == (event->key() | event->modifiers())) - plat_mouse_capture(0); - - // TODO: Other accelerators should probably be here? event->accept(); } From fd235bcf9630eff939ccab2604a046e3b5510785 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 14:31:46 -0700 Subject: [PATCH 0769/1190] Added pause shortcut. --- src/86box.c | 5 ++++- src/qt/qt_mainwindow.cpp | 15 ++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/86box.c b/src/86box.c index e3d1e785c..dae2d4ba5 100644 --- a/src/86box.c +++ b/src/86box.c @@ -246,7 +246,10 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { .seq="Ctrl+Alt+F12" }, { .name="pause", .desc="Toggle pause", - .seq="Ctrl+Alt+F1" } + .seq="Ctrl+Alt+F1" }, + + { .name="mute", .desc="Toggle mute", + .seq="Ctrl+Alt+M" } }; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ad1c0e2a0..27124b9fd 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -836,6 +836,7 @@ void MainWindow::updateShortcuts() ui->actionCtrl_Alt_Esc->setShortcut(QKeySequence()); ui->actionHard_Reset->setShortcut(QKeySequence()); ui->actionPause->setShortcut(QKeySequence()); + ui->actionMute_Unmute->setShortcut(QKeySequence()); int accID; QKeySequence seq; @@ -863,6 +864,10 @@ void MainWindow::updateShortcuts() accID = FindAccelerator("pause"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionPause->setShortcut(seq); + + accID = FindAccelerator("mute"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionMute_Unmute->setShortcut(seq); } void @@ -1353,9 +1358,6 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) // Detect shortcuts when menubar is hidden // TODO: Could this be simplified by proxying the event and manually // shoving it into the menubar? - - // Note: This section should ONLY contain shortcuts that are valid - // when the emulator if (event->type() == QEvent::KeyPress) { this->keyPressEvent((QKeyEvent *) event); @@ -1393,6 +1395,11 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) { ui->actionPause->trigger(); } + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("mute")) + { + ui->actionMute_Unmute->setShortcut(seq); + } + return true; } } @@ -1429,8 +1436,6 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) } } - - return QMainWindow::eventFilter(receiver, event); } From eaff1fcd703a08b846e0fc6e6efe08e670b5c6ae Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 14:33:19 -0700 Subject: [PATCH 0770/1190] Added mute shortcut. --- src/include/86box/86box.h | 2 +- src/qt/qt_mainwindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 51f1dbcbc..7f7723bba 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -242,7 +242,7 @@ struct accelKey { char desc[64]; char seq[64]; }; -#define NUM_ACCELS 7 +#define NUM_ACCELS 8 extern struct accelKey acc_keys[NUM_ACCELS]; extern struct accelKey def_acc_keys[NUM_ACCELS]; extern int FindAccelerator(const char *name); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 27124b9fd..568c84b36 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1397,7 +1397,7 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) } if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("mute")) { - ui->actionMute_Unmute->setShortcut(seq); + ui->actionMute_Unmute->trigger(); } return true; From 505874f22ee33691a54774487f273d775edc0336 Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 15:23:38 -0700 Subject: [PATCH 0771/1190] Added translation to key shortcut table, modals, and release mouse status line. --- src/qt/languages/fr-FR.po | 8 ++++---- src/qt/qt_mainwindow.cpp | 26 +++++++++++++++++--------- src/qt/qt_platform.cpp | 10 ++++++++-- src/qt/qt_settingsinput.cpp | 9 +++++---- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 8456baf2f..5416f7662 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -717,11 +717,11 @@ msgstr "Autres périfériques" msgid "Click to capture mouse" msgstr "Cliquer pour capturer la souris" -msgid "Press %1 to release mouse" -msgstr "Appuyer sur %1 pour libérer la souris" +msgid "Press %s to release mouse" +msgstr "Appuyer sur %s pour libérer la souris" -msgid "Press %1 or middle button to release mouse" -msgstr "Appuyer sur %1 ou le bouton central pour libérer la souris" +msgid "Press %s or middle button to release mouse" +msgstr "Appuyer sur %s ou le bouton central pour libérer la souris" msgid "Bus" msgstr "Bus" diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 568c84b36..d79cc1b9e 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -823,10 +823,9 @@ void MainWindow::updateShortcuts() { /* Update menu shortcuts from accelerator table - Note that the "Release mouse" shortcut is hardcoded elsewhere - This section only applies to shortcuts anchored to UI elements - MainWindow::eventFilter + Note that these only work in windowed mode. If you add any new shortcuts, + you have to go duplicate them in MainWindow::eventFilter() */ // First we need to wipe all existing accelerators, otherwise Qt will @@ -1295,7 +1294,10 @@ MainWindow::on_actionFullscreen_triggered() if (video_fullscreen_first) { bool wasCaptured = mouse_capture == 1; - QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), tr("Press Ctrl+Alt+PgDn to return to windowed mode."), QMessageBox::Ok, this); + char strFullscreen[100]; + sprintf(strFullscreen, qPrintable(tr("To return to windowed mode, press %s")), acc_keys[FindAccelerator("fullscreen")].seq); + + QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), QString(strFullscreen), QMessageBox::Ok, this); QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); questionbox.setCheckBox(chkbox); chkbox->setChecked(!video_fullscreen_first); @@ -1362,15 +1364,21 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) { this->keyPressEvent((QKeyEvent *) event); + // We check for mouse release even if we aren't fullscreen, + // because it's not a menu accelerator. + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *ke = (QKeyEvent *) event; + if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("release_mouse")) + { + plat_mouse_capture(0); + } + } + if (event->type() == QEvent::KeyPress && video_fullscreen != 0) { QKeyEvent *ke = (QKeyEvent *) event; - if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("release_mouse")) - { - qDebug() << ke; - plat_mouse_capture(0); - } if ((QKeySequence)(ke->key() | ke->modifiers()) == FindAcceleratorSeq("screenshot")) { ui->actionTake_screenshot->trigger(); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 0f792feda..26682528d 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -595,8 +595,14 @@ ProgSettings::reloadStrings() { translatedstrings.clear(); translatedstrings[STRING_MOUSE_CAPTURE] = QCoreApplication::translate("", "Click to capture mouse").toStdWString(); - translatedstrings[STRING_MOUSE_RELEASE] = QCoreApplication::translate("", "Press %1 to release mouse").arg(QCoreApplication::translate("", MOUSE_CAPTURE_KEYSEQ)).toStdWString(); - translatedstrings[STRING_MOUSE_RELEASE_MMB] = QCoreApplication::translate("", "Press %1 or middle button to release mouse").arg(QCoreApplication::translate("", MOUSE_CAPTURE_KEYSEQ)).toStdWString(); + + char mouseCaptureKeyseq[100]; + sprintf(mouseCaptureKeyseq, qPrintable(QCoreApplication::translate("", "Press %s to release mouse")), acc_keys[FindAccelerator("release_mouse")].seq); + translatedstrings[STRING_MOUSE_RELEASE] = QString(mouseCaptureKeyseq).toStdWString(); + + sprintf(mouseCaptureKeyseq, qPrintable(QCoreApplication::translate("", "Press %s or middle button to release mouse")), acc_keys[FindAccelerator("release_mouse")].seq); + translatedstrings[STRING_MOUSE_RELEASE_MMB] = QString(mouseCaptureKeyseq).toStdWString(); + translatedstrings[STRING_INVALID_CONFIG] = QCoreApplication::translate("", "Invalid configuration").toStdWString(); translatedstrings[STRING_NO_ST506_ESDI_CDROM] = QCoreApplication::translate("", "MFM/RLL or ESDI CD-ROM drives never existed").toStdWString(); translatedstrings[STRING_PCAP_ERROR_NO_DEVICES] = QCoreApplication::translate("", "No PCap devices found").toStdWString(); diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 3be460a4a..20cb40ecd 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -51,8 +51,8 @@ SettingsInput::SettingsInput(QWidget *parent) QStringList horizontalHeader; QStringList verticalHeader; - horizontalHeader.append("Action"); - horizontalHeader.append("Keybind"); + horizontalHeader.append(tr("Action")); + horizontalHeader.append(tr("Keybind")); QTableWidget *keyTable = ui->tableKeys; keyTable->setRowCount(10); @@ -61,7 +61,7 @@ SettingsInput::SettingsInput(QWidget *parent) keyTable->setColumnWidth(0, 200); keyTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); QStringList headers; - headers << "Action" << "Bound key"; + //headers << "Action" << "Bound key"; keyTable->setHorizontalHeaderLabels(headers); keyTable->verticalHeader()->setVisible(false); keyTable->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -109,6 +109,7 @@ SettingsInput::save() strcpy(acc_keys[x].desc, acc_keys_t[x].desc); strcpy(acc_keys[x].seq, acc_keys_t[x].seq); } + // ProgSettings::reloadStrings(); } void @@ -169,7 +170,7 @@ SettingsInput::refreshInputList() { for (int x=0;xtableKeys->setItem(x, 0, new QTableWidgetItem(acc_keys_t[x].desc)); + ui->tableKeys->setItem(x, 0, new QTableWidgetItem(tr(acc_keys_t[x].desc))); ui->tableKeys->setItem(x, 1, new QTableWidgetItem(acc_keys_t[x].seq)); ui->tableKeys->setItem(x, 2, new QTableWidgetItem(acc_keys_t[x].name)); } From d6b280dd29eb066fcf48c3b1df1d813dd290736e Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 15:29:15 -0700 Subject: [PATCH 0772/1190] Status line now updates --- src/qt/qt_settingsinput.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 20cb40ecd..f87296451 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -17,6 +17,7 @@ #include "qt_settingsinput.hpp" #include "ui_qt_settingsinput.h" #include "qt_mainwindow.hpp" +#include "qt_progsettings.hpp" #include #include @@ -109,7 +110,7 @@ SettingsInput::save() strcpy(acc_keys[x].desc, acc_keys_t[x].desc); strcpy(acc_keys[x].seq, acc_keys_t[x].seq); } - // ProgSettings::reloadStrings(); + ProgSettings::reloadStrings(); } void From 30ea1eb08752cf6332b1c48a924aa7daeb80dc7e Mon Sep 17 00:00:00 2001 From: = Date: Sun, 20 Apr 2025 15:36:49 -0700 Subject: [PATCH 0773/1190] Updated translations --- src/qt/languages/ca-ES.po | 12 ++++++------ src/qt/languages/cs-CZ.po | 12 ++++++------ src/qt/languages/de-DE.po | 12 ++++++------ src/qt/languages/es-ES.po | 12 ++++++------ src/qt/languages/fi-FI.po | 12 ++++++------ src/qt/languages/fr-FR.po | 4 ++-- src/qt/languages/hr-HR.po | 12 ++++++------ src/qt/languages/hu-HU.po | 12 ++++++------ src/qt/languages/it-IT.po | 12 ++++++------ src/qt/languages/ja-JP.po | 12 ++++++------ src/qt/languages/ko-KR.po | 12 ++++++------ src/qt/languages/nl-NL.po | 12 ++++++------ src/qt/languages/pl-PL.po | 12 ++++++------ src/qt/languages/pt-BR.po | 12 ++++++------ src/qt/languages/pt-PT.po | 12 ++++++------ src/qt/languages/ru-RU.po | 12 ++++++------ src/qt/languages/sk-SK.po | 12 ++++++------ src/qt/languages/sl-SI.po | 12 ++++++------ src/qt/languages/sv-SE.po | 12 ++++++------ src/qt/languages/tr-TR.po | 12 ++++++------ src/qt/languages/uk-UA.po | 12 ++++++------ src/qt/languages/vi-VN.po | 12 ++++++------ src/qt/languages/zh-CN.po | 8 ++++---- src/qt/languages/zh-TW.po | 8 ++++---- src/qt/qt_mainwindow.cpp | 2 +- 25 files changed, 137 insertions(+), 137 deletions(-) diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 847cc0138..4851106cd 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -630,8 +630,8 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Premeu Ctrl+Alt+PgDn per tornar al mode de finestra." +msgid "Press %s to return to windowed mode." +msgstr "Premeu %s per tornar al mode de finestra." msgid "Speed" msgstr "Velocitat" @@ -717,11 +717,11 @@ msgstr "Altres perifèrics" msgid "Click to capture mouse" msgstr "Feu clic per capturar el ratolí" -msgid "Press %1 to release mouse" -msgstr "Premeu %1 per alliberar el ratolí" +msgid "Press %s to release mouse" +msgstr "Premeu %s per alliberar el ratolí" -msgid "Press %1 or middle button to release mouse" -msgstr "Premeu %1 o el botó central per alliberar el ratolí" +msgid "Press %s or middle button to release mouse" +msgstr "Premeu %s o el botó central per alliberar el ratolí" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index ea492f0b6..352fafc31 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -630,8 +630,8 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENO" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Stiskněte Ctrl+Alt+PgDn pro návrat z režimu celé obrazovky." +msgid "Press %s to return to windowed mode." +msgstr "Stiskněte %s pro návrat z režimu celé obrazovky." msgid "Speed" msgstr "Rychlost" @@ -717,11 +717,11 @@ msgstr "Jiné příslušenství" msgid "Click to capture mouse" msgstr "Klikněte pro zabraní myši" -msgid "Press %1 to release mouse" -msgstr "Stiskněte %1 pro uvolnění myši" +msgid "Press %s to release mouse" +msgstr "Stiskněte %s pro uvolnění myši" -msgid "Press %1 or middle button to release mouse" -msgstr "Stiskněte %1 nebo prostřední tlačítko pro uvolnění myši" +msgid "Press %s or middle button to release mouse" +msgstr "Stiskněte %s nebo prostřední tlačítko pro uvolnění myši" msgid "Bus" msgstr "Sběrnice" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 95d1b0249..ce7d52d55 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -630,8 +630,8 @@ msgstr "Fataler Fehler" msgid " - PAUSED" msgstr " - PAUSIERT" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Strg+Alt+Bild ab, zur Rückkehr in den Fenstermodus." +msgid "Press %s to return to windowed mode." +msgstr "%s ab, zur Rückkehr in den Fenstermodus." msgid "Speed" msgstr "Geschwindigkeit" @@ -717,11 +717,11 @@ msgstr "Andere Peripheriegeräte" msgid "Click to capture mouse" msgstr "Klicken zum Einfangen des Mauszeigers" -msgid "Press %1 to release mouse" -msgstr "Drücke %1 zur Mausfreigabe" +msgid "Press %s to release mouse" +msgstr "Drücke %s zur Mausfreigabe" -msgid "Press %1 or middle button to release mouse" -msgstr "Drücke %1 oder die mittlere Maustaste zur Mausfreigabe" +msgid "Press %s or middle button to release mouse" +msgstr "Drücke %s oder die mittlere Maustaste zur Mausfreigabe" msgid "Ctrl+End" msgstr "Strg+Ende" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 57474ae53..177d08d18 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -630,8 +630,8 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Pulsa Ctrl+Alt+PgDn para volver a modo ventana." +msgid "Press %s to return to windowed mode." +msgstr "Pulsa %s para volver a modo ventana." msgid "Speed" msgstr "Velocidad" @@ -717,11 +717,11 @@ msgstr "Otros periféricos" msgid "Click to capture mouse" msgstr "Haga click para capturar el ratón" -msgid "Press %1 to release mouse" -msgstr "Pulse %1 para liberar el ratón" +msgid "Press %s to release mouse" +msgstr "Pulse %s para liberar el ratón" -msgid "Press %1 or middle button to release mouse" -msgstr "Pulse %1 o el botón central para liberar el ratón" +msgid "Press %s or middle button to release mouse" +msgstr "Pulse %s o el botón central para liberar el ratón" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 187a423f6..a77b3f6ef 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -630,8 +630,8 @@ msgstr "Vakava virhe" msgid " - PAUSED" msgstr " - TAUKO" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Paina Ctrl+Alt+PgDn palataksesi ikkunoituun tilaan." +msgid "Press %s to return to windowed mode." +msgstr "Paina %s palataksesi ikkunoituun tilaan." msgid "Speed" msgstr "Nopeus" @@ -717,11 +717,11 @@ msgstr "Muut oheislaitteet" msgid "Click to capture mouse" msgstr "Kaappaa hiiri klikkaamalla" -msgid "Press %1 to release mouse" -msgstr "Paina %1 vapauttaaksesi hiiren" +msgid "Press %s to release mouse" +msgstr "Paina %s vapauttaaksesi hiiren" -msgid "Press %1 or middle button to release mouse" -msgstr "Paina %1 tai keskipainiketta vapauttaaksesi hiiren" +msgid "Press %s or middle button to release mouse" +msgstr "Paina %s tai keskipainiketta vapauttaaksesi hiiren" msgid "Bus" msgstr "Väylä" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 5416f7662..fe3dc4bb4 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -630,8 +630,8 @@ msgstr "Erreur fatale" msgid " - PAUSED" msgstr " - EN PAUSE" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Appuyez sur Ctrl+Alt+PgDn pour revenir au mode fenêtré." +msgid "Press %s to return to windowed mode." +msgstr "Appuyez sur %s pour revenir au mode fenêtré." msgid "Speed" msgstr "Vitesse" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 0fd342f88..1eecaa2d0 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -630,8 +630,8 @@ msgstr "Fatalna greška" msgid " - PAUSED" msgstr " - ZASTAO" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Pritisnite Ctrl+Alt+PgDn za povratak u prozorski način rada." +msgid "Press %s to return to windowed mode." +msgstr "Pritisnite %s za povratak u prozorski način rada." msgid "Speed" msgstr "Brzina" @@ -717,11 +717,11 @@ msgstr "Ostali periferni uređaji" msgid "Click to capture mouse" msgstr "Kliknite da uhvatite miš" -msgid "Press %1 to release mouse" -msgstr "Pritisnite %1 za otpustanje miša" +msgid "Press %s to release mouse" +msgstr "Pritisnite %s za otpustanje miša" -msgid "Press %1 or middle button to release mouse" -msgstr "Pritisnite %1 ili srednji gumb miša za otpuštanje miša" +msgid "Press %s or middle button to release mouse" +msgstr "Pritisnite %s ili srednji gumb miša za otpuštanje miša" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index cbb753890..43a1fd9ba 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -630,8 +630,8 @@ msgstr "Végzetes hiba" msgid " - PAUSED" msgstr " - SZÜNETELT" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Használja a Ctrl+Alt+PgDn gombokat az ablakhoz való visszatéréshez." +msgid "Press %s to return to windowed mode." +msgstr "Használja a %s gombokat az ablakhoz való visszatéréshez." msgid "Speed" msgstr "Sebesség" @@ -717,11 +717,11 @@ msgstr "Egyéb perifériák" msgid "Click to capture mouse" msgstr "Kattintson az egér elfogásához" -msgid "Press %1 to release mouse" -msgstr "Nyomja meg az %1-t az egér elengédéséhez" +msgid "Press %s to release mouse" +msgstr "Nyomja meg az %s-t az egér elengédéséhez" -msgid "Press %1 or middle button to release mouse" -msgstr "Nyomja meg az %1-t vagy a középső gombot az egér elengédéséhez" +msgid "Press %s or middle button to release mouse" +msgstr "Nyomja meg az %s-t vagy a középső gombot az egér elengédéséhez" msgid "Bus" msgstr "Busz" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index c505b9eaa..b8ded74de 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -630,8 +630,8 @@ msgstr "Errore fatale" msgid " - PAUSED" msgstr " - IN PAUSA" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Usa Ctrl+Alt+PgDn per tornare alla modalità finestra." +msgid "Press %s to return to windowed mode." +msgstr "Usa %s per tornare alla modalità finestra." msgid "Speed" msgstr "Velocità" @@ -717,11 +717,11 @@ msgstr "Altre periferiche" msgid "Click to capture mouse" msgstr "Fare clic per catturare mouse" -msgid "Press %1 to release mouse" -msgstr "Premi %1 per rilasciare il mouse" +msgid "Press %s to release mouse" +msgstr "Premi %s per rilasciare il mouse" -msgid "Press %1 or middle button to release mouse" -msgstr "Premi %1 o pulsante centrale per rilasciare il mouse" +msgid "Press %s or middle button to release mouse" +msgstr "Premi %s o pulsante centrale per rilasciare il mouse" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index cff667239..dc000b175 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -630,8 +630,8 @@ msgstr "致命的なエラー" msgid " - PAUSED" msgstr " - 一時停止" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Ctrl+Alt+PgDnでウィンドウ モードに戻ります。" +msgid "Press %s to return to windowed mode." +msgstr "%sでウィンドウ モードに戻ります。" msgid "Speed" msgstr "速度" @@ -717,11 +717,11 @@ msgstr "他の周辺デバイス" msgid "Click to capture mouse" msgstr "左クリックでマウスをキャプチャします" -msgid "Press %1 to release mouse" -msgstr "%1キーでマウスを解放します" +msgid "Press %s to release mouse" +msgstr "%sキーでマウスを解放します" -msgid "Press %1 or middle button to release mouse" -msgstr "%1キーまたは中クリックでマウスを解放します" +msgid "Press %s or middle button to release mouse" +msgstr "%sキーまたは中クリックでマウスを解放します" msgid "Bus" msgstr "バス" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 55f47be27..3ef901789 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -630,8 +630,8 @@ msgstr "치명적인 오류" msgid " - PAUSED" msgstr " - 일시 중지됨" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Ctrl+Alt+PgDn 키를 누르면 창 모드로 전환합니다." +msgid "Press %s to return to windowed mode." +msgstr "%s 키를 누르면 창 모드로 전환합니다." msgid "Speed" msgstr "속도" @@ -717,11 +717,11 @@ msgstr "기타 주변기기" msgid "Click to capture mouse" msgstr "이 창을 클릭하면 마우스를 사용합니다" -msgid "Press %1 to release mouse" -msgstr "%1키를 누르면 마우스를 해제합니다" +msgid "Press %s to release mouse" +msgstr "%s키를 누르면 마우스를 해제합니다" -msgid "Press %1 or middle button to release mouse" -msgstr "%1키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" +msgid "Press %s or middle button to release mouse" +msgstr "%s키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" msgid "Bus" msgstr "버스" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index e854ea3f3..8ee391957 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -630,8 +630,8 @@ msgstr "Fatale fout" msgid " - PAUSED" msgstr " - GEPAUZEERD" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Druk op Ctrl+Alt+PgDn om terug te gaan naar de venstermodus." +msgid "Press %s to return to windowed mode." +msgstr "Druk op %s om terug te gaan naar de venstermodus." msgid "Speed" msgstr "Snelheid" @@ -717,11 +717,11 @@ msgstr "Andere randapparatuur" msgid "Click to capture mouse" msgstr "Klik om muis vast te leggen" -msgid "Press %1 to release mouse" -msgstr "Druk op %1 om de muis los te laten" +msgid "Press %s to release mouse" +msgstr "Druk op %s om de muis los te laten" -msgid "Press %1 or middle button to release mouse" -msgstr "Druk op %1 of middelste knop om de muis los te laten" +msgid "Press %s or middle button to release mouse" +msgstr "Druk op %s of middelste knop om de muis los te laten" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 3fc731e5f..d5b5ec3ea 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -630,8 +630,8 @@ msgstr "Fatalny błąd" msgid " - PAUSED" msgstr " - PAUSED" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Naciśnij klawisze Ctrl+Alt+PgDn aby wrócić to trybu okna." +msgid "Press %s to return to windowed mode." +msgstr "Naciśnij klawisze %s aby wrócić to trybu okna." msgid "Speed" msgstr "Szybkość" @@ -717,11 +717,11 @@ msgstr "Inne urządzenia peryferyjne" msgid "Click to capture mouse" msgstr "Kliknij w celu przechwycenia myszy" -msgid "Press %1 to release mouse" -msgstr "Naciśnij klawisze %1 w celu uwolnienia myszy" +msgid "Press %s to release mouse" +msgstr "Naciśnij klawisze %s w celu uwolnienia myszy" -msgid "Press %1 or middle button to release mouse" -msgstr "Naciśnij klawisze %1 lub środkowy przycisk w celu uwolnienia myszy" +msgid "Press %s or middle button to release mouse" +msgstr "Naciśnij klawisze %s lub środkowy przycisk w celu uwolnienia myszy" msgid "Bus" msgstr "Magistrala" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 02abe2321..8961f11b8 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -630,8 +630,8 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - PAUSADO" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Use Ctrl+Alt+PgDn para retornar ao modo janela" +msgid "Press %s to return to windowed mode." +msgstr "Use %s para retornar ao modo janela" msgid "Speed" msgstr "Velocidade" @@ -717,11 +717,11 @@ msgstr "Outros periféricos" msgid "Click to capture mouse" msgstr "Clique para capturar o mouse" -msgid "Press %1 to release mouse" -msgstr "Aperte %1 para liberar o mouse" +msgid "Press %s to release mouse" +msgstr "Aperte %s para liberar o mouse" -msgid "Press %1 or middle button to release mouse" -msgstr "Aperte %1 ou botão do meio para liberar o mouse" +msgid "Press %s or middle button to release mouse" +msgstr "Aperte %s ou botão do meio para liberar o mouse" msgid "Bus" msgstr "Barramento" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 42550a266..ba1c6976c 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -630,8 +630,8 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - EM PAUSA" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Pressione Ctrl+Alt+PgDn para voltar ao modo de janela." +msgid "Press %s to return to windowed mode." +msgstr "Pressione %s para voltar ao modo de janela." msgid "Speed" msgstr "Velocidade" @@ -717,11 +717,11 @@ msgstr "Outros dispositivos" msgid "Click to capture mouse" msgstr "Clique para capturar o rato" -msgid "Press %1 to release mouse" -msgstr "Pressione %1 para soltar o rato" +msgid "Press %s to release mouse" +msgstr "Pressione %s para soltar o rato" -msgid "Press %1 or middle button to release mouse" -msgstr "Pressione %1 ou tecla média para soltar o rato" +msgid "Press %s or middle button to release mouse" +msgstr "Pressione %s ou tecla média para soltar o rato" msgid "Bus" msgstr "Barramento" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index dde5387a7..baf1035ea 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -630,8 +630,8 @@ msgstr "Неустранимая ошибка" msgid " - PAUSED" msgstr " - ПАУЗА" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Нажмите Ctrl+Alt+PgDn для возврата в оконный режим." +msgid "Press %s to return to windowed mode." +msgstr "Нажмите %s для возврата в оконный режим." msgid "Speed" msgstr "Скорость" @@ -717,11 +717,11 @@ msgstr "Другая периферия" msgid "Click to capture mouse" msgstr "Щёлкните мышью для захвата курсора" -msgid "Press %1 to release mouse" -msgstr "Нажмите %1, чтобы освободить курсор" +msgid "Press %s to release mouse" +msgstr "Нажмите %s, чтобы освободить курсор" -msgid "Press %1 or middle button to release mouse" -msgstr "Нажмите %1 или среднюю кнопку мыши, чтобы освободить курсор" +msgid "Press %s or middle button to release mouse" +msgstr "Нажмите %s или среднюю кнопку мыши, чтобы освободить курсор" msgid "Bus" msgstr "Шина" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 6039adedc..f11f335d4 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -630,8 +630,8 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENÝ" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Stlačte Ctrl+Alt+PgDn pre návrat z režimu celej obrazovky." +msgid "Press %s to return to windowed mode." +msgstr "Stlačte %s pre návrat z režimu celej obrazovky." msgid "Speed" msgstr "Rýchlosť" @@ -717,11 +717,11 @@ msgstr "Iné príslušenstvo" msgid "Click to capture mouse" msgstr "Kliknite pre zabráni myši" -msgid "Press %1 to release mouse" -msgstr "Stlačte %1 pre uvoľnenie myši" +msgid "Press %s to release mouse" +msgstr "Stlačte %s pre uvoľnenie myši" -msgid "Press %1 or middle button to release mouse" -msgstr "Stlačte %1 alebo prostredné tlačidlo na uvoľnenie myši" +msgid "Press %s or middle button to release mouse" +msgstr "Stlačte %s alebo prostredné tlačidlo na uvoľnenie myši" msgid "Bus" msgstr "Zbernica" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index b6641f8a1..7c2b36650 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -630,8 +630,8 @@ msgstr "Kritična napaka" msgid " - PAUSED" msgstr " - ZAUSTAVLJEN" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Pritisnite Ctrl+Alt+PgDn za povratek iz celozaslonskega načina." +msgid "Press %s to return to windowed mode." +msgstr "Pritisnite %s za povratek iz celozaslonskega načina." msgid "Speed" msgstr "Hitrost" @@ -717,11 +717,11 @@ msgstr "Druga periferija" msgid "Click to capture mouse" msgstr "Kliknite za zajem miške" -msgid "Press %1 to release mouse" -msgstr "Pritisnite %1 za izpust miške" +msgid "Press %s to release mouse" +msgstr "Pritisnite %s za izpust miške" -msgid "Press %1 or middle button to release mouse" -msgstr "Pritisnite %1 ali srednji gumb za izpust miške" +msgid "Press %s or middle button to release mouse" +msgstr "Pritisnite %s ali srednji gumb za izpust miške" msgid "Bus" msgstr "Vodilo" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index a47997225..61152c663 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -630,8 +630,8 @@ msgstr "Allvarligt fel" msgid " - PAUSED" msgstr " - PAUSAD" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Tryck på Ctrl+Alt+PgDn för att återvända till fönsterläge." +msgid "Press %s to return to windowed mode." +msgstr "Tryck på %s för att återvända till fönsterläge." msgid "Speed" msgstr "Hastighet" @@ -717,11 +717,11 @@ msgstr "Andra tillbehör" msgid "Click to capture mouse" msgstr "Klicka för att fånga upp musen" -msgid "Press %1 to release mouse" -msgstr "Tryck på %1 för att släppa musen" +msgid "Press %s to release mouse" +msgstr "Tryck på %s för att släppa musen" -msgid "Press %1 or middle button to release mouse" -msgstr "Tryck på %1 eller mellersta musknappen för att släppa musen" +msgid "Press %s or middle button to release mouse" +msgstr "Tryck på %s eller mellersta musknappen för att släppa musen" msgid "Bus" msgstr "Buss" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index e9a42a896..de111c59b 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -630,8 +630,8 @@ msgstr "Kritik hata" msgid " - PAUSED" msgstr " - DURAKLATILDI" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Pencere moduna geri dönmek için Ctrl+Alt+PgDn tuşlarına basın." +msgid "Press %s to return to windowed mode." +msgstr "Pencere moduna geri dönmek için %s tuşlarına basın." msgid "Speed" msgstr "Hız" @@ -717,11 +717,11 @@ msgstr "Diğer cihazlar" msgid "Click to capture mouse" msgstr "Farenin yakalanması için tıklayın" -msgid "Press %1 to release mouse" -msgstr "Farenin bırakılması için %1 tuşlarına basın" +msgid "Press %s to release mouse" +msgstr "Farenin bırakılması için %s tuşlarına basın" -msgid "Press %1 or middle button to release mouse" -msgstr "Farenin bırakılması için %1 tuşlarına veya tekerlek tuşuna basın" +msgid "Press %s or middle button to release mouse" +msgstr "Farenin bırakılması için %s tuşlarına veya tekerlek tuşuna basın" msgid "Bus" msgstr "Veri yolu" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index bceb7bea5..db9b73491 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -630,8 +630,8 @@ msgstr "Непереробна помилка" msgid " - PAUSED" msgstr " - ПРИЗУПИНЕННЯ" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Натисніть Ctrl+Alt+PgDn для повернення у віконний режим." +msgid "Press %s to return to windowed mode." +msgstr "Натисніть %s для повернення у віконний режим." msgid "Speed" msgstr "Швидкість" @@ -717,11 +717,11 @@ msgstr "Інша периферія" msgid "Click to capture mouse" msgstr "Клацніть мишею для захвату курсора" -msgid "Press %1 to release mouse" -msgstr "Натисніть %1, щоб звільнити курсор" +msgid "Press %s to release mouse" +msgstr "Натисніть %s, щоб звільнити курсор" -msgid "Press %1 or middle button to release mouse" -msgstr "Натисніть %1 або середню кнопку миші, щоб звільнити курсор" +msgid "Press %s or middle button to release mouse" +msgstr "Натисніть %s або середню кнопку миші, щоб звільнити курсор" msgid "Bus" msgstr "Шина" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index e14386bf8..e21466a18 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -630,8 +630,8 @@ msgstr "Lỗi nghiêm trọng" msgid " - PAUSED" msgstr " - TẠM DỪNG" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "Bấm Ctrl+Alt+PgDn để quay lại chế độ cửa sổ." +msgid "Press %s to return to windowed mode." +msgstr "Bấm %s để quay lại chế độ cửa sổ." msgid "Speed" msgstr "Vận tốc" @@ -717,11 +717,11 @@ msgstr "Thiết bị ngoại vi khác" msgid "Click to capture mouse" msgstr "Nhấp vào khung hình để 'nhốt' chuột vào" -msgid "Press %1 to release mouse" -msgstr "Nhấn %1 để thả chuột" +msgid "Press %s to release mouse" +msgstr "Nhấn %s để thả chuột" -msgid "Press %1 or middle button to release mouse" -msgstr "Nhấn %1 hoặc nhấp chuột giữa để thả chuột" +msgid "Press %s or middle button to release mouse" +msgstr "Nhấn %s hoặc nhấp chuột giữa để thả chuột" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 9f6cc0328..c29e40dfb 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -717,11 +717,11 @@ msgstr "其他外围设备" msgid "Click to capture mouse" msgstr "单击窗口捕捉鼠标" -msgid "Press %1 to release mouse" -msgstr "按下 %1 释放鼠标" +msgid "Press %s to release mouse" +msgstr "按下 %s 释放鼠标" -msgid "Press %1 or middle button to release mouse" -msgstr "按下 %1 或鼠标中键释放鼠标" +msgid "Press %s or middle button to release mouse" +msgstr "按下 %s 或鼠标中键释放鼠标" msgid "Bus" msgstr "总线" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index aefa89d5f..7de6f8cd3 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -717,11 +717,11 @@ msgstr "其他周邊裝置" msgid "Click to capture mouse" msgstr "點擊視窗捕捉滑鼠" -msgid "Press %1 to release mouse" -msgstr "按下 %1 釋放滑鼠" +msgid "Press %s to release mouse" +msgstr "按下 %s 釋放滑鼠" -msgid "Press %1 or middle button to release mouse" -msgstr "按下 %1 或滑鼠中鍵釋放滑鼠" +msgid "Press %s or middle button to release mouse" +msgstr "按下 %s 或滑鼠中鍵釋放滑鼠" msgid "Bus" msgstr "匯流排" diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index d79cc1b9e..1fb9b3fb5 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1295,7 +1295,7 @@ MainWindow::on_actionFullscreen_triggered() bool wasCaptured = mouse_capture == 1; char strFullscreen[100]; - sprintf(strFullscreen, qPrintable(tr("To return to windowed mode, press %s")), acc_keys[FindAccelerator("fullscreen")].seq); + sprintf(strFullscreen, qPrintable(tr("Press %s to return to windowed mode.")), acc_keys[FindAccelerator("fullscreen")].seq); QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), QString(strFullscreen), QMessageBox::Ok, this); QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); From a0f90f7c98830bd826d74e7e5c4d926c1683dfa6 Mon Sep 17 00:00:00 2001 From: snake-4 <18491360+snake-4@users.noreply.github.com> Date: Mon, 21 Apr 2025 03:29:00 +0200 Subject: [PATCH 0774/1190] Fixed stack overflow in CharPointer::operator= --- src/qt/qt_platform.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 26682528d..be40452fd 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -87,13 +87,13 @@ public: CharPointer &operator=(const QByteArray &ba) { if (s > 0) { + // If the size is known, copy up to s - 1 bytes + // and null-terminate the string. strncpy(b, ba.data(), s - 1); - b[s] = 0; - } else { - // if we haven't been told the length of b, just assume enough - // because we didn't get it from emulator code + b[s - 1] = 0; + } else if (ba.size() > 0) { + // If the size is unknown, copy the whole QByteArray strcpy(b, ba.data()); - b[ba.size()] = 0; } return *this; } From 46546f203289ed0a7f2e59f202c28786ed667133 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 21 Apr 2025 14:46:21 +0600 Subject: [PATCH 0775/1190] Keybind UI fixes 1. Don't clear the description text cell if selected; clear the actual keybind text instead. 2. Header texts are now correct. 3. Make the keybind dialog model and usable with dark mode --- src/qt/qt_keybind.cpp | 13 +++++++------ src/qt/qt_keybind.hpp | 2 +- src/qt/qt_settingsinput.cpp | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/qt/qt_keybind.cpp b/src/qt/qt_keybind.cpp index e8cbbf5b6..8b0f52eab 100644 --- a/src/qt/qt_keybind.cpp +++ b/src/qt/qt_keybind.cpp @@ -6,15 +6,15 @@ * * This file is part of the 86Box distribution. * - * Device configuration UI code. + * Keybind dialog * * * - * Authors: Joakim L. Gilje + * Authors: Cathode Ray Dude * Cacodemon345 * - * Copyright 2021 Joakim L. Gilje - * Copyright 2022 Cacodemon345 + * Copyright 2025 Cathode Ray Dude + * Copyright 2025 Cacodemon345 */ #include "qt_keybind.hpp" #include "ui_qt_keybind.h" @@ -85,12 +85,13 @@ bool KeyBinder::eventFilter(QObject *obj, QEvent *event) } QKeySequence -KeyBinder::BindKey(QString CurValue) +KeyBinder::BindKey(QWidget* widget, QString CurValue) { - KeyBinder kb; + KeyBinder kb(widget); kb.setWindowTitle("Bind Key"); kb.setFixedSize(kb.minimumSizeHint()); kb.findChild()->setKeySequence(QKeySequence::fromString(CurValue)); + kb.setEnabled(true); if (kb.exec() == QDialog::Accepted) { QKeySequenceEdit *seq = kb.findChild(); diff --git a/src/qt/qt_keybind.hpp b/src/qt/qt_keybind.hpp index e8e7b6e5e..393ee0f5c 100644 --- a/src/qt/qt_keybind.hpp +++ b/src/qt/qt_keybind.hpp @@ -22,7 +22,7 @@ public: explicit KeyBinder(QWidget *parent = nullptr); ~KeyBinder() override; - static QKeySequence BindKey(QString CurValue); + static QKeySequence BindKey(QWidget* widget, QString CurValue); private: Ui::KeyBinder *ui; diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index f87296451..bf5035110 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -63,7 +63,7 @@ SettingsInput::SettingsInput(QWidget *parent) keyTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); QStringList headers; //headers << "Action" << "Bound key"; - keyTable->setHorizontalHeaderLabels(headers); + keyTable->setHorizontalHeaderLabels(horizontalHeader); keyTable->verticalHeader()->setVisible(false); keyTable->setEditTriggers(QAbstractItemView::NoEditTriggers); keyTable->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -201,7 +201,7 @@ SettingsInput::on_tableKeys_doubleClicked(int row, int col) QTableWidgetItem *cell = ui->tableKeys->item(row,1); if (!cell) return; - QKeySequence keyseq = KeyBinder::BindKey(cell->text()); + QKeySequence keyseq = KeyBinder::BindKey(this, cell->text()); if (keyseq != false) { // If no change was made, don't change anything. if (keyseq.toString(QKeySequence::NativeText) == cell->text()) return; @@ -247,7 +247,7 @@ void SettingsInput::on_pushButtonClearBind_Clicked() { // Wipe bind - QTableWidgetItem *cell = ui->tableKeys->currentItem(); + QTableWidgetItem *cell = ui->tableKeys->item(ui->tableKeys->currentRow(), 1); if (!cell) return; cell->setText(""); From 0e634a3b7fa9eec1aa61c29d70fff6051d221fad Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 21 Apr 2025 16:13:11 +0600 Subject: [PATCH 0776/1190] HDD tooltips now list paths of disk images, CHS and their sizes --- src/qt/qt_machinestatus.cpp | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index d86dae7b9..c8f089749 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -640,6 +640,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_MFM].setActive(false); d->hdds[HDD_BUS_MFM].refresh(); d->hdds[HDD_BUS_MFM].label->setToolTip(tr("Hard disk (%1)").arg("MFM/RLL")); + auto tooltip = d->hdds[HDD_BUS_MFM].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_MFM && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_MFM].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_MFM].label.get()); } if ((has_esdi || (hdc_name.left(4) == QStringLiteral("esdi"))) && (c_esdi > 0)) { @@ -647,6 +655,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_ESDI].setActive(false); d->hdds[HDD_BUS_ESDI].refresh(); d->hdds[HDD_BUS_ESDI].label->setToolTip(tr("Hard disk (%1)").arg("ESDI")); + auto tooltip = d->hdds[HDD_BUS_ESDI].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_ESDI && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_ESDI].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_ESDI].label.get()); } if ((has_xta || (hdc_name.left(3) == QStringLiteral("xta"))) && (c_xta > 0)) { @@ -654,6 +670,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_XTA].setActive(false); d->hdds[HDD_BUS_XTA].refresh(); d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%1)").arg("XTA")); + auto tooltip = d->hdds[HDD_BUS_XTA].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_XTA && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_XTA].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_XTA].label.get()); } if (hasIDE() || (hdc_name.left(5) == QStringLiteral("xtide")) || @@ -664,6 +688,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_IDE].setActive(false); d->hdds[HDD_BUS_IDE].refresh(); d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%1)").arg("IDE")); + auto tooltip = d->hdds[HDD_BUS_IDE].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_IDE && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_IDE].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_IDE].label.get()); } if (c_atapi > 0) { @@ -671,6 +703,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_ATAPI].setActive(false); d->hdds[HDD_BUS_ATAPI].refresh(); d->hdds[HDD_BUS_ATAPI].label->setToolTip(tr("Hard disk (%1)").arg("ATAPI")); + auto tooltip = d->hdds[HDD_BUS_ATAPI].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_ATAPI && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_ATAPI].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_ATAPI].label.get()); } } @@ -682,6 +722,14 @@ MachineStatus::refresh(QStatusBar *sbar) d->hdds[HDD_BUS_SCSI].setActive(false); d->hdds[HDD_BUS_SCSI].refresh(); d->hdds[HDD_BUS_SCSI].label->setToolTip(tr("Hard disk (%1)").arg("SCSI")); + auto tooltip = d->hdds[HDD_BUS_SCSI].label->toolTip(); + tooltip.append("\n"); + for (int i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus_type == HDD_BUS_SCSI && hdd[i].fn[0] != 0) { + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 4), QString::asprintf("%02d", hdd[i].channel & 15), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + } + } + d->hdds[HDD_BUS_SCSI].label->setToolTip(tooltip); sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); } From c7db5122b76ca68cf99e22dcea76715c0847863d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 21 Apr 2025 17:25:12 +0600 Subject: [PATCH 0777/1190] Make `MB` in HDD tooltips translated --- src/qt/qt_machinestatus.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index c8f089749..f93734887 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -644,7 +644,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_MFM && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_MFM].label->setToolTip(tooltip); @@ -659,7 +659,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_ESDI && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_ESDI].label->setToolTip(tooltip); @@ -674,7 +674,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_XTA && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_XTA].label->setToolTip(tooltip); @@ -692,7 +692,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_IDE && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_IDE].label->setToolTip(tooltip); @@ -707,7 +707,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_ATAPI && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 1), QString::number(hdd[i].channel & 1), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_ATAPI].label->setToolTip(tooltip); @@ -726,7 +726,7 @@ MachineStatus::refresh(QStatusBar *sbar) tooltip.append("\n"); for (int i = 0; i < HDD_NUM; i++) { if (hdd[i].bus_type == HDD_BUS_SCSI && hdd[i].fn[0] != 0) { - tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 MB)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 4), QString::asprintf("%02d", hdd[i].channel & 15), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull))); + tooltip.append(QString("\n%5:%6: %1 (C:H:S = %2:%3:%4, %7 %8)").arg(QString::fromUtf8(hdd[i].fn), QString::number(hdd[i].tracks), QString::number(hdd[i].hpc), QString::number(hdd[i].spt), QString::number(hdd[i].channel >> 4), QString::asprintf("%02d", hdd[i].channel & 15), QString::number((((qulonglong)hdd[i].hpc * (qulonglong)hdd[i].spt * (qulonglong)hdd[i].tracks) * 512ull) / 1048576ull), tr("MB"))); } } d->hdds[HDD_BUS_SCSI].label->setToolTip(tooltip); From 11a55708fb66e8fa1a65117741cbbab2eb4abfe8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 21 Apr 2025 13:41:58 +0200 Subject: [PATCH 0778/1190] Made it compile as GUI again on Windows and made the help message a message box. --- CMakeLists.txt | 2 +- src/86box.c | 52 ++++++++++++++++++++++++++---------------------- src/qt/qt_ui.cpp | 9 ++++++++- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6ffa89e5..007c1ffd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ if(WIN32) # Default value for the `WIN32` target property, which specifies whether # to build the application for the Windows GUI or console subsystem - option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" OFF) + option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" ON) else() # Prefer dynamic builds everywhere else set(PREFER_STATIC OFF) diff --git a/src/86box.c b/src/86box.c index dae2d4ba5..cde98f5d8 100644 --- a/src/86box.c +++ b/src/86box.c @@ -666,40 +666,44 @@ usage: } } - printf("\nUsage: 86box [options] [cfg-file]\n\n"); - printf("Valid options are:\n\n"); - printf("-? or --help - show this information\n"); - printf("-C or --config path - set 'path' to be config file\n"); + ui_msgbox(MBX_INFO, L"\nUsage: 86box [options] [cfg-file]\n\n" + "Valid options are:\n\n" + "-? or --help\t\t\t- show this information\n" + "-C or --config path\t\t- set 'path' to be config file\n" #ifdef _WIN32 - printf("-D or --debug - force debug output logging\n"); + "-D or --debug\t\t\t- force debug output logging\n" #endif #if 0 - printf("-E or --nographic - forces the old behavior\n"); + "-E or --nographic\t\t- forces the old behavior\n" #endif - printf("-F or --fullscreen - start in fullscreen mode\n"); - printf("-G or --lang langid - start with specified language (e.g. en-US, or system)\n"); + "-F or --fullscreen\t\t- start in fullscreen mode\n" + "-G or --lang langid\t\t- start with specified language\n" + "\t\t\t\t (e.g. en-US, or system)\n" #ifdef _WIN32 - printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); + "-H or --hwnd id,hwnd\t\t- sends back the main dialog's hwnd\n" #endif - printf("-I or --image d:path - load 'path' as floppy image on drive d\n"); + "-I or --image d:path\t\t- load 'path' as floppy image on drive d\n" #ifdef USE_INSTRUMENT - printf("-J or --instrument name - set 'name' to be the profiling instrument\n"); + "-J or --instrument name\t- set 'name' to be the profiling instrument\n" #endif - printf("-L or --logfile path - set 'path' to be the logfile\n"); - printf("-M or --missing - dump missing machines and video cards\n"); - printf("-N or --noconfirm - do not ask for confirmation on quit\n"); - printf("-P or --vmpath path - set 'path' to be root for vm\n"); - printf("-R or --rompath path - set 'path' to be ROM path\n"); + "-L or --logfile pat\t\t- set 'path' to be the logfile\n" + "-M or --missing\t\t- dump missing machines and video cards\n" + "-N or --noconfirm\t\t- do not ask for confirmation on quit\n" + "-P or --vmpath path\t\t- set 'path' to be root for vm\n" + "-R or --rompath path\t\t- set 'path' to be ROM path\n" #ifndef USE_SDL_UI - printf("-S or --settings - show only the settings dialog\n"); + "-S or --settings\t\t\t- show only the settings dialog\n" #endif - printf("-T or --testmode - test mode: execute the test mode entry point on init/hard reset\n"); - printf("-V or --vmname name - overrides the name of the running VM\n"); - printf("-W or --nohook - disables keyboard hook (compatibility-only outside Windows)\n"); - printf("-X or --clear what - clears the 'what' (cmos/flash/both)\n"); - printf("-Y or --donothing - do not show any UI or run the emulation\n"); - printf("-Z or --lastvmpath - the last parameter is VM path rather than config\n"); - printf("\nA config file can be specified. If none is, the default file will be used.\n"); + "-T or --testmode\t\t- test mode: execute the test mode entry\n" + "\t\t\t\t point on init/hard reset\n" + "-V or --vmname name\t\t- overrides the name of the running VM\n" + "-W or --nohook\t\t- disables keyboard hook\n" + "\t\t\t\t (compatibility-only outside Windows)\n" + "-X or --clear what\t\t- clears the 'what' (cmos/flash/both)\n" + "-Y or --donothing\t\t- do not show any UI or run the emulation\n" + "-Z or --lastvmpath\t\t- the last parameter is VM path rather\n" + "\t\t\t\t than config\n" + "\nA config file can be specified. If none is, the default file will be used.\n"); return 0; } else if (!strcasecmp(argv[c], "--lastvmpath") || !strcasecmp(argv[c], "-Z")) { lvmp = 1; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 57f8001dc..b4e8a5486 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -141,7 +141,14 @@ ui_msgbox_header(int flags, void *header, void *message) // any error in early init if (main_window == nullptr) { - QMessageBox msgBox(QMessageBox::Icon::Critical, hdr, msg); + auto msgicon = QMessageBox::Icon::Critical; + if (flags & MBX_INFO) + msgicon = QMessageBox::Icon::Information; + else if (flags & MBX_QUESTION) + msgicon = QMessageBox::Icon::Question; + else if (flags & MBX_WARNING) + msgicon = QMessageBox::Icon::Warning; + QMessageBox msgBox(msgicon, hdr, msg); msgBox.exec(); } else { // else scope it to main_window From ac25b87e48ce723f3d7896089634fe2e0b603148 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 21 Apr 2025 13:42:28 +0200 Subject: [PATCH 0779/1190] Fix a warning in QT. --- src/qt/qt_settingsinput.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index bf5035110..79225cb91 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -48,7 +48,6 @@ SettingsInput::SettingsInput(QWidget *parent) { ui->setupUi(this); - QStandardItemModel *model; QStringList horizontalHeader; QStringList verticalHeader; From 5d33bc0dc23be9bfa95567b5121c0a02ff3a7c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Mon, 21 Apr 2025 14:20:57 +0200 Subject: [PATCH 0780/1190] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c01a852b5..ee0e1e7f1 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,9 @@ Performance may vary depending on both host and guest configuration. Most emulat It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines. +* [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux) * [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only) * [86Box Manager X](https://github.com/RetBox/86BoxManagerX) by [xafero](https://github.com/xafero) (Cross platform Port of 86Box Manager using Avalonia) -* [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux) * [sl86](https://github.com/DDXofficial/sl86) by [DDX](https://github.com/DDXofficial) (Command-line 86Box machine manager written in Python) * [Linbox-qt5](https://github.com/Dungeonseeker/linbox-qt5) by [Dungeonseeker](https://github.com/Dungeonseeker/) (Linux focused, should work on Windows though untested) * [MacBox for 86Box](https://github.com/Moonif/MacBox) by [Moonif](https://github.com/Moonif) (MacOS only) From 369167dd9be5aa9fe4f54c9d5f1a2a8fa1728e9f Mon Sep 17 00:00:00 2001 From: richardg867 Date: Mon, 21 Apr 2025 21:05:54 -0300 Subject: [PATCH 0781/1190] Update Jenkinsfile Jenkins: Fix the branch build manifest change (note: new Windows build node starts here) --- .ci/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index 04b0bc350..530349ced 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -20,7 +20,7 @@ def repository = ['https://github.com/86Box/86Box.git', scm.userRemoteConfigs[0] def commitBrowser = ['https://github.com/86Box/86Box/commit/%s', null] def branch = ['master', scm.branches[0].name] def buildType = ['beta', 'alpha'] -def tarballFlags = ['', '-s'] +def tarballFlags = ['', '-t'] def buildBranch = env.JOB_BASE_NAME.contains('-') ? 1 : 0 def osArchs = [ From 8790395a055578f29c2d1cac65178ecfa39301e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 22 Apr 2025 09:13:38 +0200 Subject: [PATCH 0782/1190] Fix the FXSAVE/FXRSTOR instructions. --- src/codegen/codegen_x86-64.c | 13 +++++++++ src/codegen/codegen_x86.c | 13 +++++++++ src/codegen_new/codegen.c | 12 +++++++++ src/codegen_new/codegen_reg.c | 1 + src/codegen_new/codegen_reg.h | 3 ++- src/cpu/386_common.c | 2 ++ src/cpu/cpu.h | 2 ++ src/cpu/x86_ops_fpu.h | 16 +++++++++++ src/cpu/x86_ops_fpu_2386.h | 16 +++++++++++ src/cpu/x86_ops_i686.h | 50 ++++++++++++++++++++++++----------- 10 files changed, 111 insertions(+), 17 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index 00db630a3..adb97169d 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -819,6 +819,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int pc_off = 0; int test_modrm = 1; int c; + uint16_t op87 = 0x0000; op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; @@ -872,6 +873,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p break; case 0xd8: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d8; opcode_shift = 3; @@ -882,6 +884,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xd9: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d9; opcode_mask = 0xff; @@ -891,6 +894,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xda: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_da; opcode_mask = 0xff; @@ -900,6 +904,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdb: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_db; opcode_mask = 0xff; @@ -909,6 +914,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdc: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dc; opcode_shift = 3; @@ -919,6 +925,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdd: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dd; opcode_mask = 0xff; @@ -928,6 +935,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xde: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_de; opcode_mask = 0xff; @@ -937,6 +945,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdf: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_df; opcode_mask = 0xff; @@ -1000,6 +1009,10 @@ generate_call: recomp_op_table = recomp_opcodes; } + if (op87 != 0x0000) { + STORE_IMM_ADDR_W((uintptr_t) &x87_op, op87); + } + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); if (new_pc) { diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index 935e2bab6..cb635d4f1 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1858,6 +1858,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int pc_off = 0; int test_modrm = 1; int c; + uint16_t op87 = 0x0000; op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; @@ -1912,6 +1913,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p break; case 0xd8: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d8; opcode_shift = 3; @@ -1922,6 +1924,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xd9: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d9; opcode_mask = 0xff; @@ -1931,6 +1934,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xda: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_da; opcode_mask = 0xff; @@ -1940,6 +1944,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdb: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_db; opcode_mask = 0xff; @@ -1949,6 +1954,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdc: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dc; opcode_shift = 3; @@ -1959,6 +1965,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdd: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dd; opcode_mask = 0xff; @@ -1968,6 +1975,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xde: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_de; opcode_mask = 0xff; @@ -1977,6 +1985,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p block->flags |= CODEBLOCK_HAS_FPU; break; case 0xdf: + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_df; opcode_mask = 0xff; @@ -2041,6 +2050,10 @@ generate_call: recomp_op_table = recomp_opcodes; } + if (op87 != 0x0000) { + STORE_IMM_ADDR_W((uintptr_t) &x87_op, op87); + } + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); if (new_pc) { diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 82f6cd037..44dd408ab 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -396,6 +396,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int test_modrm = 1; int pc_off = 0; uint32_t next_pc = 0; + uint16_t op87 = 0x0000; #ifdef DEBUG_EXTRA uint8_t last_prefix = 0; #endif @@ -451,6 +452,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xd8; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d8; opcode_shift = 3; @@ -464,6 +466,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xd9; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_d9; opcode_mask = 0xff; @@ -476,6 +479,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xda; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_da; opcode_mask = 0xff; @@ -488,6 +492,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xdb; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_db; opcode_mask = 0xff; @@ -500,6 +505,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xdc; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dc; opcode_shift = 3; @@ -513,6 +519,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xdd; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_dd; opcode_mask = 0xff; @@ -525,6 +532,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xde; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_de; opcode_mask = 0xff; @@ -537,6 +545,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p #ifdef DEBUG_EXTRA last_prefix = 0xdf; #endif + op87 = (op87 & 0xf800) | ((opcode & 0x07) << 8) | (fetchdat & 0xff); op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; recomp_op_table = fpu_softfloat ? NULL : recomp_opcodes_df; opcode_mask = 0xff; @@ -657,6 +666,9 @@ generate_call: } } codegen_mark_code_present(block, cs + old_pc, (op_pc - old_pc) - pc_off); + if (op87 != 0x0000) { + uop_MOV_IMM(ir, IREG_x87_op, op87); + } /* It is apparently a prefixed instruction. */ #if 0 if ((recomp_op_table == recomp_opcodes) && (opcode == 0x48)) diff --git a/src/codegen_new/codegen_reg.c b/src/codegen_new/codegen_reg.c index de67fde5a..ba60ab038 100644 --- a/src/codegen_new/codegen_reg.c +++ b/src/codegen_new/codegen_reg.c @@ -170,6 +170,7 @@ struct [IREG_SS_limit_high] = { REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT}, [IREG_eaa16] = { REG_WORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT}, + [IREG_x87_op] = { REG_WORD, &x87_op, REG_INTEGER, REG_PERMANENT}, /*Temporary registers are stored on the stack, and are not guaranteed to be preserved across uOPs. They will not be written back if they will diff --git a/src/codegen_new/codegen_reg.h b/src/codegen_new/codegen_reg.h index fd3cf279a..2185fde45 100644 --- a/src/codegen_new/codegen_reg.h +++ b/src/codegen_new/codegen_reg.h @@ -133,8 +133,9 @@ enum { IREG_SS_limit_high = 87, IREG_eaa16 = 88, + IREG_x87_op = 89, - IREG_COUNT = 89, + IREG_COUNT = 90, IREG_INVALID = 255, diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 2853e3c9a..ecd83966c 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -113,6 +113,8 @@ uint8_t is_smint = 0; uint16_t io_port = 0x0000; uint32_t io_val = 0x00000000; +uint16_t x87_op = 0x0000; + int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 0e49704fd..63b831d84 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -784,6 +784,8 @@ typedef struct { uint32_t smhr; } cyrix_t; +extern uint16_t x87_op; + extern uint32_t addr64; extern uint32_t addr64_2; extern uint32_t addr64a[8]; diff --git a/src/cpu/x86_ops_fpu.h b/src/cpu/x86_ops_fpu.h index 3434c4a73..afc79dd42 100644 --- a/src/cpu/x86_ops_fpu.h +++ b/src/cpu/x86_ops_fpu.h @@ -4,88 +4,104 @@ static int opESCAPE_d8_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_d8_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_d9_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_d9_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_da_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_da_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_db_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_db_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_dc_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_dc_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_dd_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_dd_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_de_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_de_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_df_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_df_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); } diff --git a/src/cpu/x86_ops_fpu_2386.h b/src/cpu/x86_ops_fpu_2386.h index c2252af12..7488a3d85 100644 --- a/src/cpu/x86_ops_fpu_2386.h +++ b/src/cpu/x86_ops_fpu_2386.h @@ -4,88 +4,104 @@ static int opESCAPE_d8_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_d8_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_d9_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_d9_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_d9_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_d9_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_da_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_da_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_da_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_da_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_db_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_db_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_db_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_db_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_dc_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_dc_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); } static int opESCAPE_dd_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_dd_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_dd_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_dd_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_de_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_de_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_de_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_de_a32[fetchdat & 0xff](fetchdat); } static int opESCAPE_df_a16(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_df_a16[fetchdat & 0xff](fetchdat); } static int opESCAPE_df_a32(uint32_t fetchdat) { + x87_op = ((opcode & 0x07) << 8) | (fetchdat & 0xff); return x86_2386_opcodes_df_a32[fetchdat & 0xff](fetchdat); } diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index a67571875..0809fac74 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -46,8 +46,6 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) if (CPUID < 0x650) return ILLEGAL(fetchdat); - FP_ENTER(); - if (bits == 32) { fetch_ea_32(fetchdat); } else { @@ -82,12 +80,18 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) /* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */ fpu_state.foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; - fpu_state.fip = readmeml(easeg, cpu_state.eaaddr + 8); + if (bits == 32) + fpu_state.fip = readmeml(easeg, cpu_state.eaaddr + 8); + else + fpu_state.fip = readmemw(easeg, cpu_state.eaaddr + 8); fpu_state.fcs = readmemw(easeg, cpu_state.eaaddr + 12); tag_byte = readmemb(easeg, cpu_state.eaaddr + 4); - fpu_state.fdp = readmeml(easeg, cpu_state.eaaddr + 16); + if (bits == 32) + fpu_state.fdp = readmeml(easeg, cpu_state.eaaddr + 16); + else + fpu_state.fdp = readmemw(easeg, cpu_state.eaaddr + 16); fpu_state.fds = readmemw(easeg, cpu_state.eaaddr + 20); /* load i387 register file */ @@ -110,7 +114,6 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) fpu_state.swd &= ~(FPU_SW_Summary | FPU_SW_Backward); } - // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); CLOCK_CYCLES(1); } else { /* FXSAVE */ @@ -132,7 +135,10 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) * x87 CS FPU IP Selector * + 16 bit, in 16/32 bit mode only */ - writememl(easeg, cpu_state.eaaddr + 8, fpu_state.fip); + if (bits == 32) + writememl(easeg, cpu_state.eaaddr + 8, fpu_state.fip); + else + writememl(easeg, cpu_state.eaaddr + 8, fpu_state.fip & 0xffff); writememl(easeg, cpu_state.eaaddr + 12, fpu_state.fcs); /* @@ -145,7 +151,10 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) * x87 DS FPU Instruction Operand (Data) Pointer Selector * + 16 bit, in 16/32 bit mode only */ - writememl(easeg, cpu_state.eaaddr + 16, fpu_state.fdp); + if (bits == 32) + writememl(easeg, cpu_state.eaaddr + 16, fpu_state.fdp); + else + writememl(easeg, cpu_state.eaaddr + 16, fpu_state.fdp & 0xffff); writememl(easeg, cpu_state.eaaddr + 20, fpu_state.fds); /* store i387 register file */ @@ -256,8 +265,6 @@ fx_save_stor_common(uint32_t fetchdat, int bits) return cpu_state.abrt; } - FP_ENTER(); - old_eaaddr = cpu_state.eaaddr; if (fxinst == 1) { @@ -269,13 +276,19 @@ fx_save_stor_common(uint32_t fetchdat, int bits) cpu_state.TOP = (fpus >> 11) & 7; cpu_state.npxs &= fpus & ~0x3800; - x87_pc_off = readmeml(easeg, cpu_state.eaaddr + 8); + if (bits == 32) + x87_pc_off = readmeml(easeg, cpu_state.eaaddr + 8); + else + x87_pc_off = readmemw(easeg, cpu_state.eaaddr + 8); x87_pc_seg = readmemw(easeg, cpu_state.eaaddr + 12); ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + x87_op = readmemw(easeg, cpu_state.eaaddr + 6) & 0x07ff; - x87_op_off = readmeml(easeg, cpu_state.eaaddr + 16); - x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + if (bits == 32) + x87_op_off = readmeml(easeg, cpu_state.eaaddr + 16); + else + x87_op_off = readmemw(easeg, cpu_state.eaaddr +16); x87_op_seg = readmemw(easeg, cpu_state.eaaddr + 20); for (i = 0; i <= 7; i++) { @@ -320,7 +333,6 @@ fx_save_stor_common(uint32_t fetchdat, int bits) } } - // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); CLOCK_CYCLES(1); } else { /* FXSAVE */ @@ -345,11 +357,17 @@ fx_save_stor_common(uint32_t fetchdat, int bits) writememw(easeg, cpu_state.eaaddr + 2, cpu_state.npxs); writememb(easeg, cpu_state.eaaddr + 4, ftwb); - writememw(easeg, cpu_state.eaaddr + 6, (x87_op_off >> 16) << 12); - writememl(easeg, cpu_state.eaaddr + 8, x87_pc_off); + writememw(easeg, cpu_state.eaaddr + 6, x87_op); + if (bits == 32) + writememl(easeg, cpu_state.eaaddr + 8, x87_pc_off); + else + writememl(easeg, cpu_state.eaaddr + 8, x87_pc_off & 0xffff); writememw(easeg, cpu_state.eaaddr + 12, x87_pc_seg); - writememl(easeg, cpu_state.eaaddr + 16, x87_op_off); + if (bits == 32) + writememl(easeg, cpu_state.eaaddr + 16, x87_op_off); + else + writememl(easeg, cpu_state.eaaddr + 16, x87_op_off & 0xffff); writememw(easeg, cpu_state.eaaddr + 20, x87_op_seg); if (cpu_state.ismmx) { From b15f25ffa46ed7c2bc189fcf34fef2dd546dd6a4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 22 Apr 2025 09:46:58 +0200 Subject: [PATCH 0783/1190] Fixed old recompiler compiling in a kludgy way because it appears there's no STORE_IMM_ADDR_W. --- src/codegen/codegen_x86-64.c | 4 ++-- src/codegen/codegen_x86.c | 4 ++-- src/cpu/386_common.c | 2 +- src/cpu/cpu.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index adb97169d..c424cf8c5 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -819,7 +819,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int pc_off = 0; int test_modrm = 1; int c; - uint16_t op87 = 0x0000; + uint32_t op87 = 0x00000000; op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; @@ -1010,7 +1010,7 @@ generate_call: } if (op87 != 0x0000) { - STORE_IMM_ADDR_W((uintptr_t) &x87_op, op87); + STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87); } if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index cb635d4f1..bf34c2de8 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1858,7 +1858,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int pc_off = 0; int test_modrm = 1; int c; - uint16_t op87 = 0x0000; + uint32_t op87 = 0x00000000; op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; @@ -2051,7 +2051,7 @@ generate_call: } if (op87 != 0x0000) { - STORE_IMM_ADDR_W((uintptr_t) &x87_op, op87); + STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87); } if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index ecd83966c..c6a759d36 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -113,7 +113,7 @@ uint8_t is_smint = 0; uint16_t io_port = 0x0000; uint32_t io_val = 0x00000000; -uint16_t x87_op = 0x0000; +uint32_t x87_op = 0x00000000; int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 63b831d84..b76e2d622 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -784,7 +784,7 @@ typedef struct { uint32_t smhr; } cyrix_t; -extern uint16_t x87_op; +extern uint32_t x87_op; extern uint32_t addr64; extern uint32_t addr64_2; From e703ac760b6c0cf0cac3bfa0b196688178c5a099 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 22 Apr 2025 17:37:00 +0600 Subject: [PATCH 0784/1190] Write indicators (except for floppy drives) --- src/disk/hdc_esdi_at.c | 24 ++++-- src/disk/hdc_esdi_mca.c | 9 ++ src/disk/hdc_ide.c | 12 +-- src/disk/hdc_st506_at.c | 9 +- src/disk/hdc_st506_xt.c | 18 ++-- src/disk/hdc_xta.c | 10 +-- src/disk/mo.c | 6 +- src/disk/zip.c | 6 +- src/include/86box/machine_status.h | 2 + src/include/86box/ui.h | 1 + src/machine/m_ps1_hdc.c | 13 +-- src/network/network.c | 4 +- src/qt/icons/write_active.ico | Bin 0 -> 6950 bytes src/qt/qt_iconindicators.cpp | 8 +- src/qt/qt_iconindicators.hpp | 2 + src/qt/qt_machinestatus.cpp | 131 ++++++++++++++++++++++++----- src/qt/qt_ui.cpp | 37 ++++++++ src/qt_resources.qrc | 1 + src/scsi/scsi_disk.c | 5 +- src/sound/CMakeLists.txt | 2 +- 20 files changed, 232 insertions(+), 68 deletions(-) create mode 100644 src/qt/icons/write_active.ico diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index ab24aa6fa..64d292250 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -395,7 +395,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) fatal("Write with ECC\n"); esdi->status = STAT_READY | STAT_DRQ | STAT_DSC; esdi->pos = 0; - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 1); break; case CMD_VERIFY: @@ -412,7 +412,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_FORMAT: esdi->status = STAT_DRQ; esdi->pos = 0; - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 1); break; case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ @@ -593,6 +593,7 @@ esdi_callback(void *priv) esdi->reset = 0; ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); return; } @@ -650,7 +651,7 @@ read_error: esdi->status = STAT_READY | STAT_ERR | STAT_DSC; esdi->error = ERR_ABRT; irq_raise(esdi); - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; } else { if (get_sector(esdi, &addr)) { @@ -658,7 +659,7 @@ read_error: write_error: esdi->status = STAT_READY | STAT_DSC | STAT_ERR; irq_raise(esdi); - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; } @@ -672,10 +673,10 @@ write_error: esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; esdi->pos = 0; next_sector(esdi); - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 1); } else { esdi->status = STAT_READY | STAT_DSC; - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } } break; @@ -718,7 +719,7 @@ verify_error: break; case CMD_FORMAT: - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); if (!drive->present) { esdi->status = STAT_READY | STAT_ERR | STAT_DSC; esdi->error = ERR_ABRT; @@ -752,10 +753,12 @@ format_error: esdi->status = STAT_READY | STAT_DSC; irq_raise(esdi); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); if (!drive->present) { esdi->status = STAT_READY | STAT_ERR | STAT_DSC; esdi->error = ERR_ABRT; @@ -778,10 +781,12 @@ format_error: esdi->error = ERR_ABRT; irq_raise(esdi); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case 0xe0: ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); if (!drive->present) { esdi->status = STAT_READY | STAT_ERR | STAT_DSC; esdi->error = ERR_ABRT; @@ -825,6 +830,7 @@ format_error: } irq_raise(esdi); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case CMD_READ_PARAMETERS: @@ -869,6 +875,7 @@ format_error: irq_raise(esdi); } ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; default: @@ -880,6 +887,7 @@ format_error: esdi->error = ERR_ABRT; irq_raise(esdi); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; } } @@ -954,6 +962,7 @@ wd1007vse1_init(UNUSED(const device_t *info)) timer_add(&esdi->callback_timer, esdi_callback, esdi, 0); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); return esdi; } @@ -973,6 +982,7 @@ wd1007vse1_close(void *priv) free(esdi); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } static int diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 8f1def137..e59ae981d 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -288,6 +288,7 @@ cmd_unsupported(esdi_t *dev) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } static void @@ -309,6 +310,7 @@ device_not_present(esdi_t *dev) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } static void @@ -330,6 +332,7 @@ rba_out_of_range(esdi_t *dev) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } static void @@ -351,6 +354,7 @@ defective_block(esdi_t *dev) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } static void @@ -368,6 +372,7 @@ complete_command_status(esdi_t *dev) dev->status_data[5] = (dev->rba - 1) >> 8; dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/ ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); } #define ESDI_ADAPTER_ONLY() \ @@ -696,6 +701,7 @@ esdi_callback(void *priv) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case CMD_GET_DEV_CONFIG: @@ -744,6 +750,7 @@ esdi_callback(void *priv) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case CMD_GET_POS_INFO: @@ -764,6 +771,7 @@ esdi_callback(void *priv) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; case 0x10: @@ -817,6 +825,7 @@ esdi_callback(void *priv) dev->irq_in_progress = 1; set_irq(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_ESDI, 0); break; default: diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 04e580e72..fe48bba6d 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -1827,7 +1827,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on less times. */ - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); fallthrough; case WIN_WRITE: @@ -2479,10 +2479,10 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide->tf->pos = 0; ide_next_sector(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } else { ide->tf->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } if (ret < 0) err = UNC_ERR; @@ -2524,7 +2524,7 @@ ide_callback(void *priv) err = UNC_ERR; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } else { /* Bus master DMA error, abort the command. */ ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); @@ -2562,7 +2562,7 @@ ide_callback(void *priv) ide_next_sector(ide); } else { ide->tf->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 0); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } if (ret < 0) err = UNC_ERR; @@ -2596,7 +2596,7 @@ ide_callback(void *priv) err = UNC_ERR; ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus_type, 1); + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } break; diff --git a/src/disk/hdc_st506_at.c b/src/disk/hdc_st506_at.c index 07c57b2ca..ed7b29d1f 100644 --- a/src/disk/hdc_st506_at.c +++ b/src/disk/hdc_st506_at.c @@ -557,6 +557,7 @@ do_callback(void *priv) mfm->reset = 0; ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); return; } @@ -627,9 +628,9 @@ write_error: mfm->status |= STAT_DRQ; mfm->pos = 0; next_sector(mfm); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 1); } else - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); break; case CMD_VERIFY: @@ -657,7 +658,7 @@ write_error: mfm->status = STAT_READY | STAT_DSC; irq_raise(mfm); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 1); break; case CMD_DIAGNOSE: @@ -772,6 +773,7 @@ mfm_init(UNUSED(const device_t *info)) timer_add(&mfm->callback_timer, do_callback, mfm, 0); ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); return mfm; } @@ -790,6 +792,7 @@ mfm_close(void *priv) free(mfm); ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); } const device_t st506_at_wd1003_device = { diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c index 536fd76c0..b3a07fa5a 100644 --- a/src/disk/hdc_st506_xt.c +++ b/src/disk/hdc_st506_xt.c @@ -580,14 +580,14 @@ st506_callback(void *priv) (void) get_chs(dev, drive); st506_xt_log("ST506: FORMAT_DRIVE(%i) interleave=%i\n", dev->drive_sel, dev->command[4]); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 1); timer_advance_u64(&dev->timer, ST506_TIME); dev->state = STATE_SEND_DATA; break; case STATE_SEND_DATA: /* wrong, but works */ if (!get_sector(dev, drive, &addr)) { - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_error(dev, dev->error); st506_complete(dev); return; @@ -604,7 +604,7 @@ st506_callback(void *priv) break; case STATE_SENT_DATA: - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_complete(dev); break; @@ -663,14 +663,14 @@ st506_callback(void *priv) st506_xt_log("ST506: FORMAT_%sTRACK(%i, %i/%i)\n", (dev->command[0] == CMD_FORMAT_BAD_TRACK) ? "BAD_" : "", dev->drive_sel, dev->cylinder, dev->head); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 1); timer_advance_u64(&dev->timer, ST506_TIME); dev->state = STATE_SEND_DATA; break; case STATE_SEND_DATA: /* wrong, but works */ if (!get_sector(dev, drive, &addr)) { - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_error(dev, dev->error); st506_complete(dev); return; @@ -686,7 +686,7 @@ st506_callback(void *priv) break; case STATE_SENT_DATA: - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_complete(dev); break; @@ -828,7 +828,7 @@ read_error_sent: return; } - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 1); /* Set up the data transfer. */ dev->buff_pos = 0; @@ -865,7 +865,7 @@ read_error_sent: case STATE_RECEIVED_DATA: if (!get_sector(dev, drive, &addr)) { write_error: - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_error(dev, dev->error); st506_complete(dev); return; @@ -879,7 +879,7 @@ write_error: } if (--dev->count == 0) { - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_MFM, 0); st506_complete(dev); break; } diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index b01d80c61..85581af2d 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -385,7 +385,7 @@ do_format(hdc_t *dev, drive_t *drive, dcb_t *dcb) dev->sector = 0; /* Activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 1); do_fmt: /* @@ -426,7 +426,7 @@ do_fmt: } /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); } /* Execute the DCB we just received. */ @@ -631,7 +631,7 @@ read_error: case STATE_RECV: /* Activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 1); do_recv: /* Ready to transfer the data in. */ dev->state = STATE_RDATA; @@ -680,7 +680,7 @@ do_recv: if (get_sector(dev, drive, &addr)) { write_error: /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); dev->comp |= COMP_ERR; set_intr(dev); @@ -697,7 +697,7 @@ write_error: dev->buf_idx = 0; if (--dev->count == 0) { /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); set_intr(dev); return; diff --git a/src/disk/mo.c b/src/disk/mo.c index a20333404..1a2db0443 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -628,6 +628,7 @@ mo_cmd_error(mo_t *dev) dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); + ui_sb_update_icon_write(SB_MO | dev->id, 0); mo_log(dev->log, "[%02X] ERROR: %02X/%02X/%02X\n", dev->current_cdb[0], mo_sense_key, mo_asc, mo_ascq); } @@ -644,6 +645,7 @@ mo_unit_attention(mo_t *dev) dev->callback = 50.0 * MO_TIME; mo_set_callback(dev); ui_sb_update_icon(SB_MO | dev->id, 0); + ui_sb_update_icon_write(SB_MO | dev->id, 0); mo_log(dev->log, "UNIT ATTENTION\n"); } @@ -1462,7 +1464,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) mo_data_command_finish(dev, dev->packet_len, dev->drv->sector_size, dev->packet_len, 1); - ui_sb_update_icon(SB_MO | dev->id, + ui_sb_update_icon_write(SB_MO | dev->id, dev->packet_status != PHASE_COMPLETE); } else { mo_set_phase(dev, SCSI_PHASE_STATUS); @@ -1501,7 +1503,7 @@ mo_command(scsi_common_t *sc, const uint8_t *cdb) dev->drv->sector_size, alloc_length, 1); - ui_sb_update_icon(SB_MO | dev->id, + ui_sb_update_icon_write(SB_MO | dev->id, dev->packet_status != PHASE_COMPLETE); } else { mo_set_phase(dev, SCSI_PHASE_STATUS); diff --git a/src/disk/zip.c b/src/disk/zip.c index 7a407c5fe..55cf901a4 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -709,6 +709,7 @@ zip_cmd_error(zip_t *dev) dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); ui_sb_update_icon(SB_ZIP | dev->id, 0); + ui_sb_update_icon_write(SB_ZIP | dev->id, 0); zip_log(dev->log, "[%02X] ERROR: %02X/%02X/%02X\n", dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); } @@ -725,6 +726,7 @@ zip_unit_attention(zip_t *dev) dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); ui_sb_update_icon(SB_ZIP | dev->id, 0); + ui_sb_update_icon_write(SB_ZIP | dev->id, 0); zip_log(dev->log, "UNIT ATTENTION\n", dev->id); } @@ -1485,7 +1487,7 @@ zip_command(scsi_common_t *sc, const uint8_t *cdb) zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - ui_sb_update_icon(SB_ZIP | dev->id, + ui_sb_update_icon_write(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); } else { zip_set_phase(dev, SCSI_PHASE_STATUS); @@ -1526,7 +1528,7 @@ zip_command(scsi_common_t *sc, const uint8_t *cdb) zip_data_command_finish(dev, 512, 512, alloc_length, 1); - ui_sb_update_icon(SB_ZIP | dev->id, + ui_sb_update_icon_write(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE); } else { zip_set_phase(dev, SCSI_PHASE_STATUS); diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index e7c57881b..e6e9e6acd 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -4,10 +4,12 @@ typedef struct dev_status_empty_active_t { atomic_bool_t empty; atomic_bool_t active; + atomic_bool_t write_active; } dev_status_empty_active_t; typedef struct dev_status_active_t { atomic_bool_t active; + atomic_bool_t write_active; } dev_status_active_t; typedef struct dev_status_empty_t { diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index c12eb73a0..783400ebc 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -65,6 +65,7 @@ extern void ui_sb_update_panes(void); extern void ui_sb_update_text(void); extern void ui_sb_update_tip(int meaning); extern void ui_sb_update_icon(int tag, int active); +extern void ui_sb_update_icon_write(int tag, int write); extern void ui_sb_update_icon_state(int tag, int state); extern void ui_sb_set_text_w(wchar_t *wstr); extern void ui_sb_set_text(char *str); diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index 18792ded7..ea71c918b 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -653,7 +653,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) case STATE_FINIT: do_fmt: /* Activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 1); /* Seek to cylinder. */ if (do_seek(dev, drive, start_cyl)) { @@ -691,7 +691,7 @@ do_fmt: } /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); /* This saves us a LOT of code. */ dev->state = STATE_FINIT; @@ -705,6 +705,7 @@ do_fmt: if (intr) { /* De-activate the status icon. */ ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); do_finish(dev); } @@ -970,7 +971,7 @@ do_send: case STATE_RECV: /* Activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 1); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 1); do_recv: /* Ready to transfer the data in. */ dev->state = STATE_RDATA; @@ -1000,7 +1001,7 @@ do_recv: ps1_hdc_log("HDC: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); dev->intstat |= ISR_EQUIP_CHECK; dev->ssb.need_reset = 1; @@ -1025,7 +1026,7 @@ do_recv: /* Get address of sector to write. */ if (get_sector(dev, drive, &addr)) { /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); do_finish(dev); return; @@ -1038,7 +1039,7 @@ do_recv: dev->buf_idx = 0; if (--dev->count == 0) { /* De-activate the status icon. */ - ui_sb_update_icon(SB_HDD | HDD_BUS_XTA, 0); + ui_sb_update_icon_write(SB_HDD | HDD_BUS_XTA, 0); if (!(dev->ctrl & ACR_DMA_EN)) dev->status &= ~ASR_DATA_REQ; diff --git a/src/network/network.c b/src/network/network.c index 52b686c7e..239178a5d 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -432,7 +432,8 @@ network_rx_queue(void *priv) bool activity = rx_bytes || tx_bytes; bool led_on = card->led_timer & 0x80000000; if ((activity && !led_on) || (card->led_timer & 0x7fffffff) >= 150000) { - ui_sb_update_icon(SB_NETWORK | card->card_num, activity); + ui_sb_update_icon(SB_NETWORK | card->card_num, !!(rx_bytes)); + ui_sb_update_icon_write(SB_NETWORK | card->card_num, !!(tx_bytes)); card->led_timer = 0 | (activity << 31); } @@ -577,6 +578,7 @@ void network_reset(void) { ui_sb_update_icon(SB_NETWORK, 0); + ui_sb_update_icon_write(SB_NETWORK, 0); #ifdef ENABLE_NETWORK_LOG network_dump_mutex = thread_create_mutex(); diff --git a/src/qt/icons/write_active.ico b/src/qt/icons/write_active.ico new file mode 100644 index 0000000000000000000000000000000000000000..d1ebdb22498d6dbdfeae87c7d21969948c5cc868 GIT binary patch literal 6950 zcmZQzU}RunkdRa-s|j8Vn2!AR`PIK<06PBpDo-z!ZdF1WSO~|NsAI@bLK0(AW1L%pWC2Ltr!n zMs^4=Apzu&U}9v30p!wzVd#i6!T_rKarhV6@1txiA;A8hfq?`Js%uEWpn42c^*Mm6 zD@Z-Yz=GtC(RvIiFh-f9Aut*O*g^oQcn34l)gaYhp!yA^ZUCtrl?Me29Md3tVAV31 z#xx%sYX|}qC!=^Y1P~!m|DS<@eEgq60BWazy5yj?3L^uwodRl`z#Ir-gD?XF1E~Eo z+TVr+%qTq?0wXsBpfwsi03huQMD<5HA5?!L>4#VVH-Eqxpdm&)`2T-U`G^~X%307* zCy0iXvlF1@D%fuzHV89-3}OJ0V8g)XGW=&aaNq#L{~sS1uD|}paOHnJSpJcA7lW48 zQt%ik3kwSa2L}guEL2cXkU>mLj6p_5hCxY5i9u6Slfl^7n8DK0lEKNziNV*`mmxGX zlp!G@fgvp|jiI2RfT5wGfuX0ThhfT;DGW1b&SY4!WC_EXHES5QZQBO6`^=d$3|FpP zVYqec7Q=%F4;bFOdBgDI#}9_zzkh@41!D#VhBO8ShM5cu3}--f1;|sz3=GD`3=C<; z3=A`k85qtOGcf#zDl|@GU`R`2V3?W4z;Gswf#E+?v++y@hP0Us3^QjkFr1mm!0;bx zpz#?7hO{#b3^UI#Fq}EV!0;bxiSd61hP3|-3^V^TFq{De9Vm_%jKMIC!I)ttgE7My z24jZ*3=qep85=XqG&W{9V{FXuAL=;cG-HOeG-HODX~qm^(u^7YLmg~9)0iP`rZL0J znZ^ufW*Rg6hkC;Jj4?yn8DoZ-XN(!noH1tj5A~Swe`AKU|Hce6{~I%$`EShdAL?0S zhBPpo$&kiyh9QmNKPaS((-@46(-_i>(->wNr!kx{PGk5F4HV@|j`7Ty3~4iGGMt$?li~l&nGB3)W-=I`naPlLW+ubTGcy^^ zoSDh+9~yzi|7S9!{h!G&^Z!hSGyi8Y{D(#=C}uz*GLzv982$&P9OE+##>QtD(u~hA z%rrj3aK`uy!+&Vx8>gLNNJ~4zFf;88!;&oHF@Kf^Hd{~3le|IaY|hbAOY3IW9oC`8UM{0Bn@ z label; PixmapSetActive *pixmaps = nullptr; bool active = false; + bool write_active = false; void setActive(bool b) { @@ -115,11 +122,23 @@ struct StateActive { refresh(); } + void setWriteActive(bool b) + { + if (!label || b == write_active) + return; + + write_active = b; + refresh(); + } + void refresh() { if (!label) return; - label->setPixmap(active ? pixmaps->active : pixmaps->normal); + if (active && write_active) + label->setPixmap(pixmaps->read_write_active); + else + label->setPixmap(write_active ? pixmaps->write_active : (active ? pixmaps->active : pixmaps->normal)); } }; struct StateEmpty { @@ -145,9 +164,10 @@ struct StateEmpty { }; struct StateEmptyActive { std::unique_ptr label; - PixmapSetEmptyActive *pixmaps = nullptr; - bool empty = false; - bool active = false; + PixmapSetEmptyActive *pixmaps = nullptr; + bool empty = false; + bool active = false; + bool write_active = false; void setActive(bool b) { @@ -157,6 +177,14 @@ struct StateEmptyActive { active = b; refresh(); } + void setWriteActive(bool b) + { + if (!label || b == write_active) + return; + + write_active = b; + refresh(); + } void setEmpty(bool b) { if (!label || b == empty) @@ -170,9 +198,15 @@ struct StateEmptyActive { if (!label) return; if (empty) { - label->setPixmap(active ? pixmaps->empty_active : pixmaps->empty); + if (active && write_active) + label->setPixmap(pixmaps->empty_read_write_active); + else + label->setPixmap(write_active ? pixmaps->empty_write_active : (active ? pixmaps->empty_active : pixmaps->empty)); } else { - label->setPixmap(active ? pixmaps->active : pixmaps->normal); + if (active && write_active) + label->setPixmap(pixmaps->read_write_active); + else + label->setPixmap(write_active ? pixmaps->write_active : (active ? pixmaps->active : pixmaps->normal)); } } }; @@ -191,6 +225,9 @@ PixmapSetActive::load(const QIcon &icon) { normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); + + write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteActive); + read_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, ReadWriteActive); } void @@ -203,10 +240,14 @@ PixmapSetDisabled::load(const QIcon &icon) void PixmapSetEmptyActive::load(const QIcon &icon) { - normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); - active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); - empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None); - empty_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Active); + normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); + write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteActive); + read_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, ReadWriteActive); + empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None); + empty_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Active); + empty_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, WriteActive); + empty_read_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, ReadWriteActive); } } @@ -217,10 +258,13 @@ struct MachineStatus::States { { pixmaps.cartridge.load(QIcon(":/settings/qt/icons/cartridge.ico")); pixmaps.cassette.load(QIcon(":/settings/qt/icons/cassette.ico")); - pixmaps.floppy_disabled.normal = QIcon(":/settings/qt/icons/floppy_disabled.ico").pixmap(pixmap_size); - pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal; - pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal; - pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.normal = QIcon(":/settings/qt/icons/floppy_disabled.ico").pixmap(pixmap_size); + pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.read_write_active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty_write_active = pixmaps.floppy_disabled.normal; + pixmaps.floppy_disabled.empty_read_write_active = pixmaps.floppy_disabled.normal; pixmaps.floppy_525.load(QIcon(":/settings/qt/icons/floppy_525.ico")); pixmaps.floppy_35.load(QIcon(":/settings/qt/icons/floppy_35.ico")); pixmaps.cdrom.load(QIcon(":/settings/qt/icons/cdrom.ico")); @@ -435,49 +479,79 @@ MachineStatus::refreshIcons() if (!update_icons) return; - for (size_t i = 0; i < FDD_NUM; ++i) + for (size_t i = 0; i < FDD_NUM; ++i) { d->fdd[i].setActive(machine_status.fdd[i].active); + d->fdd[i].setWriteActive(machine_status.fdd[i].write_active); + } for (size_t i = 0; i < CDROM_NUM; ++i) { d->cdrom[i].setActive(machine_status.cdrom[i].active); - if (machine_status.cdrom[i].active) + d->cdrom[i].setWriteActive(machine_status.cdrom[i].write_active); + if (machine_status.cdrom[i].active) { ui_sb_update_icon(SB_CDROM | i, 0); + } + if (machine_status.cdrom[i].write_active) { + ui_sb_update_icon_write(SB_CDROM | i, 0); + } } for (size_t i = 0; i < ZIP_NUM; i++) { d->zip[i].setActive(machine_status.zip[i].active); + d->zip[i].setWriteActive(machine_status.zip[i].write_active); if (machine_status.zip[i].active) ui_sb_update_icon(SB_ZIP | i, 0); + if (machine_status.zip[i].write_active) + ui_sb_update_icon_write(SB_ZIP | i, 0); } for (size_t i = 0; i < MO_NUM; i++) { d->mo[i].setActive(machine_status.mo[i].active); + d->mo[i].setWriteActive(machine_status.mo[i].write_active); if (machine_status.mo[i].active) ui_sb_update_icon(SB_MO | i, 0); + if (machine_status.mo[i].write_active) + ui_sb_update_icon_write(SB_MO | i, 0); } for (size_t i = 0; i < HDD_BUS_USB; i++) { d->hdds[i].setActive(machine_status.hdd[i].active); + d->hdds[i].setWriteActive(machine_status.hdd[i].write_active); if (machine_status.hdd[i].active) ui_sb_update_icon(SB_HDD | i, 0); + if (machine_status.hdd[i].write_active) + ui_sb_update_icon_write(SB_HDD | i, 0); } - for (size_t i = 0; i < NET_CARD_MAX; i++) + for (size_t i = 0; i < NET_CARD_MAX; i++) { d->net[i].setActive(machine_status.net[i].active); + d->net[i].setWriteActive(machine_status.net[i].write_active); + } } void MachineStatus::clearActivity() { - for (auto &fdd : d->fdd) + for (auto &fdd : d->fdd) { fdd.setActive(false); - for (auto &cdrom : d->cdrom) + fdd.setWriteActive(false); + } + for (auto &cdrom : d->cdrom) { cdrom.setActive(false); - for (auto &zip : d->zip) + cdrom.setWriteActive(false); + } + for (auto &zip : d->zip) { zip.setActive(false); - for (auto &mo : d->mo) + zip.setWriteActive(false); + } + for (auto &mo : d->mo) { mo.setActive(false); - for (auto &hdd : d->hdds) + mo.setWriteActive(false); + } + for (auto &hdd : d->hdds) { hdd.setActive(false); - for (auto &net : d->net) + hdd.setWriteActive(false); + } + for (auto &net : d->net) { net.setActive(false); + net.setWriteActive(false); + } } void @@ -562,6 +636,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->fdd[i].label = std::make_unique(); d->fdd[i].setEmpty(QString(floppyfns[i]).isEmpty()); d->fdd[i].setActive(false); + d->fdd[i].setWriteActive(false); d->fdd[i].refresh(); connect((ClickableLabel *) d->fdd[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->floppyMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->floppyMenus[i]->sizeHint().height())); @@ -578,6 +653,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->cdrom[i].label = std::make_unique(); d->cdrom[i].setEmpty(QString(cdrom[i].image_path).isEmpty()); d->cdrom[i].setActive(false); + d->cdrom[i].setWriteActive(false); d->cdrom[i].refresh(); connect((ClickableLabel *) d->cdrom[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->cdromMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->cdromMenus[i]->sizeHint().height())); @@ -594,6 +670,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->zip[i].label = std::make_unique(); d->zip[i].setEmpty(QString(zip_drives[i].image_path).isEmpty()); d->zip[i].setActive(false); + d->zip[i].setWriteActive(false); d->zip[i].refresh(); connect((ClickableLabel *) d->zip[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->zipMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->zipMenus[i]->sizeHint().height())); @@ -610,6 +687,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->mo[i].label = std::make_unique(); d->mo[i].setEmpty(QString(mo_drives[i].image_path).isEmpty()); d->mo[i].setActive(false); + d->mo[i].setWriteActive(false); d->mo[i].refresh(); connect((ClickableLabel *) d->mo[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { MediaMenu::ptr->moMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->moMenus[i]->sizeHint().height())); @@ -626,6 +704,7 @@ MachineStatus::refresh(QStatusBar *sbar) d->net[i].label = std::make_unique(); d->net[i].setEmpty(!network_is_connected(i)); d->net[i].setActive(false); + d->net[i].setWriteActive(false); d->net[i].refresh(); d->net[i].label->setToolTip(MediaMenu::ptr->netMenus[i]->title()); connect((ClickableLabel *) d->net[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) { @@ -638,6 +717,7 @@ MachineStatus::refresh(QStatusBar *sbar) if ((has_mfm || (hdc_name.left(5) == QStringLiteral("st506"))) && (c_mfm > 0)) { d->hdds[HDD_BUS_MFM].label = std::make_unique(); d->hdds[HDD_BUS_MFM].setActive(false); + d->hdds[HDD_BUS_MFM].setWriteActive(false); d->hdds[HDD_BUS_MFM].refresh(); d->hdds[HDD_BUS_MFM].label->setToolTip(tr("Hard disk (%1)").arg("MFM/RLL")); auto tooltip = d->hdds[HDD_BUS_MFM].label->toolTip(); @@ -653,6 +733,7 @@ MachineStatus::refresh(QStatusBar *sbar) if ((has_esdi || (hdc_name.left(4) == QStringLiteral("esdi"))) && (c_esdi > 0)) { d->hdds[HDD_BUS_ESDI].label = std::make_unique(); d->hdds[HDD_BUS_ESDI].setActive(false); + d->hdds[HDD_BUS_ESDI].setWriteActive(false); d->hdds[HDD_BUS_ESDI].refresh(); d->hdds[HDD_BUS_ESDI].label->setToolTip(tr("Hard disk (%1)").arg("ESDI")); auto tooltip = d->hdds[HDD_BUS_ESDI].label->toolTip(); @@ -668,6 +749,7 @@ MachineStatus::refresh(QStatusBar *sbar) if ((has_xta || (hdc_name.left(3) == QStringLiteral("xta"))) && (c_xta > 0)) { d->hdds[HDD_BUS_XTA].label = std::make_unique(); d->hdds[HDD_BUS_XTA].setActive(false); + d->hdds[HDD_BUS_XTA].setWriteActive(false); d->hdds[HDD_BUS_XTA].refresh(); d->hdds[HDD_BUS_XTA].label->setToolTip(tr("Hard disk (%1)").arg("XTA")); auto tooltip = d->hdds[HDD_BUS_XTA].label->toolTip(); @@ -686,6 +768,7 @@ MachineStatus::refresh(QStatusBar *sbar) if (c_ide > 0) { d->hdds[HDD_BUS_IDE].label = std::make_unique(); d->hdds[HDD_BUS_IDE].setActive(false); + d->hdds[HDD_BUS_IDE].setWriteActive(false); d->hdds[HDD_BUS_IDE].refresh(); d->hdds[HDD_BUS_IDE].label->setToolTip(tr("Hard disk (%1)").arg("IDE")); auto tooltip = d->hdds[HDD_BUS_IDE].label->toolTip(); @@ -701,6 +784,7 @@ MachineStatus::refresh(QStatusBar *sbar) if (c_atapi > 0) { d->hdds[HDD_BUS_ATAPI].label = std::make_unique(); d->hdds[HDD_BUS_ATAPI].setActive(false); + d->hdds[HDD_BUS_ATAPI].setWriteActive(false); d->hdds[HDD_BUS_ATAPI].refresh(); d->hdds[HDD_BUS_ATAPI].label->setToolTip(tr("Hard disk (%1)").arg("ATAPI")); auto tooltip = d->hdds[HDD_BUS_ATAPI].label->toolTip(); @@ -720,6 +804,7 @@ MachineStatus::refresh(QStatusBar *sbar) (c_scsi > 0)) { d->hdds[HDD_BUS_SCSI].label = std::make_unique(); d->hdds[HDD_BUS_SCSI].setActive(false); + d->hdds[HDD_BUS_SCSI].setWriteActive(false); d->hdds[HDD_BUS_SCSI].refresh(); d->hdds[HDD_BUS_SCSI].label->setToolTip(tr("Hard disk (%1)").arg("SCSI")); auto tooltip = d->hdds[HDD_BUS_SCSI].label->toolTip(); diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index b4e8a5486..5a6bda852 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -314,4 +314,41 @@ ui_sb_update_icon(int tag, int active) break; } } + +void +ui_sb_update_icon_write(int tag, int write) +{ + const auto temp = static_cast(tag); + const int category = static_cast(temp & 0xfffffff0); + const int item = tag & 0xf; + + switch (category) { + default: + case SB_CASSETTE: + case SB_CARTRIDGE: + break; + case SB_FLOPPY: + machine_status.fdd[item].write_active = write > 0 ? true : false; + break; + case SB_CDROM: + machine_status.cdrom[item].write_active = write > 0 ? true : false; + break; + case SB_ZIP: + machine_status.zip[item].write_active = write > 0 ? true : false; + break; + case SB_MO: + machine_status.mo[item].write_active = write > 0 ? true : false; + break; + case SB_HDD: + machine_status.hdd[item].write_active = write > 0 ? true : false; + break; + case SB_NETWORK: + machine_status.net[item].write_active = write > 0 ? true : false; + break; + case SB_SOUND: + case SB_TEXT: + break; + } +} + } diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index dc8db2c06..bc553ac61 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -28,6 +28,7 @@ qt/icons/zip.ico qt/icons/zip_disabled.ico qt/icons/active.ico + qt/icons/write_active.ico qt/icons/disabled.ico qt/icons/86Box-gray.ico qt/icons/86Box-green.ico diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 0a035a23d..8c09a30a1 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -614,6 +614,7 @@ scsi_disk_cmd_error(scsi_disk_t *dev) dev->callback = 50.0 * SCSI_TIME; scsi_disk_set_callback(dev); ui_sb_update_icon(SB_HDD | dev->drv->bus_type, 0); + ui_sb_update_icon_write(SB_HDD | dev->drv->bus_type, 0); scsi_disk_log(dev->log, "ERROR: %02X/%02X/%02X\n", scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); } @@ -1208,7 +1209,7 @@ scsi_disk_command(scsi_common_t *sc, const uint8_t *cdb) scsi_disk_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); - ui_sb_update_icon(SB_HDD | dev->drv->bus_type, dev->packet_status != PHASE_COMPLETE); + ui_sb_update_icon_write(SB_HDD | dev->drv->bus_type, dev->packet_status != PHASE_COMPLETE); } else { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log(dev->log, "All done - callback set\n"); @@ -1243,7 +1244,7 @@ scsi_disk_command(scsi_common_t *sc, const uint8_t *cdb) scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); - ui_sb_update_icon(SB_HDD | dev->drv->bus_type, + ui_sb_update_icon_write(SB_HDD | dev->drv->bus_type, dev->packet_status != PHASE_COMPLETE); } else { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index d575717a0..0bbeb2af5 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -146,7 +146,7 @@ if(FLUIDSYNTH) pkg_check_modules(FLUIDSYNTH REQUIRED IMPORTED_TARGET fluidsynth) target_link_libraries(86Box PkgConfig::FLUIDSYNTH) if(STATIC_BUILD) - target_link_libraries(86Box -static ${FLUIDSYNTH_STATIC_LIBRARIES} -fopenmp) + target_link_libraries(86Box -static ${FLUIDSYNTH_STATIC_LIBRARIES} -fopenmp -lgomp) if(WIN32) add_compile_definitions(FLUIDSYNTH_NOT_A_DLL) From 7901842c429a650278de5e0039cee30c01e9465b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 22 Apr 2025 22:08:52 +0600 Subject: [PATCH 0785/1190] Write indicator for floppy drives Write indicator is also properly contrasted on 5.25 floppy drives --- src/floppy/fdc.c | 27 +++++++++++++++++++++------ src/qt/icons/write_active.ico | Bin 6950 -> 6950 bytes src/sound/CMakeLists.txt | 2 +- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 1f49b192a..c32b1f442 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -615,7 +615,10 @@ fdc_io_command_phase1(fdc_t *fdc, int out) } } - ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + if (fdc->processed_cmd == 0x05 || fdc->processed_cmd == 0x09) + ui_sb_update_icon_write(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + else + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->stat = out ? 0x10 : 0x50; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) { fdc->stat |= 0x20; @@ -671,8 +674,10 @@ fdc_soft_reset(fdc_t *fdc) fdc->perp &= 0xfc; - for (int i = 0; i < FDD_NUM; i++) - ui_sb_update_icon(SB_FLOPPY | i, 0); + for (int i = 0; i < FDD_NUM; i++) { + ui_sb_update_icon(SB_FLOPPY | i, 0); + ui_sb_update_icon_write(SB_FLOPPY | i, 0); + } fdc_ctrl_reset(fdc); } @@ -706,6 +711,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; ui_sb_update_icon(SB_FLOPPY | 0, 0); + ui_sb_update_icon_write(SB_FLOPPY | 0, 0); fdc_ctrl_reset(fdc); } if (!fdd_get_flags(0)) @@ -1502,6 +1508,7 @@ fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) fdc->res[10] = fdc->params[4]; fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n", fdc->res[4], fdc->res[5], fdc->res[6], fdc->res[7], fdc->res[8], fdc->res[9], fdc->res[10]); ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); + ui_sb_update_icon_write(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; dma_set_drq(fdc->dma_ch, 0); } @@ -1545,8 +1552,10 @@ fdc_callback(void *priv) case -5: /*Reset in power down mode */ fdc->perp &= 0xfc; - for (uint8_t i = 0; i < FDD_NUM; i++) + for (uint8_t i = 0; i < FDD_NUM; i++) { ui_sb_update_icon(SB_FLOPPY | i, 0); + ui_sb_update_icon_write(SB_FLOPPY | i, 0); + } fdc_ctrl_reset(fdc); @@ -1694,7 +1703,10 @@ fdc_callback(void *priv) fdc->sector++; else if (fdc->params[5] == 0) fdc->sector++; - ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + if (fdc->interrupt == 0x05 || fdc->interrupt == 0x09) + ui_sb_update_icon_write(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); + else + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); switch (fdc->interrupt) { case 5: case 9: @@ -1885,6 +1897,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) break; } ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); + ui_sb_update_icon_write(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -2333,8 +2346,10 @@ fdc_reset(void *priv) current_drive = 0; - for (uint8_t i = 0; i < FDD_NUM; i++) + for (uint8_t i = 0; i < FDD_NUM; i++) { ui_sb_update_icon(SB_FLOPPY | i, 0); + ui_sb_update_icon_write(SB_FLOPPY | i, 0); + } fdc->power_down = 0; } diff --git a/src/qt/icons/write_active.ico b/src/qt/icons/write_active.ico index d1ebdb22498d6dbdfeae87c7d21969948c5cc868..9cbf6e74b659ca410b87ec4501534d187c76f82f 100644 GIT binary patch delta 1081 zcmZ2xw#;lo1LOaVjq)t@EHJ>tfCQKrVZto56*pob*@Df1tlt?yu4iSLIDupGJ7M<8 zvE0%KkAPf`;%Jb+kUT^i`Fcc%(Z&J-=GW8Qhxi?^`76(BCdU683;!~sMg{zvkkvhb0^Z4jQb#8%Nbyd-CKUhxV4ypk delta 933 zcmZ2xw#;lo!{!hC@0ce}keJ-YB2~`}156A^fQb<%%uHKxBW98<*c{0Eoe}B>g~?&u zN(euI9F5{$ke87BLL2#dL}1az0s`jO)7*#n9kBT;&ugZM1p?4G5lCQy08rqAF~og{ zh#{TN$jHcu&_7w8cjDy7BGQw8iS#h_^={zvkk!E*I9X8Y=wt;c-pSXb0sv_`bx!~Q diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 0bbeb2af5..d575717a0 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -146,7 +146,7 @@ if(FLUIDSYNTH) pkg_check_modules(FLUIDSYNTH REQUIRED IMPORTED_TARGET fluidsynth) target_link_libraries(86Box PkgConfig::FLUIDSYNTH) if(STATIC_BUILD) - target_link_libraries(86Box -static ${FLUIDSYNTH_STATIC_LIBRARIES} -fopenmp -lgomp) + target_link_libraries(86Box -static ${FLUIDSYNTH_STATIC_LIBRARIES} -fopenmp) if(WIN32) add_compile_definitions(FLUIDSYNTH_NOT_A_DLL) From c23f33b65e9cf64239c2bd3ddb3032e371ba01fd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 22 Apr 2025 22:12:15 +0600 Subject: [PATCH 0786/1190] Fix SDL compiles --- src/unix/unix.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/unix/unix.c b/src/unix/unix.c index 8e44cc26a..2e92a90d3 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -471,6 +471,12 @@ ui_sb_update_icon(UNUSED(int tag), UNUSED(int active)) /* No-op. */ } +void +ui_sb_update_icon_write(UNUSED(int tag), UNUSED(int active)) +{ + /* No-op. */ +} + void plat_delay_ms(uint32_t count) { From e1cdf1b288aeffd759112e7bdd21a8c7206b9a27 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 22 Apr 2025 22:31:58 +0600 Subject: [PATCH 0787/1190] 20x20 icon made consistent with other sizes --- src/qt/icons/write_active.ico | Bin 6950 -> 6950 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/icons/write_active.ico b/src/qt/icons/write_active.ico index 9cbf6e74b659ca410b87ec4501534d187c76f82f..babf8c86c0f94585cf9e00cd60d17c682fcf7c34 100644 GIT binary patch delta 155 xcmZ2xw#;lpo@6~QI|Bsp^1%Up#MnWAnVp??a)6}VWNE40lNF?RCts5a005JK4IBUf delta 171 ycmZ2xw#;lpo@D(Kb_NLG<%0wIh_Qo!I6FJC#ZRDsce0?=(a8!@ypyj<1poj5RvMH5 From 592e5c6a79e6f700e7e9de6036450d28c2955871 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 22 Apr 2025 21:10:06 +0200 Subject: [PATCH 0788/1190] Cirrus Logic: Implement proper VLB addressing, closes #5337. --- src/video/vid_cl54xx.c | 95 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 21d9b21d8..b60f9bdca 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -260,6 +260,8 @@ typedef struct gd54xx_t { uint8_t pos_regs[8]; + uint32_t vlb_lfb_base; + uint32_t lfb_base; uint32_t vgablt_base; @@ -1750,7 +1752,8 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) } else mem_mapping_disable(&gd54xx->mmio_mapping); } else { - if ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) || (!gd54xx->pci && !gd54xx->vlb)) { + if ((svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) || + (!gd54xx->pci && !gd54xx->vlb)) { if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { base = (svga->seqregs[0x07] & 0xf0) << 16; size = 1 * 1024 * 1024; @@ -1770,7 +1773,10 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) else size = 4 * 1024 * 1024; } else { /*VLB/ISA/MCA*/ - base = 128 * 1024 * 1024; + if (gd54xx->vlb_lfb_base != 0x00000000) + base = gd54xx->vlb_lfb_base; + else + base = 128 * 1024 * 1024; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) size = 16 * 1024 * 1024; else @@ -4224,6 +4230,12 @@ gd54xx_init(const device_t *info) gd54xx->id = id; + if (gd54xx->vlb && ((gd54xx->id == CIRRUS_ID_CLGD5430) || + (gd54xx->id == CIRRUS_ID_CLGD5434) || + (gd54xx->id == CIRRUS_ID_CLGD5434_4) || + (gd54xx->id == CIRRUS_ID_CLGD5440))) + gd54xx->vlb_lfb_base = device_get_config_int("lfb_base") << 20; + switch (id) { case CIRRUS_ID_CLGD5401: romfn = BIOS_GD5401_PATH; @@ -4777,6 +4789,41 @@ static const device_config_t gd5429_config[] = { { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t gd5430_vlb_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "lfb_base", + .description = "Linear framebuffer base", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "32 MB", .value = 32 }, + { .description = "64 MB", .value = 64 }, + { .description = "2048 MB", .value = 2048 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + static const device_config_t gd5440_onboard_config[] = { { .name = "memory", @@ -4816,6 +4863,42 @@ static const device_config_t gd5434_config[] = { { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t gd5434_vlb_config[] = { + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 4, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "4 MB", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "lfb_base", + .description = "Linear framebuffer base", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "32 MB", .value = 32 }, + { .description = "64 MB", .value = 64 }, + { .description = "2048 MB", .value = 2048 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + static const device_config_t gd5434_onboard_config[] = { { .name = "memory", @@ -5150,7 +5233,7 @@ const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device = { .available = gd5430_diamond_a8_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5429_config + .config = gd5430_vlb_config }; const device_t gd5430_vlb_device = { @@ -5164,7 +5247,7 @@ const device_t gd5430_vlb_device = { .available = gd5430_orchid_vlb_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5429_config + .config = gd5430_vlb_config }; const device_t gd5430_onboard_vlb_device = { @@ -5178,7 +5261,7 @@ const device_t gd5430_onboard_vlb_device = { .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5429_config + .config = gd5430_vlb_config }; const device_t gd5430_pci_device = { @@ -5263,7 +5346,7 @@ const device_t gd5434_vlb_device = { .available = gd5430_orchid_vlb_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5434_config + .config = gd5434_vlb_config }; const device_t gd5434_pci_device = { From 14ef3b75ac810a9b65500ac61b6c108576c01033 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 22 Apr 2025 21:15:05 +0200 Subject: [PATCH 0789/1190] Vast fixes to the Mach8/32/8514/A compatible side (April 22nd 2025) 1. As tiring as it seems, XOR properly the passthrough bits for mode changes. Fixes everything tested as of now (Mach8/32). 2. Implemented separate destination and source GE pitch and offsets. Fixes Windows 3.1 mach8/32 drivers using devicebitmap enabled (or dmp=1). 3. Properly fixed high and true color patterns so that the aforementioned patterns are drawn correctly in various stuff. 4. Implemented in the best possible way the CRT offset (currently in on conjunction with the GE offset). 5. On ScanToX with bpp set to 24 and dpconfig 0x6211, optmize the SRC/CUR X-Y coordinates at the end of the blit. 6. For mode changes, don't call the mode change recalctimings function if we aren't in the appropriate bits of the respective ports. 7. Separate 8514/A compatible and Extended foreground/background selection implemented, fixes Windows 3.x ATI Ultra drivers from 1992 without hacks. 8. Clear the busy flags when needed without stalling the entire guests (but not the emulator itself) (Mach8/32). 9. The MMIO regs should be enabled only when the VGA aperture has reached a graphics mode (0xA000). This fixes NT 3.x mach drivers in true color mode and making Win3.1 drivers working without a hitch at the same time. 10. Actually implement the hardware 4bpp cursor properly on Mach32. 11. Cosmetic cleanups. --- src/include/86box/vid_8514a.h | 17 +- src/include/86box/vid_ati_mach8.h | 14 +- src/include/86box/vid_svga.h | 4 +- src/video/vid_8514a.c | 236 ++--- src/video/vid_ati_mach8.c | 1344 +++++++++++++++-------------- src/video/vid_svga.c | 6 +- 6 files changed, 803 insertions(+), 818 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index 7694a028a..696b640bc 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -90,6 +90,7 @@ typedef struct ibm8514_t { uint16_t subsys_cntl; uint16_t setup_md; uint16_t advfunc_cntl; + uint16_t advfunc_cntl_old; uint16_t cur_y; uint16_t cur_x; int16_t destx; @@ -107,8 +108,10 @@ typedef struct ibm8514_t { uint16_t wrt_mask; uint16_t rd_mask; uint16_t color_cmp; - uint16_t bkgd_mix; - uint16_t frgd_mix; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint8_t bkgd_sel; + uint8_t frgd_sel; uint16_t multifunc_cntl; uint16_t multifunc[16]; uint16_t clip_right; @@ -159,6 +162,14 @@ typedef struct ibm8514_t { int ydir; int linedraw; uint32_t ge_offset; + uint32_t src_ge_offset; + uint32_t dst_ge_offset; + uint16_t src_pitch; + uint16_t dst_pitch; + int64_t cur_x_24bpp; + int64_t cur_y_24bpp; + int64_t dest_x_24bpp; + int64_t dest_y_24bpp; } accel; uint16_t test; @@ -240,6 +251,8 @@ typedef struct ibm8514_t { uint32_t vram_amount; int vram_512k_8514; int vendor_mode; + int _8514on; + int _8514crt; PALETTE _8514pal; latch8514_t latch; diff --git a/src/include/86box/vid_ati_mach8.h b/src/include/86box/vid_ati_mach8.h index 8ed1dbc74..d5e80d0c8 100644 --- a/src/include/86box/vid_ati_mach8.h +++ b/src/include/86box/vid_ati_mach8.h @@ -77,8 +77,9 @@ typedef struct mach_t { uint8_t overscan_g_col_24; uint8_t overscan_r_col_24; uint16_t fifo_test_data[17]; - int port_len; - int crt_resolution; + uint8_t old_on1; + uint8_t old_on2; + int crt_resolution; struct { uint8_t line_idx; @@ -99,12 +100,13 @@ typedef struct mach_t { uint16_t src_x_end; uint16_t src_x_start; uint16_t src_x; - uint16_t r_src_x; uint16_t src_y; int16_t bres_count; uint16_t clock_sel; uint16_t crt_pitch; uint16_t ge_pitch; + uint16_t src_pitch; + uint16_t dst_pitch; uint16_t dest_cmp_fn; uint16_t dp_config; uint16_t ext_ge_config; @@ -158,14 +160,18 @@ typedef struct mach_t { int src_stepx; uint8_t mono_pattern_normal[16]; uint8_t color_pattern[32]; + uint16_t color_pattern_hicol[8]; int mono_pattern[8][8]; - uint32_t ge_offset; + uint32_t src_ge_offset; + uint32_t dst_ge_offset; uint32_t crt_offset; uint32_t patt_len_reg; int poly_fill; uint16_t dst_clr_cmp_mask; int clip_overrun; int color_pattern_idx; + int64_t src_x_scan; + int64_t src_y_scan; } accel; atomic_int force_busy; diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 068774eac..932aa718a 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -171,11 +171,11 @@ typedef struct svga_t { latch_t latch; pc_timer_t timer; - pc_timer_t timer8514; + pc_timer_t timer_8514; pc_timer_t timer_xga; double clock; - double clock8514; + double clock_8514; double clock_xga; double multiplier; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 8925f01da..533ec8fa9 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -124,7 +124,7 @@ CLAMP(int16_t in, int16_t min, int16_t max) #define MIX(mixmode, dest_dat, src_dat) \ { \ - switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + switch ((mixmode) ? dev->accel.frgd_mix : dev->accel.bkgd_mix) { \ case 0x00: \ dest_dat = ~dest_dat; \ break; \ @@ -268,8 +268,8 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in uint32_t monoxfer = 0xffffffff; int pixcnt = 0; int pixcntl = (dev->accel.multifunc[0x0a] >> 6) & 3; - int frgd_mix = (dev->accel.frgd_mix >> 5) & 3; - int bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; + int frgd_mix = dev->accel.frgd_sel; + int bkgd_mix = dev->accel.bkgd_sel; int cmd = dev->accel.cmd >> 13; if (!dev->accel.cmd_back) { @@ -351,13 +351,12 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x6e8: /*In preparation to switch from VGA to 8514/A mode*/ WRITE8(port, dev->hdisped, val); - dev->hdisp = (dev->hdisped + 1) << 3; ibm8514_log("[%04X:%08X]: IBM 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); svga_recalctimings(svga); break; case 0x6e9: - WRITE8(port, dev->htotal, val); + WRITE8(port - 1, dev->htotal, val); ibm8514_log("IBM 8514/A compatible: (0x%04x): htotal=0x%02x.\n", port, val); svga_recalctimings(svga); break; @@ -379,10 +378,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (len == 2) { dev->v_total_reg = val; dev->v_total_reg &= 0x1fff; - dev->v_total = dev->v_total_reg + 1; - if (dev->interlace) - dev->v_total >>= 1; - ibm8514_log("IBM 8514/A compatible: (0x%04x): vtotal=0x%02x.\n", port, val); svga_recalctimings(svga); } else { @@ -392,12 +387,8 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x12e9: /*In preparation to switch from VGA to 8514/A mode*/ if (len == 1) { - WRITE8(port, dev->v_total_reg, val); + WRITE8(port, dev->v_total_reg, val >> 8); dev->v_total_reg &= 0x1fff; - dev->v_total = dev->v_total_reg + 1; - if (dev->interlace) - dev->v_total >>= 1; - ibm8514_log("IBM 8514/A compatible: (0x%04x): vtotal=0x%02x.\n", port, val); svga_recalctimings(svga); } @@ -408,7 +399,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (len == 2) { dev->v_disp = val; dev->v_disp &= 0x1fff; - dev->vdisp = (dev->v_disp + 1) >> 1; ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp); ibm8514_log("IBM 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); svga_recalctimings(svga); @@ -419,9 +409,8 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x16e9: /*In preparation to switch from VGA to 8514/A mode*/ if (len == 1) { - WRITE8(port, dev->v_disp, val); + WRITE8(port, dev->v_disp, val >> 8); dev->v_disp &= 0x1fff; - dev->vdisp = (dev->v_disp + 1) >> 1; ibm8514_log("IBM 8514/A: V_DISP write 16E8 = %d\n", dev->v_disp); ibm8514_log("IBM 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); svga_recalctimings(svga); @@ -433,10 +422,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (len == 2) { dev->v_sync_start = val; dev->v_sync_start &= 0x1fff; - dev->v_syncstart = dev->v_sync_start + 1; - if (dev->interlace) - dev->v_syncstart >>= 1; - ibm8514_log("IBM 8514/A compatible: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); ibm8514_log("IBM 8514/A compatible: (0x%04x): vsyncstart=0x%02x.\n", port, val); svga_recalctimings(svga); @@ -447,7 +432,7 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) case 0x1ae9: /*In preparation to switch from VGA to 8514/A mode*/ if (len == 1) { - WRITE8(port, dev->v_sync_start, val); + WRITE8(port, dev->v_sync_start, val >> 8); dev->v_sync_start &= 0x1fff; dev->v_syncstart = dev->v_sync_start + 1; if (dev->interlace) @@ -639,11 +624,15 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0xb6e8: - dev->accel.bkgd_mix = val & 0xff; + dev->accel.bkgd_mix = val & 0x1f; + dev->accel.bkgd_sel = (val >> 5) & 3; + ibm8514_log("Background Mix reg=%02x.\n", val); break; case 0xbae8: - dev->accel.frgd_mix = val & 0xff; + dev->accel.frgd_mix = val & 0x1f; + dev->accel.frgd_sel = (val >> 5) & 3; + ibm8514_log("Foreground Mix reg=%02x.\n", val); break; case 0xbee8: @@ -667,7 +656,6 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if ((dev->accel.multifunc_cntl >> 12) == 4) dev->accel.clip_right = dev->accel.multifunc[4] & 0x7ff; - } break; @@ -821,8 +809,22 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) if (dev->fifo_idx > 0) dev->fifo_idx--; - if (dev->force_busy) + if (dev->force_busy) { temp |= 0x0200; /*Hardware busy*/ + switch (dev->accel.cmd >> 13) { + case 2: + case 3: + case 4: + case 6: + if (dev->accel.sy < 0) + dev->force_busy = 0; + break; + default: + if (!dev->accel.sy) + dev->force_busy = 0; + break; + } + } if (dev->data_available) { temp |= 0x0100; /*Read Data available*/ @@ -1066,8 +1068,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat rd_mask_polygon &= 0xff; } - frgd_mix = (dev->accel.frgd_mix >> 5) & 3; - bkgd_mix = (dev->accel.bkgd_mix >> 5) & 3; + frgd_mix = dev->accel.frgd_sel; + bkgd_mix = dev->accel.bkgd_sel; if (cpu_input) { if ((dev->accel.cmd & 0x02) || (pixcntl == 2)) { @@ -1821,12 +1823,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); if (cmd == 4) dev->accel.cmd |= 0x02; @@ -2030,12 +2027,7 @@ skip_vector_rect_write: break; } - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; dev->accel.x_count = 0; @@ -2194,12 +2186,7 @@ skip_nibble_rect_write: else dev->accel.cy--; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; dev->accel.x_count = 0; @@ -2285,12 +2272,7 @@ skip_nibble_rect_write: else dev->accel.cy--; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; @@ -2367,12 +2349,7 @@ skip_nibble_rect_write: else dev->accel.cy--; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; @@ -2482,12 +2459,7 @@ skip_nibble_rect_write: else dev->accel.cy--; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; @@ -2512,8 +2484,6 @@ skip_nibble_rect_write: switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; - if (!bkgd_mix && (dev->accel.cmd & 0x40) && ((dev->accel.frgd_mix & 0x1f) == 7) && ((dev->accel.bkgd_mix & 0x1f) == 3) && !dev->bpp && (bkgd_color == 0x00)) /*For some reason, the September 1992 Mach8/32 drivers for Win3.x don't set the background colors properly.*/ - src_dat = frgd_color; break; case 1: src_dat = frgd_color; @@ -2570,12 +2540,7 @@ skip_nibble_rect_write: else dev->accel.cy--; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - else if (dev->bpp) - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; if (dev->accel.sy < 0) { @@ -2870,16 +2835,8 @@ skip_nibble_rect_write: dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; dev->accel.sy = dev->accel.multifunc[0] & 0x7ff; - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } else if (dev->bpp) { - dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - } else { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); dev->accel.fill_state = 0; if (ibm8514_cpu_src(svga)) { @@ -3051,16 +3008,8 @@ skip_nibble_bitblt_write: dev->accel.cy--; } - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } else if (dev->bpp) { - dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - } else { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); dev->accel.sy--; dev->accel.x_count = 0; @@ -3156,16 +3105,8 @@ skip_nibble_bitblt_write: dev->accel.cy--; } - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } else if (dev->bpp) { - dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - } else { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); dev->accel.sy--; @@ -3252,16 +3193,9 @@ skip_nibble_bitblt_write: dev->accel.cy--; } - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } else if (dev->bpp) { - dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - } else { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); + dev->accel.sy--; if (dev->accel.sy < 0) { @@ -3282,29 +3216,14 @@ skip_nibble_bitblt_write: cx = (int64_t) dev->accel.cx; dx = (int64_t) dev->accel.dx; + dev->accel.src = dev->accel.src_ge_offset + (dev->accel.cy * dev->accel.src_pitch); + dev->accel.dest = dev->accel.dst_ge_offset + (dev->accel.dy * dev->accel.dst_pitch); + while (1) { if ((dx >= (((int64_t)clip_l) * 3)) && (dx <= (((uint64_t)clip_r) * 3)) && (dev->accel.dy >= (clip_t << 1)) && (dev->accel.dy <= (clip_b << 1))) { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = 0; - break; - case 3: - READ(dev->accel.src + cx, src_dat); - break; - - default: - break; - } - READ(dev->accel.src + cx, src_dat); READ(dev->accel.dest + dx, dest_dat); old_dest_dat = dest_dat; @@ -3411,16 +3330,9 @@ skip_nibble_bitblt_write: dev->accel.cy--; } - if ((dev->accel_bpp == 24) || (dev->accel_bpp <= 8)) { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } else if (dev->bpp) { - dev->accel.src = (dev->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - } else { - dev->accel.src = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); - dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.src = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); + dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); + dev->accel.sy--; if (dev->accel.sy < 0) { @@ -3804,7 +3716,7 @@ ibm8514_poll(void *priv) if ((svga->cgastat & 8) && ((dev->displine & 0x0f) == (svga->crtc[0x11] & 0x0f)) && svga->vslines) svga->cgastat &= ~8; svga->vslines++; - if (dev->displine > 1500) + if (dev->displine > 2000) dev->displine = 0; } else { timer_advance_u64(&svga->timer, dev->dispontime); @@ -3871,9 +3783,9 @@ ibm8514_poll(void *priv) svga->vslines = 0; if (dev->interlace && dev->oddeven) - dev->ma = dev->maback = dev->ma_latch + (dev->rowoffset << 1); + dev->ma = dev->maback = (dev->rowoffset << 1); else - dev->ma = dev->maback = dev->ma_latch; + dev->ma = dev->maback = 0; dev->ma = (dev->ma << 2); dev->maback = (dev->maback << 2); @@ -3904,26 +3816,43 @@ ibm8514_recalctimings(svga_t *svga) ati8514_recalctimings(svga); } else { if (dev->on) { + dev->hdisp = (dev->hdisped + 1) << 3; dev->h_total = dev->htotal + 1; + + if (dev->h_total == 1) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ + dev->h_total = 0x9e; + + dev->vdisp = (dev->v_disp + 1) >> 1; + if ((dev->vdisp == 478) || (dev->vdisp == 766)) + dev->vdisp += 2; + + dev->v_total = dev->v_total_reg + 1; + if (dev->interlace) + dev->v_total >>= 1; + + dev->v_syncstart = dev->v_sync_start + 1; + if (dev->interlace) + dev->v_syncstart >>= 1; + dev->rowcount = !!(dev->disp_cntl & 0x08); - if (dev->accel.advfunc_cntl & 0x01) { + if ((dev->hdisp != 640) && (dev->hdisp != 1024)) { if (dev->accel.advfunc_cntl & 0x04) { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; + dev->hdisp = 1024; + dev->vdisp = 768; } else { - dev->h_disp = 640; - dev->dispend = 480; + dev->hdisp = 640; + dev->vdisp = 480; } - } else { - dev->h_disp = dev->hdisp; - dev->dispend = dev->vdisp; } + dev->h_disp = dev->hdisp; + dev->dispend = dev->vdisp; + if (dev->accel.advfunc_cntl & 0x04) - svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; else - svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0; + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0; if ((dev->dispend == 478) || (dev->dispend == 766)) dev->dispend += 2; @@ -4026,6 +3955,7 @@ ibm8514_init(const device_t *info) dev->map8 = dev->pallook; dev->local = 0; dev->accel_bpp = 8; + dev->on = 0; dev->type = info->flags; dev->bpp = 0; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 9f92ebde1..3bcde5b0c 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -15,6 +15,7 @@ * * Copyright 2022-2024 TheCollector1995. */ +#include #include #include #include @@ -142,10 +143,10 @@ mach_log(const char *fmt, ...) } \ } else if ((mach->accel.cmd_type == 3) || (mach->accel.cmd_type == 4)) { \ if (dev->bpp) \ - temp = vram_w[((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ + temp = vram_w[(mach->accel.dst_ge_offset + ((dev->accel.cy) * (mach->accel.dst_pitch)) + (cx) + (n)) & (dev->vram_mask >> 1)]; \ else { \ - temp = dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n)) & dev->vram_mask]; \ - temp |= (dev->vram[((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ + temp = dev->vram[(mach->accel.dst_ge_offset + ((dev->accel.cy) * (mach->accel.dst_pitch)) + (cx) + (n)) & dev->vram_mask]; \ + temp |= (dev->vram[(mach->accel.dst_ge_offset + ((dev->accel.cy) * (mach->accel.dst_pitch)) + (cx) + (n + 1)) & dev->vram_mask] << 8); \ } \ } @@ -160,7 +161,7 @@ mach_log(const char *fmt, ...) #define MIX(mixmode, dest_dat, src_dat) \ { \ - switch ((mixmode) ? (dev->accel.frgd_mix & 0x1f) : (dev->accel.bkgd_mix & 0x1f)) { \ + switch ((mixmode) ? dev->accel.frgd_mix : dev->accel.bkgd_mix) { \ case 0x00: \ dest_dat = ~dest_dat; \ break; \ @@ -334,7 +335,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } - mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y); + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d, cl = %d, cr = %d, ct = %d, cb = %d, accel_bpp = %d, pitch = %d, hicolbpp = %d, pattlen = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y, clip_l, clip_r, clip_t, clip_b, dev->accel_bpp, dev->pitch, dev->bpp, mach->accel.patt_len); switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -368,6 +369,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + mach_log("Extended Bresenham Write pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -375,6 +377,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + mach_log("Extended Bresenham Read pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -423,11 +426,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 3: - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, mix); mix = (mix & rd_mask) == rd_mask; break; @@ -439,6 +438,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= INT_GE_BSY; switch (mix ? frgd_sel : bkgd_sel) { case 0: src_dat = bkgd_color; @@ -453,19 +453,16 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach_pixel_read(mach)) src_dat = cpu_dat; else { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); - } else { - READ((mach->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: @@ -473,22 +470,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); poly_src = ((poly_src & rd_mask) == rd_mask); if (poly_src) mach->accel.poly_fill = !mach->accel.poly_fill; } if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); switch (compare_mode) { case 1: @@ -528,18 +517,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config & 0x10) { if (mach->accel.linedraw_opt & 0x04) { if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } else { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -570,10 +551,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -658,11 +636,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 3: - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), mix); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, mix); mix = (mix & rd_mask) == rd_mask; break; @@ -689,20 +663,17 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach_pixel_read(mach)) src_dat = cpu_dat; else { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), src_dat); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); if (mono_src == 3) { src_dat = (src_dat & rd_mask) == rd_mask; } } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: @@ -710,22 +681,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); poly_src = ((poly_src & rd_mask) == rd_mask); if (poly_src) mach->accel.poly_fill = !mach->accel.poly_fill; } if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); switch (compare_mode) { case 1: @@ -765,18 +728,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config & 0x10) { if (mach->accel.linedraw_opt & 0x04) { if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } else { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.dy) * (dev->pitch)) + (dev->accel.dx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -807,10 +762,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -869,7 +821,6 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dest_x_start >= 0x600) mach->accel.dx_start |= ~0x5ff; - mach_log("DXStart=%d, CURX=%d.\n", mach->accel.dx_start, dev->accel.dx); mach->accel.dx_end = mach->accel.dest_x_end; if (mach->accel.dest_x_end >= 0x600) mach->accel.dx_end |= ~0x5ff; @@ -916,10 +867,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } dev->accel.sy = 0; - if (dev->bpp) - dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - else - dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); mach->accel.src_stepx = 0; /*Source Width*/ @@ -961,15 +909,12 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.dp_config, mach->accel.src_width & 1); } mach->accel.sx = 0; - if (mach->accel.patt_data_idx < 16) + if (mach->accel.patt_data_idx < 0x10) mach->accel.color_pattern_idx = mach->accel.patt_idx; else mach->accel.color_pattern_idx = 0; - if (dev->bpp) - dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); if (mono_src == 1) { if (mach->accel.mono_pattern_enable || mach->accel.block_write_mono_pattern_enable) { @@ -982,7 +927,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mono_dat1 |= (mach->accel.mono_pattern_normal[6] << 16); mono_dat1 |= (mach->accel.mono_pattern_normal[7] << 24); - mach_log("MonoData0=%x, MonoData1=%x.\n", mono_dat0, mono_dat1); + mach_log("MonoData0=%x, MonoData1=%x, enable mono pattern=%x, dpconfig=%04x.\n", mono_dat0, mono_dat1, mach->accel.mono_pattern_enable, mach->accel.dp_config); for (uint8_t y = 0; y < 8; y++) { for (uint8_t x = 0; x < 8; x++) { uint32_t temp = (y & 4) ? mono_dat1 : mono_dat0; @@ -994,6 +939,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + mach_log("Non-Conforming BitBLT Write pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -1001,6 +947,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + mach_log("Non-Conforming BitBLT Read pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -1140,9 +1087,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: @@ -1151,7 +1099,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { if (dev->accel.sy & 1) { - READ(dev->accel.dest + dev->accel.dx - dev->pitch, dest_dat); + READ(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); } else { READ(dev->accel.dest + dev->accel.dx, dest_dat); } @@ -1197,7 +1145,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config & 0x10) { if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { if (dev->accel.sy & 1) { - WRITE(dev->accel.dest + dev->accel.dx - dev->pitch, dest_dat); + WRITE(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); } else { WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } @@ -1213,11 +1161,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (mach->accel.dp_config == 0x2071 || (mach->accel.dp_config == 0x2011)) - mach_log("FontBlit: SX=%d, C(%d,%d), SRCWidth=%d, frgdmix=%d, bkgdmix=%d, rdmask=%04x, D(%d,%d), geoffset=%x, addr=%08x,.\n", + if (mach->accel.dp_config == 0x2071) + mach_log("FontBlit: SX=%d, C(%d,%d), SRCWidth=%d, frgdmix=%d, bkgdmix=%d, rdmask=%04x, D(%d,%d), geoffset=%x, addr=%08x, 8bppdata=%02x, 16bppdata=%04x, vgabase=%06x.\n", mach->accel.sx, dev->accel.cx, dev->accel.cy, mach->accel.src_width, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, rd_mask, dev->accel.dx, dev->accel.dy, dev->accel.ge_offset, - (dev->accel.src + dev->accel.cx) & dev->vram_mask); + (dev->accel.src + dev->accel.cx) & dev->vram_mask, dev->vram[(dev->accel.src + dev->accel.cx) & dev->vram_mask], vram_w[(dev->accel.src + dev->accel.cx) & (dev->vram_mask >> 1)], svga->mapping.base); if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) { dev->accel.cx += mach->accel.src_stepx; @@ -1230,17 +1178,11 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.cx -= mach->accel.src_width; dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); - if (dev->bpp) - dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * dev->pitch); - else - dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); } } - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if ((mono_src == 1) && !mach->accel.mono_pattern_enable && !mach->accel.block_write_mono_pattern_enable && (frgd_sel == 5) && (dev->accel_bpp == 24)) { if (mach->accel.color_pattern_idx > 2) @@ -1263,14 +1205,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.sy++; mach->accel.poly_fill = 0; - if (mach->accel.dp_config & 0x02) - dev->accel.dest = (dev->accel.dy * dev->pitch); - else { - if (dev->bpp) - dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - else - dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); - } + dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); if (dev->accel.sy >= mach->accel.height) { if (cpu_input) { @@ -1321,7 +1256,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { - mach_log("Write PIXTRANS.\n"); + mach_log("Direct Linedraw Write pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -1329,7 +1264,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { - mach_log("Read PIXTRANS.\n"); + mach_log("Direct Linedraw Read pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -1384,20 +1319,17 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 src_dat = 0; break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); switch (compare_mode) { case 1: @@ -1434,11 +1366,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1459,10 +1387,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -1508,11 +1433,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), poly_src); - } + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); if (poly_src) mach->accel.poly_fill ^= 1; } @@ -1535,24 +1456,17 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - READ(((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); switch (compare_mode) { case 1: @@ -1594,26 +1508,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { if (mach->accel.linedraw_opt & 0x04) { if (dev->accel.sx < mach->accel.width) { - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - WRITE(((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } else { - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - WRITE(((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -1635,10 +1533,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -1690,20 +1585,18 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + switch (compare_mode) { case 1: compare = 1; @@ -1740,11 +1633,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1765,10 +1654,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -1831,24 +1717,17 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - READ((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - READ((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - READ(((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); switch (compare_mode) { case 1: @@ -1888,26 +1767,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { if (mach->accel.linedraw_opt & 0x04) { if (dev->accel.sx < mach->accel.width) { - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } else { - if (mach->accel.linedraw_opt & 0x02) { - if (dev->bpp) { - WRITE((mach->accel.ge_offset << 1) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } else { - WRITE((mach->accel.ge_offset << 2) + ((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } - } else { - WRITE(((dev->accel.cy) * (dev->pitch)) + (dev->accel.cx), dest_dat); - } + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -1929,10 +1792,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else cpu_dat >>= 8; - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; if (mach->accel.color_pattern_idx > mach->accel.patt_len) mach->accel.color_pattern_idx = 0; @@ -2010,11 +1870,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.sy = 0; } - if (dev->bpp) - dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * (dev->pitch)); - else - dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * (dev->pitch)); - + dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); mach->accel.src_stepx = 0; /*Source Width*/ @@ -2047,33 +1903,14 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } mach->accel.sx = 0; - if (dev->bpp) - dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); - else - dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); - if ((dev->accel_bpp >= 24) && (frgd_sel == 5)) { - if (mach->accel.patt_len == 0x17) - mach->accel.color_pattern_idx = 0; - - dev->accel.x1 = dev->accel.dx + mach->accel.width; - if (dev->accel.x1 == dev->pitch) - dev->accel.x2 = mach->accel.width & 1; - else if ((dev->accel.x1 == mach->accel.width) && (dev->accel.dy & 1) && !dev->accel.y1 && dev->accel.x2) { - if (mach->accel.patt_len == 0x17) - mach->accel.color_pattern_idx = 3; - - dev->accel.x3 = 1; - } else - dev->accel.x3 = 0; - } - dev->accel.y1 = 0; - - mach_log("ScanToX: Parameters=%04x: xbit=%d, ybit=%d, widthbit=%d, DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, srcwidth=%d, height=%d, frmix=%02x.\n", - mach->accel.dp_config, dev->accel.dx & 1, dev->accel.dy & 1, mach->accel.width & 1, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.src_width, dev->accel.sy, dev->accel.frgd_mix & 0x1f); + mach_log("ScanToX: Parameters=%04x: xbit=%d, ybit=%d, widthbit=%d, DX=%d, DY=%d, CX=%d, CY=%d, dstwidth=%d, srcwidth=%d, height=%d, frmix=%02x, colpatidx=%d, srcpitch=%d, dstpitch=%d, scantox=%d.\n", + mach->accel.dp_config, dev->accel.dx & 1, dev->accel.dy & 1, mach->accel.width & 1, dev->accel.dx, dev->accel.dy, dev->accel.cx, dev->accel.cy, mach->accel.width, mach->accel.src_width, dev->accel.sy, dev->accel.frgd_mix & 0x1f, mach->accel.color_pattern_idx, mach->accel.src_pitch, mach->accel.dst_pitch, mach->accel.scan_to_x); if (!dev->accel.cmd_back) { if (mach_pixel_write(mach)) { + mach_log("Scan To X Write pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -2081,6 +1918,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->data_available2 = 0; return; } else if (mach_pixel_read(mach)) { + mach_log("Scan To X Read pixtrans.\n"); dev->force_busy = 1; dev->force_busy2 = 1; mach->force_busy = 1; @@ -2091,6 +1929,110 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } + if ((dev->accel_bpp == 24) && (mach->accel.dp_config == 0x6211)) { + int64_t cx; + int64_t cy; + + cx = mach->accel.src_x_scan; + cy = mach->accel.src_y_scan; + + if (mach->accel.src_stepx == -1) { + if (cx > 0) + cx--; + } + + dev->accel.src = mach->accel.src_ge_offset + (cy * mach->accel.src_pitch); + + while (1) { + mix = 1; + + if ((dev->accel.dx >= clip_l) && + (dev->accel.dx <= clip_r) && + (dev->accel.dy >= clip_t) && + (dev->accel.dy <= clip_b)) { + dev->subsys_stat |= INT_GE_BSY; + READ(dev->accel.src + cx, src_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; + + default: + break; + } + + if (!compare) { + old_dest_dat = dest_dat; + MIX(mix, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + } + + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + + cx += mach->accel.src_stepx; + mach->accel.sx++; + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + cx = mach->accel.src_x_scan; + if (mach->accel.src_stepx == -1) { + if (cx > 0) + cx--; + } + + cy += (mach->accel.src_y_dir ? 1 : -1); + dev->accel.src = mach->accel.src_ge_offset + (cy * mach->accel.src_pitch); + } + + dev->accel.dx += mach->accel.stepx; + dev->accel.sx++; + if (dev->accel.sx >= mach->accel.width) { + dev->accel.sx = 0; + dev->accel.dy += mach->accel.stepy; + dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); + + if (mach->accel.line_idx == 2) { + mach->accel.line_array[0] = dev->accel.dx; + mach->accel.line_array[4] = dev->accel.dx; + } + if (dev->accel.sy >= 0) + dev->accel.sy--; + + dev->fifo_idx = 0; + dev->force_busy = 0; + dev->force_busy2 = 0; + mach->force_busy = 0; + dev->accel.cmd_back = 1; + dev->accel.cur_x = dev->accel.dx; + dev->accel.cur_y = dev->accel.dy; + mach->accel.src_x_scan = cx; + mach->accel.src_y_scan = cy; + return; + } + } + return; + } + if (mono_src == 1) { count = mach->accel.width; mix_dat = mach->accel.mono_pattern_normal[0]; @@ -2128,7 +2070,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 3: - READ(dev->accel.src + (dev->accel.cx), mix); + READ(dev->accel.src + dev->accel.cx, mix); mix = (mix & rd_mask) == rd_mask; break; @@ -2161,9 +2103,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 5: - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; if (dev->bpp) - src_dat |= (mach->accel.color_pattern[mach->accel.color_pattern_idx + 1] << 8); + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: @@ -2209,7 +2152,6 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config & 0x10) { WRITE(dev->accel.dest + dev->accel.dx, dest_dat); - mach_log("ScanToX: DXS=%d, DYS=%d, dest data=%02x, lineidx=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, mach->accel.line_idx); } } @@ -2228,40 +2170,21 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.cx -= mach->accel.src_width; dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); - if (dev->bpp) - dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); - else - dev->accel.src = (mach->accel.ge_offset << 2) + (dev->accel.cy * (dev->pitch)); + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); } - mach_log("ColorIdx=%d, data=%02x, DestX=%d, DestY=%d.\n", mach->accel.color_pattern_idx, mach->accel.color_pattern[mach->accel.color_pattern_idx], dev->accel.dx, dev->accel.dy & 1); - if (dev->bpp) - mach->accel.color_pattern_idx += 2; - else - mach->accel.color_pattern_idx++; + mach->accel.color_pattern_idx++; - if ((dev->accel_bpp >= 24) && (frgd_sel == 5) && (mach->accel.patt_len == 0x17)) { - if (dev->accel.x3) { - if (mach->accel.color_pattern_idx == 9) - mach->accel.color_pattern_idx = 3; - } else { - if (mach->accel.color_pattern_idx == 6) - mach->accel.color_pattern_idx = 0; - } - } else { - if (mach->accel.color_pattern_idx > mach->accel.patt_len) - mach->accel.color_pattern_idx = 0; - } + if (mach->accel.color_pattern_idx > mach->accel.patt_len) + mach->accel.color_pattern_idx = 0; dev->accel.dx += mach->accel.stepx; dev->accel.sx++; if (dev->accel.sx >= mach->accel.width) { dev->accel.sx = 0; dev->accel.dy += mach->accel.stepy; - if (dev->bpp) - dev->accel.dest = (mach->accel.ge_offset << 1) + (dev->accel.dy * dev->pitch); - else - dev->accel.dest = (mach->accel.ge_offset << 2) + (dev->accel.dy * dev->pitch); + dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); + if (mach->accel.line_idx == 2) { mach->accel.line_array[0] = dev->accel.dx; mach->accel.line_array[4] = dev->accel.dx; @@ -2348,13 +2271,12 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; - if (((dev->disp_cntl & 0x60) == 0x20) && ATI_MACH32) { - if ((addr >= 0x3c6) && (addr <= 0x3c9)) { - mach_log("VGA DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", - addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); - } else if ((addr >= 0x2ea) && (addr <= 0x2ed)) - mach_log("8514/A DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", - addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); + if ((addr >= 0x3c6) && (addr <= 0x3c9)) { + mach_log("VGA DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", + addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); + } else if ((addr >= 0x2ea) && (addr <= 0x2ed)) { + mach_log("8514/A DAC write regs=%03x, on=%d, display control=%02x, on1=%x, clocksel=%02x.\n", + addr, dev->on, dev->disp_cntl & 0x60, dev->accel.advfunc_cntl & 0x01, mach->accel.clock_sel & 0x01); } switch (addr) { @@ -2364,7 +2286,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x1cf: old = mach->regs[mach->index]; mach->regs[mach->index] = val; - mach_log("ATI VGA write reg=%02x, val=%02x.\n", mach->index, val); + mach_log("ATI VGA write reg=%02x, val=%02x, old=%02x.\n", mach->index, val, old); switch (mach->index) { case 0xa3: if ((old ^ val) & 0x10) { @@ -2388,8 +2310,25 @@ mach_out(uint16_t addr, uint8_t val, void *priv) break; case 0xb0: if ((old ^ val) & 0x60) { - mach_log("ATI B0 bits 5-6: old=%02x, val=%02x.\n", old & 0x60, val & 0x60); - svga_recalctimings(svga); + if (dev->_8514crt) { + if (!(mach->accel.clock_sel & 0x01)) { + if ((val & 0x20) && !(old & 0x20)) { + dev->on = 1; + dev->vendor_mode = !!(ATI_MACH32); + mach_set_resolution(mach, svga); + mach32_updatemapping(mach, svga); + } else if (!(val & 0x20) && (old & 0x20)) { + dev->on = 0; + dev->vendor_mode = 0; + mach_set_resolution(mach, svga); + mach32_updatemapping(mach, svga); + } + } + } else + svga_recalctimings(svga); + + mach_log("ATI B0 bits 5-6: old=%02x, val=%02x, on=%d, bpp=%d, hires=%x, vgahires=%02x, base=%05x.\n", + old & 0x60, val & 0x60, dev->on, dev->accel_bpp, dev->accel.advfunc_cntl & 0x04, svga->gdcreg[5] & 0x60, svga->mapping.base); } break; case 0xae: @@ -2464,23 +2403,12 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); - mach_log("8514/A RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); - if (ATI_MACH32) { - if (mach->regs[0xb0] & 0x20) { /*ATI extended 8514/A mode.*/ - mach_log("Extended 8514/A mode.\n"); - dev->vendor_mode = 1; - dev->on |= 0x01; - mach_set_resolution(mach, svga); - mach32_updatemapping(mach, svga); - } - if (dev->on) - svga_out(addr, val, svga); - else { - if (mach->pci_bus && !mach->ramdac_type) - ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); - else - ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } + mach_log("8514/A Extended mode=%02x.\n", mach->regs[0xb0] & 0x20); + if (ATI_MACH32 && !dev->on) { + if (mach->pci_bus && !mach->ramdac_type) + ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); + else + ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); } else svga_out(addr, val, svga); return; @@ -2491,23 +2419,12 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x3C9: rs2 = !!(mach->regs[0xa0] & 0x20); rs3 = !!(mach->regs[0xa0] & 0x40); - mach_log("VGA RS2=%d, RS3=%d, addr=%03x.\n", rs2, rs3, addr); - if (ATI_MACH32) { - if (svga->attrregs[0x10] & 0x40) { - mach_log("VGA mode.\n"); - dev->vendor_mode = 0; - dev->on &= ~0x01; - mach_set_resolution(mach, svga); - mach32_updatemapping(mach, svga); - } - if (dev->on) - svga_out(addr, val, svga); - else { - if (mach->pci_bus && !mach->ramdac_type) - ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); - else - ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } + mach_log("VGA Extended mode=%02x.\n", mach->regs[0xb0] & 0x20); + if (ATI_MACH32 && !dev->on) { + if (mach->pci_bus && !mach->ramdac_type) + ati68860_ramdac_out((addr & 0x03) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); + else + ati68875_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); } else svga_out(addr, val, svga); return; @@ -2622,15 +2539,11 @@ mach_in(uint16_t addr, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); - if (ATI_MACH32) { - if (dev->on) - temp = svga_in(addr, svga); - else { - if (mach->pci_bus && !mach->ramdac_type) - temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); - else - temp = ati68875_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } + if (ATI_MACH32 && !dev->on) { + if (mach->pci_bus && !mach->ramdac_type) + temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); + else + temp = ati68875_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); } else temp = svga_in(addr, svga); break; @@ -2770,13 +2683,15 @@ static void mach_set_resolution(mach_t *mach, svga_t *svga) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + int ret = 0; - dev->hdisp = (dev->hdisped + 1) << 3; dev->h_total = dev->htotal + 1; if (dev->h_total == 1) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ dev->h_total = 0x9e; + dev->hdisp = (dev->hdisped + 1) << 3; + dev->vdisp = (dev->v_disp + 1) >> 1; if ((dev->vdisp == 478) || (dev->vdisp == 598) || (dev->vdisp == 766) || (dev->vdisp == 1022)) dev->vdisp += 2; @@ -2789,70 +2704,53 @@ mach_set_resolution(mach_t *mach, svga_t *svga) if (dev->interlace) dev->v_syncstart >>= 1; - mach_log("Shadow set ATI=%x, shadow set 8514/A=%x, resolution h=%d, v=%d, vtotal=%d, vsyncstart=%d.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart); - switch (mach->shadow_set & 0x03) { - case 0x00: /*Primary CRT Register set*/ - if (dev->on) { - if (mach->crt_resolution == 0x01) { - if (ATI_8514A_ULTRA) { + if ((mach->accel.clock_sel & 0x01) && !(mach->old_on2 & 0x01) && + !(dev->accel.advfunc_cntl & 0x01)) + ret = 2; + else if ((dev->accel.advfunc_cntl & 0x01) && !(mach->old_on1 & 0x01) && + !(mach->accel.clock_sel & 0x01)) + ret = 1; + else if ((!(dev->accel.advfunc_cntl & 0x01) && (mach->old_on1 & 0x01)) || + (!(mach->accel.clock_sel & 0x01) && (mach->old_on2 & 0x01))) + ret = 0; + + if (ret) { + if (ret == 2) + svga_recalctimings(svga); + else { + switch (mach->shadow_set & 0x03) { + case 0x00: + if (mach->crt_resolution) + svga_recalctimings(svga); + else { if (dev->accel.advfunc_cntl & 0x04) { if (dev->hdisp == 640) { dev->hdisp = 1024; dev->vdisp = 768; - svga_recalctimings(svga); } } else { if (dev->hdisp == 1024) { dev->hdisp = 640; dev->vdisp = 480; - svga_recalctimings(svga); } } - } else svga_recalctimings(svga); - } else if (mach->crt_resolution == 0x02) { - if (dev->accel.advfunc_cntl & 0x04) { - if (dev->hdisp == 640) { - dev->hdisp = 1024; - dev->vdisp = 768; - svga_recalctimings(svga); - } - } else { - if (dev->hdisp == 1024) { - dev->hdisp = 640; - dev->vdisp = 480; - svga_recalctimings(svga); - } } - } else - svga_recalctimings(svga); + break; + case 0x01: + mach->crt_resolution = 0x01; + break; + case 0x02: + mach->crt_resolution = 0x02; + break; + default: + break; } - break; - case 0x01: /*Shadow 640x480 CRT register set*/ - if (dev->on) { - if (!(dev->accel.advfunc_cntl & 0x04)) { - if (dev->hdisp == 1024) { - dev->hdisp = 640; - dev->vdisp = 480; - } - } - svga_recalctimings(svga); - } - break; - case 0x02: /*Shadow 1024x768 CRT register set*/ - if (dev->on) { - if (dev->accel.advfunc_cntl & 0x04) { - if (dev->hdisp == 640) { - dev->hdisp = 1024; - dev->vdisp = 768; - } - } - svga_recalctimings(svga); - } - break; - default: - break; - } + } + } else + svga_recalctimings(svga); + + mach_log("Shadow set ATI=%x, shadow set 8514/A and on1=%x, on2=%x, resolution h=%d, v=%d, vtotal=%d, vsyncstart=%d, crtres=%d, ret=%d, actual passthrough=%x.\n", mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart, mach->crt_resolution, ret, dev->on); } void @@ -2864,42 +2762,52 @@ ati8514_recalctimings(svga_t *svga) mach_log("ON=%d, vgahdisp=%d.\n", dev->on, svga->hdisp); if (dev->on) { mach_log("8514/A ON.\n"); - dev->pitch = dev->ext_pitch; + dev->pitch = ((mach->accel.ge_pitch & 0xff) << 3); + dev->interlace = !!(dev->disp_cntl & 0x10); dev->rowoffset = dev->ext_crt_pitch; dev->rowcount = !!(dev->disp_cntl & 0x08); - dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); - mach->accel.ge_offset = dev->accel.ge_offset; + dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; + mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2; + dev->accel.ge_offset -= mach->accel.crt_offset; mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); + mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; + mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; + mach->accel.src_ge_offset -= mach->accel.crt_offset; + mach->accel.dst_ge_offset -= mach->accel.crt_offset; + dev->h_disp = dev->hdisp; dev->dispend = dev->vdisp; + if (dev->dispend == 600) + dev->h_disp = 800; + else if (dev->h_disp == 640) + dev->dispend = 480; if (dev->accel.advfunc_cntl & 0x04) - svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; else - svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0; + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0; if (dev->interlace) dev->dispend >>= 1; - mach->crt_resolution = 0x00; mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n", dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace); if (dev->vram_512k_8514) { - if (dev->h_disp == 640) { - dev->ext_pitch = 640; - dev->pitch = dev->ext_pitch; - } else { - dev->ext_pitch = 1024; - dev->pitch = dev->ext_pitch; - } + if (dev->h_disp == 640) + dev->pitch = 640; + else + dev->pitch = 1024; } dev->accel_bpp = 8; svga->render8514 = ibm8514_render_8bpp; - } + } else + mach->crt_resolution = 0; } static void @@ -2956,13 +2864,29 @@ mach_recalctimings(svga_t *svga) mach_log("ON=%d, override=%d, gelo=%04x, gehi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, svga->hdisp); if (dev->on) { dev->ma_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ - dev->pitch = dev->ext_pitch; + dev->interlace = !!(dev->disp_cntl & 0x10); + dev->pitch = ((mach->accel.ge_pitch & 0xff) << 3); dev->rowoffset = dev->ext_crt_pitch; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); - mach->accel.ge_offset = dev->accel.ge_offset; - mach_log("8514/A ON, extpitch=%d, geoffset=%x, 8514malatch=%x, vgamalatch=%x.\n", dev->ext_pitch, mach->accel.ge_offset, dev->ma_latch, svga->ma_latch); + mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)); + if (dev->bpp) { + dev->accel.ge_offset <<= 1; + mach->accel.crt_offset <<= 1; + } else { + dev->accel.ge_offset <<= 2; + mach->accel.crt_offset <<= 2; + } + + if (ATI_MACH32 && !dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + dev->accel.ge_offset <<= 1; + mach->accel.crt_offset <<= 1; + } + + dev->accel.ge_offset -= mach->accel.crt_offset; + + mach_log("RowCount=%x, rowoffset=%x, pitch=%d, geoffset=%x, crtoffset=%x.\n", dev->rowcount, dev->rowoffset, dev->pitch, dev->accel.ge_offset, mach->accel.crt_offset); mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x, interlace=%x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0xfe, dev->interlace); @@ -2972,59 +2896,94 @@ mach_recalctimings(svga_t *svga) if (dev->dispend == 959) { /*FIXME: vertical resolution mess on EEPROM tests on Mach8*/ dev->dispend >>= 1; dev->dispend++; - } + } else if (dev->dispend == 600) + dev->h_disp = 800; + else if (dev->h_disp == 640) + dev->dispend = 480; - svga->clock8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen); + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen); if (mach->accel.clock_sel & 0x40) - svga->clock8514 *= 2; + svga->clock_8514 *= 2; if (dev->interlace) dev->dispend >>= 1; - mach->crt_resolution = 0x00; if (ATI_MACH32) { + switch ((mach->shadow_set >> 8) & 0x03) { + case 0x00: + mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + if (dev->bpp) { + mach->accel.src_ge_offset <<= 1; + mach->accel.dst_ge_offset <<= 1; + } else { + mach->accel.src_ge_offset <<= 2; + mach->accel.dst_ge_offset <<= 2; + } + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { + mach->accel.src_ge_offset <<= 1; + mach->accel.dst_ge_offset <<= 1; + } + mach->accel.src_ge_offset -= mach->accel.crt_offset; + mach->accel.dst_ge_offset -= mach->accel.crt_offset; + dev->accel.src_pitch = mach->accel.src_pitch; + dev->accel.dst_pitch = mach->accel.dst_pitch; + dev->accel.src_ge_offset = mach->accel.src_ge_offset; + dev->accel.dst_ge_offset = mach->accel.dst_ge_offset; + break; + case 0x01: + mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + if (dev->bpp) + mach->accel.dst_ge_offset <<= 1; + else + mach->accel.dst_ge_offset <<= 2; + + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) + mach->accel.dst_ge_offset <<= 1; + + mach->accel.dst_ge_offset -= mach->accel.crt_offset; + dev->accel.dst_pitch = mach->accel.dst_pitch; + dev->accel.dst_ge_offset = mach->accel.dst_ge_offset; + break; + case 0x02: + mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + if (dev->bpp) + mach->accel.src_ge_offset <<= 1; + else + mach->accel.src_ge_offset <<= 2; + + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) + mach->accel.src_ge_offset <<= 1; + + mach->accel.src_ge_offset -= mach->accel.crt_offset; + dev->accel.src_pitch = mach->accel.src_pitch; + dev->accel.src_ge_offset = mach->accel.src_ge_offset; + break; + default: + break; + } mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace, svga->hdisp); if ((mach->accel.ext_ge_config & 0x800) || (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800))) { - if ((mach->accel.ext_ge_config & 0x30) == 0x20) { - if ((mach->accel.ext_ge_config & 0xc0) == 0x40) { - dev->accel_bpp = 16; - svga->overscan_color = video_16to32[((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24) & 0xffff]; - } else { - dev->accel_bpp = 15; - svga->overscan_color = video_15to32[((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24) & 0xffff]; - } - } else if ((mach->accel.ext_ge_config & 0x30) == 0x30) { - if (mach->accel.ext_ge_config & 0x200) - dev->accel_bpp = 32; - else - dev->accel_bpp = 24; - - svga->overscan_color = ((mach->overscan_r_col_24 << 16) | (mach->overscan_g_col_24 << 8) | mach->overscan_b_col_24); - } else if ((mach->accel.ext_ge_config & 0x30) == 0x10) { - dev->accel_bpp = 8; - svga->overscan_color = dev->pallook[mach->overscan_col_8]; - } else { - if (dev->vram_512k_8514) { - if (dev->h_disp == 640) { - dev->ext_pitch = 640; - dev->pitch = dev->ext_pitch; - } else { - dev->ext_pitch = 1024; - dev->pitch = dev->ext_pitch; - } - } - dev->accel_bpp = 8; - svga->overscan_color = dev->pallook[mach->overscan_col_8]; - } - - mach_log("hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", + mach_log("hv=%d,%d, pitch=%d, rowoffset=%d, gextconfig=%03x, bpp=%d, shadow=%x, vgahdisp=%d.\n", dev->h_disp, dev->dispend, dev->pitch, dev->ext_crt_pitch, mach->accel.ext_ge_config & 0xcec0, - dev->accel_bpp, mach->shadow_set & 3, svga->hdisp); + dev->accel_bpp, mach->shadow_set & 0x03, svga->hdisp); switch (dev->accel_bpp) { case 8: + if ((mach->accel.ext_ge_config & 0x30) == 0x00) { + if (dev->vram_512k_8514) { + if (dev->h_disp == 640) + dev->pitch = 640; + else + dev->pitch = 1024; + } + } svga->render8514 = ibm8514_render_8bpp; break; case 15: @@ -3047,22 +3006,34 @@ mach_recalctimings(svga_t *svga) } } } else { + mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); + if (dev->bpp) { + mach->accel.src_ge_offset <<= 1; + mach->accel.dst_ge_offset <<= 1; + } else { + mach->accel.src_ge_offset <<= 2; + mach->accel.dst_ge_offset <<= 2; + } + mach->accel.src_ge_offset -= mach->accel.crt_offset; + mach->accel.dst_ge_offset -= mach->accel.crt_offset; + mach_log("cntl=%d, clksel=%x, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d, vgahdisp=%d.\n", dev->accel.advfunc_cntl & 0x04, mach->accel.clock_sel & 0x01, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset, - mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 3, dev->interlace, svga->hdisp); + mach->accel.ext_ge_config & 0xcec0, mach->shadow_set & 0x03, dev->interlace, svga->hdisp); if (dev->vram_512k_8514) { - if (dev->h_disp == 640) { - dev->ext_pitch = 640; - dev->pitch = dev->ext_pitch; - } else { - dev->ext_pitch = 1024; - dev->pitch = dev->ext_pitch; - } + if (dev->h_disp == 640) + dev->pitch = 640; + else + dev->pitch = 1024; } dev->accel_bpp = 8; svga->render8514 = ibm8514_render_8bpp; } } else { + mach->crt_resolution = 0; if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d.\n", svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on); @@ -3129,9 +3100,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x04)) dev->htotal = val; - - mach_set_resolution(mach, svga); } + svga_recalctimings(svga); break; case 0xae8: @@ -3139,8 +3109,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_start, val); } - mach_set_resolution(mach, svga); } + svga_recalctimings(svga); break; case 0xee8: @@ -3148,14 +3118,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (!(mach->shadow_cntl & 0x04)) { WRITE8(port, dev->hsync_width, val); } - mach_set_resolution(mach, svga); } - break; - - case 0x1ee8: - case 0x1ee9: - if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) /*For 8514/A mode, take the shadow sets into account.*/ - mach_set_resolution(mach, svga); + svga_recalctimings(svga); break; case 0x6e8: @@ -3166,52 +3130,45 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u dev->htotal = (val >> 8) & 0xff; if (!(mach->shadow_cntl & 0x08)) { - if (dev->htotal || (mach->accel.clock_sel & 0x01)) { + if ((dev->htotal || (mach->accel.clock_sel & 0x01)) && (val & 0xff)) { WRITE8(port, dev->hdisped, val); } } - - if (dev->htotal || (mach->accel.clock_sel & 0x01)) - mach_set_resolution(mach, svga); } } else { mach_log("HDISP and HTOTAL=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x08)) { - WRITE8(port, dev->hdisped, val); + if ((dev->htotal || (mach->accel.clock_sel & 0x01)) && (val & 0xff)) { + WRITE8(port, dev->hdisped, val); + } } - mach_set_resolution(mach, svga); - } else if (!(mach->accel.clock_sel & 0x01) && ((mach->shadow_set & 0x03) == 0x00) && dev->on) { /*Still write the parameter even after going to 8514/A mode if needed*/ - if (!(mach->shadow_cntl & 0x08)) { - WRITE8(port, dev->hdisped, val); - } - mach_set_resolution(mach, svga); } } mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x, shadowcntl=%02x, shadowset=%02x.\n", CS, cpu_state.pc, port, val, mach->shadow_cntl & 0x08, mach->shadow_set & 0x03); + svga_recalctimings(svga); break; case 0x6e9: if (len == 1) { mach_log("HDISP and HTOTAL+1=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01); if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x04)) + if (!(mach->shadow_cntl & 0x04)) { dev->htotal = val; - - mach_set_resolution(mach, svga); + } } } + svga_recalctimings(svga); break; case 0x12e8: if (len == 2) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x10)) { + if (!(mach->shadow_cntl & 0x10) && val) { dev->v_total_reg = val; dev->v_total_reg &= 0x1fff; } - mach_set_resolution(mach, svga); } } else { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ @@ -3219,39 +3176,32 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u WRITE8(port, dev->v_total_reg, val); dev->v_total_reg &= 0x1fff; } - mach_set_resolution(mach, svga); } } mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); + svga_recalctimings(svga); break; case 0x12e9: if (len == 1) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { if (!(mach->shadow_cntl & 0x10)) { /*For 8514/A mode, take the shadow sets into account.*/ - WRITE8(port, dev->v_total_reg, val); + WRITE8(port, dev->v_total_reg, val >> 8); dev->v_total_reg &= 0x1fff; } - mach_set_resolution(mach, svga); } mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): hdisp=0x%02x.\n", CS, cpu_state.pc, port, val); } + svga_recalctimings(svga); break; case 0x16e8: if (len == 2) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x20)) { + if (!(mach->shadow_cntl & 0x20) && val) { dev->v_disp = val; dev->v_disp &= 0x1fff; } - mach_set_resolution(mach, svga); - } else if (!(mach->accel.clock_sel & 0x01) && ((mach->shadow_set & 0x03) == 0x00) && dev->on) { /*Still write the parameter even after going to 8514/A mode if needed*/ - if (!(mach->shadow_cntl & 0x20)) { - dev->v_disp = val; - dev->v_disp &= 0x1fff; - } - mach_set_resolution(mach, svga); } mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); @@ -3261,9 +3211,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u WRITE8(port, dev->v_disp, val); dev->v_disp &= 0x1fff; } - mach_set_resolution(mach, svga); } } + svga_recalctimings(svga); break; case 0x16e9: if (len == 1) { @@ -3272,21 +3222,20 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u WRITE8(port, dev->v_disp, val); dev->v_disp &= 0x1fff; } - mach_set_resolution(mach, svga); } mach_log("ATI 8514/A: V_DISP write 16E8=%d, vdisp2=%d.\n", dev->v_disp, dev->v_disp2); mach_log("ATI 8514/A: (0x%04x): vdisp=0x%02x.\n", port, val); } + svga_recalctimings(svga); break; case 0x1ae8: if (len == 2) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ - if (!(mach->shadow_cntl & 0x10)) { + if (!(mach->shadow_cntl & 0x10) && val) { dev->v_sync_start = val; dev->v_sync_start &= 0x1fff; } - mach_set_resolution(mach, svga); } mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); @@ -3296,9 +3245,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; } - mach_set_resolution(mach, svga); } } + svga_recalctimings(svga); break; case 0x1ae9: if (len == 1) { @@ -3307,18 +3256,22 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u WRITE8(port, dev->v_sync_start, val); dev->v_sync_start &= 0x1fff; } - mach_set_resolution(mach, svga); } mach_log("ATI 8514/A: V_SYNCSTART write 1AE8 = %d\n", dev->v_syncstart); mach_log("ATI 8514/A: (0x%04x): vsyncstart=0x%02x.\n", port, val); } + svga_recalctimings(svga); + break; + + case 0x1ee8: + case 0x1ee9: + svga_recalctimings(svga); break; case 0x22e8: - if ((mach->shadow_cntl & 0x03) == 0x00) { + if ((mach->shadow_cntl & 0x03) == 0x00) dev->disp_cntl = val; - dev->interlace = !!(dev->disp_cntl & 0x10); - } + mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n", port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace); svga_recalctimings(svga); @@ -3346,17 +3299,25 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x4ae8: - dev->accel.advfunc_cntl = val; - dev->on = val & 0x01; + case 0x4ae9: + mach->old_on1 = dev->accel.advfunc_cntl & 0x01; + WRITE8(port, dev->accel.advfunc_cntl, val); + if (len == 2) { + WRITE8(port + 1, dev->accel.advfunc_cntl, val >> 8); + } + dev->on = dev->accel.advfunc_cntl & 0x01; dev->vendor_mode = 0; - mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, shadow crt=%x, hdisp=%d, vdisp=%d, extmode=%02x.\n", - CS, cpu_state.pc, port, val & 0x01, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, mach->regs[0xb0] & 0x20); + if (dev->_8514crt) { + if (mach->regs[0xb0] & 0x20) { + dev->on = 1; + dev->vendor_mode = !!(ATI_MACH32); + } + } + + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, valxor=%x, shadow crt=%x, hdisp=%d, vdisp=%d, extmode=%02x, accelbpp=%d, crt=%d, crtres=%d.\n", + CS, cpu_state.pc, port, val & 0x01, dev->on, dev->accel.advfunc_cntl & 0x04, dev->hdisp, dev->vdisp, mach->regs[0xb0] & 0x20, dev->accel_bpp, dev->_8514crt, mach->crt_resolution); if (ATI_MACH32) { - if ((mach->regs[0xb0] & 0x20) || (dev->accel_bpp >= 15)) { /*Account for the extended ATI 8514/A mode here too*/ - dev->on |= 0x01; - dev->vendor_mode = 1; - } mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); } else { @@ -3367,23 +3328,30 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x82e8: + ibm8514_accel_out_fifo(svga, port, val, len); + mach_log("DSTY=%04x, len=%d.\n", val & 0x07ff, len); + break; + case 0x86e8: ibm8514_accel_out_fifo(svga, port, val, len); + mach_log("DSTX=%04x, len=%d.\n", val & 0x07ff, len); break; case 0x8ae8: ibm8514_accel_out_fifo(svga, port, val, len); + mach_log("SRCY=%04x, len=%d.\n", val & 0x07ff, len); if (len == 2) { - mach_log("SRCY=%d.\n", val & 0x07ff); mach->accel.src_y = val & 0x07ff; + mach->accel.src_y_scan = ((int64_t)(val & 0x07ff)); } break; case 0x8ee8: ibm8514_accel_out_fifo(svga, port, val, len); + mach_log("SRCX=%04x, len=%d.\n", val & 0x07ff, len); if (len == 2) { - mach_log("SRCX=%d.\n", val & 0x07ff); mach->accel.src_x = val & 0x07ff; + mach->accel.src_x_scan = ((int64_t)(val & 0x07ff)); } break; @@ -3409,7 +3377,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xa2e8: case 0xe2e8: if (port == 0xe2e8) { - mach_log("%04X: Background Color=%04x.\n", port, val); + mach_log("%04X: Background Color=%04x, pix=%d, len=%d.\n", port, val, dev->accel.cmd_back, len); if (len == 2) { if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { @@ -3430,7 +3398,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_log("%04X: CMDBack BKGDCOLOR, sy=%d, height=%d, cmdtype=%d, val=%04x.\n", port, dev->accel.sy, mach->accel.height, mach->accel.cmd_type, val); } } else { - if (dev->accel.cmd & 0x100) { + if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { if (mach_pixel_read(mach)) break; @@ -3450,7 +3418,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xa6e8: case 0xe6e8: if (port == 0xe6e8) { - mach_log("%04X: Foreground Color=%04x.\n", port, val); + mach_log("%04X: Foreground Color=%04x, pix=%d, len=%d.\n", port, val, dev->accel.cmd_back, len); if (len == 2) { if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { @@ -3533,6 +3501,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xaae8: + if (len == 2) + mach->accel.dst_clr_cmp_mask = val; + fallthrough; case 0xaee8: case 0xb2e8: case 0xb6e8: @@ -3580,65 +3551,63 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xaee: case 0xaef: - if (len == 2) - mach->cursor_offset_lo_reg = val; - else { - WRITE8(port, mach->cursor_offset_lo_reg, val); + WRITE8(port, mach->cursor_offset_lo_reg, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_offset_lo_reg, val >> 8); } mach->cursor_offset_lo = mach->cursor_offset_lo_reg; dev->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16)) << 2); + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) + dev->hwcursor.addr <<= 1; break; case 0xeee: case 0xeef: - if (len == 2) - mach->cursor_offset_hi_reg = val; - else { - WRITE8(port, mach->cursor_offset_hi_reg, val); + WRITE8(port, mach->cursor_offset_hi_reg, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_offset_hi_reg, val >> 8); } dev->hwcursor.ena = !!(mach->cursor_offset_hi_reg & 0x8000); mach->cursor_offset_hi = mach->cursor_offset_hi_reg & 0x0f; dev->hwcursor.addr = ((mach->cursor_offset_lo | (mach->cursor_offset_hi << 16)) << 2); - mach_log("HWCursorEnabled=%x.\n", dev->hwcursor.ena); + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) + dev->hwcursor.addr <<= 1; break; case 0x12ee: case 0x12ef: - if (len == 2) - mach->cursor_x = val; - else { - WRITE8(port, mach->cursor_x, val); + WRITE8(port, mach->cursor_x, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_x, val >> 8); } dev->hwcursor.x = mach->cursor_x & 0x7ff; break; case 0x16ee: case 0x16ef: - if (len == 2) - mach->cursor_y = val; - else { - WRITE8(port, mach->cursor_y, val); + WRITE8(port, mach->cursor_y, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_y, val >> 8); } dev->hwcursor.y = mach->cursor_y & 0xfff; break; case 0x1aee: case 0x1aef: - if (len == 2) - mach->cursor_col_b = val; - else { - WRITE8(port, mach->cursor_col_b, val); + WRITE8(port, mach->cursor_col_b, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_col_b, val >> 8); } mach->cursor_col_0 = mach->cursor_col_b & 0xff; mach->cursor_col_1 = (mach->cursor_col_b >> 8) & 0xff; + mach_log("ATI 8514/A: (0x%04x) Cursor Color B, val=0x%02x, len=%d, extended 8514/A mode bpp=%d.\n", port, val, len, dev->accel_bpp); break; case 0x1eee: case 0x1eef: - if (len == 2) - mach->cursor_vh_offset = val; - else { - WRITE8(port, mach->cursor_vh_offset, val); + WRITE8(port, mach->cursor_vh_offset, val); + if (len == 2) { + WRITE8(port + 1, mach->cursor_vh_offset, val >> 8); } dev->hwcursor.xoff = mach->cursor_vh_offset & 0x3f; dev->hwcursor.yoff = (mach->cursor_vh_offset >> 8) & 0x3f; @@ -3654,45 +3623,52 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x26ee: case 0x26ef: - if (len == 2) - mach->accel.crt_pitch = val; - else { - WRITE8(port, mach->accel.crt_pitch, val); + WRITE8(port, mach->accel.crt_pitch, val); + if (len == 2) { + WRITE8(port + 1, mach->accel.crt_pitch, val >> 8); } + dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; + if (dev->accel_bpp > 8) { - if (dev->accel_bpp == 24) + if (dev->accel_bpp == 24) { dev->ext_crt_pitch *= 3; - else if (dev->accel_bpp == 32) + } else if (dev->accel_bpp == 32) dev->ext_crt_pitch <<= 2; else dev->ext_crt_pitch <<= 1; } - if (ATI_MACH32) { - dev->on |= 0x01; - dev->vendor_mode = 1; - } - svga_recalctimings(svga); + + if (len == 2) { + dev->_8514crt = 0; + if (!(dev->accel.advfunc_cntl & 0x01)) { + dev->on = 1; + dev->vendor_mode = !!ATI_MACH32; + } + } else + dev->_8514crt = 1; + + mach_set_resolution(mach, svga); if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); - mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode=%02x.\n", port, val, dev->ext_crt_pitch, len, mach->regs[0xb0] & 0x20); + mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode bpp=%d.\n", port, val, dev->ext_crt_pitch, len, dev->accel_bpp); break; case 0x2aee: case 0x2aef: - if (len == 2) { + if (len == 2) mach->accel.crt_offset_lo = val; - } else { + else { WRITE8(port, mach->accel.crt_offset_lo, val); } - svga_recalctimings(svga); + mach_log("ATI 8514/A: (0x%04x) CRT Offset Low val=0x%02x, len=%d.\n", port, val, len); break; case 0x2eee: case 0x2eef: mach->accel.crt_offset_hi = val & 0x0f; - svga_recalctimings(svga); + mach_log("ATI 8514/A: (0x%04x) CRT Offset High val=0x%02x, len=%d.\n", port, val, len); break; case 0x32ee: @@ -3727,6 +3703,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } mach->ext_cur_col_0_g = mach->cursor_col_0_rg & 0xff; mach->ext_cur_col_0_r = (mach->cursor_col_0_rg >> 8) & 0xff; + mach_log("ATI 8514/A: (0x%04x) Cursor Color 0 RG, val=0x%02x, len=%d, extended 8514/A mode bpp=%d.\n", port, val, len, dev->accel_bpp); break; case 0x3eee: @@ -3738,6 +3715,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } mach->ext_cur_col_1_g = mach->cursor_col_1_rg & 0xff; mach->ext_cur_col_1_r = (mach->cursor_col_1_rg >> 8) & 0xff; + mach_log("ATI 8514/A: (0x%04x) Cursor Color 1 RG, val=0x%02x, len=%d, extended 8514/A mode bpp=%d.\n", port, val, len, dev->accel_bpp); break; case 0x42ee: @@ -3763,18 +3741,20 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x4aee: case 0x4aef: - if (len == 2) - mach->accel.clock_sel = val; - else { - WRITE8(port, mach->accel.clock_sel, val); + mach->old_on2 = mach->accel.clock_sel & 0x01; + WRITE8(port, mach->accel.clock_sel, val); + if (len == 2) { + WRITE8(port + 1, mach->accel.clock_sel, val >> 8); } dev->on = mach->accel.clock_sel & 0x01; dev->vendor_mode = 1; - mach_log("ATI 8514/A: (0x%04x): ON=%d, val=%04x, hdisp=%d, vdisp=%d.\n", - port, mach->accel.clock_sel & 0x01, val, dev->hdisp, dev->vdisp); + + mach_log("[%04X:%08X]: ATI 8514/A: (0x%04x): ON=%d, val=%04x, xor=%d, hdisp=%d, vdisp=%d, accelbpp=%d.\n", + CS, cpu_state.pc, port, mach->accel.clock_sel & 0x01, val, dev->on, dev->hdisp, dev->vdisp, dev->accel_bpp); mach_log("Vendor ATI mode set %s resolution.\n", (dev->accel.advfunc_cntl & 0x04) ? "2: 1024x768" : "1: 640x480"); - svga_recalctimings(svga); + + mach_set_resolution(mach, svga); if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); break; @@ -3801,29 +3781,17 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x5aee: case 0x5aef: - if (len == 2) - mach->shadow_set = val; - else { - WRITE8(port, mach->shadow_set, val); + WRITE8(port, mach->shadow_set, val); + if (len == 2) { + WRITE8(port + 1, mach->shadow_set, val >> 8); } - mach_log("ATI 8514/A: (0x%04x) val=0x%02x.\n", port, val); + mach_log("ATI 8514/A: (0x%04x) val=0x%02x, len=%d.\n", port, val, len); if ((mach->shadow_set & 0x03) == 0x00) mach_log("Primary CRT register set.\n"); - else if ((mach->shadow_set & 0x03) == 0x01) { - mach->crt_resolution = 0x01; + else if ((mach->shadow_set & 0x03) == 0x01) mach_log("CRT Shadow Set 1: 640x480.\n"); - } else if ((mach->shadow_set & 0x03) == 0x02) { - mach->crt_resolution = 0x02; + else if ((mach->shadow_set & 0x03) == 0x02) mach_log("CRT Shadow Set 2: 1024x768.\n"); - } - - if (ATI_MACH32) { - mach_log("Load both SRC/DST GE Offset/Pitch=%03x, offset=%08x.\n", mach->shadow_set & 0x300, dev->accel.ge_offset); - if ((mach->shadow_set & 0x300) == 0x000) { - mach->accel.ge_offset_lo = 0x0000; - mach->accel.ge_offset_hi = 0x0000; - } - } break; case 0x5eee: @@ -3857,8 +3825,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->accel.ge_offset_lo, val); } + mach_log("ATI 8514/A: (0x%04x) GE Offset Low val=0x%02x, geoffset=%04x, len=%d.\n", port, val, dev->accel.ge_offset, len); svga_recalctimings(svga); - mach_log("ATI 8514/A: (0x%04x) val=0x%02x, geoffset=%04x.\n", port, val, dev->accel.ge_offset); break; case 0x72ee: @@ -3868,8 +3836,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->accel.ge_offset_hi, val); } + mach_log("ATI 8514/A: (0x%04x) GE Offset High val=0x%02x, geoffset=%04x, len=%d.\n", port, val, dev->accel.ge_offset, len); svga_recalctimings(svga); - mach_log("ATI 8514/A: (0x%04x) val=0x%02x, geoffset=%04x.\n", port, val, dev->accel.ge_offset); break; case 0x76ee: @@ -3879,18 +3847,17 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->accel.ge_pitch, val); } - dev->ext_pitch = ((mach->accel.ge_pitch & 0xff) << 3); - mach_log("ATI 8514/A: (0x%04x) val=0x%02x, extpitch=%d.\n", port, val, dev->ext_pitch); + mach_log("ATI 8514/A: (0x%04x) GE Pitch val=0x%02x.\n", port, val); svga_recalctimings(svga); break; case 0x7aee: case 0x7aef: - if (len == 2) - mach->accel.ext_ge_config = val; - else { - WRITE8(port, mach->accel.ext_ge_config, val); + WRITE8(port, mach->accel.ext_ge_config, val); + if (len == 2) { + WRITE8(port + 1, mach->accel.ext_ge_config, val >> 8); } + if (ATI_MACH32) { if (mach->accel.crt_pitch & 0xff) dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; @@ -3899,25 +3866,40 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x00: case 0x10: dev->bpp = 0; + dev->accel_bpp = 8; break; case 0x20: dev->bpp = 1; dev->ext_crt_pitch <<= 1; + switch (mach->accel.ext_ge_config & 0xc0) { + case 0x00: + dev->accel_bpp = 15; + break; + case 0x40: + dev->accel_bpp = 16; + break; + default: /*TODO: 655RGB and 664RGB*/ + break; + } break; case 0x30: dev->bpp = 0; - if (mach->accel.ext_ge_config & 0x200) + if (mach->accel.ext_ge_config & 0x200) { dev->ext_crt_pitch <<= 2; - else + dev->accel_bpp = 32; + } else { dev->ext_crt_pitch *= 3; + dev->accel_bpp = 24; + } break; default: break; } svga_set_ramdac_type(svga, !!(mach->accel.ext_ge_config & 0x4000)); - mach_log("ATI 8514/A: (0x%04x) val=%02x.\n", port, val); - svga_recalctimings(svga); + mach_log("ATI 8514/A: (0x%04x) Extended Configuration=%04x, val=%04x.\n", port, mach->accel.ext_ge_config, val); + mach_set_resolution(mach, svga); + mach32_updatemapping(mach, svga); } else ati_eeprom_write(&mach->eeprom, !!(mach->accel.ext_ge_config & 0x04), !!(mach->accel.ext_ge_config & 0x02), !!(mach->accel.ext_ge_config & 0x01)); break; @@ -3936,30 +3918,33 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach->accel.patt_data_idx_reg = val & 0x1f; mach->accel.patt_data_idx = mach->accel.patt_data_idx_reg; + mach_log("Write Port 82ee: Pattern Data Index=%d, idx for color=%d.\n", val & 0x1f, mach->accel.color_pattern_idx); + if (mach->accel.patt_data_idx_reg < 0x10) mach->accel.color_pattern_idx = mach->accel.patt_idx; else mach->accel.color_pattern_idx = 0; - - mach_log("Write Port 82ee: Pattern Data Index=%d.\n", val & 0x1f); break; case 0x8eee: if (len == 2) { - frgd_sel = (mach->accel.dp_config >> 13) & 7; - if (mach->accel.patt_data_idx_reg < 0x10) { - mach->accel.color_pattern[mach->accel.patt_data_idx] = val & 0xff; - mach->accel.color_pattern[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; - mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); - if ((dev->accel_bpp >= 24) && (frgd_sel == 5) && (mach->accel.patt_len == 0x17)) - dev->accel.y1 = 1; + if (dev->bpp) { + mach->accel.color_pattern_hicol[mach->accel.patt_data_idx] = val; + mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); + mach->accel.patt_data_idx++; + } else { + mach->accel.color_pattern[mach->accel.patt_data_idx] = val & 0xff; + mach->accel.color_pattern[mach->accel.patt_data_idx + 1] = (val >> 8) & 0xff; + mach_log("Write Port 8eee: Color Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx, val); + mach->accel.patt_data_idx += 2; + } } else { mach->accel.mono_pattern_normal[mach->accel.patt_data_idx - 0x10] = val & 0xff; mach->accel.mono_pattern_normal[(mach->accel.patt_data_idx + 1) - 0x10] = (val >> 8) & 0xff; mach_log("Write Port 8eee: Mono Pattern Word Data[%d]=%04x.\n", mach->accel.patt_data_idx - 0x10, val); + mach->accel.patt_data_idx += 2; } - mach->accel.patt_data_idx += 2; } break; @@ -4026,7 +4011,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } dev->data_available = 0; dev->data_available2 = 0; - mach_log("BitBLT=%04x.\n", mach->accel.dp_config); + mach_log("BitBLT=%04x, pattidx=%d.\n", mach->accel.dp_config, mach->accel.patt_idx); mach_log(".\n"); mach->accel.cmd_type = 2; /*Non-conforming BitBLT from dest_y_end register (0xaeee)*/ @@ -4048,11 +4033,13 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xb6ee: - dev->accel.bkgd_mix = val & 0xff; + dev->accel.bkgd_mix = val & 0x1f; + dev->accel.bkgd_sel = (mach->accel.dp_config >> 7) & 3; break; case 0xbaee: - dev->accel.frgd_mix = val & 0xff; + dev->accel.frgd_mix = val & 0x1f; + dev->accel.frgd_sel = (mach->accel.dp_config >> 13) & 3; break; case 0xbeee: @@ -4088,6 +4075,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u dev->data_available = 0; dev->data_available2 = 0; mach->accel.cmd_type = 5; /*Horizontal Raster Draw from scan_to_x register (0xcaee)*/ + mach_log("ScanToX len=%d.\n", val); mach_log(".\n"); frgd_sel = (mach->accel.dp_config >> 13) & 7; @@ -4104,7 +4092,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xceee: - mach_log("Data Path Configuration (%04x) write val=%04x.\n", port, val); + mach_log("Data Path Configuration (%04x) write val=%04x, len=%d.\n", port, val, len); if (len == 2) { dev->data_available = 0; dev->data_available2 = 0; @@ -4124,6 +4112,11 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xd6ee: mach->accel.patt_idx = val & 0x1f; + frgd_sel = (mach->accel.dp_config >> 13) & 7; + + if ((frgd_sel == 5) && (dev->accel_bpp >= 24) && (mach->accel.patt_len == 0x17)) + mach->accel.color_pattern_idx = 0; + mach_log("Write Port d6ee: Pattern Index=%d.\n", val & 0x1f); break; @@ -4169,12 +4162,13 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xeeee: + mach_log("EEEE val=%04x, len=%d.\n", val, len); if (len == 2) mach->accel.dest_cmp_fn = val; break; case 0xf2ee: - mach_log("F2EE.\n"); + mach_log("F2EE val=%04x, len=%d.\n", val, len); if (len == 2) mach->accel.dst_clr_cmp_mask = val; break; @@ -4259,8 +4253,39 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in if (dev->fifo_idx > 0) dev->fifo_idx--; - if (dev->force_busy) + if (dev->force_busy) { temp |= 0x0200; /*Hardware busy*/ + if (mach->accel.cmd_type >= 0) { + switch (mach->accel.cmd_type) { + case 2: + if (dev->accel.sy >= mach->accel.height) + dev->force_busy = 0; + break; + case 5: + if (dev->accel.sx >= mach->accel.width) + dev->force_busy = 0; + break; + default: + if (dev->accel.sy < 0) + dev->force_busy = 0; + break; + } + } else { + switch (dev->accel.cmd >> 13) { + case 2: + case 3: + case 4: + case 6: + if (dev->accel.sy < 0) + dev->force_busy = 0; + break; + default: + if (!dev->accel.sy) + dev->force_busy = 0; + break; + } + } + } if (dev->data_available) { temp |= 0x0100; /*Read Data available*/ @@ -4837,6 +4862,7 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x56ee: case 0x56ef: READ8(port, mach->accel.scratch1); + mach_log("ScratchPad1=%x.\n", mach->accel.scratch1); break; case 0x5eee: @@ -4855,6 +4881,8 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) if (mach->force_busy) temp |= 0x20; + mach->force_busy = 0; + if (ati_eeprom_read(&mach->eeprom)) temp |= 0x40; @@ -5425,6 +5453,7 @@ mach32_svga_write(uint32_t addr, uint8_t val, void *priv) xga_write_test(addr, val, svga); addr = svga_decode_addr(svga, addr, 1); + if (addr == 0xffffffff) { mach_log("WriteCommon Over.\n"); return; @@ -5465,7 +5494,7 @@ mach32_svga_write(uint32_t addr, uint8_t val, void *priv) count = 4; - switch (svga->writemode) { + switch (svga->writemode) { case 0: val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { @@ -5696,17 +5725,17 @@ mach32_read_common(uint32_t addr, int linear, mach_t *mach, svga_t *svga) addr &= dev->vram_mask; if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { - switch (addr & 0x06) { + switch ((addr & 0x06) >> 1) { case 0x00: - case 0x06: + case 0x03: ret = dev->vram[addr] & 0x0f; ret |= (dev->vram[addr + 1] << 4); break; - case 0x02: + case 0x01: ret = dev->vram[addr + 2] & 0x0f; ret |= (dev->vram[addr + 3] << 4); break; - case 0x04: + case 0x02: ret = dev->vram[addr - 2] & 0x0f; ret |= (dev->vram[addr - 1] << 4); break; @@ -5800,24 +5829,24 @@ mach32_read(uint32_t addr, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t ret = 0x00; + uint8_t ret; (void) xga_read_test(addr, svga); addr = (addr & svga->banked_mask) + svga->read_bank; if ((ATI_MACH32 && !dev->vram_512k_8514) && ((mach->accel.ext_ge_config & 0x30) == 0x00)) { addr <<= 1; - switch (addr & 0x06) { + switch ((addr & 0x06) >> 1) { case 0x00: - case 0x06: + case 0x03: ret = mach32_read_common(addr, 0, mach, svga) & 0x0f; ret |= (mach32_read_common(addr + 1, 0, mach, svga) << 4); break; - case 0x02: + case 0x01: ret = mach32_read_common(addr + 2, 0, mach, svga) & 0x0f; ret |= (mach32_read_common(addr + 3, 0, mach, svga) << 4); break; - case 0x04: + case 0x02: ret = mach32_read_common(addr - 2, 0, mach, svga) & 0x0f; ret |= (mach32_read_common(addr - 1, 0, mach, svga) << 4); break; @@ -5958,7 +5987,8 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) uint16_t actual_port_ext = 0x02ee + (addr & 1) + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) { mach_log("Port WORDB Write=%04x.\n", actual_port_ext); mach_accel_outb(actual_port_ext, val, mach); @@ -5967,8 +5997,8 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_accel_outb(actual_port, val, mach); } } else { - mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr & dev->vram_mask, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); + mach_log("Linear WORDB Write=%08x, val=%02x, ON=%x, dpconfig=%04x, apsize=%08x, addr=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20, addr); if (dev->on) mach32_write_common(addr, val, 1, mach, svga); @@ -5988,17 +6018,19 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) { mach_log("Port WORDW Write=%04x, localcntl=%02x, pcicntl=%02x, actual addr=%08x, val=%04x.\n", actual_port_ext, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80, addr, val); mach_accel_outw(actual_port_ext, val, mach); } else { - mach_log("Port WORDW Write=%04x, localcntl=%02x, pcicntl=%02x, actual addr=%08x.\n", actual_port, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80, addr); + mach_log("Port WORDW Write=%04x, localcntl=%02x, pcicntl=%02x, actual addr=%08x, val=%04x.\n", actual_port, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80, addr, val); mach_accel_outw(actual_port, val, mach); } } else { - mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x, base=%08x, 8514/A port=%04x, ATI port=%04x, switch=%03x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20, mach->linear_base, actual_port, actual_port_ext, addr & 0x100); + mach_log("Linear WORDW Write=%08x, val=%04x, ON=%x, dpconfig=%04x, apsize=%08x, addr=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20, addr); + if (dev->on) mach32_writew_linear(addr, val, mach); else @@ -6016,11 +6048,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) uint16_t actual_port = 0x02e8 + (port_dword << 8); uint16_t actual_port_ext = 0x02ee + (port_dword << 8); - mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x.\n", - addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20); - if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) { mach_log("Port WORDL Write=%04x, localcntl=%02x, pcicntl=%02x.\n", actual_port_ext, mach->local_cntl & 0x20, mach->pci_cntl_reg & 0x80); mach_accel_outl(actual_port_ext, val, mach); @@ -6029,6 +6059,9 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outl(actual_port, val, mach); } } else { + mach_log("Linear WORDL Write=%08x, val=%08x, ON=%x, dpconfig=%04x, apsize=%08x, addr=%08x.\n", + addr - mach->linear_base, val, dev->on, mach->accel.dp_config, mach->ap_size << 20, addr); + if (dev->on) mach32_writel_linear(addr, val, mach); else @@ -6048,7 +6081,8 @@ mach32_ap_readb(uint32_t addr, void *priv) uint16_t actual_port_ext = 0x02ee + (addr & 1) + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) temp = mach_accel_inb(actual_port_ext, mach); else @@ -6077,7 +6111,8 @@ mach32_ap_readw(uint32_t addr, void *priv) uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) { temp = mach_accel_inw(actual_port_ext, mach); mach_log("Port WORDW Read=%04x.\n", actual_port_ext); @@ -6109,7 +6144,8 @@ mach32_ap_readl(uint32_t addr, void *priv) uint16_t actual_port_ext = 0x02ee + (port_dword << 8); if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && - (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20)))) { + (((addr - mach->linear_base) >= ((mach->ap_size << 20) - 0x200)) && ((addr - mach->linear_base) < (mach->ap_size << 20))) && + (svga->mapping.base == 0xa0000)) { if (addr & 0x100) { temp = mach_accel_inl(actual_port_ext, mach); mach_log("Port WORDL Read=%04x.\n", actual_port_ext); @@ -6149,32 +6185,18 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; - mem_mapping_set_addr(&mach->banked_mapping, 0xa0000, 0x20000); break; case 0x4: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; - mem_mapping_set_addr(&mach->banked_mapping, 0xa0000, 0x10000); break; case 0x8: /*32k at B0000*/ mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); svga->banked_mask = 0x7fff; - mem_mapping_set_addr(&mach->banked_mapping, 0xb0000, 0x08000); break; case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); svga->banked_mask = 0x7fff; - if (ATI_MACH32 && !(dev->accel.advfunc_cntl & 0x01) && !(mach->accel.clock_sel & 0x01)) { - if ((svga->gdcreg[6] & 0x01) || (svga->attrregs[0x10] & 0x01)) { - if (svga->attrregs[0x10] & 0x40) { - dev->vendor_mode = 0; - dev->on &= ~0x01; - mach_log("No 8514/A mode on b8000.\n"); - mach_set_resolution(mach, svga); - } - } - } - mem_mapping_set_addr(&mach->banked_mapping, 0xb8000, 0x08000); break; default: @@ -6205,16 +6227,16 @@ mach32_updatemapping(mach_t *mach, svga_t *svga) if (ATI_MACH32) { if (dev->on && dev->vendor_mode) { mach_log("Mach32 banked mapping.\n"); - mem_mapping_disable(&svga->mapping); - mem_mapping_enable(&mach->banked_mapping); + mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel); + mem_mapping_set_p(&svga->mapping, mach); } else { mach_log("IBM compatible banked mapping.\n"); - mem_mapping_enable(&svga->mapping); - mem_mapping_disable(&mach->banked_mapping); + mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, mach32_svga_write, mach32_svga_writew, mach32_svga_writel); + mem_mapping_set_p(&svga->mapping, svga); } } else { - mem_mapping_enable(&svga->mapping); - mem_mapping_disable(&mach->banked_mapping); + mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&svga->mapping, svga); } } @@ -6231,8 +6253,11 @@ mach32_hwcursor_draw(svga_t *svga, int displine) uint32_t *p; int x_pos; int y_pos; + int shift = 0; offset = dev->hwcursor_latch.x - dev->hwcursor_latch.xoff; + if (!dev->vram_512k_8514 && ((mach->accel.ext_ge_config & 0x30) == 0x00)) + shift = 1; mach_log("BPP=%d, displine=%d.\n", dev->accel_bpp, displine); switch (dev->accel_bpp) { @@ -6254,16 +6279,26 @@ mach32_hwcursor_draw(svga_t *svga, int displine) case 32: color0 = ((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0); color1 = ((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1); + mach_log("24/32BPP: Color0=%08x, Color1=%08x.\n", color0, color1); break; } if (dev->interlace && dev->hwcursor_oddeven) - dev->hwcursor_latch.addr += 16; + dev->hwcursor_latch.addr += (16 >> shift); - for (int x = 0; x < 64; x += 8) { - dat = dev->vram[dev->hwcursor_latch.addr & dev->vram_mask] | (dev->vram[(dev->hwcursor_latch.addr + 1) & dev->vram_mask] << 8); - - for (int xx = 0; xx < 8; xx++) { + for (int x = 0; x < 64; x += (8 >> shift)) { + if (shift) { + dat = dev->vram[(dev->hwcursor_latch.addr) & dev->vram_mask] & 0x0f; + dat |= (dev->vram[(dev->hwcursor_latch.addr + 1) & dev->vram_mask] << 4); + dat |= (dev->vram[(dev->hwcursor_latch.addr + 2) & dev->vram_mask] << 8); + dat |= (dev->vram[(dev->hwcursor_latch.addr + 3) & dev->vram_mask] << 12); + mach_log("4bpp Data=%04x.\n", dat); + } else { + dat = dev->vram[dev->hwcursor_latch.addr & dev->vram_mask]; + dat |= (dev->vram[(dev->hwcursor_latch.addr + 1) & dev->vram_mask] << 8); + mach_log("8bppplus Data=%04x.\n", dat); + } + for (int xx = 0; xx < (8 >> shift); xx++) { comb = (dat >> (xx << 1)) & 0x03; y_pos = displine; @@ -6293,7 +6328,7 @@ mach32_hwcursor_draw(svga_t *svga, int displine) } if (dev->interlace && !dev->hwcursor_oddeven) - dev->hwcursor_latch.addr += 16; + dev->hwcursor_latch.addr += (16 >> shift); } static void @@ -6923,20 +6958,20 @@ ati8514_accel_out_fifo(void *priv, uint16_t port, uint16_t val, int len) static void mach_disable_handlers(mach_t *mach) { - io_removehandler(0x01ce, 2, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); - io_removehandler(0x02ea, 4, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); - io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); - mach_io_remove(mach); + if (mach->pci_bus) { + io_removehandler(0x01ce, 2, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_removehandler(0x02ea, 4, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + io_removehandler(0x03c0, 32, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); + mach_io_remove(mach); + } mem_mapping_disable(&mach->mmio_linear_mapping); - mem_mapping_disable(&mach->banked_mapping); mem_mapping_disable(&mach->svga.mapping); if (mach->pci_bus && mach->has_bios) mem_mapping_disable(&mach->bios_rom.mapping); /* Save all the mappings and the timers because they are part of linked lists. */ reset_state->mmio_linear_mapping = mach->mmio_linear_mapping; - reset_state->banked_mapping = mach->banked_mapping; reset_state->svga.mapping = mach->svga.mapping; reset_state->bios_rom.mapping = mach->bios_rom.mapping; @@ -6951,6 +6986,10 @@ mach_reset(void *priv) ibm8514_t *dev = (ibm8514_t *) svga->dev8514; if (reset_state != NULL) { + dev->on = 0; + dev->vendor_mode = 0; + dev->_8514on = 0; + dev->_8514crt = 0; mach_disable_handlers(mach); mach->force_busy = 0; dev->force_busy = 0; @@ -7068,9 +7107,7 @@ mach8_init(const device_t *info) mach->config1 |= 0x0400; svga->clock_gen = device_add(&ati18811_1_device); } - mem_mapping_add(&mach->banked_mapping, 0, 0, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel, NULL, MEM_MAPPING_EXTERNAL, mach); mem_mapping_add(&mach->mmio_linear_mapping, 0, 0, mach32_ap_readb, mach32_ap_readw, mach32_ap_readl, mach32_ap_writeb, mach32_ap_writew, mach32_ap_writel, NULL, MEM_MAPPING_EXTERNAL, mach); - mem_mapping_disable(&mach->banked_mapping); mem_mapping_disable(&mach->mmio_linear_mapping); mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, mach32_svga_write, mach32_svga_writew, mach32_svga_writel); @@ -7096,7 +7133,7 @@ mach8_init(const device_t *info) svga->getclock = ics2494_getclock; dev->on = 0; - dev->ext_pitch = 1024; + dev->pitch = 1024; dev->ext_crt_pitch = 0x80; dev->accel_bpp = 8; svga->force_old_addr = 1; @@ -7158,7 +7195,7 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) /*Init as 1024x768 87hz interlaced first, per 8514/A.*/ dev->on = 0; - dev->ext_pitch = 1024; + dev->pitch = 1024; dev->ext_crt_pitch = 0x80; dev->accel_bpp = 8; dev->rowoffset = 0x80; @@ -7170,7 +7207,6 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) dev->disp_cntl = 0x33; mach->accel.clock_sel = 0x1c; mach->shadow_set = 0x02; - mach->crt_resolution = 0x02; dev->accel.cmd_back = 1; io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index d0189e0f7..67469ed22 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -776,9 +776,9 @@ svga_recalctimings(svga_t *svga) } if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) { /*40 column*/ + if (svga->seqregs[1] & 8) /*40 column*/ svga->render = svga_render_text_40; - } else + else svga->render = svga_render_text_80; if (xga_active && (svga->xga != NULL)) { @@ -981,7 +981,7 @@ svga_recalctimings(svga_t *svga) crtcconst = svga->clock * svga->char_width; if (ibm8514_active && (svga->dev8514 != NULL)) { if (dev->on) - crtcconst8514 = svga->clock8514; + crtcconst8514 = svga->clock_8514; } if (xga_active && (svga->xga != NULL)) { if (xga->on) From b7319cf60b6297803f3405c877b3a7b3474fe40f Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 22 Apr 2025 21:24:31 +0200 Subject: [PATCH 0790/1190] Fix warnings and build. --- src/video/vid_ati_mach8.c | 2 +- src/video/vid_chips_69000.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 3bcde5b0c..5cbd48623 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -5829,7 +5829,7 @@ mach32_read(uint32_t addr, void *priv) mach_t *mach = (mach_t *) priv; svga_t *svga = &mach->svga; ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t ret; + uint8_t ret = 0x00; (void) xga_read_test(addr, svga); addr = (addr & svga->banked_mask) + svga->read_bank; diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index d06ab0484..c9830f0ed 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -2793,7 +2793,8 @@ chips_69000_disable_handlers(chips_69000_t *chips) reset_state->decrement_timer = chips->decrement_timer; reset_state->svga.timer = chips->svga.timer; - reset_state->svga.timer8514 = chips->svga.timer8514; + reset_state->svga.timer_8514 = chips->svga.timer_8514; + reset_state->svga.timer_xga = chips->svga.timer_xga; } static void From cdb01de6d4604b57fbb493877d9b6e75db3887d1 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 22 Apr 2025 21:33:21 +0200 Subject: [PATCH 0791/1190] Apply it to the virge too. --- src/video/vid_s3_virge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index cc0985c02..1b61c02d5 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -5109,7 +5109,8 @@ s3_virge_disable_handlers(virge_t *dev) reset_state->bios_rom.mapping = dev->bios_rom.mapping; reset_state->svga.timer = dev->svga.timer; - reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->svga.timer_8514 = dev->svga.timer_8514; + reset_state->svga.timer_xga = dev->svga.timer_xga; reset_state->irq_timer = dev->irq_timer; } From 571b0595debfb26093c1e6c3b27cbbdc94b4789b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 22 Apr 2025 21:44:56 +0200 Subject: [PATCH 0792/1190] sigh, apply it to the Bochs VBE virtual card too. --- src/video/vid_bochs_vbe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index 6dc015fb0..36185214c 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -344,7 +344,7 @@ bochs_vbe_recalctimings(svga_t* svga) svga->rowoffset = dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8)); svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); - svga->fullchange = 3; + svga->fullchange = 3; } if (svga->bpp == 4) @@ -708,7 +708,7 @@ bochs_vbe_disable_handlers(bochs_vbe_t *dev) reset_state->bios_rom.mapping = dev->bios_rom.mapping; reset_state->svga.timer = dev->svga.timer; - reset_state->svga.timer8514 = dev->svga.timer8514; + reset_state->svga.timer_8514 = dev->svga.timer_8514; } static void From 406588293ce2bea83bd83b746eb734ed32640946 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 22 Apr 2025 22:38:16 +0200 Subject: [PATCH 0793/1190] Load key bind defaults before loading the config, fixes saved key binds across emulator closures and reopenings. --- src/86box.c | 15 +++++++-------- src/config.c | 54 ++++++++++++++++++++++++---------------------------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/86box.c b/src/86box.c index cde98f5d8..57abb12a6 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1000,6 +1000,13 @@ usage: zip_global_init(); mo_global_init(); + /* Initialize the keyboard accelerator list with default values */ + for (int x = 0; x < NUM_ACCELS; x++) { + strcpy(acc_keys[x].name, def_acc_keys[x].name); + strcpy(acc_keys[x].desc, def_acc_keys[x].desc); + strcpy(acc_keys[x].seq, def_acc_keys[x].seq); + } + /* Load the configuration file. */ config_load(); @@ -1030,14 +1037,6 @@ usage: gdbstub_init(); - // Initialize the keyboard accelerator list with default values - for(int x=0;x Date: Wed, 23 Apr 2025 12:49:29 +0500 Subject: [PATCH 0794/1190] Fix cleared key bindings not being reloaded --- src/config.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/config.c b/src/config.c index 0de69de70..98923d9cf 100644 --- a/src/config.c +++ b/src/config.c @@ -1774,9 +1774,12 @@ load_keybinds(void) /* Now load values from config */ for (int x = 0; x < NUM_ACCELS; x++) { - p = ini_section_get_string(cat, acc_keys[x].name, "none"); + p = ini_section_get_string(cat, acc_keys[x].name, "default"); + /* Check if the binding was marked as cleared */ + if (strcmp(p, "none") == 0) + acc_keys[x].seq[0] = '\0'; /* If there's no binding in the file, leave it alone. */ - if (strcmp(p, "none") != 0) { + else if (strcmp(p, "default") != 0) { /* It would be ideal to validate whether the user entered a valid combo at this point, but the Qt method for testing that is @@ -2527,6 +2530,9 @@ save_keybinds(void) /* Has accelerator been changed from default? */ if (strcmp(def_acc_keys[x].seq, acc_keys[x].seq) == 0) ini_section_delete_var(cat, acc_keys[x].name); + /* Check for a cleared binding to avoid saving it as an empty string */ + else if (acc_keys[x].seq[0] == '\0') + ini_section_set_string(cat, acc_keys[x].name, "none"); else ini_section_set_string(cat, acc_keys[x].name, acc_keys[x].seq); } From 41a3e132ef75d86ae9566191cb82a033949ae19d Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 23 Apr 2025 12:56:20 +0500 Subject: [PATCH 0795/1190] Fix `QMetaObject::connectSlotsByName` warnings --- src/qt/qt_settingsinput.cpp | 17 ++++------------- src/qt/qt_settingsinput.hpp | 6 +++--- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 79225cb91..695dc43e9 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -79,15 +79,6 @@ SettingsInput::SettingsInput(QWidget *parent) refreshInputList(); - connect(ui->tableKeys, &QTableWidget::cellDoubleClicked, - this, &SettingsInput::on_tableKeys_doubleClicked); - - connect(ui->pushButtonBind, &QPushButton::clicked, - this, &SettingsInput::on_pushButtonBind_Clicked); - - connect(ui->pushButtonClearBind, &QPushButton::clicked, - this, &SettingsInput::on_pushButtonClearBind_Clicked); - onCurrentMachineChanged(machine); } @@ -194,7 +185,7 @@ SettingsInput::on_tableKeys_currentCellChanged(int currentRow, int currentColumn } void -SettingsInput::on_tableKeys_doubleClicked(int row, int col) +SettingsInput::on_tableKeys_cellDoubleClicked(int row, int col) { // Edit bind QTableWidgetItem *cell = ui->tableKeys->item(row,1); @@ -233,17 +224,17 @@ SettingsInput::on_tableKeys_doubleClicked(int row, int col) } void -SettingsInput::on_pushButtonBind_Clicked() +SettingsInput::on_pushButtonBind_clicked() { // Edit bind QTableWidgetItem *cell = ui->tableKeys->currentItem(); if (!cell) return; - on_tableKeys_doubleClicked(cell->row(), cell->column()); + on_tableKeys_cellDoubleClicked(cell->row(), cell->column()); } void -SettingsInput::on_pushButtonClearBind_Clicked() +SettingsInput::on_pushButtonClearBind_clicked() { // Wipe bind QTableWidgetItem *cell = ui->tableKeys->item(ui->tableKeys->currentRow(), 1); diff --git a/src/qt/qt_settingsinput.hpp b/src/qt/qt_settingsinput.hpp index ec7dc393b..742421f64 100644 --- a/src/qt/qt_settingsinput.hpp +++ b/src/qt/qt_settingsinput.hpp @@ -33,10 +33,10 @@ private slots: void on_pushButtonJoystick2_clicked(); void on_pushButtonJoystick3_clicked(); void on_pushButtonJoystick4_clicked(); - void on_tableKeys_doubleClicked(int row, int col); + void on_tableKeys_cellDoubleClicked(int row, int col); void on_tableKeys_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn); - void on_pushButtonBind_Clicked(); - void on_pushButtonClearBind_Clicked(); + void on_pushButtonBind_clicked(); + void on_pushButtonClearBind_clicked(); private: Ui::SettingsInput *ui; From b074c28d3d4929957319778073561869dc99d8ed Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 23 Apr 2025 16:07:41 +0600 Subject: [PATCH 0796/1190] DMA-based IDE writes are now reported properly --- src/disk/hdc_ide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index fe48bba6d..e1e12afcd 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2514,6 +2514,7 @@ ide_callback(void *priv) return; } else if (ret & 1) { /* DMA successful */ + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); ret = hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); @@ -2524,7 +2525,6 @@ ide_callback(void *priv) err = UNC_ERR; ide_irq_raise(ide); - ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } else { /* Bus master DMA error, abort the command. */ ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); From 531e6545be8ff3714536c8557e32948048fac637 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 23 Apr 2025 16:22:53 +0600 Subject: [PATCH 0797/1190] IDE: Report single sector writes properly for 28-bit Write commands --- src/disk/hdc_ide.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index e1e12afcd..d725b2ace 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2472,6 +2472,7 @@ ide_callback(void *priv) else if (!ide->tf->lba && (ide->cfg_spt == 0)) err = IDNF_ERR; else { + ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); ret = hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); ide_irq_raise(ide); ide->tf->secount--; @@ -2479,10 +2480,8 @@ ide_callback(void *priv) ide->tf->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide->tf->pos = 0; ide_next_sector(ide); - ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 1); } else { ide->tf->atastat = DRDY_STAT | DSC_STAT; - ui_sb_update_icon_write(SB_HDD | hdd[ide->hdd_num].bus_type, 0); } if (ret < 0) err = UNC_ERR; From 17eeea1fd516274a2d952d6526edd67f0b8046b9 Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:24:43 +0300 Subject: [PATCH 0798/1190] Update the Russian translation Update the Russian translation --- src/qt/languages/ru-RU.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index baf1035ea..ebc71bb1b 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1618,7 +1618,7 @@ msgid "CODEC" msgstr "Кодек" msgid "Raise CODEC interrupt on CODEC setup (needed by some drivers)" -msgstr "Поднимать прерывание кодека при настройке кодека (необходимо некоторым драйверам)." +msgstr "Поднимать прерывание кодека при настройке кодека (необходимо некоторым драйверам)" msgid "SB Address" msgstr "Адрес SB" @@ -1885,7 +1885,7 @@ msgid "Color (generic)" msgstr "Цветной (стандартный)" msgid "Green Monochrome" -msgstr "Зеленый монохромный" +msgstr "Зелёный монохромный" msgid "Amber Monochrome" msgstr "Янтарный монохромный" From 191503e5292ff2e48083ac238a0932b2dcd0b684 Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:30:11 +0300 Subject: [PATCH 0799/1190] Update the Russian translation Update the Russian translation --- src/qt/languages/ru-RU.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index ebc71bb1b..b1c6cf22b 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2059,22 +2059,22 @@ msgid "[Generic] 1989 (3500 RPM)" msgstr "[Стандартный] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "[Стандартный] 1989 (3500 RPM)" +msgstr "[Стандартный] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "Клон IBM 8514/A (ISA)" From 1c12b8c68fcaf7ba4c61c871b2b218fe8f91dc9e Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:31:20 +0300 Subject: [PATCH 0800/1190] Fixes for broken translation Fixes for broken translation --- src/qt/qt_keybind.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_keybind.cpp b/src/qt/qt_keybind.cpp index 8b0f52eab..c7ed894b3 100644 --- a/src/qt/qt_keybind.cpp +++ b/src/qt/qt_keybind.cpp @@ -88,7 +88,7 @@ QKeySequence KeyBinder::BindKey(QWidget* widget, QString CurValue) { KeyBinder kb(widget); - kb.setWindowTitle("Bind Key"); + kb.setWindowTitle(tr("Bind Key")); kb.setFixedSize(kb.minimumSizeHint()); kb.findChild()->setKeySequence(QKeySequence::fromString(CurValue)); kb.setEnabled(true); From d3f32a52f4bbee0e13780ea6b7a00b1147019c03 Mon Sep 17 00:00:00 2001 From: usergithub64 <58270614+usergithub64@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:32:21 +0300 Subject: [PATCH 0801/1190] Update the Russian translation Update the Russian translation --- src/qt/languages/ru-RU.po | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index b1c6cf22b..e88f4f0fc 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -2162,3 +2162,45 @@ msgstr "Вниз" msgid "Could not load file %1" msgstr "Не удалось загрузить файл %1" + +msgid "Key Bindings:" +msgstr "Привязки клавиш:" + +msgid "Action" +msgstr "Действие" + +msgid "Keybind" +msgstr "Привязка клавиш" + +msgid "Clear binding" +msgstr "Очистить привязку" + +msgid "Bind" +msgstr "Привязка" + +msgid "Bind Key" +msgstr "Привязать клавишу" + +msgid "Enter key combo:" +msgstr "Введите комбинацию клавиш:" + +msgid "Send Control+Alt+Del" +msgstr "Отправить Control+Alt+Del" + +msgid "Send Control+Alt+Escape" +msgstr "Отправить Control+Alt+Escape" + +msgid "Toggle fullscreen" +msgstr "Переключить на полноэкранный режим" + +msgid "Screenshot" +msgstr "Скриншот" + +msgid "Release mouse pointer" +msgstr "Отпустить указатель мыши" + +msgid "Toggle pause" +msgstr "Переключить паузу" + +msgid "Toggle mute" +msgstr "Переключить беззвучный режим" \ No newline at end of file From 57d5bb76282175db1876c49de5d1cfe0e558ba53 Mon Sep 17 00:00:00 2001 From: sharkbyte16 <87238812+sharkbyte16@users.noreply.github.com> Date: Sat, 26 Apr 2025 12:08:37 +0200 Subject: [PATCH 0802/1190] Update nl-NL.po --- src/qt/languages/nl-NL.po | 86 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 8ee391957..49a32506b 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -112,7 +112,7 @@ msgid "Hi&DPI scaling" msgstr "Hi&DPI-schaling" msgid "&Fullscreen" -msgstr "&Fullscreen" +msgstr "&Volledig scherm" msgid "Fullscreen &stretch mode" msgstr "Volledig scherm &uitrekmodus" @@ -670,16 +670,16 @@ msgid "Surface images" msgstr "Oppervlakte-images" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." -msgstr "Machine \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/machines. Overschakelen naar een beschikbare machine." +msgstr "Machine \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/machines. Er wordt overgeschakeld naar een beschikbare machine." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "Videokaart \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Overschakel over naar een beschikbare videokaart." +msgstr "Videokaart \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Er wordt overgeschakeld naar een beschikbare videokaart." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Videokaart #2 \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. Uitschakel de tweede videokaart." +msgstr "Videokaart #2 \"%hs\" is niet beschikbaar door ontbrekende ROMs in de map roms/video. De tweede videokaart wordt uitgeschakeld." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Het apparaat \"%hs\" is niet beschikbaar door ontbrekende ROMs. Negeer het apparaat." +msgstr "Het apparaat \"%hs\" is niet beschikbaar door ontbrekende ROMs. Het apparaat wordt genegeerd." msgid "Machine" msgstr "Machine" @@ -1018,7 +1018,7 @@ msgid "Differencing VHD" msgstr "Verschil-VHD" msgid "(N/A)" -msgstr "(N/A)" +msgstr "(N/B)" msgid "Raw image (.img)" msgstr "Ruw image (.img)" @@ -1054,7 +1054,7 @@ msgid "This could mean that the parent image was modified after the differencing msgstr "Dit kan betekenen dat de bovenliggende image is gewijzigd nadat de verschil-image is gemaakt.\n\nDit kan ook gebeuren als de imagebestanden zijn verplaatst of gekopieerd, of door een fout in het programma waarmee deze schijf is gemaakt.\n\nWil je de tijdstempels herstellen?" msgid "Parent and child disk timestamps do not match" -msgstr "Bovenliggende en onderliggende schijf tijdstempels komen niet overeen" +msgstr "Bovenliggende en onderliggende schijftijdstempels komen niet overeen" msgid "Could not fix VHD timestamp." msgstr "Kan VHD tijdstempel niet herstellen." @@ -1234,7 +1234,7 @@ msgid "Open screenshots folder..." msgstr "Map met schermafbeeldingen openen..." msgid "Apply fullscreen stretch mode when maximized" -msgstr "Pas fullscreen stretchmodus toe wanneer gemaximaliseerd" +msgstr "Schakel de volledig scherm-uitrekmodus in bij maximaliseren" msgid "Cursor/Puck" msgstr "Cursor/Puck" @@ -1291,7 +1291,7 @@ msgid "Browse..." msgstr "Bladeren..." msgid "Couldn't create OpenGL context." -msgstr "Kan OpenGL context niet maken." +msgstr "Kan OpenGL context niet aanmaken." msgid "Couldn't switch to OpenGL context." msgstr "Kan niet overschakelen naar OpenGL context." @@ -1444,7 +1444,7 @@ msgid "Enable backlight" msgstr "Backlight inschakelen" msgid "Invert colors" -msgstr "Kleuren omkeren" +msgstr "Kleuren inverteren" msgid "BIOS size" msgstr "BIOS-grootte" @@ -1810,7 +1810,7 @@ msgid "Five + Wheel" msgstr "Vijf + Wiel" msgid "Five + 2 Wheels" -msgstr "" +msgstr "Vijf + 2 Wielen" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serieel / SMT3(R)V" @@ -1957,13 +1957,13 @@ msgid "Bochs latest" msgstr "Bochs nieuwste" msgid "Mono Non-Interlaced" -msgstr "Mono Non-Interlaced" +msgstr "Mono niet geïnterlaced" msgid "Color Interlaced" msgstr "Kleur interlaced" msgid "Color Non-Interlaced" -msgstr "Kleur non-interlaced" +msgstr "Kleur niet geïnterlaced" msgid "3Dfx Voodoo Graphics" msgstr "3Dfx Voodoo Graphics" @@ -2053,34 +2053,34 @@ msgid "High performance impact" msgstr "Hoge prestatie-impact" msgid "[Generic] RAM Disk (max. speed)" -msgstr "[Generic] RAM-schijf (max. snelheid)" +msgstr "[Generiek] RAM-schijf (max. snelheid)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "" +msgstr "[Generiek] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "" +msgstr "[Generiek] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "" +msgstr "[Generiek] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "" +msgstr "[Generiek] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "" +msgstr "[Generiek] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "" +msgstr "[Generiek] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "" +msgstr "[Generiek] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A-kloon (ISA)" msgid "Vendor" -msgstr "Verkoper" +msgstr "Leverancier" msgid "Generic PC/XT Memory Expansion" msgstr "Generieke PC/XT geheugenuitbreiding" @@ -2095,64 +2095,64 @@ msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for t msgstr "TrueType lettertypen in de map \"roms/printer/fonts\" zijn nodig voor de emulatie van de generieke ESC/P dot-matrix-printer." msgid "Inhibit multimedia keys" -msgstr "" +msgstr "Multimedia-toetsen blokkeren" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "Vraag om bevestiging voor het opslaan van instellingen" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "Vraag om bevestiging voor een harde reset" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "Vraag om bevestiging voor afsluiten" msgid "Display hotkey message when entering full-screen mode" -msgstr "" +msgstr "Toon een sneltoetsmelding bij het openen van de volledigschermmodus" msgid "Options" -msgstr "" +msgstr "Opties" msgid "Model" -msgstr "" +msgstr "Model" msgid "Model:" -msgstr "" +msgstr "Model:" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Initialisatie van de Vulkan-renderer is mislukt." msgid "GLSL Error" -msgstr "" +msgstr "GLSL-fout" msgid "Could not load shader: %1" -msgstr "" +msgstr "Kon de shader niet laden: %1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "OpenGL versie 3.0 of hoger is vereist. Huidige GLSL-versie is %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "Kon de textuur niet laden: %1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "Kon de shader niet compileren:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "Programma niet gelinkt:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "Shaderbeheer" msgid "Shader Configuration" -msgstr "" +msgstr "Shaderconfiguratie" msgid "Add" -msgstr "" +msgstr "Toevoegen" msgid "Move up" -msgstr "" +msgstr "Omhoog verplaatsen" msgid "Move down" -msgstr "" +msgstr "Omlaag verplaatsen" msgid "Could not load file %1" -msgstr "" +msgstr "Kon bestand %1 niet laden" From 34e017bbf4c1af21c2cc86705140d6cc3680f9b9 Mon Sep 17 00:00:00 2001 From: sharkbyte16 <87238812+sharkbyte16@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:03:37 +0200 Subject: [PATCH 0803/1190] Add cmake linux clang and intel Add cmake files for x86_64 linux clang and intel compilers. --- cmake/intel-linux-x86_64.cmake | 20 ++++++++++++++++++++ cmake/llvm-linux-x86_64.cmake | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 cmake/intel-linux-x86_64.cmake create mode 100644 cmake/llvm-linux-x86_64.cmake diff --git a/cmake/intel-linux-x86_64.cmake b/cmake/intel-linux-x86_64.cmake new file mode 100644 index 000000000..a0c3e5d0b --- /dev/null +++ b/cmake/intel-linux-x86_64.cmake @@ -0,0 +1,20 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# CMake toolchain file defining GCC compiler flags +# for 64-bit x86 targets. +# +# Authors: David Hrdlička, +# +# Copyright 2021 David Hrdlička. +# + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc-x86_64.cmake) + +set(CMAKE_C_COMPILER icx) +set(CMAKE_CXX_COMPILER icpx) diff --git a/cmake/llvm-linux-x86_64.cmake b/cmake/llvm-linux-x86_64.cmake new file mode 100644 index 000000000..ccdd7b18e --- /dev/null +++ b/cmake/llvm-linux-x86_64.cmake @@ -0,0 +1,23 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# CMake toolchain file defining Clang compiler flags +# for 64-bit x86 targets. +# +# Authors: David Hrdlička, +# dob205 +# +# Copyright 2021 David Hrdlička. +# Copyright 2022 dob205. +# + +include(${CMAKE_CURRENT_LIST_DIR}/flags-gcc-x86_64.cmake) + +# Use the GCC-compatible Clang executables in order to use our flags +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) From e076c1051d9cd43936dc170857b24cb99a574a75 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 26 Apr 2025 23:17:32 +0600 Subject: [PATCH 0804/1190] Fix x87_op being outside of structure, fixing crashes in ARM64 NDR --- src/codegen_new/codegen.h | 1 + src/codegen_new/codegen_block.c | 1 + src/codegen_new/codegen_reg.c | 14 ++++++++++++++ src/cpu/386_common.c | 2 -- src/cpu/cpu.h | 4 +++- src/cpu/x86.c | 1 + 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/codegen_new/codegen.h b/src/codegen_new/codegen.h index eecfa249b..0ff6a90d6 100644 --- a/src/codegen_new/codegen.h +++ b/src/codegen_new/codegen.h @@ -306,6 +306,7 @@ struct ir_data_t; x86seg *codegen_generate_ea(struct ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset); extern void codegen_check_seg_read(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); extern void codegen_check_seg_write(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); +extern void codegen_check_regs(void); extern int codegen_purge_purgable_list(void); /*Delete a random code block to free memory. This is obviously quite expensive, and diff --git a/src/codegen_new/codegen_block.c b/src/codegen_new/codegen_block.c index a8ea0e06e..ff82384be 100644 --- a/src/codegen_new/codegen_block.c +++ b/src/codegen_new/codegen_block.c @@ -217,6 +217,7 @@ block_free_list_get(void) void codegen_init(void) { + codegen_check_regs(); codegen_allocator_init(); codegen_backend_init(); diff --git a/src/codegen_new/codegen_reg.c b/src/codegen_new/codegen_reg.c index ba60ab038..75cf25ded 100644 --- a/src/codegen_new/codegen_reg.c +++ b/src/codegen_new/codegen_reg.c @@ -226,6 +226,20 @@ reg_is_native_size(ir_reg_t ir_reg) return 0; } +void +codegen_check_regs(void) +{ + int i = 0; + for (i = 0; i < IREG_COUNT; i++) { + if (ireg_data[i].is_volatile == REG_VOLATILE) + continue; + + if (ireg_data[i].p && ((uintptr_t)ireg_data[i].p - (uintptr_t)&cpu_state) >= sizeof(cpu_state)) { + fatal("Register number %d outside cpu_state!\n", i); + } + } +} + void codegen_reg_reset(void) { diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index c6a759d36..2853e3c9a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -113,8 +113,6 @@ uint8_t is_smint = 0; uint16_t io_port = 0x0000; uint32_t io_val = 0x00000000; -uint32_t x87_op = 0x00000000; - int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b76e2d622..b6f5f593c 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -416,6 +416,8 @@ typedef struct { uint16_t eflags; uint32_t _smbase; + + uint32_t x87_op; } cpu_state_t; #define in_smm cpu_state._in_smm @@ -784,7 +786,7 @@ typedef struct { uint32_t smhr; } cyrix_t; -extern uint32_t x87_op; +#define x87_op cpu_state.x87_op extern uint32_t addr64; extern uint32_t addr64_2; diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 97ae19f3a..a8ab9d866 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -272,6 +272,7 @@ reset_common(int hard) msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); msw = 0; new_ne = 0; + x87_op = 0; ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = ccr7 = 0; ccr4 = 0x85; From 2424e848a7c7ab03671f5b65c599674b830ad6b4 Mon Sep 17 00:00:00 2001 From: Nelson Kerber Hennemann Filho <87081197+nelsonhef@users.noreply.github.com> Date: Sat, 26 Apr 2025 15:27:14 -0300 Subject: [PATCH 0805/1190] Update pt-BR.po Some fixes and added missing translations --- src/qt/languages/pt-BR.po | 86 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 8961f11b8..a3e98b625 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -631,7 +631,7 @@ msgid " - PAUSED" msgstr " - PAUSADO" msgid "Press %s to return to windowed mode." -msgstr "Use %s para retornar ao modo janela" +msgstr "Use %s para retornar ao modo janela." msgid "Speed" msgstr "Velocidade" @@ -847,7 +847,7 @@ msgid "86Box v" msgstr "86Box versão" msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." -msgstr "Um emulador de computadores antigos\n\nAutores: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, e outros.\n\nCom contribuições anteriores de Sarah Walker, leilei, JohnElliott, greatpsycho, e outros.\n\nTraduzido por: Altieres Lima da Silva\n\nLançado sob a Licença Pública Geral GNU, versão 2 ou posterior. Veja o arquivo LICENSE para mais informações." +msgstr "Um emulador de computadores antigos\n\nAutores: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, e outros.\n\nCom contribuições anteriores de Sarah Walker, leilei, JohnElliott, greatpsycho, e outros.\n\nTraduzido por: Altieres Lima da Silva, Nelson K. Hennemann Filho\n\nLançado sob a Licença Pública Geral GNU, versão 2 ou posterior. Veja o arquivo LICENSE para mais informações." msgid "Hardware not available" msgstr "Hardware não disponível" @@ -967,13 +967,13 @@ msgid "HDI or HDX images with a sector size other than 512 are not supported." msgstr "Imagens HDI ou HDX com um tamanho de setor que não seja 512 não são suportadas." msgid "Disk image file already exists" -msgstr "Esta imagem existe" +msgstr "A imagem de disco já existe" msgid "Please specify a valid file name." msgstr "Digite um nome de arquivo válido." msgid "Disk image created" -msgstr "A imagem foi criada com sucesso" +msgstr "A imagem de disco foi criada" msgid "Make sure the file exists and is readable." msgstr "Certifique-se de que o arquivo existe e é legível." @@ -982,7 +982,7 @@ msgid "Make sure the file is being saved to a writable directory." msgstr "Certifique-se de que o arquivo está sendo salvo em um diretório gravável." msgid "Disk image too large" -msgstr "A imagem do disco é muito grande" +msgstr "A imagem de disco é muito grande" msgid "Remember to partition and format the newly-created drive." msgstr "Lembre-se de particionar e formatar a unidade recém-criada." @@ -1312,16 +1312,16 @@ msgid "This machine might have been moved or copied." msgstr "Essa máquina pode ter sido movida ou copiada." msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." -msgstr "Para garantir a funcionalidade adequada da rede, o 86Box precisa saber se essa máquina foi movida ou copiada.\n\nSelecione \"A copiei\" se não tiver certeza." +msgstr "Para garantir a funcionalidade adequada da rede, o 86Box precisa saber se essa máquina foi movida ou copiada.\n\nSelecione \"Copiei\" se não tiver certeza." msgid "I Moved It" -msgstr "O movi" +msgstr "Movi" msgid "I Copied It" -msgstr "A copiei" +msgstr "Copiei" msgid "86Box Monitor #" -msgstr "Monitor 86Box " +msgstr "Monitor 86Box #" msgid "No MCA devices." msgstr "Nenhum dispositivo MCA." @@ -1483,7 +1483,7 @@ msgid "MIDI Clockout" msgstr "Saída do relógio MIDI" msgid "SoundFont" -msgstr "Fonte de som" +msgstr "SoundFont" msgid "Output Gain" msgstr "Ganho de saída" @@ -1789,7 +1789,7 @@ msgid "4th Order" msgstr "De 4ª ordem" msgid "7th Order" -msgstr "De 7º order" +msgstr "De 7ª order" msgid "Non-timed (original)" msgstr "Sem cronômetro (original)" @@ -1807,10 +1807,10 @@ msgid "Wheel" msgstr "Roda" msgid "Five + Wheel" -msgstr "Cinco + roda" +msgstr "Cinco + Roda" msgid "Five + 2 Wheels" -msgstr "" +msgstr "Cinco + 2 Rodas" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 Serial / SMT3(R)V" @@ -2035,7 +2035,7 @@ msgid "Baud Rate of Passthrough" msgstr "Taxa de transmissão de passagem" msgid "Named Pipe (Server)" -msgstr "Tubo nomeado (servidor)" +msgstr "Pipe nomeado (servidor)" msgid "Host Serial Passthrough" msgstr "Passagem da porta serial do host" @@ -2053,28 +2053,28 @@ msgid "High performance impact" msgstr "Alto impacto no desempenho" msgid "[Generic] RAM Disk (max. speed)" -msgstr "[Generic] Disco RAM (velocidade máxima)" +msgstr "[Genérico] Disco RAM (velocidade máxima)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "" +msgstr "[Genérico] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "" +msgstr "[Genérico] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "" +msgstr "[Genérico] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "" +msgstr "[Genérico] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "" +msgstr "[Genérico] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "" +msgstr "[Genérico] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "" +msgstr "[Genérico] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" @@ -2095,64 +2095,64 @@ msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for t msgstr "As fontes TrueType no diretório \"roms/printer/fonts\" são necessárias para a emulação da impressora matricial de pontos ESC/P genérica." msgid "Inhibit multimedia keys" -msgstr "" +msgstr "Inibir teclas multimídia" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "Perguntar antes de salvar configurações" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "Perguntar antes de reinicialização completa" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "Perguntar antes de sair" msgid "Display hotkey message when entering full-screen mode" -msgstr "" +msgstr "Mostrar mensagem de atalho quando entrar em tela cheia" msgid "Options" -msgstr "" +msgstr "Opções" msgid "Model" -msgstr "" +msgstr "Modelo" msgid "Model:" -msgstr "" +msgstr "Modelo:" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Falha ao inicializar o renderizador Vulkan." msgid "GLSL Error" -msgstr "" +msgstr "Erro GLSL" msgid "Could not load shader: %1" -msgstr "" +msgstr "Impossível carregar o shader: %1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "OpenGL versão 3.0 ou superior é exigido. Versão atual GLSL é %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "Impossível carregar a textura: %1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "Impossível compilar o shader:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "Programa não linkado:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "Gerenciador de Shader" msgid "Shader Configuration" -msgstr "" +msgstr "Configuração de Shader" msgid "Add" -msgstr "" +msgstr "Adicionar" msgid "Move up" -msgstr "" +msgstr "Mover para cima" msgid "Move down" -msgstr "" +msgstr "Mover para baixo" msgid "Could not load file %1" -msgstr "" +msgstr "Impossível carregar arquivo %1" From 388fcb3046b19eef209620b6920a8635e835d433 Mon Sep 17 00:00:00 2001 From: Nelson Kerber Hennemann Filho <87081197+nelsonhef@users.noreply.github.com> Date: Sat, 26 Apr 2025 15:36:47 -0300 Subject: [PATCH 0806/1190] Update 2 pt-BR.po Added strings and translations for the new key bindings settings --- src/qt/languages/pt-BR.po | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index a3e98b625..4f06e0d85 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -2156,3 +2156,45 @@ msgstr "Mover para baixo" msgid "Could not load file %1" msgstr "Impossível carregar arquivo %1" + +msgid "Key Bindings:" +msgstr "Atalhos:" + +msgid "Action" +msgstr "Ação" + +msgid "Keybind" +msgstr "Atalho" + +msgid "Clear binding" +msgstr "Limpar atalho" + +msgid "Bind" +msgstr "Vincular" + +msgid "Bind Key" +msgstr "Vincular tecla" + +msgid "Enter key combo:" +msgstr "Pressione combinação de teclas:" + +msgid "Send Control+Alt+Del" +msgstr "Enviar Control+Alt+Del" + +msgid "Send Control+Alt+Escape" +msgstr "Enviar Control+Alt+Escape" + +msgid "Toggle fullscreen" +msgstr "Alternar tela cheia" + +msgid "Screenshot" +msgstr "Captura de tela" + +msgid "Release mouse pointer" +msgstr "Liberar ponteiro do mouse" + +msgid "Toggle pause" +msgstr "Alternar pausa" + +msgid "Toggle mute" +msgstr "Alternar mudo" From 98e3cdf1cf24f18ccc293806082146aa5b71b2e8 Mon Sep 17 00:00:00 2001 From: Nelson Kerber Hennemann Filho <87081197+nelsonhef@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:18:31 -0300 Subject: [PATCH 0807/1190] Update 3 pt-BR.po Fix minor typo --- src/qt/languages/pt-BR.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 4f06e0d85..e33630ccf 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -1789,7 +1789,7 @@ msgid "4th Order" msgstr "De 4ª ordem" msgid "7th Order" -msgstr "De 7ª order" +msgstr "De 7ª ordem" msgid "Non-timed (original)" msgstr "Sem cronômetro (original)" From f563b73768b8705d1adb21db98f635276fe24b7e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 27 Apr 2025 17:52:53 +0200 Subject: [PATCH 0808/1190] Warn on deprecated usage. --- src/86box.c | 98 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/src/86box.c b/src/86box.c index 57abb12a6..66d9afa00 100644 --- a/src/86box.c +++ b/src/86box.c @@ -586,6 +586,55 @@ delete_nvr_file(uint8_t flash) extern void device_find_all_descs(void); +static void +pc_show_usage(char *s) +{ + char p[4096] = { 0 }; + + sprintf(p, + "\n%sUsage: 86box [options] [cfg-file]\n\n" + "Valid options are:\n\n" + "-? or --help\t\t\t- show this information\n" + "-C or --config path\t\t- set 'path' to be config file\n" +#ifdef _WIN32 + "-D or --debug\t\t\t- force debug output logging\n" +#endif +#if 0 + "-E or --nographic\t\t- forces the old behavior\n" +#endif + "-F or --fullscreen\t\t- start in fullscreen mode\n" + "-G or --lang langid\t\t- start with specified language\n" + "\t\t\t\t (e.g. en-US, or system)\n" +#ifdef _WIN32 + "-H or --hwnd id,hwnd\t\t- sends back the main dialog's hwnd\n" +#endif + "-I or --image d:path\t\t- load 'path' as floppy image on drive d\n" +#ifdef USE_INSTRUMENT + "-J or --instrument name\t- set 'name' to be the profiling instrument\n" +#endif + "-L or --logfile pat\t\t- set 'path' to be the logfile\n" + "-M or --missing\t\t- dump missing machines and video cards\n" + "-N or --noconfirm\t\t- do not ask for confirmation on quit\n" + "-P or --vmpath path\t\t- set 'path' to be root for vm\n" + "-R or --rompath path\t\t- set 'path' to be ROM path\n" +#ifndef USE_SDL_UI + "-S or --settings\t\t\t- show only the settings dialog\n" +#endif + "-T or --testmode\t\t- test mode: execute the test mode entry\n" + "\t\t\t\t point on init/hard reset\n" + "-V or --vmname name\t\t- overrides the name of the running VM\n" + "-W or --nohook\t\t- disables keyboard hook\n" + "\t\t\t\t (compatibility-only outside Windows)\n" + "-X or --clear what\t\t- clears the 'what' (cmos/flash/both)\n" + "-Y or --donothing\t\t- do not show any UI or run the emulation\n" + "-Z or --lastvmpath\t\t- the last parameter is VM path rather\n" + "\t\t\t\t than config\n" + "\nA config file can be specified. If none is, the default file will be used.\n", + (s == NULL) ? "" : s); + + ui_msgbox(MBX_ANSI | ((s == NULL) ? MBX_INFO : MBX_WARNING), p); +} + /* * Perform initial startup of the PC. * @@ -609,6 +658,7 @@ pc_init(int argc, char *argv[]) time_t now; int c; int lvmp = 0; + int deprecated = 1; #ifdef ENABLE_NG int ng = 0; #endif @@ -666,44 +716,7 @@ usage: } } - ui_msgbox(MBX_INFO, L"\nUsage: 86box [options] [cfg-file]\n\n" - "Valid options are:\n\n" - "-? or --help\t\t\t- show this information\n" - "-C or --config path\t\t- set 'path' to be config file\n" -#ifdef _WIN32 - "-D or --debug\t\t\t- force debug output logging\n" -#endif -#if 0 - "-E or --nographic\t\t- forces the old behavior\n" -#endif - "-F or --fullscreen\t\t- start in fullscreen mode\n" - "-G or --lang langid\t\t- start with specified language\n" - "\t\t\t\t (e.g. en-US, or system)\n" -#ifdef _WIN32 - "-H or --hwnd id,hwnd\t\t- sends back the main dialog's hwnd\n" -#endif - "-I or --image d:path\t\t- load 'path' as floppy image on drive d\n" -#ifdef USE_INSTRUMENT - "-J or --instrument name\t- set 'name' to be the profiling instrument\n" -#endif - "-L or --logfile pat\t\t- set 'path' to be the logfile\n" - "-M or --missing\t\t- dump missing machines and video cards\n" - "-N or --noconfirm\t\t- do not ask for confirmation on quit\n" - "-P or --vmpath path\t\t- set 'path' to be root for vm\n" - "-R or --rompath path\t\t- set 'path' to be ROM path\n" -#ifndef USE_SDL_UI - "-S or --settings\t\t\t- show only the settings dialog\n" -#endif - "-T or --testmode\t\t- test mode: execute the test mode entry\n" - "\t\t\t\t point on init/hard reset\n" - "-V or --vmname name\t\t- overrides the name of the running VM\n" - "-W or --nohook\t\t- disables keyboard hook\n" - "\t\t\t\t (compatibility-only outside Windows)\n" - "-X or --clear what\t\t- clears the 'what' (cmos/flash/both)\n" - "-Y or --donothing\t\t- do not show any UI or run the emulation\n" - "-Z or --lastvmpath\t\t- the last parameter is VM path rather\n" - "\t\t\t\t than config\n" - "\nA config file can be specified. If none is, the default file will be used.\n"); + pc_show_usage(NULL); return 0; } else if (!strcasecmp(argv[c], "--lastvmpath") || !strcasecmp(argv[c], "-Z")) { lvmp = 1; @@ -730,6 +743,7 @@ usage: goto usage; ppath = argv[++c]; + deprecated = 0; } else if (!strcasecmp(argv[c], "--rompath") || !strcasecmp(argv[c], "-R")) { if ((c + 1) == argc) goto usage; @@ -741,6 +755,7 @@ usage: goto usage; cfg = argv[++c]; + deprecated = 0; } else if (!strcasecmp(argv[c], "--image") || !strcasecmp(argv[c], "-I")) { if ((c + 1) == argc) goto usage; @@ -839,11 +854,18 @@ usage: ppath = argv[c++]; else cfg = argv[c++]; + + deprecated = 0; } if (c != argc) goto usage; + if (deprecated) + pc_show_usage("Running 86Box without a specified VM path and/or configuration\n" + "file has been deprected. Please specify one or use a manager\n" + "(Avalonia 86 is recommended).\n\n"); + path_slash(usr_path); path_slash(rom_path); From 5b4db319bf53e0984568c168fc56e090597846d1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 27 Apr 2025 18:50:45 +0200 Subject: [PATCH 0809/1190] Opcode D6 is now an alias of opcode D7 (XLAT) on NEC Vx0, closes #5516. --- src/cpu/808x.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index e98b7de3d..be0d5e6cc 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -3438,10 +3438,13 @@ execx86(int cycs) set_pzs(8); break; case 0xD6: /*SALC*/ - wait(1, 0); - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait(1, 0); - break; + if (!is_nec) { + wait(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + } + fallthrough; case 0xD7: /*XLATB*/ cpu_state.eaaddr = (BX + AL) & 0xffff; access(4, 8); From 9b93e71b23f9e0f539387ce22c72e0d5ab3c68ce Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 27 Apr 2025 18:57:21 +0200 Subject: [PATCH 0810/1190] #included the missing plat_fallthrough.h. --- src/cpu/808x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index be0d5e6cc..dda688ee1 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -38,6 +38,7 @@ #include <86box/ppi.h> #include <86box/timer.h> #include <86box/gdbstub.h> +#include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> /* Is the CPU 8088 or 8086. */ From d0f682ea08ceed2726fe3ee3eb6a604c50795470 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 28 Apr 2025 04:37:58 +0200 Subject: [PATCH 0811/1190] Print help to console on non-Windows OS'es unless it's the deprecaption warning. --- src/86box.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/86box.c b/src/86box.c index 66d9afa00..d96a571c0 100644 --- a/src/86box.c +++ b/src/86box.c @@ -632,7 +632,14 @@ pc_show_usage(char *s) "\nA config file can be specified. If none is, the default file will be used.\n", (s == NULL) ? "" : s); +#ifdef _WIN32 ui_msgbox(MBX_ANSI | ((s == NULL) ? MBX_INFO : MBX_WARNING), p); +#else + if (s == NULL) + pclog(p); + else + ui_msgbox(MBX_ANSI | MBX_WARNING, p); +#endif } /* From 94a68a869834ec92a16b66fb7ee38c31a4cb7be5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 28 Apr 2025 14:26:49 +0600 Subject: [PATCH 0812/1190] Add Mouse Systems Bus Mouse --- src/device/mouse.c | 27 ++++++----- src/device/mouse_serial.c | 97 +++++++++++++++++++++++++++++++++++--- src/device/serial.c | 31 ++++++++---- src/include/86box/mouse.h | 2 + src/include/86box/serial.h | 2 +- 5 files changed, 130 insertions(+), 29 deletions(-) diff --git a/src/device/mouse.c b/src/device/mouse.c index f7d8c9861..0bf87934d 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -83,23 +83,24 @@ static const device_t mouse_internal_device = { static mouse_t mouse_devices[] = { // clang-format off - { &mouse_none_device }, - { &mouse_internal_device }, - { &mouse_logibus_device }, - { &mouse_msinport_device }, + { &mouse_none_device }, + { &mouse_internal_device }, + { &mouse_logibus_device }, + { &mouse_msinport_device }, #ifdef USE_GENIBUS - { &mouse_genibus_device }, + { &mouse_genibus_device }, #endif - { &mouse_mssystems_device }, - { &mouse_msserial_device }, - { &mouse_ltserial_device }, - { &mouse_ps2_device }, + { &mouse_mssystems_device }, + { &mouse_mssystems_bus_device }, + { &mouse_msserial_device }, + { &mouse_ltserial_device }, + { &mouse_ps2_device }, #ifdef USE_WACOM - { &mouse_wacom_device }, - { &mouse_wacom_artpad_device }, + { &mouse_wacom_device }, + { &mouse_wacom_artpad_device }, #endif - { &mouse_mtouch_device }, - { NULL } + { &mouse_mtouch_device }, + { NULL } // clang-format on }; diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 8ed4865cd..24d7ae853 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -833,10 +833,6 @@ sermouse_close(void *priv) { mouse_t *dev = (mouse_t *) priv; - /* Detach serial port from the mouse. */ - if (dev && dev->serial && dev->serial->sd) - memset(dev->serial->sd, 0, sizeof(serial_device_t)); - free(dev); } @@ -849,6 +845,11 @@ sermouse_init(const device_t *info) void (*dev_write)(struct serial_s *serial, void *priv, uint8_t data); void (*transmit_period_callback)(struct serial_s *serial, void *priv, double transmit_period); + if (info->local == MOUSE_TYPE_MSYSTEMSB) { + uintptr_t irqbase = ((device_get_config_int("irq") << 16) | (device_get_config_hex16("addr") << 20)) | ns16450_device.local; + device_add_params(&ns16450_device, (void*)irqbase); + } + dev = (mouse_t *) calloc(1, sizeof(mouse_t)); dev->name = info->name; dev->but = device_get_config_int("buttons"); @@ -862,7 +863,7 @@ sermouse_init(const device_t *info) if (dev->but > 2) dev->flags |= FLAG_3BTN; - if (info->local == MOUSE_TYPE_MSYSTEMS) { + if (info->local == MOUSE_TYPE_MSYSTEMS || info->local == MOUSE_TYPE_MSYSTEMSB) { dev->format = 0; dev->type = info->local; dev->id_len = 1; @@ -893,7 +894,7 @@ sermouse_init(const device_t *info) } } - dev->port = device_get_config_int("port"); + dev->port = (info->local == MOUSE_TYPE_MSYSTEMSB) ? SERIAL_MAX : device_get_config_int("port"); /* Attach a serial port to the mouse. */ rcr_callback = dev->rts_toggle ? sermouse_callback : NULL; @@ -968,6 +969,76 @@ static const device_config_t msssermouse_config[] = { // clang-format on }; +static const device_config_t mssbusmouse_config[] = { + // clang-format off + { + .name = "addr", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x238, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x338", .value = 0x338 }, + { .description = "0x238", .value = 0x238 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 4", .value = 4 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "IRQ 10", .value = 10 }, + { .description = "IRQ 11", .value = 11 }, + { .description = "IRQ 12", .value = 12 }, + { .description = "IRQ 15", .value = 15 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "buttons", + .description = "Buttons", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Two", .value = 2 }, + { .description = "Three", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "rts_toggle", + .description = "RTS toggle", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on + }; + static const device_config_t mssermouse_config[] = { // clang-format off { @@ -1087,6 +1158,20 @@ const device_t mouse_mssystems_device = { .config = msssermouse_config }; +const device_t mouse_mssystems_bus_device = { + .name = "Mouse Systems Bus Mouse", + .internal_name = "mssystems_bus", + .flags = DEVICE_ISA, + .local = MOUSE_TYPE_MSYSTEMSB, + .init = sermouse_init, + .close = sermouse_close, + .reset = NULL, + .available = NULL, + .speed_changed = sermouse_speed_changed, + .force_redraw = NULL, + .config = mssbusmouse_config +}; + const device_t mouse_msserial_device = { .name = "Microsoft Serial Mouse", .internal_name = "msserial", diff --git a/src/device/serial.c b/src/device/serial.c index deb97225a..c00cfad10 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -38,7 +38,7 @@ #include <86box/serial.h> #include <86box/mouse.h> -serial_port_t com_ports[SERIAL_MAX]; +serial_port_t com_ports[SERIAL_MAX + 1]; enum { SERIAL_INT_LSR = 1, @@ -53,7 +53,7 @@ enum { void serial_update_ints(serial_t *dev); static int next_inst = 0; -static serial_device_t serial_devices[SERIAL_MAX]; +static serial_device_t serial_devices[SERIAL_MAX + 1]; static void serial_xmit_d_empty_evt(void *priv); @@ -884,10 +884,10 @@ serial_close(void *priv) { serial_t *dev = (serial_t *) priv; - next_inst--; - - if (com_ports[dev->inst].enabled) + if (dev->sd) { + memset(dev->sd, 0, sizeof(serial_device_t)); fifo_close(dev->rcvr_fifo); + } free(dev); } @@ -897,7 +897,7 @@ serial_reset(void *priv) { serial_t *dev = (serial_t *) priv; - if (com_ports[dev->inst].enabled) { + if (dev->sd) { timer_disable(&dev->transmit_timer); timer_disable(&dev->timeout_timer); timer_disable(&dev->receive_timer); @@ -930,16 +930,28 @@ static void * serial_init(const device_t *info) { serial_t *dev = (serial_t *) calloc(1, sizeof(serial_t)); + int orig_inst = next_inst; + + if (info->local & 0xFFF00000) { + next_inst = SERIAL_MAX; + } dev->inst = next_inst; - if (com_ports[next_inst].enabled) { + if (com_ports[next_inst].enabled || (info->local & 0xFFF00000)) { serial_log("Adding serial port %i...\n", next_inst); dev->type = info->local; memset(&(serial_devices[next_inst]), 0, sizeof(serial_device_t)); dev->sd = &(serial_devices[next_inst]); dev->sd->serial = dev; - if (next_inst == 6) + + if (info->local & 0xFFF00000) { + dev->base_address = info->local >> 20; + dev->irq = (info->local >> 16) & 0xF; + io_sethandler(dev->base_address, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, dev); + next_inst = orig_inst; + } + else if (next_inst == 6) serial_setup(dev, COM7_ADDR, COM7_IRQ); else if (next_inst == 5) serial_setup(dev, COM6_ADDR, COM6_IRQ); @@ -984,7 +996,8 @@ serial_init(const device_t *info) serial_reset_port(dev); } - next_inst++; + if (!(info->local & 0xFFF00000)) + next_inst++; return dev; } diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index 333849846..8dd3bad2d 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -41,6 +41,7 @@ #define MOUSE_TYPE_PS2 11 /* PS/2 series Bus Mouse */ #define MOUSE_TYPE_WACOM 12 /* WACOM tablet */ #define MOUSE_TYPE_WACOMARTP 13 /* WACOM tablet (ArtPad) */ +#define MOUSE_TYPE_MSYSTEMSB 14 /* Mouse Systems bus mouse */ #define MOUSE_TYPE_ONBOARD 0x80 /* Mouse is an on-board version of one of the above. */ @@ -68,6 +69,7 @@ extern const device_t mouse_msinport_device; extern const device_t mouse_genibus_device; # endif extern const device_t mouse_mssystems_device; +extern const device_t mouse_mssystems_bus_device; extern const device_t mouse_msserial_device; extern const device_t mouse_ltserial_device; extern const device_t mouse_ps2_device; diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index 31c77ce5a..c6259d7bc 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -116,7 +116,7 @@ typedef struct serial_port_s { uint8_t enabled; } serial_port_t; -extern serial_port_t com_ports[SERIAL_MAX]; +extern serial_port_t com_ports[SERIAL_MAX + 1]; extern serial_t *serial_attach_ex(int port, void (*rcr_callback)(struct serial_s *serial, void *priv), From 6fc6a16be6c8a408a3ae2f1d4729f60b20e18da8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 28 Apr 2025 11:18:57 +0200 Subject: [PATCH 0813/1190] Fixed a few minor things with how the Mouse Systems Bus Mouse as added. --- src/86box.c | 2 +- src/config.c | 6 +++--- src/device/mouse_serial.c | 11 ++++++++--- src/device/serial.c | 18 ++++++++---------- src/device/serial_passthrough.c | 2 +- src/include/86box/86box.h | 2 +- src/include/86box/serial.h | 2 +- src/include/86box/serial_passthrough.h | 2 +- src/qt/qt_settingsports.cpp | 4 ++-- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/86box.c b/src/86box.c index d96a571c0..cd573d98f 100644 --- a/src/86box.c +++ b/src/86box.c @@ -174,7 +174,7 @@ int force_43 = 0; /* (C) video * int video_filter_method = 1; /* (C) video */ int video_vsync = 0; /* (C) video */ int video_framerate = -1; /* (C) video */ -bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of +bool serial_passthrough_enabled[SERIAL_MAX - 1] = { 0, 0, 0, 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */ int bugger_enabled = 0; /* (C) enable ISAbugger */ int novell_keycard_enabled = 0; /* (C) enable Novell NetWare 2.x key card emulation. */ diff --git a/src/config.c b/src/config.c index 98923d9cf..52a80763a 100644 --- a/src/config.c +++ b/src/config.c @@ -746,7 +746,7 @@ load_ports(void) char temp[512]; memset(temp, 0, sizeof(temp)); - for (int c = 0; c < SERIAL_MAX; c++) { + for (int c = 0; c < (SERIAL_MAX - 1); c++) { sprintf(temp, "serial%d_enabled", c + 1); com_ports[c].enabled = !!ini_section_get_int(cat, temp, (c >= 2) ? 0 : 1); @@ -1839,7 +1839,7 @@ config_load(void) com_ports[0].enabled = 1; com_ports[1].enabled = 1; - for (i = 2; i < SERIAL_MAX; i++) + for (i = 2; i < (SERIAL_MAX - 1); i++) com_ports[i].enabled = 0; lpt_ports[0].enabled = 1; @@ -2459,7 +2459,7 @@ save_ports(void) ini_section_t cat = ini_find_or_create_section(config, "Ports (COM & LPT)"); char temp[512]; - for (int c = 0; c < SERIAL_MAX; c++) { + for (int c = 0; c < (SERIAL_MAX - 1); c++) { sprintf(temp, "serial%d_enabled", c + 1); if (((c < 2) && com_ports[c].enabled) || ((c >= 2) && !com_ports[c].enabled)) ini_section_delete_var(cat, temp); diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 24d7ae853..7505cf3a3 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -843,10 +843,13 @@ sermouse_init(const device_t *info) mouse_t *dev; void (*rcr_callback)(struct serial_s *serial, void *priv); void (*dev_write)(struct serial_s *serial, void *priv, uint8_t data); - void (*transmit_period_callback)(struct serial_s *serial, void *priv, double transmit_period); + void (*transmit_period_callback)(struct serial_s *serial, void *priv, + double transmit_period); if (info->local == MOUSE_TYPE_MSYSTEMSB) { - uintptr_t irqbase = ((device_get_config_int("irq") << 16) | (device_get_config_hex16("addr") << 20)) | ns16450_device.local; + uintptr_t irqbase = ((device_get_config_int("irq") << 16) | + (device_get_config_hex16("addr") << 20)) | + ns16450_device.local; device_add_params(&ns16450_device, (void*)irqbase); } @@ -894,7 +897,7 @@ sermouse_init(const device_t *info) } } - dev->port = (info->local == MOUSE_TYPE_MSYSTEMSB) ? SERIAL_MAX : device_get_config_int("port"); + dev->port = (info->local == MOUSE_TYPE_MSYSTEMSB) ? (SERIAL_MAX - 1) : device_get_config_int("port"); /* Attach a serial port to the mouse. */ rcr_callback = dev->rts_toggle ? sermouse_callback : NULL; @@ -982,6 +985,8 @@ static const device_config_t mssbusmouse_config[] = { .selection = { { .description = "0x338", .value = 0x338 }, { .description = "0x238", .value = 0x238 }, + { .description = "0x3f8", .value = 0x3f8 }, + { .description = "0x2f8", .value = 0x2f8 }, { .description = "" } }, .bios = { { 0 } } diff --git a/src/device/serial.c b/src/device/serial.c index c00cfad10..71be924c1 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -38,7 +38,7 @@ #include <86box/serial.h> #include <86box/mouse.h> -serial_port_t com_ports[SERIAL_MAX + 1]; +serial_port_t com_ports[SERIAL_MAX]; enum { SERIAL_INT_LSR = 1, @@ -53,7 +53,7 @@ enum { void serial_update_ints(serial_t *dev); static int next_inst = 0; -static serial_device_t serial_devices[SERIAL_MAX + 1]; +static serial_device_t serial_devices[SERIAL_MAX]; static void serial_xmit_d_empty_evt(void *priv); @@ -932,9 +932,8 @@ serial_init(const device_t *info) serial_t *dev = (serial_t *) calloc(1, sizeof(serial_t)); int orig_inst = next_inst; - if (info->local & 0xFFF00000) { - next_inst = SERIAL_MAX; - } + if (info->local & 0xFFF00000) + next_inst = SERIAL_MAX - 1; dev->inst = next_inst; @@ -945,13 +944,12 @@ serial_init(const device_t *info) dev->sd = &(serial_devices[next_inst]); dev->sd->serial = dev; - if (info->local & 0xFFF00000) { + if (info->local & 0xfff00000) { dev->base_address = info->local >> 20; dev->irq = (info->local >> 16) & 0xF; io_sethandler(dev->base_address, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, dev); next_inst = orig_inst; - } - else if (next_inst == 6) + } else if (next_inst == 6) serial_setup(dev, COM7_ADDR, COM7_IRQ); else if (next_inst == 5) serial_setup(dev, COM6_ADDR, COM6_IRQ); @@ -996,7 +994,7 @@ serial_init(const device_t *info) serial_reset_port(dev); } - if (!(info->local & 0xFFF00000)) + if (!(info->local & 0xfff00000)) next_inst++; return dev; @@ -1011,7 +1009,7 @@ serial_set_next_inst(int ni) void serial_standalone_init(void) { - while (next_inst < SERIAL_MAX) + while (next_inst < (SERIAL_MAX - 1)) device_add_inst(&ns8250_device, next_inst + 1); }; diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 3ad969006..25db29096 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -54,7 +54,7 @@ serial_passthrough_log(const char *fmt, ...) void serial_passthrough_init(void) { - for (uint8_t c = 0; c < SERIAL_MAX; c++) { + for (uint8_t c = 0; c < (SERIAL_MAX - 1); c++) { if (serial_passthrough_enabled[c]) { /* Instance n for COM n */ device_add_inst(&serial_passthrough_device, c + 1); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 7f7723bba..e19665535 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -27,7 +27,7 @@ /* Configuration values. */ #define GFXCARD_MAX 2 -#define SERIAL_MAX 7 +#define SERIAL_MAX 8 #define PARALLEL_MAX 4 #define SCREEN_RES_X 640 #define SCREEN_RES_Y 480 diff --git a/src/include/86box/serial.h b/src/include/86box/serial.h index c6259d7bc..31c77ce5a 100644 --- a/src/include/86box/serial.h +++ b/src/include/86box/serial.h @@ -116,7 +116,7 @@ typedef struct serial_port_s { uint8_t enabled; } serial_port_t; -extern serial_port_t com_ports[SERIAL_MAX + 1]; +extern serial_port_t com_ports[SERIAL_MAX]; extern serial_t *serial_attach_ex(int port, void (*rcr_callback)(struct serial_s *serial, void *priv), diff --git a/src/include/86box/serial_passthrough.h b/src/include/86box/serial_passthrough.h index 7ca6479d6..c5454194a 100644 --- a/src/include/86box/serial_passthrough.h +++ b/src/include/86box/serial_passthrough.h @@ -55,7 +55,7 @@ typedef struct serial_passthrough_s { void *backend_priv; /* Private platform backend data */ } serial_passthrough_t; -extern bool serial_passthrough_enabled[SERIAL_MAX]; +extern bool serial_passthrough_enabled[SERIAL_MAX - 1]; extern const device_t serial_passthrough_device; extern void serial_passthrough_init(void); diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index f68106dc9..2b57a683c 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -58,7 +58,7 @@ SettingsPorts::save() lpt_ports[i].enabled = checkBox->isChecked() ? 1 : 0; } - for (int i = 0; i < SERIAL_MAX; i++) { + for (int i = 0; i < (SERIAL_MAX - 1); i++) { auto *checkBox = findChild(QString("checkBoxSerial%1").arg(i + 1)); auto *checkBoxPass = findChild(QString("checkBoxSerialPassThru%1").arg(i + 1)); if (checkBox != NULL) @@ -118,7 +118,7 @@ SettingsPorts::onCurrentMachineChanged(int machineId) cbox[i]->setEnabled(lpt_ports[i].enabled > 0); } - for (int i = 0; i < SERIAL_MAX; i++) { + for (int i = 0; i < (SERIAL_MAX - 1); i++) { auto *checkBox = findChild(QString("checkBoxSerial%1").arg(i + 1)); auto *checkBoxPass = findChild(QString("checkBoxSerialPassThru%1").arg(i + 1)); auto *buttonPass = findChild(QString("pushButtonSerialPassThru%1").arg(i + 1)); From aa940316ffe6446fcadfd923b85af9a1929f20ed Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Mon, 28 Apr 2025 18:00:49 +0500 Subject: [PATCH 0814/1190] qt: For device config dialogs, default to the settings dialog as the parent Fixes (somehow) controls being non-interactable when no parent dialog is passed and 86Box is running in settings-only mode --- src/qt/qt_deviceconfig.hpp | 2 +- src/qt/qt_settingsdisplay.cpp | 16 ++++++++-------- src/qt/qt_settingsinput.cpp | 2 +- src/qt/qt_settingsmachine.cpp | 2 +- src/qt/qt_settingsnetwork.cpp | 8 ++++---- src/qt/qt_settingsotherperipherals.cpp | 10 +++++----- src/qt/qt_settingsports.cpp | 14 +++++++------- src/qt/qt_settingssound.cpp | 18 ++++++++---------- src/qt/qt_settingsstoragecontrollers.cpp | 18 +++++++++--------- 9 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/qt/qt_deviceconfig.hpp b/src/qt/qt_deviceconfig.hpp index a16c152a6..a5214111f 100644 --- a/src/qt/qt_deviceconfig.hpp +++ b/src/qt/qt_deviceconfig.hpp @@ -23,7 +23,7 @@ public: ~DeviceConfig() override; static void ConfigureDevice(const _device_ *device, int instance = 0, - Settings *settings = nullptr); + Settings *settings = qobject_cast(Settings::settings)); static QString DeviceName(const _device_ *device, const char *internalName, int bus); private: diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index b7a930711..fbe6ab5cc 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -122,22 +122,22 @@ SettingsDisplay::on_pushButtonConfigure_clicked() auto *device = video_card_getdevice(videoCard); if (videoCard == VID_INTERNAL) device = machine_get_vid_device(machineId); - DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device); } void SettingsDisplay::on_pushButtonConfigureVoodoo_clicked() { - DeviceConfig::ConfigureDevice(&voodoo_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&voodoo_device); } void SettingsDisplay::on_pushButtonConfigure8514_clicked() { if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { - DeviceConfig::ConfigureDevice(&ibm8514_mca_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&ibm8514_mca_device); } else { - DeviceConfig::ConfigureDevice(&gen8514_isa_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&gen8514_isa_device); } } @@ -145,16 +145,16 @@ void SettingsDisplay::on_pushButtonConfigureXga_clicked() { if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) { - DeviceConfig::ConfigureDevice(&xga_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&xga_device); } else { - DeviceConfig::ConfigureDevice(&xga_isa_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&xga_isa_device); } } void SettingsDisplay::on_pushButtonConfigureDa2_clicked() { - DeviceConfig::ConfigureDevice(&ps55da2_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&ps55da2_device); } void @@ -298,5 +298,5 @@ void SettingsDisplay::on_pushButtonConfigureSecondary_clicked() { auto *device = video_card_getdevice(ui->comboBoxVideoSecondary->currentData().toInt()); - DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device); } diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index 695dc43e9..f3729ab3f 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -274,7 +274,7 @@ void SettingsInput::on_pushButtonConfigureMouse_clicked() { int mouseId = ui->comboBoxMouse->currentData().toInt(); - DeviceConfig::ConfigureDevice(mouse_get_device(mouseId), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(mouse_get_device(mouseId)); } static int diff --git a/src/qt/qt_settingsmachine.cpp b/src/qt/qt_settingsmachine.cpp index 939cd9eb2..8548ca8cc 100644 --- a/src/qt/qt_settingsmachine.cpp +++ b/src/qt/qt_settingsmachine.cpp @@ -347,7 +347,7 @@ SettingsMachine::on_pushButtonConfigure_clicked() // deviceconfig_inst_open int machineId = ui->comboBoxMachine->currentData().toInt(); const auto *device = machine_get_device(machineId); - DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device); } void SettingsMachine::on_checkBoxFPUSoftfloat_stateChanged(int state) { diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index 9a53411d5..1ea48ee6b 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -240,7 +240,7 @@ SettingsNetwork::on_pushButtonConf1_clicked() auto *device = network_card_getdevice(netCard); if (netCard == NET_INTERNAL) device = machine_get_net_device(machineId); - DeviceConfig::ConfigureDevice(device, 1, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 1); } void @@ -248,7 +248,7 @@ SettingsNetwork::on_pushButtonConf2_clicked() { int netCard = ui->comboBoxNIC2->currentData().toInt(); auto *device = network_card_getdevice(netCard); - DeviceConfig::ConfigureDevice(device, 2, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 2); } void @@ -256,7 +256,7 @@ SettingsNetwork::on_pushButtonConf3_clicked() { int netCard = ui->comboBoxNIC3->currentData().toInt(); auto *device = network_card_getdevice(netCard); - DeviceConfig::ConfigureDevice(device, 3, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 3); } void @@ -264,5 +264,5 @@ SettingsNetwork::on_pushButtonConf4_clicked() { int netCard = ui->comboBoxNIC4->currentData().toInt(); auto *device = network_card_getdevice(netCard); - DeviceConfig::ConfigureDevice(device, 4, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 4); } diff --git a/src/qt/qt_settingsotherperipherals.cpp b/src/qt/qt_settingsotherperipherals.cpp index b780dc1a6..e1920bf47 100644 --- a/src/qt/qt_settingsotherperipherals.cpp +++ b/src/qt/qt_settingsotherperipherals.cpp @@ -159,7 +159,7 @@ SettingsOtherPeripherals::on_comboBoxRTC_currentIndexChanged(int index) void SettingsOtherPeripherals::on_pushButtonConfigureRTC_clicked() { - DeviceConfig::ConfigureDevice(isartc_get_device(ui->comboBoxRTC->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(isartc_get_device(ui->comboBoxRTC->currentData().toInt())); } void @@ -174,7 +174,7 @@ SettingsOtherPeripherals::on_comboBoxCard1_currentIndexChanged(int index) void SettingsOtherPeripherals::on_pushButtonConfigureCard1_clicked() { - DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard1->currentData().toInt()), 1, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard1->currentData().toInt()), 1); } void @@ -189,7 +189,7 @@ SettingsOtherPeripherals::on_comboBoxCard2_currentIndexChanged(int index) void SettingsOtherPeripherals::on_pushButtonConfigureCard2_clicked() { - DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard2->currentData().toInt()), 2, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard2->currentData().toInt()), 2); } void @@ -204,7 +204,7 @@ SettingsOtherPeripherals::on_comboBoxCard3_currentIndexChanged(int index) void SettingsOtherPeripherals::on_pushButtonConfigureCard3_clicked() { - DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard3->currentData().toInt()), 3, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard3->currentData().toInt()), 3); } void @@ -219,7 +219,7 @@ SettingsOtherPeripherals::on_comboBoxCard4_currentIndexChanged(int index) void SettingsOtherPeripherals::on_pushButtonConfigureCard4_clicked() { - DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard4->currentData().toInt()), 4, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxCard4->currentData().toInt()), 4); } void diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index 2b57a683c..7e8f2aeda 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -254,43 +254,43 @@ SettingsPorts::on_checkBoxSerialPassThru7_stateChanged(int state) void SettingsPorts::on_pushButtonSerialPassThru1_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 1, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 1); } void SettingsPorts::on_pushButtonSerialPassThru2_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 2, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 2); } void SettingsPorts::on_pushButtonSerialPassThru3_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 3, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 3); } void SettingsPorts::on_pushButtonSerialPassThru4_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 4, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 4); } #if 0 void SettingsPorts::on_pushButtonSerialPassThru5_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 5, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 5); } void SettingsPorts::on_pushButtonSerialPassThru6_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 6, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 6); } void SettingsPorts::on_pushButtonSerialPassThru7_clicked() { - DeviceConfig::ConfigureDevice(&serial_passthrough_device, 7, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&serial_passthrough_device, 7); } #endif diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index 3e1240888..e49e1ae27 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -232,7 +232,7 @@ SettingsSound::on_pushButtonConfigureSoundCard1_clicked() if (sndCard == SOUND_INTERNAL) device = machine_get_snd_device(machineId); - DeviceConfig::ConfigureDevice(device, 1, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 1); } void @@ -252,7 +252,7 @@ SettingsSound::on_pushButtonConfigureSoundCard2_clicked() { int sndCard = ui->comboBoxSoundCard2->currentData().toInt(); const device_t *device = sound_card_getdevice(sndCard); - DeviceConfig::ConfigureDevice(device, 2, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 2); } void @@ -273,7 +273,7 @@ SettingsSound::on_pushButtonConfigureSoundCard3_clicked() int sndCard = ui->comboBoxSoundCard3->currentData().toInt(); const device_t *device = sound_card_getdevice(sndCard); - DeviceConfig::ConfigureDevice(device, 3, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 3); } void @@ -294,7 +294,7 @@ SettingsSound::on_pushButtonConfigureSoundCard4_clicked() int sndCard = ui->comboBoxSoundCard4->currentData().toInt(); const device_t *device = sound_card_getdevice(sndCard); - DeviceConfig::ConfigureDevice(device, 4, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(device, 4); } void @@ -312,8 +312,7 @@ SettingsSound::on_comboBoxMidiOut_currentIndexChanged(int index) void SettingsSound::on_pushButtonConfigureMidiOut_clicked() { - DeviceConfig::ConfigureDevice(midi_out_device_getdevice(ui->comboBoxMidiOut->currentData().toInt()), 0, - qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(midi_out_device_getdevice(ui->comboBoxMidiOut->currentData().toInt())); } void @@ -331,8 +330,7 @@ SettingsSound::on_comboBoxMidiIn_currentIndexChanged(int index) void SettingsSound::on_pushButtonConfigureMidiIn_clicked() { - DeviceConfig::ConfigureDevice(midi_in_device_getdevice(ui->comboBoxMidiIn->currentData().toInt()), 0, - qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(midi_in_device_getdevice(ui->comboBoxMidiIn->currentData().toInt())); } void @@ -345,7 +343,7 @@ void SettingsSound::on_pushButtonConfigureMPU401_clicked() { if (machine_has_bus(machineId, MACHINE_BUS_MCA) > 0) - DeviceConfig::ConfigureDevice(&mpu401_mca_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&mpu401_mca_device); else - DeviceConfig::ConfigureDevice(&mpu401_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&mpu401_device); } diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index 6fa5906b5..48fa04892 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -281,31 +281,31 @@ SettingsStorageControllers::on_checkBoxQuaternaryIDE_stateChanged(int arg1) void SettingsStorageControllers::on_pushButtonHD_clicked() { - DeviceConfig::ConfigureDevice(hdc_get_device(ui->comboBoxHD->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(hdc_get_device(ui->comboBoxHD->currentData().toInt())); } void SettingsStorageControllers::on_pushButtonFD_clicked() { - DeviceConfig::ConfigureDevice(fdc_card_getdevice(ui->comboBoxFD->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(fdc_card_getdevice(ui->comboBoxFD->currentData().toInt())); } void SettingsStorageControllers::on_pushButtonCDInterface_clicked() { - DeviceConfig::ConfigureDevice(cdrom_interface_get_device(ui->comboBoxCDInterface->currentData().toInt()), 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(cdrom_interface_get_device(ui->comboBoxCDInterface->currentData().toInt())); } void SettingsStorageControllers::on_pushButtonTertiaryIDE_clicked() { - DeviceConfig::ConfigureDevice(&ide_ter_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&ide_ter_device); } void SettingsStorageControllers::on_pushButtonQuaternaryIDE_clicked() { - DeviceConfig::ConfigureDevice(&ide_qua_device, 0, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(&ide_qua_device); } void @@ -347,25 +347,25 @@ SettingsStorageControllers::on_comboBoxSCSI4_currentIndexChanged(int index) void SettingsStorageControllers::on_pushButtonSCSI1_clicked() { - DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI1->currentData().toInt()), 1, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI1->currentData().toInt()), 1); } void SettingsStorageControllers::on_pushButtonSCSI2_clicked() { - DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI2->currentData().toInt()), 2, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI2->currentData().toInt()), 2); } void SettingsStorageControllers::on_pushButtonSCSI3_clicked() { - DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI3->currentData().toInt()), 3, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI3->currentData().toInt()), 3); } void SettingsStorageControllers::on_pushButtonSCSI4_clicked() { - DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4, qobject_cast(Settings::settings)); + DeviceConfig::ConfigureDevice(scsi_card_getdevice(ui->comboBoxSCSI4->currentData().toInt()), 4); } void From d566a0620285ed3d625fe01b6d1a85f14b3cf43d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 28 Apr 2025 19:28:58 +0200 Subject: [PATCH 0815/1190] Fix pitch regression of the ATI Mach8/32 side (April 28th, 2025) This patch fixes the pitch that was originally 0 when specifying the 8514/A compatible side in the Mach8/32 cards, which should be 1024 for 8514/A compatible stuff. --- src/video/vid_ati_mach8.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 5cbd48623..d2fde4f93 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2761,9 +2761,9 @@ ati8514_recalctimings(svga_t *svga) mach_log("ON=%d, vgahdisp=%d.\n", dev->on, svga->hdisp); if (dev->on) { - mach_log("8514/A ON.\n"); - dev->pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach_log("8514/A ON, pitch=%d.\n", dev->ext_pitch); dev->interlace = !!(dev->disp_cntl & 0x10); + dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; @@ -2865,7 +2865,7 @@ mach_recalctimings(svga_t *svga) if (dev->on) { dev->ma_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ dev->interlace = !!(dev->disp_cntl & 0x10); - dev->pitch = ((mach->accel.ge_pitch & 0xff) << 3); + dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; dev->rowcount = !!(dev->disp_cntl & 0x08); dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); @@ -3321,6 +3321,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u mach_set_resolution(mach, svga); mach32_updatemapping(mach, svga); } else { + dev->ext_pitch = 1024; dev->ext_crt_pitch = 128; mach_set_resolution(mach, svga); } @@ -3515,8 +3516,11 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u ibm8514_accel_out_fifo(svga, port, val, len); if (len == 2) { if ((dev->accel.multifunc_cntl >> 12) == 5) { - if (!ATI_MACH32) + if (!ATI_MACH32) { + dev->ext_pitch = 1024; dev->ext_crt_pitch = 128; + svga_recalctimings(svga); + } } } break; @@ -3847,6 +3851,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u else { WRITE8(port, mach->accel.ge_pitch, val); } + dev->ext_pitch = ((mach->accel.ge_pitch & 0xff) << 3); mach_log("ATI 8514/A: (0x%04x) GE Pitch val=0x%02x.\n", port, val); svga_recalctimings(svga); break; From ad4ec20374d08ddb3b8e8919d2fc775ab3e0c22e Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 29 Apr 2025 00:33:51 +0200 Subject: [PATCH 0816/1190] Modify the CL-GD 54xx (S)VGA read and write handlers in order to use the pointer to the svga struct instead of the gd54xx struct, fixes #5521. --- src/include/86box/vid_svga.h | 2 + src/video/vid_cl54xx.c | 78 ++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 932aa718a..6de73f9f9 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -315,6 +315,8 @@ typedef struct svga_t { card should not attempt to display anything. */ void (*render_override)(void *priv); void * priv_parent; + + void * local; } svga_t; extern void ibm8514_set_poll(svga_t *svga); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index b60f9bdca..4988b3797 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -2263,8 +2263,8 @@ gd54xx_mem_sys_src_write(gd54xx_t *gd54xx, uint8_t val, uint8_t ap) static void gd54xx_write(uint32_t addr, uint8_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { @@ -2282,16 +2282,16 @@ gd54xx_write(uint32_t addr, uint8_t val, void *priv) static void gd54xx_writew(uint32_t addr, uint16_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) val = (val >> 8) | (val << 8); - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr + 1, val >> 8, gd54xx); + gd54xx_write(addr, val, svga); + gd54xx_write(addr + 1, val >> 8, svga); return; } @@ -2312,18 +2312,18 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *priv) static void gd54xx_writel(uint32_t addr, uint32_t val, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; if (gd54xx->countminusone && !gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr + 1, val >> 8, gd54xx); - gd54xx_write(addr + 2, val >> 16, gd54xx); - gd54xx_write(addr + 3, val >> 24, gd54xx); + gd54xx_write(addr, val, svga); + gd54xx_write(addr + 1, val >> 8, svga); + gd54xx_write(addr + 2, val >> 16, svga); + gd54xx_write(addr + 3, val >> 24, svga); return; } @@ -2881,8 +2881,8 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *priv) static uint8_t gd54xx_read(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) @@ -2898,14 +2898,14 @@ gd54xx_read(uint32_t addr, void *priv) static uint16_t gd54xx_readw(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; uint16_t ret; if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { - ret = gd54xx_read(addr, priv); - ret |= gd54xx_read(addr + 1, priv) << 8; + ret = gd54xx_read(addr, svga); + ret |= gd54xx_read(addr + 1, svga) << 8; return ret; } @@ -2920,16 +2920,16 @@ gd54xx_readw(uint32_t addr, void *priv) static uint32_t gd54xx_readl(uint32_t addr, void *priv) { - gd54xx_t *gd54xx = (gd54xx_t *) priv; - svga_t *svga = &gd54xx->svga; + svga_t *svga = (svga_t *) priv; + gd54xx_t *gd54xx = (gd54xx_t *) svga->local; uint32_t ret; if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { - ret = gd54xx_read(addr, priv); - ret |= gd54xx_read(addr + 1, priv) << 8; - ret |= gd54xx_read(addr + 2, priv) << 16; - ret |= gd54xx_read(addr + 3, priv) << 24; + ret = gd54xx_read(addr, svga); + ret |= gd54xx_read(addr + 1, svga) << 8; + ret |= gd54xx_read(addr + 2, svga) << 16; + ret |= gd54xx_read(addr + 3, svga) << 24; return ret; } @@ -3120,7 +3120,7 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *priv) break; } } else if (gd54xx->mmio_vram_overlap) - gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr, val, svga); } static void @@ -3153,8 +3153,8 @@ gd543x_mmio_writew(uint32_t addr, uint16_t val, void *priv) gd543x_mmio_write(addr, val & 0xff, gd54xx); gd543x_mmio_write(addr + 1, val >> 8, gd54xx); } else { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr + 1, val >> 8, gd54xx); + gd54xx_write(addr, val, svga); + gd54xx_write(addr + 1, val >> 8, svga); } } } @@ -3178,10 +3178,10 @@ gd543x_mmio_writel(uint32_t addr, uint32_t val, void *priv) gd543x_mmio_write(addr + 2, val >> 16, gd54xx); gd543x_mmio_write(addr + 3, val >> 24, gd54xx); } else { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr + 1, val >> 8, gd54xx); - gd54xx_write(addr + 2, val >> 16, gd54xx); - gd54xx_write(addr + 3, val >> 24, gd54xx); + gd54xx_write(addr, val, svga); + gd54xx_write(addr + 1, val >> 8, svga); + gd54xx_write(addr + 2, val >> 16, svga); + gd54xx_write(addr + 3, val >> 24, svga); } } } @@ -3320,7 +3320,7 @@ gd543x_mmio_read(uint32_t addr, void *priv) break; } } else if (gd54xx->mmio_vram_overlap) - ret = gd54xx_read(addr, gd54xx); + ret = gd54xx_read(addr, svga); else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) ret = gd54xx_mem_sys_dest_read(gd54xx, 0); @@ -3338,7 +3338,7 @@ gd543x_mmio_readw(uint32_t addr, void *priv) if (gd543x_do_mmio(svga, addr)) ret = gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr + 1, gd54xx) << 8); else if (gd54xx->mmio_vram_overlap) - ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr + 1, gd54xx) << 8); + ret = gd54xx_read(addr, svga) | (gd54xx_read(addr + 1, svga) << 8); else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { ret = gd543x_mmio_read(addr, priv); @@ -3361,7 +3361,7 @@ gd543x_mmio_readl(uint32_t addr, void *priv) (gd543x_mmio_read(addr + 2, gd54xx) << 16) | (gd543x_mmio_read(addr + 3, gd54xx) << 24); else if (gd54xx->mmio_vram_overlap) - ret = gd54xx_read(addr, gd54xx) | (gd54xx_read(addr + 1, gd54xx) << 8) | + ret = gd54xx_read(addr, svga) | (gd54xx_read(addr + 1, svga) << 8) | (gd54xx_read(addr + 2, gd54xx) << 16) | (gd54xx_read(addr + 3, gd54xx) << 24); else if (gd54xx->countminusone && gd54xx->blt.ms_is_dest && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { @@ -4141,6 +4141,8 @@ gd54xx_reset(void *priv) gd54xx_t *gd54xx = (gd54xx_t *) priv; svga_t *svga = &gd54xx->svga; + pclog("gd54xx_reset()\n"); + memset(svga->crtc, 0x00, sizeof(svga->crtc)); memset(svga->seqregs, 0x00, sizeof(svga->seqregs)); memset(svga->gdcreg, 0x00, sizeof(svga->gdcreg)); @@ -4159,7 +4161,6 @@ gd54xx_reset(void *priv) memset(gd54xx->pci_regs, 0x00, 256); - mem_mapping_set_p(&svga->mapping, gd54xx); mem_mapping_disable(&gd54xx->mmio_mapping); mem_mapping_disable(&gd54xx->linear_mapping); mem_mapping_disable(&gd54xx->aperture2_mapping); @@ -4210,7 +4211,7 @@ gd54xx_reset(void *priv) static void * gd54xx_init(const device_t *info) { - gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + gd54xx_t *gd54xx = calloc(1, sizeof(gd54xx_t)); svga_t *svga = &gd54xx->svga; int id = info->local & 0xff; int vram; @@ -4218,8 +4219,6 @@ gd54xx_init(const device_t *info) const char *romfn1 = NULL; const char *romfn2 = NULL; - memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->pci = !!(info->flags & DEVICE_PCI); gd54xx->vlb = !!(info->flags & DEVICE_VLB); gd54xx->mca = !!(info->flags & DEVICE_MCA); @@ -4475,7 +4474,6 @@ gd54xx_init(const device_t *info) if ((id <= CIRRUS_ID_CLGD5429) || (!gd54xx->pci && !gd54xx->vlb)) mem_mapping_set_base_ignore(&gd54xx->linear_mapping, 0xff000000); - mem_mapping_set_p(&svga->mapping, gd54xx); mem_mapping_disable(&gd54xx->mmio_mapping); mem_mapping_disable(&gd54xx->linear_mapping); mem_mapping_disable(&gd54xx->aperture2_mapping); @@ -4538,6 +4536,8 @@ gd54xx_init(const device_t *info) gd54xx->overlay.colorkeycompare = 0xff; + svga->local = gd54xx; + return gd54xx; } From 0da871f54e45f8b7ac349c3f304d22732cc95a5a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 29 Apr 2025 00:39:26 +0200 Subject: [PATCH 0817/1190] Vast overhaul to the 15bpp/16bpp accelerated mode of the 911/924. 1. See above, as best as possible, but manuals would be helpful. 2. Reverted the ramdac of the 924 to the sierra one because of a bug that triggers 24bpp mode when it shouldn't. --- src/video/vid_s3.c | 563 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 445 insertions(+), 118 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index ef21b18df..8fa392891 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -245,6 +245,8 @@ typedef struct s3_t { uint32_t pat_bg_color, pat_fg_color; uint32_t bkgd_color; uint32_t frgd_color; + uint16_t bkgd_color_back; + uint16_t frgd_color_back; uint32_t wrt_mask; uint32_t rd_mask; uint32_t color_cmp; @@ -253,7 +255,8 @@ typedef struct s3_t { uint16_t multifunc_cntl; uint16_t multifunc[16]; uint8_t pix_trans[4]; - uint16_t pix_trans_val; + uint8_t pix_trans_val[2048][2048]; + int pix_trans_inc; int ssv_state; int16_t cx, cy; @@ -281,7 +284,10 @@ typedef struct s3_t { uint8_t bkgd_color_actual[2]; uint8_t wrt_mask_actual[2]; int color_16bit_check; + int color_16bit_check_pixtrans; int16_t minus; + int rd_mask_16bit_check; + int start; /*For non-threaded FIFO*/ int setup_fifo_slot; @@ -611,18 +617,34 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); + s3->accel_start(8, 1, val | (val << 16), 0, s3); } else { - if ((s3->bpp == 0) && s3->color_16bit) + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) + val = (val >> 8) | (val << 8); + } else { + if (s3->accel.cur_x & 0x400) + s3->accel.color_16bit_check_pixtrans = 1; + else + s3->accel.color_16bit_check_pixtrans = 0; + } s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - else + } else s3->accel_start(1, 1, 0xffffffff, val | (val << 16), s3); } } else { if ((s3->bpp == 0) && s3->color_16bit) { - if (s3->accel.cur_x & 0x400) - val = (val >> 8) | (val << 8); - + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) + val = (val >> 8) | (val << 8); + } else { + if (s3->accel.cur_x & 0x400) + s3->accel.color_16bit_check_pixtrans = 1; + else + s3->accel.color_16bit_check_pixtrans = 0; + } s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } else s3->accel_start(1, 1, 0xffffffff, val | (val << 16), s3); @@ -638,11 +660,19 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) } else s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } else { - if ((s3->bpp == 0) && s3->color_16bit) { - if (s3->accel.cur_x & 0x400) + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cmd == 0x53f1) { + if (s3->accel.cur_x & 0x400) + val = (val >> 8) | (val << 8); + + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + val = (val >> 8) | (val << 8); - } - s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } else + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } else + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } break; case 0x400: @@ -1037,7 +1067,6 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) break; case 0xa549: case 0xa6e9: - s3_log("[%04X:%08X] OUT PORTB=%04x (Foreground Color), val=%02x.\n", CS, cpu_state.pc, port, val); if (s3->bpp == 3) { if ((s3->chip >= S3_86C928) && (s3->chip < S3_VISION964)) { if (s3->accel.multifunc[0xe] & 0x10) @@ -1450,6 +1479,8 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xbee9: s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + if ((s3->accel.multifunc_cntl >> 12) == 5) + s3_log("S3 multifunc_cntl = %d, val = %03x.\n", s3->accel.multifunc_cntl >> 12, s3->accel.multifunc_cntl & 0xfff); break; case 0xd148: @@ -1589,13 +1620,36 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); } else { if ((s3->bpp == 0) && s3->color_16bit) { - s3->accel.pix_trans[1] = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx - s3->accel.minus)) & s3->vram_mask]; - if (s3->accel.cur_x & 0x400) { - s3_log("Last Pixel Written=%02x (1024).\n", s3->accel.pix_trans[1]); - s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + if (s3->accel.rd_mask_16bit_check) { + s3->accel.pix_trans[1] = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx - s3->accel.minus)) & s3->vram_mask]; + if (s3->accel.cmd & 0x1000) { + if (s3->accel.cur_x & 0x400) { + s3_log("Last Pixel Written=%02x (1024) reverse.\n", s3->accel.pix_trans[1]); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } else { + s3_log("Last Pixel Written=%02x (0) reverse, cx=%d.\n", s3->accel.pix_trans[1], s3->accel.cx, s3->accel.cur_x); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + } + } else { + if (s3->accel.cur_x & 0x400) { + s3_log("Last Pixel Written=%02x (1024) normal, cx=%d, curx=%d.\n", s3->accel.pix_trans[1], s3->accel.cx, s3->accel.cur_x); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + } else { + s3_log("Last Pixel Written=%02x (0) normal, cx=%d, curx=%d.\n", s3->accel.pix_trans[1], s3->accel.cx, s3->accel.cur_x); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + } } else { - s3_log("Last Pixel Written=%02x (0).\n", s3->accel.pix_trans[1]); - s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel.pix_trans_val[s3->accel.cy][s3->accel.cx] = val; + + if (s3->accel.cur_x & 0x400) { + s3->accel.color_16bit_check_pixtrans = 0; + s3_log("%04X:%08X: Last Pixel Written=%04x (1024) normal, cx=%d, cy=%d.\n", CS, cpu_state.pc, s3->accel.pix_trans_val[s3->accel.cy][s3->accel.cx - s3->accel.minus] | (s3->accel.pix_trans_val[s3->accel.cy][s3->accel.cx] << 8), s3->accel.cx, s3->accel.cy); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans_val[s3->accel.cy][s3->accel.cx - s3->accel.minus] | (s3->accel.pix_trans_val[s3->accel.cy][s3->accel.cx] << 8), s3); + } else { + s3->accel.color_16bit_check_pixtrans = 1; + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } } } else s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); @@ -2164,7 +2218,7 @@ s3_hwcursor_draw(svga_t *svga, int displine) const s3_t *s3 = (s3_t *) svga->priv; int shift = 1; int width = 16; - uint16_t dat[2] = { 0, 0 }; + uint16_t dat[4] = { 0, 0, 0, 0 }; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; uint32_t fg; @@ -2176,30 +2230,53 @@ s3_hwcursor_draw(svga_t *svga, int displine) case 15: fg = video_15to32[s3->hwc_fg_col & 0xffff]; bg = video_15to32[s3->hwc_bg_col & 0xffff]; - if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { - if (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805) { - if (!(svga->crtc[0x45] & 0x04)) { - shift = 2; - width = 8; + if ((s3->chip >= S3_86C928) && (s3->chip <= S3_86C805)) { + if (!s3->color_16bit) { + if ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805)) { + if (!(svga->crtc[0x45] & 0x04)) { + shift = 2; + width = 8; + } } + } else { + shift = 2; + width = 8; + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; } + } else if (s3->chip <= S3_86C924) { + shift = 2; + width = 8; + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; } break; case 16: fg = video_16to32[s3->hwc_fg_col & 0xffff]; bg = video_16to32[s3->hwc_bg_col & 0xffff]; - if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { - if ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805)) { - if (!(svga->crtc[0x45] & 0x04)) { - shift = 2; - width = 8; - } - } else if (s3->card_type == S3_MIROCRYSTAL10SD_805) { - if (!(svga->crtc[0x45] & 0x04)) { - offset <<= 1; + if ((s3->chip >= S3_86C928) && (s3->chip <= S3_86C805)) { + if (!s3->color_16bit) { + if ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805)) { + if (!(svga->crtc[0x45] & 0x04)) { + shift = 2; + width = 8; + } + } else if (s3->card_type == S3_MIROCRYSTAL10SD_805) { + if (!(svga->crtc[0x45] & 0x04)) + offset <<= 1; } + } else { + shift = 2; + width = 8; + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; } + } else if (s3->chip <= S3_86C924) { + shift = 2; + width = 8; + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; } break; @@ -2236,40 +2313,62 @@ s3_hwcursor_draw(svga_t *svga, int displine) for (uint8_t x = 0; x < 64; x += 16) { remapped_addr = dword_remap(svga, real_addr); + if (((svga->bpp == 15) || (svga->bpp == 16)) && s3->color_16bit) { + dat[0] = svga->vram[remapped_addr & s3->vram_mask]; + dat[1] = svga->vram[(remapped_addr + 1) & s3->vram_mask]; + dat[2] = svga->vram[(remapped_addr + 2) & s3->vram_mask]; + dat[3] = svga->vram[(remapped_addr + 3) & s3->vram_mask]; - dat[0] = (svga->vram[remapped_addr & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 1) & s3->vram_mask]; - dat[1] = (svga->vram[(remapped_addr + 2) & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 3) & s3->vram_mask]; - - if (svga->crtc[0x55] & 0x10) { - /*X11*/ - for (xx = 0; xx < 16; xx++) { - if (offset >= 0) { - if (dat[0] & 0x8000) - buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; - } - - offset++; - dat[0] <<= shift; - dat[1] <<= shift; - } - } else { /*Windows*/ - for (xx = 0; xx < width; xx++) { + for (xx = 0; xx < 8; xx++) { if (offset >= 0) { - if (!(dat[0] & 0x8000)) - buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; - else if (dat[1] & 0x8000) + if (!(dat[(xx & 4) ? 2 : 0] & 0x80)) + buffer32->line[displine][offset + svga->x_add] = (dat[(xx & 4) ? 3 : 1] & 0x80) ? fg : bg; + else if (dat[(xx & 4) ? 3 : 1] & 0x80) buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; } offset++; - dat[0] <<= shift; - dat[1] <<= shift; + s3_log("Up: Data0=%04x, Data1=%04x, Data2=%04x, Data3=%04x, xx=%d addr=%06x.\n", dat[0], dat[1], dat[2], dat[3], xx, remapped_addr); + dat[(xx & 4) ? 2 : 0] <<= 2; + dat[(xx & 4) ? 3 : 1] <<= 2; + } + } else { + dat[0] = (svga->vram[remapped_addr & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 1) & s3->vram_mask]; + dat[1] = (svga->vram[(remapped_addr + 2) & s3->vram_mask] << 8) | svga->vram[(remapped_addr + 3) & s3->vram_mask]; + + if (svga->crtc[0x55] & 0x10) { + /*X11*/ + for (xx = 0; xx < 16; xx++) { + if (offset >= 0) { + if (dat[0] & 0x8000) + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; + } + + offset++; + dat[0] <<= shift; + dat[1] <<= shift; + } + } else { + /*Windows*/ + for (xx = 0; xx < width; xx++) { + if (offset >= 0) { + if (!(dat[0] & 0x8000)) + buffer32->line[displine][offset + svga->x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + buffer32->line[displine][offset + svga->x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= shift; + dat[1] <<= shift; + } } } svga->hwcursor_latch.addr += 4; real_addr = s3_hwcursor_convert_addr(svga); } + if (svga->interlace && !svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; } @@ -2812,10 +2911,10 @@ s3_out(uint16_t addr, uint8_t val, void *priv) else if (s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968)) { rs3 = !!(svga->crtc[0x55] & 0x02); tvp3026_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || (s3->chip == S3_86C924)) && + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805))) att49x_ramdac_out(addr, rs2, val, svga->ramdac, svga); - else if (s3->chip == S3_86C911) { + else if (s3->chip <= S3_86C924) { sc1148x_ramdac_out(addr, rs2, val, svga->ramdac, svga); } else if (s3->card_type == S3_NUMBER9_9FX_531) att498_ramdac_out(addr, rs2, val, svga->ramdac, svga); @@ -2916,7 +3015,7 @@ s3_out(uint16_t addr, uint8_t val, void *priv) break; case 0x45: - if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968)) break; svga->hwcursor.ena = val & 1; break; @@ -2928,7 +3027,7 @@ s3_out(uint16_t addr, uint8_t val, void *priv) case 0x4d: case 0x4e: case 0x4f: - if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968)) break; svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; if (svga->bpp == 32) @@ -2937,14 +3036,14 @@ s3_out(uint16_t addr, uint8_t val, void *priv) svga->hwcursor.xoff = svga->crtc[0x4e] & 0x3f; svga->hwcursor.yoff = svga->crtc[0x4f] & 0x3f; svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); - if ((s3->chip >= S3_TRIO32) && svga->bpp == 32) + if ((s3->chip >= S3_TRIO32) && (svga->bpp == 32)) svga->hwcursor.x <<= 1; - else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && (svga->bpp == 15 || svga->bpp == 16)) { - if ((s3->card_type == S3_MIROCRYSTAL10SD_805) && !(svga->crtc[0x45] & 0x04) && svga->bpp == 16) + else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && ((svga->bpp == 15) || (svga->bpp == 16))) { + if ((s3->card_type == S3_MIROCRYSTAL10SD_805) && !(svga->crtc[0x45] & 0x04) && (svga->bpp == 16)) svga->hwcursor.x >>= 2; else svga->hwcursor.x >>= 1; - } else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && (svga->bpp == 24)) + } else if ((s3->chip >= S3_86C928) && (s3->chip <= S3_86C805) && (svga->bpp == 24)) svga->hwcursor.x /= 3; else if ((s3->chip <= S3_86C805) && s3->color_16bit) svga->hwcursor.x >>= 1; @@ -3137,10 +3236,10 @@ s3_in(uint16_t addr, void *priv) else if (s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968)) { rs3 = !!(svga->crtc[0x55] & 0x02); return tvp3026_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || (s3->chip == S3_86C924)) && + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805))) return att49x_ramdac_in(addr, rs2, svga->ramdac, svga); - else if (s3->chip == S3_86C911) + else if (s3->chip <= S3_86C924) return sc1148x_ramdac_in(addr, rs2, svga->ramdac, svga); else if (s3->card_type == S3_NUMBER9_9FX_531) return att498_ramdac_in(addr, rs2, svga->ramdac, svga); @@ -3449,7 +3548,8 @@ s3_recalctimings(svga_t *svga) if (s3->chip <= S3_86C805) { s3->color_16bit = !!(svga->crtc[0x43] & 0x08); - if (svga->bpp == 24) + s3_log("Color 16bit=%x, bpp=%d, 256color=%x.\n", s3->color_16bit, svga->bpp, (svga->attrregs[0x10] & 0x40)); + if ((svga->bpp == 24) || (svga->bpp == 8)) s3->color_16bit = 0; if (s3->color_16bit) @@ -5678,11 +5778,15 @@ s3_accel_in_w(uint16_t port, void *priv) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = (temp >> 8) | (temp << 8); + s3->accel_start(8, 1, temp | (temp << 16), 0, s3); } else { - if ((s3->bpp == 0) && s3->color_16bit) + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.cur_x & 0x400) + temp = ((temp >> 8) | (temp << 8)) & 0xffff; + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); - else + } else s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); } } else { @@ -5715,6 +5819,7 @@ s3_accel_in_w(uint16_t port, void *priv) } else { if (s3_enable_fifo(s3)) s3_wait_fifo_idle(s3); + temp = s3->accel.short_stroke; } @@ -6472,7 +6577,6 @@ polygon_setup(s3_t *s3) #define MIX \ { \ - old_dest_dat = dest_dat; \ MIX_READ \ dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); \ } @@ -7695,6 +7799,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi uint32_t srcbase; uint32_t dstbase; + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + if (((s3->chip >= S3_TRIO64) || (s3->chip == S3_VISION968) || (s3->chip == S3_VISION868)) && (s3->accel.cmd & (1 << 11))) cmd |= 0x08; @@ -7720,32 +7827,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if ((s3->accel.cmd & 0x100) && (s3_cpu_src(s3) || (s3_cpu_dest(s3))) && (!cpu_input || (s3_enable_fifo(s3) == 0))) s3->force_busy = 1; - if ((s3->bpp == 0) && s3->color_16bit && !s3->accel.b2e8_pix) { - if (cmd <= 2) { - if (s3->accel.cur_x & 0x400) { - if (s3->accel.cmd != 0x41b3) - wrt_mask = (wrt_mask << 8) & 0xff00; - else - wrt_mask &= 0xff; - - frgd_color = (frgd_color << 8) & 0xff00; - bkgd_color = (bkgd_color << 8) & 0xff00; - } else { - if (clip_r >= 0x400) { - wrt_mask &= 0xff; - frgd_color &= 0xff; - bkgd_color &= 0xff; - } - } - } else if (cmd == 6) { - if (s3->accel.destx_distp & 0x400) { - wrt_mask = (wrt_mask << 8) & 0xff00; - frgd_color = (frgd_color << 8) & 0xff00; - bkgd_color = (bkgd_color << 8) & 0xff00; - } - } - } - if (!cpu_input) s3->accel.dat_count = 0; @@ -7794,13 +7875,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi break; } - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on the NOP command)*/ - s3_log("CMD=%d, full=%04x, s3bpp=%x, multifuncE=%03x, sourcedisplay=%x, mmio=%02x, srcbase=%08x, dstbase=%08x, cpu=%04x, mix=%04x, count=%d, rd_mask=%04x, wrt_mask=%04x, width=%d, s=%d,%d, c=%d,%d, d=%d,%d, 16bitcolor=%x, frgdcolor=%04x, bkgdcolor=%04x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, svgabpp=%d.\n", cmd, s3->accel.cmd, s3->bpp, s3->accel.multifunc[0x0e], vram_mask, svga->crtc[0x53] & 0x18, srcbase, dstbase, cpu_dat & 0xffff, mix_dat & 0xffff, count, rd_mask, wrt_mask, s3->width, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->color_16bit, frgd_color, bkgd_color, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, svga->bpp); + s3_log("CMD=%d, full=%04x, s3bpp=%x, clr=%d, clb=%d, sourcedisplay=%x, mmio=%02x, srcbase=%08x, dstbase=%08x, cpu=%04x, mix=%04x, count=%d, rd_mask=%04x, wrt_mask=%04x, width=%d, s=%d,%d, c=%d,%d, d=%d,%d, 16bitcolor=%x, frgdcolor=%04x, bkgdcolor=%04x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, curx=%d, cury=%d, cll=%d, b2e8pix=%x.\n", cmd, s3->accel.cmd, s3->bpp, clip_r, clip_b, vram_mask, svga->crtc[0x53] & 0x18, srcbase, dstbase, cpu_dat & 0xffff, mix_dat & 0xffff, count, rd_mask, wrt_mask, s3->width, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->color_16bit, frgd_color, bkgd_color, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.cur_x, s3->accel.cur_y, clip_l, s3->accel.b2e8_pix); switch (cmd) { case 0: /*NOP (Short Stroke Vectors)*/ @@ -7846,6 +7924,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.ssv_draw) { @@ -7911,10 +7990,16 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi case 1: /*Draw line*/ if (!cpu_input) { s3->accel.minus = 0; + s3->accel.color_16bit_check_pixtrans = 0; s3->accel.cx = s3->accel.cur_x & 0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; s3->accel.sy = s3->accel.maj_axis_pcnt; - if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.cur_x & 0x400)) + if ((s3->bpp == 0) && s3->color_16bit) + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + else + s3->accel.rd_mask_16bit_check = 0; + + if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.cur_x & 0x400) && s3->accel.rd_mask_16bit_check) s3->accel.minus = 0x400; if (s3_cpu_src(s3)) @@ -7922,6 +8007,22 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } if (s3->accel.cmd & 0x08) { /*Radial*/ + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) + break; + } + while (count-- && s3->accel.sy >= 0) { if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -7960,6 +8061,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + old_dest_dat = dest_dat; MIX WRITE((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); @@ -7973,8 +8075,15 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi else cpu_dat >>= 16; - if (!s3->accel.sy) + if (!s3->accel.sy) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.cur_x & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } break; + } switch (s3->accel.cmd & 0xe0) { case 0x00: @@ -8016,9 +8125,40 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.cur_x = s3->accel.cx & 0xfff; s3->accel.cur_y = s3->accel.cy & 0xfff; } else { /*Bresenham*/ - if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Stupid undocumented 0xB2E8 on 911/924*/ + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Pattern on pixtrans (911/924)*/ count = s3->accel.maj_axis_pcnt + 1; s3->accel.temp_cnt = 16; + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) + break; + } + } else { + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) + break; + } } while (count-- && s3->accel.sy >= 0) { @@ -8064,6 +8204,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + old_dest_dat = dest_dat; MIX WRITE((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); @@ -8086,8 +8227,15 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi else cpu_dat >>= 16; - if (!s3->accel.sy) + if (!s3->accel.sy) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.cur_x & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } break; + } if (s3->accel.cmd & 0x40) { if (s3->accel.cmd & 0x80) @@ -8131,21 +8279,43 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi case 2: /*Rectangle fill*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ { + s3->accel.start = 0; s3->accel.minus = 0; + s3->accel.color_16bit_check_pixtrans = 0; s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; s3->accel.sy = s3->accel.multifunc[0] & 0xfff; s3->accel.cx = s3->accel.cur_x & 0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; - if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.cur_x & 0x400)) - s3->accel.minus = 0x400; - - if (s3->accel.cur_x & 0x400) - s3_log("Rectangle Fill + 1024 FULLCMD=%04x: frgdcolor=%04x, s(%d,%d), c(%d,%d).\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy); - else - s3_log("Rectangle Fill + 0 FULLCMD=%04x: frgdcolor=%04x, s(%d,%d), c(%d,%d).\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy); s3->accel.dest = dstbase + s3->accel.cy * s3->width; + if ((s3->bpp == 0) && s3->color_16bit) { + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + if (s3->accel.rd_mask_16bit_check) { + s3->accel.start = 1; + if (s3->accel.cur_x & 0x400) { + s3->accel.minus = 0x400; + if ((s3->accel.cmd == 0x41b3) && (frgd_mix == 0)) + s3->accel.minus = 0; + } + } else { + if (s3->accel.cmd & 0x100) { + if (!(s3->accel.cmd & 0x200)) { + if (s3->accel.cur_x & 0x400) + s3->accel.minus = 0x400; + else + s3->accel.minus = 0; + } + } + } + } else + s3->accel.rd_mask_16bit_check = 0; + + if (s3->accel.cur_x & 0x400) + s3_log("Rectangle Fill + 1024 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, c=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x, m2=%d, m4=%d.\n", s3->accel.cmd, s3->accel.frgd_color_actual[1] << 8, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0, s3->accel.multifunc[2], s3->accel.multifunc[4]); + else + s3_log("Rectangle Fill + 0 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, c=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x, m2=%d, m4=%d.\n", s3->accel.cmd, s3->accel.frgd_color_actual[0], s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0, s3->accel.multifunc[2], s3->accel.multifunc[4]); + if (s3_cpu_src(s3)) { s3->data_available = 0; return; /*Wait for data from CPU*/ @@ -8155,9 +8325,93 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } - if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Stupid undocumented 0xB2E8 on 911/924*/ + + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Pattern on pixtrans (911/924)*/ count = s3->accel.maj_axis_pcnt + 1; s3->accel.temp_cnt = 16; + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) { + if (s3->accel.start) { + s3->accel.minus = 0x400; + s3->accel.start = 0; + } + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + if (s3->accel.start) { + s3->accel.minus = 0; + s3->accel.start = 0; + } + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) + break; + } else { + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.cmd == 0x41b3) { + if (frgd_mix != 0) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) + break; + } + } else { + if (s3->accel.rd_mask_16bit_check) { + rd_mask &= 0x00ff; + if (s3->accel.cmd == 0x53b3) { + if (clip_l & 0x400) { + if (s3->accel.start) { + s3->accel.minus = 0x400; + s3->accel.start = 0; + } + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + if (s3->accel.start) { + s3->accel.minus = 0; + s3->accel.start = 0; + } + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + } else { + if (s3->accel.cur_x & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + } + } else { + if ((s3_cpu_src(s3)) && !(s3->accel.cmd & 0x200)) { + s3_log("FIXME: S3 911/924 15/16bpp documentation needed.\n"); + } else { + if (!cpu_input && (s3->accel.cur_x & 0x400)) + break; + else if (cpu_input && (s3->accel.cmd == 0x53b3) && (s3->accel.cur_x & 0x400)) + break; + } + } + } + } } while (count-- && (s3->accel.sy >= 0)) { @@ -8177,7 +8431,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi mix_dat = mix_dat ? mix_mask : 0; } - if (s3_cpu_dest(s3) || ((s3_cpu_src(s3)) && s3->color_16bit && (s3->bpp == 0) && (s3->accel.cmd == 0x41b3))) { + if (s3_cpu_dest(s3)) { READ(s3->accel.dest + s3->accel.cx - s3->accel.minus, src_dat); if (vram_mask) src_dat = ((src_dat & rd_mask) == rd_mask); @@ -8221,17 +8475,18 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (s3_cpu_dest(s3)) { if (vram_mask) { + old_dest_dat = dest_dat; MIX } } else { + old_dest_dat = dest_dat; MIX } if (s3->accel.cmd & 0x10) { - if (s3->accel.cmd == 0x41b3) - s3_log("Full=%04x: Destination=%04x, OldDest=%04x, c=%d,%d.\n", s3->accel.cmd, dest_dat, old_dest_dat, s3->accel.cx, s3->accel.cy); - - WRITE(s3->accel.dest + s3->accel.cx - s3->accel.minus, dest_dat); + if (!s3->accel.color_16bit_check_pixtrans) { + WRITE(s3->accel.dest + s3->accel.cx - s3->accel.minus, dest_dat); + } } } } @@ -8274,9 +8529,25 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.cy &= 0xfff; s3->accel.dest = dstbase + s3->accel.cy * s3->width; + s3->accel.sy--; if (cpu_input) { + if (s3->accel.sy < 0) { + if ((s3->bpp == 0) && s3->color_16bit) { + if ((s3->accel.cmd == 0x53b3) && !s3->accel.b2e8_pix) { + if (!(clip_l & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } else { + if (!(s3->accel.cur_x & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } + } + } if (s3->accel.b2e8_pix) { s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; @@ -8284,6 +8555,12 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi return; } if (s3->accel.sy < 0) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.cur_x & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; return; @@ -8352,6 +8629,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ(s3->accel.dest + s3->accel.poly_x, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.cmd & 0x10) { @@ -8396,10 +8674,17 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.dx = s3->accel.destx_distp & 0xfff; s3->accel.dy = s3->accel.desty_axstp & 0xfff; + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); - if ((s3->bpp == 0) && s3->color_16bit && (clip_r > 0x3ff) && (s3->accel.destx_distp & 0x400)) + if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.destx_distp & 0x400) && s3->accel.rd_mask_16bit_check) s3->accel.minus = 0x400; + if (s3->accel.destx_distp & 0x400) { + s3_log("BitBLT + 1024 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, d=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x.\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.dx, s3->accel.dy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0); + } else { + s3_log("BitBLT + 0 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, d=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x.\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.dx, s3->accel.dy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0); + } + s3->accel.cx = s3->accel.cur_x & 0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; @@ -8411,6 +8696,22 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + if ((s3->bpp == 0) && s3->color_16bit) { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.destx_distp & 0x400) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + } + rd_mask &= 0x00ff; + } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.destx_distp & 0x400)) + break; + } + if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { while (1) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { @@ -8441,6 +8742,12 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.sy--; if (s3->accel.sy < 0) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.destx_distp & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } s3->accel.destx_distp = s3->accel.dx; s3->accel.desty_axstp = s3->accel.dy; return; @@ -8493,6 +8800,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ(s3->accel.dest + s3->accel.dx - s3->accel.minus, dest_dat); + old_dest_dat = dest_dat; MIX if ((!(s3->accel.cmd & 0x10) && vram_mask) || (s3->accel.cmd & 0x10)) { @@ -8540,10 +8848,25 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.sy--; - if (cpu_input) + if (cpu_input) { + if (s3->accel.sy < 0) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.destx_distp & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } + } return; + } if (s3->accel.sy < 0) { + if ((s3->bpp == 0) && s3->color_16bit) { + if (!(s3->accel.destx_distp & 0x400)) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + } s3->accel.destx_distp = s3->accel.dx; s3->accel.desty_axstp = s3->accel.dy; return; @@ -8623,6 +8946,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ(s3->accel.dest + s3->accel.dx, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.cmd & 0x10) { @@ -8728,6 +9052,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.cmd & 0x10) { @@ -8777,6 +9102,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.cmd & 0x10) { @@ -8878,6 +9204,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (update) { READ(s3->accel.dest + s3->accel.poly_x, dest_dat); + old_dest_dat = dest_dat; MIX if (s3->accel.cmd & 0x10) { @@ -9838,7 +10165,7 @@ s3_init(const device_t *info) s3->id_ext_pci = 0; s3->packed_mmio = 0; - svga->ramdac = device_add(&att490_ramdac_device); + svga->ramdac = device_add(&sc11483_ramdac_device); svga->clock_gen = device_add(&ics2494an_305_device); svga->getclock = ics2494_getclock; break; From d623425efdf1b418623a444278aad60ec024d201 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 29 Apr 2025 00:57:03 +0200 Subject: [PATCH 0818/1190] Some more changes to the Mach8/32/8514/A side (April 29th, 2025) 1. Do not stall the guest when the passthrough mode is on, fixes hang ups in Windows 3.1 using the 2.3 drivers. 2. In the pitch register, make sure the passthrough goes on when needed only on the ATI Mach32, not 8, fixes mode on/off in text mode when needed. 3. Cosmetic changes and logs. --- src/video/vid_8514a.c | 2 +- src/video/vid_ati_mach8.c | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 533ec8fa9..ba4641259 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -961,7 +961,7 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) temp |= INT_GE_BSY; } - if (!dev->fifo_idx) { + if (!dev->fifo_idx && !dev->on) { dev->force_busy = 0; dev->force_busy2 = 0; dev->data_available = 0; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index d2fde4f93..07fa0a93c 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -866,6 +866,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.stepy = 1; } + if (mach->accel.dp_config == 0x4011) + mach->accel.height++; + dev->accel.sy = 0; dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); @@ -1172,7 +1175,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 mach->accel.sx++; if (mach->accel.sx >= mach->accel.src_width) { mach->accel.sx = 0; - if (mach->accel.src_stepx < 0) + if (mach->accel.src_stepx == -1) dev->accel.cx += mach->accel.src_width; else dev->accel.cx -= mach->accel.src_width; @@ -1196,7 +1199,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.sx++; if ((dev->accel.sx >= mach->accel.width) || (dev->accel.dx >= 0x600)) { dev->accel.sx = 0; - if (mach->accel.stepx < 0) + if (mach->accel.stepx == -1) dev->accel.dx += mach->accel.width; else dev->accel.dx -= mach->accel.width; @@ -3457,7 +3460,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0xe2e9: case 0xe6e9: - mach_log("Write PORT=%04x, 8514/A=%x, val=%04x, len=%d.\n", port, dev->accel.cmd_back, val, len); + mach_log("Write PORT=%04x, 8514/A=%x, val0=%02x, sy=%d, len=%d, dx=%d, dy=%d.\n", port, dev->accel.cmd_back, val, dev->accel.sy, len, dev->accel.dx, dev->accel.dy); if (len == 1) { if (!dev->accel.cmd_back) { if (mach->accel.cmd_type >= 0) { @@ -3645,9 +3648,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (len == 2) { dev->_8514crt = 0; - if (!(dev->accel.advfunc_cntl & 0x01)) { + if (!(dev->accel.advfunc_cntl & 0x01) && ATI_MACH32) { dev->on = 1; - dev->vendor_mode = !!ATI_MACH32; + dev->vendor_mode = 1; } } else dev->_8514crt = 1; @@ -3656,7 +3659,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (ATI_GRAPHICS_ULTRA || ATI_MACH32) mach32_updatemapping(mach, svga); - mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode bpp=%d.\n", port, val, dev->ext_crt_pitch, len, dev->accel_bpp); + mach_log("ATI 8514/A: (0x%04x) CRT Pitch, val=0x%02x, crtpitch=%x, len=%d, extended 8514/A mode bpp=%d, enable_on=%d.\n", port, val, dev->ext_crt_pitch, len, dev->accel_bpp, dev->on); break; case 0x2aee: @@ -4747,21 +4750,23 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) } } - if (!dev->fifo_idx) { + if (!dev->fifo_idx && !dev->on) { dev->force_busy = 0; dev->force_busy2 = 0; mach->force_busy = 0; dev->data_available = 0; dev->data_available2 = 0; temp |= INT_FIFO_EMP; + mach_log("Fifo Empty.\n"); } temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); if (mach->accel.ext_ge_config & 0x08) temp |= ((mach->accel.ext_ge_config & 0x07) << 4); else temp |= 0x20; + + mach_log("0x%04x read: Subsystem Status=%02x, monitoralias=%02x.\n", port, temp, mach->accel.ext_ge_config & 0x07); } - mach_log("0x%04x read: Subsystem Status=%02x, monitoralias=%02x.\n", port, temp, mach->accel.ext_ge_config & 0x07); break; /*ATI Mach8/32 specific registers*/ From 1282ecfd56fc21095de975e34a59e716d12533d2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Apr 2025 01:37:25 +0200 Subject: [PATCH 0819/1190] BT-958D PCI: Preserve PCI slot across device resets, fixes IRQ's. --- src/scsi/scsi_buslogic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 352232e34..0e8954aff 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -1551,6 +1551,8 @@ buslogic_reset(void *priv) reset_state.timer = dev->timer; reset_state.ResetCB = dev->ResetCB; + reset_state.pci_slot = dev->pci_slot; + memcpy(dev, &reset_state, sizeof(x54x_t)); dev->timer.period = 10.0; From 9f03881dd84d173280583e289ffa7a9b9258f538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Wed, 30 Apr 2025 18:04:25 +0200 Subject: [PATCH 0820/1190] Trigem 486G: Fix memory limits. --- src/machine/machine_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 39d9cc9ff..c269c7b0f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7328,9 +7328,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_VLB, .flags = MACHINE_IDE | MACHINE_APM, /* Has internal video: Western Digital WD90C33-ZZ */ .ram = { - .min = 1024, - .max = 65536, - .step = 1024 + .min = 4096, + .max = 40960, + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, From a6599a60b2f246c6e39f6969fabc481cbe6ee6c8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Apr 2025 18:46:39 +0200 Subject: [PATCH 0821/1190] TriGem 486G: Initialize NVR with 0x00's instead of 0xFF's, fixes the cache error on empty NVR. --- src/machine/m_at_386dx_486.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index ef30a5aa4..264111a96 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -2283,7 +2283,10 @@ machine_at_tg486gp_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); + + device_add(&ide_isa_device); device_add(&ali1429g_device); From 77f7be608ec596c0c584cccf43eb59f669faf96b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Apr 2025 19:15:12 +0200 Subject: [PATCH 0822/1190] Turns out I committed the NVR fix to the wrong TriGem 486 machine. --- src/machine/m_at_386dx_486.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 264111a96..5b746e3ef 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -2283,10 +2283,7 @@ machine_at_tg486gp_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init_ex(model, 2); - device_add(&amstrad_megapc_nvr_device); - - device_add(&ide_isa_device); + machine_at_common_ide_init(model); device_add(&ali1429g_device); @@ -2319,7 +2316,8 @@ machine_at_tg486g_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); device_add(&sis_85c471_device); device_add(&ide_isa_device); device_add(&fdc37c651_ide_device); From 26c0e4af811f1a41cc73bca04e8424156d8d8b38 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Wed, 30 Apr 2025 14:51:49 -0400 Subject: [PATCH 0823/1190] Fix second standard joystick --- src/game/joystick_standard.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index 122d2c65f..5f200cb98 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -62,13 +62,18 @@ joystick_standard_read(UNUSED(void *priv)) { uint8_t ret = 0xf0; - for (int js = 0; js < 2; js++) { - if (JOYSTICK_PRESENT(0, js)) { - if (joystick_state[0][js].button[0]) - ret &= ~0x10; - if (joystick_state[0][js].button[1]) - ret &= ~0x20; - } + if (JOYSTICK_PRESENT(0, 0)) { + if (joystick_state[0][0].button[0]) + ret &= ~0x10; + if (joystick_state[0][0].button[1]) + ret &= ~0x20; + } + + if (JOYSTICK_PRESENT(0, 1)) { + if (joystick_state[0][1].button[0]) + ret &= ~0x40; + if (joystick_state[0][1].button[1]) + ret &= ~0x80; } return ret; From 49bbd6e8cdcd451c099a86d18f9a28868c22c097 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 30 Apr 2025 22:20:33 +0200 Subject: [PATCH 0824/1190] Removed the usage deprecation warning. --- src/86box.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/86box.c b/src/86box.c index cd573d98f..1d7a73060 100644 --- a/src/86box.c +++ b/src/86box.c @@ -665,7 +665,9 @@ pc_init(int argc, char *argv[]) time_t now; int c; int lvmp = 0; +#ifdef DEPRECATE_USAGE int deprecated = 1; +#endif #ifdef ENABLE_NG int ng = 0; #endif @@ -750,7 +752,9 @@ usage: goto usage; ppath = argv[++c]; +#ifdef DEPRECATE_USAGE deprecated = 0; +#endif } else if (!strcasecmp(argv[c], "--rompath") || !strcasecmp(argv[c], "-R")) { if ((c + 1) == argc) goto usage; @@ -762,7 +766,9 @@ usage: goto usage; cfg = argv[++c]; +#ifdef DEPRECATE_USAGE deprecated = 0; +#endif } else if (!strcasecmp(argv[c], "--image") || !strcasecmp(argv[c], "-I")) { if ((c + 1) == argc) goto usage; @@ -862,16 +868,20 @@ usage: else cfg = argv[c++]; +#ifdef DEPRECATE_USAGE deprecated = 0; +#endif } if (c != argc) goto usage; +#ifdef DEPRECATE_USAGE if (deprecated) pc_show_usage("Running 86Box without a specified VM path and/or configuration\n" "file has been deprected. Please specify one or use a manager\n" "(Avalonia 86 is recommended).\n\n"); +#endif path_slash(usr_path); path_slash(rom_path); From 8c736c7b9a66f5ec26db51a154f08af9edb19ba5 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 30 Apr 2025 23:15:58 +0200 Subject: [PATCH 0825/1190] Stall fix for the mach8/32 (April 30th, 2025) See above. --- src/video/vid_ati_mach8.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 07fa0a93c..ce6ee12d5 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -4264,10 +4264,13 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in if (dev->force_busy) { temp |= 0x0200; /*Hardware busy*/ if (mach->accel.cmd_type >= 0) { + mono_src = (mach->accel.dp_config >> 5) & 3; switch (mach->accel.cmd_type) { case 2: if (dev->accel.sy >= mach->accel.height) dev->force_busy = 0; + else if (mono_src == 2) + dev->force_busy = 0; break; case 5: if (dev->accel.sx >= mach->accel.width) From 27425dbd492e935e094eb120139bc0d70cc03ebc Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 1 May 2025 15:39:43 +0200 Subject: [PATCH 0826/1190] SiS 85c471: Implement DRAM banks/rows. --- src/chipset/sis_85c4xx.c | 442 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 418 insertions(+), 24 deletions(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 537675a85..003b66697 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -36,24 +36,340 @@ #include <86box/machine.h> #include <86box/chipset.h> +typedef struct ram_bank_t { + uint32_t virt_base; + uint32_t virt_size; + uint32_t phys_base; + uint32_t phys_size; + + mem_mapping_t mapping; +} ram_bank_t; + typedef struct sis_85c4xx_t { - uint8_t cur_reg; - uint8_t tries; - uint8_t reg_base; - uint8_t reg_last; - uint8_t reg_00; - uint8_t is_471; - uint8_t force_flush; - uint8_t shadowed; - uint8_t smram_enabled; - uint8_t pad; - uint8_t regs[39]; - uint8_t scratch[2]; - uint32_t mem_state[8]; - smram_t *smram; - port_92_t *port_92; + uint8_t cur_reg; + uint8_t tries; + uint8_t reg_base; + uint8_t reg_last; + uint8_t reg_00; + uint8_t is_471; + uint8_t ram_banks_val; + uint8_t force_flush; + uint8_t shadowed; + uint8_t smram_enabled; + uint8_t pad; + uint8_t regs[39]; + uint8_t scratch[2]; + uint32_t mem_state[8]; + ram_bank_t ram_banks[8]; + smram_t * smram; + port_92_t * port_92; } sis_85c4xx_t; +static uint8_t ram_4xx[64] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, + 0x04, 0x04, 0x05, 0x05, 0x0b, 0x0b, 0x0b, 0x0b, + 0x13, 0x21, 0x06, 0x06, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x0f, 0x0f, 0x0f, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }; +static uint8_t ram_tg486g[64] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, + 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, + 0x15, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, + 0x17, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; + +static uint32_t banks_471[64][4] = { { 0x00100000, 0x00000000, 0x00000000, 0x00000000 }, /* 0x00 */ + { 0x00100000, 0x00100000, 0x00000000, 0x00000000 }, + { 0x00100000, 0x00100000, 0x00200000, 0x00000000 }, + { 0x00100000, 0x00100000, 0x00400000, 0x00000000 }, + { 0x00100000, 0x00100000, 0x00200000, 0x00400000 }, + { 0x00100000, 0x00100000, 0x00400000, 0x00400000 }, + { 0x00100000, 0x00100000, 0x01000000, 0x00000000 }, + { 0x00200000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00200000, 0x00200000, 0x00000000, 0x00000000 }, /* 0x08 */ + { 0x00200000, 0x00400000, 0x00000000, 0x00000000 }, + { 0x00200000, 0x00200000, 0x00400000, 0x00000000 }, + { 0x00200000, 0x00200000, 0x00400000, 0x00400000 }, + { 0x00200000, 0x01000000, 0x00000000, 0x00000000 }, + { 0x00200000, 0x00200000, 0x01000000, 0x00000000 }, + { 0x00200000, 0x00200000, 0x00400000, 0x01000000 }, + { 0x00200000, 0x00200000, 0x01000000, 0x01000000 }, + { 0x00400000, 0x00000000, 0x00000000, 0x00000000 }, /* 0x10 */ + { 0x00400000, 0x00400000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x00400000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x00400000, 0x00400000 }, + { 0x00400000, 0x01000000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x01000000, 0x00000000 }, + { 0x00400000, 0x01000000, 0x01000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x01000000, 0x01000000 }, + { 0x00800000, 0x00000000, 0x00000000, 0x00000000 }, /* 0x18 */ + { 0x00800000, 0x00800000, 0x00000000, 0x00000000 }, + { 0x00800000, 0x00800000, 0x00800000, 0x00000000 }, + { 0x00800000, 0x00800000, 0x00800000, 0x00800000 }, + { 0x01000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x01000000, 0x01000000, 0x00000000, 0x00000000 }, + { 0x01000000, 0x01000000, 0x01000000, 0x00000000 }, + { 0x01000000, 0x01000000, 0x01000000, 0x01000000 }, + { 0x00100000, 0x00400000, 0x00000000, 0x00000000 }, /* 0x20 */ + { 0x00100000, 0x01000000, 0x00000000, 0x00000000 }, + { 0x00100000, 0x04000000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x00800000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x04000000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x04000000, 0x00000000 }, + { 0x01000000, 0x04000000, 0x00000000, 0x00000000 }, + { 0x01000000, 0x01000000, 0x04000000, 0x00000000 }, + { 0x04000000, 0x00000000, 0x00000000, 0x00000000 }, /* 0x28 */ + { 0x04000000, 0x04000000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x02000000, 0x00000000, 0x00000000 }, + { 0x00400000, 0x02000000, 0x02000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x02000000, 0x00000000 }, + { 0x00400000, 0x00400000, 0x02000000, 0x02000000 }, + { 0x01000000, 0x02000000, 0x00000000, 0x00000000 }, + { 0x01000000, 0x02000000, 0x02000000, 0x00000000 }, + { 0x01000000, 0x01000000, 0x02000000, 0x00000000 }, /* 0x30 */ + { 0x01000000, 0x01000000, 0x02000000, 0x02000000 }, + { 0x02000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x02000000, 0x02000000, 0x00000000, 0x00000000 }, + { 0x02000000, 0x02000000, 0x02000000, 0x00000000 }, + { 0x02000000, 0x02000000, 0x02000000, 0x02000000 }, + { 0x00400000, 0x00800000, 0x00800000, 0x00000000 }, + { 0x00400000, 0x00800000, 0x00800000, 0x00800000 }, + { 0x00400000, 0x00400000, 0x00800000, 0x00000000 }, /* 0x38 */ + { 0x00400000, 0x00400000, 0x00800000, 0x00800000 }, + { 0x00800000, 0x01000000, 0x00000000, 0x00000000 }, + { 0x00800000, 0x00800000, 0x00800000, 0x01000000 }, + { 0x00800000, 0x00800000, 0x01000000, 0x00000000 }, + { 0x00800000, 0x00800000, 0x01000000, 0x01000000 }, + { 0x00800000, 0x00800000, 0x02000000, 0x00000000 }, + { 0x00800000, 0x00800000, 0x02000000, 0x02000000 } }; + +static uint32_t +sis_85c471_get_row(ram_bank_t *dev, uint32_t addr) +{ + uint32_t ret = 0x00000000; + + switch (dev->virt_size) { + case 0x04000000: + ret = (addr >> 14) & 0x00000fff; + break; + case 0x01000000: + ret = (addr >> 13) & 0x000007ff; + break; + case 0x00400000: + ret = (addr >> 12) & 0x000003ff; + break; + case 0x00100000: + ret = (addr >> 11) & 0x000001ff; + break; + } + + return ret; +} + +static uint32_t +sis_85c471_get_col(ram_bank_t *dev, uint32_t addr) +{ + uint32_t ret = 0x00000000; + + switch (dev->virt_size) { + case 0x04000000: + ret = (addr >> 2) & 0x00000fff; + break; + case 0x01000000: + ret = (addr >> 2) & 0x000007ff; + break; + case 0x00400000: + ret = (addr >> 2) & 0x000003ff; + break; + case 0x00100000: + ret = (addr >> 2) & 0x000001ff; + break; + } + + return ret; +} + +static uint32_t +sis_85c471_set_row(ram_bank_t *dev, uint32_t addr) +{ + uint32_t ret = 0x00000000; + + switch (dev->phys_size) { + case 0x04000000: + ret = (addr & 0x00000fff) << 14; + break; + case 0x01000000: + ret = (addr & 0x000007ff) << 13; + break; + case 0x00400000: + ret = (addr & 0x000003ff) << 12; + break; + case 0x00100000: + ret = (addr & 0x000002ff) << 11; + break; + } + + return ret; +} + +static uint32_t +sis_85c471_set_col(ram_bank_t *dev, uint32_t addr) +{ + uint32_t ret = 0x00000000; + + switch (dev->phys_size) { + case 0x04000000: + ret = (addr & 0x00000fff) << 2; + break; + case 0x01000000: + ret = (addr & 0x000007ff) << 2; + break; + case 0x00400000: + ret = (addr & 0x000003ff) << 2; + break; + case 0x00100000: + ret = (addr & 0x000002ff) << 2; + break; + } + + return ret; +} + +static uint8_t +sis_85c471_read_ram(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + uint8_t ret = 0xff; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + ret = ram[addr]; + + return ret; +} + +static uint16_t +sis_85c471_read_ramw(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + uint16_t ret = 0xffff; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + ret = *(uint16_t *) &(ram[addr]); + + return ret; +} + +static uint32_t +sis_85c471_read_raml(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + uint32_t ret = 0xffffffff; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + ret = *(uint32_t *) &(ram[addr]); + + return ret; +} + +static void +sis_85c471_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + ram[addr] = val; +} + +static void +sis_85c471_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + *(uint16_t *) &(ram[addr]) = val; +} + +static void +sis_85c471_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint32_t rel = addr - dev->virt_base; + + if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; + } + + addr = (rel + dev->phys_base); + + if ((addr < (mem_size << 10)) && (rel < dev->phys_size)) + *(uint32_t *) &(ram[addr]) = val; +} + static void sis_85c4xx_recalcremap(sis_85c4xx_t *dev) { @@ -158,6 +474,60 @@ sis_85c4xx_sw_smi_handler(sis_85c4xx_t *dev) NULL, NULL, NULL, sis_85c4xx_sw_smi_out, NULL, NULL, dev); } +static void +sis_85c471_banks_split(uint32_t *b_ex, uint32_t *banks) +{ + for (uint8_t i = 0; i < 4; i++) { + if ((banks[i] == 0x00200000) || (banks[i] == 0x00800000) || + (banks[i] == 0x02000000)) + b_ex[i << 1] = b_ex[(i << 1) + 1] = banks[i] >> 1; + else { + b_ex[i << 1] = banks[i]; + b_ex[(i << 1) + 1] = 0x00000000; + } + } +} + +static void +sis_85c471_banks_recalc(sis_85c4xx_t *dev) +{ + for (uint8_t i = 0; i < 8; i++) + mem_mapping_disable(&dev->ram_banks[i].mapping); + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_high_mapping); + mem_set_mem_state_both(1 << 20, 127 << 20, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if ((dev->regs[0x09] & 0x3f) == dev->ram_banks_val) { + if (mem_size > 1024) { + mem_mapping_enable(&ram_low_mapping); + mem_mapping_enable(&ram_high_mapping); + mem_set_mem_state_both(1 << 20, (mem_size << 10) - (1 << 20), + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + } else { + uint8_t banks_val = dev->regs[0x09] & 0x3f; + uint32_t *banks = banks_471[banks_val]; + uint32_t b_ex[8] = { 0x00000000 }; + uint32_t size = 0x00000000; + + sis_85c471_banks_split(b_ex, banks); + + for (uint8_t i = 0; i < 8; i++) if (b_ex[i] != 0x00000000) { + dev->ram_banks[i].virt_base = size; + dev->ram_banks[i].virt_size = b_ex[i]; + + mem_mapping_set_addr(&dev->ram_banks[i].mapping, size, b_ex[i]); + + size += b_ex[i]; + } + + mem_set_mem_state_both(1 << 20, 127 << 20, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + + flushmmucache_nopc(); +} + static void sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) { @@ -192,6 +562,11 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) sis_85c4xx_recalcmapping(dev); break; + case 0x09: + if (dev->is_471) + sis_85c471_banks_recalc(dev); + break; + case 0x0b: sis_85c4xx_sw_smi_handler(dev); if (valxor & 0x02) @@ -297,14 +672,6 @@ sis_85c4xx_reset(void *priv) { sis_85c4xx_t *dev = (sis_85c4xx_t *) priv; int mem_size_mb = mem_size >> 10; - static uint8_t ram_4xx[64] = { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, 0x04, 0x04, 0x05, 0x05, 0x0b, 0x0b, 0x0b, 0x0b, - 0x13, 0x21, 0x06, 0x06, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }; memset(dev->regs, 0x00, sizeof(dev->regs)); @@ -318,8 +685,25 @@ sis_85c4xx_reset(void *priv) dev->regs[0x09] |= 0x22; else dev->regs[0x09] |= 0x24; - } else + } else if (!strcmp(machine_get_internal_name(), "tg486g")) + dev->regs[0x09] |= ram_tg486g[mem_size_mb]; + else dev->regs[0x09] |= ram_471[mem_size_mb]; + dev->ram_banks_val = dev->regs[0x09] & 0x3f; + dev->regs[0x09] = 0x00; + + uint32_t *banks = banks_471[dev->ram_banks_val]; + uint32_t b_ex[8] = { 0x00000000 }; + uint32_t size = 0x00000000; + + sis_85c471_banks_split(b_ex, banks); + + for (uint8_t i = 0; i < 8; i++) { + dev->ram_banks[i].phys_base = size; + dev->ram_banks[i].phys_size = b_ex[i]; + + size += b_ex[i]; + } dev->regs[0x11] = 0x09; dev->regs[0x12] = 0xff; @@ -332,6 +716,8 @@ sis_85c4xx_reset(void *priv) port_92_remove(dev->port_92); soft_reset_mask = 0; + + sis_85c471_banks_recalc(dev); } else { /* Bits 6 and 7 must be clear on the SiS 40x. */ if (dev->reg_base == 0x60) @@ -380,6 +766,14 @@ sis_85c4xx_init(const device_t *info) dev->smram = smram_add(); dev->port_92 = device_add(&port_92_device); + + for (uint8_t i = 0; i < 8; i++) { + mem_mapping_add(&dev->ram_banks[i].mapping, 0x00000000, 0x00000000, + sis_85c471_read_ram, sis_85c471_read_ramw, sis_85c471_read_raml, + sis_85c471_write_ram, sis_85c471_write_ramw, sis_85c471_write_raml, + NULL, MEM_MAPPING_INTERNAL, &(dev->ram_banks[i])); + mem_mapping_disable(&dev->ram_banks[i].mapping); + } } else dev->reg_last = dev->reg_base + 0x11; From a2abb497e2d75d67cc9d4482a785e7910aabcc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= <13226155+dhrdlicka@users.noreply.github.com> Date: Thu, 1 May 2025 21:02:59 +0200 Subject: [PATCH 0827/1190] Fix header guard warning --- src/qt/qt_iconindicators.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_iconindicators.hpp b/src/qt/qt_iconindicators.hpp index 861e41d94..12f82f259 100644 --- a/src/qt/qt_iconindicators.hpp +++ b/src/qt/qt_iconindicators.hpp @@ -1,5 +1,5 @@ #ifndef QT_ICONINDICATORS_HPP -# define QT_INDICATORS_HPP +# define QT_ICONINDICATORS_HPP #include #include @@ -14,4 +14,4 @@ enum IconIndicator { QPixmap getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator); -#endif \ No newline at end of file +#endif From a72142f2b5395e04e40cbf0ecb0dd3ed73174d39 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Fri, 2 May 2025 10:51:34 +1200 Subject: [PATCH 0828/1190] Fix EGA/VGA/SVGA odd-even handling of write mask Matches my AMD Stoney + S3 Trio64V2, and also Intel's 2023 GPU docs (which *still* tend to be more accurate than IBM's), and makes more sense than what we've (I've?) been doing. --- src/video/vid_ega.c | 4 +--- src/video/vid_svga.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 8333e522e..b828239c0 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -1180,9 +1180,7 @@ ega_write(uint32_t addr, uint8_t val, void *priv) cycles -= video_timing_write_b; if (ega->chain2_write) { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; + writemask2 &= 0x5 << (addr & 1); } addr = ega_remap_cpu_addr(addr, ega); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 67469ed22..86a57c00e 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1689,9 +1689,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *priv) addr &= ~3; addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_write) { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; + writemask2 &= 0x5 << (addr & 1); addr &= ~1; addr <<= 2; } else From 5e85f4533a18026311f5249b1cab826034a590a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Fri, 2 May 2025 02:06:02 +0200 Subject: [PATCH 0829/1190] Update RAM limits for SiS 471 machines --- src/machine/machine_table.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c269c7b0f..77132b6b5 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7089,7 +7089,7 @@ const machine_t machines[] = { .flags = MACHINE_APM, .ram = { .min = 1024, - .max = 65536, + .max = 131072, .step = 1024 }, .nvrmask = 127, @@ -7129,7 +7129,7 @@ const machine_t machines[] = { .flags = MACHINE_APM, .ram = { .min = 1024, - .max = 65536, + .max = 131072, .step = 1024 }, .nvrmask = 127, @@ -7209,7 +7209,7 @@ const machine_t machines[] = { .flags = MACHINE_APM, .ram = { .min = 1024, - .max = 65536, + .max = 131072, .step = 1024 }, .nvrmask = 127, @@ -7249,7 +7249,7 @@ const machine_t machines[] = { .flags = MACHINE_APM, .ram = { .min = 1024, - .max = 65536, + .max = 131072, .step = 1024 }, .nvrmask = 127, @@ -7368,9 +7368,9 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2, .flags = MACHINE_IDE_DUAL | MACHINE_SUPER_IO | MACHINE_APM | MACHINE_VIDEO, .ram = { - .min = 1024, - .max = 65536, - .step = 1024 + .min = 4096, + .max = 69632, + .step = 4096 }, .nvrmask = 127, .kbc_device = NULL, From 7885c28ea2ad5597d8c52c73b750d59a0bce2ad4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 2 May 2025 02:17:09 +0200 Subject: [PATCH 0830/1190] SiS 471: Fix RAM bank values (and some other minor things), fixes #5534. --- src/chipset/sis_85c4xx.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 003b66697..51f7fd4e6 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -33,6 +33,7 @@ #include <86box/mem.h> #include <86box/smram.h> #include <86box/pic.h> +#include <86box/keyboard.h> #include <86box/machine.h> #include <86box/chipset.h> @@ -79,8 +80,8 @@ static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e }; + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d }; static uint8_t ram_tg486g[64] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, @@ -544,12 +545,23 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) case 0x23: if ((dev->cur_reg >= dev->reg_base) && (dev->cur_reg <= dev->reg_last)) { valxor = val ^ dev->regs[rel_reg]; - if (rel_reg == 0x00) + + if (!dev->is_471 && (rel_reg == 0x00)) dev->regs[rel_reg] = (dev->regs[rel_reg] & 0x1f) | (val & 0xe0); else dev->regs[rel_reg] = val; switch (rel_reg) { + case 0x00: + if (val & 0x01) { + kbc_at_set_fast_reset(0); + cpu_cpurst_on_sr = 1; + } else { + kbc_at_set_fast_reset(1); + cpu_cpurst_on_sr = 0; + } + break; + case 0x01: cpu_cache_ext_enabled = ((val & 0x84) == 0x84); cpu_update_waitstates(); @@ -560,6 +572,8 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) case 0x08: if (valxor) sis_85c4xx_recalcmapping(dev); + if (rel_reg == 0x08) + flushmmucache(); break; case 0x09: @@ -681,10 +695,16 @@ sis_85c4xx_reset(void *priv) if (dev->is_471) { dev->regs[0x09] = 0x40; if (mem_size_mb >= 64) { - if ((mem_size_mb >= 65) && (mem_size_mb < 68)) - dev->regs[0x09] |= 0x22; + if ((mem_size_mb >= 64) && (mem_size_mb < 68)) + dev->regs[0x09] |= 0x33; + if ((mem_size_mb >= 68) && (mem_size_mb < 72)) + dev->regs[0x09] |= 0x2b; + if ((mem_size_mb >= 72) && (mem_size_mb < 80)) + dev->regs[0x09] |= 0x2d; + if ((mem_size_mb >= 80) && (mem_size_mb < 96)) + dev->regs[0x09] |= 0x2f; else - dev->regs[0x09] |= 0x24; + dev->regs[0x09] |= 0x29; } else if (!strcmp(machine_get_internal_name(), "tg486g")) dev->regs[0x09] |= ram_tg486g[mem_size_mb]; else @@ -718,6 +738,9 @@ sis_85c4xx_reset(void *priv) soft_reset_mask = 0; sis_85c471_banks_recalc(dev); + + kbc_at_set_fast_reset(1); + cpu_cpurst_on_sr = 0; } else { /* Bits 6 and 7 must be clear on the SiS 40x. */ if (dev->reg_base == 0x60) From 384af874f5dee71ce0cd300d9186561d2d2227d8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 3 May 2025 17:02:30 +0600 Subject: [PATCH 0831/1190] Bochs VBE: Update for 0.9c ROM --- src/video/vid_bochs_vbe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index 36185214c..a87890c75 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -811,22 +811,22 @@ bochs_vbe_init(const device_t *info) dev->vram_size = device_get_config_int("memory") * (1 << 20); rom_init(&dev->bios_rom, "roms/video/bochs/VGABIOS-lgpl-latest.bin", - 0xc0000, 0x10000, 0xffff, 0x0000, + 0xc0000, 0x8000, 0x7fff, 0x0000, MEM_MAPPING_EXTERNAL); if (dev->id5_val == VBE_DISPI_ID4) { /* Patch the BIOS to match the PCI ID. */ dev->bios_rom.rom[0x010c] = 0xee; - dev->bios_rom.rom[0x8dff] -= (0xee - 0x34); + dev->bios_rom.rom[0x7fff] -= (0xee - 0x34); dev->bios_rom.rom[0x010d] = 0x80; - dev->bios_rom.rom[0x8dff] -= (0x80 - 0x12); + dev->bios_rom.rom[0x7fff] -= (0x80 - 0x12); dev->bios_rom.rom[0x010e] = 0xef; - dev->bios_rom.rom[0x8dff] -= (0xef - 0x11); + dev->bios_rom.rom[0x7fff] -= (0xef - 0x11); dev->bios_rom.rom[0x010f] = 0xbe; - dev->bios_rom.rom[0x8dff] -= (0xbe - 0x11); + dev->bios_rom.rom[0x7fff] -= (0xbe - 0x11); } video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_bochs); From e09a5007c5d7cde3d27fcba0dfb8ee8a96f9770c Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Sat, 3 May 2025 21:10:55 +0200 Subject: [PATCH 0832/1190] Fix Acer P3 Machine table entry... ... to make the onboard video's RAM configurable. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 77132b6b5..9c83f4b22 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8392,7 +8392,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &gd5434_onboard_pci_device, .snd_device = NULL, .net_device = NULL }, From c9d07c657c0cd8b33f5c93e989eda8db321fc1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jernej=20Simon=C4=8Di=C4=8D?= <1800143+jernejs@users.noreply.github.com> Date: Sat, 3 May 2025 21:58:14 +0200 Subject: [PATCH 0833/1190] Update sl-SI.po --- src/qt/languages/sl-SI.po | 196 +++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 7c2b36650..dcb3dbf50 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -37,7 +37,7 @@ msgid "&Hide status bar" msgstr "&Skrij statusno vrstico" msgid "Hide &toolbar" -msgstr "Hide &toolbar" +msgstr "Skrij &orodno vrstico" msgid "&Resizeable window" msgstr "S&premenljiva velikost okna" @@ -55,7 +55,7 @@ msgid "Qt (&OpenGL)" msgstr "Qt (&OpenGL)" msgid "Open&GL (3.0 Core)" -msgstr "Open&GL (Jedro 3.0)" +msgstr "Open&GL (jedro 3.0)" msgid "&VNC" msgstr "&VNC" @@ -64,10 +64,10 @@ msgid "Specify dimensions..." msgstr "&Določi velikost..." msgid "F&orce 4:3 display ratio" -msgstr "&Vsili 4:3 razmerje zaslona" +msgstr "&Vsili razmerje zaslona 4:3" msgid "&Window scale factor" -msgstr "&Faktor velikosti okna" +msgstr "&Faktor povečave okna" msgid "&0.5x" msgstr "&0.5x" @@ -100,7 +100,7 @@ msgid "&8x" msgstr "&8x" msgid "Filter method" -msgstr "&Metoda filtriranja" +msgstr "&Vrsta filtriranja" msgid "&Nearest" msgstr "&Najbližja" @@ -241,7 +241,7 @@ msgid "E&ject" msgstr "I&zvrzi" msgid "&Image..." -msgstr "Slika..." +msgstr "S&lika..." msgid "E&xport to 86F..." msgstr "&Izvozi v 86F..." @@ -355,7 +355,7 @@ msgid "Speed:" msgstr "Hitrost:" msgid "Frequency:" -msgstr "Pogostost:" +msgstr "Takt:" msgid "FPU:" msgstr "Procesor plavajoče vejice:" @@ -367,7 +367,7 @@ msgid "MB" msgstr "MB" msgid "Memory:" -msgstr "Spomin:" +msgstr "Pomnilnik:" msgid "Time synchronization" msgstr "Sinhronizacija časa" @@ -445,7 +445,7 @@ msgid "FM synth driver" msgstr "Gonilnik sintetizacije FM" msgid "Nuked (more accurate)" -msgstr "Nuked (točnejši)" +msgstr "Nuked (natančnejši)" msgid "YMFM (faster)" msgstr "YMFM (hitrejši)" @@ -487,22 +487,22 @@ msgid "Serial port 4" msgstr "Serijska vrata 4" msgid "Parallel port 1" -msgstr "Paralelna vrata 1" +msgstr "Vzporedna vrata 1" msgid "Parallel port 2" -msgstr "Paralelna vrata 2" +msgstr "Vzporedna vrata 2" msgid "Parallel port 3" -msgstr "Paralelna vrata 3" +msgstr "Vzporedna vrata 3" msgid "Parallel port 4" -msgstr "Paralelna vrata 4" +msgstr "Vzporedna vrata 4" msgid "HD Controller:" msgstr "Krmilnik trdega diska:" msgid "FD Controller:" -msgstr "Krmilnik disketnika:" +msgstr "Disketni krmilnik:" msgid "Tertiary IDE Controller" msgstr "Terciarni krmilnik IDE" @@ -550,7 +550,7 @@ msgid "ID:" msgstr "ID:" msgid "&Specify..." -msgstr "Določi..." +msgstr "&Določi..." msgid "Sectors:" msgstr "Sektorji:" @@ -595,7 +595,7 @@ msgid "ZIP 250" msgstr "ZIP 250" msgid "ISA RTC:" -msgstr "Ura v realnem času ISA:" +msgstr "Ura realnega časa ISA:" msgid "ISA Memory Expansion" msgstr "Razširitev pomnilnika ISA" @@ -643,7 +643,7 @@ msgid "ZIP images" msgstr "ZIP slike" msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." -msgstr "86Box ni našel nobenih uporabnih ROM slik.\n\nProsim prenesite set ROM-ov in ga razširite v mapo \"roms\"." +msgstr "86Box ni našel nobenih uporabnih ROM slik.\n\nProsim prenesite komplet ROM-ov in ga razširite v mapo \"roms\"." msgid "(empty)" msgstr "(prazno)" @@ -751,7 +751,7 @@ msgid "Type" msgstr "Vrsta" msgid "No PCap devices found" -msgstr "Nobena naprava PCap ni bila najdena" +msgstr "Najdena ni bila nobena naprava PCap" msgid "Invalid PCap device" msgstr "Neveljavna naprava PCap" @@ -874,16 +874,16 @@ msgid "Don't exit" msgstr "Prekliči izhod" msgid "Reset" -msgstr "Resetiraj" +msgstr "Znova zaženi" msgid "Don't reset" -msgstr "Ne resetiraj" +msgstr "Ne zaženi znova" msgid "CD-ROM images" msgstr "Slike CD-ROM" msgid "%1 Device Configuration" -msgstr "Konfiguracija naprave %1" +msgstr "Nastavitev naprave %1" msgid "Monitor in sleep mode" msgstr "Zaslon v načinu spanja" @@ -946,7 +946,7 @@ msgid "Add New Hard Disk" msgstr "Dodaj nov trdi disk" msgid "Add Existing Hard Disk" -msgstr "Dodaj obstoječ trdi disk" +msgstr "Dodaj obstoječi trdi disk" msgid "HDI disk images cannot be larger than 4 GB." msgstr "Slike diska HDI ne morejo biti večje od 4 GB." @@ -1048,13 +1048,13 @@ msgid "VHD files" msgstr "Datoteke VHD" msgid "Select the parent VHD" -msgstr "Izberite starševsko sliko VHD" +msgstr "Izberite nadrejeno sliko VHD" msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" -msgstr "To lahko pomeni, da je bila starševska slika spremenjena potem, ko je že bila ustvarjena diferencialna slika.\n\nDo tega lahko pride tudi kadar so datoteke slik diska premaknjene ali kopirane, ali pa gre za hrošča v programu, ki je ustvaril ta disk.\n\nŽelite popraviti časovni žig?" +msgstr "To lahko pomeni, da je bila nadrejena slika spremenjena po ustvaritvi diferencialne slike.\n\nDo tega lahko pride tudi kadar so datoteke slik diska premaknjene ali kopirane, ali pa gre za hrošča v programu, ki je ustvaril ta disk.\n\nŽelite popraviti časovni žig?" msgid "Parent and child disk timestamps do not match" -msgstr "Časovna žiga starševske slike diska in slike diska otroka se ne ujemata" +msgstr "Časovna žiga nadrejene in podrejene slike diska se ne ujemata" msgid "Could not fix VHD timestamp." msgstr "Ne morem popraviti časovnega žiga slike VHD." @@ -1105,10 +1105,10 @@ msgid "1.44 MB" msgstr "1.44 MB" msgid "DMF (cluster 1024)" -msgstr "DMF (grozd 1024)" +msgstr "DMF (gruča 1024)" msgid "DMF (cluster 2048)" -msgstr "DMF (grozd 2048)" +msgstr "DMF (gruča 2048)" msgid "2.88 MB" msgstr "2.88 MB" @@ -1162,7 +1162,7 @@ msgid "(System Default)" msgstr "(Sistemsko privzeto)" msgid "Failed to initialize network driver" -msgstr "Ni uspelo inicializirati omrežnega gonilnika" +msgstr "Inicializacija omrežnega gonilnika ni uspela" msgid "The network configuration will be switched to the null driver" msgstr "Omrežne nastavitve bodo preklopljene na ničelni gonilnik" @@ -1234,7 +1234,7 @@ msgid "Open screenshots folder..." msgstr "Odprite mapo s posnetki zaslona..." msgid "Apply fullscreen stretch mode when maximized" -msgstr "Uporabi način celozaslonskega raztezanja v povečanem stanju" +msgstr "Uporabi način celozaslonskega raztezanja v maksimiranem stanju" msgid "Cursor/Puck" msgstr "Kazalec/ključ" @@ -1243,19 +1243,19 @@ msgid "Pen" msgstr "Pisalo" msgid "Host CD/DVD Drive (%1:)" -msgstr "Pogon CD/DVD gostitelja (%1:)" +msgstr "Gostiteljski pogon CD/DVD (%1:)" msgid "&Connected" msgstr "&Povezan" msgid "Clear image history" -msgstr "Jasna zgodovina slik" +msgstr "Počisti zgodovino slik" msgid "Create..." msgstr "Ustvari..." msgid "Host CD/DVD Drive (%1)" -msgstr "Pogon CD/DVD gostitelja (%1)" +msgstr "Gostiteljski pogon CD/DVD (%1)" msgid "Unknown Bus" msgstr "Neznano vodilo" @@ -1288,7 +1288,7 @@ msgid "Remove" msgstr "Odstrani" msgid "Browse..." -msgstr "Brskaj..." +msgstr "Prerskaj..." msgid "Couldn't create OpenGL context." msgstr "Ni bilo mogoče ustvariti konteksta OpenGL." @@ -1297,13 +1297,13 @@ msgid "Couldn't switch to OpenGL context." msgstr "Ni bilo mogoče preklopiti na kontekst OpenGL." msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" -msgstr "Zahteva se različica OpenGL 3.0 ali novejša. Trenutna različica je %1.%2" +msgstr "Potrebna je OpenGL različica 3.0 ali novejša. Trenutna različica je %1.%2" msgid "Error initializing OpenGL" msgstr "Napaka pri inicializaciji OpenGL" msgid "\nFalling back to software rendering." -msgstr "\nVrnitev k programskemu upodabljanju." +msgstr "\nVrnitev na programsko upodabljanje." msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" msgstr "<html><head/><body><p>Pri izbiri medijskih slik (CD-ROM, disketa itd.) se bo odprto pogovorno okno začelo v istem imeniku kot konfiguracijska datoteka 86Box. Ta nastavitev bo verjetno imela pomen le v operacijskem sistemu MacOS.</p></body></html>" @@ -1312,7 +1312,7 @@ msgid "This machine might have been moved or copied." msgstr "Ta naprava je bila morda premeščena ali kopirana." msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." -msgstr "Da bi zagotovili pravilno delovanje omrežja, mora 86Box vedeti, ali je bil ta stroj prestavljen ali kopiran.\n\nČe niste prepričani, izberite \"Kopiral sem jo\"." +msgstr "Da bi zagotovili pravilno delovanje omrežja, mora 86Box vedeti, ali je bil ta virtualna naprava prestavljena ali kopirana.\n\nČe niste prepričani, izberite \"Kopiral sem jo\"." msgid "I Moved It" msgstr "Premaknil sem jo" @@ -1348,7 +1348,7 @@ msgid "Interface:" msgstr "Vmesnik:" msgid "Adapter:" -msgstr "Adapter:" +msgstr "Mrežna kartica:" msgid "VDE Socket:" msgstr "Vtičnica VDE:" @@ -1396,7 +1396,7 @@ msgid "3M MicroTouch (Serial)" msgstr "3M MicroTouch (serijska)" msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standardni modem v skladu s standardom Hayes" +msgstr "[COM] Standardni modem v skladen s Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulacija Roland MT-32" @@ -1411,10 +1411,10 @@ msgid "Roland CM-32LN Emulation" msgstr "Emulacija Roland CM-32LN" msgid "OPL4-ML Daughterboard" -msgstr "Hčerinska plošča OPL4-ML" +msgstr "Dodatna kartica OPL4-ML" msgid "System MIDI" -msgstr "Sistem MIDI" +msgstr "Sistemski MIDI" msgid "MIDI Input Device" msgstr "Vhodna naprava MIDI" @@ -1423,7 +1423,7 @@ msgid "BIOS Address" msgstr "Naslov BIOS-a" msgid "Enable BIOS extension ROM Writes" -msgstr "Omogočanje razširitve BIOS-a ROM piše" +msgstr "Omogoči zapisovanje razširitev BIOS ROM-a" msgid "Address" msgstr "Naslov" @@ -1435,7 +1435,7 @@ msgid "BIOS Revision" msgstr "Revizija BIOS-a" msgid "Translate 26 -> 17" -msgstr "Prevesti 26 -> 17" +msgstr "Prevedi 26 -> 17" msgid "Language" msgstr "Jezik" @@ -1450,25 +1450,25 @@ msgid "BIOS size" msgstr "Velikost BIOS-a" msgid "Map C0000-C7FFF as UMB" -msgstr "Zemljevid C0000-C7FFF kot UMB" +msgstr "Preslikaj C0000-C7FFF kot UMB" msgid "Map C8000-CFFFF as UMB" -msgstr "Zemljevid C8000-CFFFF kot UMB" +msgstr "Preslikaj C8000-CFFFF kot UMB" msgid "Map D0000-D7FFF as UMB" -msgstr "Zemljevid D0000-D7FFF kot UMB" +msgstr "Preslikaj D0000-D7FFF kot UMB" msgid "Map D8000-DFFFF as UMB" -msgstr "Zemljevid D8000-DFFFF kot UMB" +msgstr "Preslikaj D8000-DFFFF kot UMB" msgid "Map E0000-E7FFF as UMB" -msgstr "Zemljevid E0000-E7FFF kot UMB" +msgstr "Preslikaj E0000-E7FFF kot UMB" msgid "Map E8000-EFFFF as UMB" -msgstr "Zemljevid E8000-EFFFF kot UMB" +msgstr "Preslikaj E8000-EFFFF kot UMB" msgid "JS9 Jumper (JIM)" -msgstr "JS9 Jumper (JIM)" +msgstr "JS9 mostiček (JIM)" msgid "MIDI Output Device" msgstr "Izhodna naprava MIDI" @@ -1582,10 +1582,10 @@ msgid "RAM Address" msgstr "Naslov RAM" msgid "RAM size" -msgstr "Velikost pomnilnika RAM" +msgstr "Velikost pomnilnika" msgid "Initial RAM size" -msgstr "Začetna velikost pomnilnika RAM" +msgstr "Začetna velikost pomnilnika" msgid "Serial Number" msgstr "Serijska številka" @@ -1597,7 +1597,7 @@ msgid "FDC Address" msgstr "Naslov FDC" msgid "MPU-401 Address" -msgstr "MPU-401 Naslov" +msgstr "Naslov MPU-401" msgid "MPU-401 IRQ" msgstr "MPU-401 IRQ" @@ -1633,7 +1633,7 @@ msgid "Enable OPL" msgstr "Omogoči OPL" msgid "Receive MIDI input (MPU-401)" -msgstr "Sprejemaj vhod MIDI (MPU-401)" +msgstr "Vhod MIDI za sprejem (MPU-401)" msgid "SB low DMA" msgstr "Nizki DMA SB" @@ -1666,7 +1666,7 @@ msgid "Codec" msgstr "Kodek" msgid "GUS type" -msgstr "Tip GUS" +msgstr "Vrsta GUS" msgid "Enable 0x04 \"Exit 86Box\" command" msgstr "Omogoči ukaz 0x04 \"Zapusti 86Box\"" @@ -1681,7 +1681,7 @@ msgid "RGB type" msgstr "Vrsta RGB zaslona" msgid "Line doubling type" -msgstr "Vrsta podvojitve črt" +msgstr "Vrsta podvojevanja črt" msgid "Snow emulation" msgstr "Emulacija snega" @@ -1693,16 +1693,16 @@ msgid "Character set" msgstr "Nabor znakov" msgid "XGA type" -msgstr "Tip kartice XGA" +msgstr "Vrsta kartice XGA" msgid "Instance" -msgstr "Primer" +msgstr "Primerek" msgid "MMIO Address" msgstr "Naslov MMIO" msgid "RAMDAC type" -msgstr "Vrsta čipa RAMDAC" +msgstr "Vrsta RAMDAC" msgid "Blend" msgstr "Mešanica" @@ -1714,13 +1714,13 @@ msgid "Dithering" msgstr "Barvno stresanje" msgid "Enable NMI for CGA emulation" -msgstr "Omogočite NMI za emulacijo CGA" +msgstr "Omogoči NMI za emulacijo CGA" msgid "Voodoo type" -msgstr "Tip kartice Voodoo" +msgstr "Vrsta kartice Voodoo" msgid "Framebuffer memory size" -msgstr "Velikost pomnilnika predpomnilnika okvirja" +msgstr "Velikost videopomnilnika" msgid "Texture memory size" msgstr "Velikost pomnilnika tekstur" @@ -1732,7 +1732,7 @@ msgid "Screen Filter" msgstr "Filter zaslona" msgid "Render threads" -msgstr "Nitke za upodabljanje" +msgstr "Niti za upodabljanje" msgid "SLI" msgstr "SLI" @@ -1795,7 +1795,7 @@ msgid "Non-timed (original)" msgstr "Brez časovnika (izvirnik)" msgid "45 Hz (JMP2 not populated)" -msgstr "45 Hz (brez mostička na JMP2)" +msgstr "45 Hz (brez mostička JMP2)" msgid "Two" msgstr "Dva" @@ -1804,13 +1804,13 @@ msgid "Three" msgstr "Tri" msgid "Wheel" -msgstr "Kolesa" +msgstr "Kolesce" msgid "Five + Wheel" -msgstr "Pet + kolo" +msgstr "Pet + kolesce" msgid "Five + 2 Wheels" -msgstr "" +msgstr "Pet + 2 kolesci" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 serijska / SMT3(R)V" @@ -1885,13 +1885,13 @@ msgid "Color (generic)" msgstr "Barvni (generični)" msgid "Green Monochrome" -msgstr "Zeleni enobvarni" +msgstr "Zeleni monokromatski" msgid "Amber Monochrome" -msgstr "Jantarni enobarvni" +msgstr "Jantarni monokromatski" msgid "Gray Monochrome" -msgstr "Sivi enobarvni" +msgstr "Sivi monokromatski" msgid "Color (no brown)" msgstr "Barvni (brez rjave)" @@ -1912,13 +1912,13 @@ msgid "128 KB" msgstr "128 KB" msgid "Monochrome (5151/MDA) (white)" -msgstr "Enobarvni (5151/MDA) (beli)" +msgstr "Monokromatski (5151/MDA) (beli)" msgid "Monochrome (5151/MDA) (green)" -msgstr "Enobarvni (5151/MDA) (zeleni)" +msgstr "Monokromatski (5151/MDA) (zeleni)" msgid "Monochrome (5151/MDA) (amber)" -msgstr "Enobarvni (5151/MDA) (jantarni)" +msgstr "Monokromatski (5151/MDA) (jantarni)" msgid "Color 40x25 (5153/CGA)" msgstr "Barvni 40x25 (5153/CGA)" @@ -1930,7 +1930,7 @@ msgid "Enhanced Color - Normal Mode (5154/ECD)" msgstr "Izboljšani barvni - običajni način (5154/ECD)" msgid "Enhanced Color - Enhanced Mode (5154/ECD)" -msgstr "Izboljšani barvni - Izboljšani način (5154/ECD)" +msgstr "Izboljšani barvni - izboljšani način (5154/ECD)" msgid "Green" msgstr "Zeleni" @@ -2008,7 +2008,7 @@ msgid "Generic PCL5e Printer" msgstr "Generični tiskalnik PCL5e" msgid "Parallel Line Internet Protocol" -msgstr "Internetni protokol za paralelno linijo" +msgstr "Internetni protokol za vzporedno linijo" msgid "Protection Dongle for Savage Quest" msgstr "Zaščitni ključek za Savage Quest" @@ -2029,7 +2029,7 @@ msgid "Data bits" msgstr "Podatkovni biti" msgid "Stop bits" -msgstr "Stop biti" +msgstr "Zaključni biti" msgid "Baud Rate of Passthrough" msgstr "Baudna hitrost prepusta" @@ -2038,7 +2038,7 @@ msgid "Named Pipe (Server)" msgstr "Poimenovana cev (Strežnik)" msgid "Host Serial Passthrough" -msgstr "Prepustno serijskih vrat gostitelja" +msgstr "Prepust serijskih vrat gostitelja" msgid "E&ject %1" msgstr "I&zvrzi %1" @@ -2053,7 +2053,7 @@ msgid "High performance impact" msgstr "Visok učinek na hitrost delovanja" msgid "[Generic] RAM Disk (max. speed)" -msgstr "[Generic] Pogon RAM (največja hitrost)" +msgstr "[Generic] Pomnilniški disk (največja hitrost)" msgid "[Generic] 1989 (3500 RPM)" msgstr "" @@ -2089,28 +2089,28 @@ msgid "Generic PC/AT Memory Expansion" msgstr "Generična razširitev pomnilnika PC/AT" msgid "Unable to find Dot-Matrix fonts" -msgstr "Matričnih pisav ni bilo mogoče najti" +msgstr "Ni bilo mogoče najti matričnih pisav" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P Dot-Matrix Printer." -msgstr "Matrične pisave v imeniku \"roms/printer/fonts\" so potrebne za emulacijo generičnega matričnega tiskalnika ESC/P." +msgstr "Za emulacijo generičnega ESC/P matričnega tiskalnika so potrebne TrueType pisave v imeniku \"roms/printer/fonts\"." msgid "Inhibit multimedia keys" -msgstr "" +msgstr "Blokiraj multimedijske tipke" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "Vprašaj za potrditev pred shranjevanjem nastavitev" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "Vprašaj za potrditev pred ponovnim zagonom" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "Vprašaj za potrditev pred izhodom" msgid "Display hotkey message when entering full-screen mode" -msgstr "" +msgstr "Prikaži obvestilo o bližnjični tipki pri prehodu v celozaslonski način" msgid "Options" -msgstr "" +msgstr "Možnosti" msgid "Model" msgstr "" @@ -2119,40 +2119,40 @@ msgid "Model:" msgstr "" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Inicializacija upodobljevalnika Vulkan ni uspela." msgid "GLSL Error" -msgstr "" +msgstr "Napaka GLSL" msgid "Could not load shader: %1" -msgstr "" +msgstr "Ni bilo mogoče naložiti senčilnika: %1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "Potrebna je OpenGL različica 3.0 ali novejša. Trenutna različica GLSL je %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "Ni bilo mogoče naložiti teksture: %1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "Ni bilo mogoče prevesti senčilnika:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "Program ni povezan:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "Upravljalnik senčilnikov" msgid "Shader Configuration" -msgstr "" +msgstr "Nastavitve senčilnikov" msgid "Add" -msgstr "" +msgstr "Dodaj" msgid "Move up" -msgstr "" +msgstr "Premakni gor" msgid "Move down" -msgstr "" +msgstr "Premakni dol" msgid "Could not load file %1" -msgstr "" +msgstr "Ni bilo mogoče naložiti datoteke %1" From b1d409471c37bac854a551cbeedfae45c04e2d9d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 4 May 2025 02:01:34 +0200 Subject: [PATCH 0834/1190] Fixes to the S3 911/924 of the night (May 4th, 2025) 1. Actually mostly workarounds to make it render normally without a hitch (I hope) using the Diamond Stealth VRAM 911-based 15bpp driver. 2. Updated logs. --- src/video/vid_s3.c | 240 +++++++++++++++++++++++++++++---------------- 1 file changed, 156 insertions(+), 84 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 8fa392891..d6b91903a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -234,6 +234,8 @@ typedef struct s3_t { uint8_t advfunc_cntl; uint16_t cur_y, cur_y2; uint16_t cur_x, cur_x2; + uint16_t cur_x_overflow; + uint16_t destx_overflow; uint16_t x2, ropmix; uint16_t pat_x, pat_y; int16_t desty_axstp, desty_axstp2; @@ -288,6 +290,7 @@ typedef struct s3_t { int16_t minus; int rd_mask_16bit_check; int start; + int mix_dat_upper; /*For non-threaded FIFO*/ int setup_fifo_slot; @@ -657,22 +660,29 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) val = (val >> 8) | (val << 8); s3->accel_start(16, 1, val | (val << 16), 0, s3); - } else - s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - } else { - if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cmd == 0x53f1) { + } else { + if ((s3->accel.cmd == 0x53f1) || (s3->accel.cmd == 0x53b1)) { if (s3->accel.cur_x & 0x400) val = (val >> 8) | (val << 8); s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); val = (val >> 8) | (val << 8); - s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - } else - s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - } else + } s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } else { + if (s3->accel.rd_mask_16bit_check) { + if ((s3->accel.cmd == 0x53f1) || (s3->accel.cmd == 0x53b1)) { + if (s3->accel.cur_x & 0x400) + val = (val >> 8) | (val << 8); + + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + + val = (val >> 8) | (val << 8); + } + } + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } break; case 0x400: @@ -808,12 +818,14 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x8548: case 0x86e8: s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + s3->accel.cur_x_overflow = (s3->accel.cur_x_overflow & 0xff00) | val; s3->accel.poly_cx = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; break; case 0x8549: case 0x86e9: s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x0f) << 8); + s3->accel.cur_x_overflow = (s3->accel.cur_x_overflow & 0xff) | (val << 8); s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; s3_log("[%04X:%08X] OUT PORTB=%04x, val=%04x.\n", CS, cpu_state.pc, port - 1, s3->accel.cur_x); @@ -859,11 +871,13 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x8d48: case 0x8ee8: s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.destx_overflow = (s3->accel.destx_overflow & 0xff00) | val; s3->accel.point_1_updated = 1; break; case 0x8d49: case 0x8ee9: s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + s3->accel.destx_overflow = (s3->accel.destx_overflow & 0xff) | (val << 8); if (val & 0x20) s3->accel.destx_distp |= ~0x3fff; s3->accel.point_1_updated = 1; @@ -5763,6 +5777,8 @@ s3_accel_in_w(uint16_t port, void *priv) s3_t *s3 = (s3_t *) priv; svga_t *svga = &s3->svga; uint16_t temp = 0x0000; + uint16_t temp1 = 0x0000; + uint16_t temp2 = 0x0000; const uint16_t *vram_w = (uint16_t *) svga->vram; if (!s3->enable_8514) @@ -5774,7 +5790,7 @@ s3_accel_in_w(uint16_t port, void *priv) switch (s3->accel.cmd & 0x600) { case 0x000: - if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 0x02)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = (temp >> 8) | (temp << 8); @@ -5800,15 +5816,31 @@ s3_accel_in_w(uint16_t port, void *priv) } break; case 0x200: - if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 0x02)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = (temp >> 8) | (temp << 8); + s3->accel_start(16, 1, temp | (temp << 16), 0, s3); } else s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } else { - s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cmd == 0x53b0) { + temp1 = vram_w[dword_remap_w(svga, s3->accel.dest + s3->accel.cx - s3->accel.minus) & (s3->vram_mask >> 1)]; + temp2 = vram_w[dword_remap_w(svga, s3->accel.dest + s3->accel.cx - s3->accel.minus + 1) & (s3->vram_mask >> 1)]; + if (s3->accel.cur_x & 0x400) { + temp = temp1 >> 8; + temp |= (temp2 >> 8) << 8; + } else { + temp = temp1 & 0xff; + temp |= ((temp2 & 0xff) << 8); + } + s3->accel_start(4, 1, 0xffffffff, temp | (temp << 16), s3); + } else + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + } else + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } break; @@ -7878,7 +7910,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on the NOP command)*/ - s3_log("CMD=%d, full=%04x, s3bpp=%x, clr=%d, clb=%d, sourcedisplay=%x, mmio=%02x, srcbase=%08x, dstbase=%08x, cpu=%04x, mix=%04x, count=%d, rd_mask=%04x, wrt_mask=%04x, width=%d, s=%d,%d, c=%d,%d, d=%d,%d, 16bitcolor=%x, frgdcolor=%04x, bkgdcolor=%04x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, curx=%d, cury=%d, cll=%d, b2e8pix=%x.\n", cmd, s3->accel.cmd, s3->bpp, clip_r, clip_b, vram_mask, svga->crtc[0x53] & 0x18, srcbase, dstbase, cpu_dat & 0xffff, mix_dat & 0xffff, count, rd_mask, wrt_mask, s3->width, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->color_16bit, frgd_color, bkgd_color, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.cur_x, s3->accel.cur_y, clip_l, s3->accel.b2e8_pix); + s3_log("CMD=%d, full=%04x, s3bpp=%x, clr=%d, clb=%d, sourcedisplay=%02x, mmio=%02x, srcbase=%08x, dstbase=%08x, cpu=%04x, mix=%04x, count=%d, rd_mask=%04x, wrt_mask=%04x, width=%d, s=%d,%d, c=%d,%d, d=%d,%d, 16bitcolor=%x, frgdcolor=%04x, bkgdcolor=%04x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, curx=%d, cury=%d, cll=%d, b2e8pix=%x.\n", cmd, s3->accel.cmd, s3->bpp, clip_r, clip_b, s3->accel.multifunc[0x0a] & 0xc4, svga->crtc[0x53] & 0x18, srcbase, dstbase, cpu_dat & 0xffff, mix_dat & 0xffff, count, rd_mask, wrt_mask, s3->width, s3->accel.sx, s3->accel.sy, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->color_16bit, frgd_color, bkgd_color, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.cur_x, s3->accel.cur_y, clip_l, s3->accel.b2e8_pix); switch (cmd) { case 0: /*NOP (Short Stroke Vectors)*/ @@ -8279,8 +8311,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi case 2: /*Rectangle fill*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ { - s3->accel.start = 0; s3->accel.minus = 0; + s3->accel.mix_dat_upper = 0; s3->accel.color_16bit_check_pixtrans = 0; s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; s3->accel.sy = s3->accel.multifunc[0] & 0xfff; @@ -8292,11 +8324,37 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if ((s3->bpp == 0) && s3->color_16bit) { s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); if (s3->accel.rd_mask_16bit_check) { - s3->accel.start = 1; - if (s3->accel.cur_x & 0x400) { - s3->accel.minus = 0x400; - if ((s3->accel.cmd == 0x41b3) && (frgd_mix == 0)) - s3->accel.minus = 0; + if (s3->accel.cmd == 0x41b3) { + if (frgd_mix == 0) { + if (!(s3->accel.cur_x & 0x400)) + s3->accel.color_16bit_check = 0; + } else { + if ((s3->accel.cur_x_overflow & 0xc00) == 0xc00) + s3->accel.start = 1; + else { + if (s3->accel.start) { + s3->accel.start = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.start = 0; + if (s3->accel.cur_x_overflow & 0x400) + s3->accel.minus = 0x400; + } + } + } + } else { + if ((s3->accel.cur_x_overflow & 0xc00) == 0xc00) + s3->accel.start = 1; + else { + if (s3->accel.start) { + s3->accel.start = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.start = 0; + if (s3->accel.cur_x_overflow & 0x400) + s3->accel.minus = 0x400; + } + } } } else { if (s3->accel.cmd & 0x100) { @@ -8330,19 +8388,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi count = s3->accel.maj_axis_pcnt + 1; s3->accel.temp_cnt = 16; if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cur_x & 0x400) { - if (s3->accel.start) { - s3->accel.minus = 0x400; - s3->accel.start = 0; - } + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); } else { - if (s3->accel.start) { - s3->accel.minus = 0; - s3->accel.start = 0; - } wrt_mask = s3->accel.wrt_mask_actual[0]; frgd_color = s3->accel.frgd_color_actual[0]; bkgd_color = s3->accel.bkgd_color_actual[0]; @@ -8355,7 +8405,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (s3->accel.cmd == 0x41b3) { if (frgd_mix != 0) { if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cur_x & 0x400) { + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); @@ -8367,39 +8417,33 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi rd_mask &= 0x00ff; } else if (!s3->accel.rd_mask_16bit_check && (s3->accel.cur_x & 0x400)) break; + } else { + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); + } else { + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; + s3->accel.mix_dat_upper = !!(mix_dat & 0xff00); + } + rd_mask &= 0x00ff; + } } } else { if (s3->accel.rd_mask_16bit_check) { - rd_mask &= 0x00ff; - if (s3->accel.cmd == 0x53b3) { - if (clip_l & 0x400) { - if (s3->accel.start) { - s3->accel.minus = 0x400; - s3->accel.start = 0; - } - wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); - frgd_color = (s3->accel.frgd_color_actual[1] << 8); - bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); - } else { - if (s3->accel.start) { - s3->accel.minus = 0; - s3->accel.start = 0; - } - wrt_mask = s3->accel.wrt_mask_actual[0]; - frgd_color = s3->accel.frgd_color_actual[0]; - bkgd_color = s3->accel.bkgd_color_actual[0]; - } + if (s3->accel.minus) { + wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); + frgd_color = (s3->accel.frgd_color_actual[1] << 8); + bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); } else { - if (s3->accel.cur_x & 0x400) { - wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); - frgd_color = (s3->accel.frgd_color_actual[1] << 8); - bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); - } else { - wrt_mask = s3->accel.wrt_mask_actual[0]; - frgd_color = s3->accel.frgd_color_actual[0]; - bkgd_color = s3->accel.bkgd_color_actual[0]; - } + wrt_mask = s3->accel.wrt_mask_actual[0]; + frgd_color = s3->accel.frgd_color_actual[0]; + bkgd_color = s3->accel.bkgd_color_actual[0]; } + rd_mask &= 0x00ff; } else { if ((s3_cpu_src(s3)) && !(s3->accel.cmd & 0x200)) { s3_log("FIXME: S3 911/924 15/16bpp documentation needed.\n"); @@ -8414,6 +8458,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } + if (s3->accel.mix_dat_upper) + s3_log("CMDFULL=%04x, FRGDMIX=%x, BKGDCOLR=%04x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, OVERFLOW=%d.\n", s3->accel.cmd, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_color, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, (s3->accel.cur_x_overflow & 0xc00) == 0xc00); + while (count-- && (s3->accel.sy >= 0)) { if (s3->accel.b2e8_pix && s3_cpu_src(s3) && !s3->accel.temp_cnt) { mix_dat >>= 16; @@ -8535,15 +8582,13 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (cpu_input) { if (s3->accel.sy < 0) { if ((s3->bpp == 0) && s3->color_16bit) { - if ((s3->accel.cmd == 0x53b3) && !s3->accel.b2e8_pix) { - if (!(clip_l & 0x400)) - s3->accel.color_16bit_check = 1; - else + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) s3->accel.color_16bit_check = 0; - } else { - if (!(s3->accel.cur_x & 0x400)) - s3->accel.color_16bit_check = 1; else + s3->accel.color_16bit_check = 1; + + if ((s3->accel.cmd == 0x41b3) && (frgd_mix == 0)) s3->accel.color_16bit_check = 0; } } @@ -8556,10 +8601,12 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } if (s3->accel.sy < 0) { if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.cur_x & 0x400)) - s3->accel.color_16bit_check = 1; - else - s3->accel.color_16bit_check = 0; + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) + s3->accel.color_16bit_check = 0; + else + s3->accel.color_16bit_check = 1; + } } s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; @@ -8674,10 +8721,24 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.dx = s3->accel.destx_distp & 0xfff; s3->accel.dy = s3->accel.desty_axstp & 0xfff; - s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); - if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.destx_distp & 0x400) && s3->accel.rd_mask_16bit_check) - s3->accel.minus = 0x400; + if ((s3->bpp == 0) && s3->color_16bit) { + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + if (s3->accel.rd_mask_16bit_check) { + if (!(s3->accel.cmd & 0x40) && !(clip_r & 0x400)) + s3->accel.start = 1; + else { + if (s3->accel.start) { + s3->accel.start = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.start = 0; + if (s3->accel.destx_distp & 0x400) + s3->accel.minus = 0x400; + } + } + } + } if (s3->accel.destx_distp & 0x400) { s3_log("BitBLT + 1024 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, d=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x.\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.dx, s3->accel.dy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0); @@ -8698,7 +8759,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if ((s3->bpp == 0) && s3->color_16bit) { if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.destx_distp & 0x400) { + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); @@ -8712,6 +8773,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi break; } + if (!vram_mask && (frgd_mix == 3)) + s3_log("CMDFULL=%04x, FRGDMIX=%x, BKGDMIX=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00); + if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { while (1) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { @@ -8728,6 +8792,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.dx++; s3->accel.sx--; s3->accel.dx &= 0xfff; + if (s3->accel.sx < 0) { s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; @@ -8742,11 +8807,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.sy--; if (s3->accel.sy < 0) { - if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.destx_distp & 0x400)) - s3->accel.color_16bit_check = 1; - else + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) s3->accel.color_16bit_check = 0; + else + s3->accel.color_16bit_check = 1; } s3->accel.destx_distp = s3->accel.dx; s3->accel.desty_axstp = s3->accel.dy; @@ -8824,7 +8889,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.cx--; s3->accel.dx--; } - s3->accel.dx &= 0xfff; + if (s3->accel.rd_mask_16bit_check) + s3->accel.dx &= 0x7ff; + else + s3->accel.dx &= 0xfff; + s3->accel.sx--; if (s3->accel.sx < 0) { if (s3->accel.cmd & 0x20) { @@ -8850,21 +8919,24 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (cpu_input) { if (s3->accel.sy < 0) { - if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.destx_distp & 0x400)) - s3->accel.color_16bit_check = 1; - else + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) s3->accel.color_16bit_check = 0; + else + s3->accel.color_16bit_check = 1; } } return; } if (s3->accel.sy < 0) { - if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.destx_distp & 0x400)) - s3->accel.color_16bit_check = 1; + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) + s3->accel.color_16bit_check = 0; else + s3->accel.color_16bit_check = 1; + + if (s3->accel.mix_dat_upper && !vram_mask && (frgd_mix == 3)) s3->accel.color_16bit_check = 0; } s3->accel.destx_distp = s3->accel.dx; From 608ce2d15537751e594029b460c80c3d06cb0be3 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 4 May 2025 02:04:41 +0200 Subject: [PATCH 0835/1190] Another stall fix for the mach8/32. See above, covering the foreground and background select bits as well. --- src/video/vid_ati_mach8.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index ce6ee12d5..3537cf337 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -4264,12 +4264,14 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in if (dev->force_busy) { temp |= 0x0200; /*Hardware busy*/ if (mach->accel.cmd_type >= 0) { + frgd_sel = (mach->accel.dp_config >> 13) & 7; + bkgd_sel = (mach->accel.dp_config >> 7) & 3; mono_src = (mach->accel.dp_config >> 5) & 3; switch (mach->accel.cmd_type) { case 2: if (dev->accel.sy >= mach->accel.height) dev->force_busy = 0; - else if (mono_src == 2) + else if ((mono_src == 2) || (frgd_sel == 2) || (bkgd_sel == 2)) dev->force_busy = 0; break; case 5: From 3bce5e13f1c234f9f0e573679fe8389320bead30 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 May 2025 02:19:48 +0200 Subject: [PATCH 0836/1190] SiS 5511 Host to PCI bridge: Fix DRB unit, fixes AOpen AP5S soft reset. --- src/chipset/sis_5511_h2p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/sis_5511_h2p.c b/src/chipset/sis_5511_h2p.c index b94e69f26..c8cb44a0a 100644 --- a/src/chipset/sis_5511_h2p.c +++ b/src/chipset/sis_5511_h2p.c @@ -259,7 +259,7 @@ sis_5511_host_to_pci_write(int addr, uint8_t val, void *priv) case 0x7a: /* DRAM Bank Register 2-1 */ case 0x7c: /* DRAM Bank Register 3-0 */ case 0x7e: /* DRAM Bank Register 3-1 */ - spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x82); + spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x02); break; case 0x71: /* DRAM Bank Register 0-0 */ From dca7ed737c4f82e43c536ea8b004d7b04fbff536 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 May 2025 23:58:41 +0200 Subject: [PATCH 0837/1190] SiS 85c471: Fix DRAM banks, fixes #5545. --- src/chipset/sis_85c4xx.c | 194 ++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 72 deletions(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 51f7fd4e6..1c1e0614b 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -33,6 +33,7 @@ #include <86box/mem.h> #include <86box/smram.h> #include <86box/pic.h> +#include <86box/plat_fallthrough.h> #include <86box/keyboard.h> #include <86box/machine.h> #include <86box/chipset.h> @@ -82,6 +83,14 @@ static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d }; +static uint8_t ram_asus[64] = { 0x00, 0x00, 0x01, 0x10, 0x10, 0x20, 0x03, 0x11, + 0x11, 0x05, 0x05, 0x12, 0x12, 0x13, 0x13, 0x13, + 0x13, 0x21, 0x06, 0x14, 0x14, 0x15, 0x15, 0x15, + 0x15, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, + 0x17, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; static uint8_t ram_tg486g[64] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, @@ -162,17 +171,32 @@ sis_85c471_get_row(ram_bank_t *dev, uint32_t addr) uint32_t ret = 0x00000000; switch (dev->virt_size) { - case 0x04000000: - ret = (addr >> 14) & 0x00000fff; - break; - case 0x01000000: - ret = (addr >> 13) & 0x000007ff; + case 0x00100000: + case 0x00200000: + ret |= (addr >> 13) & 0x00000001; + ret |= ((addr >> 12) & 0x00000001) << 1; + ret |= ((addr >> 14) & 0x0000003f) << 2; + ret |= ((addr >> 11) & 0x00000001) << 8; + ret |= ((addr >> 20) & 0x00000001) << 9; + ret |= ((addr >> 22) & 0x00000001) << 10; + ret |= ((addr >> 24) & 0x00000001) << 11; break; case 0x00400000: - ret = (addr >> 12) & 0x000003ff; + case 0x00800000: + ret |= (addr >> 13) & 0x00000001; + ret |= ((addr >> 12) & 0x00000001) << 1; + ret |= ((addr >> 14) & 0x000000ff) << 2; + ret |= ((addr >> 22) & 0x00000001) << 10; + ret |= ((addr >> 24) & 0x00000001) << 11; break; - case 0x00100000: - ret = (addr >> 11) & 0x000001ff; + case 0x01000000: + case 0x02000000: + case 0x04000000: + ret |= (addr >> 13) & 0x00000001; + ret |= ((addr >> 22) & 0x00000001) << 1; + ret |= ((addr >> 14) & 0x000000ff) << 2; + ret |= ((addr >> 23) & 0x00000001) << 10; + ret |= ((addr >> 24) & 0x00000001) << 11; break; } @@ -185,17 +209,31 @@ sis_85c471_get_col(ram_bank_t *dev, uint32_t addr) uint32_t ret = 0x00000000; switch (dev->virt_size) { - case 0x04000000: - ret = (addr >> 2) & 0x00000fff; - break; - case 0x01000000: - ret = (addr >> 2) & 0x000007ff; + case 0x00100000: + case 0x00200000: + ret |= (addr >> 3) & 0x00000001; + ret |= ((addr >> 2) & 0x00000001) << 1; + ret |= ((addr >> 4) & 0x0000003f) << 2; + ret |= ((addr >> 10) & 0x00000001) << 8; + ret |= ((addr >> 21) & 0x00000001) << 9; + ret |= ((addr >> 23) & 0x00000001) << 10; + ret |= ((addr >> 25) & 0x00000001) << 11; break; case 0x00400000: - ret = (addr >> 2) & 0x000003ff; + case 0x00800000: + ret |= (addr >> 3) & 0x00000001; + ret |= ((addr >> 2) & 0x00000001) << 1; + ret |= ((addr >> 4) & 0x000000ff) << 2; + ret |= ((addr >> 23) & 0x00000001) << 10; + ret |= ((addr >> 25) & 0x00000001) << 11; break; - case 0x00100000: - ret = (addr >> 2) & 0x000001ff; + case 0x01000000: + case 0x02000000: + case 0x04000000: + ret |= (addr >> 3) & 0x00000001; + ret |= ((addr >> 2) & 0x00000001) << 1; + ret |= ((addr >> 4) & 0x000001ff) << 2; + ret |= ((addr >> 25) & 0x00000001) << 11; break; } @@ -208,17 +246,26 @@ sis_85c471_set_row(ram_bank_t *dev, uint32_t addr) uint32_t ret = 0x00000000; switch (dev->phys_size) { - case 0x04000000: - ret = (addr & 0x00000fff) << 14; + case 0x00100000: + ret = (addr & 0x1ff) << 11; break; - case 0x01000000: - ret = (addr & 0x000007ff) << 13; + case 0x00200000: + ret = (addr & 0x3ff) << 11; break; case 0x00400000: - ret = (addr & 0x000003ff) << 12; + ret = (addr & 0x3ff) << 12; break; - case 0x00100000: - ret = (addr & 0x000002ff) << 11; + case 0x00800000: + ret = (addr & 0x7ff) << 12; + break; + case 0x01000000: + ret = (addr & 0x7ff) << 13; + break; + case 0x02000000: + ret = (addr & 0xfff) << 13; + break; + case 0x04000000: + ret = (addr & 0xfff) << 14; break; } @@ -231,23 +278,28 @@ sis_85c471_set_col(ram_bank_t *dev, uint32_t addr) uint32_t ret = 0x00000000; switch (dev->phys_size) { - case 0x04000000: - ret = (addr & 0x00000fff) << 2; - break; - case 0x01000000: - ret = (addr & 0x000007ff) << 2; + case 0x00100000: + case 0x00200000: + ret = (addr & 0x1ff) << 2; break; case 0x00400000: - ret = (addr & 0x000003ff) << 2; + case 0x00800000: + ret = (addr & 0x3ff) << 2; break; - case 0x00100000: - ret = (addr & 0x000002ff) << 2; + case 0x01000000: + case 0x02000000: + ret = (addr & 0x7ff) << 2; + break; + case 0x04000000: + ret = (addr & 0xfff) << 2; break; } return ret; } +uint8_t reg09 = 0x00; + static uint8_t sis_85c471_read_ram(uint32_t addr, void *priv) { @@ -255,12 +307,10 @@ sis_85c471_read_ram(uint32_t addr, void *priv) uint32_t rel = addr - dev->virt_base; uint8_t ret = 0xff; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -277,12 +327,10 @@ sis_85c471_read_ramw(uint32_t addr, void *priv) uint32_t rel = addr - dev->virt_base; uint16_t ret = 0xffff; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -299,12 +347,10 @@ sis_85c471_read_raml(uint32_t addr, void *priv) uint32_t rel = addr - dev->virt_base; uint32_t ret = 0xffffffff; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -320,12 +366,10 @@ sis_85c471_write_ram(uint32_t addr, uint8_t val, void *priv) ram_bank_t *dev = (ram_bank_t *) priv; uint32_t rel = addr - dev->virt_base; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -339,12 +383,10 @@ sis_85c471_write_ramw(uint32_t addr, uint16_t val, void *priv) ram_bank_t *dev = (ram_bank_t *) priv; uint32_t rel = addr - dev->virt_base; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -358,12 +400,10 @@ sis_85c471_write_raml(uint32_t addr, uint32_t val, void *priv) ram_bank_t *dev = (ram_bank_t *) priv; uint32_t rel = addr - dev->virt_base; - if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) { - uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); - uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); - uint32_t dw = rel & 0x00000003; - rel = row | col | dw; - } + uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel)); + uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel)); + uint32_t dw = rel & 0x00000003; + rel = row | col | dw; addr = (rel + dev->phys_base); @@ -492,6 +532,8 @@ sis_85c471_banks_split(uint32_t *b_ex, uint32_t *banks) static void sis_85c471_banks_recalc(sis_85c4xx_t *dev) { + reg09 = dev->regs[0x09]; + for (uint8_t i = 0; i < 8; i++) mem_mapping_disable(&dev->ram_banks[i].mapping); @@ -694,17 +736,25 @@ sis_85c4xx_reset(void *priv) if (dev->is_471) { dev->regs[0x09] = 0x40; - if (mem_size_mb >= 64) { + + if (!strcmp(machine_get_internal_name(), "vli486sv2g")) { + if (mem_size_mb == 64) + dev->regs[0x09] |= 0x1f; + else + dev->regs[0x09] |= ram_asus[mem_size_mb]; + } else if (mem_size_mb >= 64) { if ((mem_size_mb >= 64) && (mem_size_mb < 68)) dev->regs[0x09] |= 0x33; - if ((mem_size_mb >= 68) && (mem_size_mb < 72)) + else if ((mem_size_mb >= 68) && (mem_size_mb < 72)) dev->regs[0x09] |= 0x2b; - if ((mem_size_mb >= 72) && (mem_size_mb < 80)) + else if ((mem_size_mb >= 72) && (mem_size_mb < 80)) dev->regs[0x09] |= 0x2d; - if ((mem_size_mb >= 80) && (mem_size_mb < 96)) + else if ((mem_size_mb >= 80) && (mem_size_mb < 96)) dev->regs[0x09] |= 0x2f; + else if ((mem_size_mb >= 96) && (mem_size_mb < 128)) + dev->regs[0x09] |= 0x34; else - dev->regs[0x09] |= 0x29; + dev->regs[0x09] |= 0x35; } else if (!strcmp(machine_get_internal_name(), "tg486g")) dev->regs[0x09] |= ram_tg486g[mem_size_mb]; else From 6a6be85852bcd1946bd6f8bd4038d5d6d68b393c Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 5 May 2025 02:02:02 +0200 Subject: [PATCH 0838/1190] Late night fixes for the Mach8 (May 5th, 2025) 1. The Mach8 doesn't have separate graphics pitches a la Mach32 (68800-6 and up), fixes the rendering in some drivers for Windows. 2. Special case for the add-on Mach8 for the mode switching (resolution only). --- src/video/vid_ati_mach8.c | 56 +++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 3537cf337..8423f096b 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2681,7 +2681,6 @@ ati_render_32bpp(svga_t *svga) When ATI mode is selected, allow complete auto-detection. But when 8514/A mode is selected, allow detection based on the shadow register sets. */ - static void mach_set_resolution(mach_t *mach, svga_t *svga) { @@ -2707,15 +2706,27 @@ mach_set_resolution(mach_t *mach, svga_t *svga) if (dev->interlace) dev->v_syncstart >>= 1; - if ((mach->accel.clock_sel & 0x01) && !(mach->old_on2 & 0x01) && - !(dev->accel.advfunc_cntl & 0x01)) - ret = 2; - else if ((dev->accel.advfunc_cntl & 0x01) && !(mach->old_on1 & 0x01) && - !(mach->accel.clock_sel & 0x01)) - ret = 1; - else if ((!(dev->accel.advfunc_cntl & 0x01) && (mach->old_on1 & 0x01)) || - (!(mach->accel.clock_sel & 0x01) && (mach->old_on2 & 0x01))) - ret = 0; + if (ATI_8514A_ULTRA) { + if ((mach->accel.clock_sel & 0x01) && + !(dev->accel.advfunc_cntl & 0x01)) + ret = 2; + else if ((dev->accel.advfunc_cntl & 0x01) && + !(mach->accel.clock_sel & 0x01)) + ret = 1; + else if ((!(dev->accel.advfunc_cntl & 0x01) && (mach->old_on1 & 0x01)) || + (!(mach->accel.clock_sel & 0x01) && (mach->old_on2 & 0x01))) + ret = 0; + } else { + if ((mach->accel.clock_sel & 0x01) && !(mach->old_on2 & 0x01) && + !(dev->accel.advfunc_cntl & 0x01)) + ret = 2; + else if ((dev->accel.advfunc_cntl & 0x01) && !(mach->old_on1 & 0x01) && + !(mach->accel.clock_sel & 0x01)) + ret = 1; + else if ((!(dev->accel.advfunc_cntl & 0x01) && (mach->old_on1 & 0x01)) || + (!(mach->accel.clock_sel & 0x01) && (mach->old_on2 & 0x01))) + ret = 0; + } if (ret) { if (ret == 2) @@ -2730,11 +2741,13 @@ mach_set_resolution(mach_t *mach, svga_t *svga) if (dev->hdisp == 640) { dev->hdisp = 1024; dev->vdisp = 768; + mach_log("1024x768.\n"); } } else { if (dev->hdisp == 1024) { dev->hdisp = 640; dev->vdisp = 480; + mach_log("640x480.\n"); } } svga_recalctimings(svga); @@ -2764,7 +2777,6 @@ ati8514_recalctimings(svga_t *svga) mach_log("ON=%d, vgahdisp=%d.\n", dev->on, svga->hdisp); if (dev->on) { - mach_log("8514/A ON, pitch=%d.\n", dev->ext_pitch); dev->interlace = !!(dev->disp_cntl & 0x10); dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; @@ -2773,16 +2785,19 @@ ati8514_recalctimings(svga_t *svga) mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2; dev->accel.ge_offset -= mach->accel.crt_offset; + mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n", dev->hdisp, dev->vdisp, mach->shadow_set & 0x03, dev->accel.advfunc_cntl & 0x05, mach->accel.clock_sel & 0x01); - mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); - mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_pitch = dev->pitch; + mach->accel.dst_pitch = dev->pitch; mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2; mach->accel.src_ge_offset -= mach->accel.crt_offset; mach->accel.dst_ge_offset -= mach->accel.crt_offset; + mach_log("8514/A ON, pitch=%d, GE offset=%08x.\n", ((mach->accel.ge_pitch & 0xff) << 3), dev->accel.ge_offset); + dev->h_disp = dev->hdisp; dev->dispend = dev->vdisp; if (dev->dispend == 600) @@ -2809,6 +2824,7 @@ ati8514_recalctimings(svga_t *svga) } dev->accel_bpp = 8; svga->render8514 = ibm8514_render_8bpp; + } else mach->crt_resolution = 0; } @@ -3009,17 +3025,12 @@ mach_recalctimings(svga_t *svga) } } } else { - mach->accel.src_pitch = ((mach->accel.ge_pitch & 0xff) << 3); - mach->accel.dst_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach->accel.src_pitch = dev->pitch; + mach->accel.dst_pitch = dev->pitch; mach->accel.src_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); mach->accel.dst_ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)); - if (dev->bpp) { - mach->accel.src_ge_offset <<= 1; - mach->accel.dst_ge_offset <<= 1; - } else { - mach->accel.src_ge_offset <<= 2; - mach->accel.dst_ge_offset <<= 2; - } + mach->accel.src_ge_offset <<= 2; + mach->accel.dst_ge_offset <<= 2; mach->accel.src_ge_offset -= mach->accel.crt_offset; mach->accel.dst_ge_offset -= mach->accel.crt_offset; @@ -7221,7 +7232,6 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514) dev->v_sync_start = 0x0600; dev->disp_cntl = 0x33; mach->accel.clock_sel = 0x1c; - mach->shadow_set = 0x02; dev->accel.cmd_back = 1; io_sethandler(0x02ea, 4, ati8514_in, NULL, NULL, ati8514_out, NULL, NULL, svga); From 018bbfae4333beaf0c71e6b05603aabb5ab242ed Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 5 May 2025 05:11:55 +0200 Subject: [PATCH 0839/1190] SM(S)C FDC37C93x Super I/O chip rewrite, add the Acer V62x, and un-dev-branch the V-Tech Laser XT machines. --- src/chipset/intel_piix.c | 61 -- src/device/kbc_at.c | 23 +- src/floppy/fdc.c | 19 +- src/include/86box/fdc.h | 5 + src/include/86box/keyboard.h | 1 + src/include/86box/machine.h | 9 +- src/include/86box/sio.h | 24 +- src/machine/CMakeLists.txt | 6 +- src/machine/m_at_slot1.c | 33 +- src/machine/m_at_socket7.c | 23 +- src/machine/m_at_socket7_3v.c | 8 +- src/machine/m_at_socket8.c | 4 +- src/machine/m_pcjr.c | 3 +- src/machine/m_xt_laserxt.c | 461 +++++++-- src/machine/m_xt_zenith.c | 3 +- src/machine/machine_table.c | 61 +- src/sio/sio_fdc37c93x.c | 1732 ++++++++++++++++++++++++--------- 17 files changed, 1810 insertions(+), 666 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 6969d3274..ed9fd9460 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -59,7 +59,6 @@ typedef struct piix_io_trap_t { } piix_io_trap_t; typedef struct _piix_ { - uint8_t cur_readout_reg; uint8_t rev; uint8_t type; uint8_t func_shift; @@ -67,7 +66,6 @@ typedef struct _piix_ { uint8_t pci_slot; uint8_t no_mirq0; uint8_t regs[4][256]; - uint8_t readout_regs[256]; uint16_t func0_id; uint16_t nvr_io_base; uint16_t acpi_io_base; @@ -1185,31 +1183,6 @@ piix_read(int func, int addr, void *priv) return ret; } -static void -board_write(uint16_t port, uint8_t val, void *priv) -{ - piix_t *dev = (piix_t *) priv; - - if (port == 0x00e0) - dev->cur_readout_reg = val; - else if (port == 0x00e1) - dev->readout_regs[dev->cur_readout_reg] = val; -} - -static uint8_t -board_read(uint16_t port, void *priv) -{ - const piix_t *dev = (piix_t *) priv; - uint8_t ret = 0x64; - - if (port == 0x00e0) - ret = dev->cur_readout_reg; - else if (port == 0x00e1) - ret = dev->readout_regs[dev->cur_readout_reg]; - - return ret; -} - static void piix_reset_hard(piix_t *dev) { @@ -1624,40 +1597,6 @@ piix_init(const device_t *info) if (dev->type < 3) pci_enable_mirq(1); - dev->readout_regs[0] = 0xff; - dev->readout_regs[1] = 0x40; - dev->readout_regs[2] = 0xff; - - /* Port E1 register 01 (TODO: Find how multipliers > 3.0 are defined): - - Bit 6: 1 = can boot, 0 = no; - Bit 7, 1 = multiplier (00 = 2.5, 01 = 2.0, 10 = 3.0, 11 = 1.5); - Bit 5, 4 = bus speed (00 = 50 MHz, 01 = 66 MHz, 10 = 60 MHz, 11 = ????): - Bit 7, 5, 4, 1: 0000 = 125 MHz, 0010 = 166 MHz, 0100 = 150 MHz, 0110 = ??? MHz; - 0001 = 100 MHz, 0011 = 133 MHz, 0101 = 120 MHz, 0111 = ??? MHz; - 1000 = 150 MHz, 1010 = 200 MHz, 1100 = 180 MHz, 1110 = ??? MHz; - 1001 = 75 MHz, 1011 = 100 MHz, 1101 = 90 MHz, 1111 = ??? MHz */ - - if (cpu_busspeed <= 40000000) - dev->readout_regs[1] |= 0x30; - else if ((cpu_busspeed > 40000000) && (cpu_busspeed <= 50000000)) - dev->readout_regs[1] |= 0x00; - else if ((cpu_busspeed > 50000000) && (cpu_busspeed <= 60000000)) - dev->readout_regs[1] |= 0x20; - else if (cpu_busspeed > 60000000) - dev->readout_regs[1] |= 0x10; - - if (cpu_dmulti <= 1.5) - dev->readout_regs[1] |= 0x82; - else if ((cpu_dmulti > 1.5) && (cpu_dmulti <= 2.0)) - dev->readout_regs[1] |= 0x02; - else if ((cpu_dmulti > 2.0) && (cpu_dmulti <= 2.5)) - dev->readout_regs[1] |= 0x00; - else if (cpu_dmulti > 2.5) - dev->readout_regs[1] |= 0x80; - - io_sethandler(0x00e0, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, dev); - #if 0 device_add(&i8254_sec_device); #endif diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 447c07780..aaa746570 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -509,9 +509,6 @@ kbc_scan_kbd_at(atkbc_t *dev) } } -static void -write_p2(atkbc_t *dev, uint8_t val); - static void kbc_at_poll_at(atkbc_t *dev) { @@ -778,6 +775,7 @@ static void write_p2(atkbc_t *dev, uint8_t val) { uint8_t old = dev->p2; + kbc_at_log("ATkbc: write P2: %02X (old: %02X)\n", val, dev->p2); uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; @@ -851,6 +849,25 @@ write_p2(atkbc_t *dev, uint8_t val) } } +uint8_t +kbc_at_read_p(void *priv, uint8_t port, uint8_t mask) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t *p = (port == 2) ? &dev->p2 : &dev->p1; + uint8_t ret = *p & mask; + + return ret; +} + +void +kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t *p = (port == 2) ? &dev->p2 : &dev->p1; + + *p = (*p & mask) | val; +} + static void write_p2_fast_a20(atkbc_t *dev, uint8_t val) { diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index c32b1f442..de8508e69 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -81,6 +81,7 @@ int fdc_current[FDC_MAX] = { 0, 0 }; volatile int fdcinited = 0; +// #define ENABLE_FDC_LOG 1 #ifdef ENABLE_FDC_LOG int fdc_do_log = ENABLE_FDC_LOG; @@ -395,6 +396,20 @@ fdc_update_rwc(fdc_t *fdc, int drive, int rwc) fdc_rate(fdc, drive); } +uint8_t +fdc_get_media_id(fdc_t *fdc, int id) +{ + uint8_t ret = fdc->media_id & (1 << id); + + return ret; +} + +void +fdc_set_media_id(fdc_t *fdc, int id, int set) +{ + fdc->media_id = (fdc->media_id & ~(1 << id)) | (set << id); +} + int fdc_get_boot_drive(fdc_t *fdc) { @@ -1369,7 +1384,7 @@ fdc_read(uint16_t addr, void *priv) } else if (!fdc->enh_mode) ret = 0x20; else - ret = fdc->rwc[drive] << 4; + ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); break; case 4: /*Status*/ ret = fdc->stat; @@ -2352,6 +2367,8 @@ fdc_reset(void *priv) } fdc->power_down = 0; + + fdc->media_id = 0; } static void diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 2d17380d0..36cfaeb7a 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -119,6 +119,8 @@ typedef struct fdc_t { uint8_t lock; uint8_t dsr; + uint8_t media_id; + uint8_t params[15]; uint8_t specify[2]; uint8_t res[11]; @@ -166,6 +168,9 @@ extern void fdc_3f1_enable(fdc_t *fdc, int enable); extern int fdc_get_bit_rate(fdc_t *fdc); extern int fdc_get_bitcell_period(fdc_t *fdc); +extern uint8_t fdc_get_media_id(fdc_t *fdc, int id); +extern void fdc_set_media_id(fdc_t *fdc, int id, int set); + /* A few functions to communicate between Super I/O chips and the FDC. */ extern void fdc_update_enh_mode(fdc_t *fdc, int enh_mode); extern int fdc_get_rwc(fdc_t *fdc, int drive); diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index e21fa60d9..583960e80 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -285,6 +285,7 @@ extern int keyboard_isfsexit(void); extern int keyboard_isfsexit_up(void); extern void keyboard_set_is_amstrad(int ams); extern void kbc_at_set_ps2(void *priv, uint8_t ps2); +extern uint8_t kbc_at_read_p(void *priv, uint8_t port, uint8_t mask); extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val); extern void kbc_at_set_fast_reset(uint8_t new_fast_reset); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 4469b55c2..d62947848 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -806,6 +806,7 @@ extern int machine_at_p65up5_cp6nd_init(const machine_t *); /* m_at_slot1.c */ extern int machine_at_m729_init(const machine_t *); +extern int machine_at_acerv62x_init(const machine_t *); extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); @@ -969,10 +970,14 @@ extern int machine_xt_compaq_deskpro_init(const machine_t *); extern int machine_xt_compaq_portable_init(const machine_t *); /* m_xt_laserxt.c */ -#ifdef USE_LASERXT extern int machine_xt_laserxt_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t laserxt_device; +#endif extern int machine_xt_lxt3_init(const machine_t *); -#endif /* USE_LASERXT */ +#ifdef EMU_DEVICE_H +extern const device_t lxt3_device; +#endif /* m_xt_philips.c */ extern int machine_xt_p3105_init(const machine_t *); diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 7fcb376b9..bdff29f7f 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -48,14 +48,22 @@ extern const device_t fdc37c669_370_device; extern const device_t fdc37c67x_device; -extern const device_t fdc37c931apm_device; -extern const device_t fdc37c931apm_compaq_device; -extern const device_t fdc37c932fr_device; -extern const device_t fdc37c932qf_device; -extern const device_t fdc37c932_device; -extern const device_t fdc37c935_device; -extern const device_t fdc37c935_370_device; -extern const device_t fdc37c935_no_nvr_device; +#define FDC37C93X_NORMAL 0x0002 +#define FDC37C93X_FR 0x0003 +#define FDC37C93X_APM 0x0030 +#define FDC37C93X_CHIP_ID 0x00ff + +#define FDC37C931 0x0100 /* Compaq KBC firmware and configuration registers on GPIO ports. */ +#define FDC37C932 0x0200 /* AMI '5' Megakey KBC firmware. */ +#define FDC37C933 0x0300 /* IBM KBC firmware. */ +#define FDC37C935 0x0500 /* Phoenix Multikey/42 1.38 KBC firmware. */ +#define FDC37C937 0x0700 /* Phoenix Multikey/42i 4.16 KBC firmware. */ +#define FDC37C93X_KBC 0x0f00 + +#define FDC37C93X_NO_NVR 0x1000 +#define FDC37C93X_370 0x2000 + +extern const device_t fdc37c93x_device; extern const device_t fdc37m60x_device; extern const device_t fdc37m60x_370_device; diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index ff6a66801..4098f2553 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(mch OBJECT machine_table.c m_xt.c m_xt_compaq.c + m_xt_laserxt.c m_xt_philips.c m_xt_t1000.c m_xt_t1000_vid.c @@ -64,11 +65,6 @@ if(DESKPRO386) target_compile_definitions(mch PRIVATE USE_DESKPRO386) endif() -if(LASERXT) - target_sources(mch PRIVATE m_xt_laserxt.c) - target_compile_definitions(mch PRIVATE USE_LASERXT) -endif() - if(OLIVETTI) target_compile_definitions(mch PRIVATE USE_OLIVETTI) endif() diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index a3ff921e3..bd3a4833f 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -40,6 +40,35 @@ #include <86box/clock.h> #include <86box/snd_ac97.h> +int +machine_at_acerv62x_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/acerv62x/v62xc0s1.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 5, 0, 0, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_APM)); + device_add(&sst_flash_29ee020_device); + + return ret; +} + int machine_at_p65up5_cpknd_init(const machine_t *model) { @@ -131,7 +160,7 @@ machine_at_spitfire_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init_ex(model, 2); + machine_at_common_init(model); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); @@ -143,7 +172,7 @@ machine_at_spitfire_init(const machine_t *model) pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440lx_device); device_add(&piix4e_device); - device_add(&fdc37c935_no_nvr_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL | FDC37C93X_NO_NVR)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0xF, 256); device_add(&lm78_device); /* no reporting in BIOS */ diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 3fe883323..319856d41 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -69,7 +69,8 @@ machine_at_acerv35n_init(const machine_t *model) pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); device_add(&i430hx_device); device_add(&piix3_device); - device_add(&fdc37c932fr_device); + /* The chip is not marked FR but the BIOS accesses register 06h of GPIO. */ + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_FR)); device_add(&sst_flash_29ee010_device); return ret; @@ -160,7 +161,7 @@ machine_at_m7shi_init(const machine_t *model) pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); device_add(&i430hx_device); device_add(&piix3_device); - device_add(&fdc37c935_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL)); device_add(&intel_flash_bxt_device); return ret; @@ -568,7 +569,7 @@ machine_at_presario2240_init(const machine_t *model) device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c932qf_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_NORMAL)); device_add(&sst_flash_29ee020_device); return ret; @@ -598,7 +599,7 @@ machine_at_presario4500_init(const machine_t *model) device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c931apm_compaq_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C931 | FDC37C93X_APM)); device_add(&sst_flash_29ee020_device); return ret; @@ -631,7 +632,7 @@ machine_at_dellhannibalp_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c932fr_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_FR)); device_add(&intel_flash_bxt_ami_device); return ret; @@ -659,7 +660,7 @@ machine_at_p55va_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c932fr_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_FR)); device_add(&intel_flash_bxt_device); return ret; @@ -687,7 +688,7 @@ machine_at_brio80xx_init(const machine_t *model) pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c935_370_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL | FDC37C93X_370)); device_add(&sst_flash_29ee020_device); return ret; @@ -756,7 +757,7 @@ machine_at_pb810_init(const machine_t *model) device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c935_370_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL | FDC37C93X_370)); device_add(&intel_flash_bxt_device); return ret; @@ -851,7 +852,7 @@ machine_at_gw2kte_init(const machine_t *model) device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c932fr_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_FR)); device_add(&intel_flash_bxt_ami_device); return ret; @@ -1553,7 +1554,7 @@ machine_at_thunderbolt_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init_ex(model, 2); + machine_at_common_init(model); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); @@ -1564,7 +1565,7 @@ machine_at_thunderbolt_init(const machine_t *model) pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 0, 1, 2); device_add(&i430tx_device); device_add(&piix4_device); - device_add(&fdc37c935_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL | FDC37C93X_NO_NVR)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 4b980f2b0..913c82518 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -455,7 +455,7 @@ machine_at_pb640_init(const machine_t *model) device_add(&piix_rev02_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&gd5440_onboard_pci_device); + device_add(machine_get_vid_device(machine)); device_add(&keyboard_ps2_intel_ami_pci_device); device_add(&pc87306_device); @@ -546,7 +546,7 @@ machine_at_acerm3a_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); device_add(&i430hx_device); device_add(&piix3_device); - device_add(&fdc37c935_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL)); device_add(&sst_flash_29ee010_device); @@ -700,7 +700,7 @@ machine_at_gw2kma_init(const machine_t *model) device_add(&i430vx_device); device_add(&piix3_device); - device_add(&fdc37c932fr_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_FR)); device_add(&intel_flash_bxt_ami_device); return ret; @@ -819,7 +819,7 @@ machine_at_vectra54_init(const machine_t *model) device_add(&i430fx_device); device_add(&piix_device); - device_add(&fdc37c932_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C932 | FDC37C93X_NORMAL)); device_add(&sst_flash_29ee010_device); return ret; diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 935a26fb2..479c4b9fc 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -188,7 +188,7 @@ machine_at_acerv60n_init(const machine_t *model) pci_register_slot(0x0C, PCI_CARD_NORMAL, 2, 3, 4, 1); device_add(&i440fx_device); device_add(&piix3_device); - device_add(&fdc37c935_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL)); device_add(&sst_flash_29ee010_device); return ret; @@ -389,7 +389,7 @@ machine_at_m6mi_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&i440fx_device); device_add(&piix3_device); - device_add(&fdc37c935_device); + device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL)); device_add(&intel_flash_bxt_device); return ret; diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index ca9e72fca..d4d3b09cf 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -1566,7 +1566,8 @@ machine_pcjr_init(UNUSED(const machine_t *model)) device_add(&fdc_pcjr_device); device_add(&ns8250_pcjr_device); - serial_set_next_inst(SERIAL_MAX); /* So that serial_standalone_init() won't do anything. */ + /* So that serial_standalone_init() won't do anything. */ + serial_set_next_inst(SERIAL_MAX - 1); /* "All the inputs are 'read' with one 'IN' from address hex 201." - PCjr Technical Reference (Nov. 83), p.2-119 diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index c0405f99a..d298e726b 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -1,6 +1,7 @@ /*This is the chipset used in the LaserXT series model*/ #include #include +#include #include #include #include <86box/86box.h> @@ -21,125 +22,411 @@ #include <86box/keyboard.h> #include <86box/plat_unused.h> -static int laserxt_emspage[4]; -static int laserxt_emscontrol[4]; -static mem_mapping_t laserxt_ems_mapping[4]; -static int laserxt_ems_baseaddr_index = 0; -static int laserxt_is_lxt3 = 0; +#define EMS_TOTAL_MAX 0x00100000 -static uint32_t -get_laserxt_ems_addr(uint32_t addr) +typedef struct { - if (laserxt_emspage[(addr >> 14) & 3] & 0x80) { - addr = (!laserxt_is_lxt3 ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); - } + uint8_t page; + uint8_t ctrl; - return addr; + uint32_t phys; + uint32_t virt; + + mem_mapping_t mapping; + + uint8_t *ram; + + void *parent; +} lxt_ems_t; + +typedef struct +{ + int ems_base_idx; + + lxt_ems_t ems[4]; + + uint16_t io_base; + uint32_t base; + + uint32_t mem_size; + + uint8_t *ram; + + void *parent; +} lxt_ems_board_t; + +typedef struct +{ + int is_lxt3; + + lxt_ems_board_t *ems_boards[2]; +} lxt_t; + +static void +ems_update_virt(lxt_ems_t *dev, uint8_t new_page) +{ + lxt_ems_board_t *board = (lxt_ems_board_t *) dev->parent; + lxt_t *lxt = (lxt_t *) board->parent; + + dev->page = new_page; + + if (new_page & 0x80) { + if (lxt->is_lxt3) { + /* Point invalid pages at 1 MB which is outside the maximum. */ + if ((new_page & 0x7f) >= 0x40) + dev->virt = EMS_TOTAL_MAX; + else + dev->virt = ((new_page & 0x7f) << 14); + } else + dev->virt = ((new_page & 0x0f) << 14) + ((new_page & 0x40) << 12); + + if (dev->virt >= board->mem_size) + dev->virt = EMS_TOTAL_MAX; + } else + dev->virt = EMS_TOTAL_MAX; + + dev->ram = board->ram + dev->virt; + + if ((new_page & 0x80) && (dev->virt != EMS_TOTAL_MAX)) { + mem_mapping_enable(&dev->mapping); + + mem_mapping_set_exec(&dev->mapping, dev->ram); + mem_mapping_set_p(&dev->mapping, dev->ram); + } else + mem_mapping_disable(&dev->mapping); + + flushmmucache(); } static void -laserxt_write(uint16_t port, uint8_t val, UNUSED(void *priv)) +lxt_ems_out(uint16_t port, uint8_t val, void *priv) { - uint32_t paddr; - uint32_t vaddr; - switch (port) { - case 0x0208: - case 0x4208: - case 0x8208: - case 0xC208: - laserxt_emspage[port >> 14] = val; - paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); - if (val & 0x80) { - mem_mapping_enable(&laserxt_ems_mapping[port >> 14]); - vaddr = get_laserxt_ems_addr(paddr); - mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr); - } else { - mem_mapping_disable(&laserxt_ems_mapping[port >> 14]); - } - flushmmucache(); - break; - case 0x0209: - case 0x4209: - case 0x8209: - case 0xC209: - laserxt_emscontrol[port >> 14] = val; - laserxt_ems_baseaddr_index = 0; + lxt_ems_board_t *dev = (lxt_ems_board_t *) priv; + uint8_t reg = port >> 14; + uint32_t saddrs[8] = { 0xc4000, 0xc8000, 0xcc000, 0xd0000, + 0xd4000, 0xd8000, 0xdc000, 0xe0000 }; + uint32_t saddr; + + if (port & 0x0001) { + dev->ems[reg].ctrl = val; + + if (reg < 0x03) { + dev->ems_base_idx = (dev->ems_base_idx & ~(0x04 >> (2 - reg))) | + ((dev->ems[reg].ctrl & 0x80) >> (7 - reg)); + + saddr = saddrs[dev->ems_base_idx]; + for (uint8_t i = 0; i < 4; i++) { - laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); + uint32_t base = saddr + (i * 0x4000); + mem_mapping_set_addr(&dev->ems[i].mapping, base, 0x4000); + if (!(dev->ems[i].page & 0x80) || (dev->ems[i].virt == EMS_TOTAL_MAX)) + mem_mapping_disable(&dev->ems[i].mapping); } + } - mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); - flushmmucache(); - break; - - default: - break; + flushmmucache(); + } else if (!(port & 0x0001)) { + dev->ems[reg].page = val; + ems_update_virt(&dev->ems[reg], val); } } static uint8_t -laserxt_read(uint16_t port, UNUSED(void *priv)) +lxt_ems_in(uint16_t port, void *priv) { - switch (port) { - case 0x0208: - case 0x4208: - case 0x8208: - case 0xC208: - return laserxt_emspage[port >> 14]; - case 0x0209: - case 0x4209: - case 0x8209: - case 0xC209: - return laserxt_emscontrol[port >> 14]; + lxt_ems_board_t *dev = (lxt_ems_board_t *) priv; + uint8_t reg = port >> 14; + uint8_t ret = 0xff; - default: - break; - } - return 0xff; + if (port & 0x0001) + ret = dev->ems[reg].ctrl; + else + ret = dev->ems[reg].page; + + return ret; } static void -mem_write_laserxtems(uint32_t addr, uint8_t val, UNUSED(void *priv)) +lxt_ems_write(uint32_t addr, uint8_t val, void *priv) { - addr = get_laserxt_ems_addr(addr); - if (addr < (mem_size << 10)) - ram[addr] = val; + uint8_t *mem = (uint8_t *) priv; + + mem[addr & 0x3fff] = val; } static uint8_t -mem_read_laserxtems(uint32_t addr, UNUSED(void *priv)) +lxt_ems_read(uint32_t addr, void *priv) { - uint8_t val = 0xFF; - addr = get_laserxt_ems_addr(addr); - if (addr < (mem_size << 10)) - val = ram[addr]; - return val; + uint8_t *mem = (uint8_t *) priv; + uint8_t ret = 0xff; + + ret = mem[addr & 0x3fff]; + + return ret; +} + +static lxt_ems_board_t * +lxt_ems_init(lxt_t *parent, int en, uint16_t io, uint32_t mem) +{ + lxt_ems_board_t *dev = (lxt_ems_board_t *) calloc(1, sizeof(lxt_ems_board_t)); + + if (en) { + dev->parent = parent; + + if (io != 0x0000) { + io_sethandler(io , 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev); + io_sethandler(io | 0x4000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev); + io_sethandler(io | 0x8000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev); + io_sethandler(io | 0xc000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev); + } + + dev->ram = (uint8_t *) calloc(mem, sizeof(uint8_t)); + dev->mem_size = mem; + + for (uint8_t i = 0; i < 4; i++) { + uint8_t *ptr = dev->ram + (i << 14); + + mem_mapping_add(&dev->ems[i].mapping, 0xe0000 + (i << 14), 0x4000, + lxt_ems_read, NULL, NULL, + lxt_ems_write, NULL, NULL, + ptr, 0, ptr); + mem_mapping_disable(&dev->ems[i].mapping); + + dev->ems[i].page = 0x7f; + dev->ems[i].ctrl = (i == 3) ? 0x00 : 0x80; + + dev->ems[i].parent = dev; + + ems_update_virt(&(dev->ems[i]), dev->ems[i].page); + } + } + + return dev; } static void -laserxt_init(int is_lxt3) +lxt_close(void *priv) { - if (mem_size > 640) { - io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - mem_mapping_set_addr(&ram_low_mapping, 0, !is_lxt3 ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); + lxt_t *dev = (lxt_t *) priv; + int ems_boards = (1 - dev->is_lxt3) + 1; + + for (int i = 0; i < ems_boards; i++) + if (dev->ems_boards[i] != NULL) { + if (dev->ems_boards[i]->ram != NULL) + free(dev->ems_boards[i]->ram); + free(dev->ems_boards[i]); + } + + free(dev); +} + +static void * +lxt_init(const device_t *info) +{ + lxt_t * dev = (lxt_t *) calloc(1, sizeof(lxt_t)); + int ems_boards = (1 - info->local) + 1; + int ems_en[2] = { 0 }; + uint16_t ems_io[2] = { 0 }; + uint32_t ems_mem[2] = { 0 }; + char conf_str[512] = { 0 }; + + dev->is_lxt3 = info->local; + + for (int i = 0; i < ems_boards; i++) { + sprintf(conf_str, "ems_%i_enable", i + 1); + ems_en[i] = device_get_config_int(conf_str); + + sprintf(conf_str, "ems_%i_base", i + 1); + ems_io[i] = device_get_config_hex16(conf_str); + + sprintf(conf_str, "ems_%i_mem_size", i + 1); + ems_mem[i] = device_get_config_int(conf_str) << 10; + + dev->ems_boards[i] = lxt_ems_init(dev, ems_en[i], ems_io[i], ems_mem[i]); } - for (uint8_t i = 0; i < 4; i++) { - laserxt_emspage[i] = 0x7F; - laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80; - mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL); - mem_mapping_disable(&laserxt_ems_mapping[i]); - } mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - laserxt_is_lxt3 = is_lxt3; + + return dev; } +static const device_config_t laserxt_config[] = { + { + .name = "ems_1_base", + .description = "EMS 1 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x208", .value = 0x208 }, + { .description = "0x218", .value = 0x218 }, + { .description = "0x258", .value = 0x258 }, + { .description = "0x268", .value = 0x268 }, + { .description = "0x2A8", .value = 0x2a8 }, + { .description = "0x2B8", .value = 0x2b8 }, + { .description = "0x2E8", .value = 0x2e8 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "ems_2_base", + .description = "EMS 2 Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x208", .value = 0x208 }, + { .description = "0x218", .value = 0x218 }, + { .description = "0x258", .value = 0x258 }, + { .description = "0x268", .value = 0x268 }, + { .description = "0x2A8", .value = 0x2a8 }, + { .description = "0x2B8", .value = 0x2b8 }, + { .description = "0x2E8", .value = 0x2e8 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "ems_1_mem_size", + .description = "EMS 1 Memory Size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 512, + .step = 32 + }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "ems_2_mem_size", + .description = "EMS 2 Memory Size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 512, + .step = 32 + }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "ems_1_enable", + .description = "Enable EMS 1", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "ems_2_enable", + .description = "Enable EMS 2", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +const device_t laserxt_device = { + .name = "VTech Laser Turbo XT", + .internal_name = "laserxt", + .flags = 0, + .local = 0, + .init = lxt_init, + .close = lxt_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = laserxt_config +}; + +static const device_config_t lxt3_config[] = { + { + .name = "ems_1_base", + .description = "EMS Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Disabled", .value = 0 }, + { .description = "0x208", .value = 0x208 }, + { .description = "0x218", .value = 0x218 }, + { .description = "0x258", .value = 0x258 }, + { .description = "0x268", .value = 0x268 }, + { .description = "0x2A8", .value = 0x2a8 }, + { .description = "0x2B8", .value = 0x2b8 }, + { .description = "0x2E8", .value = 0x2e8 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "ems_1_mem_size", + .description = "EMS Memory Size", + .type = CONFIG_SPINNER, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { + .min = 0, + .max = 1024, + .step = 32 + }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "ems_1_enable", + .description = "Enable EMS", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +const device_t lxt3_device = { + .name = "VTech Laser Turbo XT", + .internal_name = "laserxt", + .flags = 0, + .local = 1, + .init = lxt_init, + .close = lxt_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = lxt3_config +}; + static void machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3) { @@ -153,7 +440,7 @@ machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3) nmi_init(); standalone_gameport_type = &gameport_device; - laserxt_init(is_lxt3); + device_add(is_lxt3 ? &lxt3_device : &laserxt_device); device_add(&keyboard_xt_lxt3_device); } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index 6c5d556f2..62c6496d1 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -146,7 +146,8 @@ machine_xt_z184_init(const machine_t *model) lpt2_remove(); lpt1_setup(LPT2_ADDR); device_add(&ns8250_device); - serial_set_next_inst(SERIAL_MAX); /* So that serial_standalone_init() won't do anything. */ + /* So that serial_standalone_init() won't do anything. */ + serial_set_next_inst(SERIAL_MAX - 1); device_add(&cga_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9c83f4b22..44e93f721 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1709,7 +1709,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, -#ifdef USE_LASERXT { .name = "[8088] VTech Laser Turbo XT", .internal_name = "ltxt", @@ -1742,14 +1741,13 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &laserxt_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, .snd_device = NULL, .net_device = NULL }, -#endif /* USE_LASERXT */ /* Has a standard PS/2 KBC (so, use IBM PS/2 Type 1). */ { .name = "[8088] Xi8088", @@ -2612,8 +2610,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - -#ifdef USE_LASERXT { .name = "[8086] VTech Laser XT3", .internal_name = "lxt3", @@ -2637,23 +2633,22 @@ const machine_t machines[] = { .bus_flags = MACHINE_PC, .flags = MACHINE_FLAGS_NONE, .ram = { - .min = 256, + .min = 512, .max = 640, - .step = 256 + .step = 64 }, .nvrmask = 0, .kbc_device = &keyboard_xt_lxt3_device, .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &lxt3_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, .snd_device = NULL, .net_device = NULL }, -#endif /* USE_LASERXT */ /* 286 AT machines */ /* Has IBM AT KBC firmware. */ @@ -8156,7 +8151,10 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* I'm going to assume this as an AMIKey-2 like the other two 486SP3's. */ + /* + This has an AMIKey (and an on-board NCR 53C810 PCI SCSI controller), thanks, eBay! + The keyboard port is AT. + */ { .name = "[i420TX] ASUS PCI/I-486SP3", .internal_name = "486sp3", @@ -10092,7 +10090,7 @@ const machine_t machines[] = { .max_multi = 1.5 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE | MACHINE_SCSI | MACHINE_APM, + .flags = MACHINE_IDE /*| MACHINE_SCSI */ | MACHINE_APM, .ram = { .min = 2048, .max = 524288, @@ -14593,6 +14591,47 @@ const machine_t machines[] = { }, /* 440FX */ + /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix + MultiKey/42 (version 1.38) KBC firmware. */ + { + .name = "[i440FX] Acer V62X", + .internal_name = "acerv62x", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_acerv62x_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 83333333, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 511, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* The base board has a Holtek HT6542B KBC with AMIKey-2 (updated 'H') KBC firmware. */ { .name = "[i440FX] ASUS P/I-P65UP5 (C-PKND)", diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index 8d8f76cb6..ebc500c96 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -15,8 +15,9 @@ * * Copyright 2016-2018 Miran Grca. */ -#include +#include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/pci.h> +#include <86box/pic.h> #include <86box/lpt.h> #include <86box/serial.h> #include <86box/hdc.h> @@ -37,20 +39,28 @@ #include <86box/apm.h> #include <86box/access_bus.h> #include <86box/acpi.h> -#include <86box/sio.h> +#include <86box/plat.h> #include <86box/plat_unused.h> +#include <86box/video.h> +#include <86box/sio.h> +#include "cpu.h" typedef struct fdc37c93x_t { uint8_t chip_id; uint8_t is_apm; uint8_t is_compaq; uint8_t has_nvr; + uint8_t max_ld; uint8_t tries; uint8_t port_370; - uint8_t gpio_regs[2]; + uint8_t gpio_reg; + uint8_t gpio_regs[256]; + uint8_t gpio_pulldn[8]; uint8_t auxio_reg; uint8_t regs[48]; + uint8_t alt_regs[3][8]; uint8_t ld_regs[11][256]; + uint16_t kbc_type; uint16_t superio_base; uint16_t fdc_base; uint16_t lpt_base; @@ -73,6 +83,15 @@ typedef struct fdc37c93x_t { static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv); static uint8_t fdc37c93x_read(uint16_t port, void *priv); +static uint8_t gp_func_regs[8][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, /* GP00-GP07 */ + { 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7 }, /* GP10-GP17 */ + { 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef }, /* GP20-GP27 */ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, /* GP30-GP37 */ + { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 }, /* GP40-GP47 */ + { 0xc8, 0xc9, 0xff, 0xcb, 0xcc, 0xff, 0xff, 0xff }, /* GP50-GP57 */ + { 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 }, /* GP60-GP67 */ + { 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf } }; /* GP70-GP77 */ + static uint16_t make_port_superio(const fdc37c93x_t *dev) { @@ -122,14 +141,562 @@ fdc37c93x_auxio_write(UNUSED(uint16_t port), uint8_t val, void *priv) dev->auxio_reg = val; } +static __inline uint8_t +fdc37c93x_do_read_gp(fdc37c93x_t *dev, int reg, int bit) +{ + /* Update bit 2 on the Acer V35N according to the selected graphics card type. */ + if ((reg == 2) && (strstr(machine_get_internal_name(), "acer") != NULL)) + dev->gpio_pulldn[reg] = (dev->gpio_pulldn[reg] & 0xfb) | (video_is_mda() ? 0x00 : 0x04); + + return dev->gpio_regs[reg] & dev->gpio_pulldn[reg] & (1 << bit); +} + +static __inline uint8_t +fdc37c93x_do_read_alt(const fdc37c93x_t *dev, int alt, int reg, int bit) +{ + return dev->alt_regs[alt][reg] & (1 << bit); +} + +static uint8_t +fdc37c93x_read_gp(const fdc37c93x_t *dev, int reg, int bit) +{ + uint8_t gp_reg = gp_func_regs[reg][bit]; + uint8_t gp_func_reg = dev->ld_regs[0x08][gp_reg]; + uint8_t gp_func; + uint8_t ret = 1 << bit; + + if (gp_func_reg & 0x01) switch (reg) { + default: + /* Do nothing, this GP does not exist. */ + break; + case 1: + switch (bit) { + default: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + else + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + gp_func = (gp_func_reg >> 3) & 0x03; + if (!(gp_func & 0x01)) { + if (gp_func & 0x02) + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + else + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + } + break; + case 3: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x01) + /* TODO: Write to power LED if it's ever implemented. */ + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + else + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 6: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 1 ... 3: + ret = fdc37c93x_do_read_alt(dev, gp_func - 1, reg, bit); + break; + } + break; + } + break; + case 2: + switch (bit) { + default: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + else + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 0: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 2: + ret = kbc_at_read_p(dev->kbc, 2, 0x01) ? (1 << bit) : 0x00; + break; + } + break; + case 1: case 2: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 1: case 2: + ret = fdc37c93x_do_read_alt(dev, gp_func - 1, reg, bit); + break; + } + break; + case 5: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + else + ret = kbc_at_read_p(dev->kbc, 2, 0x02) ? (1 << bit) : 0x00; + break; + case 6: case 7: + /* Do nothing, these bits do not exist. */ + break; + } + break; + case 4: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + } + break; + case 0: case 1: + switch (gp_func) { + case 0: + ret = fdc_get_media_id(dev->fdc, bit ^ 1) ? (1 << bit) : 0x00; + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + } + break; + case 6: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 2: + /* TODO: Write to power LED if it's ever implemented. */ + ret = fdc37c93x_do_read_alt(dev, 1, reg, bit); + break; + case 3: + ret = fdc37c93x_do_read_alt(dev, 2, reg, bit); + break; + } + break; + case 7: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 2: + ret = fdc37c93x_do_read_alt(dev, 1, reg, bit); + break; + } + break; + } + break; + case 5: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + break; + case 0: case 3: case 4: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + } + break; + case 1: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + } + break; + } + break; + case 6: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 2: + ret = kbc_at_read_p(dev->kbc, 1, 1 << bit); + break; + } + break; + case 0: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 2: + /* TODO: Write to power LED if it's ever implemented. */ + ret = fdc37c93x_do_read_alt(dev, 1, reg, bit); + break; + } + break; + case 1: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + case 2: + ret = fdc37c93x_do_read_alt(dev, 1, reg, bit); + break; + } + break; + } + break; + case 7: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + ret = fdc37c93x_do_read_alt(dev, 0, reg, bit); + break; + case 1: + ret = fdc37c93x_do_read_gp((fdc37c93x_t *) dev, reg, bit); + break; + } + break; + } + break; + } + + if (gp_func_reg & 0x02) + ret ^= (1 << bit); + + return ret; +} + +static __inline void +fdc37c93x_do_write_gp(fdc37c93x_t *dev, int reg, int bit, int set) +{ + dev->gpio_regs[reg] = (dev->gpio_regs[reg] & ~(1 << bit)) | + (set << bit); +} + +static __inline void +fdc37c93x_do_write_alt(fdc37c93x_t *dev, int alt, int reg, int bit, int set) +{ + dev->alt_regs[alt][reg] = (dev->alt_regs[alt][reg] & ~(1 << bit)) | + (set << bit); +} + +static void +fdc37c93x_write_gp(fdc37c93x_t *dev, int reg, int bit, int set) +{ + uint8_t gp_func_reg = dev->ld_regs[0x08][gp_func_regs[reg][bit]]; + uint8_t gp_func; + + if (gp_func_reg & 0x02) + set = !set; + + if (!(gp_func_reg & 0x01)) switch (reg) { + default: + /* Do nothing, this GP does not exist. */ + break; + case 1: + switch (bit) { + default: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + fdc37c93x_do_write_gp(dev, reg, bit, set); + else + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + gp_func = (gp_func_reg >> 3) & 0x03; + if (!(gp_func & 0x01)) { + if (gp_func & 0x02) { + set ? picint(1 << 13) : picintc(1 << 13); + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + } else + fdc37c93x_do_write_gp(dev, reg, bit, set); + } + break; + case 3: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x01) + /* TODO: Write to power LED if it's ever implemented. */ + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + else + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 6: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 1 ... 3: + fdc37c93x_do_write_alt(dev, gp_func - 1, reg, bit, set); + break; + } + break; + } + break; + case 2: + switch (bit) { + default: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + fdc37c93x_do_write_gp(dev, reg, bit, set); + else + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 0: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 2: + kbc_at_write_p(dev->kbc, 2, 0xfe, set); + break; + } + break; + case 1: case 2: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (gp_func) { + case 0: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 1: case 2: + fdc37c93x_do_write_alt(dev, gp_func - 1, reg, bit, set); + break; + } + break; + case 5: + gp_func = (gp_func_reg >> 3) & 0x01; + if (gp_func == 0x00) + fdc37c93x_do_write_gp(dev, reg, bit, set); + else + kbc_at_write_p(dev->kbc, 2, 0xfd, set << 1); + break; + case 6: case 7: + /* Do nothing, these bits do not exist. */ + break; + } + break; + case 4: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + } + break; + case 0: case 1: + switch (gp_func) { + case 0: + fdc_set_media_id(dev->fdc, bit ^ 1, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + } + break; + case 6: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 2: + /* TODO: Write to power LED if it's ever implemented. */ + fdc37c93x_do_write_alt(dev, 1, reg, bit, set); + break; + case 3: + fdc37c93x_do_write_alt(dev, 2, reg, bit, set); + break; + } + break; + case 7: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 2: + fdc37c93x_do_write_alt(dev, 1, reg, bit, set); + if (!set) + smi_raise(); + break; + } + break; + } + break; + case 5: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + break; + case 0: case 3: case 4: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + } + break; + case 1: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + if (set) + plat_power_off(); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + } + break; + } + break; + case 6: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 2: + kbc_at_write_p(dev->kbc, 1, ~(1 << bit), set << bit); + break; + } + break; + case 0: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 2: + /* TODO: Write to power LED if it's ever implemented. */ + fdc37c93x_do_write_alt(dev, 1, reg, bit, set); + break; + } + break; + case 1: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + case 2: + fdc37c93x_do_write_alt(dev, 1, reg, bit, set); + break; + } + break; + } + break; + case 7: + gp_func = (gp_func_reg >> 3) & 0x03; + switch (bit) { + default: + switch (gp_func) { + case 0: + fdc37c93x_do_write_alt(dev, 0, reg, bit, set); + break; + case 1: + fdc37c93x_do_write_gp(dev, reg, bit, set); + break; + } + break; + } + break; + } +} + static uint8_t fdc37c93x_gpio_read(uint16_t port, void *priv) { const fdc37c93x_t *dev = (fdc37c93x_t *) priv; uint8_t ret = 0xff; - if (strcmp(machine_get_internal_name(), "vectra54")) - ret = dev->gpio_regs[port & 1]; + if (dev->locked) { + if (dev->is_compaq) + ret = fdc37c93x_read(port & 0x0001, priv); + } else if (port & 0x0001) switch (dev->gpio_reg) { + case 0x01: case 0x02: + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, dev->gpio_reg, i); + break; + case 0x03: + ret = dev->ld_regs[0x08][0xf4]; + break; + case 0x04 ... 0x07: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, dev->gpio_reg, i); + } + break; + case 0x08 ... 0x0f: + if (dev->chip_id >= FDC37C93X_FR) + ret = dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08]; + break; + } else + ret = dev->gpio_reg; return ret; } @@ -139,8 +706,52 @@ fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; - if (!(port & 1)) - dev->gpio_regs[0] = (dev->gpio_regs[0] & 0xfc) | (val & 0x03); + if (dev->locked) { + if (dev->is_compaq) + fdc37c93x_write(port & 0x0001, val, priv); + } else if (port & 0x0001) switch (dev->gpio_reg) { + case 0x01: case 0x02: + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, dev->gpio_reg, i, val & (1 << i)); + break; + case 0x03: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x08][0xf4] = val & 0xef; + else + dev->ld_regs[0x08][0xf4] = val & 0x0f; + break; + case 0x04 ... 0x07: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, dev->gpio_reg, i, val & (1 << i)); + break; + case 0x08: case 0x0a: + case 0x0c: case 0x0e: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val; + break; + case 0x09: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val & 0xd3; + break; + case 0x0b: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val & 0x17; + break; + case 0x0d: + if (dev->chip_id == FDC37C93X_APM) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val; + else if (dev->chip_id == FDC37C93X_FR) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val & 0xbf; + break; + case 0x0f: + if (dev->chip_id == FDC37C93X_APM) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val & 0x7f; + else if (dev->chip_id == FDC37C93X_FR) + dev->ld_regs[0x08][0xb0 + dev->gpio_reg - 0x08] = val & 0x3f; + break; + } else + dev->gpio_reg = val; } static void @@ -226,7 +837,14 @@ fdc37c93x_serial_handler(fdc37c93x_t *dev, const int uart) serial_setup(dev->uart[uart], dev->uart_base[uart], dev->ld_regs[uart_no][0x70]); } - serial_irq(dev->uart[uart], dev->ld_regs[uart_no][0x70]); + /* + TODO: If UART 2's own IRQ pin is also enabled when shared, + it should also be asserted. + */ + if ((dev->chip_id >= FDC37C93X_FR) && (dev->ld_regs[4][0xf0] & 0x80)) + serial_irq(dev->uart[uart], dev->ld_regs[4][0x70]); + else + serial_irq(dev->uart[uart], dev->ld_regs[uart_no][0x70]); } static void @@ -304,7 +922,8 @@ fdc37c93x_auxio_handler(fdc37c93x_t *dev) static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) { - const uint8_t local_enable = !dev->locked && !!(dev->regs[0x03] & 0x80); + const uint8_t local_enable = !!(dev->regs[0x03] & 0x80) || + (dev->is_compaq && dev->locked); const uint16_t old_base = dev->gpio_base; dev->gpio_base = 0x0000; @@ -383,23 +1002,15 @@ static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) { fdc37c93x_t *dev = (fdc37c93x_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; + uint8_t index = !(port & 1); uint8_t valxor; - /* Compaq Presario 4500: Unlock at FB, Register at EA, Data at EB, Lock at F9. */ - if (port == 0xea) - index = 1; - else if (port == 0xeb) - index = 0; - - if (port == 0xfb) { + if (port == 0x00fb) { fdc37c93x_state_change(dev, 1); dev->tries = 0; - return; - } else if (port == 0xf9) { + } else if (port == 0x00f9) fdc37c93x_state_change(dev, 0); - return; - } else if (index) { + else if (index) { if ((!dev->is_compaq) && (val == 0x55) && !dev->locked) { if (dev->tries) { fdc37c93x_state_change(dev, 1); @@ -407,338 +1018,480 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) } else dev->tries++; } else if (dev->locked) { - if ((!dev->is_compaq) && (val == 0xaa)) { + if ((!dev->is_compaq) && (val == 0xaa)) fdc37c93x_state_change(dev, 0); - return; - } - dev->cur_reg = val; + else + dev->cur_reg = val; } else if ((!dev->is_compaq) && dev->tries) dev->tries = 0; - return; - } else { - if (dev->locked) { - if (dev->cur_reg < 48) { - valxor = val ^ dev->regs[dev->cur_reg]; - if ((val == 0x20) || (val == 0x21)) - return; - dev->regs[dev->cur_reg] = val; - } else { - uint8_t keep = 0x00; + } else if (dev->locked) { + if (dev->cur_reg < 0x30) { + valxor = val ^ dev->regs[dev->cur_reg]; - valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; - if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) - return; - /* Block writes to some logical devices. */ - if (dev->regs[7] > 0x0a) - return; - else - switch (dev->regs[7]) { - // case 0x01: - // case 0x02: - // return; - case 0x06: - if (!dev->has_nvr) - return; - /* Bits 0 to 3 of logical device 6 (RTC) register F0h must stay set - once they are set. */ - else if (dev->cur_reg == 0xf0) - keep = dev->ld_regs[dev->regs[7]][dev->cur_reg] & 0x0f; - break; - case 0x09: - /* If we're on the FDC37C935, return as this is not a valid - logical device there. */ - if (!dev->is_apm && (dev->chip_id == 0x02)) - return; - break; - case 0x0a: - /* If we're not on the FDC37C931APM, return as this is not a - valid logical device there. */ - if (!dev->is_apm) - return; - break; - - default: - break; - } - dev->ld_regs[dev->regs[7]][dev->cur_reg] = val | keep; - } - } else - return; - } - - if (dev->cur_reg < 48) { - switch (dev->cur_reg) { - case 0x02: - if (val == 0x02) - fdc37c93x_state_change(dev, 0); - break; - case 0x03: - dev->regs[0x03] &= 0x83; - break; - case 0x22: - if (valxor & 0x01) - fdc37c93x_fdc_handler(dev); - if (valxor & 0x08) - fdc37c93x_lpt_handler(dev); - if (valxor & 0x10) - fdc37c93x_serial_handler(dev, 0); - if (valxor & 0x20) - fdc37c93x_serial_handler(dev, 1); - if ((valxor & 0x40) && (dev->chip_id != 0x02)) - fdc37c93x_access_bus_handler(dev); - break; - - case 0x27: - if (dev->chip_id != 0x02) - fdc37c93x_superio_handler(dev); - break; - - default: - break; - } - - return; - } - - switch (dev->regs[7]) { - case 0: - /* FDD */ switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - if ((dev->cur_reg == 0x30) && (val & 0x01)) - dev->regs[0x22] |= 0x01; - if (valxor) - fdc37c93x_fdc_handler(dev); + case 0x02: + dev->regs[dev->cur_reg] = val; + if (val == 0x02) + fdc37c93x_state_change(dev, 0); break; - case 0xF0: + case 0x03: + dev->regs[dev->cur_reg] = val & 0x83; + break; + case 0x07: case 0x26: + case 0x2e ... 0x2f: + dev->regs[dev->cur_reg] = val; + break; + case 0x22: + if (dev->chip_id >= FDC37C93X_FR) + dev->regs[dev->cur_reg] = val & 0x7f; + else + dev->regs[dev->cur_reg] = val & 0x6f; + if (valxor & 0x01) - fdc_update_enh_mode(dev->fdc, val & 0x01); - if (valxor & 0x10) - fdc_set_swap(dev->fdc, (val & 0x10) >> 4); - break; - case 0xF1: - if (valxor & 0xC) - fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); - break; - case 0xF2: - if (valxor & 0xC0) - fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); - if (valxor & 0x30) - fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); - if (valxor & 0x0C) - fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); - if (valxor & 0x03) - fdc_update_rwc(dev->fdc, 0, (val & 0x03)); - break; - case 0xF4: - if (valxor & 0x18) - fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); - break; - case 0xF5: - if (valxor & 0x18) - fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); - break; - case 0xF6: - if (valxor & 0x18) - fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); - break; - case 0xF7: - if (valxor & 0x18) - fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); - break; - - default: - break; - } - break; - case 3: - /* Parallel port */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if ((dev->cur_reg == 0x30) && (val & 0x01)) - dev->regs[0x22] |= 0x08; - if (valxor) + fdc37c93x_fdc_handler(dev); + if (valxor & 0x08) fdc37c93x_lpt_handler(dev); - break; - - default: - break; - } - break; - case 4: - /* Serial port 1 */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if ((dev->cur_reg == 0x30) && (val & 0x01)) - dev->regs[0x22] |= 0x10; - if (valxor) + if (valxor & 0x10) fdc37c93x_serial_handler(dev, 0); - break; - - default: - break; - } - break; - case 5: - /* Serial port 2 */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if ((dev->cur_reg == 0x30) && (val & 0x01)) - dev->regs[0x22] |= 0x20; - if (valxor) + if (valxor & 0x20) fdc37c93x_serial_handler(dev, 1); - break; - - default: - break; - } - break; - case 6: - /* RTC/NVR */ - if (!dev->has_nvr) - return; - switch (dev->cur_reg) { - case 0x30: - if (valxor) { - fdc37c93x_nvr_pri_handler(dev); - if (dev->chip_id != 0x02) - fdc37c93x_nvr_sec_handler(dev); - } - break; - case 0x62: - case 0x63: - if ((dev->chip_id != 0x02) && valxor) - fdc37c93x_nvr_sec_handler(dev); - break; - case 0xf0: - if (valxor) { - nvr_lock_set(0x80, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x01), dev->nvr); - nvr_lock_set(0xa0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x02), dev->nvr); - nvr_lock_set(0xc0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x04), dev->nvr); - nvr_lock_set(0xe0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x08), dev->nvr); - if ((dev->chip_id == 0x02) && (dev->ld_regs[6][dev->cur_reg] & 0x80)) - nvr_bank_set(0, 1, dev->nvr); - else if ((dev->chip_id != 0x02) && (dev->ld_regs[6][dev->cur_reg] & 0x80)) - switch ((dev->ld_regs[6][dev->cur_reg] >> 4) & 0x07) { - default: - case 0x00: - nvr_bank_set(0, 0xff, dev->nvr); - nvr_bank_set(1, 1, dev->nvr); - break; - case 0x01: - nvr_bank_set(0, 0, dev->nvr); - nvr_bank_set(1, 1, dev->nvr); - break; - case 0x02: - case 0x04: - nvr_bank_set(0, 0xff, dev->nvr); - nvr_bank_set(1, 0xff, dev->nvr); - break; - case 0x03: - case 0x05: - nvr_bank_set(0, 0, dev->nvr); - nvr_bank_set(1, 0xff, dev->nvr); - break; - case 0x06: - nvr_bank_set(0, 0xff, dev->nvr); - nvr_bank_set(1, 2, dev->nvr); - break; - case 0x07: - nvr_bank_set(0, 0, dev->nvr); - nvr_bank_set(1, 2, dev->nvr); - break; - } - else { - nvr_bank_set(0, 0, dev->nvr); - if (dev->chip_id != 0x02) - nvr_bank_set(1, 0xff, dev->nvr); - } - - fdc37c93x_nvr_pri_handler(dev); - if (dev->chip_id != 0x02) - fdc37c93x_nvr_sec_handler(dev); - } - break; - - default: - break; - } - break; - case 7: - /* Keyboard */ - switch (dev->cur_reg) { - case 0x30: - if (valxor) - fdc37c93x_kbc_handler(dev); - break; - - default: - break; - } - break; - case 8: - /* Auxiliary I/O */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if (valxor) - fdc37c93x_auxio_handler(dev); - break; - - default: - break; - } - break; - case 9: - /* Access bus (FDC37C932FR and FDC37C931APM only) */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x70: - if ((dev->cur_reg == 0x30) && (val & 0x01)) - dev->regs[0x22] |= 0x40; - if (valxor) + if ((dev->chip_id >= FDC37C93X_FR) && (valxor & 0x40)) fdc37c93x_access_bus_handler(dev); break; + case 0x23: + if (dev->chip_id >= FDC37C93X_FR) + dev->regs[dev->cur_reg] = val & 0x7f; + else + dev->regs[dev->cur_reg] = val & 0x6f; + break; + case 0x24: + if (dev->chip_id >= FDC37C93X_FR) + dev->regs[dev->cur_reg] = val & 0xcf; + else + dev->regs[dev->cur_reg] = val & 0xcc; + + if ((dev->chip_id >= FDC37C93X_FR) && (valxor & 0x01)) { + serial_set_clock_src(dev->uart[0], (val & 0x01) ? + 48000000.0 : 24000000.0); + serial_set_clock_src(dev->uart[1], (val & 0x01) ? + 48000000.0 : 24000000.0); + } + break; + case 0x27: + if (dev->chip_id >= FDC37C93X_FR) { + dev->regs[dev->cur_reg] = val; + + fdc37c93x_superio_handler(dev); + } + break; + case 0x28: + if (dev->chip_id >= FDC37C93X_FR) + dev->regs[dev->cur_reg] = val & 0x1f; + break; default: break; } - break; - case 10: - /* Access bus (FDC37C931APM only) */ - switch (dev->cur_reg) { - case 0x30: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x70: - if (valxor) - fdc37c93x_acpi_handler(dev); - break; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; - default: + if ((dev->regs[7] <= dev->max_ld) && ((dev->regs[7] != 0x08) || + (dev->cur_reg < 0xb0) || (dev->cur_reg > 0xdf) || + (dev->chip_id >= FDC37C93X_FR))) switch (dev->regs[7]) { + case 0x00: /* FDD */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x70: + case 0x74: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x01; + if (valxor) + fdc37c93x_fdc_handler(dev); + break; + case 0xf0: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x1f; + + if (valxor & 0x01) + fdc_update_enh_mode(dev->fdc, val & 0x01); + if (valxor & 0x10) + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xf1: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0xfc; + + if (valxor & 0x0c) + fdc_update_densel_force(dev->fdc, (val & 0xc) >> 2); + break; + case 0xf2: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if (valxor & 0xc0) + fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); + if (valxor & 0x0c) + fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (val & 0x03)); + break; + case 0xf4 ... 0xf7: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x5b; + + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, dev->cur_reg - 0xf4, + (val & 0x18) >> 3); + break; + } + break; + case 0x01: /* IDE1 */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x02; + break; + case 0xf0: case 0xf1: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x1f; + else if (dev->cur_reg == 0xf0) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + break; + } + break; + case 0x02: /* IDE2 */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x04; + break; + case 0xf0: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x01; + break; + } + break; + case 0x03: /* Parallel Port */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x70: + case 0x74: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x08; + if (valxor) + fdc37c93x_lpt_handler(dev); + break; + case 0xf0: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + break; + case 0xf1: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x03; + break; + } + break; + case 0x04: /* Serial port 1 */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x10; + if (valxor) + fdc37c93x_serial_handler(dev, 0); + break; + /* TODO: Bit 0 = MIDI Mode, Bit 1 = High speed. */ + case 0xf0: + if (dev->chip_id >= FDC37C93X_FR) { + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x83; + } else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x03; + + if (valxor & 0x83) { + fdc37c93x_serial_handler(dev, 0); + fdc37c93x_serial_handler(dev, 1); + } + break; + } + break; + case 0x05: /* Serial port 2 */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + case 0x74: + if (((dev->cur_reg != 0x62) && (dev->cur_reg != 0x63)) || + (dev->chip_id == FDC37C93X_FR)) { + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x20; + if (valxor) + fdc37c93x_serial_handler(dev, 1); + } + break; + /* TODO: Bit 0 = MIDI Mode, Bit 1 = High speed. */ + case 0xf0: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x03; + + if (valxor & 0x03) { + fdc37c93x_serial_handler(dev, 0); + fdc37c93x_serial_handler(dev, 1); + } + break; + case 0xf1: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x7f; + break; + case 0xf2: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + break; + } + break; + case 0x06: /* RTC */ + switch (dev->cur_reg) { + case 0x30: + // case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + if (((dev->cur_reg != 0x62) && (dev->cur_reg != 0x63)) || + (dev->chip_id >= FDC37C93X_FR)) { + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if (valxor) { + fdc37c93x_nvr_pri_handler(dev); + + if (dev->chip_id >= FDC37C93X_FR) + fdc37c93x_nvr_sec_handler(dev); + } + } + break; + case 0xf0: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x8f; + + if (valxor) { + nvr_lock_set(0x80, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x01), dev->nvr); + nvr_lock_set(0xa0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x02), dev->nvr); + nvr_lock_set(0xc0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x04), dev->nvr); + nvr_lock_set(0xe0, 0x20, !!(dev->ld_regs[6][dev->cur_reg] & 0x08), dev->nvr); + if (dev->ld_regs[6][dev->cur_reg] & 0x80) { + if (dev->chip_id == FDC37C93X_NORMAL) + nvr_bank_set(0, 1, dev->nvr); + else switch ((dev->ld_regs[6][dev->cur_reg] >> 4) & 0x07) { + case 0x00: + default: + nvr_bank_set(0, 0xff, dev->nvr); + nvr_bank_set(1, 1, dev->nvr); + break; + case 0x01: + nvr_bank_set(0, 0, dev->nvr); + nvr_bank_set(1, 1, dev->nvr); + break; + case 0x02: case 0x04: + nvr_bank_set(0, 0xff, dev->nvr); + nvr_bank_set(1, 0xff, dev->nvr); + break; + case 0x03: case 0x05: + nvr_bank_set(0, 0, dev->nvr); + nvr_bank_set(1, 0xff, dev->nvr); + break; + case 0x06: + nvr_bank_set(0, 0xff, dev->nvr); + nvr_bank_set(1, 2, dev->nvr); + break; + case 0x07: + nvr_bank_set(0, 0, dev->nvr); + nvr_bank_set(1, 2, dev->nvr); + break; + } + } else { + nvr_bank_set(0, 0, dev->nvr); + if (dev->chip_id >= FDC37C93X_FR) + nvr_bank_set(1, 0xff, dev->nvr); + } + + fdc37c93x_nvr_pri_handler(dev); + if (dev->chip_id >= FDC37C93X_FR) + fdc37c93x_nvr_sec_handler(dev); + } + break; + case 0xf1: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x1f; + break; + case 0xf2: case 0xf3: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + break; + case 0xf4: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x83; + break; + } + break; + case 0x07: /* Keyboard */ + switch (dev->cur_reg) { + case 0x30: + case 0x70: case 0x71: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if (valxor) + fdc37c93x_kbc_handler(dev); + break; + case 0xf0: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x87; + break; + } + break; + case 0x08: /* Aux. I/O */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if (valxor) + fdc37c93x_auxio_handler(dev); + break; + case 0xb0: case 0xb2: + case 0xb4: case 0xb6: + case 0xe0: case 0xe1: + case 0xe9: case 0xf2: + case 0xf3: + case 0xc0 ... 0xc9: + case 0xcb ... 0xcc: + case 0xd0 ... 0xdf: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + break; + case 0xb1: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0xd3; + break; + case 0xb3: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x17; + break; + case 0xb5: + if (dev->chip_id == FDC37C93X_APM) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0xbf; + break; + case 0xb7: + if (dev->chip_id == FDC37C93X_APM) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x7f; + else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x3f; + break; + case 0xb8: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x3f; + break; + case 0x18: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x18; + break; + case 0xe2 ... 0xe5: + case 0xe7: + case 0xeb ... 0xed: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x0f; + break; + case 0xe6: case 0xe8: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x1f; + break; + case 0xea: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x9f; + break; + case 0xef: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0xf8; + break; + case 0xf1: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x83; + else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x03; + break; + case 0xf4: + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0xef; + else + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val & 0x0f; + break; + case 0xf6: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 1, i, val & (1 << i)); + break; + case 0xf7: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 2, i, val & (1 << i)); + break; + case 0xf8: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 4, i, val & (1 << i)); + break; + case 0xf9: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 5, i, val & (1 << i)); + break; + case 0xfa: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 6, i, val & (1 << i)); + break; + case 0xfb: + if (dev->chip_id >= FDC37C93X_FR) + for (uint8_t i = 0; i < 8; i++) + fdc37c93x_write_gp(dev, 7, i, val & (1 << i)); + break; + } + break; + case 0x09: /* Access.Bus */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if ((dev->cur_reg == 0x30) && (val & 0x01)) + dev->regs[0x22] |= 0x40; + if (valxor) + fdc37c93x_access_bus_handler(dev); + break; + } + break; + case 0x0a: /* ACPI */ + switch (dev->cur_reg) { + case 0x30: + case 0x60: case 0x61: + case 0x62: case 0x63: + case 0x70: + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + + if (valxor) + fdc37c93x_acpi_handler(dev); + break; + } break; } - break; - - default: - break; + } } } @@ -764,11 +1517,58 @@ fdc37c93x_read(uint16_t port, void *priv) ret = dev->chip_id; else ret = dev->regs[dev->cur_reg]; - } else { - if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { - ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); - } else + } else if (dev->regs[7] <= dev->max_ld) { + if ((dev->regs[7] == 0x00) && (dev->cur_reg == 0xf2)) + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + else if ((dev->regs[7] != 0x06) || (dev->cur_reg != 0xf3)) ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + else if ((dev->regs[7] == 0x08) && (dev->cur_reg >= 0xf6) && + (dev->cur_reg <= 0xfb) && + (dev->chip_id >= FDC37C93X_FR)) switch (dev->cur_reg) { + case 0xf6: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 1, i); + } + break; + case 0xf7: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 2, i); + } + break; + case 0xf8: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 4, i); + } + break; + case 0xf9: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 5, i); + } + break; + case 0xfa: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 6, i); + } + break; + case 0xfb: + if (dev->chip_id >= FDC37C93X_FR) { + ret = 0x00; + for (uint8_t i = 0; i < 8; i++) + ret |= fdc37c93x_read_gp(dev, 7, i); + } + break; + } } } } @@ -786,10 +1586,12 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->regs[0x21] = 0x01; dev->regs[0x22] = 0x39; dev->regs[0x24] = 0x04; - dev->regs[0x26] = dev->port_370 ? 0x70 : 0xf0; + if (dev->chip_id >= FDC37C93X_FR) + dev->regs[0x26] = dev->port_370 ? 0x70 : 0xf0; dev->regs[0x27] = 0x03; - memset(dev->ld_regs, 0x00, sizeof(dev->ld_regs)); + for (uint8_t i = 0; i <= 0x0a; i++) + memset(dev->ld_regs[i], 0x00, 256); /* Logical device 0: FDD */ dev->ld_regs[0x00][0x30] = 0x00; @@ -807,7 +1609,8 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[0x01][0x62] = 0x03; dev->ld_regs[0x01][0x63] = 0xf6; dev->ld_regs[0x01][0x70] = 0x0e; - dev->ld_regs[0x01][0xf0] = 0x0c; + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x01][0xf0] = 0x0c; /* Logical device 2: IDE2 */ dev->ld_regs[0x02][0x30] = 0x00; @@ -840,7 +1643,8 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[0x05][0x70] = 0x03; dev->ld_regs[0x05][0x74] = 0x04; dev->ld_regs[0x05][0xf1] = 0x02; - dev->ld_regs[0x05][0xf2] = 0x03; + if (dev->chip_id >= FDC37C93X_FR) + dev->ld_regs[0x05][0xf2] = 0x03; serial_irq(dev->uart[1], dev->ld_regs[5][0x70]); /* Logical device 6: RTC */ @@ -858,16 +1662,34 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[0x08][0x30] = 0x00; dev->ld_regs[0x08][0x60] = 0x00; dev->ld_regs[0x08][0x61] = 0x00; + if (dev->chip_id >= FDC37C93X_FR) { + dev->ld_regs[0x08][0xb1] = 0x80; + dev->ld_regs[0x08][0xc0] = 0x01; + dev->ld_regs[0x08][0xc1] = 0x01; + dev->ld_regs[0x08][0xc5] = 0x01; + dev->ld_regs[0x08][0xc6] = 0x01; + dev->ld_regs[0x08][0xc7] = 0x01; + dev->ld_regs[0x08][0xc8] = 0x01; + dev->ld_regs[0x08][0xc9] = 0x80; + dev->ld_regs[0x08][0xcb] = 0x01; + dev->ld_regs[0x08][0xcc] = 0x01; + memset(&(dev->ld_regs[0x08][0xd0]), 0x01, 16); + } + memset(&(dev->ld_regs[0x08][0xe0]), 0x01, 14); /* Logical device 9: ACCESS.bus */ - dev->ld_regs[0x09][0x30] = 0x00; - dev->ld_regs[0x09][0x60] = 0x00; - dev->ld_regs[0x09][0x61] = 0x00; + if (dev->chip_id >= FDC37C93X_FR) { + dev->ld_regs[0x09][0x30] = 0x00; + dev->ld_regs[0x09][0x60] = 0x00; + dev->ld_regs[0x09][0x61] = 0x00; + } /* Logical device A: ACPI */ - dev->ld_regs[0x0a][0x30] = 0x00; - dev->ld_regs[0x0a][0x60] = 0x00; - dev->ld_regs[0x0a][0x61] = 0x00; + if (dev->chip_id == FDC37C93X_APM) { + dev->ld_regs[0x0a][0x30] = 0x00; + dev->ld_regs[0x0a][0x60] = 0x00; + dev->ld_regs[0x0a][0x61] = 0x00; + } fdc37c93x_gpio_handler(dev); fdc37c93x_lpt_handler(dev); @@ -899,6 +1721,62 @@ fdc37c93x_reset(fdc37c93x_t *dev) if (dev->chip_id != 0x02) fdc37c93x_superio_handler(dev); + if (dev->chip_id >= FDC37C93X_FR) { + serial_set_clock_src(dev->uart[0], 24000000.0); + serial_set_clock_src(dev->uart[1], 24000000.0); + } + + memset(dev->gpio_regs, 0xff, 256); + memset(dev->gpio_pulldn, 0xff, 8); + + /* Acer V62X requires bit 0 to be clear to not be stuck in "clear password" mode. */ + if (!strcmp(machine_get_internal_name(), "vectra54")) { + dev->gpio_pulldn[1] = 0x40; + + /* + HP Vectra VL/5 Series 4 GPIO + (TODO: Find how multipliers > 3.0 are defined): + + Bit 6: 1 = can boot, 0 = no; + Bit 7, 1 = multiplier (00 = 2.5, 01 = 2.0, + 10 = 3.0, 11 = 1.5); + Bit 5, 4 = bus speed (00 = 50 MHz, 01 = 66 MHz, + 10 = 60 MHz, 11 = ????): + Bit 7, 5, 4, 1: 0000 = 125 MHz, 0010 = 166 MHz, + 0100 = 150 MHz, 0110 = ??? MHz; + 0001 = 100 MHz, 0011 = 133 MHz, + 0101 = 120 MHz, 0111 = ??? MHz; + 1000 = 150 MHz, 1010 = 200 MHz, + 1100 = 180 MHz, 1110 = ??? MHz; + 1001 = 75 MHz, 1011 = 100 MHz, + 1101 = 90 MHz, 1111 = ??? MHz + */ + if (cpu_busspeed <= 40000000) + dev->gpio_pulldn[1] |= 0x30; + else if ((cpu_busspeed > 40000000) && (cpu_busspeed <= 50000000)) + dev->gpio_pulldn[1] |= 0x00; + else if ((cpu_busspeed > 50000000) && (cpu_busspeed <= 60000000)) + dev->gpio_pulldn[1] |= 0x20; + else if (cpu_busspeed > 60000000) + dev->gpio_pulldn[1] |= 0x10; + + if (cpu_dmulti <= 1.5) + dev->gpio_pulldn[1] |= 0x82; + else if ((cpu_dmulti > 1.5) && (cpu_dmulti <= 2.0)) + dev->gpio_pulldn[1] |= 0x02; + else if ((cpu_dmulti > 2.0) && (cpu_dmulti <= 2.5)) + dev->gpio_pulldn[1] |= 0x00; + else if (cpu_dmulti > 2.5) + dev->gpio_pulldn[1] |= 0x80; + } else if (!strcmp(machine_get_internal_name(), "acerv62x")) + dev->gpio_pulldn[1] = 0xfe; + else + dev->gpio_pulldn[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; + + if (strstr(machine_get_internal_name(), "acer") != NULL) + /* Bit 2 on the Acer V35N is the text/graphics toggle, bits 1 and 3 = ????. */ + dev->gpio_pulldn[2] = 0x10; + dev->locked = 0; } @@ -920,41 +1798,59 @@ fdc37c93x_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->chip_id = info->local & 0xff; - dev->is_apm = (info->local >> 8) & 0x01; - dev->is_compaq = (info->local >> 8) & 0x02; - dev->has_nvr = !((info->local >> 8) & 0x04); - dev->port_370 = ((info->local >> 8) & 0x08); + dev->chip_id = info->local & FDC37C93X_CHIP_ID; + dev->kbc_type = info->local & FDC37C93X_KBC; - dev->gpio_regs[0] = 0xff; -#if 0 - dev->gpio_regs[1] = (info->local == 0x0030) ? 0xff : 0xfd; -#endif - dev->gpio_regs[1] = (dev->chip_id == 0x30) ? 0xff : 0xfd; + dev->is_apm = (dev->chip_id == FDC37C93X_APM); + dev->is_compaq = (dev->kbc_type == FDC37C931); + + dev->has_nvr = !(info->local & FDC37C93X_NO_NVR); + dev->port_370 = !!(info->local & FDC37C93X_370); if (dev->has_nvr) { - dev->nvr = device_add(&at_nvr_device); + dev->nvr = device_add(&amstrad_megapc_nvr_device); nvr_bank_set(0, 0, dev->nvr); nvr_bank_set(1, 0xff, dev->nvr); } - if (dev->is_apm || (dev->chip_id == 0x03)) - dev->access_bus = device_add(&access_bus_device); + dev->max_ld = 8; - if (dev->is_apm) + if (dev->chip_id >= FDC37C93X_FR) { + dev->access_bus = device_add(&access_bus_device); + dev->max_ld++; + } + + if (dev->chip_id == FDC37C93X_APM) { dev->acpi = device_add(&acpi_smc_device); + dev->max_ld++; + } if (dev->is_compaq) { - io_sethandler(0x0ea, 0x0002, - fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); io_sethandler(0x0f9, 0x0001, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); io_sethandler(0x0fb, 0x0001, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); } - dev->kbc = device_add(&keyboard_ps2_ami_pci_device); + switch (dev->kbc_type) { + case FDC37C931: + dev->kbc = device_add(&keyboard_ps2_compaq_device); + break; + case FDC37C932: + dev->kbc = device_add(&keyboard_ps2_intel_ami_pci_device); + break; + case FDC37C933: + default: + dev->kbc = device_add(&keyboard_ps2_pci_device); + break; + case FDC37C935: + dev->kbc = device_add(&keyboard_ps2_phoenix_device); + break; + case FDC37C937: + dev->kbc = device_add(&keyboard_ps2_phoenix_pci_device); + break; + } /* Set the defaults here so the ports can be removed by fdc37c93x_reset(). */ dev->fdc_base = 0x03f0; @@ -978,109 +1874,11 @@ fdc37c93x_init(const device_t *info) return dev; } -const device_t fdc37c931apm_device = { - .name = "SMC FDC37C931APM Super I/O", - .internal_name = "fdc37c931apm", +const device_t fdc37c93x_device = { + .name = "SMC FDC37C93x Super I/O", + .internal_name = "fdc37c93x", .flags = 0, - .local = 0x130, /* Share the same ID with the 932QF. */ - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c931apm_compaq_device = { - .name = "SMC FDC37C931APM Super I/O (Compaq Presario 4500)", - .internal_name = "fdc37c931apm_compaq", - .flags = 0, - .local = 0x330, /* Share the same ID with the 932QF. */ - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c932_device = { - .name = "SMC FDC37C932 Super I/O", - .internal_name = "fdc37c932", - .flags = 0, - .local = 0x02, - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c932fr_device = { - .name = "SMC FDC37C932FR Super I/O", - .internal_name = "fdc37c932fr", - .flags = 0, - .local = 0x03, - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c932qf_device = { - .name = "SMC FDC37C932QF Super I/O", - .internal_name = "fdc37c932qf", - .flags = 0, - .local = 0x30, - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c935_device = { - .name = "SMC FDC37C935 Super I/O", - .internal_name = "fdc37c935", - .flags = 0, - .local = 0x02, - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c935_370_device = { - .name = "SMC FDC37C935 Super I/O (Port 370h)", - .internal_name = "fdc37c935_370", - .flags = 0, - .local = 0x802, - .init = fdc37c93x_init, - .close = fdc37c93x_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t fdc37c935_no_nvr_device = { - .name = "SMC FDC37C935 Super I/O", - .internal_name = "fdc37c935", - .flags = 0, - .local = 0x402, + .local = 0, .init = fdc37c93x_init, .close = fdc37c93x_close, .reset = NULL, From 76ae3eff56269fbe8c41137caf0fb56979e9be3f Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 5 May 2025 05:12:17 +0200 Subject: [PATCH 0840/1190] And the root CMakeLists.txt. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 007c1ffd8..5b78295fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,7 +180,6 @@ cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF) -cmake_dependent_option(LASERXT "VTech Laser XT" ON "DEV_BRANCH" OFF) cmake_dependent_option(OLIVETTI "Olivetti M290" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPEN_AT "OpenAT" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPL4ML "OPL4-ML daughterboard" ON "DEV_BRANCH" OFF) From ebb52490c32fed37442a8fc167d5a5ad2936a9a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 5 May 2025 05:14:56 +0200 Subject: [PATCH 0841/1190] Properly un-dev-branch the Laser XT stuff in the keyboard files. --- src/device/keyboard_xt.c | 2 -- src/include/86box/keyboard.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 3c616a2ab..bafc80d88 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -1312,7 +1312,6 @@ const device_t keyboard_xt_t1x00_device = { .config = NULL }; -#ifdef USE_LASERXT const device_t keyboard_xt_lxt3_device = { .name = "VTech Laser Turbo XT Keyboard", .internal_name = "keyboard_xt_lxt", @@ -1326,7 +1325,6 @@ const device_t keyboard_xt_lxt3_device = { .force_redraw = NULL, .config = NULL }; -#endif /* USE_LASERXT */ const device_t keyboard_xt_olivetti_device = { .name = "Olivetti XT Keyboard", diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 583960e80..024b16169 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -224,9 +224,7 @@ extern const device_t keyboard_xt86_device; extern const device_t keyboard_xt_compaq_device; extern const device_t keyboard_xt_t1x00_device; extern const device_t keyboard_tandy_device; -# ifdef USE_LASERXT extern const device_t keyboard_xt_lxt3_device; -# endif /* USE_LASERXT */ extern const device_t keyboard_xt_olivetti_device; extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_xt_hyundai_device; From 1e81473d34f254cab13019b62e948c6e9a950b53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 5 May 2025 05:59:20 +0200 Subject: [PATCH 0842/1190] Fix MMX_ENTER() exceptions. --- src/cpu/x86_ops_mmx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpu/x86_ops_mmx.h b/src/cpu/x86_ops_mmx.h index 338948af5..9a2d797a8 100644 --- a/src/cpu/x86_ops_mmx.h +++ b/src/cpu/x86_ops_mmx.h @@ -22,12 +22,12 @@ } #define MMX_ENTER() \ - if (!cpu_has_feature(CPU_FEATURE_MMX)) { \ + if (!cpu_has_feature(CPU_FEATURE_MMX) || (cr0 & 0x4)) { \ cpu_state.pc = cpu_state.oldpc; \ x86illegal(); \ return 1; \ } \ - if (cr0 & 0xc) { \ + if (cr0 & 0x8) { \ x86_int(7); \ return 1; \ } \ From c91796c388e481f759b3286f5d3d7e8f83c27251 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Mon, 5 May 2025 19:57:41 +0200 Subject: [PATCH 0843/1190] Add the Micro Firmware/Phoenix 4.05 BIOS for the PB450. --- src/machine/m_at_386dx_486.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 5b746e3ef..ed8f75a84 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -700,6 +700,8 @@ static const device_config_t pb450_config[] = { .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/OPTI802.bin", "" } }, { .name = "PNP 1.1A", .internal_name = "pnp11a", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/PNP11A.bin", "" } }, + { .name = "P4HS20 (Micro Firmware/Phoenix 4.05)", .internal_name = "p4hs20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pb450/p4hs20.bin", "" } }, { .files_no = 0 } }, }, From ab75f222fe04d44fc4f1cb552f78d216a028ec30 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:17:05 +0200 Subject: [PATCH 0844/1190] Acer V60N and V62X: Fix RAM limits. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 44e93f721..bb912cf9a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14166,7 +14166,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 786432, + .max = 532480, .step = 8192 }, .nvrmask = 511, @@ -14617,7 +14617,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 786432, + .max = 540672, .step = 8192 }, .nvrmask = 511, From a0b80e04cd41bc28b27036bb13c96431b687fef9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:18:46 +0200 Subject: [PATCH 0845/1190] Remove the unused mmu_perm stuff. --- src/cpu/x86.c | 1 - src/cpu/x86_ops_mov_ctrl.h | 4 --- src/cpu/x86_ops_mov_ctrl_2386.h | 4 --- src/include/86box/mem.h | 1 - src/mem/mem.c | 59 ++++----------------------------- src/mem/mmu_2386.c | 2 -- 6 files changed, 6 insertions(+), 65 deletions(-) diff --git a/src/cpu/x86.c b/src/cpu/x86.c index a8ab9d866..1b0de661b 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -326,7 +326,6 @@ reset_common(int hard) resetreadlookup(); makemod1table(); cpu_set_edx(); - mmu_perm = 4; } x86seg_reset(); #ifdef USE_DYNAREC diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 253dc059e..3f5d6a4d7 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -201,8 +201,6 @@ opMOV_CRx_r_a16(uint32_t fetchdat) cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; - if (!(cr0 & 0x80000000)) - mmu_perm = 4; if (hascache && !(cr0 & (1 << 30))) cpu_cache_int_enabled = 1; else @@ -267,8 +265,6 @@ opMOV_CRx_r_a32(uint32_t fetchdat) cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; - if (!(cr0 & 0x80000000)) - mmu_perm = 4; if (hascache && !(cr0 & (1 << 30))) cpu_cache_int_enabled = 1; else diff --git a/src/cpu/x86_ops_mov_ctrl_2386.h b/src/cpu/x86_ops_mov_ctrl_2386.h index 8827d29b2..0d13cc833 100644 --- a/src/cpu/x86_ops_mov_ctrl_2386.h +++ b/src/cpu/x86_ops_mov_ctrl_2386.h @@ -193,8 +193,6 @@ opMOV_CRx_r_a16(uint32_t fetchdat) cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; - if (!(cr0 & 0x80000000)) - mmu_perm = 4; if (hascache && !(cr0 & (1 << 30))) cpu_cache_int_enabled = 1; else @@ -255,8 +253,6 @@ opMOV_CRx_r_a32(uint32_t fetchdat) cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; - if (!(cr0 & 0x80000000)) - mmu_perm = 4; if (hascache && !(cr0 & (1 << 30))) cpu_cache_int_enabled = 1; else diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index f8d0f659a..62cb493a5 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -300,7 +300,6 @@ extern int writelnum; extern int memspeed[11]; -extern int mmu_perm; extern uint8_t high_page; /* if a high (> 4 gb) page was detected */ extern uint8_t *_mem_exec[MEM_MAPPINGS_NO]; diff --git a/src/mem/mem.c b/src/mem/mem.c index 8c2cfd6cc..07d897172 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -108,7 +108,6 @@ int mem_a20_alt = 0; int mem_a20_state = 0; int mmuflush = 0; -int mmu_perm = 4; #ifdef USE_NEW_DYNAREC uint64_t *byte_dirty_mask; @@ -125,10 +124,6 @@ mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; uint8_t *_mem_exec[MEM_MAPPINGS_NO]; -/* FIXME: re-do this with a 'mem_ops' struct. */ -static uint8_t *page_lookupp; /* pagetable mmu_perm lookup */ -static uint8_t *readlookupp; -static uint8_t *writelookupp; static mem_mapping_t *base_mapping; static mem_mapping_t *last_mapping; static mem_mapping_t *read_mapping_bus[MEM_MAPPINGS_NO]; @@ -187,10 +182,8 @@ resetreadlookup(void) /* Initialize the tables for high (> 1024K) RAM. */ memset(readlookup2, 0xff, (1 << 20) * sizeof(uintptr_t)); - memset(readlookupp, 0x04, (1 << 20) * sizeof(uint8_t)); memset(writelookup2, 0xff, (1 << 20) * sizeof(uintptr_t)); - memset(writelookupp, 0x04, (1 << 20) * sizeof(uint8_t)); readlnext = 0; writelnext = 0; @@ -204,14 +197,11 @@ flushmmucache(void) for (uint16_t c = 0; c < 256; c++) { if (readlookup[c] != (int) 0xffffffff) { readlookup2[readlookup[c]] = LOOKUP_INV; - readlookupp[readlookup[c]] = 4; readlookup[c] = 0xffffffff; } if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; - page_lookupp[writelookup[c]] = 4; writelookup2[writelookup[c]] = LOOKUP_INV; - writelookupp[writelookup[c]] = 4; writelookup[c] = 0xffffffff; } } @@ -231,9 +221,7 @@ flushmmucache_write(void) for (uint16_t c = 0; c < 256; c++) { if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; - page_lookupp[writelookup[c]] = 4; writelookup2[writelookup[c]] = LOOKUP_INV; - writelookupp[writelookup[c]] = 4; writelookup[c] = 0xffffffff; } } @@ -259,14 +247,11 @@ flushmmucache_nopc(void) for (uint16_t c = 0; c < 256; c++) { if (readlookup[c] != (int) 0xffffffff) { readlookup2[readlookup[c]] = LOOKUP_INV; - readlookupp[readlookup[c]] = 4; readlookup[c] = 0xffffffff; } if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; - page_lookupp[writelookup[c]] = 4; writelookup2[writelookup[c]] = LOOKUP_INV; - writelookupp[writelookup[c]] = 4; writelookup[c] = 0xffffffff; } } @@ -348,7 +333,6 @@ mmutranslatereal_normal(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; rammap(addr2) |= (rw ? 0x60 : 0x20); uint64_t page = temp & ~0x3fffff; @@ -371,7 +355,6 @@ mmutranslatereal_normal(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; rammap(addr2) |= 0x20; rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw ? 0x60 : 0x20); @@ -435,7 +418,6 @@ mmutranslatereal_pae(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; rammap64(addr3) |= (rw ? 0x60 : 0x20); return ((temp & ~0x1fffffULL) + (addr & 0x1fffffULL)) & 0x000000ffffffffffULL; @@ -456,7 +438,6 @@ mmutranslatereal_pae(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; rammap64(addr3) |= 0x20; rammap64(addr4) |= (rw ? 0x60 : 0x20); @@ -631,7 +612,6 @@ addreadlookup(uint32_t virt, uint32_t phys) else readlookup2[virt >> 12] = (uintptr_t) &ram[a]; #endif - readlookupp[virt >> 12] = mmu_perm; readlookup[readlnext++] = virt >> 12; readlnext &= (cachesize - 1); @@ -671,7 +651,6 @@ addwritelookup(uint32_t virt, uint32_t phys) # endif #endif page_lookup[virt >> 12] = &pages[phys >> 12]; - page_lookupp[virt >> 12] = mmu_perm; } else { #if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64) writelookup2[virt >> 12] = (uintptr_t) &ram[(uintptr_t) (phys & ~0xFFF) - (uintptr_t) (virt & ~0xfff)]; @@ -684,7 +663,6 @@ addwritelookup(uint32_t virt, uint32_t phys) writelookup2[virt >> 12] = (uintptr_t) &ram[a]; #endif } - writelookupp[virt >> 12] = mmu_perm; writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); @@ -973,10 +951,8 @@ readmemwl(uint32_t addr) } return readmembl_no_mmut(addr, addr64a[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, addr64a[1])) << 8); - } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = readlookupp[addr >> 12]; + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) return *(uint16_t *) (readlookup2[addr >> 12] + addr); - } } if (cr0 >> 31) { @@ -1044,7 +1020,6 @@ writememwl(uint32_t addr, uint16_t val) writemembl_no_mmut(addr + 1, addr64a[1], val >> 8); return; } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = writelookupp[addr >> 12]; *(uint16_t *) (writelookup2[addr >> 12] + addr) = val; return; } @@ -1052,7 +1027,6 @@ writememwl(uint32_t addr, uint16_t val) if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); - mmu_perm = page_lookupp[addr >> 12]; return; } @@ -1100,10 +1074,8 @@ readmemwl_no_mmut(uint32_t addr, uint32_t *a64) } return readmembl_no_mmut(addr, a64[0]) | (((uint16_t) readmembl_no_mmut(addr + 1, a64[1])) << 8); - } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = readlookupp[addr >> 12]; + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) return *(uint16_t *) (readlookup2[addr >> 12] + addr); - } } if (cr0 >> 31) { @@ -1149,14 +1121,12 @@ writememwl_no_mmut(uint32_t addr, uint32_t *a64, uint16_t val) writemembl_no_mmut(addr + 1, a64[1], val >> 8); return; } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = writelookupp[addr >> 12]; *(uint16_t *) (writelookup2[addr >> 12] + addr) = val; return; } } if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_w) { - mmu_perm = page_lookupp[addr >> 12]; page_lookup[addr >> 12]->write_w(addr, val, page_lookup[addr >> 12]); return; } @@ -1231,10 +1201,8 @@ readmemll(uint32_t addr) /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass their result as a parameter to be used if needed. */ return readmemwl_no_mmut(addr, addr64a) | (((uint32_t) readmemwl_no_mmut(addr + 2, &(addr64a[2]))) << 16); - } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = readlookupp[addr >> 12]; + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) return *(uint32_t *) (readlookup2[addr >> 12] + addr); - } } if (cr0 >> 31) { @@ -1316,14 +1284,12 @@ writememll(uint32_t addr, uint32_t val) writememwl_no_mmut(addr + 2, &(addr64a[2]), val >> 16); return; } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = writelookupp[addr >> 12]; *(uint32_t *) (writelookup2[addr >> 12] + addr) = val; return; } } if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { - mmu_perm = page_lookupp[addr >> 12]; page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); return; } @@ -1378,10 +1344,8 @@ readmemll_no_mmut(uint32_t addr, uint32_t *a64) } return readmemwl_no_mmut(addr, a64) | ((uint32_t) (readmemwl_no_mmut(addr + 2, &(a64[2]))) << 16); - } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = readlookupp[addr >> 12]; + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) return *(uint32_t *) (readlookup2[addr >> 12] + addr); - } } if (cr0 >> 31) { @@ -1429,14 +1393,12 @@ writememll_no_mmut(uint32_t addr, uint32_t *a64, uint32_t val) writememwl_no_mmut(addr + 2, &(a64[2]), val >> 16); return; } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = writelookupp[addr >> 12]; *(uint32_t *) (writelookup2[addr >> 12] + addr) = val; return; } } if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { - mmu_perm = page_lookupp[addr >> 12]; page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); return; } @@ -1516,10 +1478,8 @@ readmemql(uint32_t addr) /* No need to waste precious CPU host cycles on mmutranslate's that were already done, just pass their result as a parameter to be used if needed. */ return readmemll_no_mmut(addr, addr64a) | (((uint64_t) readmemll_no_mmut(addr + 4, &(addr64a[4]))) << 32); - } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = readlookupp[addr >> 12]; + } else if (readlookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) return *(uint64_t *) (readlookup2[addr >> 12] + addr); - } } if (cr0 >> 31) { @@ -1611,14 +1571,12 @@ writememql(uint32_t addr, uint64_t val) writememll_no_mmut(addr + 4, &(addr64a[4]), val >> 32); return; } else if (writelookup2[addr >> 12] != (uintptr_t) LOOKUP_INV) { - mmu_perm = writelookupp[addr >> 12]; *(uint64_t *) (writelookup2[addr >> 12] + addr) = val; return; } } if (page_lookup[addr >> 12] && page_lookup[addr >> 12]->write_l) { - mmu_perm = page_lookupp[addr >> 12]; page_lookup[addr >> 12]->write_l(addr, val, page_lookup[addr >> 12]); page_lookup[addr >> 12]->write_l(addr + 4, val >> 32, page_lookup[addr >> 12]); return; @@ -1702,8 +1660,7 @@ do_mmutranslate(uint32_t addr, uint32_t *a64, int num, int write) a = (a & 0xfffffffffffff000ULL) | ((uint64_t) (addr & 0xfff)); a64[i] = (uint32_t) a; } - } else - mmu_perm = page_lookupp[addr >> 12]; + } addr++; } @@ -2914,7 +2871,6 @@ mem_reset(void) pages = (page_t *) malloc(m * sizeof(page_t)); memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); - memset(page_lookupp, 0x04, (1 << 20) * sizeof(uint8_t)); memset(pages, 0x00, pages_sz * sizeof(page_t)); @@ -3033,11 +2989,8 @@ mem_init(void) /* Allocate the lookup tables. */ page_lookup = (page_t **) malloc((1 << 20) * sizeof(page_t *)); - page_lookupp = (uint8_t *) malloc((1 << 20) * sizeof(uint8_t)); readlookup2 = malloc((1 << 20) * sizeof(uintptr_t)); - readlookupp = malloc((1 << 20) * sizeof(uint8_t)); writelookup2 = malloc((1 << 20) * sizeof(uintptr_t)); - writelookupp = malloc((1 << 20) * sizeof(uint8_t)); } static void diff --git a/src/mem/mmu_2386.c b/src/mem/mmu_2386.c index 1a2782237..ebf062d95 100644 --- a/src/mem/mmu_2386.c +++ b/src/mem/mmu_2386.c @@ -211,7 +211,6 @@ mmutranslatereal_2386(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; mem_writel_map(addr2, mem_readl_map(addr2) | (rw ? 0x60 : 0x20)); return (temp & ~0x3fffff) + (addr & 0x3fffff); @@ -231,7 +230,6 @@ mmutranslatereal_2386(uint32_t addr, int rw) return 0xffffffffffffffffULL; } - mmu_perm = temp & 4; mem_writel_map(addr2, mem_readl_map(addr2) | 0x20); mem_writel_map((temp2 & ~0xfff) + ((addr >> 10) & 0xffc), mem_readl_map((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) | (rw ? 0x60 : 0x20)); From c3debc5e27dd70e94c393d06420b8845ca9187dd Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:21:54 +0200 Subject: [PATCH 0846/1190] Implement the RZ-1000 PCI IDE controller needed by some Intel machines. --- src/disk/CMakeLists.txt | 1 + src/disk/hdc_ide_rz1000.c | 322 +++++++++++++++++++++++++++++++++++++ src/include/86box/hdc.h | 6 + src/machine/m_at_socket4.c | 3 +- src/machine/m_at_socket5.c | 2 +- 5 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 src/disk/hdc_ide_rz1000.c diff --git a/src/disk/CMakeLists.txt b/src/disk/CMakeLists.txt index 3f6a4d018..bdbb9e74c 100644 --- a/src/disk/CMakeLists.txt +++ b/src/disk/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(hdd OBJECT hdc_ide_opti611.c hdc_ide_cmd640.c hdc_ide_cmd646.c + hdc_ide_rz1000.c hdc_ide_sff8038i.c hdc_ide_um8673f.c hdc_ide_w83769f.c diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c new file mode 100644 index 000000000..d93e83859 --- /dev/null +++ b/src/disk/hdc_ide_rz1000.c @@ -0,0 +1,322 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the PC Technology RZ-1000 controller. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/scsi_cdrom.h> +#include <86box/dma.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/keyboard.h> +#include <86box/mem.h> +#include <86box/pci.h> +#include <86box/pic.h> +#include <86box/timer.h> +#include <86box/hdc.h> +#include <86box/hdc_ide.h> +#include <86box/hdc_ide_sff8038i.h> +#include <86box/zip.h> +#include <86box/mo.h> + +typedef struct rz1000_t { + uint8_t vlb_idx; + uint8_t id; + uint8_t in_cfg; + uint8_t channels; + uint8_t pci; + uint8_t irq_state; + uint8_t pci_slot; + uint8_t pad0; + uint8_t regs[256]; + uint32_t local; + int irq_mode[2]; + int irq_pin; + int irq_line; +} rz1000_t; + +static int next_id = 0; + +#define ENABLE_RZ1000_LOG 1 +#ifdef ENABLE_RZ1000_LOG +int rz1000_do_log = ENABLE_RZ1000_LOG; + +static void +rz1000_log(const char *fmt, ...) +{ + va_list ap; + + if (rz1000_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define rz1000_log(fmt, ...) +#endif + +static void +rz1000_ide_handlers(rz1000_t *dev) +{ + uint16_t main; + uint16_t side; + + if (dev->channels & 0x01) { + ide_pri_disable(); + + main = 0x1f0; + side = 0x3f6; + + ide_set_base(0, main); + ide_set_side(0, side); + + if (dev->regs[0x04] & 0x01) + ide_pri_enable(); + } + + if (dev->channels & 0x02) { + ide_sec_disable(); + + main = 0x170; + side = 0x376; + + ide_set_base(1, main); + ide_set_side(1, side); + + if (dev->regs[0x04] & 0x01) + ide_sec_enable(); + } +} + +static void +rz1000_pci_write(int func, int addr, uint8_t val, void *priv) +{ + rz1000_t *dev = (rz1000_t *) priv; + + rz1000_log("rz1000_pci_write(%i, %02X, %02X)\n", func, addr, val); + + if (func == 0x00) + switch (addr) { + case 0x04: + dev->regs[addr] = (val & 0x41); + rz1000_ide_handlers(dev); + break; + case 0x07: + dev->regs[addr] &= ~(val & 0x80); + break; + case 0x09: + if ((dev->regs[addr] & 0x0a) == 0x0a) { + dev->regs[addr] = (dev->regs[addr] & 0x0a) | (val & 0x05); + dev->irq_mode[0] = !!(val & 0x01); + dev->irq_mode[1] = !!(val & 0x04); + rz1000_ide_handlers(dev); + } + break; + case 0x10: + dev->regs[0x10] = (val & 0xf8) | 1; + rz1000_ide_handlers(dev); + break; + case 0x11: + dev->regs[0x11] = val; + rz1000_ide_handlers(dev); + break; + case 0x14: + dev->regs[0x14] = (val & 0xfc) | 1; + rz1000_ide_handlers(dev); + break; + case 0x15: + dev->regs[0x15] = val; + rz1000_ide_handlers(dev); + break; + case 0x18: + dev->regs[0x18] = (val & 0xf8) | 1; + rz1000_ide_handlers(dev); + break; + case 0x19: + dev->regs[0x19] = val; + rz1000_ide_handlers(dev); + break; + case 0x1c: + dev->regs[0x1c] = (val & 0xfc) | 1; + rz1000_ide_handlers(dev); + break; + case 0x1d: + dev->regs[0x1d] = val; + rz1000_ide_handlers(dev); + break; + case 0x40 ... 0x4f: + dev->regs[addr] = val; + break; + } +} + +static uint8_t +rz1000_pci_read(int func, int addr, void *priv) +{ + rz1000_t *dev = (rz1000_t *) priv; + uint8_t ret = 0xff; + + if (func == 0x00) + ret = dev->regs[addr]; + + rz1000_log("rz1000_pci_read(%i, %02X, %02X)\n", func, addr, ret); + + return ret; +} + +static void +rz1000_reset(void *priv) +{ + rz1000_t *dev = (rz1000_t *) priv; + int i = 0; + int min_channel; + int max_channel; + + switch (dev->channels) { + default: + case 0x00: + min_channel = max_channel = 0; + break; + case 0x01: + min_channel = 0; + max_channel = 1; + break; + case 0x02: + min_channel = 2; + max_channel = 3; + break; + case 0x03: + min_channel = 0; + max_channel = 3; + break; + } + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && (cdrom[i].ide_channel >= min_channel) && + (cdrom[i].ide_channel <= max_channel) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel >= min_channel) && + (zip_drives[i].ide_channel <= max_channel) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } + for (i = 0; i < MO_NUM; i++) { + if ((mo_drives[i].bus_type == MO_BUS_ATAPI) && (mo_drives[i].ide_channel >= min_channel) && + (mo_drives[i].ide_channel <= max_channel) && mo_drives[i].priv) + mo_reset((scsi_common_t *) mo_drives[i].priv); + } + + memset(dev->regs, 0x00, sizeof(dev->regs)); + + rz1000_log("dev->local = %08X\n", dev->local); + + dev->regs[0x00] = 0x42; /* PC Technology */ + dev->regs[0x01] = 0x10; + dev->regs[0x02] = 0x00; /* RZ-1000 */ + dev->regs[0x03] = 0x10; + dev->regs[0x04] = 0x01; + dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ + dev->regs[0x08] = 0x02; /* Revision 02 */ + dev->regs[0x09] = dev->local; /* Programming interface */ + dev->regs[0x0a] = 0x01; /* IDE controller */ + dev->regs[0x0b] = 0x01; /* Mass storage controller */ + + dev->regs[0x3c] = 0x14; /* IRQ 14 */ + dev->regs[0x3d] = 0x01; /* INTA */ + + dev->irq_mode[0] = dev->irq_mode[1] = 0; + dev->irq_pin = PCI_INTA; + dev->irq_line = 14; + + rz1000_ide_handlers(dev); +} + +static void +rz1000_close(void *priv) +{ + rz1000_t *dev = (rz1000_t *) priv; + + free(dev); + + next_id = 0; +} + +static void * +rz1000_init(const device_t *info) +{ + rz1000_t *dev = (rz1000_t *) calloc(1, sizeof(rz1000_t)); + + dev->id = next_id | 0x60; + + dev->pci = !!(info->flags & DEVICE_PCI); + dev->local = info->local; + + dev->channels = ((info->local & 0x60000) >> 17) & 0x03; + + device_add(&ide_pci_2ch_device); + + if (info->local & 0x80000) + pci_add_card(PCI_ADD_NORMAL, rz1000_pci_read, rz1000_pci_write, dev, &dev->pci_slot); + else + pci_add_card(PCI_ADD_IDE, rz1000_pci_read, rz1000_pci_write, dev, &dev->pci_slot); + + if (dev->channels & 0x01) + ide_board_set_force_ata3(0, 1); + + if (dev->channels & 0x02) + ide_board_set_force_ata3(1, 1); + + next_id++; + + rz1000_reset(dev); + + return dev; +} + +const device_t ide_rz1000_pci_device = { + .name = "PC Technology RZ-1000 PCI", + .internal_name = "ide_rz1000_pci", + .flags = DEVICE_PCI, + .local = 0x6000a, + .init = rz1000_init, + .close = rz1000_close, + .reset = rz1000_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t ide_rz1000_pci_single_channel_device = { + .name = "PC Technology RZ-1000 PCI", + .internal_name = "ide_rz1000_pci_single_channel", + .flags = DEVICE_PCI, + .local = 0x2000a, + .init = rz1000_init, + .close = rz1000_close, + .reset = rz1000_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/hdc.h b/src/include/86box/hdc.h index 71f83e5e6..0a5985370 100644 --- a/src/include/86box/hdc.h +++ b/src/include/86box/hdc.h @@ -60,6 +60,8 @@ extern const device_t ide_pci_device; /* pci_ide */ extern const device_t ide_pci_sec_device; /* pci_ide sec */ extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */ +extern const device_t ide_pci_ter_qua_2ch_device; /* pci_ide_ter_qua_2ch */ + extern const device_t ide_ali1489_device; /* ALi M1489 */ extern const device_t ide_ali5213_device; /* ALi M5213 */ @@ -76,10 +78,14 @@ extern const device_t ide_cmd640_pci_single_channel_sec_device; /* CMD PCI-640B extern const device_t ide_cmd646_device; /* CMD PCI-646 */ extern const device_t ide_cmd646_legacy_only_device; /* CMD PCI-646 (Legacy Mode Only) */ extern const device_t ide_cmd646_single_channel_device; /* CMD PCI-646 (Only primary channel) */ +extern const device_t ide_cmd646_ter_qua_device; /* CMD PCI-646 (Tertiary and quaternary channels) */ extern const device_t ide_opti611_vlb_device; /* OPTi 82c611/611A VLB */ extern const device_t ide_opti611_vlb_sec_device; /* OPTi 82c611/611A VLB (Secondary channel) */ +extern const device_t ide_rz1000_pci_device; /* PC Technology RZ-1000 PCI */ +extern const device_t ide_rz1000_pci_single_channel_device; /* PC Technology RZ-1000 PCI (Only primary channel) */ + extern const device_t ide_um8673f_device; /* UMC UM8673F */ extern const device_t ide_um8886af_device; /* UMC UM8886AF */ diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index c747d8cc0..92f88fbe6 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -58,7 +58,8 @@ machine_at_premiere_common_init(const machine_t *model, int pci_switch) pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_phoenix_device); device_add(&sio_zb_device); - device_add(&fdc37c665_device); + device_add(&ide_rz1000_pci_single_channel_device); + device_add(&fdc37c665_ide_sec_device); device_add(&intel_flash_bxt_ami_device); } diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 02922b425..0d748b85e 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -169,8 +169,8 @@ machine_at_tek932_init(const machine_t *model) device_add(&keyboard_ps2_intel_ami_pci_device); device_add(&i430nx_device); device_add(&sio_zb_device); - device_add(&fdc37c665_ide_device); device_add(&ide_vlb_device); + device_add(&fdc37c665_ide_pri_device); device_add(&intel_flash_bxt_ami_device); return ret; From fc3a6379b59e897cff7cde478ef79b5d83a552c7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:36:05 +0200 Subject: [PATCH 0847/1190] A small sanity check in the VISO code. --- src/cdrom/cdrom_image_viso.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index 4bf976794..cf132c560 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -782,9 +782,8 @@ viso_close(void *priv) if (viso->entry_map) free(viso->entry_map); - if (tf->log != NULL) { - - } + if (tf->log != NULL) + log_close(tf->log); free(viso); } @@ -1607,10 +1606,12 @@ end: return &viso->tf; } else { - image_viso_log(viso->tf.log, "Initialization failed\n"); - if (data) - free(data); - viso_close(&viso->tf); + if (viso != NULL) { + image_viso_log(viso->tf.log, "Initialization failed\n"); + if (data) + free(data); + viso_close(&viso->tf); + } return NULL; } } From c438073d689f8bce2071b9c2932f630be2cd9293 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:41:33 +0200 Subject: [PATCH 0848/1190] CD-ROM Image: Actually close image if ret = 0 also in case of a cue sheet, and also warn if ret = 0, closes #5552. --- src/cdrom/cdrom_image.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 519afaa4c..6bc284fd3 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -2016,6 +2016,10 @@ image_open(cdrom_t *dev, const char *path) img->has_audio = 0; else if (ret) img->has_audio = 1; + else { + image_close(img); + img = NULL; + } } else { ret = image_load_iso(img, path); @@ -2033,7 +2037,8 @@ image_open(cdrom_t *dev, const char *path) img->log = log_open(n); dev->ops = &image_ops; - } + } else + warning("Unable to load CD-ROM image: %s\n", path); } return img; From 813a19aad87988a79c5d623c81411c488e00ec7d Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 03:44:50 +0200 Subject: [PATCH 0849/1190] Acer V60N and V62X: limit to 384 MB. --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bb912cf9a..23409d6db 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14166,7 +14166,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 532480, + .max = 393216, .step = 8192 }, .nvrmask = 511, @@ -14617,7 +14617,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, .ram = { .min = 8192, - .max = 540672, + .max = 393216, .step = 8192 }, .nvrmask = 511, From eb82f9bcca6f01a31b7ebfca04620e0bc37e9fc9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 04:51:59 +0200 Subject: [PATCH 0850/1190] Added the TriGem Delhi III (AMI VIA MVP3 machine). --- src/acpi.c | 8 ++++++++ src/include/86box/machine.h | 1 + src/machine/m_at_sockets7.c | 32 +++++++++++++++++++++++++++++ src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/src/acpi.c b/src/acpi.c index ccd51ebca..e9549adb0 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -2387,6 +2387,14 @@ acpi_reset(void *priv) dev->regs.gpi_val = 0xfff57fc1; if (!strcmp(machine_get_internal_name(), "ficva503a") || !strcmp(machine_get_internal_name(), "6via90ap")) dev->regs.gpi_val |= 0x00000004; + /* + TriGem Delhi-III second GPI word: + - Bit 7 = Save CMOS (must be set); + - Bit 6 = Password jumper (must be set); + - Bit 5 = Enable Setup (must be set). + */ + else if (!strcmp(machine_get_internal_name(), "delhi3")) + dev->regs.gpi_val |= 0x00008000; } if (acpi_power_on) { diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index d62947848..fb979172c 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -782,6 +782,7 @@ extern int machine_at_ax59pro_init(const machine_t *); extern int machine_at_mvp3_init(const machine_t *); extern int machine_at_ficva503a_init(const machine_t *); extern int machine_at_5emapro_init(const machine_t *); +extern int machine_at_delhi3_init(const machine_t *); extern int machine_at_5sg100_init(const machine_t *); diff --git a/src/machine/m_at_sockets7.c b/src/machine/m_at_sockets7.c index 0360b5650..b7ffc03b3 100644 --- a/src/machine/m_at_sockets7.c +++ b/src/machine/m_at_sockets7.c @@ -343,6 +343,38 @@ machine_at_5emapro_init(const machine_t *model) return ret; } +int +machine_at_delhi3_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/delhi3/DELHI3.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + + device_add(&via_mvp3_device); + device_add(&via_vt82c596a_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&w83877tf_device); + device_add(&sst_flash_39sf020_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)) + device_add(machine_get_snd_device(machine)); + + return ret; +} + int machine_at_5sg100_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 23409d6db..bf4c7fa1b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14013,6 +14013,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has the VIA VT82C596A southbridge with on-chip KBC identical to the VIA + VT82C42N. */ + { + .name = "[VIA MVP3] TriGem Delhi-III", + .internal_name = "delhi3", + .type = MACHINE_TYPE_SOCKETS7, + .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, + .init = machine_at_delhi3_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 124242424, + .min_voltage = 2000, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 5.5 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_SOUND | MACHINE_USB, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = &cs4235_device, + .net_device = NULL + }, /* SiS 5591 */ /* Has the SiS 5591 chipset with on-chip KBC. */ From 0d8779da649c42a8ee899f202764e7c784d277a8 Mon Sep 17 00:00:00 2001 From: borisvolk117 <141923951+borisvolk117@users.noreply.github.com> Date: Tue, 6 May 2025 13:52:29 +0800 Subject: [PATCH 0851/1190] Delhi III bus change and update internal device note for Delhi III and NEC Mate NXMA30D --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bf4c7fa1b..ccffc4a03 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14035,7 +14035,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: ATI 3D Rage IIc AGP (Rage 2) */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_SOUND | MACHINE_USB, .ram = { .min = 8192, @@ -14860,7 +14860,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: SGS Thompson Riva 128 AGP and sound: OAK Audia 3D (OTI-610) */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { .min = 8192, From 5b959937e3211923eddac3ae5c9e7492daf2d7b0 Mon Sep 17 00:00:00 2001 From: borisvolk117 <141923951+borisvolk117@users.noreply.github.com> Date: Tue, 6 May 2025 14:32:14 +0800 Subject: [PATCH 0852/1190] Update machine_table.c --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ccffc4a03..e0a2cfc10 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14860,7 +14860,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: SGS Thompson Riva 128 AGP and sound: OAK Audia 3D (OTI-610) */ + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: SGS Thompson Riva 128 AGP, network: NEC PK-UG-X006 (Intel 82558B chip) sound: OAK Audia 3D (OTI-610) */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { .min = 8192, From 17211e4564b92b97a1d9cca28e7c21a8b0876d1a Mon Sep 17 00:00:00 2001 From: borisvolk117 <141923951+borisvolk117@users.noreply.github.com> Date: Tue, 6 May 2025 14:32:48 +0800 Subject: [PATCH 0853/1190] Update machine_table.c --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e0a2cfc10..032fd6483 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14860,7 +14860,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: SGS Thompson Riva 128 AGP, network: NEC PK-UG-X006 (Intel 82558B chip) sound: OAK Audia 3D (OTI-610) */ + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, /* Has internal video: SGS Thompson Riva 128 AGP, network: NEC PK-UG-X006 (Intel 82558B chip) and sound: OAK Audia 3D (OTI-610) */ .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { .min = 8192, From c84266d41adcf90ea11d05987d4a52acaae987f8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 08:43:39 +0200 Subject: [PATCH 0854/1190] VTech Laser TX: Fix RAM step, fixes #5554. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bf4c7fa1b..a636ca3ba 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -1734,7 +1734,7 @@ const machine_t machines[] = { .ram = { .min = 256, .max = 640, - .step = 256 + .step = 64 }, .nvrmask = 0, .kbc_device = &keyboard_xt_device, From 3d233fc4b44b9881df2b03f9289862a57707d3f3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 6 May 2025 13:06:44 +0600 Subject: [PATCH 0855/1190] Use icons for the indicators --- src/qt/icons/caps_lock_off.ico | Bin 0 -> 9622 bytes src/qt/icons/caps_lock_on.ico | Bin 0 -> 9622 bytes src/qt/icons/kana_lock_off.ico | Bin 0 -> 9622 bytes src/qt/icons/kana_lock_on.ico | Bin 0 -> 9622 bytes src/qt/icons/num_lock_off.ico | Bin 0 -> 9622 bytes src/qt/icons/num_lock_on.ico | Bin 0 -> 9622 bytes src/qt/icons/scroll_lock_off.ico | Bin 0 -> 9622 bytes src/qt/icons/scroll_lock_on.ico | Bin 0 -> 9622 bytes src/qt/qt_mainwindow.cpp | 37 ++++++++++++++++++++----------- src/qt/qt_mainwindow.hpp | 3 +++ src/qt_resources.qrc | 8 +++++++ 11 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 src/qt/icons/caps_lock_off.ico create mode 100644 src/qt/icons/caps_lock_on.ico create mode 100644 src/qt/icons/kana_lock_off.ico create mode 100644 src/qt/icons/kana_lock_on.ico create mode 100644 src/qt/icons/num_lock_off.ico create mode 100644 src/qt/icons/num_lock_on.ico create mode 100644 src/qt/icons/scroll_lock_off.ico create mode 100644 src/qt/icons/scroll_lock_on.ico diff --git a/src/qt/icons/caps_lock_off.ico b/src/qt/icons/caps_lock_off.ico new file mode 100644 index 0000000000000000000000000000000000000000..6895c735cf1d2d0cdc497f20bd810e9d2ef22892 GIT binary patch literal 9622 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 literal 0 HcmV?d00001 diff --git a/src/qt/icons/kana_lock_off.ico b/src/qt/icons/kana_lock_off.ico new file mode 100644 index 0000000000000000000000000000000000000000..27c9b88c25d39dde2f48fe5fbf5283fec9dd1541 GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5PkEXtBnQGEaS#Tv zK^VjaVGtXHap?!yRbOBK9|k~r(D@)W`1FJ1L4E<50n(3+k550ypCAmg7i0!98)P0X z{UE=AFh~yw!`y((#-|@72eS*L7afDl0ja@dKS&OQL1rL_0f-O6AUTlxaOns68-_t@ zL3%)Tg2X_4kX{f?jDCaQ^sJ^gHrB* z;*%1L91oyy1z~EL2Z}2@JG=iN3^EslL1u$!WDF7mVVD?*4a3Op1DOZHpmYes$Y~Q< z3?vRp^B@c|mymfNbs!9~4`dFA4Z|QY5Qg!IF%M)0$gQAq0Hhb>9*`I)UxLIy7$go7 zgSibvgTz4T6Qmc0L26(aB!;XPB#tfyG6#kUnFn$gx_)#%%q$R%%RG=dFbwk}NG(VV znGbR=$Q&33sX_NIESy1dFbwlEI-eNxKx$xa0GWdegUkl0g}DtxgT&C?2T}vVpl|}2 z3!*`0g4DwJAR43w^d+4B~?@D8GZk4unB=qK6+Syhyr zP+CLApm+dIZvjEzo%XH5EeM0e(cK9W2Vs~$ zKxTpTfy{+rkQhGmLF%!Y0rLYkIhffXni%szc7QOtJ7IR9`we6+4C68%zAiF?%V0@4m2!r?_vqAnQCjEoL6&-`jfSC`H1DOY+VHjjK2oqyIx?YeOAa@cn zAEb|1^FeBnF|zr{;^=Hb=7Zdd4TH=9g%K$HLGmCzh=yShAB4#@AK4rj8<_@~4Z@)M z17G?9g##rRWIoIfAitugPfE;&=>?e&!n86UWDm@IP-_L`2N1^Ah9XA{WEKd6%x+*{ zq((ajs~I4(LG3Wm7^MSJJFEdTa0#*;6Js?86wWlpG;OEB(mO61AYc4InXOvytUt?nGBZuKghYf^c139mr@f289E<`MBHwQU}81+7Hr8$bOJK z2xD_2NIwWuVn0YfF7sjWKuDg}_TzISNRCqbL1qy0BQAN6UTWA6G6y-G5lV+Jd5}I* z?Fab<8%9rKAT=QKK{N=X%Y)=Vm=ybAX$s_iY#5vg|AXdNu+Og|%Y*C&VN&b|sYecH zn0chqAh(0e0^y-%KPWCiVStQ5aSOt*Z~*xa#79%j4pc<9}>s!NLIK4p97q)WE_R#Kwh* zwI5_Yu^40*A+;biAUx3a!`k+Q+Ml2{C@nC^eh?lg`$2vJ*$;{bkQ+d02iE@r$<8h2vLED6nEjxxI4BH2n4B>Ma`b@g0%4Hd4WMOAAjSY-klg@Xm{xlL literal 0 HcmV?d00001 diff --git a/src/qt/icons/kana_lock_on.ico b/src/qt/icons/kana_lock_on.ico new file mode 100644 index 0000000000000000000000000000000000000000..ec171b52bdab0120f9dbd1f7b9fedc2ec7e9eceb GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pku419dAze?7y0hJ9$dVSa&`ip0mNAIbiPx`zKS0J5jPt{%n(yBp+J zkT}G01_lO@{Yd&jE@`NTm;qMzpW%N)1AI7#Jq7QQ#obwZhT@xirE?63Zb_IRL|;G>xlVf~g^u2AK&; z`)~(>(giFXA*E+fnkIx{c4L?aN{b*f(ai&;Pi$gPalGb%%tX=)%7dV^0=63}4ikfk zlVTpouQ2^6W+IiDq?!jd6G=aqk5uN8V;*w(3o;M63?|w* z=E1@ZtPuwRGMiZQK>h-m3C2j_1@b$n4g-mU)j;cZkl85d8I)E)7@96XYGD|p7vw~+ z9yEDU+=px)$V_UP2QwENjn#diavM}nfH260}S^68yMs%!XPt1W`XK02?hoR1EltG0w-0SOsZkvd<>0W zYOoRZQ&6vg(i}1d)k)N@=a9_@u|ak~!vW$4P&$L9ZM1R#Ti(Mb1~MOnG0X?$2ap}u z%m?KWY~mm>kQ@ku*r0YgiRB!qJOZUhuzR3pz}yd$LzV}*9fZN^A)$llKY;vzW(LSC zm^olQX!0;Qm>nRqK^Ux-Nb?EV0jdiIyZInLAiER9hhb1XMydNjX5lg)SsWDhAWT&F zgVG%uhPe}}A6|~Y#6f0*FjO8A!=U^HN;@D7O&`eV0;HE13^EgBHVA{*5W|uBw@BuL z!UJRn7}q!a2ZaGjAGfalKPcS6xUS(pNF7)YiTMkp2Zlj*fcyb=8`PgLIT#IcI|zf- zz&wB@d|>L4X^=@rG(;iBYd)wB zpajF*2FaH&ACTX!0;N4<3h=F(eE?`2d49@&lPYN%m9viZ2;0hb%8VL!-^ zxXcI1fiNyNQp-O@Sp(s42b6oGwP9{h+V~g#ic; zg#SVIlZvSs|D@UtQcuu+P#YN31_ZT1X@p^J0LK}m^$+PogX{)jko`2qAU6!8{opk% skop1^0+28O_5VSAAzEUP9UzRbc|cj9GV}lg19Jld10y{#$WD;m0BH0!vH$=8 literal 0 HcmV?d00001 diff --git a/src/qt/icons/num_lock_off.ico b/src/qt/icons/num_lock_off.ico new file mode 100644 index 0000000000000000000000000000000000000000..5b14da1d4c3490e38cbda89bc89a53fc493b890f GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pk**hC$*92?_r}7-T-k&FK0;axe^155gcdAQ~nP zqH*a5sYAvfH~s(r9~`d8;^gQD*$Xp+82uoB*VosBtOwgqjDClI zD+Z@UkiRL!DCG_)J}JQ`ss!$e57(K>E=!NI%G(AR2^0@*o<7$uSS4AA~{rK{N=1*dPqb z@A&c?$Zw=zka;jSg3LhGxKzczKWL5)% z{C@@peyU)QS)h7Lf`Ng-0I7YPzzMPmE2dVxg>DX2>oHh*gVD(G3W^sHhRIQbMm8T5 z_nE=7ZuDWIhNZ`vWA7jtS*2 zkQw+e$UKlgKs2&C5Fdo8VLr0CFgD0+5C+vB_{wLH|0%&B^I?7frD;(6f)ewv=>?e& z!n86UWGBpgP-_L`2N1^Ah9XA{WEKd6%x+*{L~pZDjSn&#)D8oUQ92;C!x}&XmmteA zG1cq_#SICVrtLIXddEeB+zE;gSiFPc9+z5Lh$Gt%aswz2fiTD&w7}?oK)0XPZXm{f zkQ+ed6*V!at_5LOn8MtF&Htp>4=ZDlX>9HW*$u*!+7B`VgwgE)`2&Pu;vh934CBLS zO6`Z4gG|@e)q$#IFowASo82Hi^spb7-PE=p7U$Uf53&mzrndh zWj+QZkBq79e~{Uu_Cw~PKyd)ef1q%|hKED=gVH<TI16y_j|>~E0WAWRSYL4E_-55nkfpqKr)+(1wJk=+1F z4KcFj$RmKKL`(${UCqB><4wlL16&G;?eIpy}KI literal 0 HcmV?d00001 diff --git a/src/qt/icons/num_lock_on.ico b/src/qt/icons/num_lock_on.ico new file mode 100644 index 0000000000000000000000000000000000000000..0dd08d7ae4594ca8f076a41145181800c344c140 GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pku419dAze?7y0hJAQ+gZzbLI#&HS>~E-V_zwbL`=DmfQ-6J3J;-`U zc# $lnYMWb1FJgZLd}0NMVBnnA99P^^O70it0TBm5~%KOp@FplJ}4j*u}ZU4Sr5 z48#UuNZ3NsABY5*0m7iPh!2C*fG|i86)-4n4lw`!-@r&32I&Fm1(h=*43P4M5nS3Z zFic>hg2RY60+O~N;Ykh~VH1hv5GWnNFsS^(RW8BQkV=Eh1gCqL3qk1umX4r#8J4CA z(J;F)%mbxGkeT?*1BES`JYMraW}>Nwxer@;2$CBt=3y%@2Zj4UalpXvzrG%`JSWF} zpfVAZe?jR1MuW_OVRGUFW+t`F1GxoeCdi#2J`9uNKDgex28`56iFq({k!h^vfy!-A zJpsa?JVGJ{nF$UDSb2bK9w-l!f?;+;(iO}^1_qFsAPg#NNWmaIAdE1Hsw_~NI>2E6 zzkxxXA`CJEWEQC2l3-w9FhFV_CvZ~L$)p-aPThr155j&5>NQZBL&l&wiQ4rXviTr3 z$PScr4oZixw2hH-k#ikkHpqMs#xNh0A3$~xYd$F7U{MP)8-%f%53&P`9&}gZsv|+_ zKxTvRU^X9D9XeFpKh(pYChiBNcM$&1@V}t}(ys%jLA3M?N}C`ImV=c*p!^F;`yh;_ z9+W0P7`dLu)y4sk z1r|Oa8srBM2IU1xFvtuL2AN3*3`)lb7?}SzFfdXTgUke(4Qhvh#wZ<-+F=c#flE60 zjZ7=>wYg{^hj1oRI}X%FqBW*f z=>fUt|NsBsFa_~J`am=Y6VhK_Uk}m>$1rz*^nx%U{UCqC%z)`7#ePcl!|aB60OSUc znIN}=Fd_GY)Q}T?AUlvT$Q>X)$UGPgV&k$Oqy`;>)WgI;Y!C*e9S{cj3zmLC?j;t3 z^nx(C`a$-<^n-FU$PFMYFE9U}7z|Pi!XUj3jG#119tPEeIT{iFi0=5IEW9zp!|+6zk&Qm3I>@6b0a8?!pbXB z%s^KQG7p5QWgf_Un0cVmALK?5CZL2(aCqaX~j2O9?2iA@|?45S8z z(ai_h0m@srFeo45k^_}RAPlmLRP#alK<0wn1EOJk5F3U;VjxVa`5-rgFsN(-m7nqKgiu6J}53h zcB5l*+z&DXly+g}gZQ}cU^5>S79dQ^@If~p6gJcfe~`OD7!>v}4B~_08Jj)igg?kU znAsp2m)RiuNHrf6HXsbM1E1N%m=7`w7Y5k@k^`9oqLDF341@`}A6XAJHpmQI;vhLt z{eiE12IV74FvxtEA3$LVYF|)d9yYxo^Ff$a=7a2nnGb5MfcyZ$*xFF!h=I%kVUXDk z42-JrN30n@ad221a_XplQW@d1l>P~78E zOAB#i`$291;_?K+YfR-2!regnGd4zVQSeA@;As{P@N3IAT~&hkQ*qqA7lpz*VWa5tVO}ZxPemp zL17E3%TX*w;(*)$QiCfTD77D--7sh1a|5OJgZu`{AE59DVPrc&e2^SS4K7Tn{h+vq zVUT^u_JhQ6*$We=)P9gTAbUU&_(?S?f}_|%?*^=4>A{@8}Qi; z(o3oR*y0}Me~{fEd2Id$*$u*!+7B`VWCsXiOMm$62I-}S{UCEd_Jc4eE28k2G z#M%!sj}#2D7oU2NJP6auetdR=H!o!t4ii#X(^J!sLu8kfR4=7YKvwZU8M~0x<>vgX{(Xr%WZ^ literal 0 HcmV?d00001 diff --git a/src/qt/icons/scroll_lock_on.ico b/src/qt/icons/scroll_lock_on.ico new file mode 100644 index 0000000000000000000000000000000000000000..33476406a5a559008e9628c0772333e9fd7b08e3 GIT binary patch literal 9622 zcmZQzU}Run5D);-3Je)63=D1z3=AS75dID}28MMk3=9$y5Pku419dAze?7y0hJ846gZzYMGFJUq>~E-R_zwbLyO7KvMn6n1NIwW8 zn?a0zkZOoo|VMU_-l2_%KKf2!r%c0fQ3A0p|bz8yHE$AUzqjvc|I?Eg0~$Ww$tW`N8B)mst_3=9TH?c)Sa8aSMI zBVlQoS~S9D3hFgbnnT8*I*Ho#9J2W!HpmW?bPh^~u(XX0IW z?EOKQ+d(wQ?I28!`)O_dPz`@jT7u zL3IEn80I!mJpl_J5DoGJ2!qOMN-)R_5C)k^2MkKj2N;D{}sMS6r)*OU0k=k*fHWIBdt=oB^e25Q&{D)EwfbtDAZ{pKOEjg_A zgUTSN8wizUQYS@p@Zjk*TjLQwwupgA3L2dxyy1F`$bzls# z6C?)0AT`)9wd{wPjokJG*$)%PMN`{;Sib-i0HgNf3U!3|a0~wdOMkF3AHDpAiQ_1T zsS*C5{0&O)_%N=#Kn?prsR^GOaM=yk2OZnSTK~i9UJ#8V{6J>FFg7>fvm2z3TK)%_ z1;WT~AY?aKJr(^AG7p47ZUA8rn-He9{|VWLEHV-HZRE{5DU|?=wU|^&t J2H6R+8vt4;^acO` literal 0 HcmV?d00001 diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index aee23b18d..905a100f4 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -187,16 +187,24 @@ MainWindow::MainWindow(QWidget *parent) ui->stackedWidget->setMouseTracking(true); statusBar()->setVisible(!hide_status_bar); + num_icon = QIcon(":/settings/qt/icons/num_lock_on.ico"); + num_icon_off = QIcon(":/settings/qt/icons/num_lock_off.ico"); + scroll_icon = QIcon(":/settings/qt/icons/scroll_lock_on.ico"); + scroll_icon_off = QIcon(":/settings/qt/icons/scroll_lock_off.ico"); + caps_icon = QIcon(":/settings/qt/icons/caps_lock_on.ico"); + caps_icon_off = QIcon(":/settings/qt/icons/caps_lock_off.ico"); + /* TODO: Add Kana indicator here after the keyboard type work is done. */ + num_label = new QLabel; - num_label->setText(" NUM "); + num_label->setPixmap(num_icon_off.pixmap(QSize(16, 16))); statusBar()->addPermanentWidget(num_label); caps_label = new QLabel; - caps_label->setText(" CAPS "); + caps_label->setPixmap(caps_icon_off.pixmap(QSize(16, 16))); statusBar()->addPermanentWidget(caps_label); scroll_label = new QLabel; - scroll_label->setText(" SCRL "); + scroll_label->setPixmap(scroll_icon_off.pixmap(QSize(16, 16))); statusBar()->addPermanentWidget(scroll_label); QTimer* ledKeyboardTimer = new QTimer(this); @@ -205,10 +213,13 @@ MainWindow::MainWindow(QWidget *parent) connect(ledKeyboardTimer, &QTimer::timeout, this, [this] () { uint8_t caps, num, scroll; keyboard_get_states(&caps, &num, &scroll); - - num_label->setStyleSheet(num ? "QLabel { background: green; }" : ""); - caps_label->setStyleSheet(caps ? "QLabel { background: green; }" : ""); - scroll_label->setStyleSheet(scroll ? "QLabel { background: green; }" : ""); + + if (num_label->isVisible()) + num_label->setPixmap(num ? this->num_icon.pixmap(QSize(16, 16)) : this->num_icon_off.pixmap(QSize(16, 16))); + if (caps_label->isVisible()) + caps_label->setPixmap(caps ? this->caps_icon.pixmap(QSize(16, 16)) : this->caps_icon_off.pixmap(QSize(16, 16))); + if (scroll_label->isVisible()) + scroll_label->setPixmap(scroll ? this->scroll_icon.pixmap(QSize(16, 16)) : this->scroll_icon_off.pixmap(QSize(16, 16))); }); ledKeyboardTimer->start(); @@ -239,9 +250,9 @@ MainWindow::MainWindow(QWidget *parent) connect(this, &MainWindow::hardResetCompleted, this, [this]() { ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); - num_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); - scroll_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); - caps_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); #ifdef USE_WACOM @@ -1485,9 +1496,9 @@ MainWindow::refreshMediaMenu() ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); - num_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); - scroll_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); - caps_label->setVisible(machine_has_bus(machine, MACHINE_AT) > 0); + num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); } void diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 2ba29c128..421b9ce15 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -191,6 +192,8 @@ private: friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. QLabel *caps_label, *scroll_label, *num_label; + QIcon caps_icon, scroll_icon, num_icon; + QIcon caps_icon_off, scroll_icon_off, num_icon_off; bool isShowMessage = false; }; diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index bc553ac61..a5963c152 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -34,6 +34,14 @@ qt/icons/86Box-green.ico qt/icons/86Box-red.ico qt/icons/86Box-yellow.ico + qt/icons/caps_lock_off.ico + qt/icons/caps_lock_on.ico + qt/icons/kana_lock_off.ico + qt/icons/kana_lock_on.ico + qt/icons/num_lock_off.ico + qt/icons/num_lock_on.ico + qt/icons/scroll_lock_off.ico + qt/icons/scroll_lock_on.ico qt/icons/acpi_shutdown.ico From 8508a048256944da709d68f83edc75fadffcf5e2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:06:30 +0200 Subject: [PATCH 0856/1190] CL-GD 54xx: Remove an excess logging line. --- src/video/vid_cl54xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 4988b3797..43c4e22b2 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4141,8 +4141,6 @@ gd54xx_reset(void *priv) gd54xx_t *gd54xx = (gd54xx_t *) priv; svga_t *svga = &gd54xx->svga; - pclog("gd54xx_reset()\n"); - memset(svga->crtc, 0x00, sizeof(svga->crtc)); memset(svga->seqregs, 0x00, sizeof(svga->seqregs)); memset(svga->gdcreg, 0x00, sizeof(svga->gdcreg)); From 0c97a1f7f6060aa547cd3070b2ec17fd615b8e91 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:08:16 +0200 Subject: [PATCH 0857/1190] Acer V60N and V62X: Tell the DRB filler the slot limits to avoid unsupported DRAM row combinations, fixes black screen on PCI graphics cards on some RAM sizes. --- src/machine/m_at_slot1.c | 1 + src/machine/m_at_socket8.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index bd3a4833f..b2f05d33e 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -65,6 +65,7 @@ machine_at_acerv62x_init(const machine_t *model) device_add(&piix3_device); device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_APM)); device_add(&sst_flash_29ee020_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 128); return ret; } diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 479c4b9fc..f604c4f01 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -190,6 +190,7 @@ machine_at_acerv60n_init(const machine_t *model) device_add(&piix3_device); device_add_params(&fdc37c93x_device, (void *) (FDC37C935 | FDC37C93X_NORMAL)); device_add(&sst_flash_29ee010_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 128); return ret; } From 3b149759ae2cec3df911622783ebca002f86b1e1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:14:56 +0200 Subject: [PATCH 0858/1190] LG IBM x61: Remove some left-over commented out lines. --- src/machine/m_at_socket8.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index f604c4f01..006e0f419 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -217,9 +217,7 @@ machine_at_lgibmx61_init(const machine_t *model) pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&i440fx_device); device_add(&piix3_device); - // device_add(&keyboard_ps2_ami_pci_device); device_add(&keyboard_ps2_ami_device); - // device_add(&w83787f_device); device_add(&w83877f_president_device); device_add(&sst_flash_29ee010_device); From ef3f57b338e58e2443e2dedf4fc06e85f4937955 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:26:26 +0200 Subject: [PATCH 0859/1190] S3 Trio32 On-Board VLB: Actually use the DEC Venturis 4xx video BIOS. --- src/video/vid_s3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index d6b91903a..595ec3a17 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -58,6 +58,7 @@ #define ROM_PHOENIX_VISION864 "roms/video/s3/86c864p.bin" #define ROM_DIAMOND_STEALTH64_964 "roms/video/s3/964_107h.rom" #define ROM_PHOENIX_TRIO32 "roms/video/s3/86c732p.bin" +#define ROM_PHOENIX_TRIO32_ONBOARD_VLB "roms/machines/dvent/Venturis466_VIDEO.BIN" #define ROM_SPEA_MIRAGE_P64 "roms/video/s3/S3_764VL_SPEAMirageP64VL_ver5_03.BIN" #define ROM_NUMBER9_9FX "roms/video/s3/s3_764.bin" #define ROM_PHOENIX_TRIO64 "roms/video/s3/86c764x1.bin" @@ -9946,7 +9947,7 @@ s3_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_vlb); break; case S3_PHOENIX_TRIO32_ONBOARD: - bios_fn = NULL; + bios_fn = ROM_PHOENIX_TRIO32_ONBOARD_VLB; chip = S3_TRIO32; if (info->flags & DEVICE_PCI) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_pci); From 93025cc1156f7cb5c7d9121a15003e45aab28e13 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:29:30 +0200 Subject: [PATCH 0860/1190] SM(S)C FDC 37c6xx: Return 0xFF on out of bound register read, fixes segmentation fault on the DEC Venturis 4xx. --- src/sio/sio_fdc37c6xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index 0f3460565..3afd92e4c 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -232,7 +232,7 @@ fdc37c6xx_read(uint16_t port, void *priv) uint8_t ret = 0xff; if (dev->tries == 2) { - if (port == 0x3f1) + if ((port == 0x3f1) && (dev->cur_reg <= dev->max_reg)) ret = dev->regs[dev->cur_reg]; } From 4a417da09bc5bdc80e463da3750a71261d560575 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:34:14 +0200 Subject: [PATCH 0861/1190] S3: Revert the video BIOS change, it was not necessary. --- src/video/vid_s3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 595ec3a17..d6b91903a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -58,7 +58,6 @@ #define ROM_PHOENIX_VISION864 "roms/video/s3/86c864p.bin" #define ROM_DIAMOND_STEALTH64_964 "roms/video/s3/964_107h.rom" #define ROM_PHOENIX_TRIO32 "roms/video/s3/86c732p.bin" -#define ROM_PHOENIX_TRIO32_ONBOARD_VLB "roms/machines/dvent/Venturis466_VIDEO.BIN" #define ROM_SPEA_MIRAGE_P64 "roms/video/s3/S3_764VL_SPEAMirageP64VL_ver5_03.BIN" #define ROM_NUMBER9_9FX "roms/video/s3/s3_764.bin" #define ROM_PHOENIX_TRIO64 "roms/video/s3/86c764x1.bin" @@ -9947,7 +9946,7 @@ s3_init(const device_t *info) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_vlb); break; case S3_PHOENIX_TRIO32_ONBOARD: - bios_fn = ROM_PHOENIX_TRIO32_ONBOARD_VLB; + bios_fn = NULL; chip = S3_TRIO32; if (info->flags & DEVICE_PCI) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_trio32_pci); From d27bd54bfae36b17a843189fed6ce9601e053e2d Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:48:50 +0200 Subject: [PATCH 0862/1190] SiS 85c4xx: Gate two 471-specific changes in a 471 check, fixes the SiS 461 DECpc machine. --- src/chipset/sis_85c4xx.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index 1c1e0614b..f715c5272 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -595,12 +595,14 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) switch (rel_reg) { case 0x00: - if (val & 0x01) { - kbc_at_set_fast_reset(0); - cpu_cpurst_on_sr = 1; - } else { - kbc_at_set_fast_reset(1); - cpu_cpurst_on_sr = 0; + if (dev->is_471) { + if (val & 0x01) { + kbc_at_set_fast_reset(0); + cpu_cpurst_on_sr = 1; + } else { + kbc_at_set_fast_reset(1); + cpu_cpurst_on_sr = 0; + } } break; @@ -614,7 +616,7 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) case 0x08: if (valxor) sis_85c4xx_recalcmapping(dev); - if (rel_reg == 0x08) + if ((rel_reg == 0x08) && dev->is_471) flushmmucache(); break; From bb7454120a71295a49d5b6298f35261946444441 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 6 May 2025 19:58:43 +0200 Subject: [PATCH 0863/1190] TriGem Delhi-III: Rename to eMachines eTower 3xxc. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 6223f1eb7..47320e6fe 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14016,7 +14016,7 @@ const machine_t machines[] = { /* Has the VIA VT82C596A southbridge with on-chip KBC identical to the VIA VT82C42N. */ { - .name = "[VIA MVP3] TriGem Delhi-III", + .name = "[VIA MVP3] eMachines eTower 3xxc", .internal_name = "delhi3", .type = MACHINE_TYPE_SOCKETS7, .chipset = MACHINE_CHIPSET_VIA_APOLLO_MVP3, From 1b1d6bcf458f8629937ac065abe0a0b8f107be4d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 6 May 2025 20:17:23 +0200 Subject: [PATCH 0864/1190] Some cleanup to the recent fixes on the S3 code (May 6th, 2025) See above. --- src/video/vid_s3.c | 114 ++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index d6b91903a..6897aed60 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -288,9 +288,11 @@ typedef struct s3_t { int color_16bit_check; int color_16bit_check_pixtrans; int16_t minus; + int16_t minus_src_24bpp; int rd_mask_16bit_check; int start; int mix_dat_upper; + int overflow; /*For non-threaded FIFO*/ int setup_fifo_slot; @@ -661,13 +663,15 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) s3->accel_start(16, 1, val | (val << 16), 0, s3); } else { - if ((s3->accel.cmd == 0x53f1) || (s3->accel.cmd == 0x53b1)) { - if (s3->accel.cur_x & 0x400) + if (s3->accel.rd_mask_16bit_check) { + if ((s3->accel.cmd == 0x53f1) || (s3->accel.cmd == 0x53b1)) { + if (s3->accel.cur_x & 0x400) + val = (val >> 8) | (val << 8); + + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + val = (val >> 8) | (val << 8); - - s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - - val = (val >> 8) | (val << 8); + } } s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } @@ -803,6 +807,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x82e9: s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x0f) << 8); s3->accel.poly_cy = s3->accel.cur_y; + s3_log("[%04X:%08X] OUT PORTB=%04x, valy=%d.\n", CS, cpu_state.pc, port - 1, s3->accel.cur_y); break; case 0x814a: case 0x82ea: @@ -828,7 +833,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.cur_x_overflow = (s3->accel.cur_x_overflow & 0xff) | (val << 8); s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; - s3_log("[%04X:%08X] OUT PORTB=%04x, val=%04x.\n", CS, cpu_state.pc, port - 1, s3->accel.cur_x); + s3_log("[%04X:%08X] OUT PORTB=%04x, valx=%d, valxover=%d.\n", CS, cpu_state.pc, port - 1, s3->accel.cur_x, s3->accel.cur_x_overflow); break; case 0x854a: case 0x86ea: @@ -921,6 +926,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x9459: case 0x96e9: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + s3_log("[%04X:%08X] OUT PORTB=%04x, valmajx=%d.\n", CS, cpu_state.pc, port - 1, s3->accel.maj_axis_pcnt); break; case 0x954a: case 0x96ea: @@ -2965,7 +2971,7 @@ s3_out(uint16_t addr, uint8_t val, void *priv) break; case 0x40: - s3->enable_8514 = (val & 0x01); + s3->enable_8514 = val & 0x01; break; case 0x50: @@ -5798,18 +5804,20 @@ s3_accel_in_w(uint16_t port, void *priv) s3->accel_start(8, 1, temp | (temp << 16), 0, s3); } else { if ((s3->bpp == 0) && s3->color_16bit) { - if (s3->accel.cur_x & 0x400) - temp = ((temp >> 8) | (temp << 8)) & 0xffff; - + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) + temp = (temp >> 8) | (temp << 8); + } s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } else s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); } } else { if ((s3->bpp == 0) && s3->color_16bit) { - if (s3->accel.cur_x & 0x400) - temp = ((temp >> 8) | (temp << 8)) & 0xffff; - + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.cur_x & 0x400) + temp = (temp >> 8) | (temp << 8); + } s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } else s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); @@ -8021,18 +8029,30 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi case 1: /*Draw line*/ if (!cpu_input) { + s3->accel.rd_mask_16bit_check = 0; s3->accel.minus = 0; s3->accel.color_16bit_check_pixtrans = 0; s3->accel.cx = s3->accel.cur_x & 0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; - s3->accel.sy = s3->accel.maj_axis_pcnt; - if ((s3->bpp == 0) && s3->color_16bit) - s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); - else - s3->accel.rd_mask_16bit_check = 0; - if ((s3->bpp == 0) && s3->color_16bit && (s3->accel.cur_x & 0x400) && s3->accel.rd_mask_16bit_check) - s3->accel.minus = 0x400; + s3->accel.sy = s3->accel.maj_axis_pcnt; + if ((s3->bpp == 0) && s3->color_16bit) { + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + if (s3->accel.rd_mask_16bit_check) { + if ((s3->accel.cur_x_overflow & 0xc00) == 0xc00) + s3->accel.start = 1; + else { + if (s3->accel.start) { + s3->accel.start = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.start = 0; + if (s3->accel.cur_x_overflow & 0x400) + s3->accel.minus = 0x400; + } + } + } + } if (s3_cpu_src(s3)) return; /*Wait for data from CPU*/ @@ -8041,7 +8061,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if (s3->accel.cmd & 0x08) { /*Radial*/ if ((s3->bpp == 0) && s3->color_16bit) { if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cur_x & 0x400) { + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); @@ -8108,11 +8128,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi cpu_dat >>= 16; if (!s3->accel.sy) { - if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.cur_x & 0x400)) - s3->accel.color_16bit_check = 1; - else + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) s3->accel.color_16bit_check = 0; + else + s3->accel.color_16bit_check = 1; } break; } @@ -8162,7 +8182,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.temp_cnt = 16; if ((s3->bpp == 0) && s3->color_16bit) { if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cur_x & 0x400) { + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); @@ -8178,7 +8198,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } else { if ((s3->bpp == 0) && s3->color_16bit) { if (s3->accel.rd_mask_16bit_check) { - if (s3->accel.cur_x & 0x400) { + if (s3->accel.minus) { wrt_mask = (s3->accel.wrt_mask_actual[1] << 8); frgd_color = (s3->accel.frgd_color_actual[1] << 8); bkgd_color = (s3->accel.bkgd_color_actual[1] << 8); @@ -8193,12 +8213,18 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } - while (count-- && s3->accel.sy >= 0) { + if (!s3->accel.b2e8_pix) + s3_log("CMDFULL=%04x, FRGDMIX=%x, FRGDCOLR=%04x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, CLIPT=%d, CLIPB=%d.\n", s3->accel.cmd, frgd_mix, s3->accel.frgd_color, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, clip_t, clip_b); + + while (count-- && (s3->accel.sy >= 0)) { if (s3->accel.b2e8_pix && s3_cpu_src(s3) && !s3->accel.temp_cnt) { mix_dat >>= 16; s3->accel.temp_cnt = 16; } + if (s3->accel.minus) + s3_log("Total pixel cx=%d, cy=%d.\n", s3->accel.cx - s3->accel.minus, s3->accel.cy); + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: @@ -8260,11 +8286,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi cpu_dat >>= 16; if (!s3->accel.sy) { - if ((s3->bpp == 0) && s3->color_16bit) { - if (!(s3->accel.cur_x & 0x400)) - s3->accel.color_16bit_check = 1; - else + if (s3->accel.rd_mask_16bit_check) { + if (s3->accel.minus) s3->accel.color_16bit_check = 0; + else + s3->accel.color_16bit_check = 1; } break; } @@ -8358,7 +8384,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } else { if (s3->accel.cmd & 0x100) { - if (!(s3->accel.cmd & 0x200)) { + if (mix_mask == 0x80) { if (s3->accel.cur_x & 0x400) s3->accel.minus = 0x400; else @@ -8458,8 +8484,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } - if (s3->accel.mix_dat_upper) - s3_log("CMDFULL=%04x, FRGDMIX=%x, BKGDCOLR=%04x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, OVERFLOW=%d.\n", s3->accel.cmd, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_color, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, (s3->accel.cur_x_overflow & 0xc00) == 0xc00); + s3_log("CMDFULL=%04x, FRGDSEL=%x, BKGDSEL=%x, FRGDMIX=%02x, BKGDMIX=%02x, MASKCHECK=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d, pitch=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_mix & 0x0f, s3->accel.rd_mask_16bit_check, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00, s3->width); while (count-- && (s3->accel.sy >= 0)) { if (s3->accel.b2e8_pix && s3_cpu_src(s3) && !s3->accel.temp_cnt) { @@ -8716,16 +8741,20 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi case 6: /*BitBlt*/ if (!cpu_input) { /*!cpu_input is trigger to start operation*/ s3->accel.minus = 0; + s3->accel.minus_src_24bpp = 0; s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; s3->accel.sy = s3->accel.multifunc[0] & 0xfff; s3->accel.dx = s3->accel.destx_distp & 0xfff; s3->accel.dy = s3->accel.desty_axstp & 0xfff; + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if ((s3->bpp == 0) && s3->color_16bit) { s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); if (s3->accel.rd_mask_16bit_check) { - if (!(s3->accel.cmd & 0x40) && !(clip_r & 0x400)) + if (!(clip_r & 0x400)) s3->accel.start = 1; else { if (s3->accel.start) { @@ -8745,10 +8774,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } else { s3_log("BitBLT + 0 FULLCMD=%04x: frgdcolor=%04x, s=%d,%d, d=%d,%d, frmix=%x, bkmix=%x, pixcntl=%02x.\n", s3->accel.cmd, frgd_color, s3->accel.sx, s3->accel.sy, s3->accel.dx, s3->accel.dy, frgd_mix, bkgd_mix, s3->accel.multifunc[0xa] & 0xc0); } - - s3->accel.cx = s3->accel.cur_x & 0xfff; - s3->accel.cy = s3->accel.cur_y & 0xfff; - s3->accel.src = srcbase + s3->accel.cy * s3->width; s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3_log("BitBLT: D(%d,%d).\n", s3->accel.dx, s3->accel.dy); @@ -8773,10 +8798,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi break; } - if (!vram_mask && (frgd_mix == 3)) - s3_log("CMDFULL=%04x, FRGDMIX=%x, BKGDMIX=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00); + s3_log("CMDFULL=%04x, FRGDSEL=%x, BKGDSEL=%x, FRGDMIX=%02x, BKGDMIX=%02x, MASKCHECK=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d, pitch=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_mix & 0x0f, s3->accel.rd_mask_16bit_check, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00, s3->width); if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { + s3_log("Special BitBLT.\n"); + while (1) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { READ(s3->accel.src + s3->accel.cx - s3->accel.minus, src_dat); @@ -8820,6 +8846,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } } else { + s3_log("Normal blit.\n"); while (count-- && (s3->accel.sy >= 0)) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { if (vram_mask && (s3->accel.cmd & 0x10)) { @@ -8912,6 +8939,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.cy--; s3->accel.dy--; } + s3->accel.src = srcbase + s3->accel.cy * s3->width; s3->accel.dest = dstbase + s3->accel.dy * s3->width; From 477956d74328c7ff16a2aafe41e8ad825806bc8b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 01:08:02 +0200 Subject: [PATCH 0865/1190] QT: Rework light/dark mode switches, fixes #5560. --- src/qt/qt_winrawinputfilter.cpp | 54 ++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index 306da575f..e94101a77 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -64,6 +64,8 @@ extern void win_keyboard_handle(uint32_t scancode, int up, int e0, int e1); #include "qt_rendererstack.hpp" #include "ui_qt_mainwindow.h" +static bool NewDarkMode = FALSE; + bool windows_is_light_theme() { // based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application @@ -220,6 +222,14 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess if ((((void *) msg->lParam) != nullptr) && (wcscmp(L"ImmersiveColorSet", (wchar_t*)msg->lParam) == 0)) { + bool OldDarkMode = NewDarkMode; +#if 0 + if (do_auto_pause && !dopause) { + auto_paused = 1; + plat_pause(1); + } +#endif + if (!windows_is_light_theme()) { QFile f(":qdarkstyle/dark/darkstyle.qss"); @@ -228,45 +238,39 @@ WindowsRawInputFilter::nativeEventFilter(const QByteArray &eventType, void *mess else { f.open(QFile::ReadOnly | QFile::Text); QTextStream ts(&f); - qApp->setStyleSheet(ts.readAll()); + qApp->setStyleSheet(ts.readAll()); } - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = TRUE; - auto vid_stack = (RendererStack::Renderer) vid_api; - DwmSetWindowAttribute((HWND) window->winId(), - DWMWA_USE_IMMERSIVE_DARK_MODE, - (LPCVOID) &DarkMode, - sizeof(DarkMode)); - window->ui->stackedWidget->switchRenderer(vid_stack); - for (int i = 1; i < MONITORS_NUM; i++) { - if ((window->renderers[i] != nullptr) && - !window->renderers[i]->isHidden()) - window->renderers[i]->switchRenderer(vid_stack); - } - }); + NewDarkMode = TRUE; } else { qApp->setStyleSheet(""); - QTimer::singleShot(1000, [this] () { - BOOL DarkMode = FALSE; - DwmSetWindowAttribute((HWND) window->winId(), - DWMWA_USE_IMMERSIVE_DARK_MODE, - (LPCVOID) &DarkMode, - sizeof(DarkMode)); - }); + NewDarkMode = FALSE; } - QTimer::singleShot(1000, [this] () { + if (NewDarkMode != OldDarkMode) QTimer::singleShot(1000, [this] () { + BOOL DarkMode = NewDarkMode; + DwmSetWindowAttribute((HWND) window->winId(), + DWMWA_USE_IMMERSIVE_DARK_MODE, + (LPCVOID) &DarkMode, + sizeof(DarkMode)); + window->resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { auto mon = &(monitors[i]); if ((window->renderers[i] != nullptr) && !window->renderers[i]->isHidden()) window->resizeContentsMonitor(mon->mon_scrnsz_x, - mon->mon_scrnsz_y, - i); + mon->mon_scrnsz_y, i); } + +#if 0 + if (auto_paused) { + plat_pause(0); + auto_paused = 0; + } +#endif }); } break; From a48f9bc7ba2410376a6bc4afc16675e14ce98bc2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 01:54:34 +0200 Subject: [PATCH 0866/1190] Implement the Kana lock LED for AX machines. --- src/device/keyboard.c | 11 ++++++++--- src/device/keyboard_at.c | 10 +++++----- src/device/keyboard_xt.c | 2 +- src/include/86box/keyboard.h | 4 ++-- src/include/86box/machine.h | 2 +- src/machine/machine_table.c | 2 +- src/qt/qt_mainwindow.cpp | 23 +++++++++++++++++++---- src/qt/qt_mainwindow.hpp | 6 +++--- 8 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 30b6f53a8..800e7fb8e 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -67,6 +67,7 @@ static scancode *scan_table; /* scancode table for keyboard */ static volatile uint8_t caps_lock = 0; static volatile uint8_t num_lock = 0; static volatile uint8_t scroll_lock = 0; +static volatile uint8_t kana_lock = 0; static uint8_t shift = 0; static int key5576mode = 0; @@ -108,6 +109,7 @@ keyboard_init(void) num_lock = 0; caps_lock = 0; scroll_lock = 0; + kana_lock = 0; shift = 0; memset(recv_key, 0x00, sizeof(recv_key)); @@ -370,11 +372,12 @@ keyboard_do_break(uint16_t scan) Caps Lock, Num Lock, and Scroll Lock when receving the "Set keyboard LEDs" command. */ void -keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl) +keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl, uint8_t kl) { caps_lock = cl; num_lock = nl; scroll_lock = sl; + kana_lock = kl; } uint8_t @@ -384,7 +387,7 @@ keyboard_get_shift(void) } void -keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl) +keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl, uint8_t *kl) { if (cl) *cl = caps_lock; @@ -392,6 +395,8 @@ keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl) *nl = num_lock; if (sl) *sl = scroll_lock; + if (kl) + *kl = kana_lock; } /* Called by the UI to update the states of Caps Lock, Num Lock, and Scroll Lock. */ @@ -435,7 +440,7 @@ keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl) } } - keyboard_update_states(cl, nl, sl); + keyboard_update_states(cl, nl, sl, kana_lock); } int diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 605f51e90..fbf167e3f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -3276,7 +3276,7 @@ add_data_kbd(uint16_t val) dev->ignore = 1; - keyboard_get_states(NULL, &num_lock, NULL); + keyboard_get_states(NULL, &num_lock, NULL, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; switch (val) { @@ -3476,7 +3476,7 @@ keyboard_at_bat(void *priv) keyboard_scan = 1; - keyboard_update_states(0, 0, 0); + keyboard_update_states(0, 0, 0, 0); kbc_at_dev_queue_add(dev, 0xaa, 0); } else { bat_counter--; @@ -3511,7 +3511,7 @@ keyboard_at_write(void *priv) switch (dev->command) { case 0xed: /* Set/reset LEDs */ kbc_at_dev_queue_add(dev, 0xfa, 0); - keyboard_update_states(!!(val & 0x4), !!(val & 0x2), val & 0x1); + keyboard_update_states(!!(val & 0x4), !!(val & 0x2), val & 0x1, !!(val & 0x8)); keyboard_at_log("%s: Set/reset LEDs [%02X]\n", dev->name, val); break; @@ -3769,7 +3769,7 @@ keyboard_at_init(const device_t *info) keyboard_send = add_data_kbd; SavedKbd = dev; - keyboard_update_states(0, 0, 0); + keyboard_update_states(0, 0, 0, 0); inv_cmd_response = (dev->type & FLAG_PS2) ? 0xfe : 0xfa; @@ -3788,7 +3788,7 @@ keyboard_at_close(void *priv) /* Disable the scancode maps. */ keyboard_set_table(NULL); - keyboard_update_states(0, 0, 0); + keyboard_update_states(0, 0, 0, 0); SavedKbd = NULL; diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index bafc80d88..7e419b39d 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -742,7 +742,7 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) if (!adddata) return; - keyboard_get_states(NULL, &num_lock, NULL); + keyboard_get_states(NULL, &num_lock, NULL, NULL); shift_states = keyboard_get_shift() & STATE_LSHIFT; if (is_amstrad) diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 024b16169..f62896106 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -271,9 +271,9 @@ extern void keyboard_process(void); extern uint16_t keyboard_convert(int ch); extern void keyboard_input(int down, uint16_t scan); extern void keyboard_all_up(void); -extern void keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl); +extern void keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl, uint8_t kl); extern uint8_t keyboard_get_shift(void); -extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl); +extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl, uint8_t *kl); extern void keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl); extern int keyboard_recv(uint16_t key); extern int keyboard_recv_ui(uint16_t key); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index fb979172c..d8c213d53 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -101,7 +101,7 @@ #define MACHINE_GAMEPORT 0x00008000 /* sys has int game port */ #define MACHINE_SOUND 0x00010000 /* sys has int sound */ #define MACHINE_NIC 0x00020000 /* sys has int NIC */ -#define MACHINE_MODEM 0x00040000 /* sys has int modem */ +#define MACHINE_AX 0x00040000 /* sys adheres to Japanese AX standard */ /* Feature flags for advanced devices. */ #define MACHINE_APM 0x00080000 /* sys has APM */ #define MACHINE_ACPI 0x00100000 /* sys has ACPI */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 47320e6fe..7e0ae8d64 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4804,7 +4804,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_AT, - .flags = MACHINE_VIDEO_FIXED, + .flags = MACHINE_VIDEO_FIXED | MACHINE_AX, .ram = { .min = 1024, .max = 4096, diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 905a100f4..e966e043a 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -193,7 +193,8 @@ MainWindow::MainWindow(QWidget *parent) scroll_icon_off = QIcon(":/settings/qt/icons/scroll_lock_off.ico"); caps_icon = QIcon(":/settings/qt/icons/caps_lock_on.ico"); caps_icon_off = QIcon(":/settings/qt/icons/caps_lock_off.ico"); - /* TODO: Add Kana indicator here after the keyboard type work is done. */ + kana_icon = QIcon(":/settings/qt/icons/kana_lock_on.ico"); + kana_icon_off = QIcon(":/settings/qt/icons/kana_lock_off.ico"); num_label = new QLabel; num_label->setPixmap(num_icon_off.pixmap(QSize(16, 16))); @@ -207,19 +208,28 @@ MainWindow::MainWindow(QWidget *parent) scroll_label->setPixmap(scroll_icon_off.pixmap(QSize(16, 16))); statusBar()->addPermanentWidget(scroll_label); + kana_label = new QLabel; + kana_label->setPixmap(kana_icon_off.pixmap(QSize(16, 16))); + statusBar()->addPermanentWidget(kana_label); + QTimer* ledKeyboardTimer = new QTimer(this); ledKeyboardTimer->setTimerType(Qt::CoarseTimer); ledKeyboardTimer->setInterval(1); connect(ledKeyboardTimer, &QTimer::timeout, this, [this] () { - uint8_t caps, num, scroll; - keyboard_get_states(&caps, &num, &scroll); + uint8_t caps, num, scroll, kana; + keyboard_get_states(&caps, &num, &scroll, &kana); if (num_label->isVisible()) num_label->setPixmap(num ? this->num_icon.pixmap(QSize(16, 16)) : this->num_icon_off.pixmap(QSize(16, 16))); if (caps_label->isVisible()) caps_label->setPixmap(caps ? this->caps_icon.pixmap(QSize(16, 16)) : this->caps_icon_off.pixmap(QSize(16, 16))); if (scroll_label->isVisible()) - scroll_label->setPixmap(scroll ? this->scroll_icon.pixmap(QSize(16, 16)) : this->scroll_icon_off.pixmap(QSize(16, 16))); + scroll_label->setPixmap(scroll ? this->scroll_icon.pixmap(QSize(16, 16)) : + this->scroll_icon_off.pixmap(QSize(16, 16))); + + if (kana_label->isVisible()) + kana_label->setPixmap(kana ? this->kana_icon.pixmap(QSize(16, 16)) : + this->kana_icon_off.pixmap(QSize(16, 16))); }); ledKeyboardTimer->start(); @@ -253,6 +263,9 @@ MainWindow::MainWindow(QWidget *parent) num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + /* TODO: Base this on keyboard type instead when that's done. */ + kana_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD) && + machine_has_flags(machine, MACHINE_AX)); while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); #ifdef USE_WACOM @@ -1499,6 +1512,8 @@ MainWindow::refreshMediaMenu() num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + kana_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD) && + machine_has_flags(machine, MACHINE_AX)); } void diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 421b9ce15..917fd43f5 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -191,9 +191,9 @@ private: friend class RendererStack; // For UI variable access by non-primary renderer windows. friend class WindowsRawInputFilter; // Needed to reload renderers on style sheet changes. - QLabel *caps_label, *scroll_label, *num_label; - QIcon caps_icon, scroll_icon, num_icon; - QIcon caps_icon_off, scroll_icon_off, num_icon_off; + QLabel *caps_label, *scroll_label, *num_label, *kana_label; + QIcon caps_icon, scroll_icon, num_icon, kana_icon; + QIcon caps_icon_off, scroll_icon_off, num_icon_off, kana_icon_off; bool isShowMessage = false; }; From 6fb01cf592ec78fac1924d69b8a239c6b9d8875b Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 7 May 2025 10:11:51 +0700 Subject: [PATCH 0867/1190] Added ISA-specific 86c805 (ELSA Winner 1000) Ported from my ELSA_Winner_Series branch. --- src/include/86box/video.h | 1 + src/video/vid_s3.c | 33 ++++++++++++++++++++++++++++++++- src/video/vid_table.c | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/include/86box/video.h b/src/include/86box/video.h index d55275359..1b50d86f8 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -488,6 +488,7 @@ extern const device_t s3_metheus_86c928_isa_device; extern const device_t s3_metheus_86c928_vlb_device; extern const device_t s3_spea_mercury_lite_86c928_pci_device; extern const device_t s3_spea_mirage_86c801_isa_device; +extern const device_t s3_winner1000_805_isa_device; extern const device_t s3_86c805_onboard_vlb_device; extern const device_t s3_spea_mirage_86c805_vlb_device; extern const device_t s3_mirocrystal_8s_805_vlb_device; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 6897aed60..1f1ab5ede 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -54,6 +54,7 @@ #define ROM_MIROCRYSTAL20SV_964_PCI "roms/video/s3/mirocrystal.VBI" #define ROM_MIROCRYSTAL20SD_864_VLB "roms/video/s3/Miro20SD.BIN" #define ROM_PHOENIX_86C80X "roms/video/s3/805.VBI" +#define ROM_WINNER1000_805 "roms/video/s3/v01_05_00-C.BIN.bin" #define ROM_PARADISE_BAHAMAS64 "roms/video/s3/bahamas64.bin" #define ROM_PHOENIX_VISION864 "roms/video/s3/86c864p.bin" #define ROM_DIAMOND_STEALTH64_964 "roms/video/s3/964_107h.rom" @@ -117,7 +118,8 @@ enum { S3_NUMBER9_9FX_771, S3_SPEA_MERCURY_LITE_PCI, S3_86C805_ONBOARD, - S3_DIAMOND_STEALTH64_968 + S3_DIAMOND_STEALTH64_968, + S3_WINNER1000_805 }; enum { @@ -3782,6 +3784,7 @@ s3_recalctimings(svga_t *svga) switch (s3->card_type) { case S3_MIROCRYSTAL8S_805: case S3_MIROCRYSTAL10SD_805: + case S3_WINNER1000_805: case S3_PHOENIX_86C805: case S3_86C805_ONBOARD: svga->hdisp >>= 1; @@ -3950,6 +3953,7 @@ s3_recalctimings(svga_t *svga) switch (s3->card_type) { case S3_MIROCRYSTAL8S_805: case S3_MIROCRYSTAL10SD_805: + case S3_WINNER1000_805: case S3_PHOENIX_86C805: case S3_86C805_ONBOARD: svga->hdisp >>= 1; @@ -4122,6 +4126,7 @@ s3_recalctimings(svga_t *svga) switch (s3->card_type) { case S3_MIROCRYSTAL8S_805: case S3_MIROCRYSTAL10SD_805: + case S3_WINNER1000_805: case S3_PHOENIX_86C805: case S3_SPEA_MIRAGE_86C805: case S3_86C805_ONBOARD: @@ -9835,6 +9840,11 @@ s3_init(const device_t *info) chip = S3_86C801; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); break; + case S3_WINNER1000_805: + bios_fn = ROM_WINNER1000_805; + chip = S3_86C805; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + break; case S3_86C805_ONBOARD: bios_fn = NULL; chip = S3_86C805; @@ -10316,6 +10326,7 @@ s3_init(const device_t *info) case S3_PHOENIX_86C801: case S3_PHOENIX_86C805: + case S3_WINNER1000_805: svga->decode_mask = (2 << 20) - 1; stepping = 0xa0; /*86C801/86C805*/ s3->id = stepping; @@ -10585,6 +10596,12 @@ s3_phoenix_86c80x_available(void) return rom_present(ROM_PHOENIX_86C80X); } +static int +s3_winner1000_805_available(void) +{ + return rom_present(ROM_WINNER1000_805); +} + static int s3_mirocrystal_8s_805_available(void) { @@ -10974,6 +10991,20 @@ const device_t s3_spea_mirage_86c801_isa_device = { .config = s3_9fx_config }; +const device_t s3_winner1000_805_isa_device = { + .name = "S3 86c805 ISA (ELSA Winner 1000)", + .internal_name = "winner1000_805_isa", + .flags = DEVICE_ISA16, + .local = S3_WINNER1000_805, + .init = s3_init, + .close = s3_close, + .reset = s3_reset, + .available = s3_winner1000_805_available, + .speed_changed = s3_speed_changed, + .force_redraw = s3_force_redraw, + .config = s3_9fx_config +}; + const device_t s3_86c805_onboard_vlb_device = { .name = "S3 86c805 VLB On-Board", .internal_name = "px_s3_805_onboard_vlb", diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 36573e9f9..e0ef7ada6 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -115,6 +115,7 @@ video_cards[] = { { .device = &s3_metheus_86c928_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_phoenix_86c801_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_spea_mirage_86c801_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_winner1000_805_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &sigma_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tvga8900b_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tvga8900d_device, .flags = VIDEO_FLAG_TYPE_NONE }, From 5d929c7735b0758ee155c07f622f97ad5d859e8e Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 7 May 2025 10:39:22 +0700 Subject: [PATCH 0868/1190] Move Winner 1000's RAMDAC to ATT491 --- src/video/vid_s3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 1f1ab5ede..23713c98b 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10297,6 +10297,7 @@ s3_init(const device_t *info) case S3_SPEA_MIRAGE_86C801: case S3_SPEA_MIRAGE_86C805: + case S3_WINNER1000_805: svga->decode_mask = (2 << 20) - 1; stepping = 0xa2; /*86C801/86C805*/ s3->id = stepping; @@ -10326,7 +10327,6 @@ s3_init(const device_t *info) case S3_PHOENIX_86C801: case S3_PHOENIX_86C805: - case S3_WINNER1000_805: svga->decode_mask = (2 << 20) - 1; stepping = 0xa0; /*86C801/86C805*/ s3->id = stepping; From 1f40db5d9e09092d6610103ef0196047fdc6b6c7 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Wed, 7 May 2025 11:29:11 +0700 Subject: [PATCH 0869/1190] Fixed ROM path --- src/video/vid_s3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 23713c98b..e88bbe58f 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -54,7 +54,7 @@ #define ROM_MIROCRYSTAL20SV_964_PCI "roms/video/s3/mirocrystal.VBI" #define ROM_MIROCRYSTAL20SD_864_VLB "roms/video/s3/Miro20SD.BIN" #define ROM_PHOENIX_86C80X "roms/video/s3/805.VBI" -#define ROM_WINNER1000_805 "roms/video/s3/v01_05_00-C.BIN.bin" +#define ROM_WINNER1000_805 "roms/video/s3/v01_05_00-C.BIN" #define ROM_PARADISE_BAHAMAS64 "roms/video/s3/bahamas64.bin" #define ROM_PHOENIX_VISION864 "roms/video/s3/86c864p.bin" #define ROM_DIAMOND_STEALTH64_964 "roms/video/s3/964_107h.rom" From 20d04c7c0834fbff8b0d4ae162e04e46c3ba707d Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 07:20:54 +0200 Subject: [PATCH 0870/1190] Added the ASUS ISA-486C. --- src/chipset/CMakeLists.txt | 1 + src/device/postcard.c | 2 ++ src/include/86box/chipset.h | 3 +++ src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 29 ++++++++++++++++++++++++++ src/machine/machine_table.c | 40 ++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 6018dd045..94ef408f6 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -39,6 +39,7 @@ add_library(chipset OBJECT intel_i450kx.c intel_sio.c intel_piix.c + isa486c.c ../ioapic.c neat.c opti283.c diff --git a/src/device/postcard.c b/src/device/postcard.c index 9e2c629c1..b91d8b402 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -158,6 +158,8 @@ postcard_init(UNUSED(const device_t *info)) postcard_port = 0x84; /* ISA Compaq machines */ else if (strstr(machines[machine].name, "Olivetti")) postcard_port = 0x378; /* Olivetti machines */ + else if (!strcmp(machines[machine].internal_name, "isa486c")) + postcard_port = 0x5080; /* ASUS ISA-486C */ else postcard_port = 0x80; /* AT and clone machines */ postcard_log("POST card initializing on port %04Xh\n", postcard_port); diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 3a65bbce9..fe088b209 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -37,6 +37,9 @@ extern const device_t ali6117d_device; /* AMD */ extern const device_t amd640_device; +/* ASUS */ +extern const device_t isa486c_device; + /* Compaq */ extern const device_t compaq_386_device; extern const device_t compaq_genoa_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index d8c213d53..996f2bf5f 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -508,6 +508,7 @@ extern int machine_at_pc916sx_init(const machine_t *); sure this appear here (and in the .c file) in the order and position in which they appear in the machine table. */ extern int machine_at_dataexpert386wb_init(const machine_t *); +extern int machine_at_isa486c_init(const machine_t *); extern int machine_at_genoa486_init(const machine_t *); extern int machine_at_ga486l_init(const machine_t *); extern int machine_at_cougar_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index ed8f75a84..f50e8af42 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -2445,6 +2445,35 @@ machine_at_dataexpert386wb_init(const machine_t *model) return ret; } +int +machine_at_isa486c_init(const machine_t *model) +{ + int ret; + +#if 0 + ret = bios_load_linear("roms/machines/isa486c/asus-isa-486c-401a0-040591-657e2c17a0218417632602.bin", + 0x000f0000, 65536, 0); +#else + ret = bios_load_linear("roms/machines/isa486c/128k.bin", + 0x000e0000, 131072, 0); +#endif + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&isa486c_device); + device_add(&port_92_key_device); + + device_add(&keyboard_at_ami_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + int machine_at_genoa486_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 7e0ae8d64..adf132a5d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5998,6 +5998,46 @@ const machine_t machines[] = { }, /* 486 machines - Socket 1 */ + /* Has Award KBC firmware. */ + { + .name = "[ZyMOS Poach] ASUS ISA-486C", + .internal_name = "isa486c", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_ZYMOS_POACH, + .init = machine_at_isa486c_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_APM, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has AMI KF KBC firmware. */ { .name = "[ZyMOS Poach] Genoa Unknown 486", From 9ac25992649e14fe8128067d61ae95b08a0368f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 07:21:26 +0200 Subject: [PATCH 0871/1190] Correct the BIOS. --- src/machine/m_at_386dx_486.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index f50e8af42..e3838ce32 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -2450,13 +2450,8 @@ machine_at_isa486c_init(const machine_t *model) { int ret; -#if 0 ret = bios_load_linear("roms/machines/isa486c/asus-isa-486c-401a0-040591-657e2c17a0218417632602.bin", 0x000f0000, 65536, 0); -#else - ret = bios_load_linear("roms/machines/isa486c/128k.bin", - 0x000e0000, 131072, 0); -#endif if (bios_only || !ret) return ret; From 572c9e176bc5d2b6051aed74cdd9a91e1087e7c6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 7 May 2025 17:41:59 +0600 Subject: [PATCH 0872/1190] Implement keyboard grabbing for Wayland --- src/qt/CMakeLists.txt | 1 + src/qt/qt_main.cpp | 10 ++ src/qt/qt_mainwindow.cpp | 25 ++- src/qt/wl_mouse.cpp | 37 ++++- ...keyboard-shortcuts-inhibit-unstable-v1.xml | 143 ++++++++++++++++++ 5 files changed, 209 insertions(+), 7 deletions(-) create mode 100644 wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 4231034d5..df13d42e2 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -453,6 +453,7 @@ if (UNIX AND NOT APPLE AND NOT HAIKU) set(WL_SOURCE_VAR) ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/relative-pointer-unstable-v1.xml BASENAME relative-pointer-unstable-v1) ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1) + ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml BASENAME keyboard-shortcuts-inhibit-unstable-v1) target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp) if (XKBCOMMON_FOUND) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 1f1dd6b49..5cea8c698 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -672,6 +672,16 @@ main(int argc, char *argv[]) } else { main_window->show(); } +#ifdef __unix__ + if (QApplication::platformName().contains("wayland")) { + /* Force a sync. */ + (void)main_window->winId(); + QApplication::sync(); + extern void wl_keyboard_grab(QWindow *window); + wl_keyboard_grab(main_window->windowHandle()); + } +#endif + app.installEventFilter(main_window); diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index e966e043a..3e0f9f001 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -322,7 +322,8 @@ MainWindow::MainWindow(QWidget *parent) if (ui->stackedWidget->mouse_capture_func) ui->stackedWidget->mouse_capture_func(this->windowHandle()); } else { - this->releaseKeyboard(); + if (!(windowState() & Qt::WindowActive)) + this->releaseKeyboard(); if (ui->stackedWidget->mouse_uncapture_func) { ui->stackedWidget->mouse_uncapture_func(); } @@ -1492,8 +1493,26 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) curdopause = dopause; plat_pause(isShowMessage ? 2 : 1); emit setMouseCapture(false); + releaseKeyboard(); } else if (event->type() == QEvent::WindowUnblocked) { plat_pause(curdopause); +#ifdef __unix__ + if (!QApplication::platformName().contains("wayland") && (this->windowState() & Qt::WindowActive)) { + this->grabKeyboard(); + } +#endif + } else if (event->type() == QEvent::WindowActivate) { +#ifdef __unix__ + if (!QApplication::platformName().contains("wayland")) { + this->grabKeyboard(); + } +#endif + } else if (event->type() == QEvent::WindowDeactivate) { +#ifdef __unix__ + if (!QApplication::platformName().contains("wayland")) { + this->releaseKeyboard(); + } +#endif } } @@ -1611,13 +1630,13 @@ MainWindow::getRenderWidgetSize() void MainWindow::focusInEvent(QFocusEvent *event) { - this->grabKeyboard(); + //this->grabKeyboard(); } void MainWindow::focusOutEvent(QFocusEvent *event) { - this->releaseKeyboard(); + //this->releaseKeyboard(); } void diff --git a/src/qt/wl_mouse.cpp b/src/qt/wl_mouse.cpp index 5d6d95a0a..9201c4ec8 100644 --- a/src/qt/wl_mouse.cpp +++ b/src/qt/wl_mouse.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,10 +31,12 @@ extern "C" { #include <86box/plat.h> } -static zwp_relative_pointer_manager_v1 *rel_manager = nullptr; -static zwp_relative_pointer_v1 *rel_pointer = nullptr; -static zwp_pointer_constraints_v1 *conf_pointer_interface = nullptr; -static zwp_locked_pointer_v1 *conf_pointer = nullptr; +static zwp_relative_pointer_manager_v1 *rel_manager = nullptr; +static zwp_relative_pointer_v1 *rel_pointer = nullptr; +static zwp_pointer_constraints_v1 *conf_pointer_interface = nullptr; +static zwp_locked_pointer_v1 *conf_pointer = nullptr; +static zwp_keyboard_shortcuts_inhibit_manager_v1 *kbd_manager = nullptr; +static zwp_keyboard_shortcuts_inhibitor_v1 *kbd_inhibitor = nullptr; static bool wl_init_ok = false; @@ -47,6 +50,12 @@ static struct zwp_relative_pointer_v1_listener rel_listener = { rel_mouse_event }; +static struct zwp_keyboard_shortcuts_inhibitor_v1_listener kbd_listener +{ + [](void *data, struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) -> void {}, + [](void *data, struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) -> void {} +}; + static void display_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) @@ -57,16 +66,25 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, if (!strcmp(interface, "zwp_pointer_constraints_v1")) { conf_pointer_interface = (zwp_pointer_constraints_v1 *) wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, version); } + if (!strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1")) { + kbd_manager = (zwp_keyboard_shortcuts_inhibit_manager_v1 *) wl_registry_bind(registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, version); + } } static void display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { plat_mouse_capture(0); + if (kbd_inhibitor) { + zwp_keyboard_shortcuts_inhibitor_v1_destroy(kbd_inhibitor); + kbd_inhibitor = nullptr; + } + zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(kbd_manager); zwp_relative_pointer_manager_v1_destroy(rel_manager); zwp_pointer_constraints_v1_destroy(conf_pointer_interface); rel_manager = nullptr; conf_pointer_interface = nullptr; + kbd_manager = nullptr; } static const struct wl_registry_listener registry_listener = { @@ -90,9 +108,20 @@ wl_init() } } +void +wl_keyboard_grab(QWindow *window) +{ + if (!kbd_inhibitor && kbd_manager) { + kbd_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(kbd_manager, (wl_surface *) QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_seat *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_seat")); + } +} + void wl_mouse_capture(QWindow *window) { + if (!kbd_inhibitor) { + kbd_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(kbd_manager, (wl_surface *) QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_seat *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_seat")); + } if (rel_manager) { rel_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(rel_manager, (wl_pointer *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer")); zwp_relative_pointer_v1_add_listener(rel_pointer, &rel_listener, nullptr); diff --git a/wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml b/wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml new file mode 100644 index 000000000..27748764d --- /dev/null +++ b/wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml @@ -0,0 +1,143 @@ + + + + + Copyright © 2017 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for a client to request the compositor + to ignore its own keyboard shortcuts for a given seat, so that all + key events from that seat get forwarded to a surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + A global interface used for inhibiting the compositor keyboard shortcuts. + + + + + Destroy the keyboard shortcuts inhibitor manager. + + + + + + Create a new keyboard shortcuts inhibitor object associated with + the given surface for the given seat. + + If shortcuts are already inhibited for the specified seat and surface, + a protocol error "already_inhibited" is raised by the compositor. + + + + + + + + + + + + + + A keyboard shortcuts inhibitor instructs the compositor to ignore + its own keyboard shortcuts when the associated surface has keyboard + focus. As a result, when the surface has keyboard focus on the given + seat, it will receive all key events originating from the specified + seat, even those which would normally be caught by the compositor for + its own shortcuts. + + The Wayland compositor is however under no obligation to disable + all of its shortcuts, and may keep some special key combo for its own + use, including but not limited to one allowing the user to forcibly + restore normal keyboard events routing in the case of an unwilling + client. The compositor may also use the same key combo to reactivate + an existing shortcut inhibitor that was previously deactivated on + user request. + + When the compositor restores its own keyboard shortcuts, an + "inactive" event is emitted to notify the client that the keyboard + shortcuts inhibitor is not effectively active for the surface and + seat any more, and the client should not expect to receive all + keyboard events. + + When the keyboard shortcuts inhibitor is inactive, the client has + no way to forcibly reactivate the keyboard shortcuts inhibitor. + + The user can chose to re-enable a previously deactivated keyboard + shortcuts inhibitor using any mechanism the compositor may offer, + in which case the compositor will send an "active" event to notify + the client. + + If the surface is destroyed, unmapped, or loses the seat's keyboard + focus, the keyboard shortcuts inhibitor becomes irrelevant and the + compositor will restore its own keyboard shortcuts but no "inactive" + event is emitted in this case. + + + + + Remove the keyboard shortcuts inhibitor from the associated wl_surface. + + + + + + This event indicates that the shortcut inhibitor is active. + + The compositor sends this event every time compositor shortcuts + are inhibited on behalf of the surface. When active, the client + may receive input events normally reserved by the compositor + (see zwp_keyboard_shortcuts_inhibitor_v1). + + This occurs typically when the initial request "inhibit_shortcuts" + first becomes active or when the user instructs the compositor to + re-enable and existing shortcuts inhibitor using any mechanism + offered by the compositor. + + + + + + This event indicates that the shortcuts inhibitor is inactive, + normal shortcuts processing is restored by the compositor. + + + + From e1a6ebac08b1575da8e4e570c03fca46d807613b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 15:23:50 +0200 Subject: [PATCH 0873/1190] The forgotten chipset/is486c.c. --- src/chipset/isa486c.c | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/chipset/isa486c.c diff --git a/src/chipset/isa486c.c b/src/chipset/isa486c.c new file mode 100644 index 000000000..6494ed1b8 --- /dev/null +++ b/src/chipset/isa486c.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/plat_unused.h> +#include <86box/chipset.h> + +typedef struct isa486c_t { + uint8_t regs[3]; +} isa486c_t; + +static void +isa486c_recalcmapping(isa486c_t *dev) +{ + uint32_t shflags = 0; + uint32_t bases[5] = { 0x000c0000, 0x000c8000, 0x000d0000, 0x000d8000, 0x000e0000 }; + uint32_t sizes[5] = { 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00020000 }; + + if (dev->regs[1] & 0x20) + shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + else + shflags = MEM_READ_INTERNAL | MEM_WRITE_EXTANY; + + shadowbios = 0; + shadowbios_write = 0; + + for (uint8_t i = 0; i < 5; i++) + if (dev->regs[1] & (1 << i)) { + if (i == 4) { + shadowbios = 1; + shadowbios_write = !!(dev->regs[1] & 0x20); + } + + mem_set_mem_state_both(bases[i], sizes[i], shflags); + } else + mem_set_mem_state_both(bases[i], sizes[i], MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + flushmmucache_nopc(); +} + +static void +isa486c_write(uint16_t addr, uint8_t val, void *priv) +{ + isa486c_t *dev = (isa486c_t *) priv; + + switch (addr) { + case 0x0023: + dev->regs[0] = val; + break; + /* + Port 25h: + - Bit 0 = Video BIOS (C000-C7FF) shadow enabled; + - Bit 1 = C800-C8FF shadow enabled; + - Bit 2 = D000-D7FF shadow enabled; + - Bit 3 = D800-DFFF shadow enabled; + - Bit 4 = E000-FFFF shadow enabled (or F0000-FFFFF?); + - Bit 5 = If set, read from ROM, write to shadow; + - Bit 6 = KEN Video & BIOS enabled (cacheability!). + */ + case 0x0025: + dev->regs[1] = val; + isa486c_recalcmapping(dev); + break; + case 0x0027: + dev->regs[2] = val; + break; + } +} + +static uint8_t +isa486c_read(uint16_t addr, void *priv) +{ + isa486c_t *dev = (isa486c_t *) priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x0023: + ret = dev->regs[0]; + break; + case 0x0025: + ret = dev->regs[1]; + break; + case 0x0027: + ret = dev->regs[2]; + break; + } + + return ret; +} + +static void +isa486c_close(void *priv) +{ + isa486c_t *dev = (isa486c_t *) priv; + + free(dev); +} + +static void * +isa486c_init(UNUSED(const device_t *info)) +{ + isa486c_t *dev = (isa486c_t *) calloc(1, sizeof(isa486c_t)); + + io_sethandler(0x0023, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev); + io_sethandler(0x0025, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev); + io_sethandler(0x0027, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev); + + return dev; +} + +const device_t isa486c_device = { + .name = "ASUS ISA-486C Gate Array", + .internal_name = "isa486c", + .flags = 0, + .local = 0, + .init = isa486c_init, + .close = isa486c_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; From 39fdda6dd9ef4ccda98f6d61db0a41eb7b077c8e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 7 May 2025 20:22:38 +0600 Subject: [PATCH 0874/1190] Fix compilation without extra-cmake-modules --- src/qt/qt_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 5cea8c698..3f8476374 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -672,7 +672,7 @@ main(int argc, char *argv[]) } else { main_window->show(); } -#ifdef __unix__ +#ifdef WAYLAND if (QApplication::platformName().contains("wayland")) { /* Force a sync. */ (void)main_window->winId(); From 5918356719158636b24aa14bfa1aef17d44ea050 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 7 May 2025 19:03:10 +0500 Subject: [PATCH 0875/1190] Fix keybinds being saved in native/localized form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keybinds are now both saved and read in portable form and only converted to native one for display purposes, fixing them not being read correctly when certain languages are set. Also get rid of qPrintable() due to it using the system 8-bit codepage instead of UTF-8, and some unnecessary QString ↔ C string conversions Co-Authored-by: Cacodemon345 --- src/include/86box/plat.h | 4 ++-- src/qt/languages/86box.pot | 2 +- src/qt/languages/ca-ES.po | 12 ++++++------ src/qt/languages/cs-CZ.po | 12 ++++++------ src/qt/languages/de-DE.po | 15 ++++++--------- src/qt/languages/es-ES.po | 12 ++++++------ src/qt/languages/fi-FI.po | 12 ++++++------ src/qt/languages/fr-FR.po | 12 ++++++------ src/qt/languages/hr-HR.po | 12 ++++++------ src/qt/languages/hu-HU.po | 12 ++++++------ src/qt/languages/it-IT.po | 12 ++++++------ src/qt/languages/ja-JP.po | 12 ++++++------ src/qt/languages/ko-KR.po | 12 ++++++------ src/qt/languages/nl-NL.po | 12 ++++++------ src/qt/languages/pl-PL.po | 12 ++++++------ src/qt/languages/pt-BR.po | 12 ++++++------ src/qt/languages/pt-PT.po | 12 ++++++------ src/qt/languages/ru-RU.po | 12 ++++++------ src/qt/languages/sk-SK.po | 12 ++++++------ src/qt/languages/sl-SI.po | 12 ++++++------ src/qt/languages/sv-SE.po | 12 ++++++------ src/qt/languages/tr-TR.po | 12 ++++++------ src/qt/languages/uk-UA.po | 12 ++++++------ src/qt/languages/vi-VN.po | 12 ++++++------ src/qt/languages/zh-CN.po | 12 ++++++------ src/qt/languages/zh-TW.po | 12 ++++++------ src/qt/qt_keybind.cpp | 2 +- src/qt/qt_mainwindow.cpp | 7 +++---- src/qt/qt_platform.cpp | 13 +++---------- src/qt/qt_settingsinput.cpp | 10 +++++----- 30 files changed, 159 insertions(+), 170 deletions(-) diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index bbc673dcf..e6a366f4c 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -32,8 +32,8 @@ /* String ID numbers. */ enum { STRING_MOUSE_CAPTURE, /* "Click to capture mouse" */ - STRING_MOUSE_RELEASE, /* "Press F8+F12 to release mouse" */ - STRING_MOUSE_RELEASE_MMB, /* "Press F8+F12 or middle button to release mouse" */ + STRING_MOUSE_RELEASE, /* "Press %1 to release mouse" */ + STRING_MOUSE_RELEASE_MMB, /* "Press %1 or middle button to release mouse" */ STRING_INVALID_CONFIG, /* "Invalid configuration" */ STRING_NO_ST506_ESDI_CDROM, /* "MFM/RLL or ESDI CD-ROM drives never existed" */ STRING_NET_ERROR, /* "Failed to initialize network driver" */ diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 6e6dd3fc3..d5152cd3d 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -630,7 +630,7 @@ msgstr "" msgid " - PAUSED" msgstr "" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." +msgid "Press %1 to return to windowed mode." msgstr "" msgid "Speed" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 4851106cd..7fe87eb1a 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -630,8 +630,8 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press %s to return to windowed mode." -msgstr "Premeu %s per tornar al mode de finestra." +msgid "Press %1 to return to windowed mode." +msgstr "Premeu %1 per tornar al mode de finestra." msgid "Speed" msgstr "Velocitat" @@ -717,11 +717,11 @@ msgstr "Altres perifèrics" msgid "Click to capture mouse" msgstr "Feu clic per capturar el ratolí" -msgid "Press %s to release mouse" -msgstr "Premeu %s per alliberar el ratolí" +msgid "Press %1 to release mouse" +msgstr "Premeu %1 per alliberar el ratolí" -msgid "Press %s or middle button to release mouse" -msgstr "Premeu %s o el botó central per alliberar el ratolí" +msgid "Press %1 or middle button to release mouse" +msgstr "Premeu %1 o el botó central per alliberar el ratolí" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 352fafc31..59a582ca6 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -630,8 +630,8 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENO" -msgid "Press %s to return to windowed mode." -msgstr "Stiskněte %s pro návrat z režimu celé obrazovky." +msgid "Press %1 to return to windowed mode." +msgstr "Stiskněte %1 pro návrat z režimu celé obrazovky." msgid "Speed" msgstr "Rychlost" @@ -717,11 +717,11 @@ msgstr "Jiné příslušenství" msgid "Click to capture mouse" msgstr "Klikněte pro zabraní myši" -msgid "Press %s to release mouse" -msgstr "Stiskněte %s pro uvolnění myši" +msgid "Press %1 to release mouse" +msgstr "Stiskněte %1 pro uvolnění myši" -msgid "Press %s or middle button to release mouse" -msgstr "Stiskněte %s nebo prostřední tlačítko pro uvolnění myši" +msgid "Press %1 or middle button to release mouse" +msgstr "Stiskněte %1 nebo prostřední tlačítko pro uvolnění myši" msgid "Bus" msgstr "Sběrnice" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index ce7d52d55..0615dada4 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -630,8 +630,8 @@ msgstr "Fataler Fehler" msgid " - PAUSED" msgstr " - PAUSIERT" -msgid "Press %s to return to windowed mode." -msgstr "%s ab, zur Rückkehr in den Fenstermodus." +msgid "Press %1 to return to windowed mode." +msgstr "%1 ab, zur Rückkehr in den Fenstermodus." msgid "Speed" msgstr "Geschwindigkeit" @@ -717,14 +717,11 @@ msgstr "Andere Peripheriegeräte" msgid "Click to capture mouse" msgstr "Klicken zum Einfangen des Mauszeigers" -msgid "Press %s to release mouse" -msgstr "Drücke %s zur Mausfreigabe" +msgid "Press %1 to release mouse" +msgstr "Drücke %1 zur Mausfreigabe" -msgid "Press %s or middle button to release mouse" -msgstr "Drücke %s oder die mittlere Maustaste zur Mausfreigabe" - -msgid "Ctrl+End" -msgstr "Strg+Ende" +msgid "Press %1 or middle button to release mouse" +msgstr "Drücke %1 oder die mittlere Maustaste zur Mausfreigabe" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 177d08d18..1f9cf10b2 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -630,8 +630,8 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press %s to return to windowed mode." -msgstr "Pulsa %s para volver a modo ventana." +msgid "Press %1 to return to windowed mode." +msgstr "Pulsa %1 para volver a modo ventana." msgid "Speed" msgstr "Velocidad" @@ -717,11 +717,11 @@ msgstr "Otros periféricos" msgid "Click to capture mouse" msgstr "Haga click para capturar el ratón" -msgid "Press %s to release mouse" -msgstr "Pulse %s para liberar el ratón" +msgid "Press %1 to release mouse" +msgstr "Pulse %1 para liberar el ratón" -msgid "Press %s or middle button to release mouse" -msgstr "Pulse %s o el botón central para liberar el ratón" +msgid "Press %1 or middle button to release mouse" +msgstr "Pulse %1 o el botón central para liberar el ratón" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index a77b3f6ef..4979332ac 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -630,8 +630,8 @@ msgstr "Vakava virhe" msgid " - PAUSED" msgstr " - TAUKO" -msgid "Press %s to return to windowed mode." -msgstr "Paina %s palataksesi ikkunoituun tilaan." +msgid "Press %1 to return to windowed mode." +msgstr "Paina %1 palataksesi ikkunoituun tilaan." msgid "Speed" msgstr "Nopeus" @@ -717,11 +717,11 @@ msgstr "Muut oheislaitteet" msgid "Click to capture mouse" msgstr "Kaappaa hiiri klikkaamalla" -msgid "Press %s to release mouse" -msgstr "Paina %s vapauttaaksesi hiiren" +msgid "Press %1 to release mouse" +msgstr "Paina %1 vapauttaaksesi hiiren" -msgid "Press %s or middle button to release mouse" -msgstr "Paina %s tai keskipainiketta vapauttaaksesi hiiren" +msgid "Press %1 or middle button to release mouse" +msgstr "Paina %1 tai keskipainiketta vapauttaaksesi hiiren" msgid "Bus" msgstr "Väylä" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index fe3dc4bb4..58de2e4d1 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -630,8 +630,8 @@ msgstr "Erreur fatale" msgid " - PAUSED" msgstr " - EN PAUSE" -msgid "Press %s to return to windowed mode." -msgstr "Appuyez sur %s pour revenir au mode fenêtré." +msgid "Press %1 to return to windowed mode." +msgstr "Appuyez sur %1 pour revenir au mode fenêtré." msgid "Speed" msgstr "Vitesse" @@ -717,11 +717,11 @@ msgstr "Autres périfériques" msgid "Click to capture mouse" msgstr "Cliquer pour capturer la souris" -msgid "Press %s to release mouse" -msgstr "Appuyer sur %s pour libérer la souris" +msgid "Press %1 to release mouse" +msgstr "Appuyer sur %1 pour libérer la souris" -msgid "Press %s or middle button to release mouse" -msgstr "Appuyer sur %s ou le bouton central pour libérer la souris" +msgid "Press %1 or middle button to release mouse" +msgstr "Appuyer sur %1 ou le bouton central pour libérer la souris" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 1eecaa2d0..5f0e60b21 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -630,8 +630,8 @@ msgstr "Fatalna greška" msgid " - PAUSED" msgstr " - ZASTAO" -msgid "Press %s to return to windowed mode." -msgstr "Pritisnite %s za povratak u prozorski način rada." +msgid "Press %1 to return to windowed mode." +msgstr "Pritisnite %1 za povratak u prozorski način rada." msgid "Speed" msgstr "Brzina" @@ -717,11 +717,11 @@ msgstr "Ostali periferni uređaji" msgid "Click to capture mouse" msgstr "Kliknite da uhvatite miš" -msgid "Press %s to release mouse" -msgstr "Pritisnite %s za otpustanje miša" +msgid "Press %1 to release mouse" +msgstr "Pritisnite %1 za otpustanje miša" -msgid "Press %s or middle button to release mouse" -msgstr "Pritisnite %s ili srednji gumb miša za otpuštanje miša" +msgid "Press %1 or middle button to release mouse" +msgstr "Pritisnite %1 ili srednji gumb miša za otpuštanje miša" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 43a1fd9ba..3398859d2 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -630,8 +630,8 @@ msgstr "Végzetes hiba" msgid " - PAUSED" msgstr " - SZÜNETELT" -msgid "Press %s to return to windowed mode." -msgstr "Használja a %s gombokat az ablakhoz való visszatéréshez." +msgid "Press %1 to return to windowed mode." +msgstr "Használja a %1 gombokat az ablakhoz való visszatéréshez." msgid "Speed" msgstr "Sebesség" @@ -717,11 +717,11 @@ msgstr "Egyéb perifériák" msgid "Click to capture mouse" msgstr "Kattintson az egér elfogásához" -msgid "Press %s to release mouse" -msgstr "Nyomja meg az %s-t az egér elengédéséhez" +msgid "Press %1 to release mouse" +msgstr "Nyomja meg az %1-t az egér elengédéséhez" -msgid "Press %s or middle button to release mouse" -msgstr "Nyomja meg az %s-t vagy a középső gombot az egér elengédéséhez" +msgid "Press %1 or middle button to release mouse" +msgstr "Nyomja meg az %1-t vagy a középső gombot az egér elengédéséhez" msgid "Bus" msgstr "Busz" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index b8ded74de..d45a0080b 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -630,8 +630,8 @@ msgstr "Errore fatale" msgid " - PAUSED" msgstr " - IN PAUSA" -msgid "Press %s to return to windowed mode." -msgstr "Usa %s per tornare alla modalità finestra." +msgid "Press %1 to return to windowed mode." +msgstr "Usa %1 per tornare alla modalità finestra." msgid "Speed" msgstr "Velocità" @@ -717,11 +717,11 @@ msgstr "Altre periferiche" msgid "Click to capture mouse" msgstr "Fare clic per catturare mouse" -msgid "Press %s to release mouse" -msgstr "Premi %s per rilasciare il mouse" +msgid "Press %1 to release mouse" +msgstr "Premi %1 per rilasciare il mouse" -msgid "Press %s or middle button to release mouse" -msgstr "Premi %s o pulsante centrale per rilasciare il mouse" +msgid "Press %1 or middle button to release mouse" +msgstr "Premi %1 o pulsante centrale per rilasciare il mouse" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index dc000b175..7883f8a5a 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -630,8 +630,8 @@ msgstr "致命的なエラー" msgid " - PAUSED" msgstr " - 一時停止" -msgid "Press %s to return to windowed mode." -msgstr "%sでウィンドウ モードに戻ります。" +msgid "Press %1 to return to windowed mode." +msgstr "%1でウィンドウ モードに戻ります。" msgid "Speed" msgstr "速度" @@ -717,11 +717,11 @@ msgstr "他の周辺デバイス" msgid "Click to capture mouse" msgstr "左クリックでマウスをキャプチャします" -msgid "Press %s to release mouse" -msgstr "%sキーでマウスを解放します" +msgid "Press %1 to release mouse" +msgstr "%1キーでマウスを解放します" -msgid "Press %s or middle button to release mouse" -msgstr "%sキーまたは中クリックでマウスを解放します" +msgid "Press %1 or middle button to release mouse" +msgstr "%1キーまたは中クリックでマウスを解放します" msgid "Bus" msgstr "バス" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 3ef901789..a9ed452d6 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -630,8 +630,8 @@ msgstr "치명적인 오류" msgid " - PAUSED" msgstr " - 일시 중지됨" -msgid "Press %s to return to windowed mode." -msgstr "%s 키를 누르면 창 모드로 전환합니다." +msgid "Press %1 to return to windowed mode." +msgstr "%1 키를 누르면 창 모드로 전환합니다." msgid "Speed" msgstr "속도" @@ -717,11 +717,11 @@ msgstr "기타 주변기기" msgid "Click to capture mouse" msgstr "이 창을 클릭하면 마우스를 사용합니다" -msgid "Press %s to release mouse" -msgstr "%s키를 누르면 마우스를 해제합니다" +msgid "Press %1 to release mouse" +msgstr "%1키를 누르면 마우스를 해제합니다" -msgid "Press %s or middle button to release mouse" -msgstr "%s키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" +msgid "Press %1 or middle button to release mouse" +msgstr "%1키 또는 가운데 버튼을 클릭하면 마우스를 해제합니다" msgid "Bus" msgstr "버스" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 49a32506b..2859916d7 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -630,8 +630,8 @@ msgstr "Fatale fout" msgid " - PAUSED" msgstr " - GEPAUZEERD" -msgid "Press %s to return to windowed mode." -msgstr "Druk op %s om terug te gaan naar de venstermodus." +msgid "Press %1 to return to windowed mode." +msgstr "Druk op %1 om terug te gaan naar de venstermodus." msgid "Speed" msgstr "Snelheid" @@ -717,11 +717,11 @@ msgstr "Andere randapparatuur" msgid "Click to capture mouse" msgstr "Klik om muis vast te leggen" -msgid "Press %s to release mouse" -msgstr "Druk op %s om de muis los te laten" +msgid "Press %1 to release mouse" +msgstr "Druk op %1 om de muis los te laten" -msgid "Press %s or middle button to release mouse" -msgstr "Druk op %s of middelste knop om de muis los te laten" +msgid "Press %1 or middle button to release mouse" +msgstr "Druk op %1 of middelste knop om de muis los te laten" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index d5b5ec3ea..02bdc26fe 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -630,8 +630,8 @@ msgstr "Fatalny błąd" msgid " - PAUSED" msgstr " - PAUSED" -msgid "Press %s to return to windowed mode." -msgstr "Naciśnij klawisze %s aby wrócić to trybu okna." +msgid "Press %1 to return to windowed mode." +msgstr "Naciśnij klawisze %1 aby wrócić to trybu okna." msgid "Speed" msgstr "Szybkość" @@ -717,11 +717,11 @@ msgstr "Inne urządzenia peryferyjne" msgid "Click to capture mouse" msgstr "Kliknij w celu przechwycenia myszy" -msgid "Press %s to release mouse" -msgstr "Naciśnij klawisze %s w celu uwolnienia myszy" +msgid "Press %1 to release mouse" +msgstr "Naciśnij klawisze %1 w celu uwolnienia myszy" -msgid "Press %s or middle button to release mouse" -msgstr "Naciśnij klawisze %s lub środkowy przycisk w celu uwolnienia myszy" +msgid "Press %1 or middle button to release mouse" +msgstr "Naciśnij klawisze %1 lub środkowy przycisk w celu uwolnienia myszy" msgid "Bus" msgstr "Magistrala" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index e33630ccf..4fb974f4d 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -630,8 +630,8 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - PAUSADO" -msgid "Press %s to return to windowed mode." -msgstr "Use %s para retornar ao modo janela." +msgid "Press %1 to return to windowed mode." +msgstr "Use %1 para retornar ao modo janela." msgid "Speed" msgstr "Velocidade" @@ -717,11 +717,11 @@ msgstr "Outros periféricos" msgid "Click to capture mouse" msgstr "Clique para capturar o mouse" -msgid "Press %s to release mouse" -msgstr "Aperte %s para liberar o mouse" +msgid "Press %1 to release mouse" +msgstr "Aperte %1 para liberar o mouse" -msgid "Press %s or middle button to release mouse" -msgstr "Aperte %s ou botão do meio para liberar o mouse" +msgid "Press %1 or middle button to release mouse" +msgstr "Aperte %1 ou botão do meio para liberar o mouse" msgid "Bus" msgstr "Barramento" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index ba1c6976c..86c40fc40 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -630,8 +630,8 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - EM PAUSA" -msgid "Press %s to return to windowed mode." -msgstr "Pressione %s para voltar ao modo de janela." +msgid "Press %1 to return to windowed mode." +msgstr "Pressione %1 para voltar ao modo de janela." msgid "Speed" msgstr "Velocidade" @@ -717,11 +717,11 @@ msgstr "Outros dispositivos" msgid "Click to capture mouse" msgstr "Clique para capturar o rato" -msgid "Press %s to release mouse" -msgstr "Pressione %s para soltar o rato" +msgid "Press %1 to release mouse" +msgstr "Pressione %1 para soltar o rato" -msgid "Press %s or middle button to release mouse" -msgstr "Pressione %s ou tecla média para soltar o rato" +msgid "Press %1 or middle button to release mouse" +msgstr "Pressione %1 ou tecla média para soltar o rato" msgid "Bus" msgstr "Barramento" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index e88f4f0fc..899b905ac 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -630,8 +630,8 @@ msgstr "Неустранимая ошибка" msgid " - PAUSED" msgstr " - ПАУЗА" -msgid "Press %s to return to windowed mode." -msgstr "Нажмите %s для возврата в оконный режим." +msgid "Press %1 to return to windowed mode." +msgstr "Нажмите %1 для возврата в оконный режим." msgid "Speed" msgstr "Скорость" @@ -717,11 +717,11 @@ msgstr "Другая периферия" msgid "Click to capture mouse" msgstr "Щёлкните мышью для захвата курсора" -msgid "Press %s to release mouse" -msgstr "Нажмите %s, чтобы освободить курсор" +msgid "Press %1 to release mouse" +msgstr "Нажмите %1, чтобы освободить курсор" -msgid "Press %s or middle button to release mouse" -msgstr "Нажмите %s или среднюю кнопку мыши, чтобы освободить курсор" +msgid "Press %1 or middle button to release mouse" +msgstr "Нажмите %1 или среднюю кнопку мыши, чтобы освободить курсор" msgid "Bus" msgstr "Шина" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index f11f335d4..624715f76 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -630,8 +630,8 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENÝ" -msgid "Press %s to return to windowed mode." -msgstr "Stlačte %s pre návrat z režimu celej obrazovky." +msgid "Press %1 to return to windowed mode." +msgstr "Stlačte %1 pre návrat z režimu celej obrazovky." msgid "Speed" msgstr "Rýchlosť" @@ -717,11 +717,11 @@ msgstr "Iné príslušenstvo" msgid "Click to capture mouse" msgstr "Kliknite pre zabráni myši" -msgid "Press %s to release mouse" -msgstr "Stlačte %s pre uvoľnenie myši" +msgid "Press %1 to release mouse" +msgstr "Stlačte %1 pre uvoľnenie myši" -msgid "Press %s or middle button to release mouse" -msgstr "Stlačte %s alebo prostredné tlačidlo na uvoľnenie myši" +msgid "Press %1 or middle button to release mouse" +msgstr "Stlačte %1 alebo prostredné tlačidlo na uvoľnenie myši" msgid "Bus" msgstr "Zbernica" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index dcb3dbf50..d07a1eac4 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -630,8 +630,8 @@ msgstr "Kritična napaka" msgid " - PAUSED" msgstr " - ZAUSTAVLJEN" -msgid "Press %s to return to windowed mode." -msgstr "Pritisnite %s za povratek iz celozaslonskega načina." +msgid "Press %1 to return to windowed mode." +msgstr "Pritisnite %1 za povratek iz celozaslonskega načina." msgid "Speed" msgstr "Hitrost" @@ -717,11 +717,11 @@ msgstr "Druga periferija" msgid "Click to capture mouse" msgstr "Kliknite za zajem miške" -msgid "Press %s to release mouse" -msgstr "Pritisnite %s za izpust miške" +msgid "Press %1 to release mouse" +msgstr "Pritisnite %1 za izpust miške" -msgid "Press %s or middle button to release mouse" -msgstr "Pritisnite %s ali srednji gumb za izpust miške" +msgid "Press %1 or middle button to release mouse" +msgstr "Pritisnite %1 ali srednji gumb za izpust miške" msgid "Bus" msgstr "Vodilo" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index 61152c663..e33dbfe21 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -630,8 +630,8 @@ msgstr "Allvarligt fel" msgid " - PAUSED" msgstr " - PAUSAD" -msgid "Press %s to return to windowed mode." -msgstr "Tryck på %s för att återvända till fönsterläge." +msgid "Press %1 to return to windowed mode." +msgstr "Tryck på %1 för att återvända till fönsterläge." msgid "Speed" msgstr "Hastighet" @@ -717,11 +717,11 @@ msgstr "Andra tillbehör" msgid "Click to capture mouse" msgstr "Klicka för att fånga upp musen" -msgid "Press %s to release mouse" -msgstr "Tryck på %s för att släppa musen" +msgid "Press %1 to release mouse" +msgstr "Tryck på %1 för att släppa musen" -msgid "Press %s or middle button to release mouse" -msgstr "Tryck på %s eller mellersta musknappen för att släppa musen" +msgid "Press %1 or middle button to release mouse" +msgstr "Tryck på %1 eller mellersta musknappen för att släppa musen" msgid "Bus" msgstr "Buss" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index de111c59b..24c1c0ba0 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -630,8 +630,8 @@ msgstr "Kritik hata" msgid " - PAUSED" msgstr " - DURAKLATILDI" -msgid "Press %s to return to windowed mode." -msgstr "Pencere moduna geri dönmek için %s tuşlarına basın." +msgid "Press %1 to return to windowed mode." +msgstr "Pencere moduna geri dönmek için %1 tuşlarına basın." msgid "Speed" msgstr "Hız" @@ -717,11 +717,11 @@ msgstr "Diğer cihazlar" msgid "Click to capture mouse" msgstr "Farenin yakalanması için tıklayın" -msgid "Press %s to release mouse" -msgstr "Farenin bırakılması için %s tuşlarına basın" +msgid "Press %1 to release mouse" +msgstr "Farenin bırakılması için %1 tuşlarına basın" -msgid "Press %s or middle button to release mouse" -msgstr "Farenin bırakılması için %s tuşlarına veya tekerlek tuşuna basın" +msgid "Press %1 or middle button to release mouse" +msgstr "Farenin bırakılması için %1 tuşlarına veya tekerlek tuşuna basın" msgid "Bus" msgstr "Veri yolu" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index db9b73491..68b50771a 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -630,8 +630,8 @@ msgstr "Непереробна помилка" msgid " - PAUSED" msgstr " - ПРИЗУПИНЕННЯ" -msgid "Press %s to return to windowed mode." -msgstr "Натисніть %s для повернення у віконний режим." +msgid "Press %1 to return to windowed mode." +msgstr "Натисніть %1 для повернення у віконний режим." msgid "Speed" msgstr "Швидкість" @@ -717,11 +717,11 @@ msgstr "Інша периферія" msgid "Click to capture mouse" msgstr "Клацніть мишею для захвату курсора" -msgid "Press %s to release mouse" -msgstr "Натисніть %s, щоб звільнити курсор" +msgid "Press %1 to release mouse" +msgstr "Натисніть %1, щоб звільнити курсор" -msgid "Press %s or middle button to release mouse" -msgstr "Натисніть %s або середню кнопку миші, щоб звільнити курсор" +msgid "Press %1 or middle button to release mouse" +msgstr "Натисніть %1 або середню кнопку миші, щоб звільнити курсор" msgid "Bus" msgstr "Шина" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index e21466a18..8632234df 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -630,8 +630,8 @@ msgstr "Lỗi nghiêm trọng" msgid " - PAUSED" msgstr " - TẠM DỪNG" -msgid "Press %s to return to windowed mode." -msgstr "Bấm %s để quay lại chế độ cửa sổ." +msgid "Press %1 to return to windowed mode." +msgstr "Bấm %1 để quay lại chế độ cửa sổ." msgid "Speed" msgstr "Vận tốc" @@ -717,11 +717,11 @@ msgstr "Thiết bị ngoại vi khác" msgid "Click to capture mouse" msgstr "Nhấp vào khung hình để 'nhốt' chuột vào" -msgid "Press %s to release mouse" -msgstr "Nhấn %s để thả chuột" +msgid "Press %1 to release mouse" +msgstr "Nhấn %1 để thả chuột" -msgid "Press %s or middle button to release mouse" -msgstr "Nhấn %s hoặc nhấp chuột giữa để thả chuột" +msgid "Press %1 or middle button to release mouse" +msgstr "Nhấn %1 hoặc nhấp chuột giữa để thả chuột" msgid "Bus" msgstr "Bus" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index c29e40dfb..194db4f3d 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -630,8 +630,8 @@ msgstr "致命错误" msgid " - PAUSED" msgstr " - 已暂停" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "按下 Ctrl+Alt+PgDn 返回到窗口模式。" +msgid "Press %1 to return to windowed mode." +msgstr "按下 %1 返回到窗口模式。" msgid "Speed" msgstr "速度" @@ -717,11 +717,11 @@ msgstr "其他外围设备" msgid "Click to capture mouse" msgstr "单击窗口捕捉鼠标" -msgid "Press %s to release mouse" -msgstr "按下 %s 释放鼠标" +msgid "Press %1 to release mouse" +msgstr "按下 %1 释放鼠标" -msgid "Press %s or middle button to release mouse" -msgstr "按下 %s 或鼠标中键释放鼠标" +msgid "Press %1 or middle button to release mouse" +msgstr "按下 %1 或鼠标中键释放鼠标" msgid "Bus" msgstr "总线" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 7de6f8cd3..3bdf6b823 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -630,8 +630,8 @@ msgstr "致命錯誤" msgid " - PAUSED" msgstr " - 已暫停" -msgid "Press Ctrl+Alt+PgDn to return to windowed mode." -msgstr "按下 Ctrl+Alt+PgDn 返回到視窗模式。" +msgid "Press %1 to return to windowed mode." +msgstr "按下 %1 返回到視窗模式。" msgid "Speed" msgstr "速度" @@ -717,11 +717,11 @@ msgstr "其他周邊裝置" msgid "Click to capture mouse" msgstr "點擊視窗捕捉滑鼠" -msgid "Press %s to release mouse" -msgstr "按下 %s 釋放滑鼠" +msgid "Press %1 to release mouse" +msgstr "按下 %1 釋放滑鼠" -msgid "Press %s or middle button to release mouse" -msgstr "按下 %s 或滑鼠中鍵釋放滑鼠" +msgid "Press %1 or middle button to release mouse" +msgstr "按下 %1 或滑鼠中鍵釋放滑鼠" msgid "Bus" msgstr "匯流排" diff --git a/src/qt/qt_keybind.cpp b/src/qt/qt_keybind.cpp index c7ed894b3..e6e87a5e2 100644 --- a/src/qt/qt_keybind.cpp +++ b/src/qt/qt_keybind.cpp @@ -90,7 +90,7 @@ KeyBinder::BindKey(QWidget* widget, QString CurValue) KeyBinder kb(widget); kb.setWindowTitle(tr("Bind Key")); kb.setFixedSize(kb.minimumSizeHint()); - kb.findChild()->setKeySequence(QKeySequence::fromString(CurValue)); + kb.findChild()->setKeySequence(QKeySequence::fromString(CurValue, QKeySequence::NativeText)); kb.setEnabled(true); if (kb.exec() == QDialog::Accepted) { diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index e966e043a..3aa29f7f4 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1347,10 +1347,9 @@ MainWindow::on_actionFullscreen_triggered() if (video_fullscreen_first) { bool wasCaptured = mouse_capture == 1; - char strFullscreen[100]; - sprintf(strFullscreen, qPrintable(tr("Press %s to return to windowed mode.")), acc_keys[FindAccelerator("fullscreen")].seq); - - QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), QString(strFullscreen), QMessageBox::Ok, this); + QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), + tr("Press %1 to return to windowed mode.").arg(QKeySequence(acc_keys[FindAccelerator("fullscreen")].seq, QKeySequence::PortableText).toString(QKeySequence::NativeText)), + QMessageBox::Ok, this); QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); questionbox.setCheckBox(chkbox); chkbox->setChecked(!video_fullscreen_first); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index be40452fd..a8c25bc2d 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -571,8 +572,6 @@ c16stombs(char dst[], const uint16_t src[], int len) } #endif -# define MOUSE_CAPTURE_KEYSEQ "F8+F12" - #ifdef _WIN32 # if defined(__amd64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) # define LIB_NAME_GS "gsdll64.dll" @@ -595,14 +594,8 @@ ProgSettings::reloadStrings() { translatedstrings.clear(); translatedstrings[STRING_MOUSE_CAPTURE] = QCoreApplication::translate("", "Click to capture mouse").toStdWString(); - - char mouseCaptureKeyseq[100]; - sprintf(mouseCaptureKeyseq, qPrintable(QCoreApplication::translate("", "Press %s to release mouse")), acc_keys[FindAccelerator("release_mouse")].seq); - translatedstrings[STRING_MOUSE_RELEASE] = QString(mouseCaptureKeyseq).toStdWString(); - - sprintf(mouseCaptureKeyseq, qPrintable(QCoreApplication::translate("", "Press %s or middle button to release mouse")), acc_keys[FindAccelerator("release_mouse")].seq); - translatedstrings[STRING_MOUSE_RELEASE_MMB] = QString(mouseCaptureKeyseq).toStdWString(); - + translatedstrings[STRING_MOUSE_RELEASE] = QCoreApplication::translate("", "Press %1 to release mouse").arg(QKeySequence(acc_keys[FindAccelerator("release_mouse")].seq, QKeySequence::PortableText).toString(QKeySequence::NativeText)).toStdWString(); + translatedstrings[STRING_MOUSE_RELEASE_MMB] = QCoreApplication::translate("", "Press %1 or middle button to release mouse").arg(QKeySequence(acc_keys[FindAccelerator("release_mouse")].seq, QKeySequence::PortableText).toString(QKeySequence::NativeText)).toStdWString(); translatedstrings[STRING_INVALID_CONFIG] = QCoreApplication::translate("", "Invalid configuration").toStdWString(); translatedstrings[STRING_NO_ST506_ESDI_CDROM] = QCoreApplication::translate("", "MFM/RLL or ESDI CD-ROM drives never existed").toStdWString(); translatedstrings[STRING_PCAP_ERROR_NO_DEVICES] = QCoreApplication::translate("", "No PCap devices found").toStdWString(); diff --git a/src/qt/qt_settingsinput.cpp b/src/qt/qt_settingsinput.cpp index f3729ab3f..a7000414c 100644 --- a/src/qt/qt_settingsinput.cpp +++ b/src/qt/qt_settingsinput.cpp @@ -162,7 +162,7 @@ SettingsInput::refreshInputList() for (int x=0;xtableKeys->setItem(x, 0, new QTableWidgetItem(tr(acc_keys_t[x].desc))); - ui->tableKeys->setItem(x, 1, new QTableWidgetItem(acc_keys_t[x].seq)); + ui->tableKeys->setItem(x, 1, new QTableWidgetItem(QKeySequence(acc_keys_t[x].seq, QKeySequence::PortableText).toString(QKeySequence::NativeText))); ui->tableKeys->setItem(x, 2, new QTableWidgetItem(acc_keys_t[x].name)); } } @@ -201,7 +201,7 @@ SettingsInput::on_tableKeys_cellDoubleClicked(int row, int col) // so we don't test against shortcuts the user already changed. for(int x=0;xshowMessage(MBX_ANSI & MBX_INFO, "Bind conflict", "This key combo is already in use", false); @@ -212,12 +212,12 @@ SettingsInput::on_tableKeys_cellDoubleClicked(int row, int col) // Go ahead and apply the bind. // Find the correct accelerator key entry - int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(row,2)->text())); + int accKeyID = FindAccelerator(ui->tableKeys->item(row,2)->text().toUtf8().constData()); if (accKeyID < 0) return; // this should never happen // Make the change cell->setText(keyseq.toString(QKeySequence::NativeText)); - strcpy(acc_keys_t[accKeyID].seq, qPrintable(keyseq.toString(QKeySequence::NativeText))); + strcpy(acc_keys_t[accKeyID].seq, keyseq.toString(QKeySequence::PortableText).toUtf8().constData()); refreshInputList(); } @@ -242,7 +242,7 @@ SettingsInput::on_pushButtonClearBind_clicked() cell->setText(""); // Find the correct accelerator key entry - int accKeyID = FindAccelerator(qPrintable(ui->tableKeys->item(cell->row(),2)->text())); + int accKeyID = FindAccelerator(ui->tableKeys->item(cell->row(),2)->text().toUtf8().constData()); if (accKeyID < 0) return; // this should never happen // Make the change From 44376db7f243e6f890411dd8a2383a359de437be Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 19:29:15 +0200 Subject: [PATCH 0876/1190] Ambra DP60: It is the original Batman, so no RZ-1000, and FDC37C665 controlling primary IDE. --- src/machine/m_at_socket4.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 92f88fbe6..03ff03a23 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -219,7 +219,22 @@ machine_at_ambradp60_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_premiere_common_init(model, 0); + machine_at_common_init_ex(model, 2); + + device_add(&amstrad_megapc_nvr_device); + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&keyboard_ps2_phoenix_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_ide_pri_device); + device_add(&intel_flash_bxt_ami_device); device_add(&i430lx_device); From c42f1e4d122efc15c832858f264683cea844d598 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Wed, 7 May 2025 21:01:43 +0500 Subject: [PATCH 0877/1190] Remove the fullscreen hotkey message No longer needed after the hotkeys to enter and exit full screen mode were merged into one --- src/86box.c | 1 - src/config.c | 8 -------- src/include/86box/86box.h | 1 - src/include/86box/video.h | 1 - src/qt/languages/86box.pot | 11 +---------- src/qt/languages/ca-ES.po | 13 ++----------- src/qt/languages/cs-CZ.po | 13 ++----------- src/qt/languages/de-DE.po | 13 ++----------- src/qt/languages/en-GB.po | 4 ++-- src/qt/languages/es-ES.po | 13 ++----------- src/qt/languages/fi-FI.po | 13 ++----------- src/qt/languages/fr-FR.po | 13 ++----------- src/qt/languages/hr-HR.po | 13 ++----------- src/qt/languages/hu-HU.po | 13 ++----------- src/qt/languages/it-IT.po | 13 ++----------- src/qt/languages/ja-JP.po | 13 ++----------- src/qt/languages/ko-KR.po | 13 ++----------- src/qt/languages/nl-NL.po | 13 ++----------- src/qt/languages/pl-PL.po | 13 ++----------- src/qt/languages/pt-BR.po | 13 ++----------- src/qt/languages/pt-PT.po | 13 ++----------- src/qt/languages/ru-RU.po | 13 ++----------- src/qt/languages/sk-SK.po | 13 ++----------- src/qt/languages/sl-SI.po | 13 ++----------- src/qt/languages/sv-SE.po | 13 ++----------- src/qt/languages/tr-TR.po | 13 ++----------- src/qt/languages/uk-UA.po | 13 ++----------- src/qt/languages/vi-VN.po | 13 ++----------- src/qt/languages/zh-CN.po | 13 ++----------- src/qt/languages/zh-TW.po | 13 ++----------- src/qt/qt_mainwindow.cpp | 20 -------------------- src/qt/qt_progsettings.cpp | 2 -- src/qt/qt_progsettings.ui | 7 ------- 33 files changed, 51 insertions(+), 316 deletions(-) diff --git a/src/86box.c b/src/86box.c index 1d7a73060..25dc0e6e9 100644 --- a/src/86box.c +++ b/src/86box.c @@ -168,7 +168,6 @@ int vid_api = 0; /* (C) video r int vid_cga_contrast = 0; /* (C) video */ int video_fullscreen = 0; /* (C) video */ int video_fullscreen_scale = 0; /* (C) video */ -int video_fullscreen_first = 0; /* (C) video */ int enable_overscan = 0; /* (C) video */ int force_43 = 0; /* (C) video */ int video_filter_method = 1; /* (C) video */ diff --git a/src/config.c b/src/config.c index 52a80763a..dfe0190ac 100644 --- a/src/config.c +++ b/src/config.c @@ -128,8 +128,6 @@ load_general(void) video_fullscreen_scale = ini_section_get_int(cat, "video_fullscreen_scale", 1); - video_fullscreen_first = ini_section_get_int(cat, "video_fullscreen_first", 1); - video_filter_method = ini_section_get_int(cat, "video_filter_method", 1); inhibit_multimedia_keys = ini_section_get_int(cat, "inhibit_multimedia_keys", 0); @@ -1832,7 +1830,6 @@ config_load(void) gfxcard[0] = video_get_video_from_internal_name("cga"); vid_api = plat_vidapi("default"); vid_resize = 0; - video_fullscreen_first = 1; video_fullscreen_scale = 1; time_sync = TIME_SYNC_ENABLED; hdc_current[0] = hdc_get_from_internal_name("none"); @@ -1955,11 +1952,6 @@ save_general(void) else ini_section_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); - if (video_fullscreen_first == 1) - ini_section_delete_var(cat, "video_fullscreen_first"); - else - ini_section_set_int(cat, "video_fullscreen_first", video_fullscreen_first); - if (video_filter_method == 1) ini_section_delete_var(cat, "video_filter_method"); else diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index e19665535..76f311d17 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -121,7 +121,6 @@ extern int dpi_scale; /* (C) DPI scaling of the emulated s extern int vid_api; /* (C) video renderer */ extern int vid_cga_contrast; /* (C) video */ extern int video_fullscreen; /* (C) video */ -extern int video_fullscreen_first; /* (C) video */ extern int video_fullscreen_scale; /* (C) video */ extern int enable_overscan; /* (C) video */ extern int force_43; /* (C) video */ diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 1b50d86f8..bbcc94fe7 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -189,7 +189,6 @@ extern uint32_t pal_lookup[256]; #endif extern int video_fullscreen; extern int video_fullscreen_scale; -extern int video_fullscreen_first; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; extern uint8_t fontdat2[2048][8]; diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index d5152cd3d..ac379b171 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -630,9 +630,6 @@ msgstr "" msgid " - PAUSED" msgstr "" -msgid "Press %1 to return to windowed mode." -msgstr "" - msgid "Speed" msgstr "" @@ -864,9 +861,6 @@ msgstr "" msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "" -msgid "Entering fullscreen mode" -msgstr "" - msgid "Don't show this message again" msgstr "" @@ -1305,7 +1299,7 @@ msgstr "" msgid "\nFalling back to software rendering." msgstr "" -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" msgstr "" msgid "This machine might have been moved or copied." @@ -2112,9 +2106,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index 7fe87eb1a..632af979a 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -630,9 +630,6 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press %1 to return to windowed mode." -msgstr "Premeu %1 per tornar al mode de finestra." - msgid "Speed" msgstr "Velocitat" @@ -864,9 +861,6 @@ msgstr "%1 és necessària per a la conversió automàtica de fitxers PostScript msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 és necessària per a la conversió automàtica de fitxers PCL a PDF.\n\nQualsevol document enviat a la impressora genèrica PCL es desarà com a fitxer Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Entrant en mode pantalla completa" - msgid "Don't show this message again" msgstr "No mostreu més aquest missatge" @@ -1305,8 +1299,8 @@ msgstr "Error en inicialitzar OpenGL" msgid "\nFalling back to software rendering." msgstr "\nTornant al renderitzador software." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Quan seleccioneu imatges de suports (CD-ROM, disquet, etc.), el diàleg obert s’iniciarà al mateix directori que el fitxer de configuració 86Box. Aquesta configuració només farà una diferència en les macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Quan seleccioneu imatges de suports (CD-ROM, disquet, etc.), el diàleg obert s’iniciarà al mateix directori que el fitxer de configuració 86Box. Aquesta configuració només farà una diferència en les macOS.

" msgid "This machine might have been moved or copied." msgstr "Aquesta màquina podria haver estat moguda o copiada." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 59a582ca6..593020962 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -630,9 +630,6 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENO" -msgid "Press %1 to return to windowed mode." -msgstr "Stiskněte %1 pro návrat z režimu celé obrazovky." - msgid "Speed" msgstr "Rychlost" @@ -864,9 +861,6 @@ msgstr "%1 je potřeba pro automatický převod PostScript dokumentů do PDF.\n\ msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 je potřeba pro automatický převod PCL dokumentů do PDF.\n\nJakékoliv dokumenty vytisknuté přes obecnou PCL-ovou tiskárnu budou uloženy jako Printer Command Language (.pcl) soubory." -msgid "Entering fullscreen mode" -msgstr "Vstup do režimu celé obrazovky" - msgid "Don't show this message again" msgstr "Nezobrazovat dále tuto zprávu" @@ -1305,8 +1299,8 @@ msgstr "Chyba při inicializaci OpenGL" msgid "\nFalling back to software rendering." msgstr "\nNávrat k softwarovému vykreslování." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Při výběru obrazů médií (CD-ROM, disketa atd.) se otevřené dialogové okno spustí ve stejném adresáři jako konfigurační soubor 86Box. Toto nastavení bude mít pravděpodobně význam pouze v systému MacOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Při výběru obrazů médií (CD-ROM, disketa atd.) se otevřené dialogové okno spustí ve stejném adresáři jako konfigurační soubor 86Box. Toto nastavení bude mít pravděpodobně význam pouze v systému MacOS.

" msgid "This machine might have been moved or copied." msgstr "Tento počítač mohl být přemístěn nebo zkopírován." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 0615dada4..439346608 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -630,9 +630,6 @@ msgstr "Fataler Fehler" msgid " - PAUSED" msgstr " - PAUSIERT" -msgid "Press %1 to return to windowed mode." -msgstr "%1 ab, zur Rückkehr in den Fenstermodus." - msgid "Speed" msgstr "Geschwindigkeit" @@ -864,9 +861,6 @@ msgstr "%1 wird zur automatischen Konvertierung von PostScript-Dateien ins PDF-F msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 wird zur automatischen Konvertierung von PCL-Dateien ins PDF-Format benötigt.\n\nSämtliche an den generischen PCL-Drucker gesendete Dateien werden als Printer Command Language (*.pcl) Dateien gesichert." -msgid "Entering fullscreen mode" -msgstr "Vollbildmodus wird aktiviert" - msgid "Don't show this message again" msgstr "Diese Nachricht nicht mehr anzeigen" @@ -1305,8 +1299,8 @@ msgstr "Fehler beim Initialisieren von OpenGL" msgid "\nFalling back to software rendering." msgstr "\nRückgriff auf Software-Rendering." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Bei der Auswahl von Medien-Abbildern (CD-ROM, Diskette usw.) wird der Öffnungsdialog im selben Verzeichnis wie die 86Box-Konfigurationsdatei gestartet. Diese Einstellung macht wahrscheinlich nur unter macOS einen Unterschied.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Bei der Auswahl von Medien-Abbildern (CD-ROM, Diskette usw.) wird der Öffnungsdialog im selben Verzeichnis wie die 86Box-Konfigurationsdatei gestartet. Diese Einstellung macht wahrscheinlich nur unter macOS einen Unterschied.

" msgid "This machine might have been moved or copied." msgstr "Dieses System wurde möglicherweise verschoben oder kopiert." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index 8cc29a71a..550bc3ab4 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -39,8 +39,8 @@ msgstr "Synchronise with video" msgid "Error initializing OpenGL" msgstr "Error initialising OpenGL" -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialogue will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

When selecting media images (CD-ROM, floppy, etc.) the open dialogue will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" msgid "Color (generic)" msgstr "Colour (generic)" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 1f9cf10b2..363d56c45 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -630,9 +630,6 @@ msgstr "Error fatal" msgid " - PAUSED" msgstr " - EN PAUSA" -msgid "Press %1 to return to windowed mode." -msgstr "Pulsa %1 para volver a modo ventana." - msgid "Speed" msgstr "Velocidad" @@ -864,9 +861,6 @@ msgstr "%1 es necesaria para la conversión automática de archivos PostScript a msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 es necesaria para la conversión automática de archivos PCL a PDF.\n\nCualquier documento enviado a la impresora genérica PCL se guardará como archivo Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Entrando en modo pantalla completa" - msgid "Don't show this message again" msgstr "No mostrar más este mensaje" @@ -1304,8 +1298,8 @@ msgstr "Error al inicializar OpenGL" msgid "\nFalling back to software rendering." msgstr "\nRecurrir al renderizado por software." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Al seleccionar imágenes multimedia (CD-ROM, disquete, etc.), el diálogo de apertura se iniciará en el mismo directorio que el archivo de configuración de 86Box. Es probable que este ajuste sólo suponga una diferencia en macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Al seleccionar imágenes multimedia (CD-ROM, disquete, etc.), el diálogo de apertura se iniciará en el mismo directorio que el archivo de configuración de 86Box. Es probable que este ajuste sólo suponga una diferencia en macOS.

" msgid "This machine might have been moved or copied." msgstr "Esta máquina puede haber sido movida o copiado." @@ -2105,9 +2099,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index 4979332ac..ae4f78bb5 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -630,9 +630,6 @@ msgstr "Vakava virhe" msgid " - PAUSED" msgstr " - TAUKO" -msgid "Press %1 to return to windowed mode." -msgstr "Paina %1 palataksesi ikkunoituun tilaan." - msgid "Speed" msgstr "Nopeus" @@ -864,9 +861,6 @@ msgstr "%1 vaaditaan PostScript-tiedostojen automaattiseen muuntamiseen PDF-tied msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 vaaditaan PCL-tiedostojen automaattiseen muuntamiseen PDF-tiedostoiksi.\n\nKaikki geneeriselle PCL-tulostimelle lähetetyt asiakirjat tallennetaan Printer Command Language (.ps) -tiedostoina." -msgid "Entering fullscreen mode" -msgstr "Siirrytään koko näytön tilaan" - msgid "Don't show this message again" msgstr "Älä näytä tätä viestiä uudelleen" @@ -1308,8 +1302,8 @@ msgstr "Virhe OpenGL:n alustamisessa" msgid "\nFalling back to software rendering." msgstr "\nPaluu ohjelmistoalustusöintiin." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Kun valitset mediakuvia (CD-ROM, levykkeet jne.), avausikkuna käynnistyy samaan hakemistoon kuin 86Boxin konfigurointitiedosto. Tällä asetuksella on todennäköisesti merkitystä vain macOS-käyttöjärjestelmässä.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Kun valitset mediakuvia (CD-ROM, levykkeet jne.), avausikkuna käynnistyy samaan hakemistoon kuin 86Boxin konfigurointitiedosto. Tällä asetuksella on todennäköisesti merkitystä vain macOS-käyttöjärjestelmässä.

" msgid "This machine might have been moved or copied." msgstr "Kone on saatettu siirtää tai kopioida." @@ -2109,9 +2103,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 58de2e4d1..87530590a 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -630,9 +630,6 @@ msgstr "Erreur fatale" msgid " - PAUSED" msgstr " - EN PAUSE" -msgid "Press %1 to return to windowed mode." -msgstr "Appuyez sur %1 pour revenir au mode fenêtré." - msgid "Speed" msgstr "Vitesse" @@ -864,9 +861,6 @@ msgstr "%1 est nécessaire pour la conversion automatique des fichiers PostScrip msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 est nécessaire pour la conversion automatique des fichiers PCL en PDF.\n\nTous les documents envoyés à l'imprimante générique PCL seront sauvés en tant quefichiers Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Entrer en mode plein écran" - msgid "Don't show this message again" msgstr "Ne pas montrer ce message à nouveau" @@ -1305,8 +1299,8 @@ msgstr "Erreur d'initialisation d'OpenGL" msgid "\nFalling back to software rendering." msgstr "\nSe rabattre sur le rendu logiciel." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Lors de la sélection d'images multimédia (CD-ROM, disquette, etc.), la boîte de dialogue d'ouverture démarrera dans le même répertoire que le fichier de configuration de 86Box. Ce paramètre ne fera probablement une différence que sur macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Lors de la sélection d'images multimédia (CD-ROM, disquette, etc.), la boîte de dialogue d'ouverture démarrera dans le même répertoire que le fichier de configuration de 86Box. Ce paramètre ne fera probablement une différence que sur macOS.

" msgid "This machine might have been moved or copied." msgstr "Cette machine peut avoir été déplacée ou copiée." @@ -2106,9 +2100,6 @@ msgstr "Demander confirmation avant Hard Reset" msgid "Ask for confirmation before quitting" msgstr "Demander confirmation avant de quitter" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Afficher Raccourcis Clavier avant de passer en plein écran" - msgid "Options" msgstr "Options" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index 5f0e60b21..50dd298c2 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -630,9 +630,6 @@ msgstr "Fatalna greška" msgid " - PAUSED" msgstr " - ZASTAO" -msgid "Press %1 to return to windowed mode." -msgstr "Pritisnite %1 za povratak u prozorski način rada." - msgid "Speed" msgstr "Brzina" @@ -864,9 +861,6 @@ msgstr "%1 je potrebno za automatsku konverziju PostScript datoteke u PDF datote msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 je potrebno za automatsku konverziju PCL datoteke u PDF datoteke.\n\nSvi dokumenti poslani na generički PCL pisač bit će spremljeni kao Printer Command Language (.pcl) datoteke." -msgid "Entering fullscreen mode" -msgstr "Ulazim u cijelozaslonski način" - msgid "Don't show this message again" msgstr "Ne pokazi više ovu poruku" @@ -1305,8 +1299,8 @@ msgstr "Nije moguće inicijalizirati OpenGL" msgid "\nFalling back to software rendering." msgstr "\nVraća se na softverski renderer." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Prilikom odabira medijskih slika (CD-ROM, diskete itd.), otvoreni dijalog zopočet će u istom direktoriju kao i konfiguracijska datoteka 86Box-a. Razlika će vjerojatno biti primjetna samo na macOS-u.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Prilikom odabira medijskih slika (CD-ROM, diskete itd.), otvoreni dijalog zopočet će u istom direktoriju kao i konfiguracijska datoteka 86Box-a. Razlika će vjerojatno biti primjetna samo na macOS-u.

" msgid "This machine might have been moved or copied." msgstr "Ovaj je sistem mogao biti premješten ili kopiran." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/hu-HU.po b/src/qt/languages/hu-HU.po index 3398859d2..981edad71 100644 --- a/src/qt/languages/hu-HU.po +++ b/src/qt/languages/hu-HU.po @@ -630,9 +630,6 @@ msgstr "Végzetes hiba" msgid " - PAUSED" msgstr " - SZÜNETELT" -msgid "Press %1 to return to windowed mode." -msgstr "Használja a %1 gombokat az ablakhoz való visszatéréshez." - msgid "Speed" msgstr "Sebesség" @@ -864,9 +861,6 @@ msgstr "%1 szükséges a PostScript fájlok PDF formátumba való automatikus ko msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Lnaugage (.pcl) files." msgstr "%1 szükséges a PCL fájlok PDF formátumba való automatikus konvertálásához.\n\nAz általános PCL nyomtatóra küldött dokumentumok Printer Command Language (.pcl) fájlként kerülnek mentésre." -msgid "Entering fullscreen mode" -msgstr "Teljes képernyős módra váltás" - msgid "Don't show this message again" msgstr "Ne jelenítse meg újra ezt az üzenetet " @@ -1305,8 +1299,8 @@ msgstr "Hiba az OpenGL inicializálásában" msgid "\nFalling back to software rendering." msgstr "\nVisszatérés a szoftveres rendereléshez." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>A médiaképek (CD-ROM, floppy stb.) kiválasztásakor a megnyitási párbeszédpanel ugyanabban a könyvtárban indul, mint a 86Box konfigurációs fájl. Ez a beállítás valószínűleg csak a macOS rendszerben jelent különbséget.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

A médiaképek (CD-ROM, floppy stb.) kiválasztásakor a megnyitási párbeszédpanel ugyanabban a könyvtárban indul, mint a 86Box konfigurációs fájl. Ez a beállítás valószínűleg csak a macOS rendszerben jelent különbséget.

" msgid "This machine might have been moved or copied." msgstr "Lehet, hogy ezt a gépet áthelyezték vagy lemásolták." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index d45a0080b..877032c85 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -630,9 +630,6 @@ msgstr "Errore fatale" msgid " - PAUSED" msgstr " - IN PAUSA" -msgid "Press %1 to return to windowed mode." -msgstr "Usa %1 per tornare alla modalità finestra." - msgid "Speed" msgstr "Velocità" @@ -864,9 +861,6 @@ msgstr "%1 è richiesto per la conversione automatica di file PostScript a file msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 è richiesto per la conversione automatica di file PCL a file PDF.\n\nQualsiasi documento mandato alla stampante generica PCL sarà salvato come file Printer Command Language (.cl)." -msgid "Entering fullscreen mode" -msgstr "Entrando nella modalità schermo intero" - msgid "Don't show this message again" msgstr "Non mostrare più questo messaggio" @@ -1305,8 +1299,8 @@ msgstr "Errore nell'inizializzazione di OpenGL" msgid "\nFalling back to software rendering." msgstr "\nRicaduta sul rendering software." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Quando si selezionano immagini multimediali (CD-ROM, floppy, ecc.) la finestra di dialogo di apertura si avvia nella stessa directory del file di configurazione di 86Box. Questa impostazione probabilmente farà la differenza solo su macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Quando si selezionano immagini multimediali (CD-ROM, floppy, ecc.) la finestra di dialogo di apertura si avvia nella stessa directory del file di configurazione di 86Box. Questa impostazione probabilmente farà la differenza solo su macOS.

" msgid "This machine might have been moved or copied." msgstr "Questa macchina potrebbe essere stata spostata o copiata." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 7883f8a5a..5efd599ed 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -630,9 +630,6 @@ msgstr "致命的なエラー" msgid " - PAUSED" msgstr " - 一時停止" -msgid "Press %1 to return to windowed mode." -msgstr "%1でウィンドウ モードに戻ります。" - msgid "Speed" msgstr "速度" @@ -864,9 +861,6 @@ msgstr "PostScriptファイルをPDFに自動変換するには%1が必要です msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "PCLファイルをPDFに自動変換するには%1が必要です。\n\n汎用PCLプリンターに送信された文書は、Printer Command Language (.pcl) ファイルとして保存されます。" -msgid "Entering fullscreen mode" -msgstr "全画面モードを入力" - msgid "Don't show this message again" msgstr "今後、このメッセージを表示しない" @@ -1305,8 +1299,8 @@ msgstr "OpenGLの初期化エラー" msgid "\nFalling back to software rendering." msgstr "\nソフトウェアレンダリングに逆戻り。" -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>メディアイメージ(CD-ROM、フロッピーなど)を選択するとき、オープンダイアログは86Box設定ファイルと同じディレクトリで開始します。この設定は、おそらく macOS でのみ違いがあります。</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

メディアイメージ(CD-ROM、フロッピーなど)を選択するとき、オープンダイアログは86Box設定ファイルと同じディレクトリで開始します。この設定は、おそらく macOS でのみ違いがあります。

" msgid "This machine might have been moved or copied." msgstr "このマシンは移動されたかコピーされた可能性がある。" @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index a9ed452d6..89dbf5809 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -630,9 +630,6 @@ msgstr "치명적인 오류" msgid " - PAUSED" msgstr " - 일시 중지됨" -msgid "Press %1 to return to windowed mode." -msgstr "%1 키를 누르면 창 모드로 전환합니다." - msgid "Speed" msgstr "속도" @@ -864,9 +861,6 @@ msgstr "%1은(는) PostScript 파일을 PDF로 자동변환하는 데에 필요 msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1은(는) PCL 파일을 PDF로 자동변환하는 데에 필요합니다.\n\n표준 PCL 프린터로 보내신 임의의 문서는 Printer Command Language (.pcl) 파일로 저장됩니다." -msgid "Entering fullscreen mode" -msgstr "전체 화면으로 전환" - msgid "Don't show this message again" msgstr "이 메시지 그만 보기" @@ -1305,8 +1299,8 @@ msgstr "OpenGL 초기화 중 오류 발생" msgid "\nFalling back to software rendering." msgstr "\n소프트웨어 렌더링으로 돌아가기." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>미디어 이미지(CD-ROM, 플로피 등)를 선택하면 86Box 구성 파일과 동일한 디렉터리에서 열기 대화 상자가 시작됩니다. 이 설정은 macOS에서만 차이가 있을 수 있습니다.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

미디어 이미지(CD-ROM, 플로피 등)를 선택하면 86Box 구성 파일과 동일한 디렉터리에서 열기 대화 상자가 시작됩니다. 이 설정은 macOS에서만 차이가 있을 수 있습니다.

" msgid "This machine might have been moved or copied." msgstr "이 컴퓨터가 이동되었거나 복사되었을 수 있습니다." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 2859916d7..aa87cd37d 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -630,9 +630,6 @@ msgstr "Fatale fout" msgid " - PAUSED" msgstr " - GEPAUZEERD" -msgid "Press %1 to return to windowed mode." -msgstr "Druk op %1 om terug te gaan naar de venstermodus." - msgid "Speed" msgstr "Snelheid" @@ -864,9 +861,6 @@ msgstr "%1 is vereist voor automatische conversie van PostScript-bestanden naar msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 is vereist voor automatische conversie van PCL-bestanden naar PDF.\n\nAlle documenten die naar de generieke PCL-printer worden gestuurd, worden opgeslagen als Printer Command Language (.pcl) bestanden." -msgid "Entering fullscreen mode" -msgstr "Volledig scherm modus openen" - msgid "Don't show this message again" msgstr "Dit bericht niet meer tonen" @@ -1305,8 +1299,8 @@ msgstr "Fout bij het initialiseren van OpenGL" msgid "\nFalling back to software rendering." msgstr "\nTerugvallen op software rendering." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Bij het selecteren van media-images (CD-ROM, floppy, etc.) zal de \"open dialoog\" starten in dezelfde map als het 86Box configuratiebestand. Deze instelling is doet er waarschijnlijk alleen toe op macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Bij het selecteren van media-images (CD-ROM, floppy, etc.) zal de \"open dialoog\" starten in dezelfde map als het 86Box configuratiebestand. Deze instelling is doet er waarschijnlijk alleen toe op macOS.

" msgid "This machine might have been moved or copied." msgstr "Deze machine is misschien verplaatst of gekopieerd." @@ -2106,9 +2100,6 @@ msgstr "Vraag om bevestiging voor een harde reset" msgid "Ask for confirmation before quitting" msgstr "Vraag om bevestiging voor afsluiten" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Toon een sneltoetsmelding bij het openen van de volledigschermmodus" - msgid "Options" msgstr "Opties" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 02bdc26fe..7433c1d65 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -630,9 +630,6 @@ msgstr "Fatalny błąd" msgid " - PAUSED" msgstr " - PAUSED" -msgid "Press %1 to return to windowed mode." -msgstr "Naciśnij klawisze %1 aby wrócić to trybu okna." - msgid "Speed" msgstr "Szybkość" @@ -864,9 +861,6 @@ msgstr "%1 jest wymagany do automatycznej konwersji plików PostScript do PDF.\n msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 jest wymagany do automatycznej konwersji plików PCL do PDF.\n\nDokumenty wysłane do generycznej drukarki PCL zostaną zapisane jako pliki Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Przechodzenie do trybu pełnoekranowego" - msgid "Don't show this message again" msgstr "Nie pokazuj więcej tego komunikatu" @@ -1305,8 +1299,8 @@ msgstr "Błąd inicjalizacji OpenGL" msgid "\nFalling back to software rendering." msgstr "\nPowrót do renderowania oprogramowania." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Podczas wybierania obrazów nośników (CD-ROM, dyskietka itp.) otwarte okno dialogowe rozpocznie się w tym samym katalogu, co plik konfiguracyjny 86Box. To ustawienie prawdopodobnie będzie miało znaczenie tylko na macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Podczas wybierania obrazów nośników (CD-ROM, dyskietka itp.) otwarte okno dialogowe rozpocznie się w tym samym katalogu, co plik konfiguracyjny 86Box. To ustawienie prawdopodobnie będzie miało znaczenie tylko na macOS.

" msgid "This machine might have been moved or copied." msgstr "To urządzenie mogło zostać przeniesione lub skopiowane." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 4fb974f4d..70e6d7b29 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -630,9 +630,6 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - PAUSADO" -msgid "Press %1 to return to windowed mode." -msgstr "Use %1 para retornar ao modo janela." - msgid "Speed" msgstr "Velocidade" @@ -864,9 +861,6 @@ msgstr "%1 é necessário para a conversão automática de arquivos PostScript p msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 é necessário para a conversão automática de arquivos PCL para PDF.\n\nQualquer documento enviado para a impressora genérica PCL será salvo como arquivos Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Entrando no modo de tela cheia" - msgid "Don't show this message again" msgstr "Não exibir esta mensagem novamente" @@ -1305,8 +1299,8 @@ msgstr "Erro ao inicializar o OpenGL" msgid "\nFalling back to software rendering." msgstr "\nVoltando à renderização de software." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Ao selecionar imagens de mídia (CD-ROM, disquete, etc.), a caixa de diálogo de abertura será iniciada no mesmo diretório do arquivo de configuração do 86Box. Essa configuração provavelmente só fará diferença no macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Ao selecionar imagens de mídia (CD-ROM, disquete, etc.), a caixa de diálogo de abertura será iniciada no mesmo diretório do arquivo de configuração do 86Box. Essa configuração provavelmente só fará diferença no macOS.

" msgid "This machine might have been moved or copied." msgstr "Essa máquina pode ter sido movida ou copiada." @@ -2106,9 +2100,6 @@ msgstr "Perguntar antes de reinicialização completa" msgid "Ask for confirmation before quitting" msgstr "Perguntar antes de sair" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Mostrar mensagem de atalho quando entrar em tela cheia" - msgid "Options" msgstr "Opções" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 86c40fc40..795d44e2b 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -630,9 +630,6 @@ msgstr "Erro fatal" msgid " - PAUSED" msgstr " - EM PAUSA" -msgid "Press %1 to return to windowed mode." -msgstr "Pressione %1 para voltar ao modo de janela." - msgid "Speed" msgstr "Velocidade" @@ -864,9 +861,6 @@ msgstr "%1 é requerido para a conversão automática de ficheiros PostScript pa msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 é requerido para a conversão automática de ficheiros PCL para ficheiros PDF.\n\nQualquer documento enviado para a impressora PCL genérica será gravado como um ficheiro Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "A entrar no modo de tela cheia" - msgid "Don't show this message again" msgstr "Não mostrar mais esta mensagem" @@ -1305,8 +1299,8 @@ msgstr "Erro ao inicializar o OpenGL" msgid "\nFalling back to software rendering." msgstr "\nRecuando para a renderização de software." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Ao selecionar imagens multimédia (CD-ROM, disquete, etc.) a caixa de diálogo de abertura irá começar no mesmo diretório que o ficheiro de configuração da 86Box. Esta configuração provavelmente só fará diferença no macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Ao selecionar imagens multimédia (CD-ROM, disquete, etc.) a caixa de diálogo de abertura irá começar no mesmo diretório que o ficheiro de configuração da 86Box. Esta configuração provavelmente só fará diferença no macOS.

" msgid "This machine might have been moved or copied." msgstr "Esta máquina pode ter sido deslocada ou copiada." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 899b905ac..af427d670 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -630,9 +630,6 @@ msgstr "Неустранимая ошибка" msgid " - PAUSED" msgstr " - ПАУЗА" -msgid "Press %1 to return to windowed mode." -msgstr "Нажмите %1 для возврата в оконный режим." - msgid "Speed" msgstr "Скорость" @@ -864,9 +861,6 @@ msgstr "Для автоматического преобразования фа msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "Для автоматического преобразования файлов PCL в PDF требуется %1.\n\nВсе документы, отправленные на стандартный принтер PCL, будут сохранены в виде файлов Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Вход в полноэкранный режим" - msgid "Don't show this message again" msgstr "Больше не показывать это сообщение" @@ -1305,8 +1299,8 @@ msgstr "Ошибка инициализации OpenGL" msgid "\nFalling back to software rendering." msgstr "\nПереключение на программный рендеринг." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>При выборе образов носителей (CD-ROM, дискет и т. д.) диалог открытия будет запускаться в том же каталоге, что и файл конфигурации 86Box. Эта настройка, скорее всего, будет иметь значение только на macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

При выборе образов носителей (CD-ROM, дискет и т. д.) диалог открытия будет запускаться в том же каталоге, что и файл конфигурации 86Box. Эта настройка, скорее всего, будет иметь значение только на macOS.

" msgid "This machine might have been moved or copied." msgstr "Возможно, эта машина была перемещена или скопирована." @@ -2112,9 +2106,6 @@ msgstr "Запрашивать подтверждение перед холод msgid "Ask for confirmation before quitting" msgstr "Запрашивать подтверждение перед выходом" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Показывать сообщение о горячей клавише при входе в полноэкранный режим" - msgid "Options" msgstr "Параметры" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 624715f76..ef89f831a 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -630,9 +630,6 @@ msgstr "Kritická chyba" msgid " - PAUSED" msgstr " - POZASTAVENÝ" -msgid "Press %1 to return to windowed mode." -msgstr "Stlačte %1 pre návrat z režimu celej obrazovky." - msgid "Speed" msgstr "Rýchlosť" @@ -864,9 +861,6 @@ msgstr "%1 je potrebná pre automatický prevod PostScript dokumentov do PDF.\n\ msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Lnaugage (.pcl) files." msgstr "%1 je potrebná pre automatický prevod PCL dokumentov do PDF.\n\nAkékoľvek dokumenty vytlačené cez všeobecnú PCLovú tlačiareň budú uložené ako Printer Command Language (.pcl) súbory." -msgid "Entering fullscreen mode" -msgstr "Vstup do režimu celej obrazovky" - msgid "Don't show this message again" msgstr "Nezobrazovať ďalej túto správu" @@ -1306,8 +1300,8 @@ msgstr "Chyba pri inicializácii OpenGL" msgid "\nFalling back to software rendering." msgstr "\nNávrat k softvérovému vykresľovaniu." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Pri výbere multimediálnych obrazov (CD-ROM, disketa atď.) sa dialógové okno otvorenia spustí v rovnakom adresári ako konfiguračný súbor 86Box. Toto nastavenie bude mať pravdepodobne význam len v systéme MacOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Pri výbere multimediálnych obrazov (CD-ROM, disketa atď.) sa dialógové okno otvorenia spustí v rovnakom adresári ako konfiguračný súbor 86Box. Toto nastavenie bude mať pravdepodobne význam len v systéme MacOS.

" msgid "This machine might have been moved or copied." msgstr "Tento stroj mohol byť premiestnený alebo skopírovaný." @@ -2107,9 +2101,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index d07a1eac4..d4fd10e43 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -630,9 +630,6 @@ msgstr "Kritična napaka" msgid " - PAUSED" msgstr " - ZAUSTAVLJEN" -msgid "Press %1 to return to windowed mode." -msgstr "Pritisnite %1 za povratek iz celozaslonskega načina." - msgid "Speed" msgstr "Hitrost" @@ -864,9 +861,6 @@ msgstr "%1 je potreben za samodejno pretvorbo datotek PostScript v PDF.\n\nVsi d msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Lnaugage (.pcl) files." msgstr "%1 je potreben za samodejno pretvorbo datotek PCL v PDF.\n\nVsi dokumenti, poslani generičnemu tiskalniku PCL bodo shranjeni kot datoteke Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Preklapljam v celozaslonski način" - msgid "Don't show this message again" msgstr "Ne pokaži več tega sporočila" @@ -1305,8 +1299,8 @@ msgstr "Napaka pri inicializaciji OpenGL" msgid "\nFalling back to software rendering." msgstr "\nVrnitev na programsko upodabljanje." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Pri izbiri medijskih slik (CD-ROM, disketa itd.) se bo odprto pogovorno okno začelo v istem imeniku kot konfiguracijska datoteka 86Box. Ta nastavitev bo verjetno imela pomen le v operacijskem sistemu MacOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Pri izbiri medijskih slik (CD-ROM, disketa itd.) se bo odprto pogovorno okno začelo v istem imeniku kot konfiguracijska datoteka 86Box. Ta nastavitev bo verjetno imela pomen le v operacijskem sistemu MacOS.

" msgid "This machine might have been moved or copied." msgstr "Ta naprava je bila morda premeščena ali kopirana." @@ -2106,9 +2100,6 @@ msgstr "Vprašaj za potrditev pred ponovnim zagonom" msgid "Ask for confirmation before quitting" msgstr "Vprašaj za potrditev pred izhodom" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Prikaži obvestilo o bližnjični tipki pri prehodu v celozaslonski način" - msgid "Options" msgstr "Možnosti" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index e33dbfe21..efbfab7eb 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -630,9 +630,6 @@ msgstr "Allvarligt fel" msgid " - PAUSED" msgstr " - PAUSAD" -msgid "Press %1 to return to windowed mode." -msgstr "Tryck på %1 för att återvända till fönsterläge." - msgid "Speed" msgstr "Hastighet" @@ -864,9 +861,6 @@ msgstr "%1 krävs för automatisk omvandling av PostScript-filer till PDF.\n\nAl msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 krävs för automatisk omvandling av PCL-filer till PDF.\n\nAlla dokument som skickas till den allmänna PCL-skrivaren kommer att sparas som Printer Command Language-filer (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Startar helskärmsläge" - msgid "Don't show this message again" msgstr "Visa inte detta meddelande igen" @@ -1305,8 +1299,8 @@ msgstr "Fel vid initialisering av OpenGL" msgid "\nFalling back to software rendering." msgstr "\nFaller tillbaka på mjukvarurendering." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Vid val av medieavbildningar (CD-ROM, diskett, osv.) så kommer fönstret att börja i samma mapp som 86Box konfigurationsfil. Denna inställning kommer troligtvis endast göra en skillnad på macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Vid val av medieavbildningar (CD-ROM, diskett, osv.) så kommer fönstret att börja i samma mapp som 86Box konfigurationsfil. Denna inställning kommer troligtvis endast göra en skillnad på macOS.

" msgid "This machine might have been moved or copied." msgstr "Denna maskin kan ha flyttats eller kopierats." @@ -2112,9 +2106,6 @@ msgstr "Bekräfta innan hård omstart" msgid "Ask for confirmation before quitting" msgstr "Bekräfta innan avslut" -msgid "Display hotkey message when entering full-screen mode" -msgstr "Visa meddelande om snabbtangenter när helskärmsläget startas" - msgid "Options" msgstr "Alternativ" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 24c1c0ba0..73d46a007 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -630,9 +630,6 @@ msgstr "Kritik hata" msgid " - PAUSED" msgstr " - DURAKLATILDI" -msgid "Press %1 to return to windowed mode." -msgstr "Pencere moduna geri dönmek için %1 tuşlarına basın." - msgid "Speed" msgstr "Hız" @@ -864,9 +861,6 @@ msgstr "%1 PostScript dosyalarının otomatik olarak PDF dosyalarına çevirilme msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 PCL dosyalarının otomatik olarak PDF dosyalarına çevirilmesi için gereklidir.\n\nBu bulunmadığından dolayı genel PostScript yazıcısına gönderilen tüm dökümanlar Printer Command Language (.pcl) dosyası olarak kaydedilecektir." -msgid "Entering fullscreen mode" -msgstr "Tam ekran moduna geçiş yapılıyor" - msgid "Don't show this message again" msgstr "Bu mesajı bir daha gösterme" @@ -1305,8 +1299,8 @@ msgstr "OpenGL başlatılırken hata oluştu" msgid "\nFalling back to software rendering." msgstr "\nYazılım işleyicisine geri dönülüyor." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Medya görüntüsü (CD-ROM, disket, vb.) seçme diyaloğu 86Box yapılandırma dosyasıyla aynı dizinde başlayacaktır. Bu ayar muhtemelen sadece macOS üzerinde bir fark meydana getirecektir.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Medya görüntüsü (CD-ROM, disket, vb.) seçme diyaloğu 86Box yapılandırma dosyasıyla aynı dizinde başlayacaktır. Bu ayar muhtemelen sadece macOS üzerinde bir fark meydana getirecektir.

" msgid "This machine might have been moved or copied." msgstr "Bu makine taşınmış veya kopyalanmış olabilir." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 68b50771a..49a8acf00 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -630,9 +630,6 @@ msgstr "Непереробна помилка" msgid " - PAUSED" msgstr " - ПРИЗУПИНЕННЯ" -msgid "Press %1 to return to windowed mode." -msgstr "Натисніть %1 для повернення у віконний режим." - msgid "Speed" msgstr "Швидкість" @@ -864,9 +861,6 @@ msgstr "%1 потрібно для автоматичного перетворе msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 потрібно для автоматичного перетворення файлів PCL в PDF.\n\nВсі документи, відправлені на загальний принтер PCL, будуть збережені у вигляді файлів Printer Command Language (.ps)." -msgid "Entering fullscreen mode" -msgstr "Вхід у повноекранний режим" - msgid "Don't show this message again" msgstr "Більше не показувати це повідомлення" @@ -1305,8 +1299,8 @@ msgstr "Помилка ініціалізації OpenGL" msgid "\nFalling back to software rendering." msgstr "\nПовернення до програмного рендерингу." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>При виборі медіа-образів (CD-ROM, дискета і т.д.) діалогове вікно буде відкриватися в тому ж каталозі, що і файл конфігурації 86Box. Цей параметр, швидше за все, матиме значення лише на macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

При виборі медіа-образів (CD-ROM, дискета і т.д.) діалогове вікно буде відкриватися в тому ж каталозі, що і файл конфігурації 86Box. Цей параметр, швидше за все, матиме значення лише на macOS.

" msgid "This machine might have been moved or copied." msgstr "Цю машину могли перемістити або скопіювати." @@ -2112,9 +2106,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 8632234df..9fed36393 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -630,9 +630,6 @@ msgstr "Lỗi nghiêm trọng" msgid " - PAUSED" msgstr " - TẠM DỪNG" -msgid "Press %1 to return to windowed mode." -msgstr "Bấm %1 để quay lại chế độ cửa sổ." - msgid "Speed" msgstr "Vận tốc" @@ -864,9 +861,6 @@ msgstr "Cần có %1 để tự động chuyển đổi file PostScript qua PDF. msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "Cần có %1 để tự động chuyển đổi file PCL qua PDF.\n\nMọi tài liệu được đưa qua máy in generic PCL sẽ lưu ở dạng Printer Command Language (.pcl)." -msgid "Entering fullscreen mode" -msgstr "Đang tiến vào chế độ toàn màn hình" - msgid "Don't show this message again" msgstr "Không hiện thông báo này nữa" @@ -1305,8 +1299,8 @@ msgstr "Lỗi khởi tạo OpenGL" msgid "\nFalling back to software rendering." msgstr "\nQuay trở lại kết xuất phần mềm." -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.</p></body></html>" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

Khi chọn hình ảnh phương tiện (CD-ROM, ổ mềm, v.v.), hộp thoại mở sẽ bắt đầu trong cùng thư mục với tệp cấu hình 86box. Cài đặt này có thể sẽ chỉ tạo ra sự khác biệt trên macOS.

" msgid "This machine might have been moved or copied." msgstr "Cấu hình máy này có thể đã được di chuyển hoặc sao chép." @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 194db4f3d..d2ed7ce71 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -630,9 +630,6 @@ msgstr "致命错误" msgid " - PAUSED" msgstr " - 已暂停" -msgid "Press %1 to return to windowed mode." -msgstr "按下 %1 返回到窗口模式。" - msgid "Speed" msgstr "速度" @@ -864,9 +861,6 @@ msgstr "%1 是将 PostScript 文件转换为 PDF 所需要的库。\n\n使用通 msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 是将 PCL 文件转换为 PDF 所需要的库。\n\n使用通用 PCL 打印机打印的文档将被保存为 Printer Command Language (.pcl) 文件。" -msgid "Entering fullscreen mode" -msgstr "正在进入全屏模式" - msgid "Don't show this message again" msgstr "不要再显示此消息" @@ -1305,8 +1299,8 @@ msgstr "初始化 OpenGL 时出错" msgid "\nFalling back to software rendering." msgstr "\n回到软件渲染。" -msgid "<html><head/><body><p>When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.</p></body></html>" -msgstr "<html><head/><body><p>选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。</p></body></html>;" +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

當選擇媒體映像 (CD-ROM、軟碟等) 時,開啟對話方塊會在與 86Box 設定檔相同的目錄中開始。此設定可能只會在 macOS 上有所影響。

" msgid "This machine might have been moved or copied." msgstr "這台機器可能已被移動或複製。" @@ -2106,9 +2100,6 @@ msgstr "" msgid "Ask for confirmation before quitting" msgstr "" -msgid "Display hotkey message when entering full-screen mode" -msgstr "" - msgid "Options" msgstr "" diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 9148abea1..bb28b47ee 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1345,26 +1345,6 @@ MainWindow::on_actionFullscreen_triggered() emit resizeContents(vid_resize == 2 ? fixed_size_x : monitors[0].mon_scrnsz_x, vid_resize == 2 ? fixed_size_y : monitors[0].mon_scrnsz_y); } } else { - if (video_fullscreen_first) { - bool wasCaptured = mouse_capture == 1; - - QMessageBox questionbox(QMessageBox::Icon::Information, tr("Entering fullscreen mode"), - tr("Press %1 to return to windowed mode.").arg(QKeySequence(acc_keys[FindAccelerator("fullscreen")].seq, QKeySequence::PortableText).toString(QKeySequence::NativeText)), - QMessageBox::Ok, this); - QCheckBox *chkbox = new QCheckBox(tr("Don't show this message again")); - questionbox.setCheckBox(chkbox); - chkbox->setChecked(!video_fullscreen_first); - - QObject::connect(chkbox, &QCheckBox::stateChanged, [](int state) { - video_fullscreen_first = (state == Qt::CheckState::Unchecked); - }); - questionbox.exec(); - config_save(); - - /* (re-capture mouse after dialog). */ - if (wasCaptured) - emit setMouseCapture(true); - } video_fullscreen = 1; setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); ui->menubar->hide(); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 4894b99c0..825689e78 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -96,7 +96,6 @@ ProgSettings::ProgSettings(QWidget *parent) ui->checkBoxConfirmExit->setChecked(confirm_exit); ui->checkBoxConfirmSave->setChecked(confirm_save); ui->checkBoxConfirmHardReset->setChecked(confirm_reset); - ui->checkBoxFullscreenFirst->setChecked(video_fullscreen_first); #ifndef Q_OS_WINDOWS ui->checkBoxMultimediaKeys->setHidden(true); @@ -111,7 +110,6 @@ ProgSettings::accept() confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0; confirm_save = ui->checkBoxConfirmSave->isChecked() ? 1 : 0; confirm_reset = ui->checkBoxConfirmHardReset->isChecked() ? 1 : 0; - video_fullscreen_first = ui->checkBoxFullscreenFirst->isChecked() ? 1 : 0; inhibit_multimedia_keys = ui->checkBoxMultimediaKeys->isChecked() ? 1 : 0; loadTranslators(QCoreApplication::instance()); diff --git a/src/qt/qt_progsettings.ui b/src/qt/qt_progsettings.ui index b01199dfd..6020efd77 100644 --- a/src/qt/qt_progsettings.ui +++ b/src/qt/qt_progsettings.ui @@ -165,13 +165,6 @@ - - - - Display hotkey message when entering full-screen mode - - - From 04a92704d1b351cd7f1292f879e38e76b28ad6ec Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 19:42:18 +0200 Subject: [PATCH 0878/1190] And the PS/ValuePoint P60 as well. --- src/machine/m_at_socket4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 03ff03a23..30da4e299 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -266,7 +266,8 @@ machine_at_valuepointp60_init(const machine_t *model) pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_ps1_pci_device); device_add(&sio_device); - device_add(&fdc37c665_device); + device_add(&ide_rz1000_pci_single_channel_device); + device_add(&fdc37c665_ide_sec_device); device_add(&intel_flash_bxt_ami_device); device_add(&i430lx_device); From baba4b704f38ea9368e23fd1b4e9e3593288d9f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 19:49:03 +0200 Subject: [PATCH 0879/1190] PS/ValuePoint P60: Only primary IDE, in accordance with the IBM hardware reference. --- src/machine/m_at_socket4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 30da4e299..88474d431 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -254,7 +254,7 @@ machine_at_valuepointp60_init(const machine_t *model) return ret; machine_at_common_init(model); - device_add(&ide_pci_2ch_device); + device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); @@ -267,7 +267,7 @@ machine_at_valuepointp60_init(const machine_t *model) device_add(&keyboard_ps2_ps1_pci_device); device_add(&sio_device); device_add(&ide_rz1000_pci_single_channel_device); - device_add(&fdc37c665_ide_sec_device); + device_add(&fdc37c665_device); device_add(&intel_flash_bxt_ami_device); device_add(&i430lx_device); From 5fcef3713d97985de56afbb10412eb4b2d2291df Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 8 May 2025 00:28:25 +0600 Subject: [PATCH 0880/1190] Add missing tooltips for keyboard lock icons --- src/qt/qt_mainwindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index bb28b47ee..3a0f1cb8a 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -198,18 +198,22 @@ MainWindow::MainWindow(QWidget *parent) num_label = new QLabel; num_label->setPixmap(num_icon_off.pixmap(QSize(16, 16))); + num_label->setToolTip(QShortcut::tr("Num Lock")); statusBar()->addPermanentWidget(num_label); caps_label = new QLabel; caps_label->setPixmap(caps_icon_off.pixmap(QSize(16, 16))); + caps_label->setToolTip(QShortcut::tr("Caps Lock")); statusBar()->addPermanentWidget(caps_label); scroll_label = new QLabel; scroll_label->setPixmap(scroll_icon_off.pixmap(QSize(16, 16))); + scroll_label->setToolTip(QShortcut::tr("Scroll Lock")); statusBar()->addPermanentWidget(scroll_label); kana_label = new QLabel; kana_label->setPixmap(kana_icon_off.pixmap(QSize(16, 16))); + kana_label->setToolTip(QShortcut::tr("Kana Lock")); statusBar()->addPermanentWidget(kana_label); QTimer* ledKeyboardTimer = new QTimer(this); @@ -1507,9 +1511,13 @@ MainWindow::refreshMediaMenu() ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); + num_label->setToolTip(QShortcut::tr("Num Lock")); num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + scroll_label->setToolTip(QShortcut::tr("Scroll Lock")); scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + caps_label->setToolTip(QShortcut::tr("Caps Lock")); caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); + kana_label->setToolTip(QShortcut::tr("Kana Lock")); kana_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD) && machine_has_flags(machine, MACHINE_AX)); } From 2becc6fa600af8fa705d09884dc1c070a0e46739 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 7 May 2025 21:27:20 +0200 Subject: [PATCH 0881/1190] P54NP4 fixes of the evening (May 7th, 2025) 1. The 430NX does support PCI IRQ steering, fix it accordingly. 2. Reorder the number of the slots. 3. Add the SIO ZB device to said machine as it must have one. 4. Remove the onboard 810 SCSI controller. --- src/machine/m_at_socket5.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 0d748b85e..4b3bbd49c 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -110,19 +110,19 @@ machine_at_p54np4_init(const machine_t *model) return ret; machine_at_common_init(model); + device_add(&ide_vlb_2ch_device); - pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_init(PCI_CONFIG_TYPE_2 | PCI_CAN_SWITCH_TYPE); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ - pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ - pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ - pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ - pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 06 = Slot 1 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 05 = Slot 2 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 04 = Slot 3 */ + pci_register_slot(0x03, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 03 = Slot 4 */ pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430nx_device); + device_add(&sio_zb_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&fdc37c665_ide_pri_device); - device_add(&ncr53c810_onboard_pci_device); device_add(&intel_flash_bxt_device); return ret; From e6a41921cf6e2f86b7ccb55f70ecfe2d21678e9a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 7 May 2025 21:40:22 +0200 Subject: [PATCH 0882/1190] Fix mono pattern position in the Mach64 cards using 24bpp mode (May 7th, 2025) See above. --- src/video/vid_ati_mach64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 4ec9afff8..026634cf2 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -1670,7 +1670,7 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) case MONO_SRC_PAT: if (mach64->dst_cntl & DST_24_ROT_EN) { if (!mach64->accel.xx_count) - mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; + mix = mach64->accel.pattern[dst_y & 7][(dst_x / 3) & 7]; } else mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; break; From 304a47c1bb1744809e2047e9a36508aef9f8c546 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Wed, 7 May 2025 22:49:05 +0200 Subject: [PATCH 0883/1190] Add files via upload --- src/video/vid_et4000w32.c | 160 +++++++++++++++++++++++++++++++------- 1 file changed, 133 insertions(+), 27 deletions(-) diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 246decb9c..c772ffdd9 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -43,8 +43,11 @@ #define BIOS_ROM_PATH_W32I_ISA "roms/video/et4000w32/ET4KW32I.VBI" #define BIOS_ROM_PATH_W32I_VLB "roms/video/et4000w32/tseng.u41.bin" #define BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB "roms/video/et4000w32/VideoMagic-BioS-HXIRTW32PWSRL.bin" +#define BIOS_ROM_PATH_W32P_IMASCAN_VLB "roms/video/et4000w32/tseng_et4000w32p-8.03.bin" +#define BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB "roms/video/et4000w32/m27c256b-at-dip28-miro20td-675dada18e7fa701369657.bin" #define BIOS_ROM_PATH_W32P "roms/video/et4000w32/ET4K_W32.BIN" #define BIOS_ROM_PATH_W32P_REVC "roms/video/et4000w32/et4000w32pcardex.BIN" +#define BIOS_ROM_PATH_W32P_REVCD_ONBOARD "roms/video/et4000w32/vid.BIN" #define ACL_WRST 1 #define ACL_RDST 2 @@ -55,7 +58,10 @@ enum { ET4000W32, ET4000W32I, ET4000W32P_REVC, + ET4000W32P_REVCD_ONBOARD, ET4000W32P_VIDEOMAGIC_REVB, + ET4000W32P_IMASCAN_VLB, + ET4000W32P_MIROVIDEO20TD_VLB, ET4000W32P, ET4000W32P_CARDEX, ET4000W32P_DIAMOND @@ -178,7 +184,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (et4000->type <= ET4000W32P_REVC) + if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) sdac_ramdac_out(addr, 0, val, svga->ramdac, svga); else stg_ramdac_out(addr, val, svga->ramdac, svga); @@ -302,13 +308,13 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) if (svga->hwcursor.cur_xsize == 128) { svga->hwcursor.xoff &= 0x7f; svga->hwcursor.yoff &= 0x7f; - if (et4000->type > ET4000W32P_REVC) { + if (et4000->type > ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { if (svga->bpp == 24) { et4000->adjust_cursor = 2; } } } else { - if (et4000->type > ET4000W32P_REVC) { + if (et4000->type > ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { if ((svga->bpp == 24) && et4000->adjust_cursor) { et4000->adjust_cursor = 0; } @@ -348,7 +354,7 @@ et4000w32p_in(uint16_t addr, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (et4000->type <= ET4000W32P_REVC) + if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) return sdac_ramdac_in(addr, 0, svga->ramdac, svga); else return stg_ramdac_in(addr, svga->ramdac, svga); @@ -503,8 +509,8 @@ et4000w32p_recalctimings(svga_t *svga) svga->hdisp >>= 1; svga->dots_per_clock >>= 1; } - if (et4000->type <= ET4000W32P_REVC) { - if (et4000->type == ET4000W32P_REVC) { + if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type == ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { if (svga->hdisp != 1024) et4000->adjust_cursor = 1; } else @@ -514,7 +520,7 @@ et4000w32p_recalctimings(svga_t *svga) case 24: svga->hdisp /= 3; svga->dots_per_clock /= 3; - if (et4000->type <= ET4000W32P_REVC) + if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) et4000->adjust_cursor = 2; if ((et4000->type == ET4000W32P_DIAMOND) && ((svga->hdisp == (640 / 2)) || (svga->hdisp == 1232))) { svga->hdisp = 640; @@ -548,7 +554,7 @@ et4000w32p_recalctimings(svga_t *svga) break; case 0x40: case 0x60: /* 256+ colours */ - if (et4000->type <= ET4000W32P_REVC) + if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) svga->clock /= 2; switch (svga->bpp) { @@ -729,13 +735,13 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00ff) | (val << 8); break; case 0x8e: - if (et4000->type >= ET4000W32P_REVC) + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) et4000->acl.queued.pixel_depth = val & 0x30; else et4000->acl.queued.vbus = val & 0x03; break; case 0x8f: - if (et4000->type >= ET4000W32P_REVC) + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) et4000->acl.queued.xy_dir = val & 0xb7; else et4000->acl.queued.xy_dir = val & 0x03; @@ -759,7 +765,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00ff) | (val << 8); break; case 0x9c: - if (et4000->type >= ET4000W32P_REVC) + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) et4000->acl.queued.ctrl_routing = val & 0xdb; else et4000->acl.queued.ctrl_routing = val & 0xb7; @@ -785,7 +791,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) case 0xa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00ffffff) | (val << 24); et4000->acl.internal = et4000->acl.queued; - if (et4000->type >= ET4000W32P_REVC) { + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { et4000w32p_blit_start(et4000); et4000w32_log("Destination Address write and start XY Block, xcnt = %i, ycnt = %i\n", et4000->acl.x_count + 1, et4000->acl.y_count + 1); if (!(et4000->acl.queued.ctrl_routing & 0x43)) { @@ -849,7 +855,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val, uint8_t bank) { - if (et4000->type >= ET4000W32P_REVC) { + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { if (!(et4000->acl.status & ACL_XYST)) { et4000w32_log("XY MMU block not started\n"); return; @@ -1087,7 +1093,7 @@ et4000w32p_mmu_read(uint32_t addr, void *priv) case 0x8d: return et4000->acl.internal.dest_off >> 8; case 0x8e: - if (et4000->type >= ET4000W32P_REVC) + if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) return et4000->acl.internal.pixel_depth; return et4000->acl.internal.vbus; case 0x8f: @@ -2779,6 +2785,30 @@ et4000w32p_init(const device_t *info) rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; + break; + + case ET4000W32P_IMASCAN_VLB: + /* ET4000/W32p Imascan RGB */ + et4000->rev = 5; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_IMASCAN_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + + et4000->svga.ramdac = device_add(&stg_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = stg_getclock; + break; + + case ET4000W32P_MIROVIDEO20TD_VLB: + /* ET4000/W32p miroVIDEO 20TD LIVE! */ + et4000->rev = 5; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + et4000->svga.ramdac = device_add(&stg_ramdac_device); et4000->svga.clock_gen = et4000->svga.ramdac; et4000->svga.getclock = stg_getclock; @@ -2791,6 +2821,18 @@ et4000w32p_init(const device_t *info) rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVC, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); + et4000->svga.clock_gen = et4000->svga.ramdac; + et4000->svga.getclock = sdac_getclock; + break; + + case ET4000W32P_REVCD_ONBOARD: + /* ET4000/W32p rev C */ + et4000->rev = 7; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVCD_ONBOARD, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); et4000->svga.clock_gen = et4000->svga.ramdac; et4000->svga.getclock = sdac_getclock; @@ -2890,12 +2932,30 @@ et4000w32p_videomagic_revb_vlb_available(void) return rom_present(BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB); } +int +et4000w32p_imascan_vlb_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_IMASCAN_VLB); +} + +int +et4000w32p_mirovideo20td_vlb_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB); +} + int et4000w32p_revc_available(void) { return rom_present(BIOS_ROM_PATH_W32P_REVC); } +int +et4000w32p_revcd_onboard_available(void) +{ + return rom_present(BIOS_ROM_PATH_W32P_REVCD_ONBOARD); +} + int et4000w32p_noncardex_available(void) { @@ -2943,19 +3003,23 @@ et4000w32p_force_redraw(void *priv) static const device_config_t et4000w32p_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = NULL, - .default_int = 2, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { - { .description = "1 MB", .value = 1 }, - { .description = "2 MB", .value = 2 }, - { .description = "" } - }, - .bios = { { 0 } } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_int = 2, + .selection = { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -3017,6 +3081,34 @@ const device_t et4000w32i_vlb_device = { .config = et4000w32p_config }; +const device_t et4000w32p_imascan_vlb_device = { + .name = "Tseng Labs ET4000/w32p VLB (Imascan)", + .internal_name = "et4000w32p_imascan_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_IMASCAN_VLB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + .available = et4000w32p_imascan_vlb_available, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + +const device_t et4000w32p_mirovideo20td_vlb_device = { + .name = "Tseng Labs ET4000/w32p VLB (miroVIDEO 20TD LIVE!)", + .internal_name = "et4000w32p_mirovideo20td_vlb", + .flags = DEVICE_VLB, + .local = ET4000W32P_MIROVIDEO20TD_VLB, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + .available = et4000w32p_mirovideo20td_vlb_available, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + const device_t et4000w32p_videomagic_revb_vlb_device = { .name = "Tseng Labs ET4000/w32p Rev. B VLB (VideoMagic)", .internal_name = "et4000w32p_videomagic_revb_vlb", @@ -3073,6 +3165,20 @@ const device_t et4000w32p_revc_pci_device = { .config = et4000w32p_config }; +const device_t et4000w32p_revcd_onboard_pci_device = { + .name = "Tseng Labs ET4000/w32p Rev. C/D PCI (On-Board)", + .internal_name = "et4000w32p_revc_pci", + .flags = DEVICE_PCI, + .local = ET4000W32P_REVCD_ONBOARD, + .init = et4000w32p_init, + .close = et4000w32p_close, + .reset = NULL, + .available = et4000w32p_revcd_onboard_available, + .speed_changed = et4000w32p_speed_changed, + .force_redraw = et4000w32p_force_redraw, + .config = et4000w32p_config +}; + const device_t et4000w32p_noncardex_vlb_device = { .name = "Tseng Labs ET4000/w32p Rev. D VLB", .internal_name = "et4000w32p_nc_vlb", From e6f99168d170351fe87b27354acc4388828098e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 22:51:27 +0200 Subject: [PATCH 0884/1190] ASUS KN97: Change minimum CPU core voltage to 2.8 V, the board does not support the 2.0 V Deschutes CPU's. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index adf132a5d..09183e5c0 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14770,7 +14770,7 @@ const machine_t machines[] = { .block = CPU_BLOCK_NONE, .min_bus = 60000000, .max_bus = 83333333, - .min_voltage = 1800, + .min_voltage = 2800, .max_voltage = 3500, .min_multi = 1.5, .max_multi = 8.0 From 58f342c27726c42c912cdb59764a49a331916396 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 23:02:29 +0200 Subject: [PATCH 0885/1190] RZ-1000: Disable logging. --- src/disk/hdc_ide_rz1000.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c index d93e83859..2c1a09e8e 100644 --- a/src/disk/hdc_ide_rz1000.c +++ b/src/disk/hdc_ide_rz1000.c @@ -55,7 +55,6 @@ typedef struct rz1000_t { static int next_id = 0; -#define ENABLE_RZ1000_LOG 1 #ifdef ENABLE_RZ1000_LOG int rz1000_do_log = ENABLE_RZ1000_LOG; From d6338e42cc0875e54bdce4b86aa30fe636d667ce Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 7 May 2025 23:08:26 +0200 Subject: [PATCH 0886/1190] Significantly speed up floppy turbo mode when the FDC is using DMA. --- src/floppy/fdc.c | 9 +++++++++ src/floppy/fdd_86f.c | 18 +++++++++++++++--- src/include/86box/fdc.h | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index de8508e69..e779ea2d7 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -279,6 +279,15 @@ fdc_is_mfm(fdc_t *fdc) return fdc->mfm ? 1 : 0; } +int +fdc_is_dma(fdc_t *fdc) +{ + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + return 0; + else + return 1; +} + void fdc_request_next_sector_id(fdc_t *fdc) { diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 0a7120b16..24fde57b1 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -2414,16 +2414,28 @@ d86f_turbo_poll(int drive, int side) case STATE_0C_READ_DATA: case STATE_11_SCAN_DATA: case STATE_16_VERIFY_DATA: - d86f_turbo_read(drive, side); + if (fdc_is_dma(d86f_fdc)) + for (int i = 0; i < (128 << dev->last_sector.id.n); i++) + d86f_turbo_read(drive, side); + else + d86f_turbo_read(drive, side); break; case STATE_05_WRITE_DATA: case STATE_09_WRITE_DATA: - d86f_turbo_write(drive, side); + if (fdc_is_dma(d86f_fdc)) + for (int i = 0; i < (128 << dev->last_sector.id.n); i++) + d86f_turbo_write(drive, side); + else + d86f_turbo_write(drive, side); break; case STATE_0D_FORMAT_TRACK: - d86f_turbo_format(drive, side, (side && (d86f_get_sides(drive) != 2))); + if (fdc_is_dma(d86f_fdc)) + while (dev->state == STATE_0D_FORMAT_TRACK) + d86f_turbo_format(drive, side, (side && (d86f_get_sides(drive) != 2))); + else + d86f_turbo_format(drive, side, (side && (d86f_get_sides(drive) != 2))); return; case STATE_IDLE: diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 36cfaeb7a..ed62cb45f 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -206,6 +206,7 @@ extern int fdc_get_drive(fdc_t *fdc); extern int fdc_get_perp(fdc_t *fdc); extern int fdc_get_format_n(fdc_t *fdc); extern int fdc_is_mfm(fdc_t *fdc); +extern int fdc_is_dma(fdc_t *fdc); extern double fdc_get_hut(fdc_t *fdc); extern double fdc_get_hlt(fdc_t *fdc); extern void fdc_request_next_sector_id(fdc_t *fdc); From 7301aaad004a8b3d9fab728230b1dba0188e7d3d Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 8 May 2025 04:52:33 +0200 Subject: [PATCH 0887/1190] Added the ASUS 386/33-64K (Award 4.00 386DX). --- src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 21 +++++++++++++++++++ src/machine/machine_table.c | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 996f2bf5f..c28add516 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -514,6 +514,7 @@ extern int machine_at_ga486l_init(const machine_t *); extern int machine_at_cougar_init(const machine_t *); extern int machine_at_acc386_init(const machine_t *); +extern int machine_at_asus386_3364k_init(const machine_t *); extern int machine_at_asus386_init(const machine_t *); extern int machine_at_ecs386_init(const machine_t *); extern int machine_at_spc6000a_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index e3838ce32..e75c5414e 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -72,6 +72,27 @@ machine_at_acc386_init(const machine_t *model) return ret; } +int +machine_at_asus386_3364k_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/asus386_3364k/am27c512dip28-64b53c26be3d8160533563.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&rabbit_device); + device_add(&keyboard_at_ami_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + int machine_at_asus386_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 09183e5c0..e0317f40f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5632,6 +5632,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has Award KBC firmware. */ + { + .name = "[SiS 310] ASUS 386/33-64K", + .internal_name = "asus386_3364k", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_SIS_310, + .init = machine_at_asus386_3364k_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_APM, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has AMIKey F KBC firmware. */ { .name = "[SiS 310] ASUS ISA-386C", From e621014addfd514b1a89104ea968d677d9c41268 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 8 May 2025 23:56:48 +0200 Subject: [PATCH 0888/1190] Actually fix the timing of the PAS16/Plus SCSI side (May 8th, 2025) See above, fixes the non-audio mamv1.sys SCSI controller driver using CD/HDD reads/writes. --- src/sound/snd_pas16.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index cfefc8df5..9b82d580d 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -792,14 +792,10 @@ pas16_in(uint16_t port, void *priv) if ((scsi_bus->tx_mode == PIO_TX_BUS) && !(ret & 0x80)) ret |= 0x80; - if (ret & 0x80) { - if (scsi_bus->data_repeat < MIN(511, scsi_bus->total_len)) - scsi_bus->data_repeat++; - } else { - if (scsi_bus->data_repeat == MIN(511, scsi_bus->total_len)) - ret = 0x00; - } - pas16_log("%04X:%08X: Port %04x read ret=%02x, status=%02x, txmode=%x, repeat=%d.\n", CS, cpu_state.pc, port + pas16->base, ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode, scsi_bus->data_repeat); + if ((pas16->scsi->status & 0x06) == 0x00) + ret = 0x00; + + pas16_log("%04X:%08X: Port %04x read ret=%02x, status=%02x, txmode=%x, repeat=%d, total=%d.\n", CS, cpu_state.pc, port + pas16->base, ret, pas16->scsi->status & 0x06, scsi_bus->tx_mode, scsi_bus->data_repeat, MIN(511, scsi_bus->total_len)); } break; case 0x5c03: From cc6076f93b5fe05fe60feb069ec57acb2b0ded50 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 9 May 2025 02:23:56 +0200 Subject: [PATCH 0889/1190] Late night S3 changes (May 9th, 2025) 1. Pixtrans on port 0xb2e8 is not available on 864/964 and up (including the trio64) due to color compare taking its place, fixes some graphical glitches in WinXP. 2. The DOS s3id utility identifies the 80x chips correctly, either it's 801 ISA or 805 VLB, but not 805 ISA even if they share the same id, but since it's an ISA card, identify the Elsa Winner 1000 805 ISA as a 801 card. --- src/video/vid_s3.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index e88bbe58f..683d2be34 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -1311,7 +1311,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xb148: case 0xb2e8: s3_log("[%04X:%08X] OUT PORTB=%04x, val=%02x, CMD=%04x, C(%d,%d).\n", CS, cpu_state.pc, port, val, s3->accel.cmd, s3->accel.cur_x, s3->accel.cur_y); - if (s3->accel.multifunc[0xe] & 0x100) { + if ((s3->accel.multifunc[0xe] & 0x100) || (s3->chip >= S3_VISION964)) { s3->accel.b2e8_pix = 0; if (s3->bpp == 3) { if ((s3->chip >= S3_86C928) && (s3->chip < S3_VISION964)) { @@ -1353,7 +1353,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xb149: case 0xb2e9: s3_log("[%04X:%08X] OUT PORTB=%04x, val=%02x, CMD=%04x, C(%d,%d).\n", CS, cpu_state.pc, port, val, s3->accel.cmd, s3->accel.cur_x, s3->accel.cur_y); - if (s3->accel.multifunc[0xe] & 0x100) { + if ((s3->accel.multifunc[0xe] & 0x100) || (s3->chip >= S3_VISION964)) { s3->accel.b2e8_pix = 0; if (s3->bpp == 3) { if ((s3->chip >= S3_86C928) && (s3->chip < S3_VISION964)) { @@ -8414,7 +8414,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } - if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Pattern on pixtrans (911/924)*/ count = s3->accel.maj_axis_pcnt + 1; s3->accel.temp_cnt = 16; @@ -8806,8 +8805,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3_log("CMDFULL=%04x, FRGDSEL=%x, BKGDSEL=%x, FRGDMIX=%02x, BKGDMIX=%02x, MASKCHECK=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d, pitch=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_mix & 0x0f, s3->accel.rd_mask_16bit_check, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00, s3->width); if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { - s3_log("Special BitBLT.\n"); - + pclog("Special BitBLT.\n"); while (1) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { READ(s3->accel.src + s3->accel.cx - s3->accel.minus, src_dat); @@ -8851,7 +8849,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi } } } else { - s3_log("Normal blit.\n"); + s3_log("Normal blit, srcbase=%08x, dstbase=%08x, full=%04x, wrt_mask=%08x, extmultifunc0e=%03x, frgdmixval=%02x.\n", srcbase, dstbase, s3->accel.cmd, wrt_mask, s3->accel.multifunc[0x0e] & 0x180, s3->accel.frgd_mix); while (count-- && (s3->accel.sy >= 0)) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { if (vram_mask && (s3->accel.cmd & 0x10)) { @@ -9842,8 +9840,8 @@ s3_init(const device_t *info) break; case S3_WINNER1000_805: bios_fn = ROM_WINNER1000_805; - chip = S3_86C805; - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + chip = S3_86C801; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); break; case S3_86C805_ONBOARD: bios_fn = NULL; From 96d5a04b338ed1b71ec23290df2b7a7ba28faa62 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 May 2025 04:20:22 +0200 Subject: [PATCH 0890/1190] Laser XT 3: EMS memory accesses are now correctly 16-bit. --- src/machine/m_xt_laserxt.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index d298e726b..ec4b41c35 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -154,6 +154,14 @@ lxt_ems_write(uint32_t addr, uint8_t val, void *priv) mem[addr & 0x3fff] = val; } +static void +lxt_ems_writew(uint32_t addr, uint16_t val, void *priv) +{ + uint8_t *mem = (uint8_t *) priv; + + *(uint16_t *) &(mem[addr & 0x3fff]) = val; +} + static uint8_t lxt_ems_read(uint32_t addr, void *priv) { @@ -165,6 +173,17 @@ lxt_ems_read(uint32_t addr, void *priv) return ret; } +static uint16_t +lxt_ems_readw(uint32_t addr, void *priv) +{ + uint8_t *mem = (uint8_t *) priv; + uint8_t ret = 0xff; + + ret = *(uint16_t *) &(mem[addr & 0x3fff]); + + return ret; +} + static lxt_ems_board_t * lxt_ems_init(lxt_t *parent, int en, uint16_t io, uint32_t mem) { @@ -186,10 +205,17 @@ lxt_ems_init(lxt_t *parent, int en, uint16_t io, uint32_t mem) for (uint8_t i = 0; i < 4; i++) { uint8_t *ptr = dev->ram + (i << 14); - mem_mapping_add(&dev->ems[i].mapping, 0xe0000 + (i << 14), 0x4000, - lxt_ems_read, NULL, NULL, - lxt_ems_write, NULL, NULL, - ptr, 0, ptr); + if (parent->is_lxt3) + mem_mapping_add(&dev->ems[i].mapping, 0xe0000 + (i << 14), 0x4000, + lxt_ems_read, lxt_ems_readw, NULL, + lxt_ems_write, lxt_ems_writew, NULL, + ptr, 0, ptr); + else + mem_mapping_add(&dev->ems[i].mapping, 0xe0000 + (i << 14), 0x4000, + lxt_ems_read, NULL, NULL, + lxt_ems_write, NULL, NULL, + ptr, 0, ptr); + mem_mapping_disable(&dev->ems[i].mapping); dev->ems[i].page = 0x7f; From 9a69e1800d1532c45297b64c7d766463927c789a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 9 May 2025 14:56:55 +0600 Subject: [PATCH 0891/1190] Honour `--nohook` on X11 as well --- src/qt/qt_mainwindow.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 3a0f1cb8a..aaf625c2d 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -322,7 +322,8 @@ MainWindow::MainWindow(QWidget *parent) mouse_capture = state ? 1 : 0; qt_mouse_capture(mouse_capture); if (mouse_capture) { - this->grabKeyboard(); + if (hook_enabled) + this->grabKeyboard(); if (ui->stackedWidget->mouse_capture_func) ui->stackedWidget->mouse_capture_func(this->windowHandle()); } else { @@ -1481,13 +1482,15 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) plat_pause(curdopause); #ifdef __unix__ if (!QApplication::platformName().contains("wayland") && (this->windowState() & Qt::WindowActive)) { - this->grabKeyboard(); + if (hook_enabled) + this->grabKeyboard(); } #endif } else if (event->type() == QEvent::WindowActivate) { #ifdef __unix__ if (!QApplication::platformName().contains("wayland")) { - this->grabKeyboard(); + if (hook_enabled) + this->grabKeyboard(); } #endif } else if (event->type() == QEvent::WindowDeactivate) { From b0c9ca6b20aee537a4cbf7fdaece49a4a942b1b8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 9 May 2025 15:28:05 +0600 Subject: [PATCH 0892/1190] Fix stack use-after-return on Linux --- src/qt/qt_rendererstack.cpp | 2 +- src/qt/qt_rendererstack.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 431b3609b..79fa78097 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -77,7 +77,7 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) m_monitor_index = monitor_index; #if defined __unix__ && !defined __HAIKU__ - char auto_mouse_type[16]; + memset(auto_mouse_type, 0, sizeof (auto_mouse_type)); mousedata.mouse_type = getenv("EMU86BOX_MOUSE"); if (!mousedata.mouse_type || (mousedata.mouse_type[0] == '\0') || !stricmp(mousedata.mouse_type, "auto")) { if (QApplication::platformName().contains("wayland")) diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index 172dc2fe6..3a76f3ada 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -137,6 +137,8 @@ private: std::atomic_bool rendererTakesScreenshots; std::atomic_bool switchInProgress{false}; + + char auto_mouse_type[16]; }; #endif // QT_RENDERERCONTAINER_HPP From 070c6c4125addb5c0af0f46f62ae10aa4af61ed9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 9 May 2025 20:21:28 +0200 Subject: [PATCH 0893/1190] Laser XT 3: Fix 16-bit EMS readout, fixes #5572. --- src/machine/m_xt_laserxt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index ec4b41c35..7a6cab5e3 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -176,8 +176,8 @@ lxt_ems_read(uint32_t addr, void *priv) static uint16_t lxt_ems_readw(uint32_t addr, void *priv) { - uint8_t *mem = (uint8_t *) priv; - uint8_t ret = 0xff; + uint8_t *mem = (uint8_t *) priv; + uint16_t ret = 0xff; ret = *(uint16_t *) &(mem[addr & 0x3fff]); From dd6d480facd9b357babbbf432a1ac41e34d1b70d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 9 May 2025 23:41:05 +0200 Subject: [PATCH 0894/1190] Spock/Tribble changes of the evening (May 9th, 2025) Don't duplicate drives into phantom drives. --- src/scsi/scsi_spock.c | 137 +++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 67 deletions(-) diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index 6f0b7aacb..0bb2d70ba 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -130,6 +130,7 @@ typedef struct { int adapter_id; int assign; int present[8]; + int id_connected; int cmd_status; int cir_status; @@ -448,7 +449,6 @@ static void spock_process_imm_cmd(spock_t *scsi) { int i; - int j = 0; int adapter_id; int phys_id; int lun_id; @@ -467,14 +467,23 @@ spock_process_imm_cmd(spock_t *scsi) if (scsi->command & (1 << 23)) { spock_log("Assign: adapter id=%d\n", adapter_id); scsi->dev_id[adapter_id].phys_id = -1; + scsi->id_connected = 0; spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); } else { if (phys_id != scsi->adapter_id) { scsi->dev_id[adapter_id].phys_id = phys_id; scsi->dev_id[adapter_id].lun_id = lun_id; - spock_log("Assign: adapter dev=%x scsi ID=%i LUN=%i.\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id); + if (scsi_device_present(&scsi_devices[scsi->bus][phys_id])) { + scsi->present[scsi->id_connected] = 1; + if (lun_id == 0) + scsi->id_connected++; + } else + scsi->present[scsi->id_connected] = 0; + + spock_log("Assign: adapter dev=%d, scsi ID=%i, LUN=%i, attention devsel=%d, present=%d, connected=%d.\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id, scsi->attention & 0x0f, scsi->present[scsi->id_connected], scsi->id_connected); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); } else { /*Can not assign adapter*/ + scsi->id_connected = 0; spock_log("Assign: PUN=%d, cannot assign adapter.\n", phys_id); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); } @@ -495,35 +504,15 @@ spock_process_imm_cmd(spock_t *scsi) spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_RESET: + scsi->id_connected = 0; spock_log("Reset command, attention=%02x.\n", scsi->attention & 0x0f); if ((scsi->attention & 0x0f) == 0x0f) { /*Adapter reset*/ for (i = 0; i < 8; i++) scsi_device_reset(&scsi_devices[scsi->bus][i]); - for (i = 6; i > -1; i--) { - if (scsi_device_present(&scsi_devices[scsi->bus][i])) { - spock_log("Adapter Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); - scsi->present[j] = i; - j++; - } else { - scsi->present[j] = 0xff; - spock_log("Adapter Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); - } - } - } else if ((scsi->attention & 0x0f) < 7) { /*Device reset*/ + } else if ((scsi->attention & 0x0f) < 7) /*Device reset*/ scsi_device_reset(&scsi_devices[scsi->bus][scsi->attention & 0x0f]); - for (i = 6; i > -1; i--) { - if (scsi_device_present(&scsi_devices[scsi->bus][i])) { - spock_log("Device Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); - scsi->present[j] = i; - j++; - } else { - scsi->present[j] = 0xff; - spock_log("Device Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); - } - } - } scsi->scb_state = 0; spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; @@ -538,7 +527,6 @@ static void spock_execute_cmd(spock_t *scsi, scb_t *scb) { int c; - int j = 0; int old_scb_state; if (scsi->in_reset) { @@ -556,17 +544,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->dev_id[c].phys_id = -1; scsi->in_reset = 0; - - for (c = 6; c >= 0; c--) { - if (scsi_device_present(&scsi_devices[scsi->bus][c])) { - spock_log("Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); - scsi->present[j] = c; - j++; - } else { - scsi->present[j] = 0xff; - spock_log("Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); - } - } + spock_log("Reset.\n"); return; } @@ -698,12 +676,15 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) break; case CMD_DEVICE_INQUIRY: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; - spock_log("Device Inquiry, ID=%d\n", scsi->cdb_id); + spock_log("Device Inquiry, ID=%d, connected=%d, present=%d.\n", scsi->cdb_id, scsi->id_connected, scsi->present[scsi->scb_id + 1]); scsi->cdb[0] = GPCMD_INQUIRY; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = 0; /*Page code*/ @@ -718,13 +699,16 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_SEND_OTHER_SCSI: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; dma_bm_read(scsi->scb_addr + 0x18, scsi->cdb, 12, 2); - spock_log("Send Other SCSI, SCB ID=%d, PHYS ID=%d, CDB[0]=%02x, CDB_ID=%d, ID Present=%d.\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->cdb[0], scsi->cdb_id, scsi->present[scsi->scb_id]); + spock_log("Send Other SCSI, SCB ID=%d, PHYS ID=%d, LUN=%d, CDB[0]=%02x, CDB_ID=%d, ID Present=%d.\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->dev_id[scsi->scb_id].lun_id, scsi->cdb[0], scsi->cdb_id, scsi->present[scsi->scb_id + 1]); scsi->cdb[1] = (scsi->cdb[1] & 0x1f) | (scsi->dev_id[scsi->scb_id].lun_id << 5); /*Patch correct LUN into command*/ scsi->cdb_len = (scb->lba_addr & 0xff) ? (scb->lba_addr & 0xff) : 6; scsi->scsi_state = SCSI_STATE_SELECT; @@ -732,10 +716,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_READ_DEVICE_CAPACITY: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Capacity, SCB ID=%d, PHYS ID=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); scsi->cdb[0] = GPCMD_READ_CDROM_CAPACITY; @@ -754,10 +741,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_READ_DATA: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Read Data, SCB ID=%d, PHYS ID=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); scsi->cdb[0] = GPCMD_READ_10; @@ -776,10 +766,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_WRITE_DATA: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Write Data\n"); scsi->cdb[0] = GPCMD_WRITE_10; @@ -798,10 +791,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_VERIFY: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Verify\n"); scsi->cdb[0] = GPCMD_VERIFY_10; @@ -821,10 +817,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_WRITE_VERIFY: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Write with Verify\n"); scsi->cdb[0] = GPCMD_WRITE_AND_VERIFY_10; @@ -843,10 +842,13 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_REQUEST_SENSE: - if (scsi->present[scsi->scb_id] != 0xff) + if (scsi->scb_id != 15) { + if (scsi->present[scsi->scb_id]) + scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + else + scsi->cdb_id = 0xff; + } else scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - else - scsi->cdb_id = 0xff; spock_log("Device Request Sense, ID=%d\n", scsi->cdb_id); scsi->cdb[0] = GPCMD_REQUEST_SENSE; @@ -870,7 +872,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) if (scsi_device_present(&scsi_devices[scsi->bus][scsi->cdb_id]) && (scsi->cdb_id != 0xff)) { if (scsi->last_status == SCSI_STATUS_OK) { scsi->scb_state = 3; - spock_log("Status is Good on device ID %d, cdb id = %d.\n", scsi->scb_id, scsi->cdb_id); + spock_log("Status is Good on device ID %d, cdb id = %d, devsel = %d.\n", scsi->scb_id, scsi->cdb_id, scsi->attention & 0x0f); } else if (scsi->last_status == SCSI_STATUS_CHECK_CONDITION) { uint16_t term_stat_block_addr7 = (0xc << 8) | 2; uint16_t term_stat_block_addr8 = 0x20; @@ -905,7 +907,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) } else { spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_SCB_COMPLETE); scsi->scb_state = 0; - spock_log("Complete SCB ID = %d.\n", scsi->attention & 0x0f); + spock_log("Complete SCB ID = %d.\n", scsi->scb_id); } break; @@ -1084,10 +1086,10 @@ spock_callback(void *priv) case 4: case 0x0f: /*Start SCB*/ scsi->cmd_status = 1; - scsi->scb_addr = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); - scsi->scb_id = scsi->attention & 0x0f; + scsi->scb_addr = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); + scsi->scb_id = scsi->attention & 0x0f; scsi->cmd_timer = SPOCK_TIME * 2; - spock_log("Start SCB at ID = %d, attention = %02x\n", scsi->scb_id, scsi->attention >> 4); + spock_log("Start SCB at ID = %d, attention = %02x, cdb_id = %d\n", scsi->scb_id, scsi->attention >> 4, scsi->cdb_id); scsi->scb_state = 1; break; @@ -1182,6 +1184,7 @@ spock_reset(void *priv) scsi->in_invalid = 0; scsi->attention_wait = 0; scsi->basic_ctrl = 0; + scsi->id_connected = 0; spock_log("Actual Reset.\n"); } From e800f99f5a2b89b9aad04a0ce39b2726bdb0a88c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 04:53:20 +0200 Subject: [PATCH 0895/1190] Make device.c assume CONFIG_BIOS is first in the config struct and make sure any device_t struct containing such follows that, in order to not have to traverse the entirety of every single device_t's config struct in the Settings dialog - should reduce the dialog's loading times further. --- src/device.c | 37 ++++++++++------------- src/disk/hdc_xta.c | 60 ++++++++++++++++++------------------- src/disk/hdc_xtide.c | 62 +++++++++++++++++++-------------------- src/scsi/scsi_ncr53c400.c | 62 +++++++++++++++++++-------------------- src/video/vid_et4000.c | 46 ++++++++++++++--------------- 5 files changed, 131 insertions(+), 136 deletions(-) diff --git a/src/device.c b/src/device.c index 25f0b55de..ecd523274 100644 --- a/src/device.c +++ b/src/device.c @@ -392,29 +392,24 @@ device_available(const device_t *dev) { if (dev != NULL) { const device_config_t *config = dev->config; - if (config != NULL) { - while (config->type != CONFIG_END) { - if (config->type == CONFIG_BIOS) { - int roms_present = 0; - const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + if ((config != NULL) && (config->type == CONFIG_BIOS)) { + int roms_present = 0; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; - /* Go through the ROM's in the device configuration. */ - while ((bios != NULL) && - (bios->name != NULL) && - (bios->internal_name != NULL) && - (bios->files_no != 0)) { - int i = 0; - for (uint8_t bf = 0; bf < bios->files_no; bf++) - i += !!rom_present(bios->files[bf]); - if (i == bios->files_no) - roms_present++; - bios++; - } - - return (roms_present ? -1 : 0); - } - config++; + /* Go through the ROM's in the device configuration. */ + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + int i = 0; + for (uint8_t bf = 0; bf < bios->files_no; bf++) + i += !!rom_present(bios->files[bf]); + if (i == bios->files_no) + roms_present++; + bios++; } + + return (roms_present ? -1 : 0); } /* No CONFIG_BIOS field present, use the classic available(). */ diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index 85581af2d..d54f6ab0c 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -1106,6 +1106,36 @@ xta_close(void *priv) static const device_config_t wdxt150_config[] = { // clang-format off + { + .name = "bios_rev", + .description = "BIOS Revision", + .type = CONFIG_BIOS, + .default_string = "rev_1", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .bios = { + { + .name = "Revision 1.0", + .internal_name = "rev_1", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { WD_REV_1_BIOS_FILE, "" } + }, + { + .name = "Revision 2.0", + .internal_name = "rev_2", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { WD_REV_2_BIOS_FILE, "" } + }, + { .files_no = 0 } + }, + }, { .name = "base", .description = "Address", @@ -1151,36 +1181,6 @@ static const device_config_t wdxt150_config[] = { }, .bios = { { 0 } } }, - { - .name = "bios_rev", - .description = "BIOS Revision", - .type = CONFIG_BIOS, - .default_string = "rev_1", - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .bios = { - { - .name = "Revision 1.0", - .internal_name = "rev_1", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { WD_REV_1_BIOS_FILE, "" } - }, - { - .name = "Revision 2.0", - .internal_name = "rev_2", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { WD_REV_2_BIOS_FILE, "" } - }, - { .files_no = 0 } - }, - }, { .name = "", .description = "", .type = CONFIG_END } // clang-format off }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 154a28cec..1c8e2c8da 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -252,6 +252,37 @@ xtide_at_close(void *priv) // clang-format off static const device_config_t xtide_config[] = { + { + .name = "bios", + .description = "BIOS Revision", + .type = CONFIG_BIOS, + .default_string = "xt", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Regular XT", + .internal_name = "xt", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_XT, "" } + }, + { + .name = "XT+ (V20/V30/8018x)", + .internal_name = "xt_plus", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { ROM_PATH_XTP, "" } + }, + { .files_no = 0 } + }, + }, { .name = "base", .description = "Address", @@ -348,37 +379,6 @@ static const device_config_t xtide_config[] = { }, .bios = { { 0 } } }, - { - .name = "bios", - .description = "BIOS Revision", - .type = CONFIG_BIOS, - .default_string = "xt", - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } }, - .bios = { - { - .name = "Regular XT", - .internal_name = "xt", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { ROM_PATH_XT, "" } - }, - { - .name = "XT+ (V20/V30/8018x)", - .internal_name = "xt_plus", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { ROM_PATH_XTP, "" } - }, - { .files_no = 0 } - }, - }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index f91dc83a9..0e04e0b5e 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -859,6 +859,37 @@ static const device_config_t ncr53c400_mmio_config[] = { }; static const device_config_t rt1000b_config[] = { + { + .name = "bios_ver", + .description = "BIOS Revision", + .type = CONFIG_BIOS, + .default_string = "v8_10r", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "Version 8.10R", + .internal_name = "v8_10r", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { RT1000B_810R_ROM, "" } + }, + { + .name = "Version 8.20R", + .internal_name = "v8_20r", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { RT1000B_820R_ROM, "" } + }, + { .files_no = 0 } + }, + }, { .name = "bios_addr", .description = "BIOS Address", @@ -895,37 +926,6 @@ static const device_config_t rt1000b_config[] = { }, .bios = { { 0 } } }, - { - .name = "bios_ver", - .description = "BIOS Revision", - .type = CONFIG_BIOS, - .default_string = "v8_10r", - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } }, - .bios = { - { - .name = "Version 8.10R", - .internal_name = "v8_10r", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { RT1000B_810R_ROM, "" } - }, - { - .name = "Version 8.20R", - .internal_name = "v8_20r", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 8192, - .files = { RT1000B_820R_ROM, "" } - }, - { .files_no = 0 } - }, - }, { .name = "", .description = "", .type = CONFIG_END } }; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 064d79230..1929d1d16 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -942,22 +942,6 @@ et4000_kasan_available(void) static const device_config_t et4000_tc6058af_config[] = { // clang-format off - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = NULL, - .default_int = 512, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { - { .description = "256 KB", .value = 256 }, - { .description = "512 KB", .value = 512 }, - { .description = "1 MB", .value = 1024 }, - { .description = "" } - }, - .bios = { { 0 } } - }, { .name = "bios_ver", .description = "BIOS Revision", @@ -989,18 +973,12 @@ static const device_config_t et4000_tc6058af_config[] = { { .files_no = 0 } } }, - { .name = "", .description = "", .type = CONFIG_END } -// clang-format on -}; - -static const device_config_t et4000_bios_config[] = { - // clang-format off { .name = "memory", .description = "Memory size", .type = CONFIG_SELECTION, .default_string = NULL, - .default_int = 1024, + .default_int = 512, .file_filter = NULL, .spinner = { 0 }, .selection = { @@ -1011,6 +989,12 @@ static const device_config_t et4000_bios_config[] = { }, .bios = { { 0 } } }, + { .name = "", .description = "", .type = CONFIG_END } +// clang-format on +}; + +static const device_config_t et4000_bios_config[] = { + // clang-format off { .name = "bios_ver", .description = "BIOS Revision", @@ -1042,6 +1026,22 @@ static const device_config_t et4000_bios_config[] = { { .files_no = 0 } } }, + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 1024, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "256 KB", .value = 256 }, + { .description = "512 KB", .value = 512 }, + { .description = "1 MB", .value = 1024 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; From 76d5fa79af07f10251eebb0c92265cdffbebfc0e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 05:01:57 +0200 Subject: [PATCH 0896/1190] Improve machine availability checking so that it absolutely never uses the legacy method if the machine has a device and the device has a CONFIG_BIOS setting. --- src/device.c | 63 ++++++++++++++++++++++---------------- src/include/86box/device.h | 2 ++ src/machine/machine.c | 20 +++++++----- 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/device.c b/src/device.c index ecd523274..1922806b9 100644 --- a/src/device.c +++ b/src/device.c @@ -390,37 +390,18 @@ device_get_priv(const device_t *dev) int device_available(const device_t *dev) { - if (dev != NULL) { - const device_config_t *config = dev->config; - if ((config != NULL) && (config->type == CONFIG_BIOS)) { - int roms_present = 0; - const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; - - /* Go through the ROM's in the device configuration. */ - while ((bios != NULL) && - (bios->name != NULL) && - (bios->internal_name != NULL) && - (bios->files_no != 0)) { - int i = 0; - for (uint8_t bf = 0; bf < bios->files_no; bf++) - i += !!rom_present(bios->files[bf]); - if (i == bios->files_no) - roms_present++; - bios++; - } - - return (roms_present ? -1 : 0); - } + int ret = machine_device_available(dev); + if (ret == 0) { /* No CONFIG_BIOS field present, use the classic available(). */ if (dev->available != NULL) - return (dev->available()); + ret = (dev->available()); else - return 1; - } + ret = (dev != NULL); + } else + ret = (ret == -1); - /* A NULL device is never available. */ - return 0; + return ret; } uint8_t @@ -964,6 +945,36 @@ machine_get_config_string(char *str) return ret; } +int +machine_device_available(const device_t *dev) +{ + if (dev != NULL) { + const device_config_t *config = dev->config; + if ((config != NULL) && (config->type == CONFIG_BIOS)) { + int roms_present = 0; + const device_config_bios_t *bios = (const device_config_bios_t *) config->bios; + + /* Go through the ROM's in the device configuration. */ + while ((bios != NULL) && + (bios->name != NULL) && + (bios->internal_name != NULL) && + (bios->files_no != 0)) { + int i = 0; + for (uint8_t bf = 0; bf < bios->files_no; bf++) + i += !!rom_present(bios->files[bf]); + if (i == bios->files_no) + roms_present++; + bios++; + } + + return (roms_present ? -1 : -2); + } + } + + /* NULL device or no CONFIG_BIOS field, return 0. */ + return 0; +} + const device_t * device_context_get_device(void) { diff --git a/src/include/86box/device.h b/src/include/86box/device.h index 91ff2daa6..76f12a0c5 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -239,6 +239,8 @@ extern const char *device_get_internal_name(const device_t *dev); extern int machine_get_config_int(char *str); extern const char *machine_get_config_string(char *str); +extern int machine_device_available(const device_t *dev); + extern const device_t device_none; extern const device_t device_internal; diff --git a/src/machine/machine.c b/src/machine/machine.c index b171dd505..505674000 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -139,18 +139,24 @@ machine_init(void) int machine_available(int m) { - int ret; + int ret = 0; const device_t *dev = machine_get_device(m); - bios_only = 1; + if (dev != NULL) + ret = machine_device_available(dev); + /* + Only via machine_init_ex() if the device is NULL or + it lacks a CONFIG_BIOS field (or the CONFIG_BIOS field + is not the first in list. + */ + if (ret == 0) { + bios_only = 1; - ret = device_available(dev); - /* Do not check via machine_init_ex() if the device is not NULL and - it has a CONFIG_BIOS field. */ - if ((dev == NULL) || (ret != -1)) ret = machine_init_ex(m); - bios_only = 0; + bios_only = 0; + } else if (ret == -2) + ret = 0; return !!ret; } From 462e9232b3633ac54e4abf2935cce95ae8426d53 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 05:05:56 +0200 Subject: [PATCH 0897/1190] Chaintech 5SBM2: Rename to 5SBM/5SBM2 and add the 4.50PG BIOS from 1996 as an option. --- src/machine/m_at_socket7_3v.c | 49 ++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 7 ++--- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 913c82518..04bc6b5ef 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -825,13 +825,56 @@ machine_at_vectra54_init(const machine_t *model) return ret; } +static const device_config_t c5sbm2_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "5sbm2", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "4.50GP (07/17/1995)", .internal_name = "5sbm2", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/5sbm2/5SBM0717.BIN", "" } }, + { .name = "4.50PG (03/21/1996)", .internal_name = "5sbm2_450pg", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/5sbm2/5SBM0326.BIN", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t c5sbm2_device = { + .name = "Chaintech 5SBM/5SBM2 (M103)", + .internal_name = "5sbm2_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = c5sbm2_config +}; + int machine_at_5sbm2_init(const machine_t *model) { - int ret; + int ret = 0; + const char* fn; - ret = bios_load_linear("roms/machines/5sbm2/5SBM0717.BIN", - 0x000e0000, 131072, 0); + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); if (bios_only || !ret) return ret; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e0317f40f..34e69ed24 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -68,6 +68,7 @@ extern const device_t ibmxt286_device; extern const device_t pb450_device; extern const device_t jukopc_device; extern const device_t vendex_device; +extern const device_t c5sbm2_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -11545,7 +11546,7 @@ const machine_t machines[] = { /* SiS 5501 */ /* Has the Lance LT38C41 KBC. */ { - .name = "[SiS 5501] Chaintech 5SBM2 (M103)", + .name = "[SiS 5501] Chaintech 5SBM/5SBM2 (M103)", .internal_name = "5sbm2", .type = MACHINE_TYPE_SOCKET7_3V, .chipset = MACHINE_CHIPSET_SIS_5501, @@ -11568,7 +11569,7 @@ const machine_t machines[] = { .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 8192, - .max = 262144, + .max = 131072, .step = 8192 }, .nvrmask = 255, @@ -11576,7 +11577,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &c5sbm2_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, From 87557685159765b3f6f6f13f964be89c258dd447 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 05:14:59 +0200 Subject: [PATCH 0898/1190] Chaintech 5SBM/5SBM2: Unicore Upgrade 4.51PG BIOS. --- src/machine/m_at_socket7_3v.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 04bc6b5ef..39dc2d735 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -840,6 +840,8 @@ static const device_config_t c5sbm2_config[] = { .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/5sbm2/5SBM0717.BIN", "" } }, { .name = "4.50PG (03/21/1996)", .internal_name = "5sbm2_450pg", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/5sbm2/5SBM0326.BIN", "" } }, + { .name = "4.51PG (03/15/2000 Unicore Upgrade)", .internal_name = "5sbm2_451pg", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/5sbm2/2A5ICC3A.BIN", "" } }, { .files_no = 0 } }, }, From 1dd460e9a445298d2e43ef936f14cf159d758603 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 06:22:56 +0200 Subject: [PATCH 0899/1190] x86_64 new recompiler: properly handle cases where pccache is not within 2 GB of the beginning of the RAM array. --- src/codegen_new/codegen_backend_x86-64_ops.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index fc6c1b492..b03ea88c3 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -780,8 +780,19 @@ host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) codegen_alloc_bytes(block, 8); codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ codegen_addlong(block, ram_offset); + } else if ((ram_offset < -2147483648LL) || (ram_offset > 2147483647LL) || !(block->flags & CODEBLOCK_NO_IMMEDIATES)) { + // fatal("host_x86_MOV32_REG_ABS - out of range\n"); + // void *q = p; + //uint32_t *r = NULL; + // *r = 5; /* Crash deliberately. */ + codegen_alloc_bytes(block, 18); + codegen_addbyte2(block, 0x41, 0x54); /*PUSH r12*/ + codegen_addbyte2(block, 0x49, 0xbc); /*MOV r12,(uintptr_t) p*/ + codegen_addquad(block, (uintptr_t) p); + codegen_addbyte4(block, 0x41, 0x8b, 0x04 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, [R12]*/ + codegen_addbyte2(block, 0x41, 0x5c); /*POP r12*/ } else { - fatal("host_x86_MOV32_REG_ABS - out of range\n"); + fatal("host_x86_MOV32_REG_ABS - RAM offset = %016" PRIX64 " (p - ram = %016" PRIX64 ")\n", ram_offset, (uintptr_t) p - (uintptr_t) ram); codegen_alloc_bytes(block, 6); codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); From b179955a12aea4510d105521df0bc39db2f519ba Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 10 May 2025 12:57:27 +0600 Subject: [PATCH 0900/1190] x64 NDR: Avoid pushes/pops for `host_x86_MOV32_REG_ABS` --- src/codegen_new/codegen_backend_x86-64_ops.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index b03ea88c3..ed218d7c4 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -785,12 +785,11 @@ host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) // void *q = p; //uint32_t *r = NULL; // *r = 5; /* Crash deliberately. */ - codegen_alloc_bytes(block, 18); - codegen_addbyte2(block, 0x41, 0x54); /*PUSH r12*/ - codegen_addbyte2(block, 0x49, 0xbc); /*MOV r12,(uintptr_t) p*/ + codegen_alloc_bytes(block, 8); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV r9,(uintptr_t) p*/ codegen_addquad(block, (uintptr_t) p); - codegen_addbyte4(block, 0x41, 0x8b, 0x04 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, [R12]*/ - codegen_addbyte2(block, 0x41, 0x5c); /*POP r12*/ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x41, 0x8b, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [R9]*/ } else { fatal("host_x86_MOV32_REG_ABS - RAM offset = %016" PRIX64 " (p - ram = %016" PRIX64 ")\n", ram_offset, (uintptr_t) p - (uintptr_t) ram); codegen_alloc_bytes(block, 6); From 7529c19ec89721859eb4e2705f7cf28f0b5338b4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 14:25:29 +0200 Subject: [PATCH 0901/1190] Reset all keys on keyboard reset and also make sure to stop the CTRL+ALT+DEL sending on keyboard reset, fixes spurious "Keyboard not present" errors. --- src/86box.c | 28 ++++++++++++++++++++++++++ src/device/keyboard.c | 38 ++++++++++++++++++++++++------------ src/device/keyboard_at.c | 4 ++++ src/include/86box/keyboard.h | 2 ++ 4 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/86box.c b/src/86box.c index 25dc0e6e9..f54a69b79 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1250,20 +1250,48 @@ pc_send_ca(uint16_t sc) if (keyboard_mode >= 0x81) { /* Use R-Alt because PS/55 DOS and OS/2 assign L-Alt Kanji */ keyboard_input(1, 0x1D); /* Ctrl key pressed */ + if (keyboard_get_in_reset()) + return; keyboard_input(1, 0x138); /* R-Alt key pressed */ + if (keyboard_get_in_reset()) + return; keyboard_input(1, sc); + if (keyboard_get_in_reset()) + return; usleep(50000); + if (keyboard_get_in_reset()) + return; keyboard_input(0, sc); + if (keyboard_get_in_reset()) + return; keyboard_input(0, 0x138); /* R-Alt key released */ + if (keyboard_get_in_reset()) + return; keyboard_input(0, 0x1D); /* Ctrl key released */ + if (keyboard_get_in_reset()) + return; } else { keyboard_input(1, 0x1D); /* Ctrl key pressed */ + if (keyboard_get_in_reset()) + return; keyboard_input(1, 0x38); /* Alt key pressed */ + if (keyboard_get_in_reset()) + return; keyboard_input(1, sc); + if (keyboard_get_in_reset()) + return; usleep(50000); + if (keyboard_get_in_reset()) + return; keyboard_input(0, sc); + if (keyboard_get_in_reset()) + return; keyboard_input(0, 0x38); /* Alt key released */ + if (keyboard_get_in_reset()) + return; keyboard_input(0, 0x1D); /* Ctrl key released */ + if (keyboard_get_in_reset()) + return; } } diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 800e7fb8e..6a5693f71 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -64,11 +64,12 @@ static int keydelay[512]; #endif static scancode *scan_table; /* scancode table for keyboard */ -static volatile uint8_t caps_lock = 0; -static volatile uint8_t num_lock = 0; -static volatile uint8_t scroll_lock = 0; -static volatile uint8_t kana_lock = 0; -static uint8_t shift = 0; +static volatile uint8_t caps_lock = 0; +static volatile uint8_t num_lock = 0; +static volatile uint8_t scroll_lock = 0; +static volatile uint8_t kana_lock = 0; +static volatile uint8_t kbd_in_reset = 0; +static uint8_t shift = 0; static int key5576mode = 0; @@ -106,11 +107,12 @@ static scconvtbl scconv55_8a[18 + 1] = void keyboard_init(void) { - num_lock = 0; - caps_lock = 0; - scroll_lock = 0; - kana_lock = 0; - shift = 0; + num_lock = 0; + caps_lock = 0; + scroll_lock = 0; + kana_lock = 0; + shift = 0; + kbd_in_reset = 0; memset(recv_key, 0x00, sizeof(recv_key)); memset(recv_key_ui, 0x00, sizeof(recv_key)); @@ -343,9 +345,9 @@ void keyboard_all_up(void) { for (unsigned short i = 0; i < 0x200; i++) { - if (recv_key_ui[i]) { + if (recv_key_ui[i]) recv_key_ui[i] = 0; - } + if (recv_key[i]) { recv_key[i] = 0; key_process(i, 0); @@ -353,6 +355,18 @@ keyboard_all_up(void) } } +void +keyboard_set_in_reset(uint8_t in_reset) +{ + kbd_in_reset = in_reset; +} + +uint8_t +keyboard_get_in_reset(void) +{ + return kbd_in_reset; +} + static uint8_t keyboard_do_break(uint16_t scan) { diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index fbf167e3f..4b1097df4 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -3476,7 +3476,10 @@ keyboard_at_bat(void *priv) keyboard_scan = 1; + keyboard_all_up(); keyboard_update_states(0, 0, 0, 0); + + keyboard_set_in_reset(0); kbc_at_dev_queue_add(dev, 0xaa, 0); } else { bat_counter--; @@ -3714,6 +3717,7 @@ keyboard_at_write(void *priv) break; case 0xff: /* reset */ + keyboard_set_in_reset(1); kbc_at_dev_reset(dev, 1); bat_counter = 1000; break; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index f62896106..dd8cae54b 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -273,6 +273,8 @@ extern void keyboard_input(int down, uint16_t scan); extern void keyboard_all_up(void); extern void keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl, uint8_t kl); extern uint8_t keyboard_get_shift(void); +extern void keyboard_set_in_reset(uint8_t in_reset); +extern uint8_t keyboard_get_in_reset(void); extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl, uint8_t *kl); extern void keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl); extern int keyboard_recv(uint16_t key); From 8577e0b532764353a2f09664753d353c48330c72 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 14:27:36 +0200 Subject: [PATCH 0902/1190] Also suppress any and all keyboard input while the keyboard is in reset. --- src/device/keyboard.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 6a5693f71..16904fe3b 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -240,6 +240,9 @@ key_process(uint16_t scan, int down) void keyboard_input(int down, uint16_t scan) { + if (kbd_in_reset) + return; + /* Special case for E1 1D, translate it to 0100 - special case. */ if ((scan >> 8) == 0xe1) { if ((scan & 0xff) == 0x1d) From 04b9735975e612bf0713d7b55037f5a3bc356e11 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 10 May 2025 22:11:19 +0200 Subject: [PATCH 0903/1190] Quick timer fix on the T128/PAS SCSI (May 10th, 2025) 1. If the timer result is less than 10.0 microseconds, then adjust it to 10.0. Fixes some timing read issues with the T128 (and possibly PAS SCSI). 2. Remove unused variables. --- src/scsi/scsi_t128.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index 94166054c..c5a1c4e67 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -241,9 +241,14 @@ t128_callback(void *priv) uint8_t c; uint8_t temp; uint8_t status; + double period = scsi_bus->period / 60.0; - if (scsi_bus->tx_mode != PIO_TX_BUS) - timer_on_auto(&t128->timer, scsi_bus->period / 60.0); + if (scsi_bus->tx_mode != PIO_TX_BUS) { + if (period >= 10.0) + timer_on_auto(&t128->timer, period); + else + timer_on_auto(&t128->timer, 10.0); + } if (scsi_bus->data_wait & 1) { scsi_bus->clear_req = 3; @@ -287,7 +292,6 @@ t128_callback(void *priv) t128->status &= ~0x02; t128->pos = 0; t128->host_pos = 0; - scsi_bus->data_repeat = 0; t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count); if (scsi_bus->data_pos >= dev->buffer_length) { t128->block_loaded = 0; @@ -336,7 +340,6 @@ t128_callback(void *priv) t128->status &= ~0x02; t128->pos = 0; t128->host_pos = 0; - scsi_bus->data_repeat = 0; t128_log("T128 blocks read=%d, total len=%d\n", scsi_bus->data_pos, dev->buffer_length); if (scsi_bus->data_pos >= dev->buffer_length) { scsi_bus->bus_out |= BUS_REQ; From e5606f75302ff0181991e2f15552d65a0052f0f4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 10 May 2025 23:14:10 +0200 Subject: [PATCH 0904/1190] Unix net socket: make the client socket non-blocking, fixes #5578. --- src/unix/unix_netsocket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/unix_netsocket.c b/src/unix/unix_netsocket.c index d626d025b..850fa3c6c 100644 --- a/src/unix/unix_netsocket.c +++ b/src/unix/unix_netsocket.c @@ -94,6 +94,8 @@ plat_netsocket_accept(SOCKET socket) if (clientsocket == -1) return -1; + fcntl(clientsocket, F_SETFL, fcntl(clientsocket, F_GETFL, 0) | O_NONBLOCK); + return clientsocket; } From 709771742d4255e066b215d1f9d5a056ff6ea0b1 Mon Sep 17 00:00:00 2001 From: Dave Cuthbert Date: Sat, 10 May 2025 17:19:39 -0400 Subject: [PATCH 0905/1190] Update README.md Small wording tweaks for clarity --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ee0e1e7f1..506eba794 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ Minimum system requirements and recommendations * macOS version: macOS High Sierra 10.13 or newer * 4 GB of RAM or higher -Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread; therefore, systems with better IPC (instructions per clock) generally should be able to emulate higher clock speeds. +Performance may vary depending on host and guest configuration. Most emulation logic is executed in a single thread. Therefore, systems with greater IPC (instructions per clock) capacity should be able to emulate higher clock speeds. -It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines. +For easier handling of multiple virtual machines, use a manager application: * [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux) * [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only) @@ -37,7 +37,7 @@ It is also recommended to use a manager application with 86Box for easier handli * [Linbox-qt5](https://github.com/Dungeonseeker/linbox-qt5) by [Dungeonseeker](https://github.com/Dungeonseeker/) (Linux focused, should work on Windows though untested) * [MacBox for 86Box](https://github.com/Moonif/MacBox) by [Moonif](https://github.com/Moonif) (MacOS only) -It is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option. +To use 86Box on its own, use the `--vmpath`/`-P` command line option. Getting started --------------- @@ -47,7 +47,7 @@ See [our documentation](https://86box.readthedocs.io/en/latest/index.html) for a Community --------- -We operate an IRC channel and a Discord server for discussing 86Box, its development and anything related to retro computing. We look forward to hearing from you! +We operate an IRC channel and a Discord server for discussing 86Box, its development, and anything related to retro computing. We look forward to hearing from you! [![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/86Box.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box) From 3b2ccf2229a15483f259a9afc5ddf20ec238a855 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 11 May 2025 03:46:06 +0600 Subject: [PATCH 0906/1190] Make sockets from incoming connections nonblocking on Windows --- src/qt/win_netsocket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/win_netsocket.c b/src/qt/win_netsocket.c index 55a84d414..d7d467c07 100644 --- a/src/qt/win_netsocket.c +++ b/src/qt/win_netsocket.c @@ -82,10 +82,12 @@ SOCKET plat_netsocket_accept(SOCKET socket) { SOCKET clientsocket = accept(socket, NULL, NULL); + u_long yes = 1; if (clientsocket == INVALID_SOCKET) return -1; + ioctlsocket(clientsocket, FIONBIO, &yes); return clientsocket; } From 750fa33136e05479b3eb5213525687dfd49e176c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 11 May 2025 22:01:24 +0600 Subject: [PATCH 0907/1190] Revert X11-related keyboard grabbing changes (except for `--nohook` ones) --- src/qt/qt_mainwindow.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index aaf625c2d..4594ee5be 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -327,8 +327,7 @@ MainWindow::MainWindow(QWidget *parent) if (ui->stackedWidget->mouse_capture_func) ui->stackedWidget->mouse_capture_func(this->windowHandle()); } else { - if (!(windowState() & Qt::WindowActive)) - this->releaseKeyboard(); + this->releaseKeyboard(); if (ui->stackedWidget->mouse_uncapture_func) { ui->stackedWidget->mouse_uncapture_func(); } @@ -1480,25 +1479,6 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) releaseKeyboard(); } else if (event->type() == QEvent::WindowUnblocked) { plat_pause(curdopause); -#ifdef __unix__ - if (!QApplication::platformName().contains("wayland") && (this->windowState() & Qt::WindowActive)) { - if (hook_enabled) - this->grabKeyboard(); - } -#endif - } else if (event->type() == QEvent::WindowActivate) { -#ifdef __unix__ - if (!QApplication::platformName().contains("wayland")) { - if (hook_enabled) - this->grabKeyboard(); - } -#endif - } else if (event->type() == QEvent::WindowDeactivate) { -#ifdef __unix__ - if (!QApplication::platformName().contains("wayland")) { - this->releaseKeyboard(); - } -#endif } } From f7079384f85ffc7649622fb61c67d309013ab0cd Mon Sep 17 00:00:00 2001 From: WinTP <1789016472@qq.com> Date: Tue, 13 May 2025 13:56:10 +0800 Subject: [PATCH 0908/1190] Update Simplified Chinese translation --- src/qt/languages/zh-CN.po | 72 +++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index d2ed7ce71..2af5abef9 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -849,8 +849,8 @@ msgstr "一个旧式计算机模拟器\n\n作者: Miran Grča (OBattler)、Richa msgid "Hardware not available" msgstr "硬件不可用" -msgid "Make sure %1 is installed and that you are on a libpcap-compatible network connection." -msgstr "请确认 %1 已安装且使用兼容 libpcap 的网络连接。" +msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." +msgstr "请确认 %1 已安装且使用兼容 %1 的网络连接。" msgid "Invalid configuration" msgstr "无效配置" @@ -1240,7 +1240,7 @@ msgid "Host CD/DVD Drive (%1:)" msgstr "主机 CD/DVD 驱动器 (%1:)" msgid "&Connected" -msgstr "" +msgstr "已连接(&C)" msgid "Clear image history" msgstr "清除映像历史记录" @@ -1300,7 +1300,7 @@ msgid "\nFalling back to software rendering." msgstr "\n回到软件渲染。" msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" -msgstr "

选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。

选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。

" msgid "This machine might have been moved or copied." msgstr "这台机器可能被移动或复制过。" @@ -1315,7 +1315,7 @@ msgid "I Copied It" msgstr "我已复制这台机器" msgid "86Box Monitor #" -msgstr "86Box 监测器 " +msgstr "86Box 监测器 #" msgid "No MCA devices." msgstr "无 MCA 设备。" @@ -1804,7 +1804,7 @@ msgid "Five + Wheel" msgstr "五键+滚轮" msgid "Five + 2 Wheels" -msgstr "" +msgstr "五键+双滚轮" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 串行 / SMT3(R)V" @@ -2050,25 +2050,25 @@ msgid "[Generic] RAM Disk (max. speed)" msgstr "[Generic] RAM 磁盘 (最大速度)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "" +msgstr "[Generic] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "" +msgstr "[Generic] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "" +msgstr "[Generic] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "" +msgstr "[Generic] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "" +msgstr "[Generic] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "IBM 8514/A 克隆 (ISA)" @@ -2076,6 +2076,12 @@ msgstr "IBM 8514/A 克隆 (ISA)" msgid "Vendor" msgstr "制造商" +msgid "30 Hz (JMP2 = 1)" +msgstr "30 Hz (JMP2 = 1)" + +msgid "60 Hz (JMP2 = 2)" +msgstr "60 Hz (JMP2 = 2)" + msgid "Generic PC/XT Memory Expansion" msgstr "通用 PC/XT 内存扩展" @@ -2089,61 +2095,61 @@ msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for t msgstr "仿真通用 ESC/P 点阵打印机需要使用 \"roms/printer/fonts\" 目录中的 TrueType 字体。" msgid "Inhibit multimedia keys" -msgstr "" +msgstr "禁止多媒体按键" msgid "Ask for confirmation before saving settings" -msgstr "" +msgstr "保存设置前要求用户确认" msgid "Ask for confirmation before hard resetting" -msgstr "" +msgstr "硬重置前要求用户确认" msgid "Ask for confirmation before quitting" -msgstr "" +msgstr "退出前要求用户确认" msgid "Options" -msgstr "" +msgstr "选项" msgid "Model" -msgstr "" +msgstr "模型" msgid "Model:" -msgstr "" +msgstr "模型:" msgid "Failed to initialize Vulkan renderer." -msgstr "" +msgstr "Vulkan 渲染器初始化失败。" msgid "GLSL Error" -msgstr "" +msgstr "GLSL 错误" msgid "Could not load shader: %1" -msgstr "" +msgstr "无法加载着色器:%1" msgid "OpenGL version 3.0 or greater is required. Current GLSL version is %1.%2" -msgstr "" +msgstr "OpenGL 版本需要达到 3.0 或更高。当前 GLSL 版本为 %1.%2" msgid "Could not load texture: %1" -msgstr "" +msgstr "无法加载材质:%1" msgid "Could not compile shader:\n\n%1" -msgstr "" +msgstr "无法编译着色器:\n\n%1" msgid "Program not linked:\n\n%1" -msgstr "" +msgstr "程序未链接:\n\n%1" msgid "Shader Manager" -msgstr "" +msgstr "着色器管理器" msgid "Shader Configuration" -msgstr "" +msgstr "着色器配置" msgid "Add" -msgstr "" +msgstr "添加" msgid "Move up" -msgstr "" +msgstr "上移" msgid "Move down" -msgstr "" +msgstr "下移" msgid "Could not load file %1" -msgstr "" +msgstr "无法加载文件 %1" From 0157520b767042e022c98f8977f90fb2d3323759 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 13 May 2025 17:05:13 +0200 Subject: [PATCH 0909/1190] PS/2 mouse: fix the "no poll" condition. --- src/device/mouse_ps2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 0d34235fe..2c1722f51 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -333,13 +333,13 @@ ps2_poll(void *priv) atkbc_dev_t *dev = (atkbc_dev_t *) priv; int packet_size = (dev->flags & FLAG_INTMODE) ? 4 : 3; - int cond = (!mouse_capture && !video_fullscreen) || (!mouse_scan || !mouse_state_changed()) || - ((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) >= (FIFO_SIZE - packet_size))); + int cond = (mouse_capture || video_fullscreen) && mouse_scan && (dev->mode == MODE_STREAM) && + mouse_state_changed() && (kbc_at_dev_queue_pos(dev, 1) < (FIFO_SIZE - packet_size)); - if (!cond && (dev->mode == MODE_STREAM)) + if (cond) ps2_report_coordinates(dev, 1); - return cond; + return !cond; } /* From e8c8d3373e3bd8ef013907ad8e31c90db83557dd Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 14 May 2025 10:15:14 +0200 Subject: [PATCH 0910/1190] AT KBC: some fixes. --- src/device/kbc_at.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index aaa746570..2b9cf8c18 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2149,6 +2149,12 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) dev->wantdata = 0; dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; return; } break; @@ -2160,11 +2166,36 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) dev->wantdata = 1; dev->state = STATE_KBC_PARAM; dev->command = 0xd1; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; return; } else if (fast_reset && ((val & 0xf0) == 0xf0)) { pulse_output(dev, val & 0x0f); dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; + } else if (val == 0xad) { + /* Fast track it because of the Bochs BIOS. */ + kbc_at_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + + dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; return; } else if (val == 0xae) { /* Fast track it because of the LG MultiNet. */ @@ -2172,6 +2203,12 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) set_enable_kbd(dev, 1); dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; return; } break; From cb6712805973a8a85b1a211fe9aa9d2327fbb9c7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 14 May 2025 19:08:35 +0200 Subject: [PATCH 0911/1190] AT / PS/2 keyboard: abort any pending scan code send and reinitialize queue on set defaults (command F5/F6). --- src/device/kbc_at.c | 1 + src/device/kbc_at_dev.c | 2 +- src/include/86box/keyboard.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 2b9cf8c18..ce80209a7 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -220,6 +220,7 @@ kbc_at_set_fast_reset(const uint8_t new_fast_reset) fast_reset = new_fast_reset; } +#define ENABLE_KBC_AT_LOG 1 #ifdef ENABLE_KBC_AT_LOG int kbc_at_do_log = ENABLE_KBC_AT_LOG; diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index c1041e6e1..cd55f91fa 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -58,7 +58,7 @@ kbc_at_dev_log(const char *fmt, ...) # define kbc_at_dev_log(fmt, ...) #endif -static void +void kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main) { if (reset_main) { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index dd8cae54b..9dfb1c8e4 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -291,6 +291,7 @@ extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t v extern void kbc_at_set_fast_reset(uint8_t new_fast_reset); extern void kbc_at_handler(int set, void *priv); +extern void kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main); extern uint8_t kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main); extern void kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main); extern void kbc_at_dev_reset(atkbc_dev_t *dev, int do_fa); From f09ebba33031f94d04c036e149482e26443697f6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 14 May 2025 19:18:49 +0200 Subject: [PATCH 0912/1190] Fix the previous commit. --- src/device/kbc_at.c | 1 - src/device/keyboard_at.c | 181 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 179 insertions(+), 3 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index ce80209a7..2b9cf8c18 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -220,7 +220,6 @@ kbc_at_set_fast_reset(const uint8_t new_fast_reset) fast_reset = new_fast_reset; } -#define ENABLE_KBC_AT_LOG 1 #ifdef ENABLE_KBC_AT_LOG int kbc_at_do_log = ENABLE_KBC_AT_LOG; diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 4b1097df4..ee5036f74 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -428,11 +428,11 @@ static const scancode scancode_set1[512] = { { .mk = {0xe0, 0x57, 0 }, .brk = { 0xe0, 0xd7, 0 } }, /* 157 */ { .mk = {0xe0, 0x58, 0 }, .brk = { 0xe0, 0xd8, 0 } }, /* 158 */ { .mk = {0xe0, 0x59, 0 }, .brk = { 0xe0, 0xd9, 0 } }, /* 159 */ - { .mk = {0xe0, 0x5a, 0 }, .brk = { 0xe0, 0xaa, 0 } }, /* 15a */ + { .mk = {0xe0, 0x5a, 0 }, .brk = { 0xe0, 0xda, 0 } }, /* 15a */ { .mk = {0xe0, 0x5b, 0 }, .brk = { 0xe0, 0xdb, 0 } }, /* 15b */ { .mk = {0xe0, 0x5c, 0 }, .brk = { 0xe0, 0xdc, 0 } }, /* 15c */ { .mk = {0xe0, 0x5d, 0 }, .brk = { 0xe0, 0xdd, 0 } }, /* 15d */ - { .mk = {0xe0, 0x5e, 0 }, .brk = { 0xe0, 0xee, 0 } }, /* 15e */ + { .mk = {0xe0, 0x5e, 0 }, .brk = { 0xe0, 0xde, 0 } }, /* 15e */ { .mk = {0xe0, 0x5f, 0 }, .brk = { 0xe0, 0xdf, 0 } }, /* 15f */ { .mk = { 0 }, .brk = { 0 } }, /* 160 */ { .mk = {0xe0, 0x61, 0 }, .brk = { 0xe0, 0xe1, 0 } }, /* 161 */ @@ -3643,6 +3643,13 @@ keyboard_at_write(void *priv) case 0xf6: /* set defaults */ keyboard_at_log("%s: set defaults%s\n", dev->name, (val == 0xf6) ? "" : " and disable keyboard"); + dev->port->out_new = -1; + dev->port->wantcmd = 0; + + kbc_at_dev_queue_reset(dev, 1); + + dev->last_scan_code = 0x00; + keyboard_scan = !(val & 0x01); keyboard_at_log("%s: val = %02X, keyboard_scan = %i\n", dev->name, val, keyboard_scan); @@ -3728,6 +3735,44 @@ keyboard_at_write(void *priv) } } +#ifdef SCAN_CODE_TABLES_COMPARISON +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0x00, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, + 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, + 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, + 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, + 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, + 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, + 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, + 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, + 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, + 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, + 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, + 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, + 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; +#endif + /* * Initialize the device for use by the user. * @@ -3777,6 +3822,138 @@ keyboard_at_init(const device_t *info) inv_cmd_response = (dev->type & FLAG_PS2) ? 0xfe : 0xfa; +#ifdef SCAN_CODE_TABLES_COMPARISON + pclog_toggle_suppr(); + + pclog("Scan code set 01 vs. 81 (make):\n===============================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + do { + if (scancode_set1[i].mk[j] == scancode_set81[i].mk[j]) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set1[i].mk[j], scancode_set81[i].mk[j]); + j++; + } while ((scancode_set1[i].mk[j] != 0) && (scancode_set81[i].mk[j] != 0)); + pclog("\n"); + } + + pclog("\nScan code set 01 vs. 81 (break):\n================================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + do { + if (scancode_set1[i].brk[j] == scancode_set81[i].brk[j]) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set1[i].brk[j], scancode_set81[i].brk[j]); + j++; + } while ((scancode_set1[i].brk[j] != 0) && (scancode_set81[i].brk[j] != 0)); + pclog("\n"); + } + + pclog("\nScan code set 02 vs. 82 (make):\n===============================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + do { + if (scancode_set2[i].mk[j] == scancode_set82[i].mk[j]) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set2[i].mk[j], scancode_set82[i].mk[j]); + j++; + } while ((scancode_set2[i].mk[j] != 0) && (scancode_set82[i].mk[j] != 0)); + pclog("\n"); + } + + pclog("\nScan code set 02 vs. 82 (break):\n================================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + do { + if (scancode_set2[i].brk[j] == scancode_set82[i].brk[j]) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set2[i].brk[j], scancode_set82[i].brk[j]); + j++; + } while ((scancode_set2[i].brk[j] != 0) && (scancode_set82[i].brk[j] != 0)); + pclog("\n"); + } + + pclog("\nScan code set 01 vs. 02 (make):\n===============================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + int k = 0; + int was_f0 = 0; + do { + if (scancode_set2[i].mk[k] == 0xf0) + was_f0 = 1; + else { + uint8_t code = nont_to_t[scancode_set2[i].mk[k]]; + + if (was_f0) { + if (code & 0x80) + code = 0x00; + else + code |= 0x80; + + was_f0 = 0; + } + + if (scancode_set1[i].mk[j] == code) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set1[i].mk[j], code); + + j++; + } + + k++; + } while ((scancode_set1[i].mk[j] != 0) && (scancode_set2[i].mk[k] != 0)); + pclog("\n"); + } + + pclog("\nScan code set 01 vs. 02 (break):\n================================\n"); + for (int i = 0; i < 512; i++) { + pclog("Scan code %03X:", i); + int j = 0; + int k = 0; + int was_f0 = 0; + do { + if (scancode_set2[i].brk[k] == 0xf0) + was_f0 = 1; + else { + uint8_t code = nont_to_t[scancode_set2[i].brk[k]]; + + if (was_f0) { + if (code & 0x80) + code = 0x00; + else + code |= 0x80; + + was_f0 = 0; + } + + if (scancode_set1[i].brk[j] == code) + pclog(" --"); + else + pclog(" (%02X != %02X)", scancode_set1[i].brk[j], code); + + j++; + } + + k++; + } while ((scancode_set1[i].brk[j] != 0) && (scancode_set2[i].brk[k] != 0)); + pclog("\n"); + } + + pclog_toggle_suppr(); + + fatal("Comparison finished\n"); +#endif + /* Return our private data to the I/O layer. */ return dev; } From 4fb38db2f8694c3856fb77f1600400d8acdd7f26 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Wed, 14 May 2025 20:12:17 +0200 Subject: [PATCH 0913/1190] Update machine.h Add the Phoenix BIOS variant for the Micronics 09-00021 (part 1) --- src/include/86box/machine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c28add516..8abd8fef1 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -519,6 +519,7 @@ extern int machine_at_asus386_init(const machine_t *); extern int machine_at_ecs386_init(const machine_t *); extern int machine_at_spc6000a_init(const machine_t *); extern int machine_at_micronics386_init(const machine_t *); +extern int machine_at_micronics386px_init(const machine_t *); extern int machine_at_ecs386v_init(const machine_t *); extern int machine_at_tandy4000_init(const machine_t *); From bf07f6452e4781ba1cd8ee2c2ca1db8169ed1e53 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Wed, 14 May 2025 20:15:21 +0200 Subject: [PATCH 0914/1190] Add the Phoenix BIOS variant for the Micronics 09-00021 (part 2) --- src/machine/m_at_286_386sx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index b084bfbbd..c9fb124cb 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -281,6 +281,26 @@ machine_at_micronics386_init(const machine_t *model) return ret; } +int +machine_at_micronics386px_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/micronics386/386-Micronics-09-00021-LO.BIN", + "roms/machines/micronics386/386-Micronics-09-00021-HI.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + static void machine_at_scat_init(const machine_t *model, int is_v4, int is_ami) { From b334bd09aff796983da71dec7c8f4057e85795b9 Mon Sep 17 00:00:00 2001 From: pankozaC++ <77279607+pankoza2-pl@users.noreply.github.com> Date: Wed, 14 May 2025 20:18:24 +0200 Subject: [PATCH 0915/1190] Add the Phoenix BIOS variant for the Micronics 09-00021 (part 3) --- src/machine/machine_table.c | 42 ++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 34e69ed24..5acee0350 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5435,7 +5435,7 @@ const machine_t machines[] = { }, /* Has IBM AT KBC firmware. */ { - .name = "[ISA] Micronics 09-00021", + .name = "[ISA] Micronics 09-00021 (Tandon BIOS)", .internal_name = "micronics386", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_DISCRETE, @@ -5474,6 +5474,46 @@ const machine_t machines[] = { .net_device = NULL }, /* Has IBM AT KBC firmware. */ + { + .name = "[ISA] Micronics 09-00021 (Phoenix BIOS)", + .internal_name = "micronics386px", + .type = MACHINE_TYPE_386DX, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_at_micronics386px_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_APM, + .ram = { + .min = 512, + .max = 8192, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, + /* Has IBM AT KBC firmware. */ { .name = "[ISA] Tandy 4000", .internal_name = "tandy4000", From c804a2892a9f1b48f4fc80503d75c77e7410de79 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 15 May 2025 00:27:46 +0200 Subject: [PATCH 0916/1190] Some more Compaq AT changes of the night (May 15th, 2025) 1. Properly return the flat panel display bit in port 0x1bc6, fixes adapt.com and the corresponding Portable identification in the disk cmos. 2. Preliminary MDA mapping on the Plasma display, per bit 3 toggling of port 0x23c6. 3. Implemented port 0x17c6. 4. Cleanups. --- src/machine/m_at_compaq.c | 552 +++++++++++++++++++++----------------- 1 file changed, 304 insertions(+), 248 deletions(-) diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 904122bad..c0b254388 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -61,11 +61,6 @@ enum { /*Very rough estimate*/ #define VID_CLOCK (double) (651 * 416 * 60) -static uint8_t cga_crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - /* Mapping of attributes to colours */ static uint32_t amber; static uint32_t black; @@ -97,7 +92,10 @@ compaq_plasma_display_get(void) typedef struct compaq_plasma_t { cga_t cga; + uint8_t ctl_mode; + uint8_t port_13c6; uint8_t port_23c6; + uint8_t port_27c6; uint8_t internal_monitor; uint8_t attrmap; } compaq_plasma_t; @@ -116,16 +114,18 @@ compaq_plasma_recalctimings(compaq_plasma_t *self) double _dispofftime; double disptime; - if (!self->internal_monitor && !(self->port_23c6 & 1)) { + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { cga_recalctimings(&self->cga); return; } disptime = 651; _dispontime = 640; - _dispofftime = disptime - _dispontime; - self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); - self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; + self->cga.dispontime = (uint64_t) (_dispontime); + self->cga.dispofftime = (uint64_t) (_dispofftime); } static void @@ -144,9 +144,9 @@ compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) compaq_plasma_t *self = (compaq_plasma_t *) priv; self->cga.vram[addr & 0x7fff] = val; + compaq_plasma_waitstates(&self->cga); } - static uint8_t compaq_plasma_read(uint32_t addr, void *priv) { @@ -163,49 +163,59 @@ static void compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) { compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t old; + + if (self->port_23c6 & 0x08) { + if ((addr >= 0x3d0) && (addr <= 0x3dc)) + addr ^= 0x60; + } switch (addr) { /* Emulated CRTC, register select */ + case 0x3d0: + case 0x3d2: case 0x3d4: + case 0x3d6: cga_out(addr, val, &self->cga); break; /* Emulated CRTC, value */ + case 0x3d1: + case 0x3d3: case 0x3d5: - old = self->cga.crtc[self->cga.crtcreg]; - self->cga.crtc[self->cga.crtcreg] = val & cga_crtcmask[self->cga.crtcreg]; - + case 0x3d7: /* Register 0x12 controls the attribute mappings for the * plasma screen. */ if (self->cga.crtcreg == 0x12) { self->attrmap = val; compaq_plasma_recalcattrs(self); - break; + return; } + cga_out(addr, val, &self->cga); - if (old != val) { - if (self->cga.crtcreg < 0xe || self->cga.crtcreg > 0x10) { - self->cga.fullchange = changeframecount; - compaq_plasma_recalctimings(self); - } - } + compaq_plasma_recalctimings(self); break; case 0x3d8: case 0x3d9: + case 0x3db: + case 0x3dc: cga_out(addr, val, &self->cga); break; case 0x13c6: - compaq_plasma_display_set((val & 8) ? 1 : 0); + self->port_13c6 = val; + compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); break; case 0x23c6: self->port_23c6 = val; - if (val & 8) /* Disable internal CGA */ - mem_mapping_disable(&self->cga.mapping); + if (val & 0x08) /* Disable internal CGA */ + mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x8000); else - mem_mapping_enable(&self->cga.mapping); + mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x8000); + break; + + case 0x27c6: + self->port_27c6 = val; break; default: @@ -219,40 +229,53 @@ compaq_plasma_in(uint16_t addr, void *priv) compaq_plasma_t *self = (compaq_plasma_t *) priv; uint8_t ret = 0xff; + if (self->port_23c6 & 0x08) { + if ((addr >= 0x3d0) && (addr <= 0x3dc)) + addr ^= 0x60; + } + switch (addr) { case 0x3d4: case 0x3da: + case 0x3db: + case 0x3dc: ret = cga_in(addr, &self->cga); break; + case 0x3d1: + case 0x3d3: case 0x3d5: + case 0x3d7: if (self->cga.crtcreg == 0x12) { ret = self->attrmap & 0x0f; - if (self->internal_monitor) + if (compaq_plasma_display_get()) ret |= 0x30; /* Plasma / CRT */ } else ret = cga_in(addr, &self->cga); + break; + + case 0x3d8: + ret = self->cga.cgamode; break; case 0x13c6: - ret = compaq_plasma_display_get() ? 8 : 0; - ret |= 4; + ret = self->port_13c6; + break; + + case 0x17c6: + ret = 0xf6; break; case 0x1bc6: - ret = 0; - if (compaq_plasma_display_get()) { - if ((self->cga.cgamode & 0x12) == 0x12) { - if (self->port_23c6 & 8) - ret |= 0x40; - else - ret |= 0x20; - } - } + ret = 0x40; break; case 0x23c6: - ret = 0; + ret = self->port_23c6; + break; + + case 0x27c6: + ret = self->port_27c6 & 0x3f; break; default: @@ -276,6 +299,8 @@ compaq_plasma_poll(void *priv) int cursorline; int blink = 0; int underline = 0; + int c; + int x; uint32_t ink = 0; uint32_t fg = (self->cga.cgacol & 0x0f) ? amber : black; uint32_t bg = black; @@ -292,230 +317,252 @@ compaq_plasma_poll(void *priv) } /* graphic mode and not mode 40h */ - if (!self->internal_monitor && !(self->port_23c6 & 1)) { + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { + /* standard cga mode */ cga_poll(&self->cga); return; - } + } else { + /* mode 40h or text mode */ + if (!self->cga.linepos) { + timer_advance_u64(&self->cga.timer, self->cga.dispofftime); + self->cga.cgastat |= 1; + self->cga.linepos = 1; + if (self->cga.cgadispon) { + if (self->cga.displine == 0) + video_wait_for_buffer(); - /* mode 40h or text mode */ - if (!self->cga.linepos) { - timer_advance_u64(&self->cga.timer, self->cga.dispofftime); - self->cga.cgastat |= 1; - self->cga.linepos = 1; - if (self->cga.cgadispon) { - if (self->cga.displine == 0) { - video_wait_for_buffer(); - } - if (self->cga.cgamode & 2) { - if (self->cga.cgamode & 0x10) { - /* 640x400 mode */ - if (self->port_23c6 & 1) /* 640*400 */ { - addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7FFF]; - addr++; + /* 80-col */ + if (self->cga.cgamode & 0x01) { + sc = self->cga.displine & 0x0f; + addr = ((ma & ~1) + (self->cga.displine >> 4) * 80) << 1; + ma += (self->cga.displine >> 4) * 80; - for (uint8_t c = 0; c < 8; c++) { - ink = (dat & 0x80) ? fg : bg; - if (!(self->cga.cgamode & 8)) - ink = black; - (buffer32->line[self->cga.displine])[x * 8 + c] = ink; - dat <<= 1; + if ((self->cga.crtc[0x0a] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); + + /* for each text column */ + for (x = 0; x < 80; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else + chr = attr = 0; + /* check if cursor has to be drawn */ + drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = (((self->port_23c6 >> 5) == 2) && (attr & 0x01) && !(attr & 0x06)); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & 0x20) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + blink = ((attr & 0x80) << 3) + 7 + 16; + } + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + + ma++; + } + } + /* 40-col */ + else if (!(self->cga.cgamode & 0x02)) { + sc = self->cga.displine & 0x0f; + addr = ((ma & ~1) + (self->cga.displine >> 4) * 40) << 1; + ma += (self->cga.displine >> 4) * 40; + + if ((self->cga.crtc[0x0a] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); + + for (x = 0; x < 40; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else + chr = attr = 0; + + /* check if cursor has to be drawn */ + drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = (((self->port_23c6 >> 5) == 2) && (attr & 0x01) && !(attr & 0x06)); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & 0x20) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + blink = ((attr & 0x80) << 3) + 7 + 16; + } + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (self->cga.sc == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + + ma++; } } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7fff]; - addr++; + if (self->cga.cgamode & 0x10) { + /* 640x400 mode */ + if (self->port_23c6 & 0x01) /* 640*400 */ { + addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + } else { + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + } + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; - for (uint8_t c = 0; c < 4; c++) { - pattern = (dat & 0xC0) >> 6; - if (!(self->cga.cgamode & 8)) - pattern = 0; - - switch (pattern & 3) { - case 0: - ink0 = ink1 = black; - break; - case 1: - if (self->cga.displine & 1) { - ink0 = black; - ink1 = black; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 2: - if (self->cga.displine & 1) { - ink0 = black; - ink1 = amber; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 3: - ink0 = ink1 = amber; - break; - - default: - break; + for (uint8_t c = 0; c < 8; c++) { + ink = (dat & 0x80) ? fg : bg; + if (!(self->cga.cgamode & 0x08)) + ink = black; + buffer32->line[self->cga.displine][(x << 3) + c] = ink; + dat <<= 1; } - buffer32->line[self->cga.displine][x * 8 + 2 * c] = ink0; - buffer32->line[self->cga.displine][x * 8 + 2 * c + 1] = ink1; - dat <<= 2; - } - } - } - } else if (self->cga.cgamode & 1) { - /* 80-col */ - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 80) * 2; - ma += (self->cga.displine >> 4) * 80; - - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = ((self->cga.crtc[0x0a] & 0x0f) * 2 <= sc) && ((self->cga.crtc[0x0b] & 0x0F) * 2 >= sc); - - /* for each text column */ - for (uint8_t x = 0; x < 80; x++) { - /* video output enabled */ - chr = self->cga.vram[(addr + 2 * x) & 0x7FFF]; - attr = self->cga.vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 8) && (self->cga.cgablink & 16)); - - blink = ((self->cga.cgablink & 16) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); - underline = ((self->port_23c6 & 0x40) && (attr & 0x1) && !(attr & 0x6)); - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if (blink) { - /* set blinking */ - cols[1] = cols[0]; } } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; - } - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; - } + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; - ++ma; - } - } else { /* 40-col */ - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 40) * 2; - ma += (self->cga.displine >> 4) * 40; + for (uint8_t c = 0; c < 4; c++) { + pattern = (dat & 0xC0) >> 6; + if (!(self->cga.cgamode & 0x08)) + pattern = 0; - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = ((self->cga.crtc[0x0a] & 0x0f) * 2 <= sc) && ((self->cga.crtc[0x0b] & 0x0F) * 2 >= sc); + switch (pattern & 3) { + case 0: + ink0 = ink1 = black; + break; + case 1: + case 2: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = amber; + } else { + ink0 = amber; + ink1 = black; + } + break; + case 3: + ink0 = ink1 = amber; + break; - for (uint8_t x = 0; x < 40; x++) { - chr = self->cga.vram[(addr + 2 * x) & 0x7FFF]; - attr = self->cga.vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 8) && (self->cga.cgablink & 16)); - - blink = ((self->cga.cgablink & 16) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); - underline = ((self->port_23c6 & 0x40) && (attr & 0x1) && !(attr & 0x6)); - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[1] = blinkcols[attr][1]; - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if (blink) { - /* set blinking */ - cols[1] = cols[0]; + default: + break; + } + buffer32->line[self->cga.displine][(x << 3) + (c << 1)] = ink0; + buffer32->line[self->cga.displine][(x << 3) + (c << 1) + 1] = ink1; + dat <<= 2; + } } - } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; } - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c * 2)] = buffer32->line[self->cga.displine][(x << 4) + (c * 2) + 1] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + c * 2] = buffer32->line[self->cga.displine][(x << 4) + c * 2 + 1] = cols[(fontdatm2[chr][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (uint8_t c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + c * 2] = buffer32->line[self->cga.displine][(x << 4) + c * 2 + 1] = cols[(fontdatm2[chr][sc] & (1 << (c ^ 7))) ? 1 : 0]; - } - ++ma; } } - } - self->cga.displine++; - /* Hardcode a fixed refresh rate and VSYNC timing */ - if (self->cga.displine == 400) { /* Start of VSYNC */ - self->cga.cgastat |= 8; - self->cga.cgadispon = 0; - } - if (self->cga.displine == 416) { /* End of VSYNC */ - self->cga.displine = 0; - self->cga.cgastat &= ~8; - self->cga.cgadispon = 1; - } - } else { - if (self->cga.cgadispon) - self->cga.cgastat &= ~1; + self->cga.displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (self->cga.displine == 400) { /* Start of VSYNC */ + self->cga.cgastat |= 8; + self->cga.cgadispon = 0; + } + if (self->cga.displine == 416) { /* End of VSYNC */ + self->cga.displine = 0; + self->cga.cgastat &= ~8; + self->cga.cgadispon = 1; + } + } else { + timer_advance_u64(&self->cga.timer, self->cga.dispontime); + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; - timer_advance_u64(&self->cga.timer, self->cga.dispontime); - self->cga.linepos = 0; + self->cga.linepos = 0; - if (self->cga.displine == 400) { - /* Hardcode 640x400 window size */ - if ((640 != xsize) || (400 != ysize) || video_force_resize_get()) { + if (self->cga.displine == 400) { xsize = 640; ysize = 400; - if (xsize < 64) - xsize = 656; - if (ysize < 32) - ysize = 200; - set_screen_size(xsize, ysize); - if (video_force_resize_get()) - video_force_resize_set(0); + if ((self->cga.cgamode & 0x08) || video_force_resize_get()) { + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + /* ogc specific */ + video_blit_memtoscreen(0, 0, xsize, ysize); + frames++; + + /* Fixed 640x400 resolution */ + video_res_x = 640; + video_res_y = 400; + + if (self->cga.cgamode & 0x02) { + if (self->cga.cgamode & 0x10) + video_bpp = 1; + else + video_bpp = 2; + } else + video_bpp = 0; + + self->cga.cgablink++; } - video_blit_memtoscreen(0, 0, xsize, ysize); - frames++; - - /* Fixed 640x400 resolution */ - video_res_x = 640; - video_res_y = 400; - - if (self->cga.cgamode & 0x02) { - if (self->cga.cgamode & 0x10) - video_bpp = 1; - else - video_bpp = 2; - } else - video_bpp = 0; - - self->cga.cgablink++; } } } @@ -560,7 +607,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) /* Set up colours */ amber = makecol(0xff, 0x7d, 0x00); - black = makecol(0x64, 0x0c, 0x00); + black = makecol(0x64, 0x19, 0x00); /* Initialize the attribute mapping. Start by defaulting everything * to black on amber, and with bold set by bit 3 */ @@ -631,12 +678,14 @@ compaq_plasma_init(UNUSED(const device_t *info)) { compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); if (compaq_machine_type == COMPAQ_PORTABLEIII) loadfont_ex("roms/machines/portableiii/K Combined.bin", 11, 0x4bb2); else loadfont_ex("roms/machines/portableiii/P.2 Combined.bin", 11, 0x4b49); + cga_init(&self->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); + self->cga.composite = 0; self->cga.revision = 0; @@ -644,12 +693,16 @@ compaq_plasma_init(UNUSED(const device_t *info)) self->internal_monitor = 1; cga_comp_init(self->cga.revision); - timer_add(&self->cga.timer, compaq_plasma_poll, self, 1); - mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, compaq_plasma_read, NULL, NULL, compaq_plasma_write, NULL, NULL, NULL /*self->cga.vram*/, MEM_MAPPING_EXTERNAL, self); - io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x13c6, 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x1bc6, 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x23c6, 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + timer_set_callback(&self->cga.timer, compaq_plasma_poll); + timer_set_p(&self->cga.timer, self); + + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, compaq_plasma_read, NULL, NULL, compaq_plasma_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + for (int i = 1; i <= 2; i++) { + io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + } + io_sethandler(0x03d0, 0x000c, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); /* Default attribute mapping is 4 */ self->attrmap = 4; @@ -793,7 +846,8 @@ machine_at_compaq_init(const machine_t *model, int type) switch (type) { case COMPAQ_PORTABLEII: - machine_at_init(model); + machine_at_common_init(model); + device_add(&keyboard_at_compaq_device); break; case COMPAQ_PORTABLEIII: @@ -801,7 +855,9 @@ machine_at_compaq_init(const machine_t *model, int type) device_add(&ide_isa_device); if (gfxcard[0] == VID_INTERNAL) device_add(&compaq_plasma_device); - machine_at_init(model); + + machine_at_common_init(model); + device_add(&keyboard_at_compaq_device); break; case COMPAQ_PORTABLEIII386: From 6aec346cc5e88f5012a9a764ba5c729373fcb174 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 May 2025 04:11:29 +0200 Subject: [PATCH 0917/1190] AT keyboard: Fix last scan code resending, fixes E0-prefixed keys on some machines. --- src/device/kbc_at_dev.c | 10 ++++++---- src/device/keyboard_at.c | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/device/kbc_at_dev.c b/src/device/kbc_at_dev.c index cd55f91fa..b20e38860 100644 --- a/src/device/kbc_at_dev.c +++ b/src/device/kbc_at_dev.c @@ -95,10 +95,6 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main) dev->cmd_queue[dev->cmd_queue_end] = val; dev->cmd_queue_end = (dev->cmd_queue_end + 1) & 0xf; } - - /* TODO: This should be done on actual send to host. */ - if (val != 0xfe) - dev->last_scan_code = val; } static void @@ -123,6 +119,8 @@ kbc_at_dev_poll(void *priv) (dev->queue_start != dev->queue_end)) { kbc_at_dev_log("%s: %02X (DATA) on channel 1\n", dev->name, dev->queue[dev->queue_start]); dev->port->out_new = dev->queue[dev->queue_start]; + if (dev->port->out_new != 0xfe) + dev->last_scan_code = dev->port->out_new; dev->queue_start = (dev->queue_start + 1) & dev->fifo_mask; } if (dev->ignore || !(*dev->scan) || dev->port->wantcmd) @@ -143,6 +141,8 @@ kbc_at_dev_poll(void *priv) if ((dev->port->out_new == -1) && (dev->cmd_queue_start != dev->cmd_queue_end)) { kbc_at_dev_log("%s: %02X (CMD ) on channel 1\n", dev->name, dev->cmd_queue[dev->cmd_queue_start]); dev->port->out_new = dev->cmd_queue[dev->cmd_queue_start]; + if (dev->port->out_new != 0xfe) + dev->last_scan_code = dev->port->out_new; dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf; } if (dev->cmd_queue_start == dev->cmd_queue_end) @@ -166,6 +166,8 @@ kbc_at_dev_poll(void *priv) if ((dev->port->out_new == -1) && (dev->cmd_queue_start != dev->cmd_queue_end)) { kbc_at_dev_log("%s: %02X (CMD ) on channel 1\n", dev->name, dev->cmd_queue[dev->cmd_queue_start]); dev->port->out_new = dev->cmd_queue[dev->cmd_queue_start]; + if (dev->port->out_new != 0xfe) + dev->last_scan_code = dev->port->out_new; dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf; } if (dev->cmd_queue_start == dev->cmd_queue_end) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index ee5036f74..7fa2b9706 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -3494,7 +3494,6 @@ keyboard_at_invalid_cmd(atkbc_dev_t *dev) kbc_at_dev_queue_add(dev, inv_cmd_response, 0); } - static void keyboard_at_write(void *priv) { @@ -3719,7 +3718,6 @@ keyboard_at_write(void *priv) /* TODO: This is supposed to resend multiple bytes after some commands. */ case 0xfe: /* resend last scan code */ keyboard_at_log("%s: resend last scan code\n", dev->name); - kbc_at_dev_queue_add(dev, 0xfa, 0); kbc_at_dev_queue_add(dev, dev->last_scan_code, 0); break; From 4331d78b829427024a4e46e338655c279929f92c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 May 2025 04:26:14 +0200 Subject: [PATCH 0918/1190] Added the DTK PKM-0031Y. --- src/chipset/CMakeLists.txt | 1 + src/chipset/sl82c461.c | 362 +++++++++++++++++++++++++++++++++++ src/include/86box/chipset.h | 3 + src/include/86box/machine.h | 1 + src/machine/m_at_386dx_486.c | 21 ++ src/machine/machine_table.c | 40 ++++ 6 files changed, 428 insertions(+) create mode 100644 src/chipset/sl82c461.c diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 94ef408f6..7d17b9983 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -72,6 +72,7 @@ add_library(chipset OBJECT sis_5572_usb.c sis_5595_pmu.c sis_55xx.c + sl82c461.c via_vt82c49x.c via_vt82c505.c gc100.c diff --git a/src/chipset/sl82c461.c b/src/chipset/sl82c461.c new file mode 100644 index 000000000..f94aa2e99 --- /dev/null +++ b/src/chipset/sl82c461.c @@ -0,0 +1,362 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Symphony SL82C461 (Haydn II) chipset. + * + * Symphony SL82C461 Configuration Registers (WARNING: May be inaccurate!): + * + * - Register 00h: + * - Bit 6: External cache present (if clear, AMI BIOS'es will not + * allow enabling external cache). + * + * - Register 01h: + * - Bit 0: Fast Gate A20 Enable (Handler mostly). + * Is it? Enabling/disabling fast gate A20 doesn't appear + * to do much to any register at all. + * + * - Register 02h: + * - Bit 0: Optional Chipset Turbo Pin; + * - Bits 4-2: + * - 000 = CLK2/3; + * - 001 = CLK2/4; + * - 010 = CLK2/5; + * - 011 = 7.159 MHz (ATCLK2); + * - 100 = CLK2/6; + * - 110 = CLK2/2.5; + * - 111 = CLK2/2. + * + * - Register 06h: + * - Bit 2: Decoupled Refresh Option. + * + * - Register 08h: + * - Bits 3, 2: I/O Recovery Time (SYSCLK): + * - 0, 0 = 0; + * - 1, 1 = 12. + * - Bit 1: Extended ALE. + * + * - Register 25h: + * Bit 7 here causes AMI 111192 CMOS Setup to return 7168 KB RAM + * instead of 6912 KB. This is 256 KB off. Relocation? + * Also, returning bit 5 clear instead of set, causes the AMI BIOS + * to set bits 0,1 of register 45h to 1,0 instead of 0,1. + * + * - Register 2Dh: + * - Bit 7: Enable 256KB Memory Relocation; + * - Bit 6: Enable 384KB Memory Relocation, bit 7 must also be set. + * + * - Register 2Eh: + * - Bit 7: CC000-CFFFF Shadow Read Enable; + * - Bit 6: CC000-CFFFF Shadow Write Enable; + * - Bit 5: C8000-CBFFF Shadow Read Enable; + * - Bit 4: C8000-CBFFF Shadow Write Enable; + * - Bit 3: C4000-C7FFF Shadow Read Enable; + * - Bit 2: C4000-C7FFF Shadow Write Enable; + * - Bit 1: C0000-C3FFF Shadow Read Enable; + * - Bit 0: C0000-C3FFF Shadow Write Enable. + * + * - Register 2Fh: + * - Bit 7: DC000-DFFFF Shadow Read Enable; + * - Bit 6: DC000-DFFFF Shadow Write Enable; + * - Bit 5: D8000-DBFFF Shadow Read Enable; + * - Bit 4: D8000-DBFFF Shadow Write Enable; + * - Bit 3: D4000-D7FFF Shadow Read Enable; + * - Bit 2: D4000-D7FFF Shadow Write Enable; + * - Bit 1: D0000-D3FFF Shadow Read Enable; + * - Bit 0: D0000-D3FFF Shadow Write Enable. + * + * - Register 30h: + * - Bit 7: E0000-EFFFF Shadow Read Enable; + * - Bit 6: E0000-EFFFF Shadow Write Enable. + * + * - Register 31h: + * - Bit 7: F0000-FFFFF Shadow Read Enable; + * - Bit 6: F0000-FFFFF Shadow Write Enable. + * + * - Register 33h (NOTE: Waitstates also affect register 32h): + * - Bits 3, 0: + * - 0,0 = 0 W/S; + * - 1,0 = 1 W/S; + * - 1,1 = 2 W/S. + * + * - Register 40h: + * - Bit 3: External Cache Enabled (0 = yes, 1 = no); + * I also see bits 5, 4, 3 of register 44h affected: + * - 38h (so all 3 set) when cache is disabled; + * - 00h (all 3 clear) when it's enabled. + * + * - Register 45h: + * - Bit 3: Video Shadow RAM Cacheable; + * - Bit 4: Adapter Shadow RAM Cacheable; + * - Bit 5: BIOS Shadow RAM Cacheable. + * + * Authors: Miran Grca, + * Tiseno100, + * + * Copyright 2025 Miran Grca. + * Copyright 2021-2025 Tiseno100. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/chipset.h> + +typedef struct { + uint8_t index; + uint8_t regs[256]; + uint8_t shadow[4]; +} sl82c461_t; + +#ifdef ENABLE_SL82C461_LOG +int sl82c461_do_log = ENABLE_SL82C461_LOG; + +static void +sl82c461_log(const char *fmt, ...) +{ + va_list ap; + + if (sl82c461_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sl82c461_log(fmt, ...) +#endif + +static void +sl82c461_recalcmapping(sl82c461_t *dev) +{ + int do_shadow = 0; + + for (uint32_t i = 0; i < 8; i += 2) { + if ((dev->regs[0x2e] ^ dev->shadow[0x00]) & (3 << i)) { + uint32_t base = 0x000c0000 + ((i >> 1) << 14); + uint32_t read = ((dev->regs[0x2e] >> i) & 0x02) ? MEM_READ_INTERNAL : + MEM_READ_EXTANY; + uint32_t write = ((dev->regs[0x2e] >> i) & 0x01) ? MEM_WRITE_INTERNAL : + MEM_WRITE_EXTANY; + + mem_set_mem_state_both(base, 0x00004000, read | write); + + do_shadow++; + } + + if ((dev->regs[0x2f] ^ dev->shadow[0x01]) & (3 << i)) { + uint32_t base = 0x000d0000 + ((i >> 1) << 14); + uint32_t read = ((dev->regs[0x2f] >> i) & 0x02) ? MEM_READ_INTERNAL : + MEM_READ_EXTANY; + uint32_t write = ((dev->regs[0x2f] >> i) & 0x01) ? MEM_WRITE_INTERNAL : + MEM_WRITE_EXTANY; + + mem_set_mem_state_both(base, 0x00004000, read | write); + + do_shadow++; + } + } + + if ((dev->regs[0x30] ^ dev->shadow[0x02]) & 0xc0) { + uint32_t base = 0x000e0000; + uint32_t read = ((dev->regs[0x30] >> 6) & 0x02) ? MEM_READ_INTERNAL : + MEM_READ_EXTANY; + uint32_t write = ((dev->regs[0x30] >> 6) & 0x01) ? MEM_WRITE_INTERNAL : + MEM_WRITE_EXTANY; + + mem_set_mem_state_both(base, 0x00010000, read | write); + + do_shadow++; + } + + if ((dev->regs[0x31] ^ dev->shadow[0x03]) & 0xc0) { + uint32_t base = 0x000f0000; + uint32_t read = ((dev->regs[0x31] >> 6) & 0x02) ? MEM_READ_INTERNAL : + MEM_READ_EXTANY; + uint32_t write = ((dev->regs[0x31] >> 6) & 0x01) ? MEM_WRITE_INTERNAL : + MEM_WRITE_EXTANY; + + shadowbios = !!((dev->regs[0x31] >> 6) & 0x02); + shadowbios_write = !!((dev->regs[0x31] >> 6) & 0x01); + + mem_set_mem_state_both(base, 0x00010000, read | write); + + do_shadow++; + } + + if (do_shadow) { + memcpy(dev->shadow, &(dev->regs[0x2e]), 4 * sizeof(uint8_t)); + flushmmucache_nopc(); + } +} + +static void +sl82c461_write(uint16_t addr, uint8_t val, void *priv) +{ + sl82c461_t *dev = (sl82c461_t *) priv; + + sl82c461_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); + + if (addr & 0x0001) { + dev->regs[dev->index] = val; + + switch (dev->index) { + case 0x01: + /* NOTE: This is to be verified. */ + mem_a20_alt = val & 1; + mem_a20_recalc(); + break; + case 0x02: { + double bus_clk; + switch (val & 0x1c) { + case 0x00: + bus_clk = cpu_busspeed / 3.0; + break; + case 0x04: + bus_clk = cpu_busspeed / 4.0; + break; + case 0x08: + bus_clk = cpu_busspeed / 5.0; + break; + default: + case 0x0c: + bus_clk = 7159091.0; + break; + case 0x10: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x18: + bus_clk = cpu_busspeed / 2.5; + break; + case 0x1c: + bus_clk = cpu_busspeed / 2.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + break; + } case 0x2d: + switch (val & 0xc0) { + case 0xc0: + mem_remap_top(384); + break; + case 0x80: + mem_remap_top(256); + break; + default: + case 0x00: + mem_remap_top(0); + break; + } + break; + case 0x2e ... 0x31: + sl82c461_recalcmapping(dev); + break; + case 0x33: + switch (val & 0x09) { + default: + case 0x00: + cpu_waitstates = 0; + break; + case 0x08: + cpu_waitstates = 1; + break; + case 0x09: + cpu_waitstates = 2; + break; + } + cpu_update_waitstates(); + break; + case 0x40: + cpu_cache_ext_enabled = !(val & 0x08); + cpu_update_waitstates(); + break; + } + } else + dev->index = val; +} + +static uint8_t +sl82c461_read(uint16_t addr, void *priv) +{ + sl82c461_t *dev = (sl82c461_t *) priv; + uint8_t ret = 0x00; + + if (addr & 0x0001) + if (dev->index == 0x00) + ret = dev->regs[dev->index] | 0x40; + else + ret = dev->regs[dev->index]; + else + ret = dev->index; + + sl82c461_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + + return ret; +} + +static void +sl82c461_close(void *priv) +{ + sl82c461_t *dev = (sl82c461_t *) priv; + + free(dev); +} + +static void * +sl82c461_init(const device_t *info) +{ + sl82c461_t *dev = (sl82c461_t *) calloc(1, sizeof(sl82c461_t)); + + dev->regs[0x00] = 0x40; + + dev->regs[0x02] = 0x0c; + dev->regs[0x40] = 0x08; + + memset(dev->shadow, 0xff, 4 * sizeof(uint8_t)); + + mem_a20_alt = 0x00; + mem_a20_recalc(); + + cpu_set_isa_speed(7159091.0); + + sl82c461_recalcmapping(dev); + + cpu_waitstates = 0; + cpu_cache_ext_enabled = 0; + + cpu_update_waitstates(); + + io_sethandler(0x00a8, 2, + sl82c461_read, NULL, NULL, + sl82c461_write, NULL, NULL, dev); + + return dev; +} + +const device_t sl82c461_device = { + .name = "Symphony SL82C461 (Haydn II)", + .internal_name = "sis_85c471", + .flags = 0, + .local = 0, + .init = sl82c461_init, + .close = sl82c461_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index fe088b209..94884383b 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -159,6 +159,9 @@ extern const device_t stpc_atlas_device; extern const device_t stpc_serial_device; extern const device_t stpc_lpt_device; +/* Symphony */ +extern const device_t sl82c461_device; + /* UMC */ extern const device_t umc_8886f_device; extern const device_t umc_8886af_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 8abd8fef1..77768832e 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -555,6 +555,7 @@ extern int machine_at_aptiva510_init(const machine_t *); extern int machine_at_pc330_6573_init(const machine_t *); extern int machine_at_mvi486_init(const machine_t *); +extern int machine_at_dtk461_init(const machine_t *); extern int machine_at_sis401_init(const machine_t *); extern int machine_at_isa486_init(const machine_t *); extern int machine_at_av4_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index e75c5414e..fded8c094 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -134,6 +134,27 @@ machine_at_tandy4000_init(const machine_t *model) return ret; } +int +machine_at_dtk461_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/dtk461/DTK.BIO", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&sl82c461_device); + device_add(&keyboard_at_ami_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + return ret; +} + static void machine_at_sis401_common_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 5acee0350..e60ccf71d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6403,6 +6403,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[Symphony SL42C460] DTK PKM-0031Y", + .internal_name = "dtk461", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SYMPHONY_SL82C460, + .init = machine_at_dtk461_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* The chip is a Lance LT38C41, a clone of the Intel 8041, and the BIOS sends commands BC, BD, and C9 which exist on both AMIKey and Phoenix MultiKey/42, but it does not write a byte after C9, which is consistent with AMIKey, so From 4beee4452b8e83cc0cb0da70dc0289ab004629f7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 May 2025 05:15:15 +0200 Subject: [PATCH 0919/1190] Siemens D824: Use the VL82C113 (should be 114 but the only datasheet available of it, has no registers, but says it's backwards compatible with the 113). --- src/machine/m_at_386dx_486.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index fded8c094..0e382d0c4 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -443,7 +443,11 @@ machine_at_d824_init(const machine_t *model) if (gfxcard[0] == VID_INTERNAL) device_add(&gd5428_onboard_device); - device_add(&keyboard_ps2_device); + /* + Technically, it should be the VL82C114 but we do not have + a proper datasheet of it that tells us the registers. + */ + device_add(&vl82c113_device); device_add(&ide_isa_device); device_add(&fdc37c651_device); From 1995ee582a7e15cfb4dbd8b4db940ffe78b3e243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Thu, 15 May 2025 06:46:10 +0200 Subject: [PATCH 0920/1190] DTK PKM-0031Y: Fix RAM limits. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e60ccf71d..e5310d7c0 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6428,7 +6428,7 @@ const machine_t machines[] = { .flags = MACHINE_APM, .ram = { .min = 1024, - .max = 65536, + .max = 32768, .step = 1024 }, .nvrmask = 127, From 94313fed0373296af47857a8bb79cfc63127d9c9 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 15 May 2025 17:44:54 -0300 Subject: [PATCH 0921/1190] AC97: Add Winbond W83971D codec --- src/include/86box/snd_ac97.h | 2 ++ src/sound/snd_ac97_codec.c | 25 +++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h index 45a921863..a365f5afa 100644 --- a/src/include/86box/snd_ac97.h +++ b/src/include/86box/snd_ac97.h @@ -100,6 +100,7 @@ #define AC97_CODEC_STAC9708 AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x08) #define AC97_CODEC_STAC9721 AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x09) #define AC97_CODEC_TR28023 AC97_VENDOR_ID('T', 'R', 'A', 0x03) +#define AC97_CODEC_W83971D AC97_VENDOR_ID('W', 'E', 'C', 0x01) #define AC97_CODEC_WM9701A AC97_VENDOR_ID('W', 'M', 'L', 0x00) typedef struct ac97_vendor_reg_t { @@ -150,6 +151,7 @@ extern const device_t cs4297a_device; extern const device_t stac9708_device; extern const device_t stac9721_device; extern const device_t tr28023_device; +extern const device_t w83971d_device; extern const device_t wm9701a_device; extern const device_t ac97_via_device; diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index e92830f67..4a9c1e6c6 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -104,6 +104,12 @@ static const struct { .extid_flags = 0, .pcsr_mask = 0x3f }, + { + .device = &w83971d_device, + .misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = (27 << AC97_3D_SHIFT), + .pcsr_mask = 0x3f + }, { .device = &wm9701a_device, .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, @@ -284,8 +290,9 @@ line_gain: case 0x22: /* 3D Control */ switch (ac97_codecs[dev->model].reset_flags >> AC97_3D_SHIFT) { - case 1: /* Analog Devices */ - case 6: /* Crystal */ + case 1: /* Analog Devices */ + case 6: /* Crystal */ + case 27: /* Winbond */ val &= 0x000f; break; @@ -764,6 +771,20 @@ const device_t tr28023_device = { .config = NULL }; +const device_t w83971d_device = { + .name = "Winbond W83971D", + .internal_name = "w83971d", + .flags = DEVICE_AC97, + .local = AC97_CODEC_W83971D, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t wm9701a_device = { .name = "Wolfson WM9701A", .internal_name = "wm9701a", From 2007632e73d6db3566bc3383d172f4931fc6c662 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 15 May 2025 17:45:27 -0300 Subject: [PATCH 0922/1190] AC97: Remove redundant initializers --- src/sound/snd_ac97_codec.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 4a9c1e6c6..1b28a8aab 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -68,7 +68,6 @@ static const struct { .device = &cs4297_device, .misc_flags = AC97_MASTER_6B | AC97_AUXOUT | AC97_AUXOUT_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, .reset_flags = AC97_HPOUT | AC97_DAC_18B | AC97_ADC_18B, - .extid_flags = 0, .pcsr_mask = 0x7f, .vendor_regs = (const ac97_vendor_reg_t[]) {{0, 0x5a, 0x0301, 0x0000}, {0}} }, @@ -100,8 +99,6 @@ static const struct { { .device = &tr28023_device, .misc_flags = AC97_MASTER_6B | AC97_MONOOUT | AC97_MONOOUT_6B | AC97_PCBEEP | AC97_PHONE | AC97_POP | AC97_MS | AC97_LPBK, - .reset_flags = 0, - .extid_flags = 0, .pcsr_mask = 0x3f }, { @@ -114,7 +111,6 @@ static const struct { .device = &wm9701a_device, .misc_flags = AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, .reset_flags = AC97_DAC_18B | AC97_ADC_18B, - .extid_flags = 0, .pcsr_mask = 0x3f } // clang-format on From 941766f2e84ec581f29c06f92e21db3361878b8d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 16 May 2025 05:04:48 +0200 Subject: [PATCH 0923/1190] Added the ZEOS Martin. --- src/chipset/vl82c480.c | 117 +++++++++++++++++++++++++++-------- src/include/86box/machine.h | 1 + src/include/86box/nvr.h | 1 + src/machine/m_at_286_386sx.c | 4 +- src/machine/m_at_386dx_486.c | 42 ++++++++++--- src/machine/machine_table.c | 65 +++++++++++++++---- src/nvr_at.c | 42 ++++++++++++- src/sio/sio_vl82c113.c | 6 +- 8 files changed, 226 insertions(+), 52 deletions(-) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 496544c63..8ca2c5847 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -24,34 +24,37 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/io.h> +#include <86box/machine.h> #include <86box/mem.h> #include <86box/nmi.h> #include <86box/port_92.h> #include <86box/chipset.h> typedef struct vl82c480_t { - uint8_t idx; - uint8_t regs[256]; + uint8_t idx; + uint8_t regs[256]; + uint32_t banks[4]; } vl82c480_t; static int -vl82c480_shflags(uint8_t access) +vl82c480_shflags(uint8_t access, uint8_t access2) { int ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + int wp = ((access2 & 0x03) == 0x01); switch (access) { default: case 0x00: - ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; + ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY); break; case 0x01: - ret = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; + ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL); break; case 0x02: - ret = MEM_READ_INTERNAL | MEM_WRITE_EXTANY; + ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY); break; case 0x03: - ret = MEM_READ_INTERNAL | MEM_WRITE_INTERNAL; + ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL); break; } @@ -59,27 +62,60 @@ vl82c480_shflags(uint8_t access) } static void -vl82c480_recalc(vl82c480_t *dev) +vl82c480_recalc_shadow(vl82c480_t *dev) { uint32_t base; uint8_t access; + uint8_t access2; shadowbios = 0; shadowbios_write = 0; for (uint8_t i = 0; i < 6; i++) { for (uint8_t j = 0; j < 8; j += 2) { - base = 0x000a0000 + (i << 16) + (j << 13); - access = (dev->regs[0x0d + i] >> j) & 3; - mem_set_mem_state(base, 0x4000, vl82c480_shflags(access)); + base = 0x000a0000 + (i << 16) + (j << 13); + access = (dev->regs[0x0d + i] >> j) & 3; + access2 = (dev->regs[0x13 + i] >> j) & 3; + mem_set_mem_state(base, 0x4000, vl82c480_shflags(access, access2)); shadowbios |= ((base >= 0xe0000) && (access & 0x02)); - shadowbios_write |= ((base >= 0xe0000) && (access & 0x01)); + shadowbios_write |= ((base >= 0xe0000) && (access & 0x01) && !(access2 & 0x01)); } } flushmmucache(); } +static void +vl82c480_recalc_banks(vl82c480_t *dev) +{ + uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 }; + uint8_t shifts[4] = { 0, 4, 0, 4 }; + uint8_t regs[4] = { 0x02, 0x02, 0x03, 0x03 }; + uint32_t total = 0; + + for (uint8_t i = 0; i < 4; i++) { + uint8_t shift = shifts[i]; + uint8_t reg = regs[i]; + uint8_t cfg = (dev->regs[reg] >> shift) & 0x7; + uint32_t size = sizes[cfg]; + + total += MIN(dev->banks[i], size); + } + + if (total > 1024) { + mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000); + mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (total - 1024) << 10); + } else { + if (total >= 1024) + mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000); + else + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_high_mapping); + } + + flushmmucache(); +} + static void vl82c480_write(uint16_t addr, uint8_t val, void *priv) { @@ -91,16 +127,24 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) break; case 0xed: - if (dev->idx >= 0x01 && dev->idx <= 0x24) { + if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) || + ((dev->idx >= 0x20) && (dev->idx <= 0x24))) { switch (dev->idx) { default: dev->regs[dev->idx] = val; break; + case 0x02: case 0x03: + dev->regs[dev->idx] = val; + if (!strcmp(machine_get_internal_name(), "martin")) + vl82c480_recalc_banks(dev); + break; case 0x04: if (dev->regs[0x00] == 0x98) dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7); else dev->regs[dev->idx] = val; + if (!strcmp(machine_get_internal_name(), "martin")) + dev->regs[dev->idx] &= 0x1f; break; case 0x05: dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef); @@ -108,14 +152,11 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) case 0x07: dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf); break; - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: + case 0x0d ... 0x18: dev->regs[dev->idx] = val; - vl82c480_recalc(dev); + vl82c480_recalc_shadow(dev); + if (dev->idx >= 0x13) + flushmmucache(); break; } } @@ -124,8 +165,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) /* TODO: This is actually Fast A20 disable. */ #if 0 case 0xee: - if (mem_a20_alt) - outb(0x92, inb(0x92) & ~2); + mem_a20_alt = 0x00; + mem_a20_recalc(); break; #endif @@ -146,14 +187,16 @@ vl82c480_read(uint16_t addr, void *priv) break; case 0xed: - ret = dev->regs[dev->idx]; + if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) || + ((dev->idx >= 0x20) && (dev->idx <= 0x24))) + ret = dev->regs[dev->idx]; break; /* TODO: This is actually Fast A20 enable. */ #if 0 case 0xee: - if (!mem_a20_alt) - outb(0x92, inb(0x92) | 2); + mem_a20_alt = 0x02; + mem_a20_recalc(); break; #endif @@ -180,7 +223,9 @@ vl82c480_close(void *priv) static void * vl82c480_init(const device_t *info) { - vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); + vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); + uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 }; + uint32_t ms = mem_size; dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; @@ -191,9 +236,27 @@ vl82c480_init(const device_t *info) dev->regs[0x07] = 0x21; dev->regs[0x08] = 0x38; + for (uint8_t i = 0; i < 4; i++) { + uint32_t size = 0; + + for (uint8_t j = 2; i < 7; j++) { + if (ms >= sizes[j]) + size = sizes[j]; + else + break; + } + + ms -= size; + + dev->banks[i] = size; + + if ((ms == 0) || (size == 0)) + break; + } + io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, dev); - device_add(&port_92_device); + device_add(&port_92_pci_device); return dev; } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 77768832e..24bfb245e 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -545,6 +545,7 @@ extern int machine_at_exp4349_init(const machine_t *); extern int machine_at_vect486vl_init(const machine_t *); extern int machine_at_d824_init(const machine_t *); +extern int machine_at_martin_init(const machine_t *); extern int machine_at_403tg_init(const machine_t *); extern int machine_at_403tg_d_init(const machine_t *); diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 0f7d22172..273fc0a37 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -99,6 +99,7 @@ extern const device_t ami_1994_nvr_device; extern const device_t ami_1995_nvr_device; extern const device_t via_nvr_device; extern const device_t p6rp4_nvr_device; +extern const device_t martin_nvr_device; extern const device_t elt_nvr_device; #endif diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index c9fb124cb..e7aa66662 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -724,7 +724,9 @@ machine_at_cmdsl386sx25_init(const machine_t *model) if (gfxcard[0] == VID_INTERNAL) device_add(&gd5402_onboard_device); - machine_at_common_ide_init(model); + machine_at_common_init_ex(model, 2); + + device_add(&ide_isa_device); device_add(&ali5105_device); /* The FDC is part of the ALi M5105. */ device_add(&vl82c113_device); /* The keyboard controller is part of the VL82c113. */ diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0e382d0c4..0b47c285f 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -412,14 +412,16 @@ machine_at_vect486vl_init(const machine_t *model) // has HDC problems if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); - - device_add(&vl82c480_device); - if (gfxcard[0] == VID_INTERNAL) device_add(&gd5428_onboard_device); + machine_at_common_init_ex(model, 2); + + device_add(&vl82c480_device); + device_add(&vl82c113_device); + + device_add(&ide_isa_device); device_add(&fdc37c651_ide_device); return ret; @@ -436,13 +438,13 @@ machine_at_d824_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); - - device_add(&vl82c480_device); - if (gfxcard[0] == VID_INTERNAL) device_add(&gd5428_onboard_device); + machine_at_common_init_ex(model, 2); + + device_add(&vl82c480_device); + /* Technically, it should be the VL82C114 but we do not have a proper datasheet of it that tells us the registers. @@ -455,6 +457,30 @@ machine_at_d824_init(const machine_t *model) return ret; } +int +machine_at_martin_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/martin/NONSCSI.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + device_add(&vl82c480_device); + device_add(&vl82c113_device); + + device_add(&ide_vlb_device); + device_add(&fdc37c651_ide_device); + + device_add(&intel_flash_bxt_device); + + return ret; +} + int machine_at_acera1g_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e60ccf71d..281505469 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6526,7 +6526,7 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has a standard IBM PS/2 KBC firmware or a clone thereof. */ + /* Has a VLSI VL82C114 Combination I/O which holds the KBC. */ { .name = "[VLSI 82C481] Siemens Nixdorf D824", .internal_name = "d824", @@ -6554,7 +6554,7 @@ const machine_t machines[] = { .max = 32768, .step = 2048 }, - .nvrmask = 127, + .nvrmask = 255, .kbc_device = NULL, .kbc_p1 = 0xff, .gpio = 0xffffffff, @@ -6773,6 +6773,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has AMI MegaKey KBC. */ + { + .name = "[i420TX] J-Bond PCI400C-A", + .internal_name = "pci400ca", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_INTEL_420TX, + .init = machine_at_pci400ca_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PCI, + .flags = MACHINE_SCSI, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = &keyboard_at_ami_device, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* This has a standalone AMI Megakey 1993, which is type 'P'. */ { .name = "[IMS 8848] Tekram G486IP", @@ -6934,13 +6974,13 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* Has AMI MegaKey KBC. */ + /* Has a VLSI VL82C113A SCAMP Combination I/O which holds the KBC. */ { - .name = "[i420TX] J-Bond PCI400C-A", - .internal_name = "pci400ca", + .name = "[VLSI 82C480] ZEOS Martin", + .internal_name = "martin", .type = MACHINE_TYPE_486_S2, - .chipset = MACHINE_CHIPSET_INTEL_420TX, - .init = machine_at_pci400ca_init, + .chipset = MACHINE_CHIPSET_VLSI_VL82C480, + .init = machine_at_martin_init, .p1_handler = NULL, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, @@ -6955,15 +6995,15 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI, - .flags = MACHINE_SCSI, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_APM, .ram = { - .min = 1024, + .min = 2048, .max = 65536, - .step = 1024 + .step = 2048 }, .nvrmask = 127, - .kbc_device = &keyboard_at_ami_device, + .kbc_device = NULL, .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, @@ -6975,7 +7015,6 @@ const machine_t machines[] = { .net_device = NULL }, - /* 486 machines - Socket 3 */ /* 486 machines with just the ISA slot */ /* Has a Fujitsu MBL8042H KBC. */ diff --git a/src/nvr_at.c b/src/nvr_at.c index bde80b434..2acfa47a4 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -296,6 +296,7 @@ #define FLAG_P6RP4_HACK 0x10 #define FLAG_PIIX4 0x20 #define FLAG_MULTI_BANK 0x40 +#define FLAG_MARTIN_HACK 0x80 typedef struct local_t { int8_t stat; @@ -733,6 +734,13 @@ nvr_read(uint16_t addr, void *priv) ret = REGD_VRT; break; + case 0x11: + if (local->flags & FLAG_MARTIN_HACK) + ret = nvr->regs[local->addr[addr_id]] | 0x02; + else + ret = nvr->regs[local->addr[addr_id]]; + break; + case 0x2c: if (!nvr->is_new && (local->flags & FLAG_AMI_1994_HACK)) ret = nvr->regs[local->addr[addr_id]] & 0x7f; @@ -771,6 +779,17 @@ nvr_read(uint16_t addr, void *priv) ret = checksum >> 8; else ret = checksum & 0xff; + } else if (!nvr->is_new && (local->flags & FLAG_MARTIN_HACK)) { + for (i = 0x10; i <= 0x2d; i++) { + if (i == 0x11) + checksum += (nvr->regs[i] | 0x02); + else + checksum += nvr->regs[i]; + } + if (local->addr[addr_id] == 0x2e) + ret = checksum >> 8; + else + ret = checksum & 0xff; } else ret = nvr->regs[local->addr[addr_id]]; break; @@ -1123,9 +1142,11 @@ nvr_at_init(const device_t *info) if (info->local & 0x10) { local->def = 0x00; local->flags |= FLAG_AMI_1992_HACK; - } else if (info->local == 36) + } else if ((info->local == 36) || (info->local == 68)) { local->def = 0x00; - else + if (info->local == 68) + local->flags |= FLAG_MARTIN_HACK; + } else local->def = 0xff; nvr->irq = 8; local->cent = RTC_CENTURY_AT; @@ -1160,6 +1181,9 @@ nvr_at_init(const device_t *info) /* Initialize the generic NVR. */ nvr_init(nvr); + if (nvr->is_new && (local->flags & FLAG_MARTIN_HACK)) + nvr->regs[0x11] = nvr->regs[0x2f] = 0x02; + if (nvr_at_inited == 0) { /* Start the timers. */ timer_add(&local->update_timer, timer_update, nvr, 0); @@ -1426,6 +1450,20 @@ const device_t amstrad_megapc_nvr_device = { .config = NULL }; +const device_t martin_nvr_device = { + .name = "Zeos Martin NVRAM", + .internal_name = "martin_nvr", + .flags = DEVICE_ISA16, + .local = 68, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + .available = NULL, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t elt_nvr_device = { .name = "Epson Equity LT NVRAM", .internal_name = "elt_nvr", diff --git a/src/sio/sio_vl82c113.c b/src/sio/sio_vl82c113.c index ee18b1893..b000fe5dd 100644 --- a/src/sio/sio_vl82c113.c +++ b/src/sio/sio_vl82c113.c @@ -22,6 +22,7 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/keyboard.h> +#include <86box/machine.h> #include <86box/nvr.h> #include <86box/sio.h> #include <86box/plat_unused.h> @@ -133,7 +134,10 @@ vl82c113_init(UNUSED(const device_t *info)) { vl82c113_t *dev = (vl82c113_t *) calloc(1, sizeof(vl82c113_t)); - dev->nvr = device_add(&at_nvr_device); + if (!strcmp(machine_get_internal_name(), "martin")) + dev->nvr = device_add(&martin_nvr_device); + else + dev->nvr = device_add(&amstrad_megapc_nvr_device); dev->nvr_enabled = 1; dev->nvr_base = 0x0070; From 948f50667e2845976010020e0c83bc2a94015b61 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Fri, 16 May 2025 18:18:23 +0200 Subject: [PATCH 0924/1190] the ZEOS Martin Board actually has VLB Slots. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ffdf902a3..2e72dd1fa 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6995,7 +6995,7 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PS2, + .bus_flags = MACHINE_PS2_VLB, .flags = MACHINE_IDE | MACHINE_APM, .ram = { .min = 2048, From 34bd61fd1bdd6862a6abe7ff356742e96445d32e Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Fri, 16 May 2025 18:21:51 +0200 Subject: [PATCH 0925/1190] Correct the ET4000/W32p file. --- src/video/vid_et4000w32.c | 160 +++++++------------------------------- 1 file changed, 27 insertions(+), 133 deletions(-) diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index c772ffdd9..246decb9c 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -43,11 +43,8 @@ #define BIOS_ROM_PATH_W32I_ISA "roms/video/et4000w32/ET4KW32I.VBI" #define BIOS_ROM_PATH_W32I_VLB "roms/video/et4000w32/tseng.u41.bin" #define BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB "roms/video/et4000w32/VideoMagic-BioS-HXIRTW32PWSRL.bin" -#define BIOS_ROM_PATH_W32P_IMASCAN_VLB "roms/video/et4000w32/tseng_et4000w32p-8.03.bin" -#define BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB "roms/video/et4000w32/m27c256b-at-dip28-miro20td-675dada18e7fa701369657.bin" #define BIOS_ROM_PATH_W32P "roms/video/et4000w32/ET4K_W32.BIN" #define BIOS_ROM_PATH_W32P_REVC "roms/video/et4000w32/et4000w32pcardex.BIN" -#define BIOS_ROM_PATH_W32P_REVCD_ONBOARD "roms/video/et4000w32/vid.BIN" #define ACL_WRST 1 #define ACL_RDST 2 @@ -58,10 +55,7 @@ enum { ET4000W32, ET4000W32I, ET4000W32P_REVC, - ET4000W32P_REVCD_ONBOARD, ET4000W32P_VIDEOMAGIC_REVB, - ET4000W32P_IMASCAN_VLB, - ET4000W32P_MIROVIDEO20TD_VLB, ET4000W32P, ET4000W32P_CARDEX, ET4000W32P_DIAMOND @@ -184,7 +178,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type <= ET4000W32P_REVC) sdac_ramdac_out(addr, 0, val, svga->ramdac, svga); else stg_ramdac_out(addr, val, svga->ramdac, svga); @@ -308,13 +302,13 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) if (svga->hwcursor.cur_xsize == 128) { svga->hwcursor.xoff &= 0x7f; svga->hwcursor.yoff &= 0x7f; - if (et4000->type > ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type > ET4000W32P_REVC) { if (svga->bpp == 24) { et4000->adjust_cursor = 2; } } } else { - if (et4000->type > ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type > ET4000W32P_REVC) { if ((svga->bpp == 24) && et4000->adjust_cursor) { et4000->adjust_cursor = 0; } @@ -354,7 +348,7 @@ et4000w32p_in(uint16_t addr, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type <= ET4000W32P_REVC) return sdac_ramdac_in(addr, 0, svga->ramdac, svga); else return stg_ramdac_in(addr, svga->ramdac, svga); @@ -509,8 +503,8 @@ et4000w32p_recalctimings(svga_t *svga) svga->hdisp >>= 1; svga->dots_per_clock >>= 1; } - if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { - if (et4000->type == ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type <= ET4000W32P_REVC) { + if (et4000->type == ET4000W32P_REVC) { if (svga->hdisp != 1024) et4000->adjust_cursor = 1; } else @@ -520,7 +514,7 @@ et4000w32p_recalctimings(svga_t *svga) case 24: svga->hdisp /= 3; svga->dots_per_clock /= 3; - if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type <= ET4000W32P_REVC) et4000->adjust_cursor = 2; if ((et4000->type == ET4000W32P_DIAMOND) && ((svga->hdisp == (640 / 2)) || (svga->hdisp == 1232))) { svga->hdisp = 640; @@ -554,7 +548,7 @@ et4000w32p_recalctimings(svga_t *svga) break; case 0x40: case 0x60: /* 256+ colours */ - if (et4000->type <= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type <= ET4000W32P_REVC) svga->clock /= 2; switch (svga->bpp) { @@ -735,13 +729,13 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00ff) | (val << 8); break; case 0x8e: - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type >= ET4000W32P_REVC) et4000->acl.queued.pixel_depth = val & 0x30; else et4000->acl.queued.vbus = val & 0x03; break; case 0x8f: - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type >= ET4000W32P_REVC) et4000->acl.queued.xy_dir = val & 0xb7; else et4000->acl.queued.xy_dir = val & 0x03; @@ -765,7 +759,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00ff) | (val << 8); break; case 0x9c: - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type >= ET4000W32P_REVC) et4000->acl.queued.ctrl_routing = val & 0xdb; else et4000->acl.queued.ctrl_routing = val & 0xb7; @@ -791,7 +785,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) case 0xa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00ffffff) | (val << 24); et4000->acl.internal = et4000->acl.queued; - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type >= ET4000W32P_REVC) { et4000w32p_blit_start(et4000); et4000w32_log("Destination Address write and start XY Block, xcnt = %i, ycnt = %i\n", et4000->acl.x_count + 1, et4000->acl.y_count + 1); if (!(et4000->acl.queued.ctrl_routing & 0x43)) { @@ -855,7 +849,7 @@ et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val, uint8_t bank) { - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) { + if (et4000->type >= ET4000W32P_REVC) { if (!(et4000->acl.status & ACL_XYST)) { et4000w32_log("XY MMU block not started\n"); return; @@ -1093,7 +1087,7 @@ et4000w32p_mmu_read(uint32_t addr, void *priv) case 0x8d: return et4000->acl.internal.dest_off >> 8; case 0x8e: - if (et4000->type >= ET4000W32P_REVC && ET4000W32P_REVCD_ONBOARD) + if (et4000->type >= ET4000W32P_REVC) return et4000->acl.internal.pixel_depth; return et4000->acl.internal.vbus; case 0x8f: @@ -2785,30 +2779,6 @@ et4000w32p_init(const device_t *info) rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - et4000->svga.ramdac = device_add(&stg_ramdac_device); - et4000->svga.clock_gen = et4000->svga.ramdac; - et4000->svga.getclock = stg_getclock; - break; - - case ET4000W32P_IMASCAN_VLB: - /* ET4000/W32p Imascan RGB */ - et4000->rev = 5; - - rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_IMASCAN_VLB, 0xc0000, 0x8000, 0x7fff, 0, - MEM_MAPPING_EXTERNAL); - - et4000->svga.ramdac = device_add(&stg_ramdac_device); - et4000->svga.clock_gen = et4000->svga.ramdac; - et4000->svga.getclock = stg_getclock; - break; - - case ET4000W32P_MIROVIDEO20TD_VLB: - /* ET4000/W32p miroVIDEO 20TD LIVE! */ - et4000->rev = 5; - - rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB, 0xc0000, 0x8000, 0x7fff, 0, - MEM_MAPPING_EXTERNAL); - et4000->svga.ramdac = device_add(&stg_ramdac_device); et4000->svga.clock_gen = et4000->svga.ramdac; et4000->svga.getclock = stg_getclock; @@ -2821,18 +2791,6 @@ et4000w32p_init(const device_t *info) rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVC, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); - et4000->svga.clock_gen = et4000->svga.ramdac; - et4000->svga.getclock = sdac_getclock; - break; - - case ET4000W32P_REVCD_ONBOARD: - /* ET4000/W32p rev C */ - et4000->rev = 7; - - rom_init(&et4000->bios_rom, BIOS_ROM_PATH_W32P_REVCD_ONBOARD, 0xc0000, 0x8000, 0x7fff, 0, - MEM_MAPPING_EXTERNAL); - et4000->svga.ramdac = device_add(&tseng_ics5341_ramdac_device); et4000->svga.clock_gen = et4000->svga.ramdac; et4000->svga.getclock = sdac_getclock; @@ -2932,30 +2890,12 @@ et4000w32p_videomagic_revb_vlb_available(void) return rom_present(BIOS_ROM_PATH_W32P_VIDEOMAGIC_REVB_VLB); } -int -et4000w32p_imascan_vlb_available(void) -{ - return rom_present(BIOS_ROM_PATH_W32P_IMASCAN_VLB); -} - -int -et4000w32p_mirovideo20td_vlb_available(void) -{ - return rom_present(BIOS_ROM_PATH_W32P_MIROVIDEO20TD_VLB); -} - int et4000w32p_revc_available(void) { return rom_present(BIOS_ROM_PATH_W32P_REVC); } -int -et4000w32p_revcd_onboard_available(void) -{ - return rom_present(BIOS_ROM_PATH_W32P_REVCD_ONBOARD); -} - int et4000w32p_noncardex_available(void) { @@ -3003,23 +2943,19 @@ et4000w32p_force_redraw(void *priv) static const device_config_t et4000w32p_config[] = { // clang-format off { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_int = 2, - .selection = { - { - .description = "1 MB", - .value = 1 - }, - { - .description = "2 MB", - .value = 2 - }, - { - .description = "" - } - } + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "1 MB", .value = 1 }, + { .description = "2 MB", .value = 2 }, + { .description = "" } + }, + .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on @@ -3081,34 +3017,6 @@ const device_t et4000w32i_vlb_device = { .config = et4000w32p_config }; -const device_t et4000w32p_imascan_vlb_device = { - .name = "Tseng Labs ET4000/w32p VLB (Imascan)", - .internal_name = "et4000w32p_imascan_vlb", - .flags = DEVICE_VLB, - .local = ET4000W32P_IMASCAN_VLB, - .init = et4000w32p_init, - .close = et4000w32p_close, - .reset = NULL, - .available = et4000w32p_imascan_vlb_available, - .speed_changed = et4000w32p_speed_changed, - .force_redraw = et4000w32p_force_redraw, - .config = et4000w32p_config -}; - -const device_t et4000w32p_mirovideo20td_vlb_device = { - .name = "Tseng Labs ET4000/w32p VLB (miroVIDEO 20TD LIVE!)", - .internal_name = "et4000w32p_mirovideo20td_vlb", - .flags = DEVICE_VLB, - .local = ET4000W32P_MIROVIDEO20TD_VLB, - .init = et4000w32p_init, - .close = et4000w32p_close, - .reset = NULL, - .available = et4000w32p_mirovideo20td_vlb_available, - .speed_changed = et4000w32p_speed_changed, - .force_redraw = et4000w32p_force_redraw, - .config = et4000w32p_config -}; - const device_t et4000w32p_videomagic_revb_vlb_device = { .name = "Tseng Labs ET4000/w32p Rev. B VLB (VideoMagic)", .internal_name = "et4000w32p_videomagic_revb_vlb", @@ -3165,20 +3073,6 @@ const device_t et4000w32p_revc_pci_device = { .config = et4000w32p_config }; -const device_t et4000w32p_revcd_onboard_pci_device = { - .name = "Tseng Labs ET4000/w32p Rev. C/D PCI (On-Board)", - .internal_name = "et4000w32p_revc_pci", - .flags = DEVICE_PCI, - .local = ET4000W32P_REVCD_ONBOARD, - .init = et4000w32p_init, - .close = et4000w32p_close, - .reset = NULL, - .available = et4000w32p_revcd_onboard_available, - .speed_changed = et4000w32p_speed_changed, - .force_redraw = et4000w32p_force_redraw, - .config = et4000w32p_config -}; - const device_t et4000w32p_noncardex_vlb_device = { .name = "Tseng Labs ET4000/w32p Rev. D VLB", .internal_name = "et4000w32p_nc_vlb", From e98424a8ae988d9e49c9f27d19122194a09c43f9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 02:35:11 +0200 Subject: [PATCH 0926/1190] Added the ICS SB486PV. --- src/chipset/intel_4x0.c | 7 ++- src/device.c | 10 +++- src/device/kbc_at.c | 5 +- src/include/86box/machine.h | 3 +- src/include/86box/sio.h | 3 ++ src/machine/m_at_386dx_486.c | 93 ++++++++++++++++++++++++++++++++++-- src/machine/machine_table.c | 42 ++++++++++++++++ src/sio/sio_82091aa.c | 14 ++++++ src/video/vid_cl54xx.c | 8 ++-- 9 files changed, 172 insertions(+), 13 deletions(-) diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index f9d6af150..84bd872f8 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -1656,7 +1656,12 @@ i4x0_init(const device_t *info) regs[0x57] = 0x31; regs[0x59] = 0x0f; regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02; - dev->max_drb = 3; + /* At the very least the 420ZX seems to read to 0x64, per the SB486PV. */ + if (dev->type == INTEL_420ZX) { + regs[0x64] = 0x02; + dev->max_drb = 4; + } else + dev->max_drb = 3; dev->drb_unit = 1; dev->drb_default = 0x02; break; diff --git a/src/device.c b/src/device.c index 1922806b9..910ff4ff9 100644 --- a/src/device.c +++ b/src/device.c @@ -897,8 +897,14 @@ device_is_valid(const device_t *device, int mch) { int ret = 1; - if ((device != NULL) && ((device->flags & DEVICE_BUS) != 0)) - ret = machine_has_bus(mch, device->flags & DEVICE_BUS); + if ((device != NULL) && ((device->flags & DEVICE_BUS) != 0)) { + /* Hide PCI devices on machines with only an internal PCI bus. */ + if ((device->flags & DEVICE_PCI) && + machine_has_flags(mch, MACHINE_PCI_INTERNAL)) + ret = 0; + else + ret = machine_has_bus(mch, device->flags & DEVICE_BUS); + } return ret; } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 2b9cf8c18..a8a8c51cc 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1336,7 +1336,10 @@ write64_ami(void *priv, uint8_t val) kbc_at_log("ATkbc: set KBC lines P22-P23 (P2 bits 2-3) low\n"); if (!(dev->flags & DEVICE_PCI)) write_p2(dev, dev->p2 & ~(4 << (val & 0x01))); - kbc_delay_to_ob(dev, dev->ob, 0, 0x00); + if (strstr(machine_get_internal_name(), "sb486pv") != NULL) + kbc_delay_to_ob(dev, 0x03, 0, 0x00); + else + kbc_delay_to_ob(dev, dev->ob, 0, 0x00); dev->pending++; return 0; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 24bfb245e..febce3fa1 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -105,7 +105,7 @@ /* Feature flags for advanced devices. */ #define MACHINE_APM 0x00080000 /* sys has APM */ #define MACHINE_ACPI 0x00100000 /* sys has ACPI */ -#define MACHINE_HWM 0x00200000 /* sys has hw monitor */ +#define MACHINE_PCI_INTERNAL 0x00200000 /* sys has only internal PCI */ #define MACHINE_CARTRIDGE 0x00400000 /* sys has cartridge bays */ /* Feature flags for internal storage controllers. */ #define MACHINE_MFM 0x00800000 /* sys has int MFM/RLL */ @@ -588,6 +588,7 @@ extern int machine_at_sb486p_init(const machine_t *); extern int machine_at_486sp3_init(const machine_t *); extern int machine_at_486sp3c_init(const machine_t *); extern int machine_at_486sp3g_init(const machine_t *); +extern int machine_at_sb486pv_init(const machine_t *); extern int machine_at_486ap4_init(const machine_t *); extern int machine_at_g486vpa_init(const machine_t *); extern int machine_at_486vipio2_init(const machine_t *); diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index bdff29f7f..06bf57f8f 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -71,7 +71,10 @@ extern const device_t fdc37m60x_370_device; /* ITE */ extern const device_t it8661f_device; extern const device_t it8671f_device; + +/* Intel */ extern const device_t i82091aa_device; +extern const device_t i82091aa_26e_device; extern const device_t i82091aa_398_device; extern const device_t i82091aa_ide_pri_device; extern const device_t i82091aa_ide_device; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0b47c285f..c2cf82352 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -756,7 +756,6 @@ machine_at_403tg_d_mr_init(const machine_t *model) return ret; } - static const device_config_t pb450_config[] = { // clang-format off { @@ -1640,6 +1639,91 @@ machine_at_486sp3g_init(const machine_t *model) return ret; } +static const device_config_t sb486pv_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "sb486pv", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "AMI 062594 (0108)", .internal_name = "sb486pv", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/sb486pv/41-0108-062594-SATURN2.rom", "" } }, + { .name = "AMI 062594 (0301)", .internal_name = "sb486pv_94", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/sb486pv/0301-062594-SATURN2.rom", "" } }, + { .name = "AMI 071595 (1301)", .internal_name = "sb486pv_95", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/sb486pv/amiboot.rom", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t sb486pv_device = { + .name = "ICS SB486PV", + .internal_name = "sb486pv_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = sb486pv_config +}; + +int +machine_at_sb486pv_init(const machine_t *model) +{ + int ret = 0; + const char* fn; + + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + else + ret = bios_load_linear_inverted(fn, 0x000e0000, 131072, 0); + device_context_restore(); + + machine_at_common_init(model); + // machine_at_common_init_ex(model, 2); + + // device_add(&amstrad_megapc_nvr_device); + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0e, PCI_CARD_IDE, 0, 0, 0, 0); + pci_register_slot(0x0f, PCI_CARD_VIDEO, 1, 2, 3, 4); + pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sio_zb_device); + device_add(&ide_rz1000_pci_single_channel_device); + device_add(&i82091aa_26e_device); + if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) + device_add(&intel_flash_bxt_device); + else + device_add(&intel_flash_bxt_ami_device); + + device_add(&i420zx_device); + + return ret; +} + int machine_at_486ap4_init(const machine_t *model) { @@ -1833,12 +1917,11 @@ machine_at_sbc490_init(const machine_t *model) pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x01, PCI_CARD_VIDEO, 4, 1, 2, 3); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + device_add(&ali1489_device); device_add(&fdc37c665_device); - - if (gfxcard[0] == VID_INTERNAL) - device_add(&tgui9440_onboard_pci_device); - device_add(&keyboard_ps2_ami_device); device_add(&sst_flash_29ee010_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ffdf902a3..3f69865c3 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -69,6 +69,7 @@ extern const device_t pb450_device; extern const device_t jukopc_device; extern const device_t vendex_device; extern const device_t c5sbm2_device; +extern const device_t sb486pv_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -8515,6 +8516,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* This has an AMI MEGAKey 'P' or 'R' keyboard controller. */ + { + .name = "[i420ZX] ICS SB486PV", + .internal_name = "sb486pv", + .type = MACHINE_TYPE_486_S3_PCI, + .chipset = MACHINE_CHIPSET_INTEL_420ZX, + .init = machine_at_sb486pv_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + /* Has PCI but no user-facing slots. */ + .bus_flags = MACHINE_PCI, + .flags = MACHINE_PS2_KBC | MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM | MACHINE_PCI_INTERNAL, + .ram = { + .min = 2048, + .max = 65536, + .step = 2048 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &sb486pv_device, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5436_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL + }, /* This most likely has a standalone AMI Megakey 1993, which is type 'P', like the below Tekram board. */ { .name = "[IMS 8848] J-Bond PCI400C-B", diff --git a/src/sio/sio_82091aa.c b/src/sio/sio_82091aa.c index d3cd5017a..71f8749f2 100644 --- a/src/sio/sio_82091aa.c +++ b/src/sio/sio_82091aa.c @@ -295,6 +295,20 @@ const device_t i82091aa_device = { .config = NULL }; +const device_t i82091aa_26e_device = { + .name = "Intel 82091AA Super I/O (Port 26Eh)", + .internal_name = "i82091aa_26e", + .flags = 0, + .local = 0x140, + .init = i82091aa_init, + .close = i82091aa_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t i82091aa_398_device = { .name = "Intel 82091AA Super I/O (Port 398h)", .internal_name = "i82091aa_398", diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 43c4e22b2..dbb9d5993 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -33,6 +33,7 @@ #include <86box/pci.h> #include <86box/rom.h> #include <86box/device.h> +#include <86box/machine.h> #include <86box/timer.h> #include <86box/video.h> #include <86box/i2c.h> @@ -4316,7 +4317,8 @@ gd54xx_init(const device_t *info) break; case CIRRUS_ID_CLGD5436: - if (info->local & 0x200) { + if ((info->local & 0x200) && + !strstr(machine_get_internal_name(), "sb486pv")) { romfn = NULL; gd54xx->has_bios = 0; } else @@ -4461,8 +4463,8 @@ gd54xx_init(const device_t *info) } io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) { - if (romfn == NULL) + if (gd54xx->pci && (id >= CIRRUS_ID_CLGD5430)) { + if (info->local & 0x200) pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx, &gd54xx->pci_slot); else pci_add_card(PCI_ADD_NORMAL, cl_pci_read, cl_pci_write, gd54xx, &gd54xx->pci_slot); From 2a58d761b94397775b2410f1cb1639b9729e64fb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 03:05:46 +0200 Subject: [PATCH 0927/1190] VL82C480: Fix and clean-up the DRAM banks calculation code, closes #5592. --- src/chipset/vl82c480.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 8ca2c5847..56e9f1d71 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -237,20 +237,16 @@ vl82c480_init(const device_t *info) dev->regs[0x08] = 0x38; for (uint8_t i = 0; i < 4; i++) { - uint32_t size = 0; - - for (uint8_t j = 2; i < 7; j++) { + for (uint8_t j = 2; j < 7; j++) { if (ms >= sizes[j]) - size = sizes[j]; + dev->banks[i] = sizes[j]; else break; } - ms -= size; + ms -= dev->banks[i]; - dev->banks[i] = size; - - if ((ms == 0) || (size == 0)) + if ((ms == 0) || (dev->banks[i] == 0)) break; } From 5ebed5dc57e96453e9ff6b77f8c2357575156b6e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 03:09:21 +0200 Subject: [PATCH 0928/1190] POST Card: Some Compaq-related fixes. --- src/device/postcard.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/device/postcard.c b/src/device/postcard.c index b91d8b402..95a4df646 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -147,14 +147,17 @@ postcard_init(UNUSED(const device_t *info)) if (machine_has_bus(machine, MACHINE_BUS_MCA)) postcard_port = 0x680; /* MCA machines */ - else if (strstr(machines[machine].name, " PS/2 ") || strstr(machine_getname_ex(machine), " PS/1 ")) + else if (strstr(machines[machine].name, " PS/2 ") || + strstr(machine_getname_ex(machine), " PS/1 ")) postcard_port = 0x190; /* ISA PS/2 machines */ else if (strstr(machines[machine].name, " IBM XT ")) postcard_port = 0x60; /* IBM XT */ else if (strstr(machines[machine].name, " IBM PCjr")) { postcard_port = 0x10; /* IBM PCjr */ postcard_ports_num = 3; /* IBM PCjr error ports 11h and 12h */ - } else if (strstr(machines[machine].name, " Compaq ") && !machine_has_bus(machine, MACHINE_BUS_PCI)) + } else if (strstr(machines[machine].name, " Compaq ") && + !strstr(machines[machine].name, " Presario ") && + !strstr(machines[machine].name, " ProSignia ")) postcard_port = 0x84; /* ISA Compaq machines */ else if (strstr(machines[machine].name, "Olivetti")) postcard_port = 0x378; /* Olivetti machines */ From 1eb4355d769c17cebc2d23814c72f061d32ba0ac Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 03:16:52 +0200 Subject: [PATCH 0929/1190] FDC: Remove an excess commented out line. --- src/floppy/fdc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index e779ea2d7..e7166d1ba 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -81,7 +81,6 @@ int fdc_current[FDC_MAX] = { 0, 0 }; volatile int fdcinited = 0; -// #define ENABLE_FDC_LOG 1 #ifdef ENABLE_FDC_LOG int fdc_do_log = ENABLE_FDC_LOG; From b97a23aa571256d9f3c67fe6962b8833b88474b1 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 17 May 2025 05:28:45 +0200 Subject: [PATCH 0930/1190] WIP Plasma code --- src/machine/m_at_compaq.c | 191 +++++++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 74 deletions(-) diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index c0b254388..ddd3f2a0c 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -84,20 +84,14 @@ compaq_plasma_display_set(uint8_t internal) cpq_st_display_internal = internal; } -static uint8_t -compaq_plasma_display_get(void) -{ - return cpq_st_display_internal; -} - typedef struct compaq_plasma_t { cga_t cga; - uint8_t ctl_mode; + mem_mapping_t font_ram_mapping; + uint8_t *font_ram; uint8_t port_13c6; uint8_t port_23c6; uint8_t port_27c6; uint8_t internal_monitor; - uint8_t attrmap; } compaq_plasma_t; static int compaq_machine_type = 0; @@ -119,13 +113,11 @@ compaq_plasma_recalctimings(compaq_plasma_t *self) return; } - disptime = 651; - _dispontime = 640; + disptime = 651; + _dispontime = 640; _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST / 2; - _dispofftime *= CGACONST / 2; - self->cga.dispontime = (uint64_t) (_dispontime); - self->cga.dispofftime = (uint64_t) (_dispofftime); + self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); + self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); } static void @@ -160,14 +152,31 @@ compaq_plasma_read(uint32_t addr, void *priv) } static void -compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) +compaq_plasma_font_write(uint32_t addr, uint8_t val, void *priv) { compaq_plasma_t *self = (compaq_plasma_t *) priv; - if (self->port_23c6 & 0x08) { - if ((addr >= 0x3d0) && (addr <= 0x3dc)) - addr ^= 0x60; - } + addr &= 0x1fff; + + self->font_ram[addr] = val; +} +static uint8_t +compaq_plasma_font_read(uint32_t addr, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t ret = 0x00; + + addr &= 0x1fff; + + ret = self->font_ram[addr]; + + return ret; +} + +static void +compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; switch (addr) { /* Emulated CRTC, register select */ @@ -183,21 +192,11 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) case 0x3d3: case 0x3d5: case 0x3d7: - /* Register 0x12 controls the attribute mappings for the - * plasma screen. */ - if (self->cga.crtcreg == 0x12) { - self->attrmap = val; - compaq_plasma_recalcattrs(self); - return; - } cga_out(addr, val, &self->cga); - compaq_plasma_recalctimings(self); break; case 0x3d8: case 0x3d9: - case 0x3db: - case 0x3dc: cga_out(addr, val, &self->cga); break; @@ -208,10 +207,15 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) case 0x23c6: self->port_23c6 = val; - if (val & 0x08) /* Disable internal CGA */ - mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x8000); - else - mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x8000); + pclog("Write 23c6=%02x.\n", val); + if (val & 0x08) { /* Disable internal CGA */ + mem_mapping_disable(&self->cga.mapping); + mem_mapping_enable(&self->font_ram_mapping); + } else { + mem_mapping_enable(&self->cga.mapping); + mem_mapping_disable(&self->font_ram_mapping); + } + compaq_plasma_recalcattrs(self); break; case 0x27c6: @@ -229,11 +233,6 @@ compaq_plasma_in(uint16_t addr, void *priv) compaq_plasma_t *self = (compaq_plasma_t *) priv; uint8_t ret = 0xff; - if (self->port_23c6 & 0x08) { - if ((addr >= 0x3d0) && (addr <= 0x3dc)) - addr ^= 0x60; - } - switch (addr) { case 0x3d4: case 0x3da: @@ -246,13 +245,8 @@ compaq_plasma_in(uint16_t addr, void *priv) case 0x3d3: case 0x3d5: case 0x3d7: - if (self->cga.crtcreg == 0x12) { - ret = self->attrmap & 0x0f; - if (compaq_plasma_display_get()) - ret |= 0x30; /* Plasma / CRT */ - } else - ret = cga_in(addr, &self->cga); - break; + ret = cga_in(addr, &self->cga); + break; case 0x3d8: ret = self->cga.cgamode; @@ -260,10 +254,16 @@ compaq_plasma_in(uint16_t addr, void *priv) case 0x13c6: ret = self->port_13c6; +#if 0 + if ((self->cga.cgamode & 0x28) == 0x00) + ret |= 0x04; +#endif + pclog("Read 13c6=%02x, mode=%02x.\n", ret, self->cga.cgamode); break; case 0x17c6: - ret = 0xf6; + ret = 0xe6; + pclog("Read 17c6=%02x, mode=%02x.\n", ret, self->cga.cgamode); break; case 0x1bc6: @@ -272,6 +272,7 @@ compaq_plasma_in(uint16_t addr, void *priv) case 0x23c6: ret = self->port_23c6; + pclog("Read 23c6=%02x.\n", ret); break; case 0x27c6: @@ -350,12 +351,15 @@ compaq_plasma_poll(void *priv) chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; /* text attributes */ attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else - chr = attr = 0; + } else { + chr = 0x00; + attr = 0x00; + } /* check if cursor has to be drawn */ drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); /* check if character underline mode should be set */ - underline = (((self->port_23c6 >> 5) == 2) && (attr & 0x01) && !(attr & 0x06)); + underline = ((attr & 0x07) == 0x01); + underline |= ((self->port_23c6 >> 5) == 2) && (attr & 0x03); if (underline) { /* set forecolor to white */ attr = attr | 0x7; @@ -376,8 +380,13 @@ compaq_plasma_poll(void *priv) /* Set intensity bit */ cols[1] = normcols[attr][1]; cols[0] = normcols[attr][0]; - blink = ((attr & 0x80) << 3) + 7 + 16; } + + /* character address */ + uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && (attr & 0x03)) + chr_addr |= 0x1000; + /* character underline active and 7th row of pixels in character height being drawn */ if (underline && (sc == 7)) { /* for each pixel in character width */ @@ -385,12 +394,25 @@ compaq_plasma_poll(void *priv) buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } else { for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; } + if (attr & 0x03) { + if ((self->port_23c6 >> 5) == 1) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] ^= (amber ^ black); + } else if ((self->port_23c6 >> 5) == 4) { + for (c = 0; c < 8; c++) { + uint32_t b = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 1) & 0x7f; + uint32_t g = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 9) & 0x7f; + uint32_t r = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 17) & 0x7f; + buffer32->line[self->cga.displine][(x << 3) + c] = b | (g << 8) || (r << 16); + } + } + } ma++; } } @@ -412,13 +434,15 @@ compaq_plasma_poll(void *priv) chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; /* text attributes */ attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else - chr = attr = 0; - + } else { + chr = 0x00; + attr = 0x00; + } /* check if cursor has to be drawn */ drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); /* check if character underline mode should be set */ - underline = (((self->port_23c6 >> 5) == 2) && (attr & 0x01) && !(attr & 0x06)); + underline = ((attr & 0x07) == 0x01); + underline |= ((self->port_23c6 >> 5) == 2) && (attr & 0x03); if (underline) { /* set forecolor to white */ attr = attr | 0x7; @@ -439,22 +463,40 @@ compaq_plasma_poll(void *priv) /* Set intensity bit */ cols[1] = normcols[attr][1]; cols[0] = normcols[attr][0]; - blink = ((attr & 0x80) << 3) + 7 + 16; } + /* character address */ + uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && (attr & 0x03)) + chr_addr |= 0x1000; + /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (self->cga.sc == 7)) { + if (underline && (sc == 7)) { /* for each pixel in character width */ for (c = 0; c < 8; c++) buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } else { for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(fontdatm2[chr + self->cga.fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; } + if (attr & 0x03) { + if ((self->port_23c6 >> 5) == 1) + for (c = 0; c < 8; c++) { + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] ^= (amber ^ black); + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] ^= (amber ^ black); + } + else if ((self->port_23c6 >> 5) == 4) + for (c = 0; c < 8; c++) { + uint32_t b = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 1) & 0x7f; + uint32_t g = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 9) & 0x7f; + uint32_t r = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 17) & 0x7f; + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = b | (g << 8) || (r << 16); + } + } ma++; } } else { @@ -493,6 +535,14 @@ compaq_plasma_poll(void *priv) ink0 = ink1 = black; break; case 1: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = black; + } else { + ink0 = amber; + ink1 = black; + } + break; case 2: if (self->cga.displine & 0x01) { ink0 = black; @@ -545,7 +595,7 @@ compaq_plasma_poll(void *priv) if (video_force_resize_get()) video_force_resize_set(0); } - /* ogc specific */ + /* Plasma specific */ video_blit_memtoscreen(0, 0, xsize, ysize); frames++; @@ -622,7 +672,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) for (n = 0x11; n <= 0xFF; n++) { if ((n & 7) == 0) continue; - if (self->attrmap & 4) { /* Inverse */ + if ((self->port_23c6 >> 5) == 1) { /* Inverse */ blinkcols[n][0] = normcols[n][0] = amber; blinkcols[n][1] = normcols[n][1] = black; } else { /* Normal */ @@ -635,7 +685,7 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) for (n = 0x01; n <= 0x0E; n++) { if (n == 7) continue; - if (self->attrmap & 1) { + if ((self->port_23c6 >> 5) == 1) { blinkcols[n][0] = normcols[n][0] = amber; blinkcols[n][1] = normcols[n][1] = black; blinkcols[n + 128][0] = amber; @@ -678,11 +728,6 @@ compaq_plasma_init(UNUSED(const device_t *info)) { compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); - if (compaq_machine_type == COMPAQ_PORTABLEIII) - loadfont_ex("roms/machines/portableiii/K Combined.bin", 11, 0x4bb2); - else - loadfont_ex("roms/machines/portableiii/P.2 Combined.bin", 11, 0x4b49); - cga_init(&self->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); @@ -691,24 +736,21 @@ compaq_plasma_init(UNUSED(const device_t *info)) self->cga.vram = malloc(0x8000); self->internal_monitor = 1; + self->font_ram = malloc(0x2000); cga_comp_init(self->cga.revision); timer_set_callback(&self->cga.timer, compaq_plasma_poll); timer_set_p(&self->cga.timer, self); mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, compaq_plasma_read, NULL, NULL, compaq_plasma_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + mem_mapping_add(&self->font_ram_mapping, 0xb8000, 0x02000, compaq_plasma_font_read, NULL, NULL, compaq_plasma_font_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); for (int i = 1; i <= 2; i++) { io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); } - io_sethandler(0x03d0, 0x000c, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - /* Default attribute mapping is 4 */ - self->attrmap = 4; - compaq_plasma_recalcattrs(self); - - self->cga.cgastat = 0xf4; overscan_x = overscan_y = 16; self->cga.rgb_type = device_get_config_int("rgb_type"); @@ -725,6 +767,7 @@ compaq_plasma_close(void *priv) compaq_plasma_t *self = (compaq_plasma_t *) priv; free(self->cga.vram); + free(self->font_ram); free(self); } From f7c27285825a234b8846af20635ca0e18e796f56 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 05:41:53 +0200 Subject: [PATCH 0931/1190] Fix the incorrect high intensity attribute bit checking (bit 3 is 0x08, not 0x03!). --- src/machine/m_at_compaq.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index ddd3f2a0c..1d1770b46 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -355,11 +355,12 @@ compaq_plasma_poll(void *priv) chr = 0x00; attr = 0x00; } + uint8_t hi_bit = attr & 0x08; /* check if cursor has to be drawn */ drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); /* check if character underline mode should be set */ underline = ((attr & 0x07) == 0x01); - underline |= ((self->port_23c6 >> 5) == 2) && (attr & 0x03); + underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); if (underline) { /* set forecolor to white */ attr = attr | 0x7; @@ -384,7 +385,7 @@ compaq_plasma_poll(void *priv) /* character address */ uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && (attr & 0x03)) + if (((self->port_23c6 >> 5) == 3) && hi_bit) chr_addr |= 0x1000; /* character underline active and 7th row of pixels in character height being drawn */ @@ -400,7 +401,7 @@ compaq_plasma_poll(void *priv) buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; } - if (attr & 0x03) { + if (hi_bit) { if ((self->port_23c6 >> 5) == 1) { for (c = 0; c < 8; c++) buffer32->line[self->cga.displine][(x << 3) + c] ^= (amber ^ black); @@ -438,11 +439,12 @@ compaq_plasma_poll(void *priv) chr = 0x00; attr = 0x00; } + uint8_t hi_bit = attr & 0x08; /* check if cursor has to be drawn */ drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); /* check if character underline mode should be set */ underline = ((attr & 0x07) == 0x01); - underline |= ((self->port_23c6 >> 5) == 2) && (attr & 0x03); + underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); if (underline) { /* set forecolor to white */ attr = attr | 0x7; @@ -467,7 +469,7 @@ compaq_plasma_poll(void *priv) /* character address */ uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && (attr & 0x03)) + if (((self->port_23c6 >> 5) == 3) && hi_bit) chr_addr |= 0x1000; /* character underline active and 7th row of pixels in character height being drawn */ @@ -483,7 +485,7 @@ compaq_plasma_poll(void *priv) buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; } - if (attr & 0x03) { + if (hi_bit) { if ((self->port_23c6 >> 5) == 1) for (c = 0; c < 8; c++) { buffer32->line[self->cga.displine][(x << 4) + (c << 1)] ^= (amber ^ black); From 45316f9be0c8e25f5538fda428b6d8574eb488ff Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 06:18:48 +0200 Subject: [PATCH 0932/1190] Potential fix for MS OS/2. --- src/machine/m_at_compaq.c | 64 +++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 1d1770b46..98803ca94 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -135,7 +135,10 @@ compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) { compaq_plasma_t *self = (compaq_plasma_t *) priv; - self->cga.vram[addr & 0x7fff] = val; + if (self->port_23c6 & 0x08) + self->font_ram[addr & 0x1fff] = val; + else + self->cga.vram[addr & 0x7fff] = val; compaq_plasma_waitstates(&self->cga); } @@ -146,29 +149,11 @@ compaq_plasma_read(uint32_t addr, void *priv) uint8_t ret; compaq_plasma_waitstates(&self->cga); - ret = (self->cga.vram[addr & 0x7fff]); - return ret; -} - -static void -compaq_plasma_font_write(uint32_t addr, uint8_t val, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - addr &= 0x1fff; - - self->font_ram[addr] = val; -} -static uint8_t -compaq_plasma_font_read(uint32_t addr, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t ret = 0x00; - - addr &= 0x1fff; - - ret = self->font_ram[addr]; + if (self->port_23c6 & 0x08) + ret = (self->font_ram[addr & 0x1fff]); + else + ret = (self->cga.vram[addr & 0x7fff]); return ret; } @@ -203,18 +188,20 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) case 0x13c6: self->port_13c6 = val; compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); + /* + For bits 2-0, John gives 0 = CGA, 1 = EGA, 3 = MDA; + Another source (Ralf Brown?) gives 4 = CGA, 5 = EGA, 7 = MDA; + This leads me to believe bit 2 is not relevant to the mode. + */ + if ((val & 0x03) == 0x03) + mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x08000); + else + mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x08000); break; case 0x23c6: self->port_23c6 = val; pclog("Write 23c6=%02x.\n", val); - if (val & 0x08) { /* Disable internal CGA */ - mem_mapping_disable(&self->cga.mapping); - mem_mapping_enable(&self->font_ram_mapping); - } else { - mem_mapping_enable(&self->cga.mapping); - mem_mapping_disable(&self->font_ram_mapping); - } compaq_plasma_recalcattrs(self); break; @@ -725,6 +712,15 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) } } +void +compaq_dump(void) +{ + FILE *f = fopen("d:\\86boxnew\\compaq_plasma_vram.dmp", "wb"); + for (int i = 0; i < 65536; i++) + fputc(mem_readb_phys(0x000b0000 + i), f); + fclose(f); +} + static void * compaq_plasma_init(UNUSED(const device_t *info)) { @@ -744,8 +740,10 @@ compaq_plasma_init(UNUSED(const device_t *info)) timer_set_callback(&self->cga.timer, compaq_plasma_poll); timer_set_p(&self->cga.timer, self); - mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, compaq_plasma_read, NULL, NULL, compaq_plasma_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); - mem_mapping_add(&self->font_ram_mapping, 0xb8000, 0x02000, compaq_plasma_font_read, NULL, NULL, compaq_plasma_font_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, + compaq_plasma_read, NULL, NULL, + compaq_plasma_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, self); for (int i = 1; i <= 2; i++) { io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); @@ -768,6 +766,8 @@ compaq_plasma_close(void *priv) { compaq_plasma_t *self = (compaq_plasma_t *) priv; + compaq_dump(); + free(self->cga.vram); free(self->font_ram); free(self); From 9772aeae4de7b83101a82dfd11b96308f3deebe3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 06:21:12 +0200 Subject: [PATCH 0933/1190] Clean up the excess logging. --- src/machine/m_at_compaq.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 98803ca94..1f5ecdb58 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -201,7 +201,6 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) case 0x23c6: self->port_23c6 = val; - pclog("Write 23c6=%02x.\n", val); compaq_plasma_recalcattrs(self); break; @@ -245,12 +244,10 @@ compaq_plasma_in(uint16_t addr, void *priv) if ((self->cga.cgamode & 0x28) == 0x00) ret |= 0x04; #endif - pclog("Read 13c6=%02x, mode=%02x.\n", ret, self->cga.cgamode); break; case 0x17c6: ret = 0xe6; - pclog("Read 17c6=%02x, mode=%02x.\n", ret, self->cga.cgamode); break; case 0x1bc6: @@ -259,7 +256,6 @@ compaq_plasma_in(uint16_t addr, void *priv) case 0x23c6: ret = self->port_23c6; - pclog("Read 23c6=%02x.\n", ret); break; case 0x27c6: @@ -712,15 +708,6 @@ compaq_plasma_recalcattrs(compaq_plasma_t *self) } } -void -compaq_dump(void) -{ - FILE *f = fopen("d:\\86boxnew\\compaq_plasma_vram.dmp", "wb"); - for (int i = 0; i < 65536; i++) - fputc(mem_readb_phys(0x000b0000 + i), f); - fclose(f); -} - static void * compaq_plasma_init(UNUSED(const device_t *info)) { @@ -766,8 +753,6 @@ compaq_plasma_close(void *priv) { compaq_plasma_t *self = (compaq_plasma_t *) priv; - compaq_dump(); - free(self->cga.vram); free(self->font_ram); free(self); From dc9101c00c247232fc2a458919c892974bcfc420 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 06:56:52 +0200 Subject: [PATCH 0934/1190] VL82C480: Remove the incorrect implementation of registers 13h to 18h, fixes the Siemens-Nixdorf D824. --- src/chipset/vl82c480.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 56e9f1d71..6354ac15a 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -37,24 +37,23 @@ typedef struct vl82c480_t { } vl82c480_t; static int -vl82c480_shflags(uint8_t access, uint8_t access2) +vl82c480_shflags(uint8_t access) { int ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; - int wp = ((access2 & 0x03) == 0x01); switch (access) { default: case 0x00: - ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY); + ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY; break; case 0x01: - ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL); + ret = MEM_READ_EXTANY | MEM_WRITE_INTERNAL; break; case 0x02: - ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY); + ret = MEM_READ_INTERNAL | MEM_WRITE_EXTANY; break; case 0x03: - ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL); + ret = MEM_READ_INTERNAL | MEM_WRITE_INTERNAL; break; } @@ -66,7 +65,6 @@ vl82c480_recalc_shadow(vl82c480_t *dev) { uint32_t base; uint8_t access; - uint8_t access2; shadowbios = 0; shadowbios_write = 0; @@ -75,10 +73,9 @@ vl82c480_recalc_shadow(vl82c480_t *dev) for (uint8_t j = 0; j < 8; j += 2) { base = 0x000a0000 + (i << 16) + (j << 13); access = (dev->regs[0x0d + i] >> j) & 3; - access2 = (dev->regs[0x13 + i] >> j) & 3; - mem_set_mem_state(base, 0x4000, vl82c480_shflags(access, access2)); + mem_set_mem_state(base, 0x4000, vl82c480_shflags(access)); shadowbios |= ((base >= 0xe0000) && (access & 0x02)); - shadowbios_write |= ((base >= 0xe0000) && (access & 0x01) && !(access2 & 0x01)); + shadowbios_write |= ((base >= 0xe0000) && (access & 0x01)); } } @@ -152,11 +149,9 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) case 0x07: dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf); break; - case 0x0d ... 0x18: + case 0x0d ... 0x12: dev->regs[dev->idx] = val; vl82c480_recalc_shadow(dev); - if (dev->idx >= 0x13) - flushmmucache(); break; } } From ddd271f6eee42c875523a10ee19eb1fdf2b8240b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 21:02:06 +0200 Subject: [PATCH 0935/1190] Honore the fixed bits of flags when pushing them to the stack, fixes #5093. --- src/codegen_new/codegen_ops_stack.c | 4 ++++ src/cpu/x86_ops_flag.h | 17 ++++------------- src/cpu/x86_ops_flag_2386.h | 17 ++++------------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/codegen_new/codegen_ops_stack.c b/src/codegen_new/codegen_ops_stack.c index fca9c9efa..f93289197 100644 --- a/src/codegen_new/codegen_ops_stack.c +++ b/src/codegen_new/codegen_ops_stack.c @@ -390,6 +390,8 @@ ropPUSHF(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUS uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); uop_CALL_FUNC(ir, flags_rebuild); sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_AND_IMM(ir, IREG_flags, IREG_flags, 0x7fd5); + uop_OR_IMM(ir, IREG_flags, IREG_flags, 0x0002); uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags); SUB_SP(ir, 2); @@ -406,6 +408,8 @@ ropPUSHFD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNU uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); uop_CALL_FUNC(ir, flags_rebuild); + uop_AND_IMM(ir, IREG_flags, IREG_flags, 0x7fd5); + uop_OR_IMM(ir, IREG_flags, IREG_flags, 0x0002); if (cpu_CR4_mask & CR4_VME) uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x3c); else if (CPUID) diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index a0fa612a8..7e7324341 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -121,6 +121,7 @@ opPUSHF(UNUSED(uint32_t fetchdat)) temp = (cpu_state.flags & ~I_FLAG) | 0x3000; if (cpu_state.eflags & VIF_FLAG) temp |= I_FLAG; + temp = (temp & 0x7fd5) | 2; PUSH_W(temp); } else { x86gpf(NULL, 0); @@ -128,6 +129,7 @@ opPUSHF(UNUSED(uint32_t fetchdat)) } } else { flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2; PUSH_W(cpu_state.flags); } CLOCK_CYCLES(4); @@ -149,6 +151,7 @@ opPUSHFD(UNUSED(uint32_t fetchdat)) else tempw = cpu_state.eflags & 4; flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2; PUSH_L(cpu_state.flags | (tempw << 16)); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0, 0, 0, 1, 0); @@ -160,23 +163,11 @@ opPOPF_186(UNUSED(uint32_t fetchdat)) { uint16_t tempw; - if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL, 0); - return 1; - } - tempw = POP_W(); if (cpu_state.abrt) return 1; - if (!(msw & 1)) - cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; - else if (!(CPL)) - cpu_state.flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) - cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; - else - cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; flags_extract(); #ifdef USE_DEBUG_REGS_486 rf_flag_no_clear = 1; diff --git a/src/cpu/x86_ops_flag_2386.h b/src/cpu/x86_ops_flag_2386.h index c9a2d5ab2..787b268dc 100644 --- a/src/cpu/x86_ops_flag_2386.h +++ b/src/cpu/x86_ops_flag_2386.h @@ -121,6 +121,7 @@ opPUSHF(UNUSED(uint32_t fetchdat)) temp = (cpu_state.flags & ~I_FLAG) | 0x3000; if (cpu_state.eflags & VIF_FLAG) temp |= I_FLAG; + temp = (temp & 0x7fd5) | 2; PUSH_W(temp); } else { x86gpf(NULL, 0); @@ -128,6 +129,7 @@ opPUSHF(UNUSED(uint32_t fetchdat)) } } else { flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2; PUSH_W(cpu_state.flags); } CLOCK_CYCLES(4); @@ -149,6 +151,7 @@ opPUSHFD(UNUSED(uint32_t fetchdat)) else tempw = cpu_state.eflags & 4; flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2; PUSH_L(cpu_state.flags | (tempw << 16)); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0, 0, 0, 1, 0); @@ -160,23 +163,11 @@ opPOPF_186(UNUSED(uint32_t fetchdat)) { uint16_t tempw; - if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL, 0); - return 1; - } - tempw = POP_W(); if (cpu_state.abrt) return 1; - if (!(msw & 1)) - cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; - else if (!(CPL)) - cpu_state.flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) - cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; - else - cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; flags_extract(); rf_flag_no_clear = 1; From 30d7c8f51ca42b4a598b4b1b25a9712e9e531fef Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 17 May 2025 22:56:15 +0200 Subject: [PATCH 0936/1190] The recently introduced x86_64 variant of host_x86_MOV32_REG_ABS() was allocating the wrong number of bytes. --- src/codegen_new/codegen_backend_x86-64_ops.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/codegen_new/codegen_backend_x86-64_ops.c b/src/codegen_new/codegen_backend_x86-64_ops.c index ed218d7c4..1569e693c 100644 --- a/src/codegen_new/codegen_backend_x86-64_ops.c +++ b/src/codegen_new/codegen_backend_x86-64_ops.c @@ -781,14 +781,9 @@ host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ codegen_addlong(block, ram_offset); } else if ((ram_offset < -2147483648LL) || (ram_offset > 2147483647LL) || !(block->flags & CODEBLOCK_NO_IMMEDIATES)) { - // fatal("host_x86_MOV32_REG_ABS - out of range\n"); - // void *q = p; - //uint32_t *r = NULL; - // *r = 5; /* Crash deliberately. */ - codegen_alloc_bytes(block, 8); + codegen_alloc_bytes(block, 13); codegen_addbyte2(block, 0x49, 0xb9); /*MOV r9,(uintptr_t) p*/ codegen_addquad(block, (uintptr_t) p); - codegen_alloc_bytes(block, 3); codegen_addbyte3(block, 0x41, 0x8b, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [R9]*/ } else { fatal("host_x86_MOV32_REG_ABS - RAM offset = %016" PRIX64 " (p - ram = %016" PRIX64 ")\n", ram_offset, (uintptr_t) p - (uintptr_t) ram); From b3147ee4732112a62723d6b74a1d6bd44b50476f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 02:20:18 +0200 Subject: [PATCH 0937/1190] LOCK instruction: ensure it is always illegal on opcodes 90h and ECh. --- src/codegen/codegen_x86-64.c | 13 ++++++++++++- src/codegen/codegen_x86.c | 13 ++++++++++++- src/codegen_new/codegen.c | 13 +++++++++++-- src/cpu/x86_ops_misc.h | 2 +- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index c424cf8c5..fb775a2d0 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -818,6 +818,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int over = 0; int pc_off = 0; int test_modrm = 1; + int in_lock = 0; int c; uint32_t op87 = 0x00000000; @@ -956,6 +957,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p break; case 0xf0: /*LOCK*/ + in_lock = 0; break; case 0xf2: /*REPNE*/ @@ -1013,6 +1015,9 @@ generate_call: STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87); } + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + goto codegen_skip; + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); if (new_pc) { @@ -1040,7 +1045,13 @@ generate_call: } } - op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +codegen_skip: + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + /* This is always ILLEGAL. */ + op = x86_dynarec_opcodes_3DNOW[0xff]; + else + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (op_ssegs != last_ssegs) { last_ssegs = op_ssegs; addbyte(0xC6); /*MOVB $0,(ssegs)*/ diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index bf34c2de8..e0b9b633a 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1857,6 +1857,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int over = 0; int pc_off = 0; int test_modrm = 1; + int in_lock = 0; int c; uint32_t op87 = 0x00000000; @@ -1996,6 +1997,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p break; case 0xf0: /*LOCK*/ + in_lock = 1; break; case 0xf2: /*REPNE*/ @@ -2054,6 +2056,9 @@ generate_call: STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87); } + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + goto codegen_skip; + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); if (new_pc) { @@ -2080,7 +2085,13 @@ generate_call: } } - op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +codegen_skip: + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + /* This is always ILLEGAL. */ + op = x86_dynarec_opcodes_3DNOW[0xff]; + else + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (op_ssegs != last_ssegs) { last_ssegs = op_ssegs; diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 44dd408ab..26a74016a 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -395,6 +395,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p int over = 0; int test_modrm = 1; int pc_off = 0; + int in_lock = 0; uint32_t next_pc = 0; uint16_t op87 = 0x0000; #ifdef DEBUG_EXTRA @@ -556,6 +557,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p break; case 0xf0: /*LOCK*/ + in_lock = 1; break; case 0xf2: /*REPNE*/ @@ -675,6 +677,9 @@ generate_call: goto codegen_skip; #endif + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + goto codegen_skip; + if (recomp_op_table && recomp_op_table[(opcode | op_32) & recomp_opcode_mask]) { uint32_t new_pc = recomp_op_table[(opcode | op_32) & recomp_opcode_mask](block, ir, opcode, fetchdat, op_32, op_pc); if (new_pc) { @@ -692,13 +697,17 @@ generate_call: } } - // codegen_skip: +codegen_skip: if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) { op_table = x86_dynarec_opcodes; recomp_op_table = recomp_opcodes; } - op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) + /* This is always ILLEGAL. */ + op = x86_dynarec_opcodes_3DNOW[0xff]; + else + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; if (!test_modrm || (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]) || (op_table == x86_dynarec_opcodes_3DNOW)) { int stack_offset = 0; diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index ffc79f0e8..5ae28abc4 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -753,7 +753,7 @@ opLOCK(uint32_t fetchdat) return 0; cpu_state.pc++; - ILLEGAL_ON((fetchdat & 0xff) == 0x90); + ILLEGAL_ON(((fetchdat & 0xff) == 0x90) || ((fetchdat & 0xff) == 0xec)); CLOCK_CYCLES(4); PREFETCH_PREFIX(); From 20b2b1c90177b5a60bcd7ad7f8b3e70342aa35d3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 02:40:49 +0200 Subject: [PATCH 0938/1190] RZ-1000: Do not initialize the second IDE channel if the controller is single-channel. --- src/disk/hdc_ide_rz1000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c index 2c1a09e8e..e2c7179ad 100644 --- a/src/disk/hdc_ide_rz1000.c +++ b/src/disk/hdc_ide_rz1000.c @@ -272,7 +272,10 @@ rz1000_init(const device_t *info) dev->channels = ((info->local & 0x60000) >> 17) & 0x03; - device_add(&ide_pci_2ch_device); + if (dev->channels & 0x02) + device_add(&ide_pci_2ch_device); + else + device_add(&ide_pci_device); if (info->local & 0x80000) pci_add_card(PCI_ADD_NORMAL, rz1000_pci_read, rz1000_pci_write, dev, &dev->pci_slot); From d6231de1bcff03db0cb808d06da6099927a9d4b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 05:59:13 +0200 Subject: [PATCH 0939/1190] Added the Dell 466/NP, closes #3585. --- src/include/86box/machine.h | 2 ++ src/include/86box/video.h | 1 + src/machine/m_at_386dx_486.c | 37 ++++++++++++++++++++++++++++--- src/machine/machine_table.c | 40 +++++++++++++++++++++++++++++++++ src/video/vid_cl54xx.c | 43 +++++++++++++++++------------------- 5 files changed, 97 insertions(+), 26 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index febce3fa1..c76761b3c 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -532,6 +532,8 @@ extern int machine_at_cs4031_init(const machine_t *); extern int machine_at_pb410a_init(const machine_t *); extern int machine_at_decpclpv_init(const machine_t *); +extern int machine_at_dell466np_init(const machine_t *); + extern int machine_at_acerv10_init(const machine_t *); extern int machine_at_acera1g_init(const machine_t *); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index bbcc94fe7..085dd5f80 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -365,6 +365,7 @@ extern const device_t gd5428_boca_isa_device; extern const device_t gd5428_mca_device; extern const device_t gd5426_mca_device; extern const device_t gd5428_onboard_device; +extern const device_t gd5428_onboard_vlb_device; extern const device_t gd5429_isa_device; extern const device_t gd5429_vlb_device; extern const device_t gd5430_diamond_speedstar_pro_se_a8_vlb_device; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index c2cf82352..e03b6d65d 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -545,16 +545,47 @@ machine_at_decpclpv_init(const machine_t *model) device_add(&sis_85c461_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&s3_86c805_onboard_vlb_device); + device_add(machine_get_vid_device(machine)); + + device_add(&keyboard_ps2_phoenix_pci_device); - /* TODO: Phoenix MultiKey KBC */ - device_add(&keyboard_ps2_ami_pci_device); device_add(&ide_isa_2ch_device); device_add(&fdc37c663_ide_device); return ret; } +int +machine_at_dell466np_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/dell466np/466np.bin", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&sis_85c461_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + else { + for (uint16_t i = 0; i < 32768; i++) + rom[i] = mem_readb_phys(0x000c0000 + i); + } + mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000); + mem_mapping_set_exec(&bios_mapping, rom); + + device_add(&keyboard_ps2_phoenix_pci_device); + + device_add(&ide_isa_device); + device_add(&fdc37c661_ide_device); + + return ret; +} + static void machine_at_ali1429_common_init(const machine_t *model, int is_green) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9b53257bf..ee3485373 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6934,6 +6934,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Uses a ???? KBC. */ + { + .name = "[SiS 461] Dell 466/NP", + .internal_name = "dell466np", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_SIS_461, + .init = machine_at_dell466np_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5428_onboard_vlb_device, + .snd_device = NULL, + .net_device = NULL + }, /* The BIOS does not send any non-standard keyboard controller commands and wants a PS/2 mouse, so it's an IBM PS/2 KBC (Type 1) firmware. */ { diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index dbb9d5993..13f96501c 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4273,7 +4273,10 @@ gd54xx_init(const device_t *info) break; case CIRRUS_ID_CLGD5428: - if (info->local & 0x100) + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else if (info->local & 0x100) if (gd54xx->vlb) romfn = BIOS_GD5428_DIAMOND_B1_VLB_PATH; else { @@ -4750,26 +4753,6 @@ static const device_config_t gd5426_config[] = { { .name = "", .description = "", .type = CONFIG_END } }; -static const device_config_t gd5428_onboard_config[] = { - { - .name = "memory", - .description = "Memory size", - .type = CONFIG_SELECTION, - .default_string = NULL, - .default_int = 2048, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { - { .description = "512 KB", .value = 512 }, - { .description = "1 MB", .value = 1024 }, - { .description = "2 MB", .value = 2048 }, - { .description = "" } - }, - .bios = { { 0 } } - }, - { .name = "", .description = "", .type = CONFIG_END } -}; - static const device_config_t gd5429_config[] = { { .name = "memory", @@ -5176,7 +5159,7 @@ const device_t gd5428_onboard_device = { .available = gd5428_isa_available, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5428_onboard_config + .config = gd5426_config }; const device_t gd5428_vlb_onboard_device = { @@ -5190,7 +5173,21 @@ const device_t gd5428_vlb_onboard_device = { .available = NULL, .speed_changed = gd54xx_speed_changed, .force_redraw = gd54xx_force_redraw, - .config = gd5428_onboard_config + .config = gd5426_config +}; + +const device_t gd5428_onboard_vlb_device = { + .name = "Cirrus Logic GD5428 (VLB) (On-Board) (Dell)", + .internal_name = "cl_gd5428_onboard_vlb", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5428 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + .available = NULL, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config }; const device_t gd5429_isa_device = { From 8b4adebfd2bc22bc5f795c98ef288fd55b8ddae2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 06:17:24 +0200 Subject: [PATCH 0940/1190] AOpen AP5S: Add two more BIOS'es, including a 4.50PG, fulfills #643. --- src/machine/m_at_386dx_486.c | 3 -- src/machine/m_at_socket7_3v.c | 55 +++++++++++++++++++++++++++++++---- src/machine/machine_table.c | 3 +- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index e03b6d65d..46b93a37f 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1727,9 +1727,6 @@ machine_at_sb486pv_init(const machine_t *model) device_context_restore(); machine_at_common_init(model); - // machine_at_common_init_ex(model, 2); - - // device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 39dc2d735..b587a8551 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -706,17 +706,62 @@ machine_at_gw2kma_init(const machine_t *model) return ret; } +static const device_config_t ap5s_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ap5s", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "04/22/96 1.20 4.50PG", .internal_name = "ap5s_450pg", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/ap5s120.bin", "" } }, + { .name = "11/13/96 1.50 4.51PG", .internal_name = "ap5s", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/AP5S150.BIN", "" } }, + { .name = "06/25/97 1.60 4.51PG", .internal_name = "ap5s_latest", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/ap5s/ap5s160.bin", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ap5s_device = { + .name = "AOpen AP5S", + .internal_name = "ap5s_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ap5s_config +}; + int machine_at_ap5s_init(const machine_t *model) { - int ret; + int ret = 0; + const char* fn; - ret = bios_load_linear("roms/machines/ap5s/AP5S150.BIN", - 0x000e0000, 131072, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + else + ret = bios_load_linear_inverted(fn, 0x000e0000, 131072, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1 | FLAG_TRC_CONTROLS_CPURST); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ee3485373..17fde9581 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -70,6 +70,7 @@ extern const device_t jukopc_device; extern const device_t vendex_device; extern const device_t c5sbm2_device; extern const device_t sb486pv_device; +extern const device_t ap5s_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -11820,7 +11821,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &ap5s_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, From 8ff85bf36b638c6f804956bef0283cd5b5d1473f Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sun, 18 May 2025 11:25:17 +0700 Subject: [PATCH 0941/1190] Moved "device" to .vid_device on SBC-490 --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 17fde9581..45986a50a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7857,10 +7857,10 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = &tgui9440_onboard_pci_device, + .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &tgui9440_onboard_pci_device, .snd_device = NULL, .net_device = NULL }, From 3f93bde031d29fbb0e43990212d478f8776e7281 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 06:44:37 +0200 Subject: [PATCH 0942/1190] AOpen AP5S: Fix BIOS loading. --- src/machine/m_at_socket7_3v.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index b587a8551..5b5724e37 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -756,10 +756,7 @@ machine_at_ap5s_init(const machine_t *model) device_context(model->device); fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); - if (!strcmp(fn, "roms/machines/sb486pv/amiboot.rom")) - ret = bios_load_linear(fn, 0x000e0000, 131072, 0); - else - ret = bios_load_linear_inverted(fn, 0x000e0000, 131072, 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); device_context_restore(); machine_at_common_init_ex(model, 2); From 7b9b2bc10df309d3b818e4e25e6b5022785dbc5c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:14:46 +0200 Subject: [PATCH 0943/1190] Some FDC, SM(S)C FDC37C66x, and VLSI VL82C480 changes. --- src/chipset/vl82c480.c | 20 +++++++++++++++----- src/floppy/fdc.c | 35 +++++++++++++++++++++++++++++----- src/include/86box/fdc.h | 42 +++++++++++++++++++++-------------------- src/sio/sio_fdc37c6xx.c | 5 ++++- 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 6354ac15a..acb3568af 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -132,7 +132,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) break; case 0x02: case 0x03: dev->regs[dev->idx] = val; - if (!strcmp(machine_get_internal_name(), "martin")) + if (!strcmp(machine_get_internal_name(), "martin") || + !strcmp(machine_get_internal_name(), "prolineamt")) vl82c480_recalc_banks(dev); break; case 0x04: @@ -140,8 +141,6 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7); else dev->regs[dev->idx] = val; - if (!strcmp(machine_get_internal_name(), "martin")) - dev->regs[dev->idx] &= 0x1f; break; case 0x05: dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef); @@ -221,6 +220,9 @@ vl82c480_init(const device_t *info) vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 }; uint32_t ms = mem_size; + uint8_t min_i = !strcmp(machine_get_internal_name(), "prolineamt") ? 1 : 0; + uint8_t min_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 4 : 2; + uint8_t max_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 8 : 7; dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; @@ -231,8 +233,16 @@ vl82c480_init(const device_t *info) dev->regs[0x07] = 0x21; dev->regs[0x08] = 0x38; - for (uint8_t i = 0; i < 4; i++) { - for (uint8_t j = 2; j < 7; j++) { + if (!strcmp(machine_get_internal_name(), "prolineamt")) { + dev->banks[0] = 4096; + + /* Bank 0 is ignored if 64 MB is installed. */ + if (ms != 65536) + ms -= 4096; + } + + if (ms > 0) for (uint8_t i = min_i; i < 4; i++) { + for (uint8_t j = min_j; j < max_j; j++) { if (ms >= sizes[j]) dev->banks[i] = sizes[j]; else diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index e7166d1ba..b43daa32c 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -469,9 +469,11 @@ fdc_update_drv2en(fdc_t *fdc, int drv2en) void fdc_update_rate(fdc_t *fdc, int drive) { - if (((fdc->rwc[drive] == 1) || (fdc->rwc[drive] == 2)) && fdc->enh_mode) + if (((fdc->rwc[drive] == 1) || (fdc->rwc[drive] == 2)) && + fdc->enh_mode && !(fdc->flags & FDC_FLAG_SMC661)) fdc->bit_rate = 500; - else if ((fdc->rwc[drive] == 3) && fdc->enh_mode) + else if ((fdc->rwc[drive] == 3) && fdc->enh_mode && + !(fdc->flags & FDC_FLAG_SMC661)) fdc->bit_rate = 250; else switch (fdc->rate) { default: @@ -535,7 +537,7 @@ fdc_get_bitcell_period(fdc_t *fdc) static int fdc_get_densel(fdc_t *fdc, int drive) { - if (fdc->enh_mode) { + if (fdc->enh_mode && !(fdc->flags & FDC_FLAG_SMC661)) { switch (fdc->rwc[drive]) { case 1: case 3: @@ -770,8 +772,13 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 3: /* TDR */ if (fdc->enh_mode) { - drive = real_drive(fdc, fdc->dor & 3); - fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); + if (fdc->flags & FDC_FLAG_SMC661) { + fdc_set_swap(fdc, !!(val & 0x20)); + fdc_update_densel_force(fdc, (val & 0x18) >> 3); + } else { + drive = real_drive(fdc, fdc->dor & 3); + fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); + } } /* Bit 2: FIFO test mode (PS/55 5550-S,T only. Undocumented) The Power-on Self Test of PS/55 writes and verifies 8 bytes of FIFO buffer through I/O 3F5h. @@ -1391,6 +1398,8 @@ fdc_read(uint16_t addr, void *priv) /* PS/55 POST throws an error and halt if ret = 1 or 2, somehow. */ } else if (!fdc->enh_mode) ret = 0x20; + else if (fdc->flags & FDC_FLAG_SMC661) + ret = (fdc->densel_force << 3) | ((!!fdc->swap) << 5) | (fdc->media_id << 6); else ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); break; @@ -2401,6 +2410,8 @@ fdc_init(const device_t *info) fdc_t *fdc = (fdc_t *) calloc(1, sizeof(fdc_t)); fdc->flags = info->local; + if (fdc->flags & FDC_FLAG_SMC661) + pclog("661!\n"); if (fdc->flags & FDC_FLAG_SEC) fdc->irq = FDC_SECONDARY_IRQ; @@ -2644,6 +2655,20 @@ const device_t fdc_at_actlow_device = { .config = NULL }; +const device_t fdc_at_smc_661_device = { + .name = "PC/AT Floppy Drive Controller (SM(s)C FDC37C661/2)", + .internal_name = "fdc_at_smc", + .flags = 0, + .local = FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_SMC661, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t fdc_at_smc_device = { .name = "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", .internal_name = "fdc_at_smc", diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index ed62cb45f..53511daac 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -38,26 +38,27 @@ #define FDC_QUATERNARY_IRQ 6 #define FDC_QUATERNARY_DMA 2 -#define FDC_FLAG_PCJR 0x01 /* PCjr */ -#define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */ -#define FDC_FLAG_AT 0x04 /* AT+, PS/x */ -#define FDC_FLAG_PS2 0x08 /* PS/1, PS/2 ISA */ -#define FDC_FLAG_PS2_MCA 0x10 /* PS/2 MCA */ -#define FDC_FLAG_SUPERIO 0x20 /* Super I/O chips */ -#define FDC_FLAG_START_RWC_1 0x40 /* W83877F, W83977F */ -#define FDC_FLAG_MORE_TRACKS 0x80 /* W83877F, W83977F, PC87306, PC87309 */ -#define FDC_FLAG_NSC 0x100 /* PC87306, PC87309 */ -#define FDC_FLAG_TOSHIBA 0x200 /* T1000, T1200 */ -#define FDC_FLAG_AMSTRAD 0x400 /* Non-AT Amstrad machines */ -#define FDC_FLAG_UMC 0x800 /* UMC UM8398 */ -#define FDC_FLAG_ALI 0x1000 /* ALi M512x / M1543C */ -#define FDC_FLAG_NO_DSR_RESET 0x2000 /* Has no DSR reset */ -#define FDC_FLAG_DENSEL_INVERT 0x4000 /* Invert DENSEL polarity */ -#define FDC_FLAG_FINTR 0x8000 /* Raise FINTR on data command finish */ -#define FDC_FLAG_NEC 0x10000 /* Is NEC upd765-compatible */ -#define FDC_FLAG_SEC 0x20000 /* Is Secondary */ -#define FDC_FLAG_TER 0x40000 /* Is Tertiary */ -#define FDC_FLAG_QUA 0x80000 /* Is Quaternary */ +#define FDC_FLAG_PCJR 0x01 /* PCjr */ +#define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */ +#define FDC_FLAG_AT 0x04 /* AT+, PS/x */ +#define FDC_FLAG_PS2 0x08 /* PS/1, PS/2 ISA */ +#define FDC_FLAG_PS2_MCA 0x10 /* PS/2 MCA */ +#define FDC_FLAG_SUPERIO 0x20 /* Super I/O chips */ +#define FDC_FLAG_START_RWC_1 0x40 /* W83877F, W83977F */ +#define FDC_FLAG_MORE_TRACKS 0x80 /* W83877F, W83977F, PC87306, PC87309 */ +#define FDC_FLAG_NSC 0x100 /* PC87306, PC87309 */ +#define FDC_FLAG_TOSHIBA 0x200 /* T1000, T1200 */ +#define FDC_FLAG_AMSTRAD 0x400 /* Non-AT Amstrad machines */ +#define FDC_FLAG_UMC 0x800 /* UMC UM8398 */ +#define FDC_FLAG_ALI 0x1000 /* ALi M512x / M1543C */ +#define FDC_FLAG_NO_DSR_RESET 0x2000 /* Has no DSR reset */ +#define FDC_FLAG_DENSEL_INVERT 0x4000 /* Invert DENSEL polarity */ +#define FDC_FLAG_FINTR 0x8000 /* Raise FINTR on data command finish */ +#define FDC_FLAG_NEC 0x10000 /* Is NEC upd765-compatible */ +#define FDC_FLAG_SEC 0x20000 /* Is Secondary */ +#define FDC_FLAG_TER 0x40000 /* Is Tertiary */ +#define FDC_FLAG_QUA 0x80000 /* Is Quaternary */ +#define FDC_FLAG_SMC661 0x100000 /* SM(s)C FDC37C661 - different TDR enhanced mode */ typedef struct fdc_t { uint8_t dor; @@ -260,6 +261,7 @@ extern const device_t fdc_at_sec_device; extern const device_t fdc_at_ter_device; extern const device_t fdc_at_qua_device; extern const device_t fdc_at_actlow_device; +extern const device_t fdc_at_smc_661_device; extern const device_t fdc_at_smc_device; extern const device_t fdc_at_ali_device; extern const device_t fdc_at_winbond_device; diff --git a/src/sio/sio_fdc37c6xx.c b/src/sio/sio_fdc37c6xx.c index 3afd92e4c..aa66af883 100644 --- a/src/sio/sio_fdc37c6xx.c +++ b/src/sio/sio_fdc37c6xx.c @@ -314,7 +314,10 @@ fdc37c6xx_init(const device_t *info) { fdc37c6xx_t *dev = (fdc37c6xx_t *) calloc(1, sizeof(fdc37c6xx_t)); - dev->fdc = device_add(&fdc_at_smc_device); + if (dev->chip_id >= 0x63) + dev->fdc = device_add(&fdc_at_smc_device); + else + dev->fdc = device_add(&fdc_at_smc_661_device); dev->chip_id = info->local & 0xff; dev->has_ide = (info->local >> 8) & 0xff; From 196289d6e50c1f2f76fd220030117e61290775a3 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:17:04 +0200 Subject: [PATCH 0944/1190] AT KBC fixes for the Dell. --- src/device/kbc_at.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index a8a8c51cc..58aab476c 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1088,12 +1088,24 @@ write64_generic(void *priv, uint8_t val) /* (B0 or F0) | (0x04 or 0x0c) */ kbc_delay_to_ob(dev, dev->p1 | fixed_bits, 0, 0x00); } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_GREEN)) { - /* (B0 or F0) | (0x08 or 0x0c) */ - uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | - (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c); - if (!strcmp(machine_get_internal_name(), "alfredo")) - p1_out &= 0xef; - kbc_delay_to_ob(dev, p1_out, 0, 0x00); + if (!strcmp(machine_get_internal_name(), "dell466np")) { + /* + Dell 466/NP: + - Bit 2: Keyboard fuse (must be set); + - Bit 4: Password disable jumper (must be clear); + - Bit 5: Manufacturing jumper (must be set); + */ + uint8_t p1 = 0x24; + kbc_delay_to_ob(dev, p1, 0, 0x01); + } else { + /* (B0 or F0) | (0x08 or 0x0c) */ + uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | + (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0x08 : 0x0c); + if (!strcmp(machine_get_internal_name(), "alfredo")) + p1_out &= 0xef; + + kbc_delay_to_ob(dev, p1_out, 0, 0x00); + } } else if (kbc_ven == KBC_VEN_COMPAQ) kbc_delay_to_ob(dev, dev->p1 | (hasfpu ? 0x00 : 0x04), 0, 0x00); else From 76c3ad9868bf83c8f90a860e4a6ce15ca6053942 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:18:18 +0200 Subject: [PATCH 0945/1190] Removed an excess logging line. --- src/floppy/fdc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index b43daa32c..cf5ae41bf 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -2410,8 +2410,6 @@ fdc_init(const device_t *info) fdc_t *fdc = (fdc_t *) calloc(1, sizeof(fdc_t)); fdc->flags = info->local; - if (fdc->flags & FDC_FLAG_SMC661) - pclog("661!\n"); if (fdc->flags & FDC_FLAG_SEC) fdc->irq = FDC_SECONDARY_IRQ; From 5dc99cc137b1815b67069a29dc29d5453069ba2f Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 08:37:02 +0200 Subject: [PATCH 0946/1190] SiS 85c46x and 471 - implement AT bus speed configuration. --- src/chipset/sis_85c4xx.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/chipset/sis_85c4xx.c b/src/chipset/sis_85c4xx.c index f715c5272..be5bd668e 100644 --- a/src/chipset/sis_85c4xx.c +++ b/src/chipset/sis_85c4xx.c @@ -15,6 +15,7 @@ * * Copyright 2019-2020 Miran Grca. */ +#include #include #include #include @@ -631,6 +632,41 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv) sis_85c4xx_recalcremap(dev); break; + case 0x10: + if (dev->reg_base == 0x50) { + double bus_clk; + + switch (val & 0xe0) { + default: + case 0x00: + bus_clk = 7159091.0; + break; + case 0x02: + bus_clk = cpu_busspeed / 10.0; + break; + case 0x04: + bus_clk = cpu_busspeed / 8.0; + break; + case 0x06: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x80: + bus_clk = cpu_busspeed / 5.0; + break; + case 0xa0: + bus_clk = cpu_busspeed / 4.0; + break; + case 0xc0: + bus_clk = cpu_busspeed / 3.0; + break; + case 0xe0: + bus_clk = cpu_busspeed / 2.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + } + break; + case 0x13: if (dev->is_471 && (valxor & 0xf0)) { smram_disable(dev->smram); @@ -813,6 +849,9 @@ sis_85c4xx_reset(void *priv) dev->force_flush = 1; sis_85c4xx_recalcmapping(dev); + + if (dev->reg_base == 0x50) + cpu_set_isa_speed((int) round(7159091.0)); } static void From 3b7515a4ff5b1b3ae611e19a50995f5e26b27ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 18 May 2025 09:11:13 +0200 Subject: [PATCH 0947/1190] Treat port 0x84, even if something is listening to it, as a delay port, fixes the Dell 466/NP on faster CPU's. --- src/io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/io.c b/src/io.c index 9554c971d..45dd4cb3d 100644 --- a/src/io.c +++ b/src/io.c @@ -445,10 +445,10 @@ outb(uint16_t port, uint8_t val) } } - if (!found) { + if (!found || (port == 0x84)) { cycles -= io_delay; #ifdef USE_DYNAREC - if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) + if (cpu_use_dynarec && ((port == 0x84) || (port == 0xeb) || (port == 0xed))) update_tsc(); #endif } From 643389e0fe0e1435d3581125a9c52adf9f9ffd3c Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:04 +0600 Subject: [PATCH 0948/1190] Revert "SAASound filter fixes" This reverts commit 14ffb89f4d01fe01353e97edf7b874d9f6944477. --- src/sound/saasound/SAAImpl.cpp | 1 + src/sound/saasound/SAAImpl.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp index cb5d8f739..f136eefc6 100644 --- a/src/sound/saasound/SAAImpl.cpp +++ b/src/sound/saasound/SAAImpl.cpp @@ -306,6 +306,7 @@ void scale_for_output(unsigned int left_input, unsigned int right_input, void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) { unsigned int left_mixed, right_mixed; + static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; #if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) BYTE* pBufferStart = pBuffer; diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h index 6cd3048fe..61fa79c58 100755 --- a/src/sound/saasound/SAAImpl.h +++ b/src/sound/saasound/SAAImpl.h @@ -36,8 +36,6 @@ private: unsigned int m_nSampleRate; unsigned int m_nOversample; bool m_bHighpass; - double filterout_z1_left_mixed = 0; - double filterout_z1_right_mixed = 0; #ifdef USE_CONFIG_FILE SAAConfig m_Config; #endif From 5fce54a7f0f36f886c836945c64e69a35d32c7a8 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:22 +0600 Subject: [PATCH 0949/1190] Revert "CMS: Divide SAA samples by 2 so that the sum remains within the -32767 to 32768 range and avoids clipping." This reverts commit c63d900a9383b74fbd8a5fa7209a0b2a6364a913. --- src/sound/snd_cms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index 9491e3076..c6591b1fc 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -34,7 +34,7 @@ cms_get_buffer(int32_t *buffer, int len, void *priv) cms_update(cms); for (int c = 0; c < len * 2; c++) - buffer[c] += (cms->buffer[c] / 2); + buffer[c] += cms->buffer[c]; cms->pos = 0; } @@ -47,7 +47,7 @@ cms_get_buffer_2(int32_t *buffer, int len, void *priv) cms_update(cms); for (int c = 0; c < len * 2; c++) - buffer[c] += (cms->buffer2[c] / 2); + buffer[c] += cms->buffer2[c]; cms->pos2 = 0; } From 9cfe5141d4595cf84b0afec21be56c592aba3ae7 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:44:49 +0600 Subject: [PATCH 0950/1190] Revert "Port Sound Blaster 1.x/2.x SAA1099 emulation to SAASound" This reverts commit b644016d1e0a7a917637c2fadcf8d8056d09b4ab. --- src/sound/snd_sb.c | 65 ++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 4a17fe20b..e89946486 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -41,7 +41,6 @@ #include <86box/sound.h> #include "cpu.h" #include <86box/timer.h> -#include "saasound/SAASound.h" #include <86box/snd_sb.h> #include <86box/plat_unused.h> @@ -146,42 +145,6 @@ sb_log(const char *fmt, ...) # define sb_log(fmt, ...) #endif -void -sb_cms_get_buffer(int32_t *buffer, int len, void *priv) -{ - sb_t *sb = (sb_t *) priv; - - cms_update(&sb->cms); - - for (int c = 0; c < len * 2; c++) { - if (sb->mixer_enabled) { - buffer[c] += sb->cms.buffer[c] * sb->mixer_sb2.fm; - } - else - buffer[c] += sb->cms.buffer[c]; - } - - sb->cms.pos = 0; -} - -void -sb_cms_get_buffer_2(int32_t *buffer, int len, void *priv) -{ - sb_t *sb = (sb_t *) priv; - - cms_update(&sb->cms); - - for (int c = 0; c < len * 2; c++) { - if (sb->mixer_enabled) { - buffer[c] += sb->cms.buffer2[c] * sb->mixer_sb2.fm; - } - else - buffer[c] += sb->cms.buffer2[c]; - } - - sb->cms.pos2 = 0; -} - /* SB 1, 1.5, MCV, and 2 do not have a mixer, so signal is hardwired. */ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) @@ -192,10 +155,23 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) sb_dsp_update(&sb->dsp); + if (sb->cms_enabled) + cms_update(&sb->cms); + for (int c = 0; c < len * 2; c += 2) { double out_l = 0.0; double out_r = 0.0; + if (sb->cms_enabled) { + out_l += sb->cms.buffer[c]; + out_r += sb->cms.buffer[c + 1]; + } + + if (sb->cms_enabled && sb->mixer_enabled) { + out_l *= mixer->fm; + out_r *= mixer->fm; + } + /* TODO: Recording: I assume it has direct mic and line in like SB2. It is unclear from the docs if it has a filter, but it probably does. */ /* TODO: Recording: Mic and line In with AGC. */ @@ -216,6 +192,9 @@ sb_get_buffer_sb2(int32_t *buffer, int len, void *priv) } sb->dsp.pos = 0; + + if (sb->cms_enabled) + sb->cms.pos = 0; } static void @@ -2911,13 +2890,6 @@ sb_init(UNUSED(const device_t *info)) cms_read, NULL, NULL, cms_write, NULL, NULL, &sb->cms); - - sb->cms.saasound = newSAASND(); - SAASNDSetSoundParameters(sb->cms.saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); - sb->cms.saasound2 = newSAASND(); - SAASNDSetSoundParameters(sb->cms.saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); - wavetable_add_handler(sb_cms_get_buffer, sb); - wavetable_add_handler(sb_cms_get_buffer_2, sb); } if (mixer_addr > 0x000) { @@ -4072,11 +4044,6 @@ sb_close(void *priv) sb_t *sb = (sb_t *) priv; sb_dsp_close(&sb->dsp); - if (sb->cms_enabled) { - deleteSAASND(sb->cms.saasound); - deleteSAASND(sb->cms.saasound2); - } - free(sb); } From 5390f50e516aaa8ec4370db30cc528a1757bd4b3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 18 May 2025 13:47:06 +0600 Subject: [PATCH 0951/1190] Revert "Switch to SAASound for CMS" This reverts commit fd618440618e3d6e426d60e59921fd8495531b09. --- src/include/86box/snd_cms.h | 23 +- src/sound/CMakeLists.txt | 3 - src/sound/saasound/CMakeLists.txt | 16 - src/sound/saasound/SAAAmp.cpp | 203 --------- src/sound/saasound/SAAAmp.h | 44 -- src/sound/saasound/SAAConfig.h | 41 -- src/sound/saasound/SAADevice.cpp | 392 ----------------- src/sound/saasound/SAADevice.h | 69 --- src/sound/saasound/SAAEnv.cpp | 380 ---------------- src/sound/saasound/SAAEnv.h | 54 --- src/sound/saasound/SAAFreq.cpp | 287 ------------ src/sound/saasound/SAAFreq.dat | 141 ------ src/sound/saasound/SAAFreq.h | 72 --- src/sound/saasound/SAAImpl.cpp | 489 --------------------- src/sound/saasound/SAAImpl.h | 75 ---- src/sound/saasound/SAANoise.cpp | 180 -------- src/sound/saasound/SAANoise.h | 54 --- src/sound/saasound/SAASndC.cpp | 100 ----- src/sound/saasound/SAASndC.h | 102 ----- src/sound/saasound/SAASound.cpp | 13 - src/sound/saasound/SAASound.h | 130 ------ src/sound/saasound/defns.h | 59 --- src/sound/saasound/resource.h | 15 - src/sound/saasound/saasound_cmake_config.h | 14 - src/sound/saasound/types.h | 34 -- src/sound/snd_cms.c | 140 ++++-- 26 files changed, 115 insertions(+), 3015 deletions(-) delete mode 100644 src/sound/saasound/CMakeLists.txt delete mode 100755 src/sound/saasound/SAAAmp.cpp delete mode 100755 src/sound/saasound/SAAAmp.h delete mode 100644 src/sound/saasound/SAAConfig.h delete mode 100644 src/sound/saasound/SAADevice.cpp delete mode 100644 src/sound/saasound/SAADevice.h delete mode 100755 src/sound/saasound/SAAEnv.cpp delete mode 100755 src/sound/saasound/SAAEnv.h delete mode 100755 src/sound/saasound/SAAFreq.cpp delete mode 100755 src/sound/saasound/SAAFreq.dat delete mode 100755 src/sound/saasound/SAAFreq.h delete mode 100644 src/sound/saasound/SAAImpl.cpp delete mode 100755 src/sound/saasound/SAAImpl.h delete mode 100755 src/sound/saasound/SAANoise.cpp delete mode 100755 src/sound/saasound/SAANoise.h delete mode 100755 src/sound/saasound/SAASndC.cpp delete mode 100644 src/sound/saasound/SAASndC.h delete mode 100755 src/sound/saasound/SAASound.cpp delete mode 100644 src/sound/saasound/SAASound.h delete mode 100644 src/sound/saasound/defns.h delete mode 100755 src/sound/saasound/resource.h delete mode 100644 src/sound/saasound/saasound_cmake_config.h delete mode 100755 src/sound/saasound/types.h diff --git a/src/include/86box/snd_cms.h b/src/include/86box/snd_cms.h index 8201fe32c..8eec22935 100644 --- a/src/include/86box/snd_cms.h +++ b/src/include/86box/snd_cms.h @@ -7,20 +7,23 @@ #define MASTER_CLOCK 7159090 typedef struct cms_t { -#ifdef SAASOUND_H_INCLUDED - SAASND saasound; - SAASND saasound2; -#else - void* saasound; - void* saasound2; -#endif + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; uint8_t latched_data; - int16_t buffer[WTBUFLEN * 2]; - int16_t buffer2[WTBUFLEN * 2]; + int16_t buffer[SOUNDBUFLEN * 2]; - int pos, pos2; + int pos; } cms_t; extern void cms_update(cms_t *cms); diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index d575717a0..0a04b0ff1 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -180,9 +180,6 @@ endif() add_subdirectory(ymfm) target_link_libraries(86Box ymfm) -add_subdirectory(saasound) -target_link_libraries(86Box saasound) - if(GUSMAX) target_compile_definitions(snd PRIVATE USE_GUSMAX) endif() diff --git a/src/sound/saasound/CMakeLists.txt b/src/sound/saasound/CMakeLists.txt deleted file mode 100644 index 2db75493e..000000000 --- a/src/sound/saasound/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -add_library(saasound OBJECT - SAAAmp.cpp - SAAAmp.h - SAADevice.cpp - SAADevice.h - SAAEnv.cpp - SAAEnv.h - SAAFreq.cpp - SAAFreq.h - SAAImpl.cpp - SAAImpl.h - SAANoise.cpp - SAANoise.h - SAASndC.cpp - SAASndC.h - SAASound.cpp) \ No newline at end of file diff --git a/src/sound/saasound/SAAAmp.cpp b/src/sound/saasound/SAAAmp.cpp deleted file mode 100755 index 8f2473fb1..000000000 --- a/src/sound/saasound/SAAAmp.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAAmp.cpp: implementation of the CSAAAmp class. -// This class handles Tone/Noise mixing, Envelope application and -// amplification. -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" -#include "types.h" -#include "SAANoise.h" -#include "SAAEnv.h" -#include "SAAFreq.h" -#include "SAAAmp.h" -#include "defns.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAAAmp::CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator) -: -m_pcConnectedToneGenerator(ToneGenerator), -m_pcConnectedNoiseGenerator(NoiseGenerator), -m_pcConnectedEnvGenerator(EnvGenerator), -m_bUseEnvelope(EnvGenerator != NULL) -{ - leftlevel = 0; - leftlevela0x0e = 0; - rightlevel = 0; - rightlevela0x0e = 0; - m_nMixMode = 0; - m_bMute=true; - m_bSync = false; - m_nOutputIntermediate=0; - last_level_byte=0; - SetAmpLevel(0x00); - -} - -CSAAAmp::~CSAAAmp() -{ - // Nothing to do -} - -void CSAAAmp::SetAmpLevel(BYTE level_byte) -{ - // if level unchanged since last call then do nothing - if (level_byte != last_level_byte) - { - last_level_byte = level_byte; - leftlevel = level_byte & 0x0f; - leftlevela0x0e = leftlevel & 0x0e; - - rightlevel = (level_byte >> 4) & 0x0f; - rightlevela0x0e = rightlevel & 0x0e; - } - -} - -void CSAAAmp::SetToneMixer(BYTE bEnabled) -{ - if (bEnabled == 0) - { - // clear mixer bit - m_nMixMode &= ~(0x01); - } - else - { - // set mixer bit - m_nMixMode |= 0x01; - } -} - -void CSAAAmp::SetNoiseMixer(BYTE bEnabled) -{ - if (bEnabled == 0) - { - m_nMixMode &= ~(0x02); - } - else - { - m_nMixMode |= 0x02; - } -} - -void CSAAAmp::Mute(bool bMute) -{ - // m_bMute refers to the GLOBAL mute setting (register 28 bit 0) - // NOT the per-channel mixer settings !! - m_bMute = bMute; -} - -void CSAAAmp::Sync(bool bSync) -{ - // m_bSync refers to the GLOBAL sync setting (register 28 bit 1) - m_bSync = bSync; -} - -void CSAAAmp::Tick(void) -{ - // updates m_nOutputIntermediate to 0, 1 or 2 - // - - // connected oscillator always ticks (this isn't really connected to the amp) - int level = m_pcConnectedToneGenerator->Tick(); - - switch (m_nMixMode) - { - case 0: - // no tone or noise for this channel - m_nOutputIntermediate = 0; - break; - case 1: - // tone only for this channel - m_nOutputIntermediate = level * 2; - // NOTE: ConnectedToneGenerator returns either 0 or 1 - break; - case 2: - // noise only for this channel - m_nOutputIntermediate = m_pcConnectedNoiseGenerator->Level() * 2; - // NOTE: ConnectedNoiseGenerator()->Level() returns either 0 or 1 - break; - case 3: - // tone+noise for this channel ... mixing algorithm : - // tone noise output - // 0 0 0 - // 1 0 2 - // 0 1 0 - // 1 1 1 - // = 2 * tone - 1 * (tone & noise) - // = tone * (2 - noise) - m_nOutputIntermediate = level * (2 - m_pcConnectedNoiseGenerator->Level()); - break; - } - // intermediate is between 0 and 2 -} - -inline int CSAAAmp::EffectiveAmplitude(int amp, int env) const -{ - // Return the effective amplitude of the low-pass-filtered result of the logical - // AND of the amplitude PDM and envelope PDM patterns. This is a more accurate - // evaluation of the SAA than simply returning amp * env , based on how the SAA - // implements pulse-density modulation. - static const int pdm[16][16] = { - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,2,2,2,2,2,2,2,2,4,4,4,4}, - {0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8}, - {0,1,1,2,4,5,5,6,6,7,7,8,10,11,11,12}, - {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, - {0,1,2,3,6,7,8,9,10,11,12,13,16,17,18,19}, - {0,2,3,5,6,8,9,11,12,14,15,17,18,20,21,23}, - {0,2,3,5,8,10,11,13,14,16,17,19,22,24,25,27}, - {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}, - {0,2,4,6,10,12,14,16,18,20,22,24,28,30,32,34}, - {0,3,5,8,10,13,15,18,20,23,25,28,30,33,35,38}, - {0,3,5,8,12,15,17,20,22,25,27,30,34,37,39,42}, - {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}, - {0,3,6,9,14,17,20,23,26,29,32,35,40,43,46,49}, - {0,4,7,11,14,18,21,25,28,32,35,39,42,46,49,53}, - {0,4,7,11,16,20,23,27,30,34,37,41,46,50,53,57} - }; - - return(pdm[amp][env] * 4); -} - -void CSAAAmp::TickAndOutputStereo(unsigned int & left, unsigned int & right) -{ - // This returns a value between 0 and 480 inclusive. - // This represents the full dynamic range of one output mixer (tone, or noise+tone, at full volume, - // without envelopes enabled). Note that, with envelopes enabled, the actual dynamic range - // is reduced on-chip to just over 88% of this (424), so the "loudest" output requires disabling envs. - // NB for 6 channels at full volume, with simple additive mixing, you would see a combined - // output of 2880, and a multiplier of 11 (=31680) fits comfortably within 16-bit signed output range. - - if (m_bSync) - { - // TODO check this - left = right = 0; - return; - } - - // first, do the Tick: - Tick(); - - // now calculate the returned amplitude for this sample: - //////////////////////////////////////////////////////// - - if (m_bMute) - { - left = right = 0; - } - else if (m_bUseEnvelope && m_pcConnectedEnvGenerator->IsActive()) - { - left = EffectiveAmplitude(m_pcConnectedEnvGenerator->LeftLevel(), leftlevela0x0e) * (2 - m_nOutputIntermediate); - right = EffectiveAmplitude(m_pcConnectedEnvGenerator->RightLevel(), rightlevela0x0e) * (2 - m_nOutputIntermediate); - } - else - { - left = leftlevel * m_nOutputIntermediate * 16; - right = rightlevel * m_nOutputIntermediate * 16; - } -} diff --git a/src/sound/saasound/SAAAmp.h b/src/sound/saasound/SAAAmp.h deleted file mode 100755 index 4a6761f21..000000000 --- a/src/sound/saasound/SAAAmp.h +++ /dev/null @@ -1,44 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAAmp.h: interface for the CSAAAmp class. -// This class handles Tone/Noise mixing, Envelope application and -// amplification. -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAAAMP_H_INCLUDED -#define SAAAMP_H_INCLUDED - -class CSAAAmp -{ -private: - int leftlevel; - int leftlevela0x0e; - int rightlevel; - int rightlevela0x0e; - int m_nOutputIntermediate; - unsigned int m_nMixMode; - CSAAFreq * const m_pcConnectedToneGenerator; // not const because amp calls ->Tick() - const CSAANoise * const m_pcConnectedNoiseGenerator; - const CSAAEnv * const m_pcConnectedEnvGenerator; - const bool m_bUseEnvelope; - mutable bool m_bMute; - mutable bool m_bSync; - mutable BYTE last_level_byte; - int EffectiveAmplitude(int amp, int env) const; - -public: - CSAAAmp(CSAAFreq * const ToneGenerator, const CSAANoise * const NoiseGenerator, const CSAAEnv * const EnvGenerator); - ~CSAAAmp(); - - void SetAmpLevel(BYTE level_byte); // really just a BYTE - void SetToneMixer(BYTE bEnabled); - void SetNoiseMixer(BYTE bEnabled); - void Mute(bool bMute); - void Sync(bool bSync); - void Tick(void); - void TickAndOutputStereo(unsigned int & left, unsigned int & right); - -}; - -#endif // SAAAMP_H_INCLUDED diff --git a/src/sound/saasound/SAAConfig.h b/src/sound/saasound/SAAConfig.h deleted file mode 100644 index a655ec59f..000000000 --- a/src/sound/saasound/SAAConfig.h +++ /dev/null @@ -1,41 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// SAAConfig.h: configuration file handler class -// -////////////////////////////////////////////////////////////////////// - -#include "defns.h" -#ifdef USE_CONFIG_FILE - -#ifndef SAA_CONFIG_H_INCLUDED -#define SAA_CONFIG_H_INCLUDED - -#define INI_READONLY -#define INI_ANSIONLY /*nb not really 'ANSI', this just forces all read/write to use 8-bit char*/ -#include "minIni/minIni.h" - -class SAAConfig -{ -private: - minIni m_minIni; - bool m_bHasReadConfig; - -public: - bool m_bGenerateRegisterLogs; - bool m_bGeneratePcmLogs; - bool m_bGeneratePcmSeparateChannels; - t_string m_strRegisterLogPath; - t_string m_strPcmOutputPath; - unsigned int m_nOversample; - bool m_bHighpass; - double m_nBoost; - - SAAConfig(); - void ReadConfig(); - - t_string getChannelPcmOutputPath(int); -}; - -#endif // SAA_CONFIG_H_INCLUDED - -#endif // USE_CONFIG_FILE \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.cpp b/src/sound/saasound/SAADevice.cpp deleted file mode 100644 index 718b05a95..000000000 --- a/src/sound/saasound/SAADevice.cpp +++ /dev/null @@ -1,392 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// SAADevice.cpp: connecting the subcomponents of the SAA1099 together. -// This class handles device inputs and outputs (clocking, data and -// address bus, and simulated output) -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" -#include "types.h" -#include "SAAEnv.h" -#include "SAANoise.h" -#include "SAAFreq.h" -#include "SAAAmp.h" -#include "SAASound.h" -#include "SAAImpl.h" -#include "defns.h" - - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAADevice::CSAADevice() - : - m_nCurrentSaaReg(0), - m_bOutputEnabled(false), - m_bSync(false), - m_bHighpass(true), - m_nOversample(0), - m_Noise0(0xffffffff), - m_Noise1(0xffffffff), - m_Env0(), - m_Env1(), - m_Osc0(&m_Noise0, NULL), - m_Osc1(NULL, &m_Env0), - m_Osc2(NULL, NULL), - m_Osc3(&m_Noise1, NULL), - m_Osc4(NULL, &m_Env1), - m_Osc5(NULL, NULL), - m_Amp0(&m_Osc0, &m_Noise0, NULL), - m_Amp1(&m_Osc1, &m_Noise0, NULL), - m_Amp2(&m_Osc2, &m_Noise0, &m_Env0), - m_Amp3(&m_Osc3, &m_Noise1, NULL), - m_Amp4(&m_Osc4, &m_Noise1, NULL), - m_Amp5(&m_Osc5, &m_Noise1, &m_Env1) -{ - // Create and link up the objects that make up the emulator - Noise[0] = &m_Noise0; - Noise[1] = &m_Noise1; - Env[0] = &m_Env0; - Env[1] = &m_Env1; - - // Create oscillators (tone generators) and link to noise generators and - // envelope controllers - Osc[0] = &m_Osc0; - Osc[1] = &m_Osc1; - Osc[2] = &m_Osc2; - Osc[3] = &m_Osc3; - Osc[4] = &m_Osc4; - Osc[5] = &m_Osc5; - - // Create amplification/mixing stages and link to appropriate oscillators, - // noise generators and envelope controllers - Amp[0] = &m_Amp0; - Amp[1] = &m_Amp1; - Amp[2] = &m_Amp2; - Amp[3] = &m_Amp3; - Amp[4] = &m_Amp4; - Amp[5] = &m_Amp5; - - _SetClockRate(EXTERNAL_CLK_HZ); - _SetOversample(DEFAULT_OVERSAMPLE); -} - -CSAADevice::~CSAADevice() -{ -} - -////////////////////////////////////////////////////////////////////// -// CSAASound members -////////////////////////////////////////////////////////////////////// - -void CSAADevice::_SetClockRate(unsigned int nClockRate) -{ - m_Osc0._SetClockRate(nClockRate); - m_Osc1._SetClockRate(nClockRate); - m_Osc2._SetClockRate(nClockRate); - m_Osc3._SetClockRate(nClockRate); - m_Osc4._SetClockRate(nClockRate); - m_Osc5._SetClockRate(nClockRate); - m_Noise0._SetClockRate(nClockRate); - m_Noise1._SetClockRate(nClockRate); -} - -void CSAADevice::_SetSampleRate(unsigned int nSampleRate) -{ - m_Osc0._SetSampleRate(nSampleRate); - m_Osc1._SetSampleRate(nSampleRate); - m_Osc2._SetSampleRate(nSampleRate); - m_Osc3._SetSampleRate(nSampleRate); - m_Osc4._SetSampleRate(nSampleRate); - m_Osc5._SetSampleRate(nSampleRate); - m_Noise0._SetSampleRate(nSampleRate); - m_Noise1._SetSampleRate(nSampleRate); -} - -void CSAADevice::_SetOversample(unsigned int nOversample) -{ - if (((int) nOversample) != m_nOversample) - { - m_nOversample = nOversample; - m_Osc0._SetOversample(nOversample); - m_Osc1._SetOversample(nOversample); - m_Osc2._SetOversample(nOversample); - m_Osc3._SetOversample(nOversample); - m_Osc4._SetOversample(nOversample); - m_Osc5._SetOversample(nOversample); - m_Noise0._SetOversample(nOversample); - m_Noise1._SetOversample(nOversample); - } -} - -void CSAADevice::_WriteData(BYTE nData) -{ -#if defined(DEBUG) || defined(DEBUGSAA) - m_Reg[m_nCurrentSaaReg] = nData; -#endif - - // route nData to the appropriate place - switch (m_nCurrentSaaReg) - { - // Amplitude data (==> Amp) - case 0: - m_Amp0.SetAmpLevel(nData); - break; - case 1: - m_Amp1.SetAmpLevel(nData); - break; - case 2: - m_Amp2.SetAmpLevel(nData); - break; - case 3: - m_Amp3.SetAmpLevel(nData); - break; - case 4: - m_Amp4.SetAmpLevel(nData); - break; - case 5: - m_Amp5.SetAmpLevel(nData); - break; - - // Freq data (==> Osc) - case 8: - m_Osc0.SetFreqOffset(nData); - break; - case 9: - m_Osc1.SetFreqOffset(nData); - break; - case 10: - m_Osc2.SetFreqOffset(nData); - break; - case 11: - m_Osc3.SetFreqOffset(nData); - break; - case 12: - m_Osc4.SetFreqOffset(nData); - break; - case 13: - m_Osc5.SetFreqOffset(nData); - break; - - // Freq octave data (==> Osc) for channels 0,1 - case 16: - m_Osc0.SetFreqOctave(nData & 0x07); - m_Osc1.SetFreqOctave((nData >> 4) & 0x07); - break; - - // Freq octave data (==> Osc) for channels 2,3 - case 17: - m_Osc2.SetFreqOctave(nData & 0x07); - m_Osc3.SetFreqOctave((nData >> 4) & 0x07); - break; - - // Freq octave data (==> Osc) for channels 4,5 - case 18: - m_Osc4.SetFreqOctave(nData & 0x07); - m_Osc5.SetFreqOctave((nData >> 4) & 0x07); - break; - - // Tone mixer control (==> Amp) - case 20: - m_Amp0.SetToneMixer(nData & 0x01); - m_Amp1.SetToneMixer(nData & 0x02); - m_Amp2.SetToneMixer(nData & 0x04); - m_Amp3.SetToneMixer(nData & 0x08); - m_Amp4.SetToneMixer(nData & 0x10); - m_Amp5.SetToneMixer(nData & 0x20); - break; - - // Noise mixer control (==> Amp) - case 21: - m_Amp0.SetNoiseMixer(nData & 0x01); - m_Amp1.SetNoiseMixer(nData & 0x02); - m_Amp2.SetNoiseMixer(nData & 0x04); - m_Amp3.SetNoiseMixer(nData & 0x08); - m_Amp4.SetNoiseMixer(nData & 0x10); - m_Amp5.SetNoiseMixer(nData & 0x20); - break; - - // Noise frequency/source control (==> Noise) - case 22: - m_Noise0.SetSource(nData & 0x03); - m_Noise1.SetSource((nData >> 4) & 0x03); - break; - - // Envelope control data (==> Env) for envelope controller #0 - case 24: - m_Env0.SetEnvControl(nData); - break; - - // Envelope control data (==> Env) for envelope controller #1 - case 25: - m_Env1.SetEnvControl(nData); - break; - - // Global enable and reset (sync) controls - case 28: - { - // Reset (sync) bit - bool bSync = bool(nData & 0x02); - if (bSync != m_bSync) - { - // Sync all devices - // This amounts to telling them all to reset to a - // known state, which is also a state that doesn't change - // (i.e. no audio output, although there are some exceptions) - // bSync=true => all devices are sync (aka reset); - // bSync=false => all devices are allowed to run and generate changing output - m_Osc0.Sync(bSync); - m_Osc1.Sync(bSync); - m_Osc2.Sync(bSync); - m_Osc3.Sync(bSync); - m_Osc4.Sync(bSync); - m_Osc5.Sync(bSync); - m_Noise0.Sync(bSync); - m_Noise1.Sync(bSync); - m_Amp0.Sync(bSync); - m_Amp1.Sync(bSync); - m_Amp2.Sync(bSync); - m_Amp3.Sync(bSync); - m_Amp4.Sync(bSync); - m_Amp5.Sync(bSync); - m_bSync = bSync; - } - - // Global mute bit - bool bOutputEnabled = bool(nData & 0x01); - if (bOutputEnabled != m_bOutputEnabled) - { - // unmute all amps - sound 'enabled' - m_Amp0.Mute(!bOutputEnabled); - m_Amp1.Mute(!bOutputEnabled); - m_Amp2.Mute(!bOutputEnabled); - m_Amp3.Mute(!bOutputEnabled); - m_Amp4.Mute(!bOutputEnabled); - m_Amp5.Mute(!bOutputEnabled); - m_bOutputEnabled = bOutputEnabled; - } - } - break; - - default: - // anything else means data is being written to a register - // that is not used within the SAA-1099 architecture - // hence, we ignore it. - {} - } -} - -void CSAADevice::_WriteAddress(BYTE nReg) -{ - m_nCurrentSaaReg = nReg & 31; - if (m_nCurrentSaaReg == 24) - { - m_Env0.ExternalClock(); - } - else if (m_nCurrentSaaReg == 25) - { - m_Env1.ExternalClock(); - } -} - -#if 1 -BYTE CSAADevice::_ReadAddress(void) -{ - // Not a real hardware function of the SAA-1099, which is write-only - // However, this is used by SAAImpl to generate debug logs (if enabled) - return(m_nCurrentSaaReg); -} -#endif -#if defined(DEBUG) -BYTE CSAADevice::_ReadData(void) -{ - // Not a real hardware function of the SAA-1099, which is write-only - // This is only compiled for Debug builds - return(m_Reg[m_nCurrentSaaReg]); -} -#endif - -void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed) -{ - unsigned int temp_left, temp_right; - unsigned int accum_left = 0, accum_right = 0; - for (int i = 1 << m_nOversample; i > 0; i--) - { - m_Noise0.Tick(); - m_Noise1.Tick(); - m_Amp0.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - m_Amp1.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - m_Amp2.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - m_Amp3.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - m_Amp4.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - m_Amp5.TickAndOutputStereo(temp_left, temp_right); - accum_left += temp_left; - accum_right += temp_right; - } - left_mixed = accum_left; - right_mixed = accum_right; -} - -void CSAADevice::_TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed, - unsigned int& left0, unsigned int& right0, - unsigned int& left1, unsigned int& right1, - unsigned int& left2, unsigned int& right2, - unsigned int& left3, unsigned int& right3, - unsigned int& left4, unsigned int& right4, - unsigned int& left5, unsigned int& right5 -) -{ - unsigned int temp_left, temp_right; - unsigned int accum_left = 0, accum_right = 0; - left0 = left1 = left2 = left3 = left4 = left5 = 0; - right0 = right1 = right2 = right3 = right4 = right5 = 0; - for (int i = 1 << m_nOversample; i > 0; i--) - { - m_Noise0.Tick(); - m_Noise1.Tick(); - m_Amp0.TickAndOutputStereo(temp_left, temp_right); - left0 += temp_left; - right0 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - m_Amp1.TickAndOutputStereo(temp_left, temp_right); - left1 += temp_left; - right1 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - m_Amp2.TickAndOutputStereo(temp_left, temp_right); - left2 += temp_left; - right2 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - m_Amp3.TickAndOutputStereo(temp_left, temp_right); - left3 += temp_left; - right3 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - m_Amp4.TickAndOutputStereo(temp_left, temp_right); - left4 += temp_left; - right4 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - m_Amp5.TickAndOutputStereo(temp_left, temp_right); - left5 += temp_left; - right5 += temp_right; - accum_left += temp_left; - accum_right += temp_right; - } - left_mixed = accum_left; - right_mixed = accum_right; -} \ No newline at end of file diff --git a/src/sound/saasound/SAADevice.h b/src/sound/saasound/SAADevice.h deleted file mode 100644 index 7b697821f..000000000 --- a/src/sound/saasound/SAADevice.h +++ /dev/null @@ -1,69 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// SAADevice.h: connecting the subcomponents of the SAA1099 together. -// This class handles device inputs and outputs (clocking, data and -// address bus, and simulated output) -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAADEVICE_H_INCLUDED -#define SAADEVICE_H_INCLUDED - -#include "SAASound.h" -#include "SAANoise.h" -#include "SAAEnv.h" -#include "SAAFreq.h" -#include "SAAAmp.h" - -class CSAADevice -{ -private: - int m_nCurrentSaaReg; - bool m_bOutputEnabled; - bool m_bSync; - bool m_bHighpass; - int m_nOversample; - - CSAANoise m_Noise0, m_Noise1; - CSAAEnv m_Env0, m_Env1; - CSAAFreq m_Osc0, m_Osc1, m_Osc2, m_Osc3, m_Osc4, m_Osc5; - CSAAAmp m_Amp0, m_Amp1, m_Amp2, m_Amp3, m_Amp4, m_Amp5; - - CSAANoise* Noise[2]; - CSAAEnv* Env[2]; - CSAAFreq* Osc[6]; - CSAAAmp* Amp[6]; - -#if defined(DEBUG) || defined(DEBUGSAA) - BYTE m_Reg[32]; -#endif - -public: - CSAADevice(); - ~CSAADevice(); - - void _WriteAddress(BYTE nReg); - void _WriteData(BYTE nData); -#if 1 - BYTE _ReadAddress(void); -#endif -#if defined(DEBUG) - BYTE _ReadData(void); -#endif - - void _SetClockRate(unsigned int nClockRate); - void _SetSampleRate(unsigned int nSampleRate); - void _SetOversample(unsigned int nOversample); - void _TickAndOutputStereo(unsigned int& left_mixed, unsigned int& right_mixed); - void _TickAndOutputSeparate(unsigned int& left_mixed, unsigned int& right_mixed, - unsigned int& left0, unsigned int& right0, - unsigned int& left1, unsigned int& right1, - unsigned int& left2, unsigned int& right2, - unsigned int& left3, unsigned int& right3, - unsigned int& left4, unsigned int& right4, - unsigned int& left5, unsigned int& right5 - ); - -}; - -#endif // SAADEVICE_H_INCLUDED \ No newline at end of file diff --git a/src/sound/saasound/SAAEnv.cpp b/src/sound/saasound/SAAEnv.cpp deleted file mode 100755 index 049f51f96..000000000 --- a/src/sound/saasound/SAAEnv.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAEnv.cpp: implementation of the CSAAEnv class. -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" -#include "types.h" -#include "SAAEnv.h" - - -////////////////////////////////////////////////////////////////////// -// Static member initialisation -////////////////////////////////////////////////////////////////////// - -const ENVDATA CSAAEnv::cs_EnvData[8] = -{ - {1,false, { {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, - {1,true, { {{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15}}, - {{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14},{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14}}}}, - {1,false, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, - {{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, - {1,true, { {{15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, - {{14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, - {2,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}}, - {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}}, - {2,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}}, - {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,0}}}}, - {1,false, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, - {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}, - {1,true, { {{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}, - {{0,0,2,2,4,4,6,6,8,8,10,10,12,12,14,14}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}}} -}; - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAAEnv::CSAAEnv() -: -m_bEnabled(false), -m_nPhase(0), -m_nPhasePosition(0), -m_bEnvelopeEnded(true), -m_nResolution(1), -m_bNewData(false), -m_nNextData(0) -{ - // initialise itself with the value 'zero' - SetEnvControl(0); -} - -CSAAEnv::~CSAAEnv() -{ - // Nothing to do -} - -void CSAAEnv::InternalClock(void) -{ - // will only do something if envelope clock mode is set to internal - // and the env control is enabled - if (m_bEnabled && (!m_bClockExternally)) Tick(); -} - -void CSAAEnv::ExternalClock(void) -{ - // will only do something if envelope clock mode is set to external - // and the env control is enabled - if (m_bClockExternally && m_bEnabled) Tick(); -} - -void CSAAEnv::SetEnvControl(int nData) -{ - // process immediate stuff first: - // start with the Enabled flag. if env is disabled, - // there's not much to do - bool bEnabled = ((nData & 0x80)==0x80); - if (!bEnabled && !m_bEnabled) - return; - m_bEnabled = bEnabled; - if (!m_bEnabled) - { - // env control was enabled, and now disabled - // Any subsequent env control changes are immediate. - m_bEnvelopeEnded = true; - return; - } - - // Resolution (3bit/4bit) is also immediately processed - int new_resolution = ((nData & 0x10) == 0x10) ? 2 : 1; - // NOTE: undocumented behaviour when changing resolution mid-waveform - // Empirically, the following matches observations: - // * When ticking the env generator with 4-bit resolution, the position += 1 - // * When ticking the env generator with 3-bit resolution, the position += 2 - // * When changing between 4-bit resolution and 3-bit resolution - // without ticking the env generator, the position is unchanged - // (although, effectively, the LSB is ignored. Purely as an implementation - // detail, I'm implementing this as clearing the LSB ie LSB=0; see next point) - // * When changing between 3-bit resolution and 4-bit resolution - // without ticking the env generator, the position LSB is set to 1 - // See test case: envext_34b - // - if (m_nResolution == 1 && new_resolution == 2) - { - // change from 4-bit to 3-bit - m_nPhasePosition &= 0xe; - } - else if (m_nResolution == 2 && new_resolution == 1) - { - // change from 3-bit to 4-bit - m_nPhasePosition |= 0x1; - } - m_nResolution = new_resolution; - - // now buffered stuff: but only if it's ok to, and only if the - // envgenerator is not disabled. otherwise it just stays buffered until - // the Tick() function sets m_bEnvelopeEnded to true and realises there is - // already some new data waiting - if (m_bEnvelopeEnded) - { - SetNewEnvData(nData); // also does the SetLevels() call for us. - m_bNewData=false; - } - else - { - // since the 'next resolution' changes arrive unbuffered, we - // may need to change the current level because of this: - SetLevels(); - - // store current new data, and set the newdata flag: - m_bNewData = true; - m_nNextData = nData; - } - -} - -int CSAAEnv::LeftLevel(void) const -{ - return m_nLeftLevel; -} - -int CSAAEnv::RightLevel(void) const -{ - return m_nRightLevel; -} - -inline void CSAAEnv::Tick(void) -{ - // if disabled, do nothing - if (!m_bEnabled) // m_bEnabled is set directly, not buffered, so this is ok - { - // for sanity, reset stuff: - m_bEnvelopeEnded = true; - m_nPhase = 0; - m_nPhasePosition = 0; - return; - } - - // else : m_bEnabled - - - if (m_bEnvelopeEnded) - { - // do nothing - // (specifically, don't change the values of m_bEnvelopeEnded, - // m_nPhase and m_nPhasePosition, as these will still be needed - // by SetLevels() should it be called again) - - return; - } - - - // else : !m_bEnvelopeEnded - // Continue playing the same envelope ... - // increments the phaseposition within an envelope. - // also handles looping and resolution appropriately. - // Changes the level of the envelope accordingly - // through calling SetLevels() . This must be called after making - // any changes that will affect the output levels of the env controller!! - // SetLevels also handles left-right channel inverting - - // increment phase position - m_nPhasePosition += m_nResolution; - - // if this means we've gone past 16 (the end of a phase) - // then change phase, and if necessary, loop - // Refer to datasheet for meanings of (3) and (4) in following text - // w.r.t SAA1099 envelopes - - // Note that we will always reach position (3) or (4), even if we keep toggling - // resolution from 4-bit to 3-bit and back, because the counter will always wrap to 0. - // In fact it's quite elegant: - // No matter how you increment and toggle and increment and toggle, the counter - // will at some point be either 0xe (either 4-bit mode or 3-bit mode) or 0xf (4-bit mode only). - // Depending on the mode, even if you change the mode, the next increment, - // or the one after it, will then take it to 0. - // 0xe + 2 (3bit mode) => 0x0 - // 0xe + 1 (4bit mode) => 0xf - // 0xf + 1 (4bit mode) => 0x0 - // 0xe -> (toggle 3bit mode to 4bit mode) => 0xf - // 0xe -> (toggle 4bit mode to 3bit mode) => 0xe - // 0xf -> (toggle 4bit mode to 3bit mode) => 0xe - // - // but there is a subtlety (of course), which is that any changes at point (3) - // can take place immediately you hit point (3), but changes at point (4) are actually - // only acted upon when the counter transitions from 0xe (or 0xf) to 0x0 (which also - // means that, for these looping envelopes, which are the ones that have a point(4), - // immediately after the counter wrapping to 0x0, a write to the env data register will - // NOT set the waveform and will NOT reset the phase/phaseposition (even though it - // will still let you toggle the 4bit/3bit mode, which will change the phaseposition LSB!) - // See test case: envext_34c - - bool bProcessNewDataIfAvailable = false; - if (m_nPhasePosition >= 16) - { - m_nPhase++; - - // if we should loop, then do so - and we've reached position (4) - // otherwise, if we shouldn't loop, - // then we've reached position (3) and so we say that - // we're ok for new data. - if (m_nPhase == m_nNumberOfPhases) - { - // at position (3) or (4) - if (!m_bLooping) - { - // position (3) only - // note that it seems that the sustain level is ALWAYS zero - // in the case of non-looping waveforms - m_bEnvelopeEnded = true; - bProcessNewDataIfAvailable = true; - } - else - { - // position (4) only - // note that any data already latched is ONLY acted upon - // at THIS point. If (after this Tick has completed) any new - // env data is written, it will NOT be acted upon, until - // we get back to position (4) again. - // this is why m_bEnvelopeEnded (which affects the behaviour - // of the SetEnvControl method) is FALSE here. - // See test case: envext_34c (as noted earlier) - m_bEnvelopeEnded = false; - // set phase pointer to start of envelope for loop - // and reset m_nPhasePosition - m_nPhase=0; - m_nPhasePosition -= 16; - bProcessNewDataIfAvailable = true; - } - } - else // (m_nPhase < m_nNumberOfPhases) - { - // not at position (3) or (4) ... - // (i.e., we're in the middle of an envelope with - // more than one phase. Specifically, we're in - // the middle of envelope 4 or 5 - the - // triangle envelopes - but that's not important) - - // any commands sent to this envelope controller - // will be buffered. Set the flag to indicate this. - m_bEnvelopeEnded = false; - m_nPhasePosition -= 16; - } - } - else // (m_nPhasePosition < 16) - { - // still within the same phase; - // but, importantly, we are no longer at the start of the phase ... - // so new data cannot be acted on immediately, and must - // be buffered - m_bEnvelopeEnded = false; - // Phase and PhasePosition have already been updated. - // SetLevels() will need to be called to actually calculate - // the output 'level' of this envelope controller - } - - - // if we have new (buffered) data, now is the time to act on it - if (m_bNewData && bProcessNewDataIfAvailable) - { - m_bNewData = false; - SetNewEnvData(m_nNextData); - } - else - { - // ok, we didn't have any new buffered date to act on, - // so we just call SetLevels() to calculate the output level - // for whatever the current envelope is - SetLevels(); - } - -} - -inline void CSAAEnv::SetLevels(void) -{ - // sets m_nLeftLevel - // Also sets m_nRightLevel in terms of m_nLeftLevel - // and m_bInvertRightChannel - - // m_nResolution: 1 means 4-bit resolution; 2 means 3-bit resolution. Resolution of envelope waveform. - - // Note that this is handled 'immediately', and doesn't wait for synchronisation of - // the envelope waveform (this is important, see test case EnvExt_imm) - // It is therefore possible to switch between 4-bit and 3-bit resolution in the middle of - // an envelope waveform. if you are at an 'odd' phase position, you would be able to hear - // the difference. if you are at an 'even' phase position, the volume level for 4-bit - // and 3-bit would be the same. - // NOTE: additional test cases are required. - - switch (m_nResolution) - { - case 1: // 4 bit res waveforms - default: - { - // special case: if envelope is not a looping one, and we're at the end - // then our level should be zero (all of the non-looping waveforms have - // a sustain level of zero): - if (m_bEnvelopeEnded && !m_bLooping) - m_nLeftLevel = 0; - else - m_nLeftLevel = m_pEnvData->nLevels[0][m_nPhase][m_nPhasePosition]; - - if (m_bInvertRightChannel) - m_nRightLevel = 15-m_nLeftLevel; - else - m_nRightLevel = m_nLeftLevel; - break; - } - case 2: // 3 bit res waveforms - { - // special case: if envelope is not a looping one, and we're at the end - // then our level should be zero (all of the non-looping waveforms have - // a sustain level of zero): - if (m_bEnvelopeEnded && !m_bLooping) - m_nLeftLevel = 0; - else - m_nLeftLevel = m_pEnvData->nLevels[1][m_nPhase][m_nPhasePosition]; - if (m_bInvertRightChannel) - m_nRightLevel = 14-m_nLeftLevel; - else - m_nRightLevel = m_nLeftLevel; - break; - } - } -} - - -inline void CSAAEnv::SetNewEnvData(int nData) -{ - // loads envgenerator's registers according to the bits set - // in nData - - m_nPhase = 0; - m_nPhasePosition = 0; - m_pEnvData = &(cs_EnvData[(nData >> 1) & 0x07]); - m_bInvertRightChannel = ((nData & 0x01) == 0x01); - m_bClockExternally = ((nData & 0x20) == 0x20); - m_nNumberOfPhases = m_pEnvData->nNumberOfPhases; - m_bLooping = m_pEnvData->bLooping; - m_nResolution = (((nData & 0x10)==0x10) ? 2 : 1); - m_bEnabled = ((nData & 0x80) == 0x80); - if (m_bEnabled) - { - m_bEnvelopeEnded = false; - // is this right? - // YES. See test case EnvExt_34c (setting data multiple times - // when at a point (3) resets the waveform so you're no longer - // at a point (3). - } - else - { - // DISABLED - so set stuff accordingly - m_bEnvelopeEnded = true; - m_nPhase = 0; - m_nPhasePosition = 0; - } - - SetLevels(); -} diff --git a/src/sound/saasound/SAAEnv.h b/src/sound/saasound/SAAEnv.h deleted file mode 100755 index 131659c06..000000000 --- a/src/sound/saasound/SAAEnv.h +++ /dev/null @@ -1,54 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAEnv.h: interface for the CSAAEnv class. -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAAENV_H_INCLUDED -#define SAAENV_H_INCLUDED - -class CSAAEnv -{ -private: - int m_nLeftLevel, m_nRightLevel; - ENVDATA const * m_pEnvData; - - bool m_bEnabled; - bool m_bInvertRightChannel; - BYTE m_nPhase; - BYTE m_nPhasePosition; - bool m_bEnvelopeEnded; - char m_nPhaseAdd[2]; - char m_nCurrentPhaseAdd; - bool m_bLooping; - char m_nNumberOfPhases; - char m_nResolution; - char m_nInitialLevel; - bool m_bNewData; - BYTE m_nNextData; - bool m_bClockExternally; - static const ENVDATA cs_EnvData[8]; - - void Tick(void); - void SetLevels(void); - void SetNewEnvData(int nData); - -public: - CSAAEnv(); - ~CSAAEnv(); - - void InternalClock(void); - void ExternalClock(void); - void SetEnvControl(int nData); // really just a BYTE - int LeftLevel(void) const; - int RightLevel(void) const; - bool IsActive(void) const; - -}; - -inline bool CSAAEnv::IsActive(void) const -{ - return m_bEnabled; -} - -#endif // SAAENV_H_INCLUDED diff --git a/src/sound/saasound/SAAFreq.cpp b/src/sound/saasound/SAAFreq.cpp deleted file mode 100755 index 61a04f6ad..000000000 --- a/src/sound/saasound/SAAFreq.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAFreq.cpp: implementation of the CSAAFreq class. -// only 7-bit fractional accuracy on oscillator periods. I may consider fixing that. -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" -#include "types.h" -#include "SAANoise.h" -#include "SAAEnv.h" -#include "SAAFreq.h" -#include "defns.h" - -#ifdef SAAFREQ_FIXED_CLOCKRATE -// 'load in' the data for the static frequency lookup table -// precomputed for a fixed clockrate -// See: tools/freqdat.py -const unsigned long CSAAFreq::m_FreqTable[2048] = { -#include "SAAFreq.dat" -}; -#else -unsigned long CSAAFreq::m_FreqTable[2048]; -unsigned long CSAAFreq::m_nClockRate = 0; -#endif // SAAFREQ_FIXED_CLOCKRATE - -const int INITIAL_LEVEL = 1; - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAAFreq::CSAAFreq(CSAANoise * const NoiseGenerator, CSAAEnv * const EnvGenerator) -: -m_nCounter(0), -m_nAdd(0), -m_nCounter_low(0), -m_nOversample(0), -m_nCounterLimit_low(1), -m_nLevel(INITIAL_LEVEL), -m_nCurrentOffset(0), -m_nCurrentOctave(0), -m_nNextOffset(0), -m_nNextOctave(0), -m_bIgnoreOffsetData(false), -m_bNewData(false), -m_bSync(false), -m_nSampleRate(SAMPLE_RATE_HZ), -m_pcConnectedNoiseGenerator(NoiseGenerator), -m_pcConnectedEnvGenerator(EnvGenerator), -m_nConnectedMode((NoiseGenerator == NULL) ? ((EnvGenerator == NULL) ? 0 : 1) : 2) -{ - _SetClockRate(EXTERNAL_CLK_HZ); - SetAdd(); // current octave, current offset -} - -CSAAFreq::~CSAAFreq() -{ - // Nothing to do -} - -void CSAAFreq::SetFreqOffset(BYTE nOffset) -{ - // nOffset between 0 and 255 - - if (!m_bSync) - { - m_nNextOffset = nOffset; - m_bNewData=true; - if (m_nNextOctave==m_nCurrentOctave) - { - // According to Philips, if you send the SAA-1099 - // new Octave data and then new Offset data in that - // order, on the next half-cycle of the current frequency - // generator, ONLY the octave data is acted upon. - // The offset data will be acted upon next time. - - // ?? TEST CASE : if you set the octave and then the offset - // but the octave you set it to is the same one it already was. - // Will this ignore the offset data? - // Do you get the same behaviour if you set offset THEN octave - // even if you set octave to the same value it was before? - - m_bIgnoreOffsetData=true; - } - } - else - { - // updates straightaway if m_bSync - m_bNewData=false; - m_bIgnoreOffsetData = false; - m_nCurrentOffset = nOffset; - m_nNextOffset = nOffset; - m_nCurrentOctave = m_nNextOctave; - SetAdd(); - } - -} - -void CSAAFreq::SetFreqOctave(BYTE nOctave) -{ - // nOctave between 0 and 7 - - if (!m_bSync) - { - m_nNextOctave = nOctave; - m_bNewData=true; - m_bIgnoreOffsetData = false; - } - else - { - // updates straightaway if m_bSync - m_bNewData=false; - m_bIgnoreOffsetData = false; - m_nCurrentOctave = nOctave; - m_nNextOctave = nOctave; - m_nCurrentOffset = m_nNextOffset; - SetAdd(); - } -} - -void CSAAFreq::UpdateOctaveOffsetData(void) -{ - // loads the buffered new octave and new offset data into the current registers - // and sets up the new frequency for this frequency generator (i.e. sets up m_nAdd) - // - called during Sync, and called when waveform half-cycle completes - - // How the SAA-1099 really treats new data: - // if only new octave data is present, - // then set new period based on just the octave data - // Otherwise, if only new offset data is present, - // then set new period based on just the offset data - // Otherwise, if new octave data is present, and new offset data is present, - // and the offset data was set BEFORE the octave data, - // then set new period based on both the octave and offset data - // Else, if the offset data came AFTER the new octave data - // then set new period based on JUST THE OCTAVE DATA, and continue - // signalling the offset data as 'new', so it will be acted upon - // next half-cycle - // - // Weird, I know. But that's how it works. Philips even documented as much. - - if (!m_bNewData) - { - // optimise for the most common case! No new data! - return; - } - - m_nCurrentOctave=m_nNextOctave; - if (!m_bIgnoreOffsetData) - { - m_nCurrentOffset=m_nNextOffset; - m_bNewData=false; - } - m_bIgnoreOffsetData=false; - - SetAdd(); -} - -void CSAAFreq::_SetSampleRate(unsigned int nSampleRate) -{ - m_nSampleRate = nSampleRate; -} - -void CSAAFreq::_SetOversample(unsigned int oversample) -{ - // oversample is a power of 2 i.e. - // if oversample == 2 then 4x oversample - // if oversample == 6 then 64x oversample - if (oversample < m_nOversample) - { - m_nCounter_low <<= (m_nOversample - oversample); - } - else - { - m_nCounter_low >>= (oversample - m_nOversample); - } - - m_nCounterLimit_low = 1<= (m_nSampleRate<<12)) - { - m_nCounter -= (m_nSampleRate<<12); - m_nCounter_low++; - if (m_nCounter_low >= m_nCounterLimit_low) - { - // period elapsed for (at least) one half-cycle of - // current frequency - m_nCounter_low = 0; - // flip state - from 0 to 1 or vice versa - m_nLevel = 1 - m_nLevel; - - // trigger any connected devices - switch (m_nConnectedMode) - { - case 1: - // env trigger - m_pcConnectedEnvGenerator->InternalClock(); - break; - - case 2: - // noise trigger - m_pcConnectedNoiseGenerator->Trigger(); - break; - - default: - // do nothing - break; - } - - // get new frequency (set period length m_nAdd) if new data is waiting: - UpdateOctaveOffsetData(); - } - } - - return m_nLevel; -} - -void CSAAFreq::SetAdd(void) -{ - // nOctave between 0 and 7; nOffset between 0 and 255 - - // Used to be: - // m_nAdd = (15625 << nOctave) / (511 - nOffset); - // Now just table lookup: - m_nAdd = m_FreqTable[m_nCurrentOctave<<8 | m_nCurrentOffset]; -} - -void CSAAFreq::Sync(bool bSync) -{ - m_bSync = bSync; - - // update straightaway if m_bSync - if (m_bSync) - { - m_nCounter = 0; - m_nCounter_low = 0; - - // this seems to need to be required to make the Fred59 SPACE DEMO audio work correctly - m_nLevel = INITIAL_LEVEL; - - m_nCurrentOctave=m_nNextOctave; - m_nCurrentOffset=m_nNextOffset; - SetAdd(); - } -} diff --git a/src/sound/saasound/SAAFreq.dat b/src/sound/saasound/SAAFreq.dat deleted file mode 100755 index 04fb9081a..000000000 --- a/src/sound/saasound/SAAFreq.dat +++ /dev/null @@ -1,141 +0,0 @@ -/* -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// Precalculated oscillator frequency period steps -// Higher scaling for better accuracy. -// -// After construction, it's important to SetSampleRate before -// trying to use the generator. -// (Just because the CSAANoise object has a default samplerate -// doesn't mean you should rely on it) -// -////////////////////////////////////////////////////////////////////// -*/ - 250489 , 250980 , 251473 , 251969 , 252465 , 252964 , 253465 , 253968 , 254473 , 254980 , 255489 , 256000 , 256513 , 257028 , 257545 , 258065 , - 258586 , 259109 , 259635 , 260163 , 260692 , 261224 , 261759 , 262295 , 262834 , 263374 , 263918 , 264463 , 265010 , 265560 , 266112 , 266667 , - 267223 , 267782 , 268344 , 268908 , 269474 , 270042 , 270613 , 271186 , 271762 , 272340 , 272921 , 273504 , 274090 , 274678 , 275269 , 275862 , - 276458 , 277056 , 277657 , 278261 , 278867 , 279476 , 280088 , 280702 , 281319 , 281938 , 282561 , 283186 , 283814 , 284444 , 285078 , 285714 , - 286353 , 286996 , 287640 , 288288 , 288939 , 289593 , 290249 , 290909 , 291572 , 292237 , 292906 , 293578 , 294253 , 294931 , 295612 , 296296 , - 296984 , 297674 , 298368 , 299065 , 299766 , 300469 , 301176 , 301887 , 302600 , 303318 , 304038 , 304762 , 305489 , 306220 , 306954 , 307692 , - 308434 , 309179 , 309927 , 310680 , 311436 , 312195 , 312958 , 313725 , 314496 , 315271 , 316049 , 316832 , 317618 , 318408 , 319202 , 320000 , - 320802 , 321608 , 322418 , 323232 , 324051 , 324873 , 325700 , 326531 , 327366 , 328205 , 329049 , 329897 , 330749 , 331606 , 332468 , 333333 , - 334204 , 335079 , 335958 , 336842 , 337731 , 338624 , 339523 , 340426 , 341333 , 342246 , 343164 , 344086 , 345013 , 345946 , 346883 , 347826 , - 348774 , 349727 , 350685 , 351648 , 352617 , 353591 , 354571 , 355556 , 356546 , 357542 , 358543 , 359551 , 360563 , 361582 , 362606 , 363636 , - 364672 , 365714 , 366762 , 367816 , 368876 , 369942 , 371014 , 372093 , 373178 , 374269 , 375367 , 376471 , 377581 , 378698 , 379822 , 380952 , - 382090 , 383234 , 384384 , 385542 , 386707 , 387879 , 389058 , 390244 , 391437 , 392638 , 393846 , 395062 , 396285 , 397516 , 398754 , 400000 , - 401254 , 402516 , 403785 , 405063 , 406349 , 407643 , 408946 , 410256 , 411576 , 412903 , 414239 , 415584 , 416938 , 418301 , 419672 , 421053 , - 422442 , 423841 , 425249 , 426667 , 428094 , 429530 , 430976 , 432432 , 433898 , 435374 , 436860 , 438356 , 439863 , 441379 , 442907 , 444444 , - 445993 , 447552 , 449123 , 450704 , 452297 , 453901 , 455516 , 457143 , 458781 , 460432 , 462094 , 463768 , 465455 , 467153 , 468864 , 470588 , - 472325 , 474074 , 475836 , 477612 , 479401 , 481203 , 483019 , 484848 , 486692 , 488550 , 490421 , 492308 , 494208 , 496124 , 498054 , 500000 , - 500978 , 501961 , 502947 , 503937 , 504931 , 505929 , 506931 , 507937 , 508946 , 509960 , 510978 , 512000 , 513026 , 514056 , 515091 , 516129 , - 517172 , 518219 , 519270 , 520325 , 521385 , 522449 , 523517 , 524590 , 525667 , 526749 , 527835 , 528926 , 530021 , 531120 , 532225 , 533333 , - 534447 , 535565 , 536688 , 537815 , 538947 , 540084 , 541226 , 542373 , 543524 , 544681 , 545842 , 547009 , 548180 , 549356 , 550538 , 551724 , - 552916 , 554113 , 555315 , 556522 , 557734 , 558952 , 560175 , 561404 , 562637 , 563877 , 565121 , 566372 , 567627 , 568889 , 570156 , 571429 , - 572707 , 573991 , 575281 , 576577 , 577878 , 579186 , 580499 , 581818 , 583144 , 584475 , 585812 , 587156 , 588506 , 589862 , 591224 , 592593 , - 593968 , 595349 , 596737 , 598131 , 599532 , 600939 , 602353 , 603774 , 605201 , 606635 , 608076 , 609524 , 610979 , 612440 , 613909 , 615385 , - 616867 , 618357 , 619855 , 621359 , 622871 , 624390 , 625917 , 627451 , 628993 , 630542 , 632099 , 633663 , 635236 , 636816 , 638404 , 640000 , - 641604 , 643216 , 644836 , 646465 , 648101 , 649746 , 651399 , 653061 , 654731 , 656410 , 658098 , 659794 , 661499 , 663212 , 664935 , 666667 , - 668407 , 670157 , 671916 , 673684 , 675462 , 677249 , 679045 , 680851 , 682667 , 684492 , 686327 , 688172 , 690027 , 691892 , 693767 , 695652 , - 697548 , 699454 , 701370 , 703297 , 705234 , 707182 , 709141 , 711111 , 713092 , 715084 , 717087 , 719101 , 721127 , 723164 , 725212 , 727273 , - 729345 , 731429 , 733524 , 735632 , 737752 , 739884 , 742029 , 744186 , 746356 , 748538 , 750733 , 752941 , 755162 , 757396 , 759644 , 761905 , - 764179 , 766467 , 768769 , 771084 , 773414 , 775758 , 778116 , 780488 , 782875 , 785276 , 787692 , 790123 , 792570 , 795031 , 797508 , 800000 , - 802508 , 805031 , 807571 , 810127 , 812698 , 815287 , 817891 , 820513 , 823151 , 825806 , 828479 , 831169 , 833876 , 836601 , 839344 , 842105 , - 844884 , 847682 , 850498 , 853333 , 856187 , 859060 , 861953 , 864865 , 867797 , 870748 , 873720 , 876712 , 879725 , 882759 , 885813 , 888889 , - 891986 , 895105 , 898246 , 901408 , 904594 , 907801 , 911032 , 914286 , 917563 , 920863 , 924188 , 927536 , 930909 , 934307 , 937729 , 941176 , - 944649 , 948148 , 951673 , 955224 , 958801 , 962406 , 966038 , 969697 , 973384 , 977099 , 980843 , 984615 , 988417 , 992248 , 996109 , 1000000 , - 1001957 , 1003922 , 1005894 , 1007874 , 1009862 , 1011858 , 1013861 , 1015873 , 1017893 , 1019920 , 1021956 , 1024000 , 1026052 , 1028112 , 1030181 , 1032258 , - 1034343 , 1036437 , 1038540 , 1040650 , 1042770 , 1044898 , 1047035 , 1049180 , 1051335 , 1053498 , 1055670 , 1057851 , 1060041 , 1062241 , 1064449 , 1066667 , - 1068894 , 1071130 , 1073375 , 1075630 , 1077895 , 1080169 , 1082452 , 1084746 , 1087049 , 1089362 , 1091684 , 1094017 , 1096360 , 1098712 , 1101075 , 1103448 , - 1105832 , 1108225 , 1110629 , 1113043 , 1115468 , 1117904 , 1120350 , 1122807 , 1125275 , 1127753 , 1130243 , 1132743 , 1135255 , 1137778 , 1140312 , 1142857 , - 1145414 , 1147982 , 1150562 , 1153153 , 1155756 , 1158371 , 1160998 , 1163636 , 1166287 , 1168950 , 1171625 , 1174312 , 1177011 , 1179724 , 1182448 , 1185185 , - 1187935 , 1190698 , 1193473 , 1196262 , 1199063 , 1201878 , 1204706 , 1207547 , 1210402 , 1213270 , 1216152 , 1219048 , 1221957 , 1224880 , 1227818 , 1230769 , - 1233735 , 1236715 , 1239709 , 1242718 , 1245742 , 1248780 , 1251834 , 1254902 , 1257985 , 1261084 , 1264198 , 1267327 , 1270471 , 1273632 , 1276808 , 1280000 , - 1283208 , 1286432 , 1289673 , 1292929 , 1296203 , 1299492 , 1302799 , 1306122 , 1309463 , 1312821 , 1316195 , 1319588 , 1322997 , 1326425 , 1329870 , 1333333 , - 1336815 , 1340314 , 1343832 , 1347368 , 1350923 , 1354497 , 1358090 , 1361702 , 1365333 , 1368984 , 1372654 , 1376344 , 1380054 , 1383784 , 1387534 , 1391304 , - 1395095 , 1398907 , 1402740 , 1406593 , 1410468 , 1414365 , 1418283 , 1422222 , 1426184 , 1430168 , 1434174 , 1438202 , 1442254 , 1446328 , 1450425 , 1454545 , - 1458689 , 1462857 , 1467049 , 1471264 , 1475504 , 1479769 , 1484058 , 1488372 , 1492711 , 1497076 , 1501466 , 1505882 , 1510324 , 1514793 , 1519288 , 1523810 , - 1528358 , 1532934 , 1537538 , 1542169 , 1546828 , 1551515 , 1556231 , 1560976 , 1565749 , 1570552 , 1575385 , 1580247 , 1585139 , 1590062 , 1595016 , 1600000 , - 1605016 , 1610063 , 1615142 , 1620253 , 1625397 , 1630573 , 1635783 , 1641026 , 1646302 , 1651613 , 1656958 , 1662338 , 1667752 , 1673203 , 1678689 , 1684211 , - 1689769 , 1695364 , 1700997 , 1706667 , 1712375 , 1718121 , 1723906 , 1729730 , 1735593 , 1741497 , 1747440 , 1753425 , 1759450 , 1765517 , 1771626 , 1777778 , - 1783972 , 1790210 , 1796491 , 1802817 , 1809187 , 1815603 , 1822064 , 1828571 , 1835125 , 1841727 , 1848375 , 1855072 , 1861818 , 1868613 , 1875458 , 1882353 , - 1889299 , 1896296 , 1903346 , 1910448 , 1917603 , 1924812 , 1932075 , 1939394 , 1946768 , 1954198 , 1961686 , 1969231 , 1976834 , 1984496 , 1992218 , 2000000 , - 2003914 , 2007843 , 2011788 , 2015748 , 2019724 , 2023715 , 2027723 , 2031746 , 2035785 , 2039841 , 2043912 , 2048000 , 2052104 , 2056225 , 2060362 , 2064516 , - 2068687 , 2072874 , 2077079 , 2081301 , 2085540 , 2089796 , 2094070 , 2098361 , 2102669 , 2106996 , 2111340 , 2115702 , 2120083 , 2124481 , 2128898 , 2133333 , - 2137787 , 2142259 , 2146751 , 2151261 , 2155789 , 2160338 , 2164905 , 2169492 , 2174098 , 2178723 , 2183369 , 2188034 , 2192719 , 2197425 , 2202151 , 2206897 , - 2211663 , 2216450 , 2221258 , 2226087 , 2230937 , 2235808 , 2240700 , 2245614 , 2250549 , 2255507 , 2260486 , 2265487 , 2270510 , 2275556 , 2280624 , 2285714 , - 2290828 , 2295964 , 2301124 , 2306306 , 2311512 , 2316742 , 2321995 , 2327273 , 2332574 , 2337900 , 2343249 , 2348624 , 2354023 , 2359447 , 2364896 , 2370370 , - 2375870 , 2381395 , 2386946 , 2392523 , 2398126 , 2403756 , 2409412 , 2415094 , 2420804 , 2426540 , 2432304 , 2438095 , 2443914 , 2449761 , 2455635 , 2461538 , - 2467470 , 2473430 , 2479419 , 2485437 , 2491484 , 2497561 , 2503667 , 2509804 , 2515971 , 2522167 , 2528395 , 2534653 , 2540943 , 2547264 , 2553616 , 2560000 , - 2566416 , 2572864 , 2579345 , 2585859 , 2592405 , 2598985 , 2605598 , 2612245 , 2618926 , 2625641 , 2632391 , 2639175 , 2645995 , 2652850 , 2659740 , 2666667 , - 2673629 , 2680628 , 2687664 , 2694737 , 2701847 , 2708995 , 2716180 , 2723404 , 2730667 , 2737968 , 2745308 , 2752688 , 2760108 , 2767568 , 2775068 , 2782609 , - 2790191 , 2797814 , 2805479 , 2813187 , 2820937 , 2828729 , 2836565 , 2844444 , 2852368 , 2860335 , 2868347 , 2876404 , 2884507 , 2892655 , 2900850 , 2909091 , - 2917379 , 2925714 , 2934097 , 2942529 , 2951009 , 2959538 , 2968116 , 2976744 , 2985423 , 2994152 , 3002933 , 3011765 , 3020649 , 3029586 , 3038576 , 3047619 , - 3056716 , 3065868 , 3075075 , 3084337 , 3093656 , 3103030 , 3112462 , 3121951 , 3131498 , 3141104 , 3150769 , 3160494 , 3170279 , 3180124 , 3190031 , 3200000 , - 3210031 , 3220126 , 3230284 , 3240506 , 3250794 , 3261146 , 3271565 , 3282051 , 3292605 , 3303226 , 3313916 , 3324675 , 3335505 , 3346405 , 3357377 , 3368421 , - 3379538 , 3390728 , 3401993 , 3413333 , 3424749 , 3436242 , 3447811 , 3459459 , 3471186 , 3482993 , 3494881 , 3506849 , 3518900 , 3531034 , 3543253 , 3555556 , - 3567944 , 3580420 , 3592982 , 3605634 , 3618375 , 3631206 , 3644128 , 3657143 , 3670251 , 3683453 , 3696751 , 3710145 , 3723636 , 3737226 , 3750916 , 3764706 , - 3778598 , 3792593 , 3806691 , 3820896 , 3835206 , 3849624 , 3864151 , 3878788 , 3893536 , 3908397 , 3923372 , 3938462 , 3953668 , 3968992 , 3984436 , 4000000 , - 4007828 , 4015686 , 4023576 , 4031496 , 4039448 , 4047431 , 4055446 , 4063492 , 4071571 , 4079681 , 4087824 , 4096000 , 4104208 , 4112450 , 4120724 , 4129032 , - 4137374 , 4145749 , 4154158 , 4162602 , 4171079 , 4179592 , 4188139 , 4196721 , 4205339 , 4213992 , 4222680 , 4231405 , 4240166 , 4248963 , 4257796 , 4266667 , - 4275574 , 4284519 , 4293501 , 4302521 , 4311579 , 4320675 , 4329810 , 4338983 , 4348195 , 4357447 , 4366738 , 4376068 , 4385439 , 4394850 , 4404301 , 4413793 , - 4423326 , 4432900 , 4442516 , 4452174 , 4461874 , 4471616 , 4481400 , 4491228 , 4501099 , 4511013 , 4520971 , 4530973 , 4541020 , 4551111 , 4561247 , 4571429 , - 4581655 , 4591928 , 4602247 , 4612613 , 4623025 , 4633484 , 4643991 , 4654545 , 4665148 , 4675799 , 4686499 , 4697248 , 4708046 , 4718894 , 4729792 , 4740741 , - 4751740 , 4762791 , 4773893 , 4785047 , 4796253 , 4807512 , 4818824 , 4830189 , 4841608 , 4853081 , 4864608 , 4876190 , 4887828 , 4899522 , 4911271 , 4923077 , - 4934940 , 4946860 , 4958838 , 4970874 , 4982968 , 4995122 , 5007335 , 5019608 , 5031941 , 5044335 , 5056790 , 5069307 , 5081886 , 5094527 , 5107232 , 5120000 , - 5132832 , 5145729 , 5158690 , 5171717 , 5184810 , 5197970 , 5211196 , 5224490 , 5237852 , 5251282 , 5264781 , 5278351 , 5291990 , 5305699 , 5319481 , 5333333 , - 5347258 , 5361257 , 5375328 , 5389474 , 5403694 , 5417989 , 5432361 , 5446809 , 5461333 , 5475936 , 5490617 , 5505376 , 5520216 , 5535135 , 5550136 , 5565217 , - 5580381 , 5595628 , 5610959 , 5626374 , 5641873 , 5657459 , 5673130 , 5688889 , 5704735 , 5720670 , 5736695 , 5752809 , 5769014 , 5785311 , 5801700 , 5818182 , - 5834758 , 5851429 , 5868195 , 5885057 , 5902017 , 5919075 , 5936232 , 5953488 , 5970845 , 5988304 , 6005865 , 6023529 , 6041298 , 6059172 , 6077151 , 6095238 , - 6113433 , 6131737 , 6150150 , 6168675 , 6187311 , 6206061 , 6224924 , 6243902 , 6262997 , 6282209 , 6301538 , 6320988 , 6340557 , 6360248 , 6380062 , 6400000 , - 6420063 , 6440252 , 6460568 , 6481013 , 6501587 , 6522293 , 6543131 , 6564103 , 6585209 , 6606452 , 6627832 , 6649351 , 6671010 , 6692810 , 6714754 , 6736842 , - 6759076 , 6781457 , 6803987 , 6826667 , 6849498 , 6872483 , 6895623 , 6918919 , 6942373 , 6965986 , 6989761 , 7013699 , 7037801 , 7062069 , 7086505 , 7111111 , - 7135889 , 7160839 , 7185965 , 7211268 , 7236749 , 7262411 , 7288256 , 7314286 , 7340502 , 7366906 , 7393502 , 7420290 , 7447273 , 7474453 , 7501832 , 7529412 , - 7557196 , 7585185 , 7613383 , 7641791 , 7670412 , 7699248 , 7728302 , 7757576 , 7787072 , 7816794 , 7846743 , 7876923 , 7907336 , 7937984 , 7968872 , 8000000 , - 8015656 , 8031373 , 8047151 , 8062992 , 8078895 , 8094862 , 8110891 , 8126984 , 8143141 , 8159363 , 8175649 , 8192000 , 8208417 , 8224900 , 8241449 , 8258065 , - 8274747 , 8291498 , 8308316 , 8325203 , 8342159 , 8359184 , 8376278 , 8393443 , 8410678 , 8427984 , 8445361 , 8462810 , 8480331 , 8497925 , 8515593 , 8533333 , - 8551148 , 8569038 , 8587002 , 8605042 , 8623158 , 8641350 , 8659619 , 8677966 , 8696391 , 8714894 , 8733475 , 8752137 , 8770878 , 8789700 , 8808602 , 8827586 , - 8846652 , 8865801 , 8885033 , 8904348 , 8923747 , 8943231 , 8962801 , 8982456 , 9002198 , 9022026 , 9041943 , 9061947 , 9082040 , 9102222 , 9122494 , 9142857 , - 9163311 , 9183857 , 9204494 , 9225225 , 9246050 , 9266968 , 9287982 , 9309091 , 9330296 , 9351598 , 9372998 , 9394495 , 9416092 , 9437788 , 9459584 , 9481481 , - 9503480 , 9525581 , 9547786 , 9570093 , 9592506 , 9615023 , 9637647 , 9660377 , 9683215 , 9706161 , 9729216 , 9752381 , 9775656 , 9799043 , 9822542 , 9846154 , - 9869880 , 9893720 , 9917676 , 9941748 , 9965937 , 9990244 , 10014670 , 10039216 , 10063882 , 10088670 , 10113580 , 10138614 , 10163772 , 10189055 , 10214464 , 10240000 , - 10265664 , 10291457 , 10317380 , 10343434 , 10369620 , 10395939 , 10422392 , 10448980 , 10475703 , 10502564 , 10529563 , 10556701 , 10583979 , 10611399 , 10638961 , 10666667 , - 10694517 , 10722513 , 10750656 , 10778947 , 10807388 , 10835979 , 10864721 , 10893617 , 10922667 , 10951872 , 10981233 , 11010753 , 11040431 , 11070270 , 11100271 , 11130435 , - 11160763 , 11191257 , 11221918 , 11252747 , 11283747 , 11314917 , 11346260 , 11377778 , 11409471 , 11441341 , 11473389 , 11505618 , 11538028 , 11570621 , 11603399 , 11636364 , - 11669516 , 11702857 , 11736390 , 11770115 , 11804035 , 11838150 , 11872464 , 11906977 , 11941691 , 11976608 , 12011730 , 12047059 , 12082596 , 12118343 , 12154303 , 12190476 , - 12226866 , 12263473 , 12300300 , 12337349 , 12374622 , 12412121 , 12449848 , 12487805 , 12525994 , 12564417 , 12603077 , 12641975 , 12681115 , 12720497 , 12760125 , 12800000 , - 12840125 , 12880503 , 12921136 , 12962025 , 13003175 , 13044586 , 13086262 , 13128205 , 13170418 , 13212903 , 13255663 , 13298701 , 13342020 , 13385621 , 13429508 , 13473684 , - 13518152 , 13562914 , 13607973 , 13653333 , 13698997 , 13744966 , 13791246 , 13837838 , 13884746 , 13931973 , 13979522 , 14027397 , 14075601 , 14124138 , 14173010 , 14222222 , - 14271777 , 14321678 , 14371930 , 14422535 , 14473498 , 14524823 , 14576512 , 14628571 , 14681004 , 14733813 , 14787004 , 14840580 , 14894545 , 14948905 , 15003663 , 15058824 , - 15114391 , 15170370 , 15226766 , 15283582 , 15340824 , 15398496 , 15456604 , 15515152 , 15574144 , 15633588 , 15693487 , 15753846 , 15814672 , 15875969 , 15937743 , 16000000 , - 16031311 , 16062745 , 16094303 , 16125984 , 16157791 , 16189723 , 16221782 , 16253968 , 16286282 , 16318725 , 16351297 , 16384000 , 16416834 , 16449799 , 16482897 , 16516129 , - 16549495 , 16582996 , 16616633 , 16650407 , 16684318 , 16718367 , 16752556 , 16786885 , 16821355 , 16855967 , 16890722 , 16925620 , 16960663 , 16995851 , 17031185 , 17066667 , - 17102296 , 17138075 , 17174004 , 17210084 , 17246316 , 17282700 , 17319239 , 17355932 , 17392781 , 17429787 , 17466951 , 17504274 , 17541756 , 17579399 , 17617204 , 17655172 , - 17693305 , 17731602 , 17770065 , 17808696 , 17847495 , 17886463 , 17925602 , 17964912 , 18004396 , 18044053 , 18083885 , 18123894 , 18164080 , 18204444 , 18244989 , 18285714 , - 18326622 , 18367713 , 18408989 , 18450450 , 18492099 , 18533937 , 18575964 , 18618182 , 18660592 , 18703196 , 18745995 , 18788991 , 18832184 , 18875576 , 18919169 , 18962963 , - 19006961 , 19051163 , 19095571 , 19140187 , 19185012 , 19230047 , 19275294 , 19320755 , 19366430 , 19412322 , 19458432 , 19504762 , 19551313 , 19598086 , 19645084 , 19692308 , - 19739759 , 19787440 , 19835351 , 19883495 , 19931873 , 19980488 , 20029340 , 20078431 , 20127764 , 20177340 , 20227160 , 20277228 , 20327543 , 20378109 , 20428928 , 20480000 , - 20531328 , 20582915 , 20634761 , 20686869 , 20739241 , 20791878 , 20844784 , 20897959 , 20951407 , 21005128 , 21059126 , 21113402 , 21167959 , 21222798 , 21277922 , 21333333 , - 21389034 , 21445026 , 21501312 , 21557895 , 21614776 , 21671958 , 21729443 , 21787234 , 21845333 , 21903743 , 21962466 , 22021505 , 22080863 , 22140541 , 22200542 , 22260870 , - 22321526 , 22382514 , 22443836 , 22505495 , 22567493 , 22629834 , 22692521 , 22755556 , 22818942 , 22882682 , 22946779 , 23011236 , 23076056 , 23141243 , 23206799 , 23272727 , - 23339031 , 23405714 , 23472779 , 23540230 , 23608069 , 23676301 , 23744928 , 23813953 , 23883382 , 23953216 , 24023460 , 24094118 , 24165192 , 24236686 , 24308605 , 24380952 , - 24453731 , 24526946 , 24600601 , 24674699 , 24749245 , 24824242 , 24899696 , 24975610 , 25051988 , 25128834 , 25206154 , 25283951 , 25362229 , 25440994 , 25520249 , 25600000 , - 25680251 , 25761006 , 25842271 , 25924051 , 26006349 , 26089172 , 26172524 , 26256410 , 26340836 , 26425806 , 26511327 , 26597403 , 26684039 , 26771242 , 26859016 , 26947368 , - 27036304 , 27125828 , 27215947 , 27306667 , 27397993 , 27489933 , 27582492 , 27675676 , 27769492 , 27863946 , 27959044 , 28054795 , 28151203 , 28248276 , 28346021 , 28444444 , - 28543554 , 28643357 , 28743860 , 28845070 , 28946996 , 29049645 , 29153025 , 29257143 , 29362007 , 29467626 , 29574007 , 29681159 , 29789091 , 29897810 , 30007326 , 30117647 , - 30228782 , 30340741 , 30453532 , 30567164 , 30681648 , 30796992 , 30913208 , 31030303 , 31148289 , 31267176 , 31386973 , 31507692 , 31629344 , 31751938 , 31875486 , 32000000 , - 32062622 , 32125490 , 32188605 , 32251969 , 32315582 , 32379447 , 32443564 , 32507937 , 32572565 , 32637450 , 32702595 , 32768000 , 32833667 , 32899598 , 32965795 , 33032258 , - 33098990 , 33165992 , 33233266 , 33300813 , 33368635 , 33436735 , 33505112 , 33573770 , 33642710 , 33711934 , 33781443 , 33851240 , 33921325 , 33991701 , 34062370 , 34133333 , - 34204593 , 34276151 , 34348008 , 34420168 , 34492632 , 34565401 , 34638478 , 34711864 , 34785563 , 34859574 , 34933902 , 35008547 , 35083512 , 35158798 , 35234409 , 35310345 , - 35386609 , 35463203 , 35540130 , 35617391 , 35694989 , 35772926 , 35851204 , 35929825 , 36008791 , 36088106 , 36167770 , 36247788 , 36328160 , 36408889 , 36489978 , 36571429 , - 36653244 , 36735426 , 36817978 , 36900901 , 36984199 , 37067873 , 37151927 , 37236364 , 37321185 , 37406393 , 37491991 , 37577982 , 37664368 , 37751152 , 37838337 , 37925926 , - 38013921 , 38102326 , 38191142 , 38280374 , 38370023 , 38460094 , 38550588 , 38641509 , 38732861 , 38824645 , 38916865 , 39009524 , 39102625 , 39196172 , 39290168 , 39384615 , - 39479518 , 39574879 , 39670702 , 39766990 , 39863747 , 39960976 , 40058680 , 40156863 , 40255528 , 40354680 , 40454321 , 40554455 , 40655087 , 40756219 , 40857855 , 40960000 , - 41062657 , 41165829 , 41269521 , 41373737 , 41478481 , 41583756 , 41689567 , 41795918 , 41902813 , 42010256 , 42118252 , 42226804 , 42335917 , 42445596 , 42555844 , 42666667 , - 42778068 , 42890052 , 43002625 , 43115789 , 43229551 , 43343915 , 43458886 , 43574468 , 43690667 , 43807487 , 43924933 , 44043011 , 44161725 , 44281081 , 44401084 , 44521739 , - 44643052 , 44765027 , 44887671 , 45010989 , 45134986 , 45259669 , 45385042 , 45511111 , 45637883 , 45765363 , 45893557 , 46022472 , 46152113 , 46282486 , 46413598 , 46545455 , - 46678063 , 46811429 , 46945559 , 47080460 , 47216138 , 47352601 , 47489855 , 47627907 , 47766764 , 47906433 , 48046921 , 48188235 , 48330383 , 48473373 , 48617211 , 48761905 , - 48907463 , 49053892 , 49201201 , 49349398 , 49498489 , 49648485 , 49799392 , 49951220 , 50103976 , 50257669 , 50412308 , 50567901 , 50724458 , 50881988 , 51040498 , 51200000 , - 51360502 , 51522013 , 51684543 , 51848101 , 52012698 , 52178344 , 52345048 , 52512821 , 52681672 , 52851613 , 53022654 , 53194805 , 53368078 , 53542484 , 53718033 , 53894737 , - 54072607 , 54251656 , 54431894 , 54613333 , 54795987 , 54979866 , 55164983 , 55351351 , 55538983 , 55727891 , 55918089 , 56109589 , 56302405 , 56496552 , 56692042 , 56888889 , - 57087108 , 57286713 , 57487719 , 57690141 , 57893993 , 58099291 , 58306050 , 58514286 , 58724014 , 58935252 , 59148014 , 59362319 , 59578182 , 59795620 , 60014652 , 60235294 , - 60457565 , 60681481 , 60907063 , 61134328 , 61363296 , 61593985 , 61826415 , 62060606 , 62296578 , 62534351 , 62773946 , 63015385 , 63258687 , 63503876 , 63750973 , 64000000 diff --git a/src/sound/saasound/SAAFreq.h b/src/sound/saasound/SAAFreq.h deleted file mode 100755 index 478754621..000000000 --- a/src/sound/saasound/SAAFreq.h +++ /dev/null @@ -1,72 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAFreq.h: interface for the CSAAFreq class. -// Note about Samplerates: 0=44100, 1=22050; 2=11025 -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAAFREQ_H_INCLUDE -#define SAAFREQ_H_INCLUDE - -#include "defns.h" - -class CSAAFreq -{ -private: -#ifdef SAAFREQ_FIXED_CLOCKRATE - // 'load in' the data for the static frequency lookup table - // precomputed for a fixed clockrate - // See: tools/freqdat.py - const static unsigned long m_FreqTable[2048]; -#else - // we'll calculate the frequency lookup table at runtime. - static unsigned long m_FreqTable[2048]; - static unsigned long m_nClockRate; -#endif - - unsigned long m_nCounter; - unsigned long m_nAdd; - unsigned long m_nCounter_low; - unsigned int m_nOversample; - unsigned long m_nCounterLimit_low; - int m_nLevel; - - int m_nCurrentOffset; - int m_nCurrentOctave; - int m_nNextOffset; - int m_nNextOctave; - bool m_bIgnoreOffsetData; - bool m_bNewData; - bool m_bSync; - - unsigned long m_nSampleRate; - CSAANoise * const m_pcConnectedNoiseGenerator; - CSAAEnv * const m_pcConnectedEnvGenerator; - const int m_nConnectedMode; // 0 = nothing; 1 = envgenerator; 2 = noisegenerator - - void UpdateOctaveOffsetData(void); - void SetAdd(void); - -public: - CSAAFreq(CSAANoise * const pcNoiseGenerator, CSAAEnv * const pcEnvGenerator); - ~CSAAFreq(); - void SetFreqOffset(BYTE nOffset); - void SetFreqOctave(BYTE nOctave); - void _SetSampleRate(unsigned int nSampleRate); - void _SetOversample(unsigned int oversample); - void _SetClockRate(int nClockRate); - void Sync(bool bSync); - int Tick(void); - int Level(void) const; - -}; - -inline int CSAAFreq::Level(void) const -{ - if (m_bSync) - return 1; - - return m_nLevel; -} - -#endif // SAAFREQ_H_INCLUDE diff --git a/src/sound/saasound/SAAImpl.cpp b/src/sound/saasound/SAAImpl.cpp deleted file mode 100644 index f136eefc6..000000000 --- a/src/sound/saasound/SAAImpl.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAAImpl.cpp: implementation of the CSAASound class. -// the bones of the 'virtual SAA-1099' emulation -// -// the actual sound generation is carried out in the other classes; -// this class provides the output stage and the external interface only -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" - -#include "types.h" -#include "SAAImpl.h" -#include "defns.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAASoundInternal::CSAASoundInternal() - : -m_chip(), -m_uParam(0), -m_uParamRate(0), -m_nClockRate(EXTERNAL_CLK_HZ), -m_nSampleRate(SAMPLE_RATE_HZ), -m_nOversample(DEFAULT_OVERSAMPLE), -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -m_bHighpass(false), -m_nDebugSample(0) -#else -m_bHighpass(false) -#endif -{ -#ifdef USE_CONFIG_FILE - m_Config.ReadConfig(); -#endif - -#if defined(DEBUGSAA) - m_dbgfile.open(_T(DEBUG_SAA_REGISTER_LOG), std::ios_base::out); - m_pcmfile.open(_T(DEBUG_SAA_PCM_LOG), std::ios_base::out | std::ios_base::binary); -#elif defined(USE_CONFIG_FILE) - if (m_Config.m_bGenerateRegisterLogs) - m_dbgfile.open(m_Config.m_strRegisterLogPath, std::ios_base::out); - if (m_Config.m_bGeneratePcmLogs) - m_pcmfile.open(m_Config.m_strPcmOutputPath, std::ios_base::out | std::ios_base::binary); - - if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels) - { - for (int i = 0; i < 6; i++) - { - m_channel_pcmfile[i].open(m_Config.getChannelPcmOutputPath(i), std::ios_base::out | std::ios_base::binary); - } - } - - -#endif - // set parameters - // TODO support defaults and overrides from config file - // m_chip.SetSoundParameters(SAAP_FILTER | SAAP_11025 | SAAP_8BIT | SAAP_MONO); - // reset the virtual SAA - // m_chip.Clear(); - - m_chip._SetClockRate(m_nClockRate); - m_chip._SetOversample(m_nOversample); -} - -CSAASoundInternal::~CSAASoundInternal() -{ - // -} - -////////////////////////////////////////////////////////////////////// -// CSAASound members -////////////////////////////////////////////////////////////////////// - -void CSAASoundInternal::SetClockRate(unsigned int nClockRate) -{ - m_nClockRate = nClockRate; - m_chip._SetClockRate(m_nClockRate); -} - -void CSAASoundInternal::Clear(void) -{ - // reinitialises virtual SAA: - // sets reg 28 to 0x02; - sync and disabled - // sets regs 00-31 (except 28) to 0x00; - // sets reg 28 to 0x00; - // sets current reg to 0 - WriteAddressData(28,2); - for (int i=31; i>=0; i--) - { - if (i!=28) WriteAddressData(i,0); - } - WriteAddressData(28,0); - WriteAddress(0); -} - -void CSAASoundInternal::WriteData(BYTE nData) -{ - // originated from an OUT 255,d call - m_chip._WriteData(nData); -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -#ifdef USE_CONFIG_FILE - if (m_Config.m_bGenerateRegisterLogs) - { -#endif - m_dbgfile << m_nDebugSample << " " << (int)m_chip._ReadAddress() << ":" << (int)nData << std::endl; -#ifdef USE_CONFIG_FILE - } -#endif -#endif -} - -void CSAASoundInternal::WriteAddress(BYTE nReg) -{ - // originated from an OUT 511,r call - m_chip._WriteAddress(nReg); -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -#ifdef USE_CONFIG_FILE - if (m_Config.m_bGenerateRegisterLogs) - { -#endif - m_dbgfile << m_nDebugSample << " " << (int)nReg << ":"; - if (nReg==24) - { - m_dbgfile << ""; - } - else if (nReg==25) - { - m_dbgfile << ""; - } - m_dbgfile << std::endl; -#ifdef USE_CONFIG_FILE - } -#endif -#endif -} - -void CSAASoundInternal::WriteAddressData(BYTE nReg, BYTE nData) -{ - // performs WriteAddress(nReg) followed by WriteData(nData) - m_chip._WriteAddress(nReg); - m_chip._WriteData(nData); -} - -#if 1 -BYTE CSAASoundInternal::ReadAddress(void) -{ - // Not a real hardware function of the SAA-1099, which is write-only - return(m_chip._ReadAddress()); -} -#else -BYTE CSAASoundInternal::ReadAddress(void) -{ - // Not a real hardware function of the SAA-1099, which is write-only - return(0); -} -#endif - -void CSAASoundInternal::SetSoundParameters(SAAPARAM uParam) -{ - // set samplerate properties from uParam (deprecated but still supported) - unsigned int nSampleRate = m_nSampleRate; - switch (uParam & SAAP_MASK_SAMPLERATE) - { - case SAAP_44100: - nSampleRate = 44100; - m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_44100; - break; - case SAAP_22050: - nSampleRate = 22050; - m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_22050; - break; - case SAAP_11025: - nSampleRate = 11025; - m_uParamRate = (m_uParamRate & ~SAAP_MASK_SAMPLERATE) | SAAP_11025; - break; - case 0:// change nothing! - default: - break; - } - - if (nSampleRate != m_nSampleRate) - { - m_nSampleRate = nSampleRate; - m_chip._SetSampleRate(m_nSampleRate); - } - - // set filter properties from uParam - m_uParam = (m_uParam & ~SAAP_MASK_FILTER) | (uParam & SAAP_MASK_FILTER); - - m_bHighpass=true; -} - -void CSAASoundInternal::SetSampleRate(unsigned int nSampleRate) -{ - if (nSampleRate != m_nSampleRate) - { - m_nSampleRate = nSampleRate; - m_chip._SetSampleRate(m_nSampleRate); - } -} - -void CSAASoundInternal::SetOversample(unsigned int nOversample) -{ - if (nOversample != m_nOversample) - { - m_nOversample = nOversample; - m_chip._SetOversample(m_nOversample); - } -} - -SAAPARAM CSAASoundInternal::GetCurrentSoundParameters(void) -{ - return m_uParam | m_uParamRate; -} - -unsigned short CSAASoundInternal::GetCurrentBytesPerSample(void) -{ - // 16 bit stereo => 4 bytes per sample - return 4; -} - -/*static*/ unsigned short CSAASound::GetBytesPerSample(SAAPARAM uParam) -{ - // 16 bit stereo => 4 bytes per sample - switch (uParam & (SAAP_MASK_CHANNELS | SAAP_MASK_BITDEPTH)) - { - case SAAP_STEREO | SAAP_16BIT: - return 4; - default: - return 0; - } -} - -unsigned long CSAASoundInternal::GetCurrentSampleRate(void) -{ - return CSAASound::GetSampleRate(m_uParamRate); -} - -/*static*/ unsigned long CSAASound::GetSampleRate(SAAPARAM uParam) // static member function -{ - switch (uParam & SAAP_MASK_SAMPLERATE) - { - case SAAP_11025: - return 11025; - case SAAP_22050: - return 22050; - case SAAP_44100: - return 44100; - default: - return 0; - } -} - -#if defined(USE_CONFIG_FILE) || (defined(DEFAULT_BOOST) && DEFAULT_BOOST>1) -#define DO_BOOST -#endif - -void scale_for_output(unsigned int left_input, unsigned int right_input, - double oversample_scalar, bool highpass, double boost, - double& filterout_z1_left, double& filterout_z1_right, - BYTE* &pBuffer) -{ - double float_left = (double)left_input; - double float_right = (double)right_input; - float_left /= oversample_scalar; - float_right /= oversample_scalar; - - // scale output into good range - float_left *= DEFAULT_UNBOOSTED_MULTIPLIER; - float_right *= DEFAULT_UNBOOSTED_MULTIPLIER; - - if (highpass) - { - /* cutoff = 5 Hz (say) - const double b1 = exp(-2.0 * M_PI * (Fc/Fs)) - const double a0 = 1.0 - b1; - */ - const double b1 = 0.99928787; - const double a0 = 1.0 - b1; - - filterout_z1_left = float_left * a0 + filterout_z1_left * b1; - filterout_z1_right = float_right * a0 + filterout_z1_right * b1; - float_left -= filterout_z1_left; - float_right -= filterout_z1_right; - } - - // multiply by boost, if defined -#if defined(DO_BOOST) - float_left *= boost; - float_right *= boost; -#endif - // convert to 16-bit signed range with hard clipping - signed short left_output = (signed short)(float_left > 32767 ? 32767 : float_left < -32768 ? -32768 : float_left); - signed short right_output = (signed short)(float_right > 32767 ? 32767 : float_right < -32768 ? -32768 : float_right); - - *pBuffer++ = left_output & 0x00ff; - *pBuffer++ = (left_output >> 8) & 0x00ff; - *pBuffer++ = right_output & 0x00ff; - *pBuffer++ = (right_output >> 8) & 0x00ff; -} - -void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples) -{ - unsigned int left_mixed, right_mixed; - static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0; - -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) - BYTE* pBufferStart = pBuffer; - unsigned long nTotalSamples = nSamples; -#endif - -#if defined(DO_BOOST) -#if defined(USE_CONFIG_FILE) - double nBoost = m_Config.m_nBoost; -#else - double nBoost = DEFAULT_BOOST; -#endif -#else - double nBoost = 1.0; -#endif - - double oversample = double(1 << m_nOversample); - -#if defined(USE_CONFIG_FILE) - static double filterout_z1_left_0 = 0, filterout_z1_right_0 = 0; - static double filterout_z1_left_1 = 0, filterout_z1_right_1 = 0; - static double filterout_z1_left_2 = 0, filterout_z1_right_2 = 0; - static double filterout_z1_left_3 = 0, filterout_z1_right_3 = 0; - static double filterout_z1_left_4 = 0, filterout_z1_right_4 = 0; - static double filterout_z1_left_5 = 0, filterout_z1_right_5 = 0; - - if (m_Config.m_bGeneratePcmLogs && m_Config.m_bGeneratePcmSeparateChannels) - { - unsigned int left0, right0, left1, right1, left2, right2, left3, right3, left4, right4, left5, right5; - BYTE* pChannelBufferPtr[6] = { m_pChannelBuffer[0], m_pChannelBuffer[1], m_pChannelBuffer[2], m_pChannelBuffer[3], m_pChannelBuffer[4], m_pChannelBuffer[5] }; - - while (nSamples--) - { - m_chip._TickAndOutputSeparate(left_mixed, right_mixed, - left0, right0, - left1, right1, - left2, right2, - left3, right3, - left4, right4, - left5, right5); - scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer); - - // and the separate channels - scale_for_output(left0, right0, oversample, m_bHighpass, nBoost, filterout_z1_left_0, filterout_z1_right_0, pChannelBufferPtr[0]); - scale_for_output(left1, right1, oversample, m_bHighpass, nBoost, filterout_z1_left_1, filterout_z1_right_1, pChannelBufferPtr[1]); - scale_for_output(left2, right2, oversample, m_bHighpass, nBoost, filterout_z1_left_2, filterout_z1_right_2, pChannelBufferPtr[2]); - scale_for_output(left3, right3, oversample, m_bHighpass, nBoost, filterout_z1_left_3, filterout_z1_right_3, pChannelBufferPtr[3]); - scale_for_output(left4, right4, oversample, m_bHighpass, nBoost, filterout_z1_left_4, filterout_z1_right_4, pChannelBufferPtr[4]); - scale_for_output(left5, right5, oversample, m_bHighpass, nBoost, filterout_z1_left_5, filterout_z1_right_5, pChannelBufferPtr[5]); - - // flush channel output PCM buffers when full - if (pChannelBufferPtr[0] >= m_pChannelBuffer[0] + CHANNEL_BUFFER_SIZE) - { - for (int i = 0; i < 6; i++) - { - m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], CHANNEL_BUFFER_SIZE); - pChannelBufferPtr[i] = m_pChannelBuffer[i]; - } - } - } - // flush remaining channel PCM output data - if (pChannelBufferPtr[0] >= m_pChannelBuffer[0]) - { - for (int i = 0; i < 6; i++) - { - m_channel_pcmfile[i].write((const char*)m_pChannelBuffer[i], pChannelBufferPtr[i]-m_pChannelBuffer[i]); - } - } - } - else - { -#endif - while (nSamples--) - { - m_chip._TickAndOutputStereo(left_mixed, right_mixed); - scale_for_output(left_mixed, right_mixed, oversample, m_bHighpass, nBoost, filterout_z1_left_mixed, filterout_z1_right_mixed, pBuffer); - } - -#if defined(USE_CONFIG_FILE) - } -#endif - -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -#ifdef USE_CONFIG_FILE - if (m_Config.m_bGeneratePcmLogs) - { -#endif - m_pcmfile.write((const char *)pBufferStart, nTotalSamples * (unsigned long)GetCurrentBytesPerSample()); - m_nDebugSample += nTotalSamples; -#ifdef USE_CONFIG_FILE - } -#endif - -#endif -} - -/////////////////////////////////////////////////////// - -LPCSAASOUND SAAAPI CreateCSAASound(void) -{ - return (new CSAASoundInternal); -} - -void SAAAPI DestroyCSAASound(LPCSAASOUND object) -{ - delete (object); -} - - -/* thoughts on lowpass filtering as part of oversampling. -I tried this and really it didn't seem to make a lot of (audible) difference. - -// lowpass oversample filter adds complexity and not particularly audibly better than simple averaging. -// use_lowpass_oversample_filter_average_output adds an additional averaging step to the output of the oversample -// filter. this seems critical, because without this, the raw output of the lowpass filter is full of aliases -// If use_lowpass_oversample_filter is False, then the _average_output flag is ignored. -// Default, use_lowpass_oversample_filter is False, it sounds just fine really. - -//#define USE_LOWPASS_OVERSAMPLE_FILTER -#undef USE_LOWPASS_OVERSAMPLE_FILTER -//#define USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT -#undef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT - -#ifdef USE_LOWPASS_OVERSAMPLE_FILTER -static double oversample_lp_filterout_z1_left_stages[10] = { 0,0,0,0,0,0,0,0,0,0 }; -static double oversample_lp_filterout_z1_right_stages[10] = { 0,0,0,0,0,0,0,0,0,0 }; -double averaged_filterout_left = 0.0, averaged_filterout_right = 0.0; -const int nStages = 10; -for (int i = 0; i < 1 << m_nOversample; i++) -{ - Noise[0]->Tick(); - Noise[1]->Tick(); - f_left = f_right = 0; - for (int c = 0; c < 6; c++) - { - Amp[c]->TickAndOutputStereo(temp_left, temp_right); - f_left += (double)temp_left; - f_right += (double)temp_right; - } - // apply lowpass here. - // HACK: ASSUME m_nOversample is 64 (I was experimenting only using the 64x oversample anyway) - // therefore Fs = 44100*64 - // let's set Fc = 10kHz - // so Fc/Fs = 0.00354308390022675736961451247166 - // const double b1 = exp(-2.0 * M_PI * (Fc/Fs)) - // const double a0 = 1.0 - b1; - // const double b1 = 0.9779841137335348363722276130195; - const double b1 = 0.977; - const double a0 = 1.0 - b1; - - oversample_lp_filterout_z1_left_stages[0] = f_left * a0 + oversample_lp_filterout_z1_left_stages[0] * b1; - for (int stage = 1; stage < nStages; stage++) - oversample_lp_filterout_z1_left_stages[stage] = oversample_lp_filterout_z1_left_stages[stage - 1] * a0 + oversample_lp_filterout_z1_left_stages[stage] * b1; - oversample_lp_filterout_z1_right_stages[0] = f_right * a0 + oversample_lp_filterout_z1_right_stages[0] * b1; - for (int stage = 1; stage < nStages; stage++) - oversample_lp_filterout_z1_right_stages[stage] = oversample_lp_filterout_z1_right_stages[stage - 1] * a0 + oversample_lp_filterout_z1_right_stages[stage] * b1; - -#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT - averaged_filterout_left += oversample_lp_filterout_4z1_left; - averaged_filterout_right += oversample_lp_filterout_4z1_right; -#endif -} - -// by the end of this loop we will have computed the oversample lowpass filter m_nOversample times -// and yielded exactly ONE sample output. -#ifdef USE_LOWPASS_OVERSAMPLE_FILTER_AVERAGE_OUTPUT -f_left = averaged_filterout_left / (1 << m_nOversample); -f_right = averaged_filterout_right / (1 << m_nOversample); -#else -f_left = oversample_lp_filterout_z1_left_stages[nStages - 1]; -f_right = oversample_lp_filterout_z1_right_stages[nStages - 1]; -#endif - -#else - // do the simple 1/N averaging which is easier and sounds good enough - -#endif - -*/ - diff --git a/src/sound/saasound/SAAImpl.h b/src/sound/saasound/SAAImpl.h deleted file mode 100755 index 61fa79c58..000000000 --- a/src/sound/saasound/SAAImpl.h +++ /dev/null @@ -1,75 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// This is the internal implementation (header file) of the SAASound object. -// This is done so that the external interface to the object always stays the same -// (SAASound.h) even though the internal object can change -// .. Meaning future releases don't require relinking everyone elses code against -// the updated saasound stuff -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAAIMPL_H_INCLUDED -#define SAAIMPL_H_INCLUDED - -#include "SAASound.h" -#include "SAADevice.h" -#ifdef USE_CONFIG_FILE -#include "SAAConfig.h" -#endif - -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) -#include -#include -#include - -#if defined(USE_CONFIG_FILE) -const int CHANNEL_BUFFER_SIZE=1024; -#endif -#endif - -class CSAASoundInternal : public CSAASound -{ -private: - CSAADevice m_chip; - int m_uParam, m_uParamRate; - unsigned int m_nClockRate; - unsigned int m_nSampleRate; - unsigned int m_nOversample; - bool m_bHighpass; -#ifdef USE_CONFIG_FILE - SAAConfig m_Config; -#endif -#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE) - unsigned long m_nDebugSample; - std::ofstream m_dbgfile, m_pcmfile; -#if defined(USE_CONFIG_FILE) - std::ofstream m_channel_pcmfile[6]; - BYTE m_pChannelBuffer[6][CHANNEL_BUFFER_SIZE]; -#endif -#endif - -public: - CSAASoundInternal(); - ~CSAASoundInternal(); - - void SetClockRate(unsigned int nClockRate); - void SetSampleRate(unsigned int nClockRate); - void SetOversample(unsigned int nOversample); - void SetSoundParameters(SAAPARAM uParam); - void WriteAddress(BYTE nReg); - void WriteData(BYTE nData); - void WriteAddressData(BYTE nReg, BYTE nData); - BYTE ReadAddress(void); - void Clear(void); - - SAAPARAM GetCurrentSoundParameters(void); - unsigned long GetCurrentSampleRate(void); - static unsigned long GetSampleRate(SAAPARAM uParam); - unsigned short GetCurrentBytesPerSample(void); - static unsigned short GetBytesPerSample(SAAPARAM uParam); - - void GenerateMany(BYTE * pBuffer, unsigned long nSamples); - -}; - -#endif // SAAIMPL_H_INCLUDED diff --git a/src/sound/saasound/SAANoise.cpp b/src/sound/saasound/SAANoise.cpp deleted file mode 100755 index 1cf3458dd..000000000 --- a/src/sound/saasound/SAANoise.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAANoise.cpp: implementation of the CSAANoise class. -// One noise generator -// -// After construction, it's important to SetSampleRate before -// trying to use the generator. -// (Just because the CSAANoise object has a default samplerate -// doesn't mean you should rely on it) -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" - -#include "types.h" -#include "SAANoise.h" -#include "defns.h" - - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CSAANoise::CSAANoise() -: -m_nCounter(0), -m_nCounter_low(0), -m_nOversample(0), -m_nCounterLimit_low(1), -m_bSync(false), -m_nSampleRate(SAMPLE_RATE_HZ), -m_nSourceMode(0), -m_nRand(1) -{ - _SetClockRate(EXTERNAL_CLK_HZ); - m_nAdd = m_nAddBase; -} - -CSAANoise::CSAANoise(unsigned long seed) -: -m_nCounter(0), -m_nCounter_low(0), -m_nOversample(0), -m_nCounterLimit_low(1), -m_bSync(false), -m_nSampleRate(SAMPLE_RATE_HZ), -m_nSourceMode(0), -m_nRand(seed) -{ - _SetClockRate(EXTERNAL_CLK_HZ); - m_nAdd = m_nAddBase; -} - -CSAANoise::~CSAANoise() -{ - // Nothing to do -} - -void CSAANoise::_SetClockRate(int nClockRate) -{ - // at 8MHz the clock rate is 31.250kHZ - // This is simply the clock rate divided by 256 i.e. 2^8 - // We then shift this by 2^12 (like the Freq) for better - // period accuracy. So that's the same as shifting by (12-8) - m_nAddBase = nClockRate << (12 - 8); -} - -void CSAANoise::Seed(unsigned long seed) -{ - m_nRand = seed; -} - -void CSAANoise::SetSource(int nSource) -{ - m_nSourceMode = nSource; - m_nAdd = m_nAddBase >> m_nSourceMode; -} - -void CSAANoise::Trigger(void) -{ - // Trigger only does anything useful when we're - // clocking from the frequency generator - i.e - // if bUseFreqGen = true (i.e. SourceMode = 3) - - // So if we're clocking from the noise generator - // clock (ie, SourceMode = 0, 1 or 2) then do nothing - -// No point actually checking m_bSync here ... because if sync is true, -// then frequency generators won't actually be generating Trigger pulses -// so we wouldn't even get here! - // EXCEPT - cool edge case: if sync is set, then actually the Noise Generator - // is triggered on EVERY CLOCK PULSE (i.e. 8MHz noise). So indeed it is correct - // to not check for sync here. NEEDS TEST CASE. - - if (m_nSourceMode == 3) - { - ChangeLevel(); - } -} - -void CSAANoise::Tick(void) -{ - // Tick only does anything useful when we're - // clocking from the noise generator clock - // (ie, SourceMode = 0, 1 or 2) - - // So, if SourceMode = 3 (ie, we're clocking from a - // frequency generator ==> bUseFreqGen = true) - // then do nothing - if ( (!m_bSync) && (m_nSourceMode!=3) ) - { - m_nCounter += m_nAdd; - while (m_nCounter >= (m_nSampleRate<<12)) - { - m_nCounter -= (m_nSampleRate<<12); - m_nCounter_low++; - if (m_nCounter_low >= m_nCounterLimit_low) - { - m_nCounter_low = 0; - ChangeLevel(); - } - } - } -} - -void CSAANoise::Sync(bool bSync) -{ - if (bSync) - { - m_nCounter = 0; - m_nCounter_low = 0; - } - m_bSync = bSync; -} - - -void CSAANoise::_SetSampleRate(int nSampleRate) -{ - m_nSampleRate = nSampleRate; -} - - -void CSAANoise::_SetOversample(unsigned int oversample) -{ - // oversample is a power of 2 i.e. - // if oversample == 2 then 4x oversample - // if oversample == 6 then 64x oversample - if (oversample < m_nOversample) - { - m_nCounter_low <<= (m_nOversample - oversample); - } - else - { - m_nCounter_low >>= (oversample - m_nOversample); - } - - m_nCounterLimit_low = 1<> 1) ^ 0x20400; - } - else - { - m_nRand >>= 1; - } -} diff --git a/src/sound/saasound/SAANoise.h b/src/sound/saasound/SAANoise.h deleted file mode 100755 index 61a65dee8..000000000 --- a/src/sound/saasound/SAANoise.h +++ /dev/null @@ -1,54 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAANoise.h: interface for the CSAANoise class. -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAANOISE_H_INCLUDED -#define SAANOISE_H_INCLUDED - -class CSAANoise -{ -private: - unsigned long m_nCounter; - unsigned long m_nAdd; - unsigned long m_nCounter_low; - unsigned int m_nOversample; - unsigned long m_nCounterLimit_low; - bool m_bSync; // see description of "SYNC" bit of register 28 - unsigned long m_nSampleRate; // = 44100 when RateMode=0, for example - int m_nSourceMode; - unsigned long m_nAddBase; // nAdd for 31.25 kHz noise at 44.1 kHz samplerate - - // pseudo-random number generator - unsigned long m_nRand; - - void ChangeLevel(void); - - -public: - CSAANoise(); - CSAANoise(unsigned long seed); - ~CSAANoise(); - - void SetSource(int nSource); - void Trigger(void); - void _SetSampleRate(int nSampleRate); - void _SetOversample(unsigned int oversample); - void _SetClockRate(int nClockRate); - void Seed(unsigned long seed); - - void Tick(void); - int Level(void) const; - void Sync(bool bSync); - -}; - -inline int CSAANoise::Level(void) const -{ - // returns 0 or 1 - return (m_nRand & 0x00000001); -} - - -#endif // SAANOISE_H_INCLUDED diff --git a/src/sound/saasound/SAASndC.cpp b/src/sound/saasound/SAASndC.cpp deleted file mode 100755 index 9af0d76e7..000000000 --- a/src/sound/saasound/SAASndC.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// Thanks to this file (and associated header file) you can now -// use CSAASound from within a standard 'C' program -// -////////////////////////////////////////////////////////////////////// - -#include "SAASound.h" -#include "types.h" -#include "SAAEnv.h" -#include "SAANoise.h" -#include "SAAFreq.h" -#include "SAAAmp.h" -#include "SAASound.h" -#include "SAAImpl.h" - -SAASND SAAAPI newSAASND(void) -{ - return (SAASND)(new CSAASoundInternal()); -} - -void SAAAPI deleteSAASND(SAASND object) -{ - delete (LPCSAASOUND)(object); -} - -void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate) -{ - ((LPCSAASOUND)(object))->SetClockRate(nClockRate); -} - -void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam) -{ - ((LPCSAASOUND)(object))->SetSoundParameters(uParam); -} - -void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg) -{ - ((LPCSAASOUND)(object))->WriteAddress(nReg); -} - -void SAAAPI SAASNDWriteData(SAASND object, BYTE nData) -{ - ((LPCSAASOUND)(object))->WriteData(nData); -} - -void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData) -{ - ((LPCSAASOUND)(object))->WriteAddressData(nReg, nData); -} - -void SAAAPI SAASNDClear(SAASND object) -{ - ((LPCSAASOUND)(object))->Clear(); -} - -SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object) -{ - return ((LPCSAASOUND)(object))->GetCurrentSoundParameters(); -} - -unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object) -{ - return ((LPCSAASOUND)(object))->GetCurrentBytesPerSample(); -} - -unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam) -{ - return CSAASound::GetBytesPerSample(uParam); -} - -unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object) -{ - return ((LPCSAASOUND)(object))->GetCurrentSampleRate(); -} - -unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam) -{ - return CSAASound::GetSampleRate(uParam); -} - -void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples) -{ - ((LPCSAASOUND)(object))->GenerateMany(pBuffer, nSamples); -} - -void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate) -{ - return ((LPCSAASOUND)(object))->SetSampleRate(nSampleRate); -} - -void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample) -{ - return ((LPCSAASOUND)(object))->SetOversample(nOversample); -} - -BYTE SAAAPI SAASNDReadAddress(SAASND object) -{ - return ((LPCSAASOUND)(object))->ReadAddress(); -} diff --git a/src/sound/saasound/SAASndC.h b/src/sound/saasound/SAASndC.h deleted file mode 100644 index c6fd65765..000000000 --- a/src/sound/saasound/SAASndC.h +++ /dev/null @@ -1,102 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// ********** -// * PUBLIC * -// ********** -// -// SAASndC.h: "C-style" interface for the CSAASound class. -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAASNDC_H_INCLUDED -#define SAASNDC_H_INCLUDED - -#ifdef _MSC_VER -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -#endif - -#ifndef SAASOUND_H_INCLUDED - -// Parameters for use with SetSoundParameters, for example, -// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAAP_16BIT | SAAP_STEREO); -#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400 -#define SAAP_FILTER_OVERSAMPLE64x 0x00000300 -#define SAAP_FILTER_OVERSAMPLE2x 0x00000200 -#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x -#define SAAP_NOFILTER 0x00000100 -#define SAAP_44100 0x00000030 -#define SAAP_22050 0x00000020 -#define SAAP_11025 0x00000010 -#define SAAP_16BIT 0x0000000c -#define SAAP_8BIT 0x00000004 -#define SAAP_STEREO 0x00000003 -#define SAAP_MONO 0x00000001 - -// Bitmasks for use with GetCurrentSoundParameters, for example, -// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters() -#define SAAP_MASK_FILTER 0x00000f00 -#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00 -#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300 -#define SAAP_MASK_SAMPLERATE 0x000000030 -#define SAAP_MASK_BITDEPTH 0x0000000c -#define SAAP_MASK_CHANNELS 0x00000003 - -typedef unsigned long SAAPARAM; - - -#ifndef BYTE -#define BYTE unsigned char -#endif - -#ifdef WIN32 -#ifndef WINAPI -#define WINAPI __stdcall -#endif -#define EXTAPI __declspec(dllexport) WINAPI -#else // Win32 -#ifndef WINAPI -#define WINAPI /**/ -#endif -#define EXTAPI /**/ -#endif // Win32 - -#endif // SAASOUND_H_INCLUDED - -typedef void * SAASND; - -// the following are implemented as calls, etc, to a class. - -#ifdef __cplusplus -extern "C" { -#endif - -SAASND EXTAPI newSAASND(void); -void EXTAPI deleteSAASND(SAASND object); - -void EXTAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam); -void EXTAPI SAASNDWriteAddress(SAASND object, BYTE nReg); -void EXTAPI SAASNDWriteData(SAASND object, BYTE nData); -void EXTAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData); -void EXTAPI SAASNDClear(SAASND object); -BYTE EXTAPI SAASNDReadAddress(SAASND object); - -SAAPARAM EXTAPI SAASNDGetCurrentSoundParameters(SAASND object); -unsigned short EXTAPI SAASNDGetCurrentBytesPerSample(SAASND object); -unsigned short EXTAPI SAASNDGetBytesPerSample(SAAPARAM uParam); -unsigned long EXTAPI SAASNDGetCurrentSampleRate(SAASND object); -unsigned long EXTAPI SAASNDGetSampleRate(SAAPARAM uParam); - -void EXTAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples); - -void EXTAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate); -void EXTAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate); -void EXTAPI SAASNDSetOversample(SAASND object, unsigned int nOversample); - - -#ifdef __cplusplus -}; // extern "C" -#endif - -#endif // SAASNDC_H_INCLUDED diff --git a/src/sound/saasound/SAASound.cpp b/src/sound/saasound/SAASound.cpp deleted file mode 100755 index c5e33d862..000000000 --- a/src/sound/saasound/SAASound.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAASound.cpp - dummy function -// -////////////////////////////////////////////////////////////////////// - -#include - -// Provide something so the compiler doesn't optimise us out of existance -int SomeFunction () -{ - return 42; -} diff --git a/src/sound/saasound/SAASound.h b/src/sound/saasound/SAASound.h deleted file mode 100644 index a5e9265ac..000000000 --- a/src/sound/saasound/SAASound.h +++ /dev/null @@ -1,130 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// SAASound.h: interface for the CSAASound class. -// -// This corresponds to the public (exported) DLL interface, so all -// APIs and client factory methods belong here. -// -// Compatibility notes : the intention is for this to be fully backwards -// compatible across minor and patch versions. Any backwards breaking changes -// should be reflected as a major version increment. New functionality can be added -// in minor versions so long as backwards compatiblity is maintained -// -// Version 3.3.0 (4th Dec 2018) -// -////////////////////////////////////////////////////////////////////// - -#ifndef SAASOUND_H_INCLUDED -#define SAASOUND_H_INCLUDED - -// define this if you want to output diagnostic text and PCM files -//#define DEBUGSAA - -// Parameters for use with SetSoundParameters, for example, -// SetSoundParameters(SAAP_NOFILTER | SAAP_44100 | SAA_16BIT | SAA_STEREO); -// SAAP_FILTER_HIGHPASS_SIMPLE can be ORd with SAAP_FILTER_OVERSAMPLE64x/2x -#define SAAP_FILTER_HIGHPASS_SIMPLE 0x00000400 -#define SAAP_FILTER_OVERSAMPLE64x 0x00000300 -#define SAAP_FILTER_OVERSAMPLE2x 0x00000200 -#define SAAP_FILTER SAAP_FILTER_OVERSAMPLE2x -#define SAAP_NOFILTER 0x00000100 -#define SAAP_44100 0x00000030 -#define SAAP_22050 0x00000020 -#define SAAP_11025 0x00000010 -#define SAAP_16BIT 0x0000000c -#define SAAP_8BIT 0x00000004 -#define SAAP_STEREO 0x00000003 -#define SAAP_MONO 0x00000001 - -// Bitmasks for use with GetCurrentSoundParameters, for example, -// unsigned long CurrentSampleRateParameter = GetCurrentSoundParameters() -#define SAAP_MASK_FILTER 0x00000f00 -#define SAAP_MASK_FILTER_HIGHPASS 0x00000c00 -#define SAAP_MASK_FILTER_OVERSAMPLE 0x00000300 -#define SAAP_MASK_SAMPLERATE 0x000000030 -#define SAAP_MASK_BITDEPTH 0x0000000c -#define SAAP_MASK_CHANNELS 0x00000003 - -typedef unsigned long SAAPARAM; - - -#ifndef BYTE -#define BYTE unsigned char -#endif - -#ifdef _WIN32 -#define SAAAPI _stdcall -#else -#define SAAAPI -#endif - - -#ifdef __cplusplus - -class CSAASound -{ -public: - virtual ~CSAASound() { } - - virtual void SetSoundParameters (SAAPARAM uParam) = 0; - virtual void WriteAddress (BYTE nReg) = 0; - virtual void WriteData (BYTE nData) = 0; - virtual void WriteAddressData (BYTE nReg, BYTE nData) = 0; - virtual void Clear () = 0; - virtual BYTE ReadAddress () = 0; - - virtual SAAPARAM GetCurrentSoundParameters () = 0; - virtual unsigned long GetCurrentSampleRate () = 0; - static unsigned long GetSampleRate (SAAPARAM uParam); - virtual unsigned short GetCurrentBytesPerSample () = 0; - static unsigned short GetBytesPerSample (SAAPARAM uParam); - - virtual void GenerateMany (BYTE * pBuffer, unsigned long nSamples) = 0; - - virtual void SetClockRate(unsigned int nClockRate) = 0; - virtual void SetSampleRate(unsigned int nSampleRate) = 0; - virtual void SetOversample(unsigned int nOversample) = 0; -}; - -typedef class CSAASound * LPCSAASOUND; - -LPCSAASOUND SAAAPI CreateCSAASound(void); -void SAAAPI DestroyCSAASound(LPCSAASOUND object); - -#endif // __cplusplus - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void * SAASND; - -// "C-style" interface for the CSAASound class -SAASND SAAAPI newSAASND(void); -void SAAAPI deleteSAASND(SAASND object); - -void SAAAPI SAASNDSetSoundParameters(SAASND object, SAAPARAM uParam); -void SAAAPI SAASNDWriteAddress(SAASND object, BYTE nReg); -void SAAAPI SAASNDWriteData(SAASND object, BYTE nData); -void SAAAPI SAASNDWriteAddressData(SAASND object, BYTE nReg, BYTE nData); -void SAAAPI SAASNDClear(SAASND object); - -SAAPARAM SAAAPI SAASNDGetCurrentSoundParameters(SAASND object); -unsigned short SAAAPI SAASNDGetCurrentBytesPerSample(SAASND object); -unsigned short SAAAPI SAASNDGetBytesPerSample(SAAPARAM uParam); -unsigned long SAAAPI SAASNDGetCurrentSampleRate(SAASND object); -unsigned long SAAAPI SAASNDGetSampleRate(SAAPARAM uParam); - -void SAAAPI SAASNDGenerateMany(SAASND object, BYTE * pBuffer, unsigned long nSamples); -void SAAAPI SAASNDSetClockRate(SAASND object, unsigned int nClockRate); -void SAAAPI SAASNDSetSampleRate(SAASND object, unsigned int nSampleRate); -void SAAAPI SAASNDSetOversample(SAASND object, unsigned int nOversample); - -BYTE SAAAPI SAASNDReadAddress(SAASND object); - -#ifdef __cplusplus -}; // extern "C" -#endif - -#endif // SAASOUND_H_INCLUDED diff --git a/src/sound/saasound/defns.h b/src/sound/saasound/defns.h deleted file mode 100644 index e81d1c819..000000000 --- a/src/sound/saasound/defns.h +++ /dev/null @@ -1,59 +0,0 @@ -// Part of SAASound copyright 2020 Dave Hooper -// -// defns.h: compile-time configuration parameters -// -////////////////////////////////////////////////////////////////////// - -#ifndef DEFNS_H_INCLUDED -#define DEFNS_H_INCLUDED - -#define HAVE_CONFIG_H -#ifdef HAVE_CONFIG_H -// using CMAKE -#include "saasound_cmake_config.h" -#else - -// initial default SAA1099 crystal clock rate in HZ (can be changed subsequently by calling SetClockRate) -#define EXTERNAL_CLK_HZ 8000000 - -// define SAAFREQ_FIXED_CLOCKRATE if the above external clock rate is the only supported clock rate -// i.e. only support a single compile-time clock rate (=> this also prevents using the SetClockRate method) -#undef SAAFREQ_FIXED_CLOCKRATE -// #define SAAFREQ_FIXED_CLOCKRATE - -// initial default sample rate (audio samplerate) -#define SAMPLE_RATE_HZ 44100 - -// initial default oversample (audio quality) recommend 0<=oversample<=6 -#define DEFAULT_OVERSAMPLE 6 - -// Whether to dump out a log of all register and value changes and raw output pcm -//#define DEBUGSAA -#undef DEBUGSAA - -// the (default) names of the register output and pcm output log files. -// If you're using a config file, you can change these (or, if you enable -// debugging via the config file settings, but leave the filenames unspecified, -// it will use these defaults) -#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt" -#define DEBUG_SAA_PCM_LOG "debugsaa.pcm" -// Whether to include support for these debug logs via config file (only making -// sense if USE_CONFIG_FILE is also defined) - -// Whether to support a startup configuration file that is parsed at load time -// #undef USE_CONFIG_FILE -#define USE_CONFIG_FILE - -// and if so, what is its location -#ifdef USE_CONFIG_FILE -#define CONFIG_FILE_PATH "SAASound.cfg" -#endif // USE_CONFIG_FILE - -#define DEFAULT_UNBOOSTED_MULTIPLIER 11.35 - -#define DEFAULT_BOOST 1 - - -#endif // HAVE_CONFIG_H - -#endif // DEFNS_H_INCLUDED diff --git a/src/sound/saasound/resource.h b/src/sound/saasound/resource.h deleted file mode 100755 index 0b893bf3a..000000000 --- a/src/sound/saasound/resource.h +++ /dev/null @@ -1,15 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by SAASound.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/sound/saasound/saasound_cmake_config.h b/src/sound/saasound/saasound_cmake_config.h deleted file mode 100644 index da914a71b..000000000 --- a/src/sound/saasound/saasound_cmake_config.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#define EXTERNAL_CLK_HZ 7159090 -/* #undef SAAFREQ_FIXED_CLOCKRATE */ -#define SAMPLE_RATE_HZ 44100 -#define DEFAULT_OVERSAMPLE 6 -#define DEFAULT_UNBOOSTED_MULTIPLIER 11.3 -#define DEFAULT_BOOST 1 -/* #undef DEBUGSAA */ -#define DEBUG_SAA_REGISTER_LOG "debugsaa.txt" -#define DEBUG_SAA_PCM_LOG "debugsaa.pcm" - -/* #undef USE_CONFIG_FILE */ -#define CONFIG_FILE_PATH "SAASound.cfg" diff --git a/src/sound/saasound/types.h b/src/sound/saasound/types.h deleted file mode 100755 index 4eb62f485..000000000 --- a/src/sound/saasound/types.h +++ /dev/null @@ -1,34 +0,0 @@ -// Part of SAASound copyright 1998-2018 Dave Hooper -// -// handy typedefs -// -////////////////////////////////////////////////////////////////////// - -#ifndef TYPES_H_INCLUDED -#define TYPES_H_INCLUDED - -#if defined(__i386__) || defined(WIN32) || \ - (defined(__alpha__) || defined(__alpha)) || \ - defined(__arm__) || \ - (defined(__mips__) && defined(__MIPSEL__)) -#else -#define __BIG_ENDIAN -#endif - - -#ifndef NULL -#define NULL 0 -#endif - -typedef struct -{ - int nNumberOfPhases; - bool bLooping; - int nLevels[2][2][16]; // [Resolution][Phase][Withinphase] -} ENVDATA; - -#ifdef WIN32 -extern "C" void _stdcall OutputDebugStringA (char*); -#endif - -#endif diff --git a/src/sound/snd_cms.c b/src/sound/snd_cms.c index c6591b1fc..66dff80f3 100644 --- a/src/sound/snd_cms.c +++ b/src/sound/snd_cms.c @@ -8,7 +8,6 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> -#include "saasound/SAASound.h" #include <86box/snd_cms.h> #include <86box/sound.h> #include <86box/plat_unused.h> @@ -16,13 +15,62 @@ void cms_update(cms_t *cms) { - if (cms->pos < wavetable_pos_global) { - SAASNDGenerateMany(cms->saasound, (unsigned char*)&cms->buffer[cms->pos], wavetable_pos_global - cms->pos); - cms->pos = wavetable_pos_global; - } - if (cms->pos2 < wavetable_pos_global) { - SAASNDGenerateMany(cms->saasound2, (unsigned char*)&cms->buffer2[cms->pos2], wavetable_pos_global - cms->pos2); - cms->pos2 = wavetable_pos_global; + for (; cms->pos < sound_pos_global; cms->pos++) { + int16_t out_l = 0; + int16_t out_r = 0; + + for (uint8_t c = 0; c < 4; c++) { + switch (cms->noisetype[c >> 1][c & 1]) { + case 0: + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 256; + break; + case 1: + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 512; + break; + case 2: + cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK / 1024; + break; + case 3: + cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; + break; + + default: + break; + } + } + for (uint8_t c = 0; c < 2; c++) { + if (cms->regs[c][0x1C] & 1) { + for (uint8_t d = 0; d < 6; d++) { + if (cms->regs[c][0x14] & (1 << d)) { + if (cms->stat[c][d]) + out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) + out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } else if (cms->regs[c][0x15] & (1 << d)) { + if (cms->noise[c][d / 3] & 1) + out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) + out_r += (cms->vol[c][d][0] * 90); + } + } + for (uint8_t d = 0; d < 2; d++) { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } + } + cms->buffer[cms->pos << 1] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; } } @@ -39,39 +87,63 @@ cms_get_buffer(int32_t *buffer, int len, void *priv) cms->pos = 0; } -void -cms_get_buffer_2(int32_t *buffer, int len, void *priv) -{ - cms_t *cms = (cms_t *) priv; - - cms_update(cms); - - for (int c = 0; c < len * 2; c++) - buffer[c] += cms->buffer2[c]; - - cms->pos2 = 0; -} - void cms_write(uint16_t addr, uint8_t val, void *priv) { cms_t *cms = (cms_t *) priv; + int voice; + int chip = (addr & 2) >> 1; switch (addr & 0xf) { case 0x1: /* SAA #1 Register Select Port */ - SAASNDWriteAddress(cms->saasound, val & 31); + cms->addrs[0] = val & 31; break; case 0x3: /* SAA #2 Register Select Port */ - SAASNDWriteAddress(cms->saasound2, val & 31); + cms->addrs[1] = val & 31; break; case 0x0: /* SAA #1 Data Port */ - cms_update(cms); - SAASNDWriteData(cms->saasound, val); - break; case 0x2: /* SAA #2 Data Port */ cms_update(cms); - SAASNDWriteData(cms->saasound2, val); + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) { + case 0x00: + case 0x01: + case 0x02: /*Volume*/ + case 0x03: + case 0x04: + case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: + case 0x09: + case 0x0A: /*Frequency*/ + case 0x0B: + case 0x0C: + case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: + case 0x11: + case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (MASTER_CLOCK / 512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + + default: + break; + } break; case 0x6: /* GameBlaster Write Port */ @@ -91,9 +163,9 @@ cms_read(uint16_t addr, void *priv) switch (addr & 0xf) { case 0x1: /* SAA #1 Register Select Port */ - return SAASNDReadAddress(cms->saasound); + return cms->addrs[0]; case 0x3: /* SAA #2 Register Select Port */ - return SAASNDReadAddress(cms->saasound2); + return cms->addrs[1]; case 0x4: /* GameBlaster Read port (Always returns 0x7F) */ return 0x7f; case 0xa: /* GameBlaster Read Port */ @@ -113,12 +185,7 @@ cms_init(UNUSED(const device_t *info)) uint16_t addr = device_get_config_hex16("base"); io_sethandler(addr, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); - cms->saasound = newSAASND(); - SAASNDSetSoundParameters(cms->saasound, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); - cms->saasound2 = newSAASND(); - SAASNDSetSoundParameters(cms->saasound2, SAAP_44100 | SAAP_16BIT | SAAP_NOFILTER | SAAP_STEREO); - wavetable_add_handler(cms_get_buffer, cms); - wavetable_add_handler(cms_get_buffer_2, cms); + sound_add_handler(cms_get_buffer, cms); return cms; } @@ -127,9 +194,6 @@ cms_close(void *priv) { cms_t *cms = (cms_t *) priv; - deleteSAASND(cms->saasound); - deleteSAASND(cms->saasound2); - free(cms); } From cdae57e7b4a28cd70f86a13be0d48724127e3193 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Sun, 18 May 2025 21:05:23 +0300 Subject: [PATCH 0952/1190] Preliminary attempt at implementing the Dell OptiPlex GN+ --- src/include/86box/machine.h | 1 + src/machine/m_at_socket7.c | 34 ++++++++++++++++++++++++++++ src/machine/machine_table.c | 44 +++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c76761b3c..5153c4627 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -751,6 +751,7 @@ extern int machine_at_gw2kte_init(const machine_t *); extern int machine_at_ma23c_init(const machine_t *); extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); +extern int machine_at_optiplex_gn_init(const machine_t *); #ifdef USE_AN430TX extern int machine_at_an430tx_init(const machine_t *); #endif /* USE_AN430TX */ diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 319856d41..17c89e39d 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -969,6 +969,40 @@ machine_at_tx97_init(const machine_t *model) return ret; } +int +machine_at_optiplex_gn_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/optiplex_gn/Gn_a11.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */ + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + device_add(&i430tx_device); + device_add(&piix4_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87307_15c_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + return ret; +} + #ifdef USE_AN430TX int machine_at_an430tx_init(const machine_t *model) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 45986a50a..f28079888 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13103,6 +13103,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* According to Dell specifications, it can have either National Semiconductor PC87307 or PC87309 + Super I/O. All known instances have the former, although other similar Dells of the era have + pinouts for accompanying either so this likely also does. + + The KBC is likely an AMIKey-2 clone. */ + { + .name = "[i430TX] Dell OptiPlex GN+", + .internal_name = "optiplex_gn", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_optiplex_gn_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2500, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO, /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905 */ + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_trio64v2_dx_onboard_pci_device, /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS */ + .snd_device = NULL, + .net_device = NULL + }, /* [TEST] Has AMI Megakey '5' KBC firmware on the SM(S)C FDC37C67x Super I/O chip. */ { .name = "[i430TX] Gateway E-1000", From 9441b6f2cf04238f51c39d3e875ac76555ae0467 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 20:42:28 +0200 Subject: [PATCH 0953/1190] PC87309: Make the Super I/O chip relocatable. --- src/sio/sio_pc87309.c | 45 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index da53802c1..2219ede17 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -41,15 +41,19 @@ typedef struct pc87309_t { uint8_t regs[48]; uint8_t ld_regs[256][208]; uint8_t pm[8]; + uint8_t baddr; uint16_t pm_base; int cur_reg; fdc_t *fdc; serial_t *uart[2]; } pc87309_t; -static void fdc_handler(pc87309_t *dev); -static void lpt1_handler(pc87309_t *dev); -static void serial_handler(pc87309_t *dev, int uart); +static void fdc_handler(pc87309_t *dev); +static void lpt1_handler(pc87309_t *dev); +static void serial_handler(pc87309_t *dev, int uart); + +static void pc87309_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pc87309_read(uint16_t port, void *priv); static void pc87309_pm_write(uint16_t port, uint8_t val, void *priv) @@ -104,6 +108,26 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr) pc87309_pm_read, NULL, NULL, pc87309_pm_write, NULL, NULL, dev); } +static void +superio_handler(pc87309_t *dev) +{ + io_removehandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + io_removehandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + + switch (dev->baddr) { + case 2: + io_sethandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + break; + case 3: + io_sethandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + break; + } +} + static void fdc_handler(pc87309_t *dev) { @@ -197,6 +221,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) break; case 0x22: dev->regs[dev->cur_reg] = val & 0x7f; + superio_handler(dev); break; default: if (dev->cur_reg >= 0x30) { @@ -379,6 +404,7 @@ pc87309_reset(pc87309_t *dev) dev->regs[0x20] = dev->id; dev->regs[0x21] = 0x04; + dev->regs[0x22] = dev->baddr; dev->ld_regs[0x00][0x01] = 0x01; dev->ld_regs[0x00][0x30] = 0x03; @@ -453,6 +479,8 @@ pc87309_reset(pc87309_t *dev) serial_remove(dev->uart[0]); serial_remove(dev->uart[1]); fdc_reset(dev->fdc); + + superio_handler(dev); } static void @@ -472,19 +500,10 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->baddr = (info->local & 0x100) ? 2 : 3; pc87309_reset(dev); - if (info->local & 0x100) { - io_sethandler(0x15c, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - } else { - io_sethandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - } - return dev; } From a262a519cbba418fd918b5e1ef2828f34d5006eb Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 18 May 2025 20:48:29 +0200 Subject: [PATCH 0954/1190] PC87309: Actually fix relocation so it's implemented according to the PC87309 datasheet, not the PC87306 one. --- src/sio/sio_pc87309.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 2219ede17..5e417aefb 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -116,12 +116,16 @@ superio_handler(pc87309_t *dev) io_removehandler(0x02e, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - switch (dev->baddr) { - case 2: + switch (dev->regs[0x21] & 0x0b) { + case 0x02: + case 0x08: + case 0x0a: io_sethandler(0x15c, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); break; - case 3: + case 0x03: + case 0x09: + case 0x0b: io_sethandler(0x02e, 0x0002, pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); break; @@ -218,10 +222,10 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) case 0x07: case 0x21: dev->regs[dev->cur_reg] = val; + superio_handler(dev); break; case 0x22: dev->regs[dev->cur_reg] = val & 0x7f; - superio_handler(dev); break; default: if (dev->cur_reg >= 0x30) { @@ -403,8 +407,7 @@ pc87309_reset(pc87309_t *dev) memset(dev->pm, 0x00, 0x08); dev->regs[0x20] = dev->id; - dev->regs[0x21] = 0x04; - dev->regs[0x22] = dev->baddr; + dev->regs[0x21] = 0x04 | dev->baddr; dev->ld_regs[0x00][0x01] = 0x01; dev->ld_regs[0x00][0x30] = 0x03; @@ -500,7 +503,7 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->baddr = (info->local & 0x100) ? 2 : 3; + dev->baddr = (info->local & 0x100) ? 8 : 9; pc87309_reset(dev); From d5a63540067b599350e90669b871b7c75ecd4dea Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 15:53:39 +0300 Subject: [PATCH 0955/1190] Add the Dell OptiPlex GXL/GXM --- src/include/86box/machine.h | 1 + src/machine/m_at_socket5.c | 32 +++++++++++++++++++++++++++++ src/machine/machine_table.c | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c76761b3c..e9dc5bda9 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -672,6 +672,7 @@ extern int machine_at_tek932_init(const machine_t *); extern int machine_at_acerv30_init(const machine_t *); extern int machine_at_apollo_init(const machine_t *); +extern int machine_at_optiplex_gxl_init(const machine_t *); extern int machine_at_zappa_init(const machine_t *); extern int machine_at_powermatev_init(const machine_t *); extern int machine_at_hawk_init(const machine_t *); diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 4b3bbd49c..9981f8e85 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -236,6 +236,38 @@ machine_at_apollo_init(const machine_t *model) return ret; } +int +machine_at_optiplex_gxl_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/optiplex_gxl/DELL.ROM", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_VIDEO, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87332_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + static void machine_at_zappa_gpio_init(void) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 45986a50a..d9e6f2940 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10553,6 +10553,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a National Semiconductor PC87332VLJ Super I/O with AMIKey 'F' KBC firmware. */ + { + .name = "[i430FX] Dell OptiPlex GXL/GXM", + .internal_name = "optiplex_gxl", + .type = MACHINE_TYPE_SOCKET5, + .chipset = MACHINE_CHIPSET_INTEL_430FX, + .init = machine_at_optiplex_gxl_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 3380, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM, /* Video: S3 Trio64V+ (86C765), Network: 3Com ETHERLINK III (3C509B) */ + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_phoenix_trio64vplus_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL /* not yet emulated */ + }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the PC87306 Super I/O chip, command 0xA1 returns '5'. Command 0xA0 copyright string: (C)1994 AMI . */ From ec613f16085fe70ce6fe02518f0e716cc2117a58 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 16:18:32 +0300 Subject: [PATCH 0956/1190] Add the onboard sound for the OptiPlex GXL/GXM --- src/machine/m_at_socket5.c | 4 ++++ src/machine/machine_table.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 9981f8e85..7c5ab697a 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -40,6 +40,7 @@ #include <86box/sio.h> #include <86box/video.h> #include <86box/machine.h> +#include <86box/sound.h> int machine_at_plato_init(const machine_t *model) @@ -259,6 +260,9 @@ machine_at_optiplex_gxl_init(const machine_t *model) if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); + if (sound_card_current[0] == SOUND_INTERNAL) + machine_snd = device_add(machine_get_snd_device(machine)); + device_add(&keyboard_ps2_ami_pci_device); device_add(&i430fx_device); device_add(&piix_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d9e6f2940..3e50442c1 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10575,7 +10575,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM, /* Video: S3 Trio64V+ (86C765), Network: 3Com ETHERLINK III (3C509B) */ + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM, /* Video: S3 Trio64V+ (86C765), Sound: Creative ViBRA 16S (CT2504), Network: 3Com ETHERLINK III (3C509B) */ .ram = { .min = 8192, .max = 131072, @@ -10590,7 +10590,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = &s3_phoenix_trio64vplus_onboard_pci_device, - .snd_device = NULL, + .snd_device = &sb_vibra16s_onboard_device, .net_device = NULL /* not yet emulated */ }, /* According to tests from real hardware: This has AMI MegaKey KBC firmware on the From d7282ddc46d2059cf1973d0b07d8dacfd5592850 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 16:28:01 +0300 Subject: [PATCH 0957/1190] Block the Cyrix Cx6x86 from the Dell OptiPlex GXL/GXM as it cannot POST with it --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3e50442c1..f4031c0b7 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10566,7 +10566,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK_NONE, + .block = CPU_BLOCK(CPU_Cx6x86), .min_bus = 60000000, .max_bus = 66666667, .min_voltage = 3380, From e04628cc7cf13131f872c8bc8304eb0c29fa8fbf Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 19 May 2025 19:25:21 +0200 Subject: [PATCH 0958/1190] Trident pattern and memory access changes (May 19th, 2025) 1. DirectDraw memory address fixes of the day (removing the bit 6 of crtc 2a side of the if in recalctimings). 2. In spite of no documentration or NDA manuals, get data from the pattern registers as best as possible in 32bpp mode, this fixes patterns in 32bpp mode using various stuff. --- src/video/vid_tgui9440.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index af203f327..6fbdb7c3f 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -125,6 +125,7 @@ typedef struct tgui_t { uint8_t rop; uint32_t flags; uint8_t pattern[0x80]; + uint8_t pattern_32bpp[0x100]; int command; int offset; uint16_t ger22; @@ -142,6 +143,7 @@ typedef struct tgui_t { uint32_t pattern_8[8 * 8]; uint32_t pattern_16[8 * 8]; uint32_t pattern_32[8 * 8]; + int pattern_32_idx; } accel; uint8_t copy_latch[16]; /*TGUI9400CXi only*/ @@ -756,7 +758,7 @@ tgui_recalctimings(svga_t *svga) if (svga->vdisp == 1020) svga->vdisp += 2; - if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + if (tgui->oldctrl2 & 0x10) svga->ma_latch <<= 1; svga->lowres = !(svga->crtc[0x2a] & 0x40); @@ -2280,6 +2282,8 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) if (count == -1) tgui->accel.x = tgui->accel.y = 0; + tgui->accel.pattern_32_idx = 0; + if (tgui->accel.flags & TGUI_SOLIDFILL) { for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { @@ -2298,22 +2302,21 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) if (tgui->accel.bpp == 0) { for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { - tgui->accel.pattern_8[(y * 8) + (7 - x)] = tgui->accel.pattern[x + y * 8]; + tgui->accel.pattern_8[(y * 8) + x] = tgui->accel.pattern[x + y * 8]; } } pattern_data = tgui->accel.pattern_8; } else if (tgui->accel.bpp == 1) { for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { - tgui->accel.pattern_16[(y * 8) + (7 - x)] = tgui->accel.pattern[x * 2 + y * 16] | (tgui->accel.pattern[x * 2 + y * 16 + 1] << 8); + tgui->accel.pattern_16[(y * 8) + x] = tgui->accel.pattern[x * 2 + y * 16] | (tgui->accel.pattern[x * 2 + y * 16 + 1] << 8); } } pattern_data = tgui->accel.pattern_16; } else { - for (y = 0; y < 4; y++) { + for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { - tgui->accel.pattern_32[(y * 8) + (7 - x)] = tgui->accel.pattern[x * 4 + y * 32] | (tgui->accel.pattern[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern[x * 4 + y * 32 + 3] << 24); - tgui->accel.pattern_32[((y + 4) * 8) + (7 - x)] = tgui->accel.pattern[x * 4 + y * 32] | (tgui->accel.pattern[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern[x * 4 + y * 32 + 3] << 24); + tgui->accel.pattern_32[(y * 8) + x] = tgui->accel.pattern_32bpp[x * 4 + y * 32] | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 1] << 8) | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 2] << 16) | (tgui->accel.pattern_32bpp[x * 4 + y * 32 + 3] << 24); } } pattern_data = tgui->accel.pattern_32; @@ -2396,6 +2399,7 @@ tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) count -= 3; } + READ(tgui->accel.dst, dst_dat); pat_dat = pattern_data[((tgui->accel.pat_y & 7) * 8) + (tgui->accel.pat_x & 7)]; @@ -3192,6 +3196,8 @@ tgui_accel_out(uint16_t addr, uint8_t val, void *priv) case 0x21fe: case 0x21ff: tgui->accel.pattern[addr & 0x7f] = val; + tgui->accel.pattern_32bpp[tgui->accel.pattern_32_idx] = val; + tgui->accel.pattern_32_idx = (tgui->accel.pattern_32_idx + 1) & 0xff; break; default: From 9f46d0b9d8c700e5c04d89e4229958a75906e310 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Mon, 19 May 2025 20:59:08 +0300 Subject: [PATCH 0959/1190] Fix the initialization and general purpose I/O (GPIO) pins for the OptiPlex GXL/GXM --- src/device/kbc_at.c | 11 ++++++++++- src/machine/m_at_socket5.c | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 58aab476c..7413b45cf 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1096,7 +1096,16 @@ write64_generic(void *priv, uint8_t val) - Bit 5: Manufacturing jumper (must be set); */ uint8_t p1 = 0x24; - kbc_delay_to_ob(dev, p1, 0, 0x01); + kbc_delay_to_ob(dev, p1, 0, 0x00); + } else if (!strcmp(machine_get_internal_name(), "optiplex_gxl")) { + /* + Dell OptiPlex GXL/GXM: + - Bit 3: Password disable jumper (must be clear); + - Bit 4: Keyboard fuse (must be set); + - Bit 5: Manufacturing jumper (must be set); + */ + uint8_t p1 = 0x30; + kbc_delay_to_ob(dev, p1, 0, 0x00); } else { /* (B0 or F0) | (0x08 or 0x0c) */ uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 7c5ab697a..5572d0484 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -248,7 +248,8 @@ machine_at_optiplex_gxl_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); @@ -263,7 +264,7 @@ machine_at_optiplex_gxl_init(const machine_t *model) if (sound_card_current[0] == SOUND_INTERNAL) machine_snd = device_add(machine_get_snd_device(machine)); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_phoenix_pci_device); device_add(&i430fx_device); device_add(&piix_device); device_add(&pc87332_device); From dbc2baebe915f443e5ce0cb6c81739cdc0cd9d1e Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 19 May 2025 22:22:03 +0200 Subject: [PATCH 0960/1190] Small ATI Mach8 changes (May 19th, 2025) 1. Report the ATI 28800 of the Graphics Ultra as 28800-6. 2. Access the upper word properly on vdisp. 3. Make sure there's enough vsyncstart/vtotal space for a full vertical display. --- src/video/vid_ati_mach8.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 8423f096b..a9544e724 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2510,6 +2510,12 @@ mach_in(uint16_t addr, void *priv) case 0xa9: temp = svga->vc & 0xff; break; + case 0xaa: + if (ATI_GRAPHICS_ULTRA) + temp = 0x06; + else + temp = 0x00; + break; case 0xb0: temp = mach->regs[0xb0] | 0x80; temp &= ~0x18; @@ -2699,12 +2705,10 @@ mach_set_resolution(mach_t *mach, svga_t *svga) dev->vdisp += 2; dev->v_total = dev->v_total_reg + 1; - if (dev->interlace) - dev->v_total >>= 1; dev->v_syncstart = dev->v_sync_start + 1; - if (dev->interlace) - dev->v_syncstart >>= 1; + + mach_log("VSYNCSTART=%d, VTOTAL=%d, interlace=%02x, vdisp=%d.\n", dev->v_syncstart, dev->v_total, dev->interlace, dev->vdisp); if (ATI_8514A_ULTRA) { if ((mach->accel.clock_sel & 0x01) && @@ -3233,7 +3237,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (len == 1) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x20)) { - WRITE8(port, dev->v_disp, val); + WRITE8(port, dev->v_disp, val >> 8); dev->v_disp &= 0x1fff; } } @@ -3267,7 +3271,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u if (len == 1) { if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/ if (!(mach->shadow_cntl & 0x10)) { - WRITE8(port, dev->v_sync_start, val); + WRITE8(port, dev->v_sync_start, val >> 8); dev->v_sync_start &= 0x1fff; } } From 06f4491193967cec42871b0748bf73f3d68cc6f0 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 20 May 2025 20:33:22 +0200 Subject: [PATCH 0961/1190] Mach8 mode changes of the day (May 20th, 2025) Make the previously Mach8 add-on only mode changes also available to the Graphics Ultra, should fix incorrect resolutions after switching from fullscreen DOS prompt to windowed and viceversa under Win98 (and SE). --- src/video/vid_ati_mach8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index a9544e724..0b5673d69 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2710,7 +2710,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) mach_log("VSYNCSTART=%d, VTOTAL=%d, interlace=%02x, vdisp=%d.\n", dev->v_syncstart, dev->v_total, dev->interlace, dev->vdisp); - if (ATI_8514A_ULTRA) { + if (!ATI_MACH32) { if ((mach->accel.clock_sel & 0x01) && !(dev->accel.advfunc_cntl & 0x01)) ret = 2; From 39a3d1ded022201f2a48f0d63646ba2ece313682 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 21 May 2025 14:04:55 +0600 Subject: [PATCH 0962/1190] Backport RxConfig fixes from QEMU --- src/network/net_rtl8139.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/net_rtl8139.c b/src/network/net_rtl8139.c index 5138b5168..0d07a8f83 100644 --- a/src/network/net_rtl8139.c +++ b/src/network/net_rtl8139.c @@ -2549,6 +2549,12 @@ rtl8139_io_writeb(uint32_t addr, uint8_t val, void *priv) break; + case RxConfig: + rtl8139_log("RxConfig write(b) val=0x%02x\n", val); + rtl8139_RxConfig_write(s, + (rtl8139_RxConfig_read(s) & 0xFFFFFF00) | val); + break; + default: rtl8139_log("not implemented write(b) addr=0x%x val=0x%02x\n", addr, val); break; From accce358e8231aca604336df4925d2b643a7e6af Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Wed, 21 May 2025 12:04:55 +0300 Subject: [PATCH 0963/1190] Fix the Password "Disabled by Jumper" error on Dimension XPS Pxxx and Pxxxa/Mxxxa --- src/device/kbc_at.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 7413b45cf..60ca29fc1 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1106,6 +1106,14 @@ write64_generic(void *priv, uint8_t val) */ uint8_t p1 = 0x30; kbc_delay_to_ob(dev, p1, 0, 0x00); + } else if (!strcmp(machine_get_internal_name(), "dellplato") | !strcmp(machine_get_internal_name(), "dellhannibalp")) { + /* + Dell Dimension XPS Pxxx & Pxxxa/Mxxxa: + - Bit 3: Password disable jumper (must be clear); + - Bit 4: Clear CMOS jumper (must be set); + */ + uint8_t p1 = 0x10; + kbc_delay_to_ob(dev, p1, 0, 0x00); } else { /* (B0 or F0) | (0x08 or 0x0c) */ uint8_t p1_out = ((dev->p1 | fixed_bits) & 0xf0) | From b18f69c037060ae0ccc79457a138da0d52c061b0 Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Wed, 21 May 2025 12:18:54 +0300 Subject: [PATCH 0964/1190] Fix a small typo that causes some checks to fail --- src/device/kbc_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 60ca29fc1..7b6bea0c4 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1106,7 +1106,7 @@ write64_generic(void *priv, uint8_t val) */ uint8_t p1 = 0x30; kbc_delay_to_ob(dev, p1, 0, 0x00); - } else if (!strcmp(machine_get_internal_name(), "dellplato") | !strcmp(machine_get_internal_name(), "dellhannibalp")) { + } else if (!strcmp(machine_get_internal_name(), "dellplato") || !strcmp(machine_get_internal_name(), "dellhannibalp")) { /* Dell Dimension XPS Pxxx & Pxxxa/Mxxxa: - Bit 3: Password disable jumper (must be clear); From e76a89bcc80cb693efaa9f6165df8868add35f11 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 13:32:17 +0200 Subject: [PATCH 0965/1190] Windows: Change cursor clipping from cursor warping to ClipCursor(), fixes #5498. --- src/qt/qt_rendererstack.cpp | 16 +++++++++++++++- src/qt/qt_ui.cpp | 23 +++++++++++++++++++++++ src/qt/qt_winrawinputfilter.cpp | 4 ++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 79fa78097..c210f4dc2 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -61,6 +61,11 @@ struct mouseinputdata { static mouseinputdata mousedata; extern MainWindow *main_window; + +#ifdef Q_OS_WINDOWS +HWND rw_hwnd; +#endif + RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) @@ -251,7 +256,9 @@ RendererStack::mouseMoveEvent(QMouseEvent *event) leaveEvent((QEvent *) event); ignoreNextMouseEvent--; } +#if !defined _WIN32 QCursor::setPos(mapToGlobal(QPoint(width() / 2, height() / 2))); +#endif ignoreNextMouseEvent = 2; oldPos = event->pos(); #endif @@ -405,8 +412,15 @@ RendererStack::createRenderer(Renderer renderer) } #endif } - if (current.get() == nullptr) + if (current.get() == nullptr) { +#ifdef Q_OS_WINDOWS + rw_hwnd = NULL; +#endif return; + } +#ifdef Q_OS_WINDOWS + rw_hwnd = (HWND) this->winId(); +#endif current->setFocusPolicy(Qt::NoFocus); current->setFocusProxy(this); current->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 5a6bda852..e54d64269 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "qt_mainwindow.hpp" #include "qt_machinestatus.hpp" @@ -122,6 +123,8 @@ plat_resize(int w, int h, int monitor_index) main_window->resizeContents(w, h); } +extern HWND rw_hwnd; + void plat_mouse_capture(int on) { @@ -129,6 +132,26 @@ plat_mouse_capture(int on) return; main_window->setMouseCapture(on > 0 ? true : false); + +#if defined _WIN32 + if (on) { + QCursor cursor(Qt::BlankCursor); + + QApplication::setOverrideCursor(cursor); + QApplication::changeOverrideCursor(cursor); + + RECT rect; + + GetWindowRect(rw_hwnd, &rect); + + ClipCursor(&rect); + + } else { + ClipCursor(NULL); + + QApplication::restoreOverrideCursor(); + } +#endif } int diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index e94101a77..a62d71920 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -395,7 +395,7 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) mouse_scale(delta_x, delta_y); - HWND wnd = (HWND)window->winId(); + /* HWND wnd = (HWND)window->winId(); RECT rect; @@ -404,5 +404,5 @@ WindowsRawInputFilter::mouse_handle(PRAWINPUT raw) int left = rect.left + (rect.right - rect.left) / 2; int top = rect.top + (rect.bottom - rect.top) / 2; - SetCursorPos(left, top); + SetCursorPos(left, top); */ } From 75e76899da86b832e9d6631bf1a5c9a4d4cc1e5b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 21 May 2025 13:43:23 +0200 Subject: [PATCH 0966/1190] S3 911/924 high color: check if rd_mask is not 0 (May 21st, 2025) This fixes wrong colors in certain instances of Windows 95 builds' 911/924 drivers. --- src/video/vid_s3.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 683d2be34..99521f061 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8042,7 +8042,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.sy = s3->accel.maj_axis_pcnt; if ((s3->bpp == 0) && s3->color_16bit) { - s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask; if (s3->accel.rd_mask_16bit_check) { if ((s3->accel.cur_x_overflow & 0xc00) == 0xc00) s3->accel.start = 1; @@ -8353,7 +8353,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.dest = dstbase + s3->accel.cy * s3->width; if ((s3->bpp == 0) && s3->color_16bit) { - s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask; if (s3->accel.rd_mask_16bit_check) { if (s3->accel.cmd == 0x41b3) { if (frgd_mix == 0) { @@ -8478,9 +8478,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi if ((s3_cpu_src(s3)) && !(s3->accel.cmd & 0x200)) { s3_log("FIXME: S3 911/924 15/16bpp documentation needed.\n"); } else { - if (!cpu_input && (s3->accel.cur_x & 0x400)) + if (!cpu_input && (s3->accel.cur_x & 0x400)) { + s3_log("No Input.\n"); break; - else if (cpu_input && (s3->accel.cmd == 0x53b3) && (s3->accel.cur_x & 0x400)) + } else if (cpu_input && (s3->accel.cmd == 0x53b3) && (s3->accel.cur_x & 0x400)) break; } } @@ -8756,7 +8757,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3->accel.cy = s3->accel.cur_y & 0xfff; if ((s3->bpp == 0) && s3->color_16bit) { - s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00); + s3->accel.rd_mask_16bit_check = ((rd_mask & 0xff00) != 0xff00) && rd_mask; if (s3->accel.rd_mask_16bit_check) { if (!(clip_r & 0x400)) s3->accel.start = 1; @@ -8805,7 +8806,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, voi s3_log("CMDFULL=%04x, FRGDSEL=%x, BKGDSEL=%x, FRGDMIX=%02x, BKGDMIX=%02x, MASKCHECK=%x, RDMASK=%04x, MINUS=%d, WRTMASK=%04X, MIX=%04x, CX=%d, CY=%d, DX=%d, DY=%d, SX=%d, SY=%d, PIXCNTL=%02x, 16BITCOLOR=%x, RDCHECK=%x, CLIPL=%d, CLIPR=%d, OVERFLOW=%d, pitch=%d.\n", s3->accel.cmd, frgd_mix, bkgd_mix, s3->accel.frgd_mix & 0x0f, s3->accel.bkgd_mix & 0x0f, s3->accel.rd_mask_16bit_check, rd_mask, s3->accel.minus, wrt_mask, mix_dat & 0xffff, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy, s3->accel.sx, s3->accel.sy, s3->accel.multifunc[0x0a] & 0xc4, s3->accel.color_16bit_check, s3->accel.rd_mask_16bit_check, clip_l, clip_r, (s3->accel.destx_overflow & 0xc00) == 0xc00, s3->width); if (!cpu_input && (frgd_mix == 3) && !vram_mask && !(s3->accel.multifunc[0xe] & 0x100) && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { - pclog("Special BitBLT.\n"); + s3_log("Special BitBLT.\n"); while (1) { if ((s3->accel.dx >= clip_l) && (s3->accel.dx <= clip_r) && (s3->accel.dy >= clip_t) && (s3->accel.dy <= clip_b)) { READ(s3->accel.src + s3->accel.cx - s3->accel.minus, src_dat); From 05ac5b62b0364019a7e229f81d05685c0dd9e719 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 13:45:12 +0200 Subject: [PATCH 0967/1190] Add some forgotten #ifdef. --- src/qt/qt_ui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index e54d64269..6e0b3cfbb 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -123,7 +123,9 @@ plat_resize(int w, int h, int monitor_index) main_window->resizeContents(w, h); } +#if defined _WIN32 extern HWND rw_hwnd; +#endif void plat_mouse_capture(int on) From 07c1bb5534d92694e4441d0e835722711c6c986b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 22 May 2025 00:19:57 +0600 Subject: [PATCH 0968/1190] Fix cursor clipping on Windows --- src/qt/qt_rendererstack.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index c210f4dc2..31cc495b0 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -663,6 +663,14 @@ RendererStack::setFocusRenderer() void RendererStack::onResize(int width, int height) { +#ifdef Q_OS_WINDOWS + if (mouse_capture) { + RECT rect; + if (GetWindowRect((HWND)this->winId(), &rect)) { + ClipCursor(&rect); + } + } +#endif if (rendererWindow) { rendererWindow->r_monitor_index = m_monitor_index; rendererWindow->onResize(width, height); From 455622492bbd1d129938638071f92e8300e4a18e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 20:49:54 +0200 Subject: [PATCH 0969/1190] All the required fixes - the Dell OptiPlex Gn+ now works correctly. --- src/acpi.c | 8 +- src/chipset/intel_piix.c | 39 +- src/device/kbc_at.c | 381 +++++++++++------- src/device/postcard.c | 54 +++ src/dma.c | 2 +- src/floppy/fdc.c | 25 +- src/include/86box/fdc.h | 1 + src/include/86box/keyboard.h | 4 +- src/include/86box/sio.h | 18 +- src/lpt.c | 4 +- src/machine/m_at_slot1.c | 2 +- src/machine/m_at_slot2.c | 2 +- src/machine/m_at_socket7.c | 13 +- src/machine/m_at_socket8.c | 9 +- src/machine/machine_table.c | 20 +- src/nvr_at.c | 5 +- src/sio/sio_fdc37c93x.c | 2 +- src/sio/sio_pc87307.c | 750 +++++++++++++++++++++++------------ src/sio/sio_pc87309.c | 643 +++++++++++++++++++----------- 19 files changed, 1310 insertions(+), 672 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index e9549adb0..e7a0de53d 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -36,6 +36,7 @@ #include <86box/pit.h> #include <86box/apm.h> #include <86box/acpi.h> +#include <86box/dma.h> #include <86box/machine.h> #include <86box/i2c.h> #include <86box/video.h> @@ -1025,8 +1026,13 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p nvr_reg_write(0x000f, 0xff, dev->nvr); } - if (sus_typ & SUS_RESET_PCI) + if (sus_typ & SUS_RESET_PCI) { + /* DMA is part of the southbridge so it responds to PCI reset. */ + dma_reset(); + dma_set_at(1); + device_reset_all(DEVICE_PCI); + } if (sus_typ & SUS_RESET_CPU) cpu_alt_reset = 0; diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index ed9fd9460..b73285f70 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -155,6 +155,7 @@ piix_ide_handlers(piix_t *dev, int bus) uint16_t side; if (bus & 0x01) { + piix_log("Disabling primary IDE...\n"); ide_pri_disable(); if (dev->type == 5) { @@ -170,11 +171,14 @@ piix_ide_handlers(piix_t *dev, int bus) ide_set_side(0, side); } - if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80)) + if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80)) { + piix_log("Enabling primary IDE...\n"); ide_pri_enable(); + } } if (bus & 0x02) { + piix_log("Disabling secondary IDE...\n"); ide_sec_disable(); if (dev->type == 5) { @@ -190,8 +194,10 @@ piix_ide_handlers(piix_t *dev, int bus) ide_set_side(1, side); } - if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80)) + if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80)) { + piix_log("Enabling secondary IDE...\n"); ide_sec_enable(); + } } } @@ -465,6 +471,13 @@ piix_write(int func, int addr, uint8_t val, void *priv) uint8_t *fregs; uint16_t base; + /* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */ + if ((dev->type == 4) && (func == 1) && (addr == 0xff)) + func = 2; + + if ((func == 1) || (addr == 0xf8) || (addr == 0xf9)) + piix_log("[W] %02X:%02X = %02X\n", func, addr, val); + /* Return on unsupported function. */ if (dev->max_func > 0) { if (func > dev->max_func) @@ -736,6 +749,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) fregs[addr] = val; break; case 0xb0: + if (val & 0x10) + warning("Write %02X to B0\n", val); if (dev->type == 4) fregs[addr] = (fregs[addr] & 0x8c) | (val & 0x73); else if (dev->type == 5) @@ -745,6 +760,8 @@ piix_write(int func, int addr, uint8_t val, void *priv) alt_access = !!(val & 0x20); break; case 0xb1: + if (val & 0x18) + warning("Write %02X to B1\n", val); if (dev->type > 3) fregs[addr] = val & 0xdf; break; @@ -923,6 +940,12 @@ piix_write(int func, int addr, uint8_t val, void *priv) if (dev->type > 4) fregs[addr] = val; break; + case 0xf8: + case 0xf9: + /* Undocumented! */ + if (dev->type == 4) + fregs[addr] = val; + break; default: break; } @@ -1169,6 +1192,10 @@ piix_read(int func, int addr, void *priv) uint8_t ret = 0xff; const uint8_t *fregs; + /* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */ + if ((dev->type == 4) && (func == 1) && (addr == 0xff)) + func = 2; + if ((dev->type == 3) && (func == 2) && (dev->max_func == 1) && (addr >= 0x40)) ret = 0x00; @@ -1199,7 +1226,7 @@ piix_reset_hard(piix_t *dev) sff_set_slot(dev->bm[1], dev->pci_slot); sff_set_irq_pin(dev->bm[1], PCI_INTA); - sff_set_irq_line(dev->bm[1], 14); + sff_set_irq_line(dev->bm[1], 15); sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY); } @@ -1315,6 +1342,10 @@ piix_reset_hard(piix_t *dev) fregs[0x45] = 0x55; fregs[0x46] = 0x01; } + if (dev->type == 4) { + fregs[0xf8] = 0x30; + fregs[0xf9] = 0x0f; + } if ((dev->type == 1) && (dev->rev == 2)) dev->max_func = 0; /* It starts with IDE disabled, then enables it. */ else @@ -1678,7 +1709,7 @@ const device_t piix4_device = { .name = "Intel 82371AB/EB (PIIX4/PIIX4E)", .internal_name = "piix4", .flags = DEVICE_PCI, - .local = 0x71100004, + .local = 0x71100014, .init = piix_init, .close = piix_close, .reset = piix_reset, diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 58aab476c..78fc32ffd 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -145,6 +145,11 @@ typedef struct atkbc_t { /* Internal FIFO for the purpose of commands with multi-byte output. */ uint8_t key_ctrl_queue[64]; + uint8_t handler_enable[2]; + + uint16_t base_addr[2]; + uint16_t irq[2]; + uint32_t flags; /* Main timers. */ @@ -157,8 +162,13 @@ typedef struct atkbc_t { /* Local copies of the pointers to both ports for easier swapping (AMI '5' MegaKey). */ kbc_at_port_t *ports[2]; - uint8_t (*write60_ven)(void *priv, uint8_t val); - uint8_t (*write64_ven)(void *priv, uint8_t val); + struct { + uint8_t (*read)(uint16_t port, void *priv); + void (*write)(uint16_t port, uint8_t val, void *priv); + } handlers[2]; + + uint8_t (*write_cmd_data_ven)(void *priv, uint8_t val); + uint8_t (*write_cmd_ven)(void *priv, uint8_t val); } atkbc_t; /* Keyboard controller ports. */ @@ -167,8 +177,6 @@ kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL }; static uint8_t kbc_ami_revision = '8'; static uint8_t kbc_award_revision = 0x42; -static uint8_t kbc_handler_set = 0; - static void (*kbc_at_do_poll)(atkbc_t *dev); /* Non-translated to translated scan codes. */ @@ -362,12 +370,19 @@ kbc_do_irq(atkbc_t *dev) if (dev->do_irq) { /* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */ - picint_common(1 << 1, 0, 0, NULL); - picint_common(1 << 12, 0, 0, NULL); - if (dev->channel >= 2) - picint_common(1 << 12, 0, 1, NULL); - else - picint_common(1 << 1, 0, 1, NULL); + if (dev->irq[0] != 0xffff) + picint_common(1 << dev->irq[0], 0, 0, NULL); + + if (dev->irq[1] != 0xffff) + picint_common(1 << dev->irq[1], 0, 0, NULL); + + if (dev->channel >= 2) { + if (dev->irq[1] != 0xffff) + picint_common(1 << dev->irq[1], 0, 1, NULL); + } else { + if (dev->irq[0] != 0xffff) + picint_common(1 << dev->irq[0], 0, 1, NULL); + } dev->do_irq = 0; } @@ -404,7 +419,9 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) } else if (dev->mem[0x20] & 0x01) kbc_set_do_irq(dev, channel); } else if (dev->mem[0x20] & 0x01) - picintlevel(1 << 1, &dev->irq_state); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */ + /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */ + if (dev->irq[0] != 0xffff) + picintlevel(1 << dev->irq[0], &dev->irq_state); #ifdef WRONG_CONDITION if ((dev->channel > 0) || dev->is_asic || (kbc_ven == KBC_VEN_IBM_PS1) || (kbc_ven == KBC_VEN_IBM)) @@ -784,10 +801,12 @@ write_p2(atkbc_t *dev, uint8_t val) /* PS/2: Handle IRQ's. */ if (dev->misc_flags & FLAG_PS2) { /* IRQ 12 */ - picint_common(1 << 12, 0, val & 0x20, NULL); + if (dev->irq[1] != 0xffff) + picint_common(1 << dev->irq[1], 0, val & 0x20, NULL); /* IRQ 1 */ - picint_common(1 << 1, 0, val & 0x10, NULL); + if (dev->irq[0] != 0xffff) + picint_common(1 << dev->irq[0], 0, val & 0x10, NULL); } #endif @@ -932,7 +951,7 @@ pulse_poll(void *priv) } static uint8_t -write64_generic(void *priv, uint8_t val) +write_cmd_generic(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; uint8_t current_drive; @@ -1161,7 +1180,7 @@ write64_generic(void *priv, uint8_t val) } static uint8_t -write60_ami(void *priv, uint8_t val) +write_cmd_data_ami(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1231,7 +1250,7 @@ kbc_at_set_ps2(void *priv, const uint8_t ps2) } static uint8_t -write64_ami(void *priv, uint8_t val) +write_cmd_ami(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; @@ -1436,11 +1455,11 @@ write64_ami(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static uint8_t -write60_phoenix(void *priv, uint8_t val) +write_cmd_data_phoenix(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1513,7 +1532,7 @@ write60_phoenix(void *priv, uint8_t val) } static uint8_t -write64_phoenix(void *priv, uint8_t val) +write_cmd_phoenix(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1659,11 +1678,11 @@ write64_phoenix(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static uint8_t -write64_siemens(void *priv, uint8_t val) +write_cmd_siemens(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1692,11 +1711,11 @@ write64_siemens(void *priv, uint8_t val) break; } - return write64_ami(dev, val); + return write_cmd_ami(dev, val); } static uint8_t -write60_quadtel(void *priv, UNUSED(uint8_t val)) +write_cmd_data_quadtel(void *priv, UNUSED(uint8_t val)) { const atkbc_t *dev = (atkbc_t *) priv; @@ -1713,7 +1732,7 @@ write60_quadtel(void *priv, UNUSED(uint8_t val)) } static uint8_t -write64_olivetti(void *priv, uint8_t val) +write_cmd_olivetti(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1734,11 +1753,11 @@ write64_olivetti(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static uint8_t -write64_quadtel(void *priv, uint8_t val) +write_cmd_quadtel(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1757,11 +1776,11 @@ write64_quadtel(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static uint8_t -write60_toshiba(void *priv, uint8_t val) +write_cmd_data_toshiba(void *priv, uint8_t val) { const atkbc_t *dev = (atkbc_t *) priv; @@ -1779,7 +1798,7 @@ write60_toshiba(void *priv, uint8_t val) } static uint8_t -write64_toshiba(void *priv, uint8_t val) +write_cmd_toshiba(void *priv, uint8_t val) { atkbc_t *dev = (atkbc_t *) priv; @@ -1868,7 +1887,7 @@ write64_toshiba(void *priv, uint8_t val) break; } - return write64_generic(dev, val); + return write_cmd_generic(dev, val); } static void @@ -1912,8 +1931,10 @@ kbc_at_process_cmd(void *priv) /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ dev->p1 = dev->p1 & 0xff; write_p2(dev, 0x4b); - picintc(0x1000); - picintc(0x0002); + if (dev->irq[1] != 0xffff) + picintc(1 << dev->irq[1]); + if (dev->irq[0] != 0xffff) + picintc(1 << dev->irq[0]); } dev->status = (dev->status & 0x0f) | 0x60; @@ -1932,7 +1953,8 @@ kbc_at_process_cmd(void *priv) /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ dev->p1 = dev->p1 & 0xff; write_p2(dev, 0xcf); - picintclevel(0x0002, &dev->irq_state); + if (dev->irq[0] != 0xffff) + picintclevel(1 << dev->irq[0], &dev->irq_state); dev->irq_state = 0; } @@ -2047,8 +2069,8 @@ kbc_at_process_cmd(void *priv) * that. Otherwise, or if that handler fails, * log a bad command. */ - if (dev->write64_ven) - bad = dev->write64_ven(dev, dev->ib); + if (dev->write_cmd_ven) + bad = dev->write_cmd_ven(dev, dev->ib); kbc_at_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib); } @@ -2134,8 +2156,8 @@ kbc_at_process_cmd(void *priv) * it returns an error, log a bad * controller command. */ - if (dev->write60_ven) - bad = dev->write60_ven(dev, dev->ib); + if (dev->write_cmd_data_ven) + bad = dev->write_cmd_data_ven(dev, dev->ib); if (bad) { kbc_at_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib); @@ -2145,7 +2167,7 @@ kbc_at_process_cmd(void *priv) } static void -kbc_at_write(uint16_t port, uint8_t val, void *priv) +kbc_at_port_1_write(uint16_t port, uint8_t val, void *priv) { atkbc_t *dev = (atkbc_t *) priv; uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; @@ -2153,83 +2175,89 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val); - switch (port) { - case 0x60: - dev->status &= ~STAT_CD; - if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) { - kbc_at_log("ATkbc: write P2\n"); + dev->status &= ~STAT_CD; - /* Fast A20 - ignore all other bits. */ - write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02)); + if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) { + kbc_at_log("ATkbc: write P2\n"); - dev->wantdata = 0; - dev->state = STATE_MAIN_IBF; + /* Fast A20 - ignore all other bits. */ + write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02)); - /* - Explicitly clear IBF so that any preceding - command is not executed. - */ - dev->status &= ~STAT_IFULL; - return; - } - break; + dev->wantdata = 0; + dev->state = STATE_MAIN_IBF; - case 0x64: - dev->status |= STAT_CD; - if (fast_a20 && (val == 0xd1)) { - kbc_at_log("ATkbc: write P2\n"); - dev->wantdata = 1; - dev->state = STATE_KBC_PARAM; - dev->command = 0xd1; + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; + } - /* - Explicitly clear IBF so that any preceding - command is not executed. - */ - dev->status &= ~STAT_IFULL; - return; - } else if (fast_reset && ((val & 0xf0) == 0xf0)) { - pulse_output(dev, val & 0x0f); + dev->ib = val; + dev->status |= STAT_IFULL; +} - dev->state = STATE_MAIN_IBF; +static void +kbc_at_port_2_write(uint16_t port, uint8_t val, void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t fast_a20 = (kbc_ven != KBC_VEN_SIEMENS); - /* - Explicitly clear IBF so that any preceding - command is not executed. - */ - dev->status &= ~STAT_IFULL; - return; - } else if (val == 0xad) { - /* Fast track it because of the Bochs BIOS. */ - kbc_at_log("ATkbc: disable keyboard\n"); - set_enable_kbd(dev, 0); + kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val); - dev->state = STATE_MAIN_IBF; + dev->status |= STAT_CD; - /* - Explicitly clear IBF so that any preceding - command is not executed. - */ - dev->status &= ~STAT_IFULL; - return; - } else if (val == 0xae) { - /* Fast track it because of the LG MultiNet. */ - kbc_at_log("ATkbc: enable keyboard\n"); - set_enable_kbd(dev, 1); + if (fast_a20 && (val == 0xd1)) { + kbc_at_log("ATkbc: write P2\n"); + dev->wantdata = 1; + dev->state = STATE_KBC_PARAM; + dev->command = 0xd1; - dev->state = STATE_MAIN_IBF; + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; + } else if (fast_reset && ((val & 0xf0) == 0xf0)) { + pulse_output(dev, val & 0x0f); - /* - Explicitly clear IBF so that any preceding - command is not executed. - */ - dev->status &= ~STAT_IFULL; - return; - } - break; + dev->state = STATE_MAIN_IBF; - default: - break; + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; + } else if (val == 0xad) { + /* Fast track it because of the Bochs BIOS. */ + kbc_at_log("ATkbc: disable keyboard\n"); + set_enable_kbd(dev, 0); + + dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; + } else if (val == 0xae) { + /* Fast track it because of the LG MultiNet. */ + kbc_at_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + + dev->state = STATE_MAIN_IBF; + + /* + Explicitly clear IBF so that any preceding + command is not executed. + */ + dev->status &= ~STAT_IFULL; + return; } dev->ib = val; @@ -2237,7 +2265,7 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) } static uint8_t -kbc_at_read(uint16_t port, void *priv) +kbc_at_port_1_read(uint16_t port, void *priv) { atkbc_t *dev = (atkbc_t *) priv; uint8_t ret = 0xff; @@ -2245,26 +2273,32 @@ kbc_at_read(uint16_t port, void *priv) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) cycles -= ISA_CYCLES(8); - switch (port) { - case 0x60: - ret = dev->ob; - dev->status &= ~STAT_OFULL; - /* TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit. - This also means that in AT mode, the IRQ is level-triggered. */ - if (!(dev->misc_flags & FLAG_PS2)) - picintclevel(1 << 1, &dev->irq_state); - if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1)) - cpu_override_dynarec = 0; - break; + ret = dev->ob; + dev->status &= ~STAT_OFULL; + /* + TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit. + This also means that in AT mode, the IRQ is level-triggered. + */ + if (!(dev->misc_flags & FLAG_PS2) && (dev->irq[0] != 0xffff)) + picintclevel(1 << dev->irq[0], &dev->irq_state); + if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1)) + cpu_override_dynarec = 0; - case 0x64: - ret = dev->status; - break; + kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret); - default: - kbc_at_log("ATkbc: read(%04x) invalid!\n",port); - break; - } + return ret; +} + +static uint8_t +kbc_at_port_2_read(uint16_t port, void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + uint8_t ret = 0xff; + + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) + cycles -= ISA_CYCLES(8); + + ret = dev->status; kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret); @@ -2303,11 +2337,14 @@ kbc_at_reset(void *priv) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { dev->misc_flags |= FLAG_PS2; kbc_at_do_poll = kbc_at_poll_ps2; - picintc(0x1000); - picintc(0x0002); + if (dev->irq[1] != 0xffff) + picintc(1 << dev->irq[1]); + if (dev->irq[0] != 0xffff) + picintc(1 << dev->irq[0]); } else { kbc_at_do_poll = kbc_at_poll_at; - picintclevel(0x0002, &dev->irq_state); + if (dev->irq[0] != 0xffff) + picintclevel(1 << dev->irq[0], &dev->irq_state); dev->irq_state = 0; } @@ -2350,21 +2387,52 @@ kbc_at_close(void *priv) } void -kbc_at_handler(int set, void *priv) +kbc_at_port_handler(int num, int set, uint16_t port, void *priv) { - if (kbc_handler_set) { - io_removehandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv); - io_removehandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv); + atkbc_t *dev = (atkbc_t *) priv; + + if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { + pclog("Disabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); + + io_removehandler(dev->base_addr[num], 1, + dev->handlers[num].read, NULL, NULL, + dev->handlers[num].write, NULL, NULL, priv); } - kbc_handler_set = set; + dev->handler_enable[num] = set; + dev->base_addr[num] = port; - if (kbc_handler_set) { - io_sethandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv); - io_sethandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv); + if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { + pclog("Enabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); + + io_sethandler(dev->base_addr[num], 1, + dev->handlers[num].read, NULL, NULL, + dev->handlers[num].write, NULL, NULL, priv); } } +void +kbc_at_handler(int set, uint16_t port, void *priv) +{ + kbc_at_port_handler(0, set, port, priv); + kbc_at_port_handler(1, set, port + 0x0004, priv); +} + +void +kbc_at_set_irq(int num, uint16_t irq, void *priv) +{ + atkbc_t *dev = (atkbc_t *) priv; + + if (dev->irq[num] != 0xffff) { + if ((num == 0) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1)) + picintclevel(1 << dev->irq[num], &dev->irq_state); + else + picintc(1 << dev->irq[num]); + } + + dev->irq[num] = irq; +} + static void * kbc_at_init(const device_t *info) { @@ -2383,16 +2451,21 @@ kbc_at_init(const device_t *info) if (info->flags & DEVICE_PCI) dev->misc_flags |= FLAG_PCI; - kbc_handler_set = 0; - kbc_at_handler(1, dev); + dev->handlers[0].read = kbc_at_port_1_read; + dev->handlers[0].write = kbc_at_port_1_write; + dev->handlers[1].read = kbc_at_port_2_read; + dev->handlers[1].write = kbc_at_port_2_write; + + dev->irq[0] = 1; + dev->irq[1] = 12; timer_add(&dev->kbc_poll_timer, kbc_at_poll, dev, 1); timer_add(&dev->pulse_cb, pulse_poll, dev, 0); timer_add(&dev->kbc_dev_poll_timer, kbc_at_dev_poll, dev, 1); - dev->write60_ven = NULL; - dev->write64_ven = NULL; + dev->write_cmd_data_ven = NULL; + dev->write_cmd_ven = NULL; kbc_ami_revision = '8'; kbc_award_revision = 0x42; @@ -2401,8 +2474,8 @@ kbc_at_init(const device_t *info) case KBC_VEN_SIEMENS: kbc_ami_revision = '8'; kbc_award_revision = 0x42; - dev->write60_ven = write60_ami; - dev->write64_ven = write64_siemens; + dev->write_cmd_data_ven = write_cmd_data_ami; + dev->write_cmd_ven = write_cmd_siemens; break; case KBC_VEN_ACER: @@ -2411,24 +2484,24 @@ kbc_at_init(const device_t *info) case KBC_VEN_IBM_PS1: case KBC_VEN_IBM: case KBC_VEN_COMPAQ: - dev->write64_ven = write64_generic; + dev->write_cmd_ven = write_cmd_generic; break; case KBC_VEN_OLIVETTI: - dev->write64_ven = write64_olivetti; + dev->write_cmd_ven = write_cmd_olivetti; break; case KBC_VEN_ALI: kbc_ami_revision = 'F'; kbc_award_revision = 0x43; - dev->write60_ven = write60_ami; - dev->write64_ven = write64_ami; + dev->write_cmd_data_ven = write_cmd_data_ami; + dev->write_cmd_ven = write_cmd_ami; break; case KBC_VEN_TRIGEM_AMI: kbc_ami_revision = 'Z'; - dev->write60_ven = write60_ami; - dev->write64_ven = write64_ami; + dev->write_cmd_data_ven = write_cmd_data_ami; + dev->write_cmd_ven = write_cmd_ami; break; case KBC_VEN_AMI: @@ -2451,23 +2524,23 @@ kbc_at_init(const device_t *info) else kbc_ami_revision = 'F'; - dev->write60_ven = write60_ami; - dev->write64_ven = write64_ami; + dev->write_cmd_data_ven = write_cmd_data_ami; + dev->write_cmd_ven = write_cmd_ami; break; case KBC_VEN_PHOENIX: - dev->write60_ven = write60_phoenix; - dev->write64_ven = write64_phoenix; + dev->write_cmd_data_ven = write_cmd_data_phoenix; + dev->write_cmd_ven = write_cmd_phoenix; break; case KBC_VEN_QUADTEL: - dev->write60_ven = write60_quadtel; - dev->write64_ven = write64_quadtel; + dev->write_cmd_data_ven = write_cmd_data_quadtel; + dev->write_cmd_ven = write_cmd_quadtel; break; case KBC_VEN_TOSHIBA: - dev->write60_ven = write60_toshiba; - dev->write64_ven = write64_toshiba; + dev->write_cmd_data_ven = write_cmd_data_toshiba; + dev->write_cmd_ven = write_cmd_toshiba; break; default: @@ -2493,6 +2566,8 @@ kbc_at_init(const device_t *info) fast_reset = 0x00; + kbc_at_handler(1, 0x0060, dev); + return dev; } diff --git a/src/device/postcard.c b/src/device/postcard.c index 95a4df646..058684c0b 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -30,11 +30,13 @@ #include "cpu.h" uint8_t postcard_codes[POSTCARDS_NUM]; +char postcard_diags[5] = { 0 }; static uint16_t postcard_port; static uint8_t postcard_written[POSTCARDS_NUM]; static uint8_t postcard_ports_num = 1; static uint8_t postcard_prev_codes[POSTCARDS_NUM]; +static char postcard_prev_diags[5] = { 0 }; #define UISTR_LEN 32 static char postcard_str[UISTR_LEN]; /* UI output string */ @@ -97,6 +99,22 @@ postcard_setui(void) ps[1][0], ps[1][1], ps[1][2], ps[1][3]); break; } + } else if (strstr(machines[machine].name, " Dell ")) { + char dell_diags[10] = { 0 }; + + if (!postcard_written[1]) + snprintf(dell_diags, sizeof(dell_diags), "---- ----"); + else if (postcard_written[1] == 1) + snprintf(dell_diags, sizeof(dell_diags), "%s ----", postcard_diags); + else + snprintf(dell_diags, sizeof(dell_diags), "%s %s", postcard_diags, postcard_prev_diags); + + if (!postcard_written[0]) + snprintf(postcard_str, sizeof(postcard_str), "POST: -- -- %s", dell_diags); + else if (postcard_written[0] == 1) + snprintf(postcard_str, sizeof(postcard_str), "POST: %02X -- %s", postcard_codes[0], dell_diags); + else + snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X %s", postcard_codes[0], postcard_prev_codes[0], dell_diags); } else { if (!postcard_written[0]) snprintf(postcard_str, sizeof(postcard_str), "POST: -- --"); @@ -122,6 +140,9 @@ postcard_reset(void) memset(postcard_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t)); memset(postcard_prev_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t)); + memset(postcard_diags, 0x00, 5 * sizeof(char)); + memset(postcard_prev_diags, 0x00, 5 * sizeof(char)); + postcard_setui(); } @@ -140,6 +161,35 @@ postcard_write(uint16_t port, uint8_t val, UNUSED(void *priv)) postcard_setui(); } +static int +postcard_cmp_diags(uint32_t val) +{ + int ret = 0; + char *pv = (char *) &val; + + for (int i = 0; i < 4; i++) + ret = ret || (pv[i] != postcard_diags[3 - i]); + + return ret; +} + +static void +postcard_writel(uint16_t port, uint32_t val, UNUSED(void *priv)) +{ + char *pv = (char *) &val; + + if (postcard_written[1] && !postcard_cmp_diags(val)) + return; + + *(uint32_t *) postcard_prev_diags = *(uint32_t *) postcard_diags; + for (int i = 0; i < 4; i++) + postcard_diags[i] = pv[3 - i]; + if (postcard_written[1] < 2) + postcard_written[1]++; + + postcard_setui(); +} + static void * postcard_init(UNUSED(const device_t *info)) { @@ -173,6 +223,10 @@ postcard_init(UNUSED(const device_t *info)) io_sethandler(postcard_port, postcard_ports_num, NULL, NULL, NULL, postcard_write, NULL, NULL, NULL); + if (strstr(machines[machine].name, " Dell ")) + io_sethandler(0x00e0, 0x0001, + NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL); + return postcard_write; } diff --git a/src/dma.c b/src/dma.c index 4edeb39f8..2265947b9 100644 --- a/src/dma.c +++ b/src/dma.c @@ -856,7 +856,7 @@ dma16_read(uint16_t addr, UNUSED(void *priv)) break; } - dma_log("dma16_read(%08X) = %02X\n", port, ret); + dma_log("dma16_read(%08X) = %02X\n", addr, ret); return ret; } diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index cf5ae41bf..ebc16cbfd 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -377,6 +377,15 @@ fdc_set_power_down(fdc_t *fdc, uint8_t power_down) fdc->power_down = power_down; } +void +fdc_toggle_flag(fdc_t *fdc, int flag, int on) +{ + if (on) + fdc->flags |= flag; + else + fdc->flags &= ~flag; +} + void fdc_update_max_track(fdc_t *fdc, int max_track) { @@ -1484,7 +1493,7 @@ fdc_read(uint16_t addr, void *priv) fdc->step = 0; break; default: - ret = 0xFF; + ret = 0xff; } fdc_log("[%04X:%08X] Read FDC %04X %02X [%i:%02X]\n", CS, cpu_state.pc, addr, ret, drive, fdc->dor & (0x10 << drive)); return ret; @@ -2235,9 +2244,13 @@ fdc_set_base(fdc_t *fdc, int base) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); + if (base == 0x0000) { + fdc->base_address = base; + return; + } + if (fdc->flags & FDC_FLAG_NSC) { - io_sethandler(base + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_sethandler(base + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { @@ -2266,10 +2279,12 @@ fdc_remove(fdc_t *fdc) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); + if (fdc->base_address == 0x0000) + return; + fdc_log("FDC Removed (%04X)\n", fdc->base_address); if (fdc->flags & FDC_FLAG_NSC) { - io_removehandler(fdc->base_address + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_removehandler(fdc->base_address + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index 53511daac..c98a03f67 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -183,6 +183,7 @@ extern uint8_t fdc_get_densel_polarity(fdc_t *fdc); extern void fdc_update_densel_force(fdc_t *fdc, int densel_force); extern void fdc_update_drvrate(fdc_t *fdc, int drive, int drvrate); extern void fdc_update_drv2en(fdc_t *fdc, int drv2en); +extern void fdc_toggle_flag(fdc_t *fdc, int flag, int on); extern void fdc_noidam(fdc_t *fdc); extern void fdc_nosector(fdc_t *fdc); diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 9dfb1c8e4..b9bac0821 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -289,7 +289,9 @@ extern uint8_t kbc_at_read_p(void *priv, uint8_t port, uint8_t mask); extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val); extern void kbc_at_set_fast_reset(uint8_t new_fast_reset); -extern void kbc_at_handler(int set, void *priv); +extern void kbc_at_port_handler(int num, int set, uint16_t port, void *priv); +extern void kbc_at_handler(int set, uint16_t port, void *priv); +extern void kbc_at_set_irq(int num, uint16_t irq, void *priv); extern void kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main); extern uint8_t kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main); diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 06bf57f8f..358cd8c9a 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -92,13 +92,23 @@ extern const device_t pc87332_398_ide_device; extern const device_t pc87332_398_ide_sec_device; extern const device_t pc87332_398_ide_fdcon_device; +#define PCX7307_PC87307 0x00c0 +#define PCX7307_PC97307 0x00cf + +#define PC87309_PC87309 0x00e0 + +#define PCX730X_CHIP_ID 0x00ff + +#define PCX730X_AMI 0x0200 /* AMI '5' Megakey KBC firmware. */ +#define PCX730X_PHOENIX_42 0x0500 /* Phoenix Multikey/42 1.37 KBC firmware. */ +#define PCX730X_PHOENIX_42I 0x0700 /* Phoenix Multikey/42i 4.16 KBC firmware. */ +#define PCX730X_KBC 0x0f00 + +#define PCX730X_15C 0x2000 + extern const device_t pc87307_device; -extern const device_t pc87307_15c_device; -extern const device_t pc87307_both_device; -extern const device_t pc97307_device; extern const device_t pc87309_device; -extern const device_t pc87309_15c_device; /* LG Prime */ extern const device_t prime3b_device; diff --git a/src/lpt.c b/src/lpt.c index 26174d96b..072f4a34c 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -229,9 +229,9 @@ void lpt_port_setup(int i, uint16_t port) { if (lpt_ports[i].enabled) { - if (lpt_ports[i].addr != 0xffff) + if ((lpt_ports[i].addr != 0xffff) && (lpt_ports[i].addr != 0x0000)) io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); - if (port != 0xffff) + if ((port != 0xffff) && (port != 0x0000)) io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); lpt_ports[i].addr = port; } else diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index b2f05d33e..773826316 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -584,7 +584,7 @@ machine_at_s1846_init(const machine_t *model) pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440bx_device); device_add(&piix4e_device); - device_add(&pc87309_device); + device_add_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309)); device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index da160c138..37c0acdfd 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -141,7 +141,7 @@ machine_at_fw6400gx_init(const machine_t *model) device_add(&i440gx_device); device_add(&piix4e_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87309_15c_device); + device_add_params(&pc87309_device, (void *) (PCX730X_15C | PCX730X_AMI | PC87309_PC87309)); device_add(ics9xxx_get(ICS9250_08)); device_add(&sst_flash_29ee020_device); spd_register(SPD_TYPE_SDRAM, 0xF, 512); diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 17c89e39d..9ceebe2e0 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -984,19 +984,21 @@ machine_at_optiplex_gn_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */ pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); + if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available()) + machine_snd = device_add(machine_get_snd_device(machine)); + device_add(&i430tx_device); device_add(&piix4_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87307_15c_device); + device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); @@ -1040,8 +1042,7 @@ machine_at_an430tx_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&i430tx_device); device_add(&piix4_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87307_both_device); + device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42I | PCX7307_PC97307)); device_add(&intel_flash_bxt_ami_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 006e0f419..aabfb9b4f 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -250,8 +250,7 @@ machine_at_vs440fx_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i440fx_device); device_add(&piix3_device); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87307_device); + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307)); device_add(&intel_flash_bxt_ami_device); @@ -287,8 +286,7 @@ machine_at_gw2kvenus_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i440fx_device); device_add(&piix3_device); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87307_device); + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307)); device_add(&intel_flash_bxt_ami_device); @@ -324,8 +322,7 @@ machine_at_ap440fx_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); device_add(&i440fx_device); device_add(&piix3_device); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87307_device); + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307)); device_add(&intel_flash_bxt_ami_device); if (sound_card_current[0] == SOUND_INTERNAL) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f28079888..f16f4e5ae 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13103,11 +13103,15 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* According to Dell specifications, it can have either National Semiconductor PC87307 or PC87309 - Super I/O. All known instances have the former, although other similar Dells of the era have - pinouts for accompanying either so this likely also does. + /* + According to Dell specifications, it can have either National Semiconductor + PC87307 or PC87309 Super I/O. All known instances have the former, although + other similar Dells of the era have pinouts for accompanying either so this + likely also does. - The KBC is likely an AMIKey-2 clone. */ + The KBC is either an AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix + MultiKey/42i 4.16. + */ { .name = "[i430TX] Dell OptiPlex GN+", .internal_name = "optiplex_gn", @@ -13129,7 +13133,8 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO, /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905 */ + /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905. */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO | MACHINE_SOUND, .ram = { .min = 8192, .max = 262144, @@ -13143,8 +13148,9 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &s3_trio64v2_dx_onboard_pci_device, /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS */ - .snd_device = NULL, + /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS. */ + .vid_device = &s3_trio64v2_dx_onboard_pci_device, + .snd_device = &sb_vibra16xv_onboard_device, .net_device = NULL }, /* [TEST] Has AMI Megakey '5' KBC firmware on the SM(S)C FDC37C67x Super I/O chip. */ diff --git a/src/nvr_at.c b/src/nvr_at.c index 2acfa47a4..4deda98be 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1107,9 +1107,10 @@ nvr_at_init(const device_t *info) case 1: /* standard AT */ case 5: /* AMI WinBIOS 1994 */ case 6: /* AMI BIOS 1995 */ - if ((info->local & 0x1f) == 0x11) + if ((info->local & 0x1f) == 0x11) { local->flags |= FLAG_PIIX4; - else { + local->def = 0x00; + } else { local->def = 0x00; if ((info->local & 0x1f) == 0x15) local->flags |= FLAG_AMI_1994_HACK; diff --git a/src/sio/sio_fdc37c93x.c b/src/sio/sio_fdc37c93x.c index ebc500c96..dce5b11dc 100644 --- a/src/sio/sio_fdc37c93x.c +++ b/src/sio/sio_fdc37c93x.c @@ -894,7 +894,7 @@ fdc37c93x_kbc_handler(fdc37c93x_t *dev) dev->kbc_base = local_enable ? 0x0060 : 0x0000; if (dev->kbc_base != old_base) - kbc_at_handler(local_enable, dev->kbc); + kbc_at_handler(local_enable, dev->kbc_base, dev->kbc); } static void diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index ae21d34af..7bc9bb441 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -8,11 +8,9 @@ * * Emulation of the NatSemi PC87307 Super I/O chip. * - * - * * Authors: Miran Grca, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Miran Grca. */ #include #include @@ -24,45 +22,89 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/lpt.h> +#include <86box/machine.h> #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> #include <86box/rom.h> #include <86box/serial.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/keyboard.h> #include <86box/sio.h> #include <86box/plat_fallthrough.h> +#include "cpu.h" typedef struct pc87307_t { uint8_t id; + uint8_t baddr; uint8_t pm_idx; uint8_t regs[48]; uint8_t ld_regs[256][208]; uint8_t pcregs[16]; - uint8_t gpio[2][4]; + uint8_t gpio[2][8]; uint8_t pm[8]; + uint16_t superio_base; uint16_t gpio_base; uint16_t gpio_base2; uint16_t pm_base; int cur_reg; + void *kbc; fdc_t *fdc; serial_t *uart[2]; } pc87307_t; -static void fdc_handler(pc87307_t *dev); -static void lpt1_handler(pc87307_t *dev); -static void serial_handler(pc87307_t *dev, int uart); +enum { + LD_KBD = 0, + LD_MOUSE, + LD_RTC, + LD_FDC, + LD_LPT, + LD_UART2, + LD_UART1, + LD_GPIO, + LD_PM +} pc87307_ld_t; + +#define LD_MIN LD_KBD +#define LD_MAX LD_PM + +static void fdc_handler(pc87307_t *dev); +static void lpt1_handler(pc87307_t *dev); +static void serial_handler(pc87307_t *dev, int uart); +static void kbc_handler(pc87307_t *dev); +static void pc87307_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pc87307_read(uint16_t port, void *priv); + +#ifdef ENABLE_PC87307_LOG +int pc87307_do_log = ENABLE_PC87307_LOG; + +static void +pc87307_log(const char *fmt, ...) +{ + va_list ap; + + if (pc87307_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define pc87307_log(fmt, ...) +#endif static void pc87307_gpio_write(uint16_t port, uint8_t val, void *priv) { pc87307_t *dev = (pc87307_t *) priv; - uint8_t bank = ((port & 0xfffc) == dev->gpio_base2); + uint8_t bank = !!(dev->regs[0x22] & 0x80); - dev->gpio[bank][port & 3] = val; + /* Bit 7 of SCNF2 = bank. */ + pc87307_log("[%04X:%08X] [W] (%04X) Bank %i = %02X\n", + CS, cpu_state.pc, port, bank, val); + + dev->gpio[bank][port & 0x0007] = val; } uint8_t @@ -70,20 +112,36 @@ pc87307_gpio_read(uint16_t port, void *priv) { const pc87307_t *dev = (pc87307_t *) priv; uint8_t pins = 0xff; - uint8_t bank = ((port & 0xfffc) == dev->gpio_base2); - uint8_t mask; - uint8_t ret = dev->gpio[bank][port & 0x0003]; + uint8_t bank = !!(dev->regs[0x22] & 0x80); + uint8_t ret = dev->gpio[bank][port & 0x0007]; switch (port & 0x0003) { case 0x0000: - mask = dev->gpio[bank][0x0001]; - ret = (ret & mask) | (pins & ~mask); + if (bank == 0) { + uint8_t mask = dev->gpio[0][1]; + pins = 0x7f; + ret = (ret & mask) | (pins & ~mask); + } + break; + case 0x0004: + if (bank == 0) { + uint8_t mask = dev->gpio[0][5]; + pins = 0xfb; + ret = (ret & mask) | (pins & ~mask); + } else + ret = 0xff; break; default: + if (bank == 1) + ret = 0xff; break; } + /* Bit 7 of SCNF2 = bank. */ + pc87307_log("[%04X:%08X] [R] (%04X) Bank %i = %02X\n", + CS, cpu_state.pc, port, bank, ret); + return ret; } @@ -123,6 +181,7 @@ pc87307_pm_write(uint16_t port, uint8_t val, void *priv) dev->pm[dev->pm_idx] = val; else { dev->pm_idx = val & 0x07; + switch (dev->pm_idx) { case 0x00: fdc_handler(dev); @@ -167,20 +226,49 @@ pc87307_pm_init(pc87307_t *dev, uint16_t addr) pc87307_pm_read, NULL, NULL, pc87307_pm_write, NULL, NULL, dev); } +static void +kbc_handler(pc87307_t *dev) +{ + uint8_t active = (dev->ld_regs[LD_KBD][0x00] & 0x01) && + (dev->pm[0x00] & 0x01); + uint8_t active_2 = dev->ld_regs[LD_MOUSE][0x00] & 0x01; + uint8_t irq = (dev->ld_regs[LD_KBD][0x40] & 0x0f); + uint8_t irq_2 = (dev->ld_regs[LD_MOUSE][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_KBD][0x30] << 8) | + dev->ld_regs[LD_KBD][0x31]; + uint16_t addr_2 = (dev->ld_regs[LD_KBD][0x32] << 8) | + dev->ld_regs[LD_KBD][0x33]; + + pc87307_log("%02X, %02X, %02X, %02X, %04X, %04X\n", + active, active_2, irq, irq_2, addr, addr_2); + + if (addr <= 0xfff8) { + pc87307_log("Enabling KBC #1 on %04X...\n", addr); + kbc_at_port_handler(0, active, addr, dev->kbc); + } + + if (addr_2 <= 0xfff8) { + pc87307_log("Enabling KBC #2 on %04X...\n", addr_2); + kbc_at_port_handler(1, active, addr_2, dev->kbc); + } + + kbc_at_set_irq(0, active ? irq : 0xffff, dev->kbc); + kbc_at_set_irq(1, (active && active_2) ? irq_2 : 0xffff, dev->kbc); +} + static void fdc_handler(pc87307_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; - fdc_remove(dev->fdc); - active = (dev->ld_regs[0x03][0x00] & 0x01) && (dev->pm[0x00] & 0x08); - addr = ((dev->ld_regs[0x03][0x30] << 8) | dev->ld_regs[0x03][0x31]) - 0x0002; - irq = (dev->ld_regs[0x03][0x40] & 0x0f); + uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) && + (dev->pm[0x00] & 0x08); + uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f); + uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) | + dev->ld_regs[LD_FDC][0x31]) & 0xfff8; if (active && (addr <= 0xfff8)) { + pc87307_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq); fdc_set_base(dev->fdc, addr); fdc_set_irq(dev->fdc, irq); } @@ -189,268 +277,405 @@ fdc_handler(pc87307_t *dev) static void lpt1_handler(pc87307_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; - - lpt1_remove(); - - active = (dev->ld_regs[0x04][0x00] & 0x01) && (dev->pm[0x00] & 0x10); - addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31]; - irq = (dev->ld_regs[0x04][0x40] & 0x0f); + uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) && + (dev->pm[0x00] & 0x10); + uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) | + dev->ld_regs[LD_LPT][0x31]; if (active && (addr <= 0xfffc)) { + pc87307_log("Enabling LPT1 on %04X...\n", addr); lpt1_setup(addr); - lpt1_irq(irq); - } + } else + lpt1_setup(0xffff); + + lpt1_irq(irq); } static void serial_handler(pc87307_t *dev, int uart) { - uint8_t irq; - uint8_t active; - uint16_t addr; - serial_remove(dev->uart[uart]); - active = (dev->ld_regs[0x06 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart))); - addr = (dev->ld_regs[0x06 - uart][0x30] << 8) | dev->ld_regs[0x06 - uart][0x31]; - irq = (dev->ld_regs[0x06 - uart][0x40] & 0x0f); + uint8_t active = (dev->ld_regs[LD_UART1 - uart][0x00] & 0x01) && + (dev->pm[0x00] & (1 << (6 - uart))); + uint8_t irq = (dev->ld_regs[LD_UART1 - uart][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_UART1 - uart][0x30] << 8) | + dev->ld_regs[LD_UART1 - uart][0x31]; - if (active && (addr <= 0xfff8)) + if (active && (addr <= 0xfff8)) { + pc87307_log("Enabling COM%i on %04X...\n", uart + 1, addr); serial_setup(dev->uart[uart], addr, irq); + } else + serial_setup(dev->uart[uart], 0x0000, irq); } static void gpio_handler(pc87307_t *dev) { - uint8_t active; - uint16_t addr; - pc87307_gpio_remove(dev); - active = (dev->ld_regs[0x07][0x00] & 0x01); - addr = (dev->ld_regs[0x07][0x30] << 8) | dev->ld_regs[0x07][0x31]; + uint8_t active = (dev->ld_regs[LD_GPIO][0x00] & 0x01); + uint16_t addr = (dev->ld_regs[LD_GPIO][0x30] << 8) | + dev->ld_regs[LD_GPIO][0x31]; + uint16_t addr_2 = (dev->ld_regs[LD_GPIO][0x32] << 8) | + dev->ld_regs[LD_GPIO][0x33]; - if (active) + if (active) { + pc87307_log("Enabling GPIO #1 on %04X...\n", addr); pc87307_gpio_init(dev, 0, addr); - - addr = (dev->ld_regs[0x07][0x32] << 8) | dev->ld_regs[0x07][0x33]; - - if (active) - pc87307_gpio_init(dev, 1, addr); + pc87307_log("Enabling GPIO #2 on %04X...\n", addr_2); + pc87307_gpio_init(dev, 1, addr_2); + } } static void pm_handler(pc87307_t *dev) { - uint8_t active; - uint16_t addr; - pc87307_pm_remove(dev); - active = (dev->ld_regs[0x08][0x00] & 0x01); - addr = (dev->ld_regs[0x08][0x30] << 8) | dev->ld_regs[0x08][0x31]; + uint8_t active = (dev->ld_regs[LD_PM][0x00] & 0x01); + uint16_t addr = (dev->ld_regs[LD_PM][0x30] << 8) | + dev->ld_regs[LD_PM][0x31]; - if (active) + if (active) { + pc87307_log("Enabling power management on %04X...\n", addr); pc87307_pm_init(dev, addr); + } +} + +static void +superio_handler(pc87307_t *dev) +{ + if (dev->superio_base != 0x0000) + io_removehandler(dev->superio_base, 0x0002, + pc87307_read, NULL, NULL, + pc87307_write, NULL, NULL, dev); + + switch (dev->regs[0x22] & 0x03) { + default: + dev->superio_base = 0x0000; + break; case 0x02: + dev->superio_base = 0x015c; + break; + case 0x03: + dev->superio_base = 0x002e; + break; + } + + if (dev->superio_base != 0x0000) { + pc87307_log("Enabling Super I/O on %04X...\n", dev->superio_base); + io_sethandler(dev->superio_base, 0x0002, + pc87307_read, NULL, NULL, + pc87307_write, NULL, NULL, dev); + } } static void pc87307_write(uint16_t port, uint8_t val, void *priv) { - pc87307_t *dev = (pc87307_t *) priv; - uint8_t index; - - index = (port & 1) ? 0 : 1; + pc87307_t *dev = (pc87307_t *) priv; + uint8_t ld = dev->regs[0x07]; + uint8_t reg = dev->cur_reg - 0x30; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t old = dev->regs[dev->cur_reg]; if (index) { dev->cur_reg = val; return; } else { +#ifdef ENABLE_PC87307_LOG + if (dev->cur_reg >= 0x30) + pc87307_log("[%04X:%08X] [W] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, val); + else + pc87307_log("[%04X:%08X] [W] (%04X) %02X = %02X\n", + CS, cpu_state.pc, port, dev->cur_reg, val); +#endif switch (dev->cur_reg) { case 0x00: - case 0x02: - case 0x03: - case 0x06: - case 0x07: - case 0x21: + case 0x02: case 0x03: + case 0x06: case 0x07: dev->regs[dev->cur_reg] = val; break; + case 0x21: + dev->regs[dev->cur_reg] = val; + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); + break; case 0x22: - dev->regs[dev->cur_reg] = val & 0x7f; + dev->regs[dev->cur_reg] = val; + superio_handler(dev); break; case 0x23: - dev->regs[dev->cur_reg] = val & 0x0f; + dev->regs[dev->cur_reg] = (old & 0xf0) | (val & 0x0f); break; case 0x24: dev->pcregs[dev->regs[0x23]] = val; break; default: - if (dev->cur_reg >= 0x30) { - if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10)) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; - } + if (dev->cur_reg >= 0x30) + old = dev->ld_regs[ld][reg]; break; } } switch (dev->cur_reg) { case 0x30: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01; - switch (dev->regs[0x07]) { - case 0x03: + switch (ld) { + default: + break; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x04: + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x05: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x06: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x07: + case LD_GPIO: + dev->ld_regs[ld][reg] = val; gpio_handler(dev); break; - case 0x08: + case LD_PM: + dev->ld_regs[ld][reg] = val; pm_handler(dev); break; - - default: - break; } break; + /* I/O Range Check. */ + case 0x31: + switch (ld) { + default: + break; + case LD_MIN ... LD_MAX: + if (ld != LD_MOUSE) + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* Base Address 0 MSB. */ case 0x60: - if (dev->regs[0x07] == 0x04) { - val &= 0x03; - } - fallthrough; - case 0x62: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; - if ((dev->cur_reg == 0x62) && (dev->regs[0x07] != 0x07)) - break; - switch (dev->regs[0x07]) { - case 0x03: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x04: + case LD_LPT: + dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03); lpt1_handler(dev); break; - case 0x05: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x06: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x07: + case LD_GPIO: + dev->ld_regs[ld][reg] = val; gpio_handler(dev); break; - case 0x08: + case LD_PM: + dev->ld_regs[ld][reg] = val; pm_handler(dev); break; - - default: - break; } break; + /* Base Address 0 LSB. */ case 0x61: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfb; + switch (ld) { + default: break; - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); fdc_handler(dev); break; - case 0x04: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc; + case LD_LPT: + dev->ld_regs[ld][reg] = (old & 0x03) | (val & 0xfc); lpt1_handler(dev); break; - case 0x05: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_UART2: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); serial_handler(dev, 1); break; - case 0x06: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_UART1: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); serial_handler(dev, 0); break; - case 0x07: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_GPIO: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); gpio_handler(dev); break; - case 0x08: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; + case LD_PM: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); pm_handler(dev); break; - - default: - break; } break; + /* Base Address 1 MSB (undocumented for Logical Device 7). */ + case 0x62: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_GPIO: + dev->ld_regs[ld][reg] = val; + gpio_handler(dev); + break; + } + break; + /* Base Address 1 LSB (undocumented for Logical Device 7). */ case 0x63: - if (dev->regs[0x07] == 0x00) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfb) | 0x04; - else if (dev->regs[0x07] == 0x07) { - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; - gpio_handler(dev); - } - break; - case 0x70: - case 0x74: - case 0x75: - switch (dev->regs[0x07]) { - case 0x03: - fdc_handler(dev); - break; - case 0x04: - lpt1_handler(dev); - break; - case 0x05: - serial_handler(dev, 1); - break; - case 0x06: - serial_handler(dev, 0); - break; - case 0x07: - gpio_handler(dev); - break; - case 0x08: - pm_handler(dev); - break; - + switch (ld) { default: break; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + case LD_GPIO: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); + gpio_handler(dev); + break; } break; - case 0xf0: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1; + /* Interrupt Select. */ + case 0x70: + switch (ld) { + default: break; - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_RTC: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; + fdc_handler(dev); + break; + case LD_LPT: + dev->ld_regs[ld][reg] = val; + lpt1_handler(dev); + break; + case LD_UART2: + dev->ld_regs[ld][reg] = val; + serial_handler(dev, 1); + break; + case LD_UART1: + dev->ld_regs[ld][reg] = val; + serial_handler(dev, 0); + break; + } + break; + /* Interrupt Type. */ + case 0x71: + switch (ld) { + default: + break; + case LD_MIN ... LD_MAX: + if ((ld == LD_KBD) || (ld == LD_MOUSE)) + dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03); + else + dev->ld_regs[ld][reg] = (old & 0xfd) | (val & 0x02); + break; + } + break; + /* DMA Channel Select 0. */ + case 0x74: + switch (ld) { + default: + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; + fdc_handler(dev); + break; + case LD_LPT: + dev->ld_regs[ld][reg] = val; + lpt1_handler(dev); + break; + case LD_UART2: + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* DMA Channel Select 1. */ + case 0x75: + switch (ld) { + default: + break; + case LD_UART2: + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* Configuration Register 0. */ + case 0xf0: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0); fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0); break; - case 0x04: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3; + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x05: - case 0x06: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87; - break; - - default: + case LD_UART2: case LD_UART1: + dev->ld_regs[ld][reg] = val; break; } break; + /* Configuration Register 1. */ case 0xf1: - if (dev->regs[0x07] == 0x03) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f; + switch (ld) { + default: + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; + break; + } break; default: @@ -458,32 +683,46 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) } } -uint8_t +static uint8_t pc87307_read(uint16_t port, void *priv) { - const pc87307_t *dev = (pc87307_t *) priv; - uint8_t ret = 0xff; - uint8_t index; - - index = (port & 1) ? 0 : 1; + const pc87307_t *dev = (pc87307_t *) priv; + uint8_t ld = dev->regs[0x07]; + uint8_t reg = dev->cur_reg - 0x30; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; if (index) ret = dev->cur_reg; else { if (dev->cur_reg >= 0x30) - ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + ret = dev->ld_regs[ld][reg]; else if (dev->cur_reg == 0x24) ret = dev->pcregs[dev->regs[0x23]]; + /* Write-only registers. */ + else if ((dev->cur_reg == 0x00) || + (dev->cur_reg == 0x02) || (dev->cur_reg == 0x03)) + ret = 0x00; else ret = dev->regs[dev->cur_reg]; +#ifdef EANBLE_PC87307_LOG + if (dev->cur_reg >= 0x30) + pc87307_log("[%04X:%08X] [R] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, ret); + else + pc87307_log("[%04X:%08X] [R] (%04X) %02X = %02X\n", + CS, cpu_state.pc, port, dev->cur_reg, ret); +#endif } return ret; } void -pc87307_reset(pc87307_t *dev) +pc87307_reset(void *priv) { + pc87307_t *dev = (pc87307_t *) priv; + memset(dev->regs, 0x00, 0x30); for (uint16_t i = 0; i < 256; i++) memset(dev->ld_regs[i], 0x00, 0xd0); @@ -493,77 +732,77 @@ pc87307_reset(pc87307_t *dev) dev->regs[0x20] = dev->id; dev->regs[0x21] = 0x04; + dev->regs[0x22] = dev->baddr; - dev->ld_regs[0x00][0x01] = 0x01; - dev->ld_regs[0x00][0x31] = 0x60; - dev->ld_regs[0x00][0x33] = 0x64; - dev->ld_regs[0x00][0x40] = 0x01; - dev->ld_regs[0x00][0x41] = 0x02; - dev->ld_regs[0x00][0x44] = 0x04; - dev->ld_regs[0x00][0x45] = 0x04; - dev->ld_regs[0x00][0xc0] = 0x40; + dev->ld_regs[LD_KBD ][0x00] = 0x01; + dev->ld_regs[LD_KBD ][0x31] = 0x60; + dev->ld_regs[LD_KBD ][0x33] = 0x64; + dev->ld_regs[LD_KBD ][0x40] = 0x01; + dev->ld_regs[LD_KBD ][0x41] = 0x02; + dev->ld_regs[LD_KBD ][0x44] = 0x04; + dev->ld_regs[LD_KBD ][0x45] = 0x04; + dev->ld_regs[LD_KBD ][0xc0] = 0x40; - dev->ld_regs[0x01][0x40] = 0x0c; - dev->ld_regs[0x01][0x41] = 0x02; - dev->ld_regs[0x01][0x44] = 0x04; - dev->ld_regs[0x01][0x45] = 0x04; + dev->ld_regs[LD_MOUSE][0x40] = 0x0c; + dev->ld_regs[LD_MOUSE][0x41] = 0x02; + dev->ld_regs[LD_MOUSE][0x44] = 0x04; + dev->ld_regs[LD_MOUSE][0x45] = 0x04; - dev->ld_regs[0x02][0x00] = 0x01; - dev->ld_regs[0x02][0x31] = 0x70; - dev->ld_regs[0x02][0x40] = 0x08; - dev->ld_regs[0x02][0x44] = 0x04; - dev->ld_regs[0x02][0x45] = 0x04; + dev->ld_regs[LD_RTC ][0x00] = 0x01; + dev->ld_regs[LD_RTC ][0x31] = 0x70; + dev->ld_regs[LD_RTC ][0x40] = 0x08; + dev->ld_regs[LD_RTC ][0x44] = 0x04; + dev->ld_regs[LD_RTC ][0x45] = 0x04; - dev->ld_regs[0x03][0x01] = 0x01; - dev->ld_regs[0x03][0x30] = 0x03; - dev->ld_regs[0x03][0x31] = 0xf2; - dev->ld_regs[0x03][0x40] = 0x06; - dev->ld_regs[0x03][0x41] = 0x03; - dev->ld_regs[0x03][0x44] = 0x02; - dev->ld_regs[0x03][0x45] = 0x04; - dev->ld_regs[0x03][0xc0] = 0x02; + dev->ld_regs[LD_FDC ][0x01] = 0x01; + dev->ld_regs[LD_FDC ][0x30] = 0x03; + dev->ld_regs[LD_FDC ][0x31] = 0xf0; + dev->ld_regs[LD_FDC ][0x32] = 0x03; + dev->ld_regs[LD_FDC ][0x33] = 0xf7; + dev->ld_regs[LD_FDC ][0x40] = 0x06; + dev->ld_regs[LD_FDC ][0x41] = 0x03; + dev->ld_regs[LD_FDC ][0x44] = 0x02; + dev->ld_regs[LD_FDC ][0x45] = 0x04; + dev->ld_regs[LD_FDC ][0xc0] = 0x02; - dev->ld_regs[0x04][0x30] = 0x02; - dev->ld_regs[0x04][0x31] = 0x78; - dev->ld_regs[0x04][0x40] = 0x07; - dev->ld_regs[0x04][0x44] = 0x04; - dev->ld_regs[0x04][0x45] = 0x04; - dev->ld_regs[0x04][0xc0] = 0xf2; + dev->ld_regs[LD_LPT ][0x30] = 0x02; + dev->ld_regs[LD_LPT ][0x31] = 0x78; + dev->ld_regs[LD_LPT ][0x40] = 0x07; + dev->ld_regs[LD_LPT ][0x44] = 0x04; + dev->ld_regs[LD_LPT ][0x45] = 0x04; + dev->ld_regs[LD_LPT ][0xc0] = 0xf2; - dev->ld_regs[0x05][0x30] = 0x02; - dev->ld_regs[0x05][0x31] = 0xf8; - dev->ld_regs[0x05][0x40] = 0x03; - dev->ld_regs[0x05][0x41] = 0x03; - dev->ld_regs[0x05][0x44] = 0x04; - dev->ld_regs[0x05][0x45] = 0x04; - dev->ld_regs[0x05][0xc0] = 0x02; + dev->ld_regs[LD_UART2][0x30] = 0x02; + dev->ld_regs[LD_UART2][0x31] = 0xf8; + dev->ld_regs[LD_UART2][0x40] = 0x03; + dev->ld_regs[LD_UART2][0x41] = 0x03; + dev->ld_regs[LD_UART2][0x44] = 0x04; + dev->ld_regs[LD_UART2][0x45] = 0x04; + dev->ld_regs[LD_UART2][0xc0] = 0x02; - dev->ld_regs[0x06][0x30] = 0x03; - dev->ld_regs[0x06][0x31] = 0xf8; - dev->ld_regs[0x06][0x40] = 0x04; - dev->ld_regs[0x06][0x41] = 0x03; - dev->ld_regs[0x06][0x44] = 0x04; - dev->ld_regs[0x06][0x45] = 0x04; - dev->ld_regs[0x06][0xc0] = 0x02; + dev->ld_regs[LD_UART1][0x30] = 0x03; + dev->ld_regs[LD_UART1][0x31] = 0xf8; + dev->ld_regs[LD_UART1][0x40] = 0x04; + dev->ld_regs[LD_UART1][0x41] = 0x03; + dev->ld_regs[LD_UART1][0x44] = 0x04; + dev->ld_regs[LD_UART1][0x45] = 0x04; + dev->ld_regs[LD_UART1][0xc0] = 0x02; - dev->ld_regs[0x07][0x44] = 0x04; - dev->ld_regs[0x07][0x45] = 0x04; + dev->ld_regs[LD_GPIO ][0x44] = 0x04; + dev->ld_regs[LD_GPIO ][0x45] = 0x04; - dev->ld_regs[0x08][0x44] = 0x04; - dev->ld_regs[0x08][0x45] = 0x04; + dev->ld_regs[LD_PM ][0x44] = 0x04; + dev->ld_regs[LD_PM ][0x45] = 0x04; -#if 0 - dev->gpio[0] = 0xff; - dev->gpio[1] = 0xfb; -#endif dev->gpio[0][0] = 0xff; dev->gpio[0][1] = 0x00; dev->gpio[0][2] = 0x00; dev->gpio[0][3] = 0xff; - dev->gpio[1][0] = 0xff; + dev->gpio[0][4] = 0xff; + dev->gpio[0][5] = 0x00; + dev->gpio[0][6] = 0x00; + dev->gpio[0][7] = 0xff; dev->gpio[1][1] = 0x00; - dev->gpio[1][2] = 0x00; - dev->gpio[1][3] = 0xff; dev->pm[0] = 0xff; dev->pm[1] = 0xff; @@ -576,10 +815,17 @@ pc87307_reset(pc87307_t *dev) 0 = 360 rpm @ 500 kbps for 3.5" 1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5" */ - lpt1_remove(); - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, 0); fdc_reset(dev->fdc); + + kbc_handler(dev); + fdc_handler(dev); + lpt1_handler(dev); + serial_handler(dev, 0); + serial_handler(dev, 1); + gpio_handler(dev); + pm_handler(dev); + superio_handler(dev); } static void @@ -602,16 +848,26 @@ pc87307_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - pc87307_reset(dev); + switch (info->local & PCX730X_KBC) { + default: + case PCX730X_AMI: + dev->kbc = device_add(&keyboard_ps2_intel_ami_pci_device); + break; + /* Optiplex! */ + case PCX730X_PHOENIX_42: + dev->kbc = device_add(&keyboard_ps2_phoenix_device); + break; + case PCX730X_PHOENIX_42I: + dev->kbc = device_add(&keyboard_ps2_phoenix_pci_device); + break; + } - if (info->local & 0x100) { - io_sethandler(0x02e, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); - } - if (info->local & 0x200) { - io_sethandler(0x15c, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); - } + if (info->local & PCX730X_15C) + dev->baddr = 0x02; + else + dev->baddr = 0x03; + + pc87307_reset(dev); return dev; } @@ -623,7 +879,7 @@ const device_t pc87307_device = { .local = 0x1c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -637,7 +893,7 @@ const device_t pc87307_15c_device = { .local = 0x2c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -651,7 +907,7 @@ const device_t pc87307_both_device = { .local = 0x3c0, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, @@ -665,7 +921,7 @@ const device_t pc97307_device = { .local = 0x1cf, .init = pc87307_init, .close = pc87307_close, - .reset = NULL, + .reset = pc87307_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 5e417aefb..d2d3f4ac0 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -8,11 +8,9 @@ * * Emulation of the NatSemi PC87309 Super I/O chip. * - * - * * Authors: Miran Grca, * - * Copyright 2020 Miran Grca. + * Copyright 2020-2025 Miran Grca. */ #include #include @@ -24,44 +22,81 @@ #include <86box/timer.h> #include <86box/device.h> #include <86box/lpt.h> +#include <86box/machine.h> #include <86box/mem.h> #include <86box/nvr.h> #include <86box/pci.h> #include <86box/rom.h> #include <86box/serial.h> -#include <86box/hdc.h> -#include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> +#include <86box/keyboard.h> #include <86box/sio.h> +#include <86box/plat_fallthrough.h> +#include "cpu.h" typedef struct pc87309_t { uint8_t id; + uint8_t baddr; uint8_t pm_idx; uint8_t regs[48]; uint8_t ld_regs[256][208]; uint8_t pm[8]; - uint8_t baddr; + uint16_t superio_base; uint16_t pm_base; int cur_reg; + void *kbc; fdc_t *fdc; serial_t *uart[2]; } pc87309_t; +enum { + LD_FDC = 0, + LD_LPT, + LD_UART2, + LD_UART1, + LD_PM, + LD_KBD, + LD_MOUSE +} pc87309_ld_t; + +#define LD_MIN LD_FDC +#define LD_MAX LD_MOUSE + static void fdc_handler(pc87309_t *dev); static void lpt1_handler(pc87309_t *dev); static void serial_handler(pc87309_t *dev, int uart); - +static void kbc_handler(pc87309_t *dev); static void pc87309_write(uint16_t port, uint8_t val, void *priv); static uint8_t pc87309_read(uint16_t port, void *priv); +#ifdef ENABLE_PC87309_LOG +int pc87309_do_log = ENABLE_PC87309_LOG; + +static void +pc87309_log(const char *fmt, ...) +{ + va_list ap; + + if (pc87309_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define pc87309_log(fmt, ...) +#endif + static void pc87309_pm_write(uint16_t port, uint8_t val, void *priv) { pc87309_t *dev = (pc87309_t *) priv; - if (port & 1) { + if (port & 1) dev->pm[dev->pm_idx] = val; + else { + dev->pm_idx = val & 0x07; switch (dev->pm_idx) { case 0x00: @@ -74,8 +109,7 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv) default: break; } - } else - dev->pm_idx = val & 0x07; + } } uint8_t @@ -109,43 +143,48 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr) } static void -superio_handler(pc87309_t *dev) +kbc_handler(pc87309_t *dev) { - io_removehandler(0x15c, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - io_removehandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + uint8_t active = (dev->ld_regs[LD_KBD][0x00] & 0x01) && + (dev->pm[0x00] & 0x01); + uint8_t active_2 = dev->ld_regs[LD_MOUSE][0x00] & 0x01; + uint8_t irq = (dev->ld_regs[LD_KBD][0x40] & 0x0f); + uint8_t irq_2 = (dev->ld_regs[LD_MOUSE][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_KBD][0x30] << 8) | + dev->ld_regs[LD_KBD][0x31]; + uint16_t addr_2 = (dev->ld_regs[LD_KBD][0x32] << 8) | + dev->ld_regs[LD_KBD][0x33]; - switch (dev->regs[0x21] & 0x0b) { - case 0x02: - case 0x08: - case 0x0a: - io_sethandler(0x15c, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - break; - case 0x03: - case 0x09: - case 0x0b: - io_sethandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - break; + pc87309_log("%02X, %02X, %02X, %02X, %04X, %04X\n", + active, active_2, irq, irq_2, addr, addr_2); + + if (addr <= 0xfff8) { + pc87309_log("Enabling KBC #1 on %04X...\n", addr); + kbc_at_port_handler(0, active, addr, dev->kbc); } + + if (addr_2 <= 0xfff8) { + pc87309_log("Enabling KBC #2 on %04X...\n", addr_2); + kbc_at_port_handler(1, active, addr_2, dev->kbc); + } + + kbc_at_set_irq(0, active ? irq : 0xffff, dev->kbc); + kbc_at_set_irq(1, (active && active_2) ? irq_2 : 0xffff, dev->kbc); } static void fdc_handler(pc87309_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; - fdc_remove(dev->fdc); - active = (dev->ld_regs[0x00][0x00] & 0x01) && (dev->pm[0x00] & 0x08); - addr = ((dev->ld_regs[0x00][0x30] << 8) | dev->ld_regs[0x00][0x31]) - 0x0002; - irq = (dev->ld_regs[0x00][0x40] & 0x0f); + uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) && + (dev->pm[0x00] & 0x08); + uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f); + uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) | + dev->ld_regs[LD_FDC][0x31]) & 0xfff8; - if (active) { + if (active && (addr <= 0xfff8)) { + pc87309_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq); fdc_set_base(dev->fdc, addr); fdc_set_irq(dev->fdc, irq); } @@ -154,222 +193,351 @@ fdc_handler(pc87309_t *dev) static void lpt1_handler(pc87309_t *dev) { - uint8_t irq; - uint8_t active; - uint16_t addr; + uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) && + (dev->pm[0x00] & 0x10); + uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) | + dev->ld_regs[LD_LPT][0x31]; - lpt1_remove(); - - active = (dev->ld_regs[0x01][0x00] & 0x01) && (dev->pm[0x00] & 0x10); - addr = (dev->ld_regs[0x01][0x30] << 8) | dev->ld_regs[0x01][0x31]; - irq = (dev->ld_regs[0x01][0x40] & 0x0f); - - if (active) { + if (active && (addr <= 0xfffc)) { + pc87309_log("Enabling LPT1 on %04X...\n", addr); lpt1_setup(addr); - lpt1_irq(irq); - } + } else + lpt1_setup(0xffff); + + lpt1_irq(irq); } static void serial_handler(pc87309_t *dev, int uart) { - uint8_t irq; - uint8_t active; - uint16_t addr; - serial_remove(dev->uart[uart]); - active = (dev->ld_regs[0x03 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart))); - addr = (dev->ld_regs[0x03 - uart][0x30] << 8) | dev->ld_regs[0x03 - uart][0x31]; - irq = (dev->ld_regs[0x03 - uart][0x40] & 0x0f); + uint8_t active = (dev->ld_regs[LD_UART1 - uart][0x00] & 0x01) && + (dev->pm[0x00] & (1 << (6 - uart))); + uint8_t irq = (dev->ld_regs[LD_UART1 - uart][0x40] & 0x0f); + uint16_t addr = (dev->ld_regs[LD_UART1 - uart][0x30] << 8) | + dev->ld_regs[LD_UART1 - uart][0x31]; - if (active) + if (active && (addr <= 0xfff8)) { + pc87309_log("Enabling COM%i on %04X...\n", uart + 1, addr); serial_setup(dev->uart[uart], addr, irq); + } else + serial_setup(dev->uart[uart], 0x0000, irq); } static void pm_handler(pc87309_t *dev) { - uint8_t active; - uint16_t addr; - pc87309_pm_remove(dev); - active = (dev->ld_regs[0x04][0x00] & 0x01); - addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31]; + uint8_t active = (dev->ld_regs[LD_PM][0x00] & 0x01); + uint16_t addr = (dev->ld_regs[LD_PM][0x30] << 8) | + dev->ld_regs[LD_PM][0x31]; - if (active) + if (active) { + pc87309_log("Enabling power management on %04X...\n", addr); pc87309_pm_init(dev, addr); + } +} + +static void +superio_handler(pc87309_t *dev) +{ + if (dev->superio_base != 0x0000) + io_removehandler(dev->superio_base, 0x0002, + pc87309_read, NULL, NULL, + pc87309_write, NULL, NULL, dev); + + switch (dev->regs[0x22] & 0x0b) { + default: + dev->superio_base = 0x0000; + break; + case 0x02: + case 0x08: case 0x0a: + dev->superio_base = 0x015c; + break; + case 0x03: + case 0x09: case 0x0b: + dev->superio_base = 0x002e; + break; + } + + if (dev->superio_base != 0x0000) { + pc87309_log("Enabling Super I/O on %04X...\n", dev->superio_base); + io_sethandler(dev->superio_base, 0x0002, + pc87309_read, NULL, NULL, + pc87309_write, NULL, NULL, dev); + } } static void pc87309_write(uint16_t port, uint8_t val, void *priv) { - pc87309_t *dev = (pc87309_t *) priv; - uint8_t index; - - index = (port & 1) ? 0 : 1; + pc87309_t *dev = (pc87309_t *) priv; + uint8_t ld = dev->regs[0x07]; + uint8_t reg = dev->cur_reg - 0x30; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t old = dev->regs[dev->cur_reg]; if (index) { dev->cur_reg = val; return; } else { +#ifdef ENABLE_PC87309_LOG + if (dev->cur_reg >= 0x30) + pc87309_log("[%04X:%08X] [W] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, val); + else + pc87309_log("[%04X:%08X] [W] (%04X) %02X = %02X\n", + CS, cpu_state.pc, port, dev->cur_reg, val); +#endif switch (dev->cur_reg) { case 0x00: - case 0x02: - case 0x03: - case 0x06: - case 0x07: + case 0x02: case 0x03: + case 0x06: case 0x07: + dev->regs[dev->cur_reg] = val; + break; case 0x21: dev->regs[dev->cur_reg] = val; + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); superio_handler(dev); break; case 0x22: - dev->regs[dev->cur_reg] = val & 0x7f; + dev->regs[dev->cur_reg] = val; break; default: - if (dev->cur_reg >= 0x30) { - if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10)) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val; - } + if (dev->cur_reg >= 0x30) + old = dev->ld_regs[ld][reg]; break; } } switch (dev->cur_reg) { case 0x30: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01; - switch (dev->regs[0x07]) { - case 0x00: + switch (ld) { + default: + break; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x01: + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x02: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x03: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x04: + case LD_PM: + dev->ld_regs[ld][reg] = val; pm_handler(dev); break; - - default: - break; } break; + /* I/O Range Check. */ + case 0x31: + switch (ld) { + default: + break; + case LD_MIN ... LD_MAX: + if (ld != LD_MOUSE) + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* Base Address 0 MSB. */ case 0x60: - case 0x62: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07; - if (dev->cur_reg == 0x62) - break; - switch (dev->regs[0x07]) { - case 0x00: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x01: + case LD_LPT: + dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03); lpt1_handler(dev); break; - case 0x02: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x03: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x04: + case LD_PM: + dev->ld_regs[ld][reg] = val; pm_handler(dev); break; - - default: - break; } break; - case 0x63: - if (dev->regs[0x07] == 0x06) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xf8) | 0x04; - break; + /* Base Address 0 LSB. */ case 0x61: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); fdc_handler(dev); break; - case 0x01: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc; + case LD_LPT: + dev->ld_regs[ld][reg] = (old & 0x03) | (val & 0xfc); lpt1_handler(dev); break; - case 0x02: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_UART2: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); serial_handler(dev, 1); break; - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; + case LD_UART1: + dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8); serial_handler(dev, 0); break; - case 0x04: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe; + case LD_PM: + dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe); pm_handler(dev); break; - case 0x06: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8; - break; - - default: - break; } break; + /* Base Address 1 MSB (undocumented for Logical Device 7). */ + case 0x62: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + } + break; + /* Base Address 1 LSB (undocumented for Logical Device 7). */ + case 0x63: + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb); + kbc_handler(dev); + break; + } + break; + /* Interrupt Select. */ case 0x70: - case 0x74: - case 0x75: - switch (dev->regs[0x07]) { - case 0x00: + switch (ld) { + default: + break; + case LD_KBD: case LD_MOUSE: + dev->ld_regs[ld][reg] = val; + kbc_handler(dev); + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_handler(dev); break; - case 0x01: + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x02: + case LD_UART2: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 1); break; - case 0x03: + case LD_UART1: + dev->ld_regs[ld][reg] = val; serial_handler(dev, 0); break; - case 0x04: - pm_handler(dev); - break; - - default: - break; } break; + /* Interrupt Type. */ + case 0x71: + switch (ld) { + default: + break; + case LD_MIN ... LD_MAX: + if ((ld == LD_KBD) || (ld == LD_MOUSE)) + dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03); + else + dev->ld_regs[ld][reg] = (old & 0xfd) | (val & 0x02); + break; + } + break; + /* DMA Channel Select 0. */ + case 0x74: + switch (ld) { + default: + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; + fdc_handler(dev); + break; + case LD_LPT: + dev->ld_regs[ld][reg] = val; + lpt1_handler(dev); + break; + case LD_UART2: + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* DMA Channel Select 1. */ + case 0x75: + switch (ld) { + default: + break; + case LD_UART2: + dev->ld_regs[ld][reg] = val; + break; + } + break; + /* Configuration Register 0. */ case 0xf0: - switch (dev->regs[0x07]) { - case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1; + switch (ld) { + default: + break; + case LD_KBD: + dev->ld_regs[ld][reg] = val; + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0); fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0); break; - case 0x01: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3; + case LD_LPT: + dev->ld_regs[ld][reg] = val; lpt1_handler(dev); break; - case 0x02: - case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87; - break; - case 0x06: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1; - break; - - default: + case LD_UART2: case LD_UART1: + dev->ld_regs[ld][reg] = val; break; } break; + /* Configuration Register 1. */ case 0xf1: - if (dev->regs[0x07] == 0x00) - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f; + switch (ld) { + default: + break; + case LD_FDC: + dev->ld_regs[ld][reg] = val; + break; + } break; default: @@ -377,30 +545,44 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) } } -uint8_t +static uint8_t pc87309_read(uint16_t port, void *priv) { - const pc87309_t *dev = (pc87309_t *) priv; - uint8_t ret = 0xff; - uint8_t index; - - index = (port & 1) ? 0 : 1; + const pc87309_t *dev = (pc87309_t *) priv; + uint8_t ld = dev->regs[0x07]; + uint8_t reg = dev->cur_reg - 0x30; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; if (index) - ret = dev->cur_reg & 0x1f; + ret = dev->cur_reg; else { if (dev->cur_reg >= 0x30) - ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30]; + ret = dev->ld_regs[ld][reg]; + /* Write-only registers. */ + else if ((dev->cur_reg == 0x00) || + (dev->cur_reg == 0x02) || (dev->cur_reg == 0x03)) + ret = 0x00; else ret = dev->regs[dev->cur_reg]; +#ifdef ENABLE_PC87309_LOG + if (dev->cur_reg >= 0x30) + pc87309_log("[%04X:%08X] [R] (%04X) %02X:%02X = %02X\n", + CS, cpu_state.pc, port, ld, dev->cur_reg, ret); + else + pc87309_log("[%04X:%08X] [R] (%04X) %02X = %02X\n", + CS, cpu_state.pc, port, dev->cur_reg, ret); +#endif } return ret; } void -pc87309_reset(pc87309_t *dev) +pc87309_reset(void *priv) { + pc87309_t *dev = (pc87309_t *) priv; + memset(dev->regs, 0x00, 0x30); for (uint16_t i = 0; i < 256; i++) memset(dev->ld_regs[i], 0x00, 0xd0); @@ -409,65 +591,56 @@ pc87309_reset(pc87309_t *dev) dev->regs[0x20] = dev->id; dev->regs[0x21] = 0x04 | dev->baddr; - dev->ld_regs[0x00][0x01] = 0x01; - dev->ld_regs[0x00][0x30] = 0x03; - dev->ld_regs[0x00][0x31] = 0xf2; - dev->ld_regs[0x00][0x40] = 0x06; - dev->ld_regs[0x00][0x41] = 0x03; - dev->ld_regs[0x00][0x44] = 0x02; - dev->ld_regs[0x00][0x45] = 0x04; - dev->ld_regs[0x00][0xc0] = 0x02; + dev->ld_regs[LD_KBD ][0x00] = 0x01; + dev->ld_regs[LD_KBD ][0x31] = 0x60; + dev->ld_regs[LD_KBD ][0x33] = 0x64; + dev->ld_regs[LD_KBD ][0x40] = 0x01; + dev->ld_regs[LD_KBD ][0x41] = 0x02; + dev->ld_regs[LD_KBD ][0x44] = 0x04; + dev->ld_regs[LD_KBD ][0x45] = 0x04; + dev->ld_regs[LD_KBD ][0xc0] = 0x40; - dev->ld_regs[0x01][0x30] = 0x02; - dev->ld_regs[0x01][0x31] = 0x78; - dev->ld_regs[0x01][0x40] = 0x07; - dev->ld_regs[0x01][0x44] = 0x04; - dev->ld_regs[0x01][0x45] = 0x04; - dev->ld_regs[0x01][0xc0] = 0xf2; + dev->ld_regs[LD_MOUSE][0x40] = 0x0c; + dev->ld_regs[LD_MOUSE][0x41] = 0x02; + dev->ld_regs[LD_MOUSE][0x44] = 0x04; + dev->ld_regs[LD_MOUSE][0x45] = 0x04; - dev->ld_regs[0x02][0x30] = 0x02; - dev->ld_regs[0x02][0x31] = 0xf8; - dev->ld_regs[0x02][0x40] = 0x03; - dev->ld_regs[0x02][0x41] = 0x03; - dev->ld_regs[0x02][0x44] = 0x04; - dev->ld_regs[0x02][0x45] = 0x04; - dev->ld_regs[0x02][0xc0] = 0x02; + dev->ld_regs[LD_FDC ][0x01] = 0x01; + dev->ld_regs[LD_FDC ][0x30] = 0x03; + dev->ld_regs[LD_FDC ][0x31] = 0xf0; + dev->ld_regs[LD_FDC ][0x32] = 0x03; + dev->ld_regs[LD_FDC ][0x33] = 0xf7; + dev->ld_regs[LD_FDC ][0x40] = 0x06; + dev->ld_regs[LD_FDC ][0x41] = 0x03; + dev->ld_regs[LD_FDC ][0x44] = 0x02; + dev->ld_regs[LD_FDC ][0x45] = 0x04; + dev->ld_regs[LD_FDC ][0xc0] = 0x02; - dev->ld_regs[0x03][0x30] = 0x03; - dev->ld_regs[0x03][0x31] = 0xf8; - dev->ld_regs[0x03][0x40] = 0x04; - dev->ld_regs[0x03][0x41] = 0x03; - dev->ld_regs[0x03][0x44] = 0x04; - dev->ld_regs[0x03][0x45] = 0x04; - dev->ld_regs[0x03][0xc0] = 0x02; + dev->ld_regs[LD_LPT ][0x30] = 0x02; + dev->ld_regs[LD_LPT ][0x31] = 0x78; + dev->ld_regs[LD_LPT ][0x40] = 0x07; + dev->ld_regs[LD_LPT ][0x44] = 0x04; + dev->ld_regs[LD_LPT ][0x45] = 0x04; + dev->ld_regs[LD_LPT ][0xc0] = 0xf2; - dev->ld_regs[0x04][0x44] = 0x04; - dev->ld_regs[0x04][0x45] = 0x04; + dev->ld_regs[LD_UART2][0x30] = 0x02; + dev->ld_regs[LD_UART2][0x31] = 0xf8; + dev->ld_regs[LD_UART2][0x40] = 0x03; + dev->ld_regs[LD_UART2][0x41] = 0x03; + dev->ld_regs[LD_UART2][0x44] = 0x04; + dev->ld_regs[LD_UART2][0x45] = 0x04; + dev->ld_regs[LD_UART2][0xc0] = 0x02; - dev->ld_regs[0x05][0x40] = 0x0c; - dev->ld_regs[0x05][0x41] = 0x02; - dev->ld_regs[0x05][0x44] = 0x04; - dev->ld_regs[0x05][0x45] = 0x04; + dev->ld_regs[LD_UART1][0x30] = 0x03; + dev->ld_regs[LD_UART1][0x31] = 0xf8; + dev->ld_regs[LD_UART1][0x40] = 0x04; + dev->ld_regs[LD_UART1][0x41] = 0x03; + dev->ld_regs[LD_UART1][0x44] = 0x04; + dev->ld_regs[LD_UART1][0x45] = 0x04; + dev->ld_regs[LD_UART1][0xc0] = 0x02; - dev->ld_regs[0x06][0x01] = 0x01; - dev->ld_regs[0x06][0x31] = 0x60; - dev->ld_regs[0x06][0x33] = 0x64; - dev->ld_regs[0x06][0x40] = 0x01; - dev->ld_regs[0x06][0x41] = 0x02; - dev->ld_regs[0x06][0x44] = 0x04; - dev->ld_regs[0x06][0x45] = 0x04; - dev->ld_regs[0x06][0xc0] = 0x40; - - dev->regs[0x00] = 0x0B; - dev->regs[0x01] = 0x01; - dev->regs[0x03] = 0x01; - dev->regs[0x05] = 0x0D; - dev->regs[0x08] = 0x70; - dev->regs[0x09] = 0xC0; - dev->regs[0x0b] = 0x80; - dev->regs[0x0f] = 0x1E; - dev->regs[0x12] = 0x30; - dev->regs[0x19] = 0xEF; + dev->ld_regs[LD_PM ][0x44] = 0x04; + dev->ld_regs[LD_PM ][0x45] = 0x04; dev->pm[0] = 0x79; dev->pm[4] = 0x0e; @@ -478,11 +651,15 @@ pc87309_reset(pc87309_t *dev) 0 = 360 rpm @ 500 kbps for 3.5" 1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5" */ - lpt1_remove(); - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, 0); fdc_reset(dev->fdc); + kbc_handler(dev); + fdc_handler(dev); + lpt1_handler(dev); + serial_handler(dev, 0); + serial_handler(dev, 1); + pm_handler(dev); superio_handler(dev); } @@ -503,7 +680,27 @@ pc87309_init(const device_t *info) dev->fdc = device_add(&fdc_at_nsc_device); - dev->baddr = (info->local & 0x100) ? 8 : 9; + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + switch (info->local & PCX730X_KBC) { + default: + case PCX730X_AMI: + dev->kbc = device_add(&keyboard_ps2_intel_ami_pci_device); + break; + /* Optiplex! */ + case PCX730X_PHOENIX_42: + dev->kbc = device_add(&keyboard_ps2_phoenix_device); + break; + case PCX730X_PHOENIX_42I: + dev->kbc = device_add(&keyboard_ps2_phoenix_pci_device); + break; + } + + if (info->local & PCX730X_15C) + dev->baddr = 0x0a; + else + dev->baddr = 0x0b; pc87309_reset(dev); @@ -514,24 +711,10 @@ const device_t pc87309_device = { .name = "National Semiconductor PC87309 Super I/O", .internal_name = "pc87309", .flags = 0, - .local = 0xe0, + .local = 0, .init = pc87309_init, .close = pc87309_close, - .reset = NULL, - .available = NULL, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; - -const device_t pc87309_15c_device = { - .name = "National Semiconductor PC87309 Super I/O (Port 15Ch)", - .internal_name = "pc87309_15c", - .flags = 0, - .local = 0x1e0, - .init = pc87309_init, - .close = pc87309_close, - .reset = NULL, + .reset = pc87309_reset, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, From d8a53f6fdb09ed94c965282db9872139b2fbdcf7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 21 May 2025 20:55:00 +0200 Subject: [PATCH 0970/1190] Make it use the A12 BIOS. --- src/machine/m_at_socket7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 9ceebe2e0..3d51e1a06 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -974,7 +974,7 @@ machine_at_optiplex_gn_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/optiplex_gn/Gn_a11.rom", + ret = bios_load_linear("roms/machines/optiplex_gn/DELL.ROM", 0x000c0000, 262144, 0); if (bios_only || !ret) From e9a1768da935313187c2312f357966a1324bdae4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 00:35:07 +0200 Subject: [PATCH 0971/1190] KBC AT: Remove some excess logging. --- src/device/kbc_at.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 78fc32ffd..f068b8699 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2391,24 +2391,18 @@ kbc_at_port_handler(int num, int set, uint16_t port, void *priv) { atkbc_t *dev = (atkbc_t *) priv; - if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { - pclog("Disabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); - + if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) io_removehandler(dev->base_addr[num], 1, dev->handlers[num].read, NULL, NULL, dev->handlers[num].write, NULL, NULL, priv); - } dev->handler_enable[num] = set; dev->base_addr[num] = port; - if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) { - pclog("Enabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]); - + if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) io_sethandler(dev->base_addr[num], 1, dev->handlers[num].read, NULL, NULL, dev->handlers[num].write, NULL, NULL, priv); - } } void From f6dd42ca87010f7dcc1fb08979322aee61448198 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 00:54:57 +0200 Subject: [PATCH 0972/1190] Packard Bell PB410: Fix on-board video. --- src/machine/m_at_386dx_486.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 46b93a37f..c1f471ff3 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -396,7 +396,7 @@ machine_at_pb410a_init(const machine_t *model) device_add(&phoenix_486_jumper_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&ht216_32_pb410a_device); + device_add(machine_get_vid_device(machine)); return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f16f4e5ae..e864f580b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -6647,7 +6647,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &ht216_32_pb410a_device, .snd_device = NULL, .net_device = NULL }, From c8fbee1b62845e9894a849509527573cc96d48d1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 22 May 2025 06:20:04 +0200 Subject: [PATCH 0973/1190] Fixes to the two recently NSC Super I/O chips and the two boards that use the PC87309 (Tyan Tsunami ATX and the Freeway). --- src/machine/m_at_slot1.c | 1 - src/machine/m_at_slot2.c | 1 - src/sio/sio_pc87307.c | 4 +++- src/sio/sio_pc87309.c | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 773826316..c764b4229 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -585,7 +585,6 @@ machine_at_s1846_init(const machine_t *model) device_add(&i440bx_device); device_add(&piix4e_device); device_add_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309)); - device_add(&keyboard_ps2_ami_pci_device); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index 37c0acdfd..7bf412823 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -140,7 +140,6 @@ machine_at_fw6400gx_init(const machine_t *model) device_add(&i440gx_device); device_add(&piix4e_device); - device_add(&keyboard_ps2_ami_pci_device); device_add_params(&pc87309_device, (void *) (PCX730X_15C | PCX730X_AMI | PC87309_PC87309)); device_add(ics9xxx_get(ICS9250_08)); device_add(&sst_flash_29ee020_device); diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index 7bc9bb441..7e51c5975 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -12,11 +12,13 @@ * * Copyright 2020-2025 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/timer.h> @@ -400,7 +402,7 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) break; case 0x21: dev->regs[dev->cur_reg] = val; - fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !(val & 0x04)); break; case 0x22: dev->regs[dev->cur_reg] = val; diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index d2d3f4ac0..8bbbb7036 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -12,11 +12,13 @@ * * Copyright 2020-2025 Miran Grca. */ +#include #include #include #include #include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/io.h> #include <86box/timer.h> @@ -249,7 +251,7 @@ superio_handler(pc87309_t *dev) pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); - switch (dev->regs[0x22] & 0x0b) { + switch (dev->regs[0x21] & 0x0b) { default: dev->superio_base = 0x0000; break; @@ -300,7 +302,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) break; case 0x21: dev->regs[dev->cur_reg] = val; - fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04)); + fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !(val & 0x04)); superio_handler(dev); break; case 0x22: From 2139e3dd511cd0d9a099c4a558499a3ed50efd6b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 23 May 2025 00:34:12 +0600 Subject: [PATCH 0974/1190] Attempt to make OpenGL 3.0 filter settings consistent --- src/qt/qt_openglrenderer.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 45bae6ea7..9ca2d887e 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -1503,6 +1503,7 @@ OpenGLRenderer::render() /* loop through each pass */ for (i = 0; i < shader->num_passes; ++i) { + bool resetFiltering = false; struct shader_pass *pass = &shader->passes[i]; memcpy(pass->state.input_size, input->state.output_size, 2 * sizeof(GLfloat)); @@ -1524,8 +1525,14 @@ OpenGLRenderer::render() glw.glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id); glw.glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); - } else + } else { + resetFiltering = true; + glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, 0); glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + } glw.glClearColor(0, 0, 0, 1); glw.glClear(GL_COLOR_BUFFER_BIT); @@ -1570,6 +1577,13 @@ OpenGLRenderer::render() glw.glBindTexture(GL_TEXTURE_2D, 0); } + if (resetFiltering) { + glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, input->fbo.texture.min_filter); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, input->fbo.texture.mag_filter); + glw.glBindTexture(GL_TEXTURE_2D, 0); + } + input = pass; } @@ -1637,6 +1651,11 @@ OpenGLRenderer::render() pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); } + glw.glBindTexture(GL_TEXTURE_2D, input->fbo.texture.id); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, video_filter_method ? GL_LINEAR : GL_NEAREST); + glw.glBindTexture(GL_TEXTURE_2D, 0); + glw.glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); glw.glClearColor(0, 0, 0, 1); From 0278077a4ba75ed62ced41aa0a8b32cdc742ab8c Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Thu, 22 May 2025 22:48:52 +0300 Subject: [PATCH 0975/1190] Add the Dell OptiPlex GXa --- src/include/86box/machine.h | 2 +- src/machine/m_at_slot1.c | 33 +++++++++++++++++++++++++++++ src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index cbf2fda15..be9f17505 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -822,8 +822,8 @@ extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); extern int machine_at_lx6_init(const machine_t *); +extern int machine_at_optiplex_gxa_init(const machine_t *); extern int machine_at_spitfire_init(const machine_t *); - extern int machine_at_ma30d_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index c764b4229..d7a47c901 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -150,6 +150,39 @@ machine_at_lx6_init(const machine_t *model) return ret; } +int +machine_at_optiplex_gxa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/optiplex_gxa/DELL.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + + device_add(&i440lx_device); + device_add(&piix4_device); + device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x7, 256); + + return ret; +} + int machine_at_spitfire_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 10ce1694b..d2bd76ca6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15170,6 +15170,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a National Semiconductor PC87307 Super I/O with on-chip KBC, which has one of these + firmwares: AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix MultiKey/42i 4.16. */ + { + .name = "[i440LX] Dell OptiPlex GXa", + .internal_name = "optiplex_gxa", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440LX, + .init = machine_at_optiplex_gxa_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK(CPU_PENTIUMPRO, CPU_CYRIX3S), + .min_bus = 66666667, + .max_bus = 66666667, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 5.0 + }, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, /* Video: ATi 3D Rage Pro, Network: 3Com 3C905, Sound: Crystal CS4236B */ + .ram = { + .min = 8192, + .max = 786432, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, /* not yet emulated */ + .snd_device = &cs4236b_onboard_device, + .net_device = NULL /* not yet emulated */ + }, /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix MultiKey/42 (version 1.38) KBC firmware. */ { From 734885b930c90e7b94a10dad668ff83adea9df3f Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 23 May 2025 00:01:42 +0300 Subject: [PATCH 0976/1190] Fix the onboard audio on the OptiPlex GXa --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d2bd76ca6..de830cb89 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -15208,7 +15208,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, /* not yet emulated */ - .snd_device = &cs4236b_onboard_device, + .snd_device = &cs4236b_device, .net_device = NULL /* not yet emulated */ }, /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix From 8c2ee25b39e9fcc4f50ee1e4c32f401ac2f31e9c Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 23 May 2025 00:13:55 +0300 Subject: [PATCH 0977/1190] Fix a small mistake with the IRQ table of the OptiPlex GXA --- src/machine/m_at_slot1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index d7a47c901..54cf1a03a 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -167,7 +167,7 @@ machine_at_optiplex_gxa_init(const machine_t *model) pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); From 8d971d06966e7565cacea9de2b4b70a13c23a0ba Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Fri, 23 May 2025 11:10:05 +0300 Subject: [PATCH 0978/1190] Add the Dell Dimension XPS Pro___n --- src/include/86box/machine.h | 1 + src/machine/m_at_socket8.c | 36 +++++++++++++++++++++++++++++++ src/machine/machine_table.c | 42 ++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index be9f17505..ced3397e1 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -804,6 +804,7 @@ extern int machine_at_686nx_init(const machine_t *); extern int machine_at_acerv60n_init(const machine_t *); extern int machine_at_lgibmx61_init(const machine_t *); extern int machine_at_vs440fx_init(const machine_t *); +extern int machine_at_dellvenus_init(const machine_t *); extern int machine_at_gw2kvenus_init(const machine_t *); extern int machine_at_ap440fx_init(const machine_t *); extern int machine_at_mb600n_init(const machine_t *); diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index aabfb9b4f..d81b41502 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -260,6 +260,42 @@ machine_at_vs440fx_init(const machine_t *model) return ret; } +int +machine_at_dellvenus_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2("roms/machines/dellvenus/1006CS1J.BIO", + "roms/machines/dellvenus/1006CS1J.BI1", + "roms/machines/dellvenus/1006CS1J.BI2", + "roms/machines/dellvenus/1006CS1J.BI3", + "roms/machines/dellvenus/1006CS1J.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307)); + + device_add(&intel_flash_bxt_ami_device); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(machine_get_snd_device(machine)); + + return ret; +} + int machine_at_gw2kvenus_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index de830cb89..9a9cb5cf1 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14675,7 +14675,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* It's a Intel VS440FX with a Gateway 2000 OEM BIOS */ + /* It's an Intel VS440FX with a Dell OEM BIOS */ + { + .name = "[i440FX] Dell Dimension XPS Pro___n", + .internal_name = "dellvenus", + .type = MACHINE_TYPE_SOCKET8, + .chipset = MACHINE_CHIPSET_INTEL_440FX, + .init = machine_at_dellvenus_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET8, + .block = CPU_BLOCK_NONE, + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2100, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_GAMEPORT | MACHINE_USB, + .ram = { + .min = 8192, + .max = 524288, + .step = 8192 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = &cs4236_onboard_device, + .net_device = NULL + }, + /* It's an Intel VS440FX with a Gateway 2000 OEM BIOS */ { .name = "[i440FX] Gateway 2000 Venus", .internal_name = "gw2kvenus", From 054be5c76cca2ed3820607b3bd0dbc368ec60620 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Fri, 23 May 2025 22:50:05 +0700 Subject: [PATCH 0979/1190] Machine table fixes 1. Unblock original i486 and Am486 CPUs and correct minimum RAM on Acer P3 (since it was copied from Soyo 4SAW2 a while ago) 2. Correct RAM step on few machines with SiS chipset 3. Correct minimum RAM on PCChips M579 and M729 respectively 4. Gigabyte GA-5SG100 does support 60MHZ bus speed according to its manual, so change its minimum bus speed to 60MHZ --- src/machine/machine_table.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9a9cb5cf1..6f004ee78 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8650,7 +8650,7 @@ const machine_t machines[] = { .gpio_acpi_handler = NULL, .cpu = { .package = CPU_PKG_SOCKET3, - .block = CPU_BLOCK(CPU_i486SX, CPU_i486DX, CPU_Am486SX, CPU_Am486DX), + .block = CPU_BLOCK_NONE, .min_bus = 0, .max_bus = 0, .min_voltage = 0, @@ -8661,7 +8661,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, .ram = { - .min = 2048, + .min = 1024, .max = 131072, .step = 1024 }, @@ -13838,7 +13838,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 1572864, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -13878,7 +13878,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 1572864, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -13920,7 +13920,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 786432, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -14084,7 +14084,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 1024, + .min = 8192, .max = 1572864, .step = 8192 }, @@ -14443,7 +14443,7 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK_NONE, - .min_bus = 66666667, + .min_bus = 60000000, .max_bus = 100000000, .min_voltage = 2000, .max_voltage = 3520, @@ -14455,7 +14455,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 786432, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -15027,7 +15027,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_GAMEPORT | MACHINE_USB, /* Machine has internal sound: C-Media CMI8330 */ .ram = { - .min = 1024, + .min = 8192, .max = 1572864, .step = 8192 }, From 8556d05acd5c64ee531b59806dd9c191a2e96792 Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Fri, 23 May 2025 22:54:27 +0700 Subject: [PATCH 0980/1190] Revert minimum RAM on Acer P3 --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 6f004ee78..ba24ea742 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8661,7 +8661,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_VIDEO, .ram = { - .min = 1024, + .min = 2048, .max = 131072, .step = 1024 }, From e083daf4bb545e015611738db45badb64334a3df Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 24 May 2025 06:17:16 +0200 Subject: [PATCH 0981/1190] Fix on-board audio on the GXL and the jumpers on the XPS P60 and 560/L. --- src/chipset/intel_piix.c | 5 +++- src/chipset/intel_sio.c | 18 ++++++++++++- src/device/CMakeLists.txt | 1 + src/device/kbc_at.c | 4 ++- src/device/postcard.c | 6 +++-- src/include/86box/chipset.h | 2 ++ src/include/86box/machine.h | 1 + src/machine/m_at_socket4.c | 14 ++++++---- src/machine/m_at_socket5.c | 1 + src/machine/machine_table.c | 6 +++++ src/sound/snd_sb.c | 52 ++++++++++++++++++++----------------- 11 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index b73285f70..9867a0fa7 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1621,7 +1621,10 @@ piix_init(const device_t *info) else cpu_set_isa_pci_div(3); - dma_alias_set(); + if (dev->type > 1) + dma_alias_set(); + else + dma_alias_set_piix(); if (dev->type < 4) pci_enable_mirq(0); diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index 9b6d28ab1..b11ec0765 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -355,7 +355,23 @@ sio_config_read(uint16_t port, UNUSED(void *priv)) ret = 0xff; break; case 5: - ret = 0xd3; + /* + Dell Dimension XPS P60 jumpers: + - Bit 5: Disable CMOS Setup (1 = yes, 0 = no). + + Dell OptiPlex 560/L jumpers: + - Bit 1: Password (1 = disable, 0 = enable); + - Bit 5: Clear CMOS (1 = no, 0 = yes). + - Bits 7, 6: Board type: + - 0, 0 = L; + - 0, 1 = MT; + - 1, 0 = M; + - 1, 1 = M. + */ + if (!strcmp(machine_get_internal_name(), "opti560l")) + ret = 0x20; + else + ret = 0xd3; switch (cpu_pci_speed) { case 20000000: diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index bbbab22fd..486d40b07 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(dev OBJECT cartridge.c cassette.c clock_ics9xxx.c + dell_jumper.c hasp.c hwm.c hwm_gl518sm.c diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 9a1800ed9..dc93a4fba 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1125,7 +1125,9 @@ write_cmd_generic(void *priv, uint8_t val) */ uint8_t p1 = 0x30; kbc_delay_to_ob(dev, p1, 0, 0x00); - } else if (!strcmp(machine_get_internal_name(), "dellplato") || !strcmp(machine_get_internal_name(), "dellhannibalp")) { + } else if (!strcmp(machine_get_internal_name(), "dellplato") || + !strcmp(machine_get_internal_name(), "dellhannibalp") || + !strcmp(machine_get_internal_name(), "dellxp60")) { /* Dell Dimension XPS Pxxx & Pxxxa/Mxxxa: - Bit 3: Password disable jumper (must be clear); diff --git a/src/device/postcard.c b/src/device/postcard.c index 058684c0b..19d81b692 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -99,7 +99,8 @@ postcard_setui(void) ps[1][0], ps[1][1], ps[1][2], ps[1][3]); break; } - } else if (strstr(machines[machine].name, " Dell ")) { + } else if (strstr(machines[machine].name, " Dell ") && + (machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX)) { char dell_diags[10] = { 0 }; if (!postcard_written[1]) @@ -223,7 +224,8 @@ postcard_init(UNUSED(const device_t *info)) io_sethandler(postcard_port, postcard_ports_num, NULL, NULL, NULL, postcard_write, NULL, NULL, NULL); - if (strstr(machines[machine].name, " Dell ")) + if (strstr(machines[machine].name, " Dell ") && + (machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX)) io_sethandler(0x00e0, 0x0001, NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL); diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 94884383b..688a5fecb 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -197,6 +197,8 @@ extern const device_t vlsi_scamp_device; extern const device_t wd76c10_device; /* Miscellaneous Hardware */ +extern const device_t dell_jumper_device; + extern const device_t nec_mate_unk_device; extern const device_t phoenix_486_jumper_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ced3397e1..0dbbe98c5 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -385,6 +385,7 @@ extern int machine_get_min_ram(int m); extern int machine_get_max_ram(int m); extern int machine_get_ram_granularity(int m); extern int machine_get_type(int m); +extern int machine_get_chipset(int m); extern void machine_close(void); extern int machine_has_mouse(void); extern int machine_is_sony(void); diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 88474d431..033a2e5fe 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -157,7 +157,9 @@ machine_at_dellxp60_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); + machine_at_common_init_ex(model, 2); + + device_add(&amstrad_megapc_nvr_device); device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2); @@ -170,7 +172,7 @@ machine_at_dellxp60_init(const machine_t *model) pci_register_slot(0x06, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430lx_device); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_phoenix_device); device_add(&sio_zb_device); device_add(&fdc37c665_device); device_add(&intel_flash_bxt_ami_device); @@ -189,8 +191,10 @@ machine_at_opti560l_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init(model); - device_add(&ide_pci_2ch_device); + machine_at_common_init_ex(model, 2); + + device_add(&amstrad_megapc_nvr_device); + device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); @@ -199,7 +203,7 @@ machine_at_opti560l_init(const machine_t *model) pci_register_slot(0x08, PCI_CARD_NORMAL, 2, 1, 3, 4); pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&i430lx_device); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_phoenix_device); device_add(&sio_zb_device); device_add(&i82091aa_device); device_add(&intel_flash_bxt_ami_device); diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 5572d0484..442281811 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -268,6 +268,7 @@ machine_at_optiplex_gxl_init(const machine_t *model) device_add(&i430fx_device); device_add(&piix_device); device_add(&pc87332_device); + device_add(&dell_jumper_device); device_add(&intel_flash_bxt_device); return ret; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9a9cb5cf1..2664e1819 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -17346,6 +17346,12 @@ machine_get_type(int m) return (machines[m].type); } +int +machine_get_chipset(int m) +{ + return (machines[m].chipset); +} + int machine_get_machine_from_internal_name(const char *s) { diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index e89946486..14726d358 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -2091,35 +2091,39 @@ sb_vibra16s_onboard_relocate_base(uint16_t new_addr, void *priv) sb_t *sb = (sb_t *) priv; uint16_t addr = sb->dsp.sb_addr; - io_removehandler(addr, 0x0004, - sb->opl.read, NULL, NULL, - sb->opl.write, NULL, NULL, - sb->opl.priv); - io_removehandler(addr + 8, 0x0002, - sb->opl.read, NULL, NULL, - sb->opl.write, NULL, NULL, - sb->opl.priv); - io_removehandler(addr + 4, 0x0002, - sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, - sb); + if (addr != 0x0000) { + io_removehandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_removehandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + } sb_dsp_setaddr(&sb->dsp, 0); addr = new_addr; - io_sethandler(addr, 0x0004, - sb->opl.read, NULL, NULL, - sb->opl.write, NULL, NULL, - sb->opl.priv); - io_sethandler(addr + 8, 0x0002, - sb->opl.read, NULL, NULL, - sb->opl.write, NULL, NULL, - sb->opl.priv); - io_sethandler(addr + 4, 0x0002, - sb_ct1745_mixer_read, NULL, NULL, - sb_ct1745_mixer_write, NULL, NULL, - sb); + if (addr != 0x0000) { + io_sethandler(addr, 0x0004, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 4, 0x0002, + sb_ct1745_mixer_read, NULL, NULL, + sb_ct1745_mixer_write, NULL, NULL, + sb); + } sb_dsp_setaddr(&sb->dsp, addr); } From fa5f1224cafb09af021774f843eaf1a31a01095a Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 24 May 2025 07:10:49 +0200 Subject: [PATCH 0982/1190] Implement the DEC/Intel 21152-AB PCI bridge for the Dell Gn+/GXa riser card. --- src/device/pci_bridge.c | 64 ++++++++++++++++++++++++++++++++++---- src/include/86box/pci.h | 1 + src/machine/m_at_slot1.c | 10 +++--- src/machine/m_at_socket7.c | 4 ++- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 7dda00aee..8893acf69 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -30,8 +30,10 @@ #include <86box/mem.h> #include <86box/device.h> #include <86box/pci.h> +#include <86box/plat_fallthrough.h> #define PCI_BRIDGE_DEC_21150 0x10110022 +#define PCI_BRIDGE_DEC_21152 0x10110024 #define AGP_BRIDGE_ALI_M5243 0x10b95243 #define AGP_BRIDGE_ALI_M5247 0x10b95247 #define AGP_BRIDGE_INTEL_440LX 0x80867181 @@ -242,12 +244,15 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) case 0x40: if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x32; + else if (dev->local == PCI_BRIDGE_DEC_21152) + val &= 0x12; break; case 0x41: if (AGP_BRIDGE_VIA(dev->local)) val &= 0x7e; - else if (dev->local == PCI_BRIDGE_DEC_21150) + else if ((dev->local == PCI_BRIDGE_DEC_21150) || + (dev->local == PCI_BRIDGE_DEC_21152)) val &= 0x07; break; @@ -257,18 +262,22 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) break; case 0x43: - if (dev->local == PCI_BRIDGE_DEC_21150) + if ((dev->local == PCI_BRIDGE_DEC_21150) || + (dev->local == PCI_BRIDGE_DEC_21152)) val &= 0x03; break; case 0x64: - if (dev->local == PCI_BRIDGE_DEC_21150) + if ((dev->local == PCI_BRIDGE_DEC_21150) || + (dev->local == PCI_BRIDGE_DEC_21152)) val &= 0x7e; break; case 0x69: if (dev->local == PCI_BRIDGE_DEC_21150) val &= 0x3f; + else if (dev->local == PCI_BRIDGE_DEC_21152) + val = (val & 0x01) | 0x3e; break; case 0x86: @@ -302,6 +311,15 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv) break; case 0xe0: + if (AGP_BRIDGE_ALI(dev->local)) { + if (!(dev->ctl & 0x20)) + return; + } else if (dev->local == PCI_BRIDGE_DEC_21152) + val &= 0x03; + else + return; + break; + case 0xe1: if (AGP_BRIDGE_ALI(dev->local)) { if (!(dev->ctl & 0x20)) @@ -399,6 +417,14 @@ pci_bridge_reset(void *priv) /* command and status */ switch (dev->local) { + case PCI_BRIDGE_DEC_21152: + dev->regs[0x08] = 0x03; + dev->regs[0x34] = 0xdc; + dev->regs[0x69] = 0x3e; + dev->regs[0xdc] = 0x01; + dev->regs[0xde] = 0x01; + dev->regs[0xe2] = 0x80; + fallthrough; case PCI_BRIDGE_DEC_21150: dev->regs[0x06] = 0x80; dev->regs[0x07] = 0x02; @@ -490,6 +516,8 @@ pci_bridge_init(const device_t *info) uint8_t interrupt_count; uint8_t interrupt_mask; uint8_t slot_count; + uint8_t dell_slots[3] = { 0x09, 0x0a, 0x0b }; + uint8_t dell_interrupts[3][4] = { { 1, 2, 3, 4 }, { 4, 2, 1, 3 }, { 1, 3, 4, 2 } }; pci_bridge_t *dev = (pci_bridge_t *) calloc(1, sizeof(pci_bridge_t)); @@ -499,7 +527,10 @@ pci_bridge_init(const device_t *info) pci_bridge_reset(dev); - pci_add_bridge(AGP_BRIDGE(dev->local), pci_bridge_read, pci_bridge_write, dev, &dev->slot); + if (info->local == PCI_BRIDGE_DEC_21152) + pci_add_card(PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev, &dev->slot); + else + pci_add_bridge(AGP_BRIDGE(dev->local), pci_bridge_read, pci_bridge_write, dev, &dev->slot); interrupt_count = sizeof(interrupts); interrupt_mask = interrupt_count - 1; @@ -513,16 +544,23 @@ pci_bridge_init(const device_t *info) if (info->local == PCI_BRIDGE_DEC_21150) slot_count = 9; /* 9 bus masters */ + else if (info->local == PCI_BRIDGE_DEC_21152) + slot_count = 3; /* 3 bus masters */ else slot_count = 1; /* AGP bridges always have 1 slot */ for (uint8_t i = 0; i < slot_count; i++) { + uint8_t slot = i; + if (info->local == PCI_BRIDGE_DEC_21152) { + slot = dell_slots[i]; + memcpy(interrupts, dell_interrupts[i], 4); + } /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", - dev->bus_index, i, interrupts[i & interrupt_mask], + dev->bus_index, slot, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); - pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, + pci_register_bus_slot(dev->bus_index, slot, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], @@ -547,6 +585,20 @@ const device_t dec21150_device = { .config = NULL }; +const device_t dec21152_device = { + .name = "DEC 21152 PCI Bridge", + .internal_name = "dec21152", + .flags = DEVICE_PCI, + .local = PCI_BRIDGE_DEC_21152, + .init = pci_bridge_init, + .close = NULL, + .reset = pci_bridge_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + /* AGP bridges */ const device_t ali5243_agp_device = { .name = "ALi M5243 AGP Bridge", diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 097fcf502..462b4f821 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -286,6 +286,7 @@ extern void pci_bridge_set_ctl(void *priv, uint8_t ctl); #ifdef EMU_DEVICE_H extern const device_t dec21150_device; +extern const device_t dec21152_device; extern const device_t ali5243_agp_device; extern const device_t ali5247_agp_device; diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 54cf1a03a..a147d0e13 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -164,18 +164,20 @@ machine_at_optiplex_gxa_init(const machine_t *model) machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0F, PCI_CARD_BRIDGE, 1, 2, 3, 4); if (sound_card_current[0] == SOUND_INTERNAL) device_add(machine_get_snd_device(machine)); device_add(&i440lx_device); device_add(&piix4_device); + device_add(&dec21152_device); device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 3d51e1a06..7d2441e18 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -24,7 +24,6 @@ #include <86box/mem.h> #include <86box/io.h> #include <86box/rom.h> -#include <86box/pci.h> #include <86box/device.h> #include <86box/chipset.h> #include <86box/hdc.h> @@ -45,6 +44,7 @@ #include <86box/scsi_ncr53c8xx.h> #include <86box/thread.h> #include <86box/network.h> +#include <86box/pci.h> int machine_at_acerv35n_init(const machine_t *model) @@ -989,6 +989,7 @@ machine_at_optiplex_gn_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */ pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x0F, PCI_CARD_BRIDGE, 1, 2, 3, 4); if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); @@ -998,6 +999,7 @@ machine_at_optiplex_gn_init(const machine_t *model) device_add(&i430tx_device); device_add(&piix4_device); + device_add(&dec21152_device); device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); From e1a4f3fbaa19be6e6cc694ff1b116a94bbc47148 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 24 May 2025 08:23:28 +0200 Subject: [PATCH 0983/1190] Forgot the dell_jumper.c. --- src/device/dell_jumper.c | 175 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 src/device/dell_jumper.c diff --git a/src/device/dell_jumper.c b/src/device/dell_jumper.c new file mode 100644 index 000000000..12fc3d13b --- /dev/null +++ b/src/device/dell_jumper.c @@ -0,0 +1,175 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Dell 486 and 586 Jumper Readout. + * + * Register 0x02: + * - Bit 0: ATX power: 1 = off, 0 = on. + * + * Register 0x05: + * - Appears to be: 0x02 = On-board audio enabled; + * 0x07 = On-board audio disabled. + * + * Register 0x07: + * - Bit 0: On-board NIC: 1 = present, 0 = absent; + * - Bit 1: On-board audio: 1 = present, 0 = absent; + * - Bits 4-2: + * - 0, 0, 0 = GXL; + * - 0, 0, 1 = GL+; + * - 0, 1, 0 = GXMT; + * - 0, 1, 1 = GMT+; + * - 1, 0, 0 = GXM; + * - 1, 0, 1 = GM+; + * - 1, 1, 0 = WS; + * - 1, 1, 1 = GWS+. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/sound.h> +#include <86box/chipset.h> +#include <86box/plat.h> +#include <86box/plat_unused.h> + +typedef struct dell_jumper_t { + uint8_t index; + uint8_t regs[256]; +} dell_jumper_t; + +#ifdef ENABLE_DELL_JUMPER_LOG +int dell_jumper_do_log = ENABLE_DELL_JUMPER_LOG; + +static void +dell_jumper_log(const char *fmt, ...) +{ + va_list ap; + + if (dell_jumper_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define dell_jumper_log(fmt, ...) +#endif + +static void +dell_jumper_write(uint16_t addr, uint8_t val, void *priv) +{ + dell_jumper_t *dev = (dell_jumper_t *) priv; + + dell_jumper_log("Dell Jumper: Write %02x\n", val); + + if (addr & 1) switch (dev->index) { + default: + dev->regs[dev->index] = val; + break; + case 0x02: + dev->regs[dev->index] = val; + if (val & 0x04) + /* Soft power off. */ + plat_power_off(); + break; + case 0x05: + dev->regs[dev->index] = (dev->regs[dev->index] & 0x02) | (val & 0xfd); + if (machine_snd != NULL) switch (val & 0x05) { + default: + case 0x05: + sb_vibra16s_onboard_relocate_base(0x0000, machine_snd); + break; + case 0x00: + sb_vibra16s_onboard_relocate_base(0x0220, machine_snd); + break; + } + break; + case 0x07: + break; + } else + dev->index = val; +} + +static uint8_t +dell_jumper_read(uint16_t addr, void *priv) +{ + const dell_jumper_t *dev = (dell_jumper_t *) priv; + uint8_t ret = 0xff; + + dell_jumper_log("Dell Jumper: Read %02x\n", dev->jumper); + + if (addr & 1) + ret = dev->regs[dev->index]; + else + ret = dev->index; + + return ret; +} + +static void +dell_jumper_reset(void *priv) +{ + dell_jumper_t *dev = (dell_jumper_t *) priv; + + dev->index = 0x00; + memset(dev->regs, 0x00, 256); + + if (sound_card_current[0] == SOUND_INTERNAL) + /* GXL, on-board audio present, on-board NIC absent. */ + dev->regs[0x07] = 0x02; + else + /* GXL, on-board audio absent, on-board NIC absent. */ + dev->regs[0x07] = 0x00; +} + +static void +dell_jumper_close(void *priv) +{ + dell_jumper_t *dev = (dell_jumper_t *) priv; + + free(dev); +} + +static void * +dell_jumper_init(const device_t *info) +{ + dell_jumper_t *dev = (dell_jumper_t *) calloc(1, sizeof(dell_jumper_t)); + + dell_jumper_reset(dev); + + io_sethandler(0x00e8, 0x0002, dell_jumper_read, NULL, NULL, dell_jumper_write, NULL, NULL, dev); + + return dev; +} + +const device_t dell_jumper_device = { + .name = "Dell Jumper Readout", + .internal_name = "dell_jumper", + .flags = 0, + .local = 0, + .init = dell_jumper_init, + .close = dell_jumper_close, + .reset = dell_jumper_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; From 121e5f6b60e8579a8d8eaa9ab22db5bf782496da Mon Sep 17 00:00:00 2001 From: Jester Date: Sat, 24 May 2025 14:32:43 +0200 Subject: [PATCH 0984/1190] Update m_xt_olivetti.c add Olivetti M240 BIOS 2.12 --- src/machine/m_xt_olivetti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 34ca441ec..7cfab9c11 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -2366,8 +2366,8 @@ machine_xt_m240_init(const machine_t *model) m24_kbd_t *m24_kbd; nvr_t *nvr; - ret = bios_load_interleaved("roms/machines/m240/olivetti_m240_pchj_2.11_low.bin", - "roms/machines/m240/olivetti_m240_pchk_2.11_high.bin", + ret = bios_load_interleaved("roms/machines/m240/olivetti_m240_pchj_2.12_low.bin", + "roms/machines/m240/olivetti_m240_pchk_2.12_high.bin", 0x000f8000, 32768, 0); if (bios_only || !ret) From dac9f6ee8a26d83ba415d2693f237bfafec707cd Mon Sep 17 00:00:00 2001 From: MaxwellS04 Date: Sat, 24 May 2025 21:04:10 +0700 Subject: [PATCH 0985/1190] RAM step corrections for SiS 5600 machines --- src/machine/machine_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 4bbf7f412..f72da7338 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16108,7 +16108,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 1572864, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -16148,7 +16148,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 1572864, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, @@ -16909,7 +16909,7 @@ const machine_t machines[] = { .ram = { .min = 8192, .max = 1572864, - .step = 1024 + .step = 8192 }, .nvrmask = 255, .kbc_device = NULL, From 1754deff4dda4286cc0a091f6c46cdc91f60a49e Mon Sep 17 00:00:00 2001 From: Jester Date: Sat, 24 May 2025 18:00:53 +0200 Subject: [PATCH 0986/1190] Fix wrong filename used for M240 BIOS I only updated the number, but should have changed the correct filename, oopsie --- src/machine/m_xt_olivetti.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 7cfab9c11..acdb77fd1 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -2366,8 +2366,8 @@ machine_xt_m240_init(const machine_t *model) m24_kbd_t *m24_kbd; nvr_t *nvr; - ret = bios_load_interleaved("roms/machines/m240/olivetti_m240_pchj_2.12_low.bin", - "roms/machines/m240/olivetti_m240_pchk_2.12_high.bin", + ret = bios_load_interleaved("roms/machines/m240/olivetti_m240_pchm_2.12_low.bin", + "roms/machines/m240/olivetti_m240_pchl_2.12_high.bin", 0x000f8000, 32768, 0); if (bios_only || !ret) From a1a3ed22f4a9defc0bb0eaa923ff607ab37a8582 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 25 May 2025 01:39:58 +0200 Subject: [PATCH 0987/1190] Fix RZ-1000 so the AMI 062594 BIOS'es of the SB486PV don't disable it. --- src/disk/hdc_ide_rz1000.c | 41 +++--------------------------------- src/machine/m_at_386dx_486.c | 1 - 2 files changed, 3 insertions(+), 39 deletions(-) diff --git a/src/disk/hdc_ide_rz1000.c b/src/disk/hdc_ide_rz1000.c index e2c7179ad..06586b267 100644 --- a/src/disk/hdc_ide_rz1000.c +++ b/src/disk/hdc_ide_rz1000.c @@ -130,38 +130,6 @@ rz1000_pci_write(int func, int addr, uint8_t val, void *priv) rz1000_ide_handlers(dev); } break; - case 0x10: - dev->regs[0x10] = (val & 0xf8) | 1; - rz1000_ide_handlers(dev); - break; - case 0x11: - dev->regs[0x11] = val; - rz1000_ide_handlers(dev); - break; - case 0x14: - dev->regs[0x14] = (val & 0xfc) | 1; - rz1000_ide_handlers(dev); - break; - case 0x15: - dev->regs[0x15] = val; - rz1000_ide_handlers(dev); - break; - case 0x18: - dev->regs[0x18] = (val & 0xf8) | 1; - rz1000_ide_handlers(dev); - break; - case 0x19: - dev->regs[0x19] = val; - rz1000_ide_handlers(dev); - break; - case 0x1c: - dev->regs[0x1c] = (val & 0xfc) | 1; - rz1000_ide_handlers(dev); - break; - case 0x1d: - dev->regs[0x1d] = val; - rz1000_ide_handlers(dev); - break; case 0x40 ... 0x4f: dev->regs[addr] = val; break; @@ -233,16 +201,13 @@ rz1000_reset(void *priv) dev->regs[0x01] = 0x10; dev->regs[0x02] = 0x00; /* RZ-1000 */ dev->regs[0x03] = 0x10; - dev->regs[0x04] = 0x01; + dev->regs[0x04] = 0x00; dev->regs[0x07] = 0x02; /* DEVSEL timing: 01 medium */ dev->regs[0x08] = 0x02; /* Revision 02 */ dev->regs[0x09] = dev->local; /* Programming interface */ dev->regs[0x0a] = 0x01; /* IDE controller */ dev->regs[0x0b] = 0x01; /* Mass storage controller */ - dev->regs[0x3c] = 0x14; /* IRQ 14 */ - dev->regs[0x3d] = 0x01; /* INTA */ - dev->irq_mode[0] = dev->irq_mode[1] = 0; dev->irq_pin = PCI_INTA; dev->irq_line = 14; @@ -299,7 +264,7 @@ const device_t ide_rz1000_pci_device = { .name = "PC Technology RZ-1000 PCI", .internal_name = "ide_rz1000_pci", .flags = DEVICE_PCI, - .local = 0x6000a, + .local = 0x60000, .init = rz1000_init, .close = rz1000_close, .reset = rz1000_reset, @@ -313,7 +278,7 @@ const device_t ide_rz1000_pci_single_channel_device = { .name = "PC Technology RZ-1000 PCI", .internal_name = "ide_rz1000_pci_single_channel", .flags = DEVICE_PCI, - .local = 0x2000a, + .local = 0x20000, .init = rz1000_init, .close = rz1000_close, .reset = rz1000_reset, diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index c1f471ff3..9f7534244 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1727,7 +1727,6 @@ machine_at_sb486pv_init(const machine_t *model) device_context_restore(); machine_at_common_init(model); - device_add(&ide_pci_device); pci_init(PCI_CONFIG_TYPE_2); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); From c58ef2be81956e40150b6c24969b83e65abf4227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 25 May 2025 11:03:21 +0200 Subject: [PATCH 0988/1190] IBM PS/ValuePoint P60: Remove RZ-1000 - primary IDE is controlled by the Super I/O chip, fixes #5628. --- src/machine/m_at_socket4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/machine/m_at_socket4.c b/src/machine/m_at_socket4.c index 033a2e5fe..2d4e1a51a 100644 --- a/src/machine/m_at_socket4.c +++ b/src/machine/m_at_socket4.c @@ -270,8 +270,7 @@ machine_at_valuepointp60_init(const machine_t *model) pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_ps1_pci_device); device_add(&sio_device); - device_add(&ide_rz1000_pci_single_channel_device); - device_add(&fdc37c665_device); + device_add(&fdc37c665_ide_device); device_add(&intel_flash_bxt_ami_device); device_add(&i430lx_device); From 72c093e7db61f2289445cca975406668b323e641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 25 May 2025 11:07:27 +0200 Subject: [PATCH 0989/1190] AEWIN AW-O671R: Set vid_device. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f72da7338..a3a02bfcd 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -16502,7 +16502,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &chips_69000_onboard_device, .snd_device = NULL, .net_device = NULL }, From 6f6e64e321bf33d9c3eabcc62a62b7a7c279c2f1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 25 May 2025 15:42:57 +0600 Subject: [PATCH 0990/1190] Some minor fixes --- src/video/vid_chips_69000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index c9830f0ed..8267e271c 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -2247,8 +2247,8 @@ chips_69000_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) break; case 0x13: - chips->linear_mapping.base = val << 24; mem_mapping_disable(&chips->linear_mapping); + chips->linear_mapping.base = val << 24; if ((chips->pci_conf_status & PCI_COMMAND_MEM) && (chips->linear_mapping.base > 0x00000000)) mem_mapping_set_addr(&chips->linear_mapping, chips->linear_mapping.base, (1 << 24)); @@ -2785,6 +2785,8 @@ chips_69000_disable_handlers(chips_69000_t *chips) mem_mapping_disable(&chips->svga.mapping); if (!chips->on_board) mem_mapping_disable(&chips->bios_rom.mapping); + + chips->linear_mapping.base = 0; /* Save all the mappings and the timers because they are part of linked lists. */ reset_state->linear_mapping = chips->linear_mapping; From c26b2ac2abe3bbfb628e44bcec846dd789fd473f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 25 May 2025 12:27:21 +0200 Subject: [PATCH 0991/1190] AEWin: Make slot 0D PCI_CARD_VIDEO so the on-board video works. --- src/machine/m_at_socket370.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index 3f8db4e8c..ff299ee50 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -386,7 +386,7 @@ machine_at_awo671r_init(const machine_t *model) pci_register_slot(0x0A, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x0C, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0D, PCI_CARD_VIDEO, 2, 3, 4, 1); pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&i440bx_device); device_add(&piix4e_device); @@ -394,9 +394,8 @@ machine_at_awo671r_init(const machine_t *model) device_add_inst(&w83977ef_device, 2); device_add(&keyboard_ps2_pci_device); device_add(&sst_flash_39sf020_device); - if (gfxcard[0] == VID_INTERNAL) { - device_add(&chips_69000_onboard_device); - } + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); spd_register(SPD_TYPE_SDRAM, 0x3, 256); return ret; From d67788331e45386ea6f45f0ae10c31f54a063a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 25 May 2025 15:40:02 +0200 Subject: [PATCH 0992/1190] Fix PIIX4 revision. --- src/chipset/intel_piix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 9867a0fa7..e0d80f348 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1712,7 +1712,7 @@ const device_t piix4_device = { .name = "Intel 82371AB/EB (PIIX4/PIIX4E)", .internal_name = "piix4", .flags = DEVICE_PCI, - .local = 0x71100014, + .local = 0x71100004, .init = piix_init, .close = piix_close, .reset = piix_reset, From e277fb894bdf9a50208cc3c7609b70444f8eef34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sun, 25 May 2025 20:16:51 +0200 Subject: [PATCH 0993/1190] PC87309: Swap keyboard and mouse to their correct logical devices. --- src/sio/sio_pc87309.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 8bbbb7036..5a3f0d828 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -58,8 +58,8 @@ enum { LD_UART2, LD_UART1, LD_PM, - LD_KBD, - LD_MOUSE + LD_MOUSE, + LD_KBD } pc87309_ld_t; #define LD_MIN LD_FDC From 343c011f6b50194a4fef9c7f57ad87263f9773d1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 26 May 2025 00:28:27 +0600 Subject: [PATCH 0994/1190] Rename "AMD PCnet-VL" to "AMD PCnet-32" --- src/network/net_pcnet.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index b13fd8438..16fd7c65c 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -3256,8 +3256,12 @@ const device_t pcnet_am79c960_eb_device = { .config = pcnet_isa_config }; +/* + Used to be incorrectly called "AMD PCnet-VL" but the real name of the chip is "AMD PCnet-32" per the relevant datasheet. + https://theretroweb.com/chip/documentation/am79c965-66c24a7e6969d347126123.pdf +*/ const device_t pcnet_am79c960_vlb_device = { - .name = "AMD PCnet-VL", + .name = "AMD PCnet-32", .internal_name = "pcnetvlb", .flags = DEVICE_VLB, .local = DEV_AM79C960_VLB, From 853830f8bb6a6e50f4b8ddd8d88d19966fddeef4 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 25 May 2025 19:21:33 -0400 Subject: [PATCH 0995/1190] Add Mindscape Music Board Ported from PCem --- src/include/86box/snd_mmb.h | 42 ++++ src/include/86box/sound.h | 3 + src/sound/CMakeLists.txt | 4 + src/sound/ayumi/CMakeLists.txt | 14 ++ src/sound/ayumi/LICENSE | 21 ++ src/sound/ayumi/ayumi.c | 338 ++++++++++++++++++++++++++++++++ src/sound/ayumi/ayumi.h | 71 +++++++ src/sound/snd_mmb.c | 339 +++++++++++++++++++++++++++++++++ src/sound/sound.c | 1 + 9 files changed, 833 insertions(+) create mode 100644 src/include/86box/snd_mmb.h create mode 100644 src/sound/ayumi/CMakeLists.txt create mode 100644 src/sound/ayumi/LICENSE create mode 100644 src/sound/ayumi/ayumi.c create mode 100644 src/sound/ayumi/ayumi.h create mode 100644 src/sound/snd_mmb.c diff --git a/src/include/86box/snd_mmb.h b/src/include/86box/snd_mmb.h new file mode 100644 index 000000000..6e5f7d3a8 --- /dev/null +++ b/src/include/86box/snd_mmb.h @@ -0,0 +1,42 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Mindscape Music Board emulation. + * + * Authors: Roy Baer, + * Jasmine Iwanek, + * + * Copyright 2025 Roy Baer. + * Copyright 2025 Jasmine Iwanek. + */ +#ifndef _SOUND_SND_MMB_H_ +#define _SOUND_SND_MMB_H_ + +#define MMB_FREQ FREQ_48000 + +/* NOTE: + * The constant clock rate is a deviation from the real hardware which has + * the design flaw that the clock rate is always half the ISA bus clock. + */ +#define MMB_CLOCK 2386364 + +typedef struct ay_3_891x_s { + uint8_t index; + uint8_t regs[16]; + struct ayumi chip; +} ay_3_891x_t; + +typedef struct mmb_s { + ay_3_891x_t first; + ay_3_891x_t second; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} mmb_t; + +#endif /* _SOUND_SND_MMB_H_ */ diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index a30095c66..b2e202ddb 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -205,6 +205,9 @@ extern const device_t ps1snd_device; extern const device_t ssi2001_device; extern const device_t entertainer_device; +/* Mindscape Music Board */ +extern const device_t mmb_device; + /* Pro Audio Spectrum Plus, 16, and 16D */ extern const device_t pasplus_device; extern const device_t pas16_device; diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 0a04b0ff1..3aaf49bb3 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -41,6 +41,7 @@ add_library(snd OBJECT snd_sb.c snd_sb_dsp.c snd_emu8k.c + snd_mmb.c snd_mpu401.c snd_pas16.c snd_sn76489.c @@ -177,6 +178,9 @@ if(MUNT) endif() endif() +add_subdirectory(ayumi) +target_link_libraries(86Box ayumi) + add_subdirectory(ymfm) target_link_libraries(86Box ymfm) diff --git a/src/sound/ayumi/CMakeLists.txt b/src/sound/ayumi/CMakeLists.txt new file mode 100644 index 000000000..f3e4b18c7 --- /dev/null +++ b/src/sound/ayumi/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# CMake build script. +# + +add_library(ayumi STATIC + ayumi.c +) diff --git a/src/sound/ayumi/LICENSE b/src/sound/ayumi/LICENSE new file mode 100644 index 000000000..25371edc6 --- /dev/null +++ b/src/sound/ayumi/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) Peter Sovietov, http://sovietov.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/sound/ayumi/ayumi.c b/src/sound/ayumi/ayumi.c new file mode 100644 index 000000000..861b0fd45 --- /dev/null +++ b/src/sound/ayumi/ayumi.c @@ -0,0 +1,338 @@ +/* Author: Peter Sovietov */ + +#include +#include +#include "ayumi.h" + +static const double AY_dac_table[] = { + 0.0, 0.0, + 0.00999465934234, 0.00999465934234, + 0.0144502937362, 0.0144502937362, + 0.0210574502174, 0.0210574502174, + 0.0307011520562, 0.0307011520562, + 0.0455481803616, 0.0455481803616, + 0.0644998855573, 0.0644998855573, + 0.107362478065, 0.107362478065, + 0.126588845655, 0.126588845655, + 0.20498970016, 0.20498970016, + 0.292210269322, 0.292210269322, + 0.372838941024, 0.372838941024, + 0.492530708782, 0.492530708782, + 0.635324635691, 0.635324635691, + 0.805584802014, 0.805584802014, + 1.0, 1.0 +}; + +static const double YM_dac_table[] = { + 0.0, 0.0, + 0.00465400167849, 0.00772106507973, + 0.0109559777218, 0.0139620050355, + 0.0169985503929, 0.0200198367285, + 0.024368657969, 0.029694056611, + 0.0350652323186, 0.0403906309606, + 0.0485389486534, 0.0583352407111, + 0.0680552376593, 0.0777752346075, + 0.0925154497597, 0.111085679408, + 0.129747463188, 0.148485542077, + 0.17666895552, 0.211551079576, + 0.246387426566, 0.281101701381, + 0.333730067903, 0.400427252613, + 0.467383840696, 0.53443198291, + 0.635172045472, 0.75800717174, + 0.879926756695, 1.0 +}; + +static void reset_segment(struct ayumi* ay); + +static int update_tone(struct ayumi* ay, int index) { + struct tone_channel* ch = &ay->channels[index]; + ch->tone_counter += 1; + if (ch->tone_counter >= ch->tone_period) { + ch->tone_counter = 0; + ch->tone ^= 1; + } + return ch->tone; +} + +static int update_noise(struct ayumi* ay) { + int bit0x3; + ay->noise_counter += 1; + if (ay->noise_counter >= (ay->noise_period << 1)) { + ay->noise_counter = 0; + bit0x3 = ((ay->noise ^ (ay->noise >> 3)) & 1); + ay->noise = (ay->noise >> 1) | (bit0x3 << 16); + } + return ay->noise & 1; +} + +static void slide_up(struct ayumi* ay) { + ay->envelope += 1; + if (ay->envelope > 31) { + ay->envelope_segment ^= 1; + reset_segment(ay); + } +} + +static void slide_down(struct ayumi* ay) { + ay->envelope -= 1; + if (ay->envelope < 0) { + ay->envelope_segment ^= 1; + reset_segment(ay); + } +} + +static void hold_top(struct ayumi* ay) { + (void) ay; +} + +static void hold_bottom(struct ayumi* ay) { + (void) ay; +} + +static void (* const Envelopes[][2])(struct ayumi*) = { + {slide_down, hold_bottom}, + {slide_down, hold_bottom}, + {slide_down, hold_bottom}, + {slide_down, hold_bottom}, + {slide_up, hold_bottom}, + {slide_up, hold_bottom}, + {slide_up, hold_bottom}, + {slide_up, hold_bottom}, + {slide_down, slide_down}, + {slide_down, hold_bottom}, + {slide_down, slide_up}, + {slide_down, hold_top}, + {slide_up, slide_up}, + {slide_up, hold_top}, + {slide_up, slide_down}, + {slide_up, hold_bottom} +}; + +static void reset_segment(struct ayumi* ay) { + if (Envelopes[ay->envelope_shape][ay->envelope_segment] == slide_down + || Envelopes[ay->envelope_shape][ay->envelope_segment] == hold_top) { + ay->envelope = 31; + return; + } + ay->envelope = 0; +} + +int update_envelope(struct ayumi* ay) { + ay->envelope_counter += 1; + if (ay->envelope_counter >= ay->envelope_period) { + ay->envelope_counter = 0; + Envelopes[ay->envelope_shape][ay->envelope_segment](ay); + } + return ay->envelope; +} + +static void update_mixer(struct ayumi* ay) { + int i; + int out; + int noise = update_noise(ay); + int envelope = update_envelope(ay); + ay->left = 0; + ay->right = 0; + for (i = 0; i < TONE_CHANNELS; i += 1) { + out = (update_tone(ay, i) | ay->channels[i].t_off) & (noise | ay->channels[i].n_off); + out *= ay->channels[i].e_on ? envelope : ay->channels[i].volume * 2 + 1; + ay->left += ay->dac_table[out] * ay->channels[i].pan_left; + ay->right += ay->dac_table[out] * ay->channels[i].pan_right; + } +} + +int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr) { + int i; + memset(ay, 0, sizeof(struct ayumi)); + ay->step = clock_rate / (sr * 8 * DECIMATE_FACTOR); + ay->dac_table = is_ym ? YM_dac_table : AY_dac_table; + ay->noise = 1; + ayumi_set_envelope(ay, 1); + for (i = 0; i < TONE_CHANNELS; i += 1) { + ayumi_set_tone(ay, i, 1); + } + return ay->step < 1; +} + +void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp) { + if (is_eqp) { + ay->channels[index].pan_left = sqrt(1 - pan); + ay->channels[index].pan_right = sqrt(pan); + } else { + ay->channels[index].pan_left = 1 - pan; + ay->channels[index].pan_right = pan; + } +} + +void ayumi_set_tone(struct ayumi* ay, int index, int period) { + period &= 0xfff; + ay->channels[index].tone_period = (period == 0) | period; +} + +void ayumi_set_noise(struct ayumi* ay, int period) { + period &= 0x1f; + ay->noise_period = (period == 0) | period; +} + +void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on) { + ay->channels[index].t_off = t_off & 1; + ay->channels[index].n_off = n_off & 1; + ay->channels[index].e_on = e_on; +} + +void ayumi_set_volume(struct ayumi* ay, int index, int volume) { + ay->channels[index].volume = volume & 0xf; +} + +void ayumi_set_envelope(struct ayumi* ay, int period) { + period &= 0xffff; + ay->envelope_period = (period == 0) | period; +} + +void ayumi_set_envelope_shape(struct ayumi* ay, int shape) { + ay->envelope_shape = shape & 0xf; + ay->envelope_counter = 0; + ay->envelope_segment = 0; + reset_segment(ay); +} + +static double decimate(double* x) { + double y = -0.0000046183113992051936 * (x[1] + x[191]) + + -0.00001117761640887225 * (x[2] + x[190]) + + -0.000018610264502005432 * (x[3] + x[189]) + + -0.000025134586135631012 * (x[4] + x[188]) + + -0.000028494281690666197 * (x[5] + x[187]) + + -0.000026396828793275159 * (x[6] + x[186]) + + -0.000017094212558802156 * (x[7] + x[185]) + + 0.000023798193576966866 * (x[9] + x[183]) + + 0.000051281160242202183 * (x[10] + x[182]) + + 0.00007762197826243427 * (x[11] + x[181]) + + 0.000096759426664120416 * (x[12] + x[180]) + + 0.00010240229300393402 * (x[13] + x[179]) + + 0.000089344614218077106 * (x[14] + x[178]) + + 0.000054875700118949183 * (x[15] + x[177]) + + -0.000069839082210680165 * (x[17] + x[175]) + + -0.0001447966132360757 * (x[18] + x[174]) + + -0.00021158452917708308 * (x[19] + x[173]) + + -0.00025535069106550544 * (x[20] + x[172]) + + -0.00026228714374322104 * (x[21] + x[171]) + + -0.00022258805927027799 * (x[22] + x[170]) + + -0.00013323230495695704 * (x[23] + x[169]) + + 0.00016182578767055206 * (x[25] + x[167]) + + 0.00032846175385096581 * (x[26] + x[166]) + + 0.00047045611576184863 * (x[27] + x[165]) + + 0.00055713851457530944 * (x[28] + x[164]) + + 0.00056212565121518726 * (x[29] + x[163]) + + 0.00046901918553962478 * (x[30] + x[162]) + + 0.00027624866838952986 * (x[31] + x[161]) + + -0.00032564179486838622 * (x[33] + x[159]) + + -0.00065182310286710388 * (x[34] + x[158]) + + -0.00092127787309319298 * (x[35] + x[157]) + + -0.0010772534348943575 * (x[36] + x[156]) + + -0.0010737727700273478 * (x[37] + x[155]) + + -0.00088556645390392634 * (x[38] + x[154]) + + -0.00051581896090765534 * (x[39] + x[153]) + + 0.00059548767193795277 * (x[41] + x[151]) + + 0.0011803558710661009 * (x[42] + x[150]) + + 0.0016527320270369871 * (x[43] + x[149]) + + 0.0019152679330965555 * (x[44] + x[148]) + + 0.0018927324805381538 * (x[45] + x[147]) + + 0.0015481870327877937 * (x[46] + x[146]) + + 0.00089470695834941306 * (x[47] + x[145]) + + -0.0010178225878206125 * (x[49] + x[143]) + + -0.0020037400552054292 * (x[50] + x[142]) + + -0.0027874356824117317 * (x[51] + x[141]) + + -0.003210329988021943 * (x[52] + x[140]) + + -0.0031540624117984395 * (x[53] + x[139]) + + -0.0025657163651900345 * (x[54] + x[138]) + + -0.0014750752642111449 * (x[55] + x[137]) + + 0.0016624165446378462 * (x[57] + x[135]) + + 0.0032591192839069179 * (x[58] + x[134]) + + 0.0045165685815867747 * (x[59] + x[133]) + + 0.0051838984346123896 * (x[60] + x[132]) + + 0.0050774264697459933 * (x[61] + x[131]) + + 0.0041192521414141585 * (x[62] + x[130]) + + 0.0023628575417966491 * (x[63] + x[129]) + + -0.0026543507866759182 * (x[65] + x[127]) + + -0.0051990251084333425 * (x[66] + x[126]) + + -0.0072020238234656924 * (x[67] + x[125]) + + -0.0082672928192007358 * (x[68] + x[124]) + + -0.0081033739572956287 * (x[69] + x[123]) + + -0.006583111539570221 * (x[70] + x[122]) + + -0.0037839040415292386 * (x[71] + x[121]) + + 0.0042781252851152507 * (x[73] + x[119]) + + 0.0084176358598320178 * (x[74] + x[118]) + + 0.01172566057463055 * (x[75] + x[117]) + + 0.013550476647788672 * (x[76] + x[116]) + + 0.013388189369997496 * (x[77] + x[115]) + + 0.010979501242341259 * (x[78] + x[114]) + + 0.006381274941685413 * (x[79] + x[113]) + + -0.007421229604153888 * (x[81] + x[111]) + + -0.01486456304340213 * (x[82] + x[110]) + + -0.021143584622178104 * (x[83] + x[109]) + + -0.02504275058758609 * (x[84] + x[108]) + + -0.025473530942547201 * (x[85] + x[107]) + + -0.021627310017882196 * (x[86] + x[106]) + + -0.013104323383225543 * (x[87] + x[105]) + + 0.017065133989980476 * (x[89] + x[103]) + + 0.036978919264451952 * (x[90] + x[102]) + + 0.05823318062093958 * (x[91] + x[101]) + + 0.079072012081405949 * (x[92] + x[100]) + + 0.097675998716952317 * (x[93] + x[99]) + + 0.11236045936950932 * (x[94] + x[98]) + + 0.12176343577287731 * (x[95] + x[97]) + + 0.125 * x[96]; + memcpy(&x[FIR_SIZE - DECIMATE_FACTOR], x, DECIMATE_FACTOR * sizeof(double)); + return y; +} + +void ayumi_process(struct ayumi* ay) { + int i; + double y1; + double* c_left = ay->interpolator_left.c; + double* y_left = ay->interpolator_left.y; + double* c_right = ay->interpolator_right.c; + double* y_right = ay->interpolator_right.y; + double* fir_left = &ay->fir_left[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; + double* fir_right = &ay->fir_right[FIR_SIZE - ay->fir_index * DECIMATE_FACTOR]; + ay->fir_index = (ay->fir_index + 1) % (FIR_SIZE / DECIMATE_FACTOR - 1); + for (i = DECIMATE_FACTOR - 1; i >= 0; i -= 1) { + ay->x += ay->step; + if (ay->x >= 1) { + ay->x -= 1; + y_left[0] = y_left[1]; + y_left[1] = y_left[2]; + y_left[2] = y_left[3]; + y_right[0] = y_right[1]; + y_right[1] = y_right[2]; + y_right[2] = y_right[3]; + update_mixer(ay); + y_left[3] = ay->left; + y_right[3] = ay->right; + y1 = y_left[2] - y_left[0]; + c_left[0] = 0.5 * y_left[1] + 0.25 * (y_left[0] + y_left[2]); + c_left[1] = 0.5 * y1; + c_left[2] = 0.25 * (y_left[3] - y_left[1] - y1); + y1 = y_right[2] - y_right[0]; + c_right[0] = 0.5 * y_right[1] + 0.25 * (y_right[0] + y_right[2]); + c_right[1] = 0.5 * y1; + c_right[2] = 0.25 * (y_right[3] - y_right[1] - y1); + } + fir_left[i] = (c_left[2] * ay->x + c_left[1]) * ay->x + c_left[0]; + fir_right[i] = (c_right[2] * ay->x + c_right[1]) * ay->x + c_right[0]; + } + ay->left = decimate(fir_left); + ay->right = decimate(fir_right); +} + +static double dc_filter(struct dc_filter* dc, int index, double x) { + dc->sum += -dc->delay[index] + x; + dc->delay[index] = x; + return x - dc->sum / DC_FILTER_SIZE; +} + +void ayumi_remove_dc(struct ayumi* ay) { + ay->left = dc_filter(&ay->dc_left, ay->dc_index, ay->left); + ay->right = dc_filter(&ay->dc_right, ay->dc_index, ay->right); + ay->dc_index = (ay->dc_index + 1) & (DC_FILTER_SIZE - 1); +} diff --git a/src/sound/ayumi/ayumi.h b/src/sound/ayumi/ayumi.h new file mode 100644 index 000000000..f15939514 --- /dev/null +++ b/src/sound/ayumi/ayumi.h @@ -0,0 +1,71 @@ +/* Author: Peter Sovietov */ + +#ifndef AYUMI_H +#define AYUMI_H + +enum { + TONE_CHANNELS = 3, + DECIMATE_FACTOR = 8, + FIR_SIZE = 192, + DC_FILTER_SIZE = 1024 +}; + +struct tone_channel { + int tone_period; + int tone_counter; + int tone; + int t_off; + int n_off; + int e_on; + int volume; + double pan_left; + double pan_right; +}; + +struct interpolator { + double c[4]; + double y[4]; +}; + +struct dc_filter { + double sum; + double delay[DC_FILTER_SIZE]; +}; + +struct ayumi { + struct tone_channel channels[TONE_CHANNELS]; + int noise_period; + int noise_counter; + int noise; + int envelope_counter; + int envelope_period; + int envelope_shape; + int envelope_segment; + int envelope; + const double* dac_table; + double step; + double x; + struct interpolator interpolator_left; + struct interpolator interpolator_right; + double fir_left[FIR_SIZE * 2]; + double fir_right[FIR_SIZE * 2]; + int fir_index; + struct dc_filter dc_left; + struct dc_filter dc_right; + int dc_index; + double left; + double right; +}; + +int ayumi_configure(struct ayumi* ay, int is_ym, double clock_rate, int sr); +void ayumi_set_pan(struct ayumi* ay, int index, double pan, int is_eqp); +void ayumi_set_tone(struct ayumi* ay, int index, int period); +void ayumi_set_noise(struct ayumi* ay, int period); +void ayumi_set_mixer(struct ayumi* ay, int index, int t_off, int n_off, int e_on); +void ayumi_set_volume(struct ayumi* ay, int index, int volume); +void ayumi_set_envelope(struct ayumi* ay, int period); +void ayumi_set_envelope_shape(struct ayumi* ay, int shape); +void ayumi_process(struct ayumi* ay); +void ayumi_remove_dc(struct ayumi* ay); + +#endif diff --git a/src/sound/snd_mmb.c b/src/sound/snd_mmb.c new file mode 100644 index 000000000..35a72efbc --- /dev/null +++ b/src/sound/snd_mmb.c @@ -0,0 +1,339 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Mindscape Music Board emulation. + * + * Authors: Roy Baer, + * Jasmine Iwanek, + * + * Copyright 2025 Roy Baer. + * Copyright 2025 Jasmine Iwanek. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/sound.h> +//#i nclude "cpu.h" +#include "ayumi/ayumi.h" +#include <86box/snd_mmb.h> +#include <86box/plat_unused.h> + +#ifdef ENABLE_MMB_LOG +int mmb_do_log = ENABLE_MMB_LOG; + +static void +mmb_log(const char *fmt, ...) +{ + va_list ap; + + if (mmb_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define mmb_log(fmt, ...) +#endif + +void +mmb_update(mmb_t *mmb) +{ + for (; mmb->pos < sound_pos_global; mmb->pos++) { + ayumi_process(&mmb->first.chip); + ayumi_process(&mmb->second.chip); + + ayumi_remove_dc(&mmb->first.chip); + ayumi_remove_dc(&mmb->second.chip); + + mmb->buffer[mmb->pos << 1] = (mmb->first.chip.left + mmb->second.chip.left) * 16000; + mmb->buffer[(mmb->pos << 1) + 1] = (mmb->first.chip.right + mmb->second.chip.right) * 16000; + } +} + +void +mmb_get_buffer(int32_t *buffer, int len, void *priv) +{ + mmb_t *mmb = (mmb_t *) priv; + + mmb_update(mmb); + + for (int c = 0; c < len * 2; c++) + buffer[c] += mmb->buffer[c]; + + mmb->pos = 0; +} + +void +mmb_write(uint16_t addr, uint8_t val, void *priv) +{ + mmb_t *mmb = (mmb_t *) priv; + + mmb_update(mmb); + + mmb_log("mmb_write(%04X): activity now: %02X\n", addr, val); + + switch (addr & 3) { + case 0: + mmb->first.index = val; + break; + case 2: + mmb->second.index = val; + break; + case 1: + case 3: + { + ay_3_891x_t *ay = ((addr & 2) == 0) ? &mmb->first : &mmb->second; + + switch (ay->index) { + case 0: + ay->regs[0] = val; + ayumi_set_tone(&ay->chip, 0, (ay->regs[1] << 8) | ay->regs[0]); + break; + case 1: + ay->regs[1] = val & 0xf; + ayumi_set_tone(&ay->chip, 0, (ay->regs[1] << 8) | ay->regs[0]); + break; + case 2: + ay->regs[2] = val; + ayumi_set_tone(&ay->chip, 1, (ay->regs[3] << 8) | ay->regs[2]); + break; + case 3: + ay->regs[3] = val & 0xf; + ayumi_set_tone(&ay->chip, 1, (ay->regs[3] << 8) | ay->regs[2]); + break; + case 4: + ay->regs[4] = val; + ayumi_set_tone(&ay->chip, 2, (ay->regs[5] << 8) | ay->regs[4]); + break; + case 5: + ay->regs[5] = val & 0xf; + ayumi_set_tone(&ay->chip, 2, (ay->regs[5] << 8) | ay->regs[4]); + break; + case 6: + ay->regs[6] = val & 0x1f; + ayumi_set_noise(&ay->chip, ay->regs[6]); + break; + case 7: + ay->regs[7] = val; + ayumi_set_mixer(&ay->chip, 0, val & 1, (val >> 3) & 1, (ay->regs[8] >> 4) & 1); + ayumi_set_mixer(&ay->chip, 1, (val >> 1) & 1, (val >> 4) & 1, (ay->regs[9] >> 4) & 1); + ayumi_set_mixer(&ay->chip, 2, (val >> 2) & 1, (val >> 5) & 1, (ay->regs[10] >> 4) & 1); + break; + case 8: + ay->regs[8] = val; + ayumi_set_volume(&ay->chip, 0, val & 0xf); + ayumi_set_mixer(&ay->chip, 0, ay->regs[7] & 1, (ay->regs[7] >> 3) & 1, (val >> 4) & 1); + break; + case 9: + ay->regs[9] = val; + ayumi_set_volume(&ay->chip, 1, val & 0xf); + ayumi_set_mixer(&ay->chip, 1, (ay->regs[7] >> 1) & 1, (ay->regs[7] >> 4) & 1, (val >> 4) & 1); + break; + case 10: + ay->regs[10] = val; + ayumi_set_volume(&ay->chip, 2, val & 0xf); + ayumi_set_mixer(&ay->chip, 2, (ay->regs[7] >> 2) & 1, (ay->regs[7] >> 5) & 1, (val >> 4) & 1); + break; + case 11: + ay->regs[11] = val; + ayumi_set_envelope(&ay->chip, (ay->regs[12] >> 8) | ay->regs[11]); + break; + case 12: + ay->regs[12] = val; + ayumi_set_envelope(&ay->chip, (ay->regs[12] >> 8) | ay->regs[11]); + break; + case 13: + ay->regs[13] = val; + ayumi_set_envelope_shape(&ay->chip, val & 0xf); + break; + case 14: + ay->regs[14] = val; + break; + case 15: + ay->regs[15] = val; + break; + + default: + break; + } + break; + } + + default: + break; + } +} + +uint8_t +mmb_read(uint16_t addr, void *priv) +{ + mmb_t *mmb = (mmb_t *) priv; + ay_3_891x_t *ay = ((addr & 2) == 0) ? &mmb->first : &mmb->second; + uint8_t ret = 0; + + switch (ay->index) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + ret = ay->regs[ay->index]; + break; + case 14: + if (ay->regs[7] & 0x40) + ret = ay->regs[14]; + break; + case 15: + if (ay->regs[7] & 0x80) + ret = ay->regs[15]; + break; + + default: + break; + } + + mmb_log("mmb_read(%04X): activity now: %02X\n", addr, ret); + + return ret; +} + +void * +mmb_init(UNUSED(const device_t *info)) +{ + mmb_t *mmb = calloc(1, sizeof(mmb_t)); +# if 0 + uint16_t addr = (device_get_config_int("addr96") << 6) | (device_get_config_int("addr52") << 2); +#else + uint16_t addr = 0x300; + +#endif + sound_add_handler(mmb_get_buffer, mmb); + + ayumi_configure(&mmb->first.chip, 0, MMB_CLOCK, MMB_FREQ); + ayumi_configure(&mmb->second.chip, 0, MMB_CLOCK, MMB_FREQ); + + for (uint8_t i = 0; i < 3; i++) { + ayumi_set_pan(&mmb->first.chip, i, 0.5, 1); + ayumi_set_pan(&mmb->second.chip, i, 0.5, 1); + } + + io_sethandler(addr, 0x0004, + mmb_read, NULL, NULL, + mmb_write, NULL, NULL, + mmb); + + return mmb; +} + +void +mmb_close(void *priv) +{ + mmb_t *mmb = (mmb_t *) priv; + + free(mmb); +} + +// clang-format off +#if 0 +static device_config_t mmb_config[] = { + { + .name = "addr96", + .description = "Base address A9...A6", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 12, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0000", .value = 0 }, + { .description = "0001", .value = 1 }, + { .description = "0010", .value = 2 }, + { .description = "0011", .value = 3 }, + { .description = "0100", .value = 4 }, + { .description = "0101", .value = 5 }, + { .description = "0110", .value = 6 }, + { .description = "0111", .value = 7 }, + { .description = "1000", .value = 8 }, + { .description = "1001", .value = 9 }, + { .description = "1010", .value = 10 }, + { .description = "1011", .value = 11 }, + { .description = "1100", .value = 12 }, + { .description = "1101", .value = 13 }, + { .description = "1110", .value = 14 }, + { .description = "1111", .value = 15 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "addr52", + .description = "Base address A5...A2", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0000", .value = 0 }, + { .description = "0001", .value = 1 }, + { .description = "0010", .value = 2 }, + { .description = "0011", .value = 3 }, + { .description = "0100", .value = 4 }, + { .description = "0101", .value = 5 }, + { .description = "0110", .value = 6 }, + { .description = "0111", .value = 7 }, + { .description = "1000", .value = 8 }, + { .description = "1001", .value = 9 }, + { .description = "1010", .value = 10 }, + { .description = "1011", .value = 11 }, + { .description = "1100", .value = 12 }, + { .description = "1101", .value = 13 }, + { .description = "1110", .value = 14 }, + { .description = "1111", .value = 15 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .type = CONFIG_END } +}; +#endif +// clang-format on + +const device_t mmb_device = { + .name = "Mindscape Music Board", + .internal_name = "mmb", + .flags = DEVICE_ISA, + .local = 0, + .init = mmb_init, + .close = mmb_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, +#if 0 + .config = mmb_config +#else + .config = NULL +#endif +}; diff --git a/src/sound/sound.c b/src/sound/sound.c index 0c8dffe12..c3ecc8632 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -137,6 +137,7 @@ static const SOUND_CARD sound_cards[] = { { &sb_vibra16xv_device }, { &ssi2001_device }, { &entertainer_device }, + { &mmb_device }, { &pasplus_device }, { &pas16_device }, { &pas16d_device }, From 4033f81c4888b211d06afdf38cf19c6da650e2b2 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 25 May 2025 20:15:14 -0400 Subject: [PATCH 0996/1190] Clean up sound/CMakeLists.txt --- src/sound/CMakeLists.txt | 9 +++++---- src/sound/esfmu/CMakeLists.txt | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/sound/esfmu/CMakeLists.txt diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 3aaf49bb3..fb3c9b43d 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -49,8 +49,6 @@ add_library(snd OBJECT snd_wss.c snd_ym7128.c snd_optimc.c - esfmu/esfm.c - esfmu/esfm_registers.c snd_opl_esfm.c ) @@ -181,6 +179,9 @@ endif() add_subdirectory(ayumi) target_link_libraries(86Box ayumi) +add_subdirectory(esfmu) +target_link_libraries(86Box esfmu) + add_subdirectory(ymfm) target_link_libraries(86Box ymfm) @@ -193,8 +194,8 @@ if(OPL4ML) target_sources(snd PRIVATE midi_opl4.c midi_opl4_yrw801.c) endif() -find_package(PkgConfig ) -pkg_check_modules(SERIALPORT libserialport) +find_package(PkgConfig) +pkg_check_modules(SERIALPORT libserialport) if(SERIALPORT_FOUND OR DEFINED LIBSERIALPORT_ROOT) add_compile_definitions(USE_LIBSERIALPORT=1) diff --git a/src/sound/esfmu/CMakeLists.txt b/src/sound/esfmu/CMakeLists.txt new file mode 100644 index 000000000..2505038f1 --- /dev/null +++ b/src/sound/esfmu/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# CMake build script. +# + +add_library(esfmu STATIC + esfm.c + esfm_registers.c +) From 09f63b6466450c7b22df74584ded24d71048d2de Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 27 May 2025 04:47:45 +0200 Subject: [PATCH 0997/1190] Assorted fixes, the Compaq Presario 7100 486 no longer crashes on CTRL+ALT+DEL. --- src/chipset/umc_hb4.c | 53 ++----------------------------------------- src/device/kbc_at.c | 4 +++- src/mem/mem.c | 12 ++++++---- src/mem/smram.c | 15 +++++++++--- 4 files changed, 24 insertions(+), 60 deletions(-) diff --git a/src/chipset/umc_hb4.c b/src/chipset/umc_hb4.c index 889691988..55901b32e 100644 --- a/src/chipset/umc_hb4.c +++ b/src/chipset/umc_hb4.c @@ -270,6 +270,8 @@ hb4_smram(hb4_t *dev) } umc_smram_recalc(dev->smram_base >> 12, 1); + + flushmmucache(); } static void @@ -398,55 +400,6 @@ hb4_close(void *priv) free(dev); } -static void -ims8848_write(uint16_t addr, uint8_t val, void *priv) -{ - hb4_t *dev = (hb4_t *) priv; - - switch (addr) { - case 0x22: - dev->idx = val; - break; - case 0x23: - if (((val & 0x0f) == ((dev->idx >> 4) & 0x0f)) && ((val & 0xf0) == ((dev->idx << 4) & 0xf0))) - dev->access_data = 1; - break; - case 0x24: - if (dev->access_data) - dev->access_data = 0; - break; - - default: - break; - } -} - -static uint8_t -ims8848_read(uint16_t addr, void *priv) -{ - uint8_t ret = 0xff; - hb4_t *dev = (hb4_t *) priv; - - switch (addr) { - case 0x22: - ret = dev->idx; - break; - case 0x23: - ret = (dev->idx >> 4) | (dev->idx << 4); - break; - case 0x24: - if (dev->access_data) { - ret = dev->pci_conf[dev->idx]; - dev->access_data = 0; - } - break; - default: - break; - } - - return ret; -} - static void * hb4_init(UNUSED(const device_t *info)) { @@ -463,8 +416,6 @@ hb4_init(UNUSED(const device_t *info)) dev->smram_base = 0x000a0000; hb4_reset(dev); - io_sethandler(0x0022, 0x0003, ims8848_read, NULL, NULL, ims8848_write, NULL, NULL, dev); - return dev; } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index dc93a4fba..8840a0e4d 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -830,7 +830,9 @@ write_p2(atkbc_t *dev, uint8_t val) softresetx86(); /* Pulse reset! */ cpu_set_edx(); flushmmucache(); - if ((kbc_ven == KBC_VEN_ALI) || !strcmp(machine_get_internal_name(), "spc7700plw")) + if ((kbc_ven == KBC_VEN_ALI) || + !strcmp(machine_get_internal_name(), "spc7700plw") || + !strcmp(machine_get_internal_name(), "pl4600c")) smbase = 0x00030000; /* Yes, this is a hack, but until someone gets ahold of the real PCD-2L diff --git a/src/mem/mem.c b/src/mem/mem.c index 07d897172..d365ecffb 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2994,10 +2994,12 @@ mem_init(void) } static void -umc_page_recalc(uint32_t c, int set) +umc_page_recalc(uint32_t c, uint32_t phys, int set) { + uint32_t target = set ? phys : c; + if (set) { - pages[c].mem = &ram[(c & 0xff) << 12]; + pages[c].mem = &ram[(target & 0xff) << 12]; pages[c].write_b = mem_write_ramb_page; pages[c].write_w = mem_write_ramw_page; pages[c].write_l = mem_write_raml_page; @@ -3010,8 +3012,8 @@ umc_page_recalc(uint32_t c, int set) #ifdef USE_NEW_DYNAREC pages[c].evict_prev = EVICT_NOT_IN_LIST; - pages[c].byte_dirty_mask = &byte_dirty_mask[(c & 0xff) * 64]; - pages[c].byte_code_present_mask = &byte_code_present_mask[(c & 0xff) * 64]; + pages[c].byte_dirty_mask = &byte_dirty_mask[(target & 0xff) * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[(target & 0xff) * 64]; #endif } @@ -3019,7 +3021,7 @@ void umc_smram_recalc(uint32_t start, int set) { for (uint32_t c = start; c < (start + 0x0020); c++) - umc_page_recalc(c, set); + umc_page_recalc(c, c - start + 0x000a0000, set); } static void diff --git a/src/mem/smram.c b/src/mem/smram.c index afbc5475c..928760f3a 100644 --- a/src/mem/smram.c +++ b/src/mem/smram.c @@ -59,9 +59,12 @@ smram_read(uint32_t addr, void *priv) const smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (new_addr >= (1 << 30)) return mem_read_ram_2gb(new_addr, priv); - else if (!use_separate_smram || (new_addr >= 0xa0000)) + else +#endif + if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_ram(new_addr, priv); else return dev->mapping.exec[addr - dev->host_base]; @@ -73,9 +76,12 @@ smram_readw(uint32_t addr, void *priv) smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (new_addr >= (1 << 30)) return mem_read_ram_2gbw(new_addr, priv); - else if (!use_separate_smram || (new_addr >= 0xa0000)) + else +#endif + if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_ramw(new_addr, priv); else return *(uint16_t *) &(dev->mapping.exec[addr - dev->host_base]); @@ -87,9 +93,12 @@ smram_readl(uint32_t addr, void *priv) smram_t *dev = (smram_t *) priv; uint32_t new_addr = addr - dev->host_base + dev->ram_base; +#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)) if (new_addr >= (1 << 30)) return mem_read_ram_2gbl(new_addr, priv); - else if (!use_separate_smram || (new_addr >= 0xa0000)) + else +#endif + if (!use_separate_smram || (new_addr >= 0xa0000)) return mem_read_raml(new_addr, priv); else return *(uint32_t *) &(dev->mapping.exec[addr - dev->host_base]); From 8e895903ed2373372f2b0a2e22669e21abdfddae Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Mon, 26 May 2025 04:38:28 -0400 Subject: [PATCH 0998/1190] Alternate font support for MDA and Hercules --- src/include/86box/video.h | 35 +++++---- src/machine/m_amstrad.c | 2 +- src/machine/m_pcjr.c | 2 +- src/video/vid_hercules.c | 44 ++++++++++-- src/video/vid_mda.c | 45 +++++++++++- src/video/vid_table.c | 2 +- src/video/video.c | 144 ++++++++++++++++++-------------------- 7 files changed, 176 insertions(+), 98 deletions(-) diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 085dd5f80..6a73c6462 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -36,6 +36,10 @@ using atomic_int = std::atomic_int; #define getcolg(color) (((color) >> 8) & 0xFF) #define getcolb(color) ((color) & 0xFF) +#ifdef __cplusplus +extern "C" { +#endif + enum { VID_NONE = 0, VID_INTERNAL @@ -49,10 +53,6 @@ enum { FULLSCR_SCALE_INT43 }; -#ifdef __cplusplus -extern "C" { -#endif - enum { VIDEO_ISA = 0, VIDEO_MCA, @@ -71,6 +71,11 @@ enum { #define VIDEO_FLAG_TYPE_SECONDARY VIDEO_FLAG_TYPE_SPECIAL +#define FONT_IBM_MDA_437_PATH "roms/video/mda/mda.rom" +#define FONT_IBM_MDA_437_NORDIC_PATH "roms/video/mda/4733197.bin" +#define FONT_KAM_PATH "roms/video/mda/kam.bin" +#define FONT_KAMCL16_PATH "roms/video/mda/kamcl16.bin" + typedef struct video_timings_t { int type; int write_b; @@ -189,15 +194,15 @@ extern uint32_t pal_lookup[256]; #endif extern int video_fullscreen; extern int video_fullscreen_scale; -extern uint8_t fontdat[2048][8]; -extern uint8_t fontdatm[2048][16]; -extern uint8_t fontdat2[2048][8]; -extern uint8_t fontdatm2[2048][16]; -extern uint8_t fontdatw[512][32]; -extern uint8_t fontdat8x12[256][16]; -extern uint8_t fontdat12x18[256][36]; -extern dbcs_font_t *fontdatksc5601; -extern dbcs_font_t *fontdatksc5601_user; +extern uint8_t fontdat[2048][8]; /* IBM CGA font */ +extern uint8_t fontdatm[2048][16]; /* IBM MDA font */ +extern uint8_t fontdat2[2048][8]; /* IBM CGA 2nd instance font */ +extern uint8_t fontdatm2[2048][16]; /* IBM MDA 2nd instance font */ +extern uint8_t fontdatw[512][32]; /* Wyse700 font */ +extern uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ +extern uint8_t fontdat12x18[256][36]; /* IM1024 font */ +extern dbcs_font_t *fontdatksc5601; /* Korean KSC-5601 font */ +extern dbcs_font_t *fontdatksc5601_user; /* Korean KSC-5601 user defined font */ extern uint32_t *video_6to8; extern uint32_t *video_8togs; extern uint32_t *video_8to32; @@ -277,8 +282,8 @@ extern uint8_t video_force_resize_get_monitor(int monitor_index); extern void video_force_resize_set_monitor(uint8_t res, int monitor_index); extern void video_update_timing(void); -extern void loadfont_ex(char *s, int format, int offset); -extern void loadfont(char *s, int format); +extern void loadfont_ex(char *fn, int format, int offset); +extern void loadfont(char *fn, int format); extern int get_actual_size_x(void); extern int get_actual_size_y(void); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 3dba578bd..814d95ffd 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -2936,7 +2936,7 @@ machine_amstrad_init(const machine_t *model, int type) break; case AMS_PC1640: - loadfont("roms/video/mda/mda.rom", 0); + loadfont(FONT_IBM_MDA_437_PATH, 0); device_context(&vid_1640_device); ams->language = device_get_config_int("language"); vid_init_1640(ams); diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index d4d3b09cf..cb69bd9e5 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -1541,7 +1541,7 @@ machine_pcjr_init(UNUSED(const machine_t *model)) /* Initialize the video controller. */ video_reset(gfxcard[0]); - loadfont("roms/video/mda/mda.rom", 0); + loadfont(FONT_IBM_MDA_437_PATH, 0); device_context(&pcjr_device); pcjr_vid_init(pcjr); device_context_restore(); diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 00374d08f..af8ad08f8 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -543,14 +543,33 @@ hercules_init(UNUSED(const device_t *info)) dev->vram = (uint8_t *) malloc(0x10000); + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + case 2: + loadfont(FONT_KAM_PATH, 0); + break; + case 3: + loadfont(FONT_KAMCL16_PATH, 0); + break; + } + timer_add(&dev->timer, hercules_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, - hercules_read, NULL, NULL, hercules_write, NULL, NULL, - NULL /*dev->vram*/, MEM_MAPPING_EXTERNAL, dev); + hercules_read, NULL, NULL, + hercules_write, NULL, NULL, + NULL /*dev->vram*/, MEM_MAPPING_EXTERNAL, + dev); - io_sethandler(0x03b0, 16, - hercules_in, NULL, NULL, hercules_out, NULL, NULL, dev); + io_sethandler(0x03b0, 0x0010, + hercules_in, NULL, NULL, + hercules_out, NULL, NULL, + dev); for (uint16_t c = 0; c < 256; c++) { dev->cols[c][0][0] = dev->cols[c][1][0] = dev->cols[c][1][1] = 16; @@ -642,6 +661,23 @@ static const device_config_t hercules_config[] = { .selection = { { 0 } }, .bios = { { 0 } } }, + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, + { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 66a0fbb71..7b6e54806 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -317,8 +317,32 @@ mda_standalone_init(UNUSED(const device_t *info)) mda->vram = malloc(0x1000); - mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); - io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + + case 2: + loadfont(FONT_KAM_PATH, 0); + break; + case 3: + loadfont(FONT_KAMCL16_PATH, 0); + break; + } + + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, + mda_read, NULL, NULL, + mda_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, + mda); + + io_sethandler(0x03b0, 0x0010, + mda_in, NULL, NULL, + mda_out, NULL, NULL, + mda); mda_init(mda); @@ -369,6 +393,23 @@ static const device_config_t mda_config[] = { }, .bios = { { 0 } } }, + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, + { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index e0ef7ada6..33a7f30ca 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -328,7 +328,7 @@ video_reset(int card) card, machine_has_flags(machine, MACHINE_VIDEO) ? 1 : 0); monitor_index_global = 0; - loadfont("roms/video/mda/mda.rom", 0); + loadfont(FONT_IBM_MDA_437_PATH, 0); for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if ((card != VID_NONE) && !machine_has_flags(machine, MACHINE_VIDEO_ONLY) && diff --git a/src/video/video.c b/src/video/video.c index 0773e61ce..11edbc3f4 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -1006,76 +1006,73 @@ video_force_resize_set_monitor(uint8_t res, int monitor_index) } void -loadfont_common(FILE *f, int format) +loadfont_common(FILE *fp, int format) { - int c; - int d; - switch (format) { case 0: /* MDA */ - for (c = 0; c < 256; c++) - for (d = 0; d < 8; d++) - fontdatm[c][d] = fgetc(f) & 0xff; - for (c = 0; c < 256; c++) - for (d = 0; d < 8; d++) - fontdatm[c][d + 8] = fgetc(f) & 0xff; - (void) fseek(f, 4096 + 2048, SEEK_SET); - for (c = 0; c < 256; c++) - for (d = 0; d < 8; d++) - fontdat[c][d] = fgetc(f) & 0xff; + for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x8 cell (lines 0-7) */ + for (uint8_t d = 0; d < 8; d++) + fontdatm[c][d] = fgetc(fp) & 0xff; + for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x8 cell (lines 8-13 + padding lines) */ + for (uint8_t d = 0; d < 8; d++) + fontdatm[c][d + 8] = fgetc(fp) & 0xff; + (void) fseek(fp, 4096 + 2048, SEEK_SET); + for (uint16_t c = 0; c < 256; c++) + for (uint8_t d = 0; d < 8; d++) /* 8x8 CGA (thick, primary) */ + fontdat[c][d] = fgetc(fp) & 0xff; break; case 1: /* PC200 */ - for (d = 0; d < 4; d++) { + for (uint8_t d = 0; d < 4; d++) { /* There are 4 fonts in the ROM */ - for (c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ - (void) !fread(&fontdatm[256 * d + c][0], 1, 16, f); - for (c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ - (void) !fread(&fontdat[256 * d + c][0], 1, 8, f); - fseek(f, 8, SEEK_CUR); + for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ + (void) !fread(&fontdatm[256 * d + c][0], 1, 16, fp); + for (uint16_t c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ + (void) !fread(&fontdat[256 * d + c][0], 1, 8, fp); + fseek(fp, 8, SEEK_CUR); } } break; default: case 2: /* CGA */ - for (c = 0; c < 256; c++) - for (d = 0; d < 8; d++) - fontdat[c][d] = fgetc(f) & 0xff; + for (uint16_t c = 0; c < 256; c++) + for (uint8_t d = 0; d < 8; d++) + fontdat[c][d] = fgetc(fp) & 0xff; break; case 3: /* Wyse 700 */ - for (c = 0; c < 512; c++) - for (d = 0; d < 32; d++) - fontdatw[c][d] = fgetc(f) & 0xff; + for (uint16_t c = 0; c < 512; c++) + for (uint8_t d = 0; d < 32; d++) + fontdatw[c][d] = fgetc(fp) & 0xff; break; case 4: /* MDSI Genius */ - for (c = 0; c < 256; c++) - for (d = 0; d < 16; d++) - fontdat8x12[c][d] = fgetc(f) & 0xff; + for (uint16_t c = 0; c < 256; c++) + for (uint8_t d = 0; d < 16; d++) + fontdat8x12[c][d] = fgetc(fp) & 0xff; break; - case 5: /* Toshiba 3100e */ - for (d = 0; d < 2048; d += 512) { /* Four languages... */ - for (c = d; c < d + 256; c++) { - (void) !fread(&fontdatm[c][8], 1, 8, f); + case 5: /* Toshiba 3100e */ + for (uint16_t d = 0; d < 2048; d += 512) { /* Four languages... */ + for (uint16_t c = d; c < d + 256; c++) { + (void) !fread(&fontdatm[c][8], 1, 8, fp); } - for (c = d + 256; c < d + 512; c++) { - (void) !fread(&fontdatm[c][8], 1, 8, f); + for (uint16_t c = d + 256; c < d + 512; c++) { + (void) !fread(&fontdatm[c][8], 1, 8, fp); } - for (c = d; c < d + 256; c++) { - (void) !fread(&fontdatm[c][0], 1, 8, f); + for (uint16_t c = d; c < d + 256; c++) { + (void) !fread(&fontdatm[c][0], 1, 8, fp); } - for (c = d + 256; c < d + 512; c++) { - (void) !fread(&fontdatm[c][0], 1, 8, f); + for (uint16_t c = d + 256; c < d + 512; c++) { + (void) !fread(&fontdatm[c][0], 1, 8, fp); } - fseek(f, 4096, SEEK_CUR); /* Skip blank section */ - for (c = d; c < d + 256; c++) { - (void) !fread(&fontdat[c][0], 1, 8, f); + fseek(fp, 4096, SEEK_CUR); /* Skip blank section */ + for (uint16_t c = d; c < d + 256; c++) { + (void) !fread(&fontdat[c][0], 1, 8, fp); } - for (c = d + 256; c < d + 512; c++) { - (void) !fread(&fontdat[c][0], 1, 8, f); + for (uint16_t c = d + 256; c < d + 512; c++) { + (void) !fread(&fontdat[c][0], 1, 8, fp); } } break; @@ -1087,65 +1084,64 @@ loadfont_common(FILE *f, int format) if (!fontdatksc5601_user) fontdatksc5601_user = malloc(192 * sizeof(dbcs_font_t)); - for (c = 0; c < 16384; c++) { - for (d = 0; d < 32; d++) - fontdatksc5601[c].chr[d] = fgetc(f) & 0xff; + for (uint32_t c = 0; c < 16384; c++) { + for (uint8_t d = 0; d < 32; d++) + fontdatksc5601[c].chr[d] = fgetc(fp) & 0xff; } break; case 7: /* Sigma Color 400 */ /* The first 4k of the character ROM holds an 8x8 font */ - for (c = 0; c < 256; c++) { - (void) !fread(&fontdat[c][0], 1, 8, f); - fseek(f, 8, SEEK_CUR); + for (uint16_t c = 0; c < 256; c++) { + (void) !fread(&fontdat[c][0], 1, 8, fp); + fseek(fp, 8, SEEK_CUR); } /* The second 4k holds an 8x16 font */ - for (c = 0; c < 256; c++) { - if (fread(&fontdatm[c][0], 1, 16, f) != 16) + for (uint16_t c = 0; c < 256; c++) { + if (fread(&fontdatm[c][0], 1, 16, fp) != 16) fatal("loadfont(): Error reading 8x16 font in Sigma Color 400 mode, c = %i\n", c); } break; - case 8: /* Amstrad PC1512, Toshiba T1000/T1200 */ - for (c = 0; c < 2048; c++) /* Allow up to 2048 chars */ - for (d = 0; d < 8; d++) - fontdat[c][d] = fgetc(f) & 0xff; + case 8: /* Amstrad PC1512, Toshiba T1000/T1200 */ + for (uint16_t c = 0; c < 2048; c++) /* Allow up to 2048 chars */ + for (uint8_t d = 0; d < 8; d++) + fontdat[c][d] = fgetc(fp) & 0xff; break; case 9: /* Image Manager 1024 native font */ - for (c = 0; c < 256; c++) - (void) !fread(&fontdat12x18[c][0], 1, 36, f); + for (uint16_t c = 0; c < 256; c++) + (void) !fread(&fontdat12x18[c][0], 1, 36, fp); break; - case 10: /* Pravetz */ - for (c = 0; c < 1024; c++) /* Allow up to 1024 chars */ - for (d = 0; d < 8; d++) - fontdat[c][d] = fgetc(f) & 0xff; + case 10: /* Pravetz */ + for (uint16_t c = 0; c < 1024; c++) /* Allow up to 1024 chars */ + for (uint8_t d = 0; d < 8; d++) + fontdat[c][d] = fgetc(fp) & 0xff; break; - case 11: /* PC200 */ - for (d = 0; d < 4; d++) { + for (uint8_t d = 0; d < 4; d++) { /* There are 4 fonts in the ROM */ - for (c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ - (void) !fread(&fontdatm2[256 * d + c][0], 1, 16, f); - for (c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ - (void) !fread(&fontdat2[256 * d + c][0], 1, 8, f); - fseek(f, 8, SEEK_CUR); + for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ + (void) !fread(&fontdatm2[256 * d + c][0], 1, 16, fp); + for (uint16_t c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ + (void) !fread(&fontdat2[256 * d + c][0], 1, 8, fp); + fseek(fp, 8, SEEK_CUR); } } break; } - (void) fclose(f); + (void) fclose(fp); } void -loadfont_ex(char *s, int format, int offset) +loadfont_ex(char *fn, int format, int offset) { FILE *fp; - fp = rom_fopen(s, "rb"); + fp = rom_fopen(fn, "rb"); if (fp == NULL) return; @@ -1154,9 +1150,9 @@ loadfont_ex(char *s, int format, int offset) } void -loadfont(char *s, int format) +loadfont(char *fn, int format) { - loadfont_ex(s, format, 0); + loadfont_ex(fn, format, 0); } uint32_t From eac0006e7fc6923cac973dbe4c69fa478e3fd1ab Mon Sep 17 00:00:00 2001 From: rushieda <185547947+rushieda@users.noreply.github.com> Date: Tue, 27 May 2025 23:40:14 +0300 Subject: [PATCH 0999/1190] Add the Dell System 200 machine --- src/include/86box/machine.h | 1 + src/machine/m_at_286_386sx.c | 18 ++++++++++++++++ src/machine/machine_table.c | 41 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 0dbbe98c5..ac26f7a50 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -475,6 +475,7 @@ extern int machine_at_spc4216p_init(const machine_t *); extern int machine_at_spc4620p_init(const machine_t *); extern int machine_at_kmxc02_init(const machine_t *); extern int machine_at_deskmaster286_init(const machine_t *); +extern int machine_at_dells200_init(const machine_t *); extern int machine_at_pc8_init(const machine_t *); extern int machine_at_3302_init(const machine_t *); diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index e7aa66662..8400e4ae8 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -261,6 +261,24 @@ machine_at_px286_init(const machine_t *model) return ret; } +int +machine_at_dells200_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved("roms/machines/dells200/dellL200256_LO_@DIP28.BIN", + "roms/machines/dells200/Dell200256_HI_@DIP28.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + device_add(&keyboard_at_device); + + return ret; +} + int machine_at_micronics386_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index a3a02bfcd..d2ef357e1 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2975,6 +2975,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC + firmware. */ + { + .name = "[ISA] Dell System 200", + .internal_name = "dells200", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_PROPRIETARY, + .init = machine_at_dells200_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 12000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has IBM AT KBC firmware. */ { .name = "[ISA] MR BIOS 286 clone", From cebf27f02d134c77877ef430a9d690795e245d12 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 04:09:47 +0200 Subject: [PATCH 1000/1190] Finish the Dell System 200 work. --- src/chipset/CMakeLists.txt | 1 + src/chipset/cs8220.c | 289 +++++++++++++++++++++++++++++++++++ src/include/86box/chipset.h | 1 + src/include/86box/machine.h | 1 + src/machine/m_at_286_386sx.c | 10 +- src/machine/machine_table.c | 89 +++++------ 6 files changed, 345 insertions(+), 46 deletions(-) create mode 100644 src/chipset/cs8220.c diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 7d17b9983..7a8233003 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(chipset OBJECT 82c100.c acc2168.c + cs8220.c cs8230.c ali1429.c ali1435.c diff --git a/src/chipset/cs8220.c b/src/chipset/cs8220.c new file mode 100644 index 000000000..4c08ecef5 --- /dev/null +++ b/src/chipset/cs8220.c @@ -0,0 +1,289 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of C&T CS8220 ("PC/AT") chipset. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/chipset.h> + +typedef struct { + uint32_t virt; + uint32_t phys; + + uint32_t size; + + mem_mapping_t mapping; +} ram_bank_t; + +typedef struct { + uint8_t regs[3]; + + ram_bank_t ram_banks[3]; +} cs8220_t; + +static uint8_t +cs8220_mem_read(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint8_t ret = 0xff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = ram[addr]; + + return ret; +} + +static uint16_t +cs8220_mem_readw(uint32_t addr, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + uint16_t ret = 0xffff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = *(uint16_t *) &(ram[addr]); + + return ret; +} + +static void +cs8220_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ram[addr] = val; +} + +static void +cs8220_mem_writew(uint32_t addr, uint16_t val, void *priv) +{ + ram_bank_t *dev = (ram_bank_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + *(uint16_t *) &(ram[addr]) = val; +} + +static uint8_t +cs8220_in(uint16_t port, void *priv) { + cs8220_t *dev = (cs8220_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x00a4 ... 0x00a5: + ret = dev->regs[port & 0x0001]; + break; + case 0x00ab: + ret = dev->regs[2]; + break; + } + + return ret; +} + +static void +cs8220_out(uint16_t port, uint8_t val, void *priv) { + cs8220_t *dev = (cs8220_t *) priv; + + switch (port) { + case 0x00a4: + dev->regs[0] = val; + mem_a20_alt = val & 0x40; + mem_a20_recalc(); + break; + case 0x00a5: + dev->regs[1] = val; + if (val & 0x01) { + mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, 0x000040000); + mem_mapping_disable(&dev->ram_banks[1].mapping); + mem_mapping_disable(&dev->ram_banks[2].mapping); + } else { + mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, dev->ram_banks[0].size); + mem_mapping_enable(&dev->ram_banks[1].mapping); + mem_mapping_enable(&dev->ram_banks[2].mapping); + } + break; + case 0x00ab: + dev->regs[2] = val; + break; + } +} + +static void +cs8220_close(void *priv) +{ + cs8220_t *dev = (cs8220_t *) priv; + + free(dev); +} + +static void * +cs8220_init(UNUSED(const device_t *info)) +{ + cs8220_t *dev = (cs8220_t *) calloc(1, sizeof(cs8220_t)); + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + /* + Dell System 200: 640 kB soldered on-board, any other RAM is expansion. + */ + if (!strcmp(machine_get_internal_name(), "dells200")) switch (mem_size) { + default: + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x000a0000; + dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000; + fallthrough; + case 640: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + break; + /* + We are limited to steps of equal size, so we have to simulate some + memory expansions to work around the chipset's limits. + */ + } else switch (mem_size) { + case 256: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00020000; + dev->ram_banks[1].virt = 0x00020000; + dev->ram_banks[1].phys = 0x00020000; + dev->ram_banks[1].size = 0x00020000; + break; + case 384: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00020000; + /* Pretend there's a 128k expansion. */ + dev->ram_banks[2].virt = 0x00020000; + dev->ram_banks[2].phys = 0x00020000; + dev->ram_banks[2].size = 0x00040000; + break; + case 512: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + break; + default: + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x000a0000; + dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000; + fallthrough; + case 640: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + break; + case 768: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + /* Pretend there's a 128k expansion. */ + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x00080000; + dev->ram_banks[2].size = 0x00020000; + break; + case 896: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00080000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00020000; + /* Pretend there's a 256k expansion. */ + dev->ram_banks[2].virt = 0x00100000; + dev->ram_banks[2].phys = 0x00080000; + dev->ram_banks[2].size = 0x00040000; + break; + case 1024: + dev->ram_banks[0].virt = 0x00000000; + dev->ram_banks[0].phys = 0x00000000; + dev->ram_banks[0].size = 0x00080000; + dev->ram_banks[1].virt = 0x00100000; + dev->ram_banks[1].phys = 0x00080000; + dev->ram_banks[1].size = 0x00080000; + break; + } + + if (dev->ram_banks[0].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[0].mapping, dev->ram_banks[0].virt, dev->ram_banks[0].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[0].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[0])); + + if (dev->ram_banks[1].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[1].mapping, dev->ram_banks[1].virt, dev->ram_banks[1].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[1].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[1])); + + if (dev->ram_banks[2].size > 0x00000000) + mem_mapping_add(&dev->ram_banks[2].mapping, dev->ram_banks[2].virt, dev->ram_banks[2].size, + cs8220_mem_read, cs8220_mem_readw, NULL, + cs8220_mem_write, cs8220_mem_writew, NULL, + ram + dev->ram_banks[2].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[2])); + + io_sethandler(0x00a4, 0x0002, + cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev); + io_sethandler(0x00ab, 0x0001, + cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev); + + return dev; +} + +const device_t cs8220_device = { + .name = "C&T CS8220 (PC/AT)", + .internal_name = "cs8220", + .flags = 0, + .local = 0, + .init = cs8220_init, + .close = cs8220_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 688a5fecb..e11af5e4d 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -55,6 +55,7 @@ extern const device_t neat_sx_device; extern const device_t scat_device; extern const device_t scat_4_device; extern const device_t scat_sx_device; +extern const device_t cs8220_device; extern const device_t cs8230_device; extern const device_t cs4031_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ac26f7a50..137880a11 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -211,6 +211,7 @@ enum { MACHINE_CHIPSET_SCAT_SX, MACHINE_CHIPSET_NEAT, MACHINE_CHIPSET_NEAT_SX, + MACHINE_CHIPSET_CT_AT, MACHINE_CHIPSET_CT_386, MACHINE_CHIPSET_CT_CS4031, MACHINE_CHIPSET_CONTAQ_82C596, diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 8400e4ae8..2b181c499 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -273,8 +273,14 @@ machine_at_dells200_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_ide_init(model); - device_add(&keyboard_at_device); + machine_at_common_init(model); + + device_add(&cs8220_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + device_add(&keyboard_at_phoenix_device); return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d2ef357e1..4b5f82f5d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -117,11 +117,12 @@ const machine_filter_t machine_chipsets[] = { { "ALi ALADDiN IV+", MACHINE_CHIPSET_ALI_ALADDIN_IV_PLUS }, { "ALi ALADDiN V", MACHINE_CHIPSET_ALI_ALADDIN_V }, { "ALi ALADDiN-PRO II", MACHINE_CHIPSET_ALI_ALADDIN_PRO_II }, + { "C&T PC/AT", MACHINE_CHIPSET_CT_AT }, + { "C&T 386/AT", MACHINE_CHIPSET_CT_386 }, { "C&T 82C235 SCAT", MACHINE_CHIPSET_SCAT }, { "C&T 82C236 SCATsx", MACHINE_CHIPSET_SCAT_SX }, { "C&T CS8221 NEAT", MACHINE_CHIPSET_NEAT }, { "C&T CS8281 NEATsx", MACHINE_CHIPSET_NEAT_SX }, - { "C&T 386", MACHINE_CHIPSET_CT_386 }, { "C&T CS4031", MACHINE_CHIPSET_CT_CS4031 }, { "Contaq 82C596", MACHINE_CHIPSET_CONTAQ_82C596 }, { "Contaq 82C597", MACHINE_CHIPSET_CONTAQ_82C597 }, @@ -2975,47 +2976,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC - firmware. */ - { - .name = "[ISA] Dell System 200", - .internal_name = "dells200", - .type = MACHINE_TYPE_286, - .chipset = MACHINE_CHIPSET_PROPRIETARY, - .init = machine_at_dells200_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_286, - .block = CPU_BLOCK_NONE, - .min_bus = 6000000, - .max_bus = 12000000, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_AT, - .flags = MACHINE_FLAGS_NONE, - .ram = { - .min = 640, - .max = 16384, - .step = 128 - }, - .nvrmask = 127, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, /* Has IBM AT KBC firmware. */ { .name = "[ISA] MR BIOS 286 clone", @@ -3460,6 +3420,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC + firmware. */ + { + .name = "[C&T PC/AT] Dell System 200", + .internal_name = "dells200", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_CT_AT, + .init = machine_at_dells200_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 12000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has Quadtel KBC firmware. */ { .name = "[GC103] Quadtel 286 clone", @@ -5280,7 +5281,7 @@ const machine_t machines[] = { }, /* Has an AMI Keyboard BIOS PLUS KBC firmware ('8'). */ { - .name = "[C&T 386] ECS 386/32", + .name = "[C&T 386/AT] ECS 386/32", .internal_name = "ecs386", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_CT_386, @@ -5320,7 +5321,7 @@ const machine_t machines[] = { }, /* Has IBM AT KBC firmware. */ { - .name = "[C&T 386] Samsung SPC-6000A", + .name = "[C&T 386/AT] Samsung SPC-6000A", .internal_name = "spc6000a", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_CT_386, From 83224dcadefa4cb3b3a99779e47c5ea35f3e27c4 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 04:20:25 +0200 Subject: [PATCH 1001/1190] Bring the AN430TX out of the Dev branch in form of the Packard Bell PB790. --- CMakeLists.txt | 1 - src/chipset/intel_4x0.c | 13 +++-- src/machine/CMakeLists.txt | 8 --- src/machine/m_at_socket7.c | 30 +++++------- src/machine/machine_table.c | 97 +++++++++++++++++++------------------ 5 files changed, 71 insertions(+), 78 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b78295fd..3ad83fb4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,7 +173,6 @@ endif() # Option Description Def. Condition Otherwise # ------ ----------- ---- ------------ --------- cmake_dependent_option(AMD_K5 "AMD K5" ON "DEV_BRANCH" OFF) -cmake_dependent_option(AN430TX "Intel AN430TX" ON "DEV_BRANCH" OFF) cmake_dependent_option(CDROM_MITSUMI "Mitsumi CDROM" ON "DEV_BRANCH" OFF) cmake_dependent_option(G100 "Matrox Productiva G100" ON "DEV_BRANCH" OFF) cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" ON "DEV_BRANCH" OFF) diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c index 84bd872f8..8e6ce97c3 100644 --- a/src/chipset/intel_4x0.c +++ b/src/chipset/intel_4x0.c @@ -1013,7 +1013,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) case INTEL_430TX: if (!dev->smram_locked) { i4x0_smram_handler_phase0(dev); - regs[0x71] = (regs[0x71] & 0x20) | (val & 0xdf); + regs[0x71] = (regs[0x71] & 0x60) | (val & 0x9f); + regs[0x71] &= (val & 0x40); i4x0_smram_handler_phase1(dev); } break; @@ -1041,9 +1042,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv) regs[0x72] = (val & 0x7f); else regs[0x72] = (regs[0x72] & 0x87) | (val & 0x78); - dev->smram_locked = (val & 0x10); - if (dev->smram_locked) - regs[0x72] &= 0xbf; + if (val & 0x08) { + dev->smram_locked = (val & 0x10); + if (dev->smram_locked) + regs[0x72] &= 0xbf; + } } } else { if (dev->smram_locked) @@ -1577,6 +1580,8 @@ i4x0_reset(void *priv) dev->regs[0x68 + i] = 0x00; } + dev->smram_locked = 0; + if (dev->type >= INTEL_430FX) { dev->regs[0x72] &= 0xef; /* Forcibly unlock the SMRAM register. */ i4x0_write(0, 0x72, 0x02, priv); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 4098f2553..20d60c075 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -57,14 +57,6 @@ add_library(mch OBJECT m_at_misc.c ) -if(AN430TX) - target_compile_definitions(mch PRIVATE USE_AN430TX) -endif() - -if(DESKPRO386) - target_compile_definitions(mch PRIVATE USE_DESKPRO386) -endif() - if(OLIVETTI) target_compile_definitions(mch PRIVATE USE_OLIVETTI) endif() diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 7d2441e18..d4b71f92f 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -1007,27 +1007,17 @@ machine_at_optiplex_gn_init(const machine_t *model) return ret; } -#ifdef USE_AN430TX int machine_at_an430tx_init(const machine_t *model) { int ret; -# if 1 - ret = bios_load_linear_combined2("roms/machines/an430tx/P10-0095.BIO", - "roms/machines/an430tx/P10-0095.BI1", - "roms/machines/an430tx/P10-0095.BI2", - "roms/machines/an430tx/P10-0095.BI3", - "roms/machines/an430tx/P10-0095.RCV", + ret = bios_load_linear_combined2("roms/machines/an430tx/ANP0911A.BIO", + "roms/machines/an430tx/ANP0911A.BI1", + "roms/machines/an430tx/ANP0911A.BI2", + "roms/machines/an430tx/ANP0911A.BI3", + "roms/machines/an430tx/ANP0911A.RCV", 0x3a000, 160); -# else - ret = bios_load_linear_combined2("roms/machines/an430tx/P06-0062.BIO", - "roms/machines/an430tx/P06-0062.BI1", - "roms/machines/an430tx/P06-0062.BI2", - "roms/machines/an430tx/P06-0062.BI3", - "roms/machines/an430tx/P10-0095.RCV", - 0x3a000, 160); -# endif if (bios_only || !ret) return ret; @@ -1036,21 +1026,25 @@ machine_at_an430tx_init(const machine_t *model) pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ - // pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); /* PIIX4 */ pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); device_add(&i430tx_device); device_add(&piix4_device); +#ifdef FOLLOW_THE_SPECIFICATION device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42I | PCX7307_PC97307)); +#else + /* The technical specification says Phoenix, a real machnine HWINFO dump says AMI '5'. */ + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC97307)); +#endif device_add(&intel_flash_bxt_ami_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); return ret; } -#endif /* USE_AN430TX */ int machine_at_ym430tx_init(const machine_t *model) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 4b5f82f5d..add0c2b7c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -13275,49 +13275,6 @@ const machine_t machines[] = { .snd_device = &cs4236b_device, .net_device = &pcnet_am79c973_onboard_device }, -#ifdef USE_AN430TX - /* This has the Phoenix MultiKey KBC firmware. */ - { - .name = "[i430TX] Intel AN430TX (Anchorage)", - .internal_name = "an430tx", - .type = MACHINE_TYPE_SOCKET7, - .chipset = MACHINE_CHIPSET_INTEL_430TX, - .init = machine_at_an430tx_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_SOCKET5_7, - .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, - CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), - .min_bus = 60000000, - .max_bus = 66666667, - .min_voltage = 2800, - .max_voltage = 3520, - .min_multi = 1.5, - .max_multi = 3.5 - }, - .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, - .ram = { - .min = 8192, - .max = 262144, - .step = 8192 - }, - .nvrmask = 255, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, -#endif /* USE_AN430TX */ /* This has the AMIKey KBC firmware, which is an updated 'F' type. */ { .name = "[i430TX] Intel YM430TX (Yamamoto)", @@ -13359,9 +13316,13 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, - /* PhoenixBIOS 4.0 Rel 6.0 for 430TX, has onboard Yamaha YMF701 which is not emulated yet. */ - /* Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix - MultiKey/42 (version 1.38) KBC firmware. */ + /* + PhoenixBIOS 4.0 Rel 6.0 for 430TX, has onboard Yamaha YMF701 which + is not emulated yet. + + Has a SM(S)C FDC37C935 Super I/O chip with on-chip KBC with Phoenix + MultiKey/42 (version 1.38) KBC firmware. + */ { .name = "[i430TX] Micronics Thunderbolt", .internal_name = "thunderbolt", @@ -13383,7 +13344,8 @@ const machine_t machines[] = { .max_multi = 3.5 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_GAMEPORT | MACHINE_USB, /* Machine has internal sound: Yamaha YMF701-S */ + /* Machine has internal sound: Yamaha YMF701-S */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_GAMEPORT | MACHINE_USB, .ram = { .min = 8192, .max = 262144, @@ -13442,6 +13404,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* This has the Phoenix MultiKey KBC firmware. */ + { + .name = "[i430TX] Packard Bell PB790", + .internal_name = "an430tx", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_an430tx_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), + .min_bus = 60000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* The BIOS sends KBC command BB and expects it to output a byte, which is AMI KBC behavior. A picture shows a VIA VT82C42N KBC though, so it could be a case of that KBC with AMI firmware. */ { From 265b69c7eaef196c9a98683beb73ec2772798ca1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 04:34:00 +0200 Subject: [PATCH 1002/1190] And machine.h - this should fix compile. --- src/include/86box/machine.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 137880a11..320847e7b 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -756,11 +756,9 @@ extern int machine_at_ma23c_init(const machine_t *); extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); extern int machine_at_optiplex_gn_init(const machine_t *); -#ifdef USE_AN430TX -extern int machine_at_an430tx_init(const machine_t *); -#endif /* USE_AN430TX */ extern int machine_at_ym430tx_init(const machine_t *); extern int machine_at_thunderbolt_init(const machine_t *); +extern int machine_at_an430tx_init(const machine_t *); extern int machine_at_mb540n_init(const machine_t *); extern int machine_at_56a5_init(const machine_t *); extern int machine_at_p5mms98_init(const machine_t *); From 76e9a20e12975d1cfd9bcf3b01b29b216cecf966 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 05:51:40 +0200 Subject: [PATCH 1003/1190] Bring the Olivetti M290 out of the Dev branch. --- CMakeLists.txt | 1 - src/chipset/CMakeLists.txt | 5 +---- src/chipset/olivetti_eva.c | 27 +++++++++------------------ src/include/86box/machine.h | 2 -- src/machine/CMakeLists.txt | 4 ---- src/machine/m_at_286_386sx.c | 10 +++++----- src/machine/machine_table.c | 2 -- 7 files changed, 15 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ad83fb4a..161394778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,6 @@ cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF) -cmake_dependent_option(OLIVETTI "Olivetti M290" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPEN_AT "OpenAT" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPL4ML "OPL4-ML daughterboard" ON "DEV_BRANCH" OFF) cmake_dependent_option(PCL "Generic PCL5e Printer" ON "DEV_BRANCH" OFF) diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 7a8233003..7817ac052 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(chipset OBJECT isa486c.c ../ioapic.c neat.c + olivetti_eva.c opti283.c opti291.c opti391.c @@ -86,7 +87,3 @@ add_library(chipset OBJECT vl82c480.c wd76c10.c ) - -if(OLIVETTI) - target_sources(chipset PRIVATE olivetti_eva.c) -endif() diff --git a/src/chipset/olivetti_eva.c b/src/chipset/olivetti_eva.c index 7defac6ae..0dcbdd21f 100644 --- a/src/chipset/olivetti_eva.c +++ b/src/chipset/olivetti_eva.c @@ -73,26 +73,24 @@ olivetti_eva_write(uint16_t addr, uint8_t val, void *priv) break; case 0x069: dev->reg_069 = val; - /* - * Unfortunately, if triggered, the BIOS remapping function fails causing - * a fatal error. Therefore, this code section is currently commented. - */ -#if 0 - if (val & 1) { + mem_remap_top(0); + if (val == 0x01) { /* * Set the register to 7 or above for the BIOS to trigger the * memory remapping function if shadowing is active. */ - dev->reg_069 = 0x7; + dev->reg_069 = 0x07; } - if (val & 8) { + if (val & 0x08) { /* * Activate shadowing for region e0000-fffff */ mem_remap_top(256); - mem_set_mem_state_both(0xa0000, 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else { + mem_remap_top(384); + mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } -#endif break; default: break; @@ -143,7 +141,7 @@ olivetti_eva_init(UNUSED(const device_t *info)) dev->reg_067 = 0x00; /* RAM enable registers */ - dev->reg_069 = 0x0; + dev->reg_069 = 0x00; io_sethandler(0x0065, 0x0001, olivetti_eva_read, NULL, NULL, olivetti_eva_write, NULL, NULL, dev); io_sethandler(0x0067, 0x0001, olivetti_eva_read, NULL, NULL, olivetti_eva_write, NULL, NULL, dev); @@ -152,13 +150,6 @@ olivetti_eva_init(UNUSED(const device_t *info)) /* When shadowing is not enabled in BIOS, all upper memory is available as XMS */ mem_remap_top(384); - /* - * Default settings when NVRAM is cleared activate shadowing. - * Thus, to avoid boot errors, remap only 256k from UMB to XMS. - * Remove this block once BIOS memory remapping works. - */ - mem_remap_top(256); - return dev; } diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 320847e7b..d6725ec9a 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -481,9 +481,7 @@ extern int machine_at_dells200_init(const machine_t *); extern int machine_at_pc8_init(const machine_t *); extern int machine_at_3302_init(const machine_t *); -#ifdef USE_OLIVETTI extern int machine_at_m290_init(const machine_t *); -#endif /* USE_OLIVETTI */ extern int machine_at_shuttle386sx_init(const machine_t *); extern int machine_at_adi386sx_init(const machine_t *); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 20d60c075..2e3bc02bc 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -57,10 +57,6 @@ add_library(mch OBJECT m_at_misc.c ) -if(OLIVETTI) - target_compile_definitions(mch PRIVATE USE_OLIVETTI) -endif() - if(OPEN_AT) target_compile_definitions(mch PRIVATE USE_OPEN_AT) endif() diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 2b181c499..853829ccc 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -1069,7 +1069,6 @@ machine_at_pc916sx_init(const machine_t *model) return ret; } -#ifdef USE_OLIVETTI int machine_at_m290_init(const machine_t *model) { @@ -1081,15 +1080,16 @@ machine_at_m290_init(const machine_t *model) if (bios_only || !ret) return ret; - machine_at_common_init_ex(model, 4); - device_add(&keyboard_at_olivetti_device); + machine_at_common_init_ex(model, 6); + device_add(&amstrad_megapc_nvr_device); + + device_add(&olivetti_eva_device); device_add(&port_6x_olivetti_device); if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&olivetti_eva_device); + device_add(&keyboard_at_olivetti_device); return ret; } -#endif /* USE_OLIVETTI */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index add0c2b7c..8cdc7444b 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3096,7 +3096,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, -#ifdef USE_OLIVETTI /* Has Olivetti KBC firmware. */ { .name = "[ISA] Olivetti M290", @@ -3137,7 +3136,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, -#endif /* USE_OLIVETTI */ #ifdef USE_OPEN_AT /* Has IBM AT KBC firmware. */ { From 6426c375ee7acba5d1dc3b90f88675fe9416677d Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 06:45:18 +0200 Subject: [PATCH 1004/1190] And chipset.h. --- src/include/86box/chipset.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index e11af5e4d..e0e775fa1 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -113,6 +113,9 @@ extern const device_t slc90e66_device; extern const device_t ioapic_device; +/* Olivetti */ +extern const device_t olivetti_eva_device; + /* OPTi */ extern const device_t opti283_device; extern const device_t opti291_device; @@ -204,8 +207,4 @@ extern const device_t nec_mate_unk_device; extern const device_t phoenix_486_jumper_device; extern const device_t phoenix_486_jumper_pci_device; - -#ifdef USE_OLIVETTI -extern const device_t olivetti_eva_device; -#endif /* USE_OLIVETTI */ #endif /*EMU_CHIPSET_H*/ From d49a71ee6e7841378b1b9a69105805e9f7b8f55d Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 09:48:53 +0200 Subject: [PATCH 1005/1190] Remove the GUS Max from the Dev branch. --- CMakeLists.txt | 1 - src/include/86box/sound.h | 1 + src/sound/CMakeLists.txt | 4 --- src/sound/snd_gus.c | 69 ++++++++++++--------------------------- src/sound/sound.c | 1 + 5 files changed, 23 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 161394778..a632b71ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,7 +175,6 @@ endif() cmake_dependent_option(AMD_K5 "AMD K5" ON "DEV_BRANCH" OFF) cmake_dependent_option(CDROM_MITSUMI "Mitsumi CDROM" ON "DEV_BRANCH" OFF) cmake_dependent_option(G100 "Matrox Productiva G100" ON "DEV_BRANCH" OFF) -cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF) diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index b2e202ddb..985abe777 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -197,6 +197,7 @@ extern const device_t ct5880_onboard_device; /* Gravis UltraSound and UltraSound Max */ extern const device_t gus_device; +extern const device_t gus_max_device; /* IBM PS/1 Audio Card */ extern const device_t ps1snd_device; diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index fb3c9b43d..66a0ee4e3 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -185,10 +185,6 @@ target_link_libraries(86Box esfmu) add_subdirectory(ymfm) target_link_libraries(86Box ymfm) -if(GUSMAX) - target_compile_definitions(snd PRIVATE USE_GUSMAX) -endif() - if(OPL4ML) target_compile_definitions(snd PRIVATE USE_OPL4ML) target_sources(snd PRIVATE midi_opl4.c midi_opl4_yrw801.c) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 1885581a5..fff679e81 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -17,9 +17,7 @@ #include <86box/sound.h> #include "cpu.h" #include <86box/timer.h> -#ifdef USE_GUSMAX -# include <86box/snd_ad1848.h> -#endif /*USE_GUSMAX */ +#include <86box/snd_ad1848.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> @@ -145,11 +143,9 @@ typedef struct gus_t { uint8_t usrr; -#ifdef USE_GUSMAX uint8_t max_ctrl; ad1848_t ad1848; -#endif /*USE_GUSMAX */ } gus_t; static int gus_gf1_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 }; @@ -257,9 +253,7 @@ writegus(uint16_t addr, uint8_t val, void *priv) int d; int old; uint16_t port; -#ifdef USE_GUSMAX uint16_t csioport; -#endif /*USE_GUSMAX */ if ((addr == 0x388) || (addr == 0x389)) port = addr; @@ -607,10 +601,9 @@ writegus(uint16_t addr, uint8_t val, void *priv) gus->irq_midi = gus->irq; } else gus->irq_midi = gus_midi_irqs[(val >> 3) & 7]; -#ifdef USE_GUSMAX + if (gus->type == GUS_MAX) ad1848_setirq(&gus->ad1848, gus->irq); -#endif /*USE_GUSMAX */ gus->sb_nmi = val & 0x80; } else { @@ -623,10 +616,9 @@ writegus(uint16_t addr, uint8_t val, void *priv) gus->dma2 = gus->dma; } else gus->dma2 = gus_dmas[(val >> 3) & 7]; -#ifdef USE_GUSMAX + if (gus->type == GUS_MAX) ad1848_setdma(&gus->ad1848, gus->dma2); -#endif /*USE_GUSMAX */ } break; case 1: @@ -684,7 +676,6 @@ writegus(uint16_t addr, uint8_t val, void *priv) break; case 0x306: case 0x706: -#ifdef USE_GUSMAX if (gus->type == GUS_MAX) { if (gus->dma >= 4) val |= 0x10; @@ -704,7 +695,6 @@ writegus(uint16_t addr, uint8_t val, void *priv) } } } -#endif /*USE_GUSMAX */ break; default: @@ -756,11 +746,9 @@ readgus(uint16_t addr, void *priv) return val; case 0x20F: -#ifdef USE_GUSMAX if (gus->type == GUS_MAX) val = 0x02; else -#endif /*USE_GUSMAX */ val = 0x00; break; @@ -879,11 +867,9 @@ readgus(uint16_t addr, void *priv) break; case 0x306: case 0x706: -#ifdef USE_GUSMAX if (gus->type == GUS_MAX) val = 0x0a; /* GUS MAX */ else -#endif /*USE_GUSMAX */ val = 0xff; /*Pre 3.7 - no mixer*/ break; @@ -1183,24 +1169,20 @@ gus_get_buffer(int32_t *buffer, int len, void *priv) { gus_t *gus = (gus_t *) priv; -#ifdef USE_GUSMAX if ((gus->type == GUS_MAX) && (gus->max_ctrl)) ad1848_update(&gus->ad1848); -#endif /*USE_GUSMAX */ + gus_update(gus); for (int c = 0; c < len * 2; c++) { -#ifdef USE_GUSMAX if ((gus->type == GUS_MAX) && (gus->max_ctrl)) buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2); -#endif /*USE_GUSMAX */ buffer[c] += (int32_t) gus->buffer[c & 1][c >> 1]; } -#ifdef USE_GUSMAX if ((gus->type == GUS_MAX) && (gus->max_ctrl)) gus->ad1848.pos = 0; -#endif /*USE_GUSMAX */ + gus->pos = 0; } @@ -1333,9 +1315,7 @@ gus_reset(void *priv) gus->usrr = 0; -#ifdef USE_GUSMAX gus->max_ctrl = 0; -#endif /*USE_GUSMAX */ gus->irq_state = 0; gus->midi_irq_state = 0; @@ -1373,7 +1353,7 @@ gus_init(UNUSED(const device_t *info)) gus->uart_out = 1; - gus->type = device_get_config_int("type"); + gus->type = info->local; gus->base = device_get_config_hex16("base"); @@ -1382,7 +1362,6 @@ gus_init(UNUSED(const device_t *info)) io_sethandler(0x0506 + gus->base, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); -#ifdef USE_GUSMAX if (gus->type == GUS_MAX) { ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231); ad1848_setirq(&gus->ad1848, 5); @@ -1390,7 +1369,6 @@ gus_init(UNUSED(const device_t *info)) io_sethandler(0x10C + gus->base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &gus->ad1848); } -#endif /*USE_GUSMAX */ timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); @@ -1423,31 +1401,12 @@ gus_speed_changed(void *priv) else gus->samp_latch = (uint64_t) (TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); -#ifdef USE_GUSMAX if ((gus->type == GUS_MAX) && (gus->max_ctrl)) ad1848_speed_changed(&gus->ad1848); -#endif /*USE_GUSMAX */ } static const device_config_t gus_config[] = { // clang-format off - { - .name = "type", - .description = "GUS type", - .type = CONFIG_SELECTION, - .default_string = NULL, - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { - { .description = "Classic", .value = GUS_CLASSIC }, -#ifdef USE_GUSMAX - { .description = "MAX", .value = GUS_MAX }, -#endif /*USE_GUSMAX */ - { NULL } - }, - .bios = { { 0 } } - }, { .name = "base", .description = "Address", @@ -1502,7 +1461,21 @@ const device_t gus_device = { .name = "Gravis UltraSound", .internal_name = "gus", .flags = DEVICE_ISA16, - .local = 0, + .local = GUS_CLASSIC, + .init = gus_init, + .close = gus_close, + .reset = gus_reset, + .available = NULL, + .speed_changed = gus_speed_changed, + .force_redraw = NULL, + .config = gus_config +}; + +const device_t gus_max_device = { + .name = "Gravis UltraSound MAX", + .internal_name = "gus", + .flags = DEVICE_ISA16, + .local = GUS_MAX, .init = gus_init, .close = gus_close, .reset = gus_reset, diff --git a/src/sound/sound.c b/src/sound/sound.c index c3ecc8632..7bf27a136 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -115,6 +115,7 @@ static const SOUND_CARD sound_cards[] = { { &ess_ess0102_pnp_device }, { &ess_ess0968_pnp_device }, { &gus_device }, + { &gus_max_device }, { &sb_1_device }, { &sb_15_device }, { &sb_2_device }, From e9c7795c7a06ddbe2e3197685cce375d40be42d7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 09:51:08 +0200 Subject: [PATCH 1006/1190] Remove the OpenAT entirely - its BIOS never rearched any sort of actually usable state (and is also not actually Open, just visible source). --- CMakeLists.txt | 1 - src/include/86box/machine.h | 3 --- src/machine/CMakeLists.txt | 4 --- src/machine/m_at.c | 18 ------------- src/machine/machine_table.c | 51 ++----------------------------------- 5 files changed, 2 insertions(+), 75 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a632b71ce..777ede9ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,7 +178,6 @@ cmake_dependent_option(G100 "Matrox Productiva G100" cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF) -cmake_dependent_option(OPEN_AT "OpenAT" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPL4ML "OPL4-ML daughterboard" ON "DEV_BRANCH" OFF) cmake_dependent_option(PCL "Generic PCL5e Printer" ON "DEV_BRANCH" OFF) cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index d6725ec9a..98667f244 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -448,9 +448,6 @@ extern int machine_at_pb286_init(const machine_t *); extern int machine_at_siemens_init(const machine_t *); // Siemens PCD-2L. N82330 discrete machine. It segfaults in some places extern int machine_at_wellamerastar_init(const machine_t *); // Wells American A*Star with custom award BIOS -#ifdef USE_OPEN_AT -extern int machine_at_openat_init(const machine_t *); -#endif /* USE_OPEN_AT */ /* m_at_286_386sx.c */ extern int machine_at_tg286m_init(const machine_t *); diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 2e3bc02bc..8cd54edec 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -56,7 +56,3 @@ add_library(mch OBJECT m_at_socket370.c m_at_misc.c ) - -if(OPEN_AT) - target_compile_definitions(mch PRIVATE USE_OPEN_AT) -endif() diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 86fbe3776..13cd831ba 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -388,21 +388,3 @@ machine_at_wellamerastar_init(const machine_t *model) return ret; } - -#ifdef USE_OPEN_AT -int -machine_at_openat_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear("roms/machines/openat/bios.bin", - 0x000f0000, 65536, 0); - - if (bios_only || !ret) - return ret; - - machine_at_ibm_common_init(model); - - return ret; -} -#endif /* USE_OPEN_AT */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8cdc7444b..408deb615 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8,17 +8,12 @@ * * Handling of the emulated machines. * - * NOTES: OpenAT wip for 286-class machine with open BIOS. - * PS2_M80-486 wip, pending receipt of TRM's for machine. - * - * - * * Authors: Miran Grca, * Fred N. van Kempen, * Jasmine Iwanek, * - * Copyright 2016-2020 Miran Grca. - * Copyright 2017-2020 Fred N. van Kempen. + * Copyright 2016-2025 Miran Grca. + * Copyright 2017-2025 Fred N. van Kempen. * Copyright 2025 Jasmine Iwanek. */ #include @@ -3136,48 +3131,6 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, -#ifdef USE_OPEN_AT - /* Has IBM AT KBC firmware. */ - { - .name = "[ISA] OpenAT", - .internal_name = "openat", - .type = MACHINE_TYPE_286, - .chipset = MACHINE_CHIPSET_DISCRETE, - .init = machine_at_openat_init, - .p1_handler = NULL, - .gpio_handler = NULL, - .available_flag = MACHINE_AVAILABLE, - .gpio_acpi_handler = NULL, - .cpu = { - .package = CPU_PKG_286, - .block = CPU_BLOCK_NONE, - .min_bus = 0, - .max_bus = 0, - .min_voltage = 0, - .max_voltage = 0, - .min_multi = 0, - .max_multi = 0 - }, - .bus_flags = MACHINE_AT, - .flags = MACHINE_FLAGS_NONE, - .ram = { - .min = 256, - .max = 15872, - .step = 128 - }, - .nvrmask = 63, - .kbc_device = NULL, - .kbc_p1 = 0xff, - .gpio = 0xffffffff, - .gpio_acpi = 0xffffffff, - .device = NULL, - .fdc_device = NULL, - .sio_device = NULL, - .vid_device = NULL, - .snd_device = NULL, - .net_device = NULL - }, -#endif /* USE_OPEN_AT */ /* Has IBM AT KBC firmware. */ { .name = "[ISA] Phoenix IBM AT", From 802355e982d1995e6fa2a0a34ad3b48c98f226ca Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 12:57:07 -0300 Subject: [PATCH 1007/1190] Add proper on-board CS4235 to delhi3 --- src/machine/machine_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 408deb615..780f8d474 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -4456,7 +4456,7 @@ const machine_t machines[] = { .net_device = NULL }, { - .name = "[ALI M1409] Acer 100T", + .name = "[ALi M1409] Acer 100T", .internal_name = "acer100t", .type = MACHINE_TYPE_386SX, .chipset = MACHINE_CHIPSET_ALI_M1409, @@ -14420,7 +14420,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = &cs4235_device, + .snd_device = &cs4235_onboard_device, .net_device = NULL }, From d3cc0df2bb5f99f7f6862840aab13f3e5484fa29 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 13:20:34 -0300 Subject: [PATCH 1008/1190] CS423x: Remove delhi3 PnP disable command hack as it's no longer required (there's a clean nvr issue elsewhere) --- src/sound/snd_cs423x.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 17ea48dd3..74382a53b 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -650,15 +650,7 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig) isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], dev->pnp_size); /* Disable PnP key if the PKD bit is set, or if it was disabled by command 0x55. */ - /* But wait! The TriGem Delhi-III BIOS sends command 0x55, and its behavior doesn't - line up with real hardware (still listed in the POST summary and seen by software). - Disable the PnP key disabling mechanism until someone figures something out. */ -#if 0 isapnp_enable_card(dev->pnp_card, ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) ? ISAPNP_CARD_NO_KEY : ISAPNP_CARD_ENABLE); -#else - if ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable) - pclog("CS423x: Attempted to disable PnP key\n"); -#endif } /* Update some register bits based on the config data in RAM if requested. */ From 9ebcc443508eede6fd572379f49e2f3c627ae13b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 28 May 2025 19:41:27 +0200 Subject: [PATCH 1009/1190] Add the Dell System 333s/L. --- src/chipset/scamp.c | 2 +- src/device/kbc_at.c | 13 +++++-- src/device/postcard.c | 8 +++-- src/include/86box/machine.h | 1 + src/include/86box/video.h | 1 + src/machine/m_at_286_386sx.c | 70 ++++++++++++++++++++++++++++++++++++ src/machine/machine_table.c | 42 ++++++++++++++++++++++ src/sio/sio_detect.c | 7 ++-- src/video/vid_cl54xx.c | 19 +++++++++- 9 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c index 8e7892c2e..855175dcd 100644 --- a/src/chipset/scamp.c +++ b/src/chipset/scamp.c @@ -1177,7 +1177,7 @@ scamp_init(UNUSED(const device_t *info)) dev->mem_flags[i] = MEM_FLAG_READ | MEM_FLAG_WRITE; scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_RW); - if (i >= 60) + if (i >= 56) scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS); } } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 8840a0e4d..dd2d5a636 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -1079,7 +1079,14 @@ write_cmd_generic(void *priv, uint8_t val) /* The SMM handlers of Intel AMI Pentium BIOS'es expect bit 6 to be set. */ if ((kbc_ven == KBC_VEN_AMI) && ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_GREEN)) fixed_bits |= 0x40; - if (kbc_ven == KBC_VEN_IBM_PS1) { + if (!strcmp(machine_get_internal_name(), "dells333sl")) { + /* + Dell System 333s/L: + - Bit 5: Stuck in reboot loop if clear. + */ + uint8_t p1 = 0x20 | (video_is_mda() ? 0x40 : 0x00); + kbc_delay_to_ob(dev, p1, 0, 0x00); + } else if (kbc_ven == KBC_VEN_IBM_PS1) { current_drive = fdc_get_current_drive(); /* (B0 or F0) | (fdd_is_525(current_drive) on bit 6) */ kbc_delay_to_ob(dev, dev->p1 | fixed_bits | (fdd_is_525(current_drive) ? 0x40 : 0x00), @@ -1114,7 +1121,7 @@ write_cmd_generic(void *priv, uint8_t val) Dell 466/NP: - Bit 2: Keyboard fuse (must be set); - Bit 4: Password disable jumper (must be clear); - - Bit 5: Manufacturing jumper (must be set); + - Bit 5: Manufacturing jumper (must be set). */ uint8_t p1 = 0x24; kbc_delay_to_ob(dev, p1, 0, 0x00); @@ -1123,7 +1130,7 @@ write_cmd_generic(void *priv, uint8_t val) Dell OptiPlex GXL/GXM: - Bit 3: Password disable jumper (must be clear); - Bit 4: Keyboard fuse (must be set); - - Bit 5: Manufacturing jumper (must be set); + - Bit 5: Manufacturing jumper (must be set). */ uint8_t p1 = 0x30; kbc_delay_to_ob(dev, p1, 0, 0x00); diff --git a/src/device/postcard.c b/src/device/postcard.c index 19d81b692..27f5a5aa3 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -100,7 +100,8 @@ postcard_setui(void) break; } } else if (strstr(machines[machine].name, " Dell ") && - (machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX)) { + ((machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX) || + (machine_get_chipset(machine) >= MACHINE_CHIPSET_VLSI_SCAMP))) { char dell_diags[10] = { 0 }; if (!postcard_written[1]) @@ -225,8 +226,9 @@ postcard_init(UNUSED(const device_t *info)) NULL, NULL, NULL, postcard_write, NULL, NULL, NULL); if (strstr(machines[machine].name, " Dell ") && - (machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX)) - io_sethandler(0x00e0, 0x0001, + ((machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX) || + (machine_get_chipset(machine) >= MACHINE_CHIPSET_VLSI_SCAMP))) + io_sethandler(is486 ? 0x00e0 : 0x00e4, 0x0001, NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL); return postcard_write; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 98667f244..d4d5e8618 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -485,6 +485,7 @@ extern int machine_at_adi386sx_init(const machine_t *); extern int machine_at_cmdsl386sx16_init(const machine_t *); extern int machine_at_cmdsl386sx25_init(const machine_t *); extern int machine_at_dataexpert386sx_init(const machine_t *); +extern int machine_at_dells333sl_init(const machine_t *); extern int machine_at_if386sx_init(const machine_t *); extern int machine_at_spc6033p_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 6a73c6462..bd3101d84 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -356,6 +356,7 @@ extern const device_t gd5401_isa_device; extern const device_t gd5402_isa_device; extern const device_t gd5402_onboard_device; extern const device_t gd5420_isa_device; +extern const device_t gd5420_onboard_device; extern const device_t gd5422_isa_device; extern const device_t gd5424_vlb_device; extern const device_t gd5426_isa_device; diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 853829ccc..6ac5b0195 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -37,6 +37,7 @@ #include <86box/hdc.h> #include <86box/nvr.h> #include <86box/port_6x.h> +#define USE_SIO_DETECT #include <86box/sio.h> #include <86box/serial.h> #include <86box/video.h> @@ -760,6 +761,75 @@ machine_at_cmdsl386sx25_init(const machine_t *model) return ret; } +static const device_config_t dells333sl_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "dells333sl", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "J01 (Jostens Learning Corporation OEM)", .internal_name = "dells333sl_j01", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/dells333sl/DELL386.BIN", "" } }, + { .name = "A02", .internal_name = "dells333sl", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/dells333sl/Dell_386SX_30807_UBIOS_B400_VLSI_VL82C311_Cirrus_Logic_GD5420.bin", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t dells333sl_device = { + .name = "Dell System 333s/L", + .internal_name = "dells333sl_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = dells333sl_config +}; + +int +machine_at_dells333sl_init(const machine_t *model) +{ + int ret = 0; + const char* fn; + + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 262144, 0); + memcpy(rom, &(rom[0x00020000]), 131072); + mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000); + mem_mapping_set_exec(&bios_mapping, rom); + device_context_restore(); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + machine_at_common_init_ex(model, 2); + + device_add(&ide_isa_device); + + device_add(&pc87311_device); + device_add(&vl82c113_device); /* The keyboard controller is part of the VL82c113. */ + + device_add(&vlsi_scamp_device); + + return ret; +} + int machine_at_dataexpert386sx_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 408deb615..e18581082 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -66,6 +66,7 @@ extern const device_t vendex_device; extern const device_t c5sbm2_device; extern const device_t sb486pv_device; extern const device_t ap5s_device; +extern const device_t dells333sl_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -4942,6 +4943,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC + firmware. */ + { + .name = "[SCAMP] Dell System 333s/L", + .internal_name = "dells333sl", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_VLSI_SCAMP, + .init = machine_at_dells333sl_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 10000000, + .max_bus = 33333333, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &dells333sl_device, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5420_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* Has IBM PS/2 Type 1 KBC firmware. */ { .name = "[SCAMP] Samsung SPC-6033P", diff --git a/src/sio/sio_detect.c b/src/sio/sio_detect.c index ffa0ec9d0..d36522fe0 100644 --- a/src/sio/sio_detect.c +++ b/src/sio/sio_detect.c @@ -47,11 +47,12 @@ sio_detect_write(uint16_t port, uint8_t val, void *priv) static uint8_t sio_detect_read(uint16_t port, void *priv) { - const sio_detect_t *dev = (sio_detect_t *) priv; + /*const sio_detect_t *dev = (sio_detect_t *) priv*/; + uint8_t ret = 0xff /*dev->regs[port & 1]*/; - pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]); + pclog("sio_detect_read : port=%04x = %02X\n", port, ret); - return 0xff /*dev->regs[port & 1]*/; + return ret; } static void diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 13f96501c..0d02c10c3 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4247,7 +4247,10 @@ gd54xx_init(const device_t *info) break; case CIRRUS_ID_CLGD5420: - romfn = BIOS_GD5420_PATH; + if (info->local & 0x200) + romfn = NULL; + else + romfn = BIOS_GD5420_PATH; break; case CIRRUS_ID_CLGD5422: @@ -4978,6 +4981,20 @@ const device_t gd5420_isa_device = { .config = gd542x_config, }; +const device_t gd5420_onboard_device = { + .name = "Cirrus Logic GD5420 (ISA)", + .internal_name = "cl_gd5420_isa", + .flags = DEVICE_ISA16, + .local = CIRRUS_ID_CLGD5420 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + .available = NULL, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config, +}; + const device_t gd5422_isa_device = { .name = "Cirrus Logic GD5422 (ISA)", .internal_name = "cl_gd5422_isa", From 30324bb859a60e76fec7cebfcb7af302674391bd Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 15:13:52 -0300 Subject: [PATCH 1010/1190] Add internal PCI flag to STPC SBCs without PCI slots --- src/machine/machine_table.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 780f8d474..52c483ff5 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -9422,7 +9422,7 @@ const machine_t machines[] = { .max_multi = 2.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, /* Machine has internal video: ST STPC Atlas */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_PCI_INTERNAL, /* Machine has internal video: ST STPC Atlas */ .ram = { .min = 32768, .max = 163840, @@ -9463,7 +9463,7 @@ const machine_t machines[] = { .max_multi = 2.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, /* Machine has internal video: ST STPC Atlas */ + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_PCI_INTERNAL | MACHINE_USB, /* Machine has internal video: ST STPC Atlas */ .ram = { .min = 32768, .max = 163840, @@ -9504,7 +9504,7 @@ const machine_t machines[] = { .max_multi = 2.0 }, .bus_flags = MACHINE_PS2, - .flags = MACHINE_IDE | MACHINE_APM, /* Machine has internal video: ST STPC Atlas and NIC: Realtek RTL8139C+ */ + .flags = MACHINE_IDE | MACHINE_APM | MACHINE_PCI_INTERNAL, /* Machine has internal video: ST STPC Atlas and NIC: Realtek RTL8139C+ */ .ram = { .min = 32768, .max = 131072, @@ -9545,7 +9545,7 @@ const machine_t machines[] = { .max_multi = 2.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_PCI_INTERNAL, .ram = { .min = 32768, .max = 98304, @@ -9586,7 +9586,7 @@ const machine_t machines[] = { .max_multi = 2.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_APM, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_PCI_INTERNAL, .ram = { .min = 32768, .max = 131072, From 81af1f8195361cf8b7bcc5a8813076dda9f9d7f0 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 15:35:43 -0300 Subject: [PATCH 1011/1190] De-underscore the ASUS 386/33-64K --- src/include/86box/machine.h | 2 +- src/machine/m_at_386dx_486.c | 4 ++-- src/machine/machine_table.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 98667f244..53b47c4c1 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -512,7 +512,7 @@ extern int machine_at_ga486l_init(const machine_t *); extern int machine_at_cougar_init(const machine_t *); extern int machine_at_acc386_init(const machine_t *); -extern int machine_at_asus386_3364k_init(const machine_t *); +extern int machine_at_asus3863364k_init(const machine_t *); extern int machine_at_asus386_init(const machine_t *); extern int machine_at_ecs386_init(const machine_t *); extern int machine_at_spc6000a_init(const machine_t *); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 9f7534244..b81a6bda7 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -73,11 +73,11 @@ machine_at_acc386_init(const machine_t *model) } int -machine_at_asus386_3364k_init(const machine_t *model) +machine_at_asus3863364k_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/asus386_3364k/am27c512dip28-64b53c26be3d8160533563.bin", + ret = bios_load_linear("roms/machines/asus3863364k/am27c512dip28-64b53c26be3d8160533563.bin", 0x000f0000, 65536, 0); if (bios_only || !ret) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 52c483ff5..63d19c8c6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5671,10 +5671,10 @@ const machine_t machines[] = { /* Has Award KBC firmware. */ { .name = "[SiS 310] ASUS 386/33-64K", - .internal_name = "asus386_3364k", + .internal_name = "asus3863364k", .type = MACHINE_TYPE_386DX, .chipset = MACHINE_CHIPSET_SIS_310, - .init = machine_at_asus386_3364k_init, + .init = machine_at_asus3863364k_init, .p1_handler = NULL, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, From 4a3eb800828e2ce176cc446be97563f84ea4556c Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 15:36:53 -0300 Subject: [PATCH 1012/1190] De-underscore the Dell OptiPlex machines --- src/include/86box/machine.h | 6 +++--- src/machine/m_at_slot1.c | 4 ++-- src/machine/m_at_socket5.c | 4 ++-- src/machine/m_at_socket7.c | 4 ++-- src/machine/machine_table.c | 12 ++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 53b47c4c1..155e6aecc 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -670,7 +670,7 @@ extern int machine_at_tek932_init(const machine_t *); extern int machine_at_acerv30_init(const machine_t *); extern int machine_at_apollo_init(const machine_t *); -extern int machine_at_optiplex_gxl_init(const machine_t *); +extern int machine_at_optiplexgxl_init(const machine_t *); extern int machine_at_zappa_init(const machine_t *); extern int machine_at_powermatev_init(const machine_t *); extern int machine_at_hawk_init(const machine_t *); @@ -750,7 +750,7 @@ extern int machine_at_gw2kte_init(const machine_t *); extern int machine_at_ma23c_init(const machine_t *); extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); -extern int machine_at_optiplex_gn_init(const machine_t *); +extern int machine_at_optiplexgn_init(const machine_t *); extern int machine_at_ym430tx_init(const machine_t *); extern int machine_at_thunderbolt_init(const machine_t *); extern int machine_at_an430tx_init(const machine_t *); @@ -819,7 +819,7 @@ extern int machine_at_p65up5_cpknd_init(const machine_t *); extern int machine_at_kn97_init(const machine_t *); extern int machine_at_lx6_init(const machine_t *); -extern int machine_at_optiplex_gxa_init(const machine_t *); +extern int machine_at_optiplexgxa_init(const machine_t *); extern int machine_at_spitfire_init(const machine_t *); extern int machine_at_ma30d_init(const machine_t *); diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index a147d0e13..280462858 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -151,11 +151,11 @@ machine_at_lx6_init(const machine_t *model) } int -machine_at_optiplex_gxa_init(const machine_t *model) +machine_at_optiplexgxa_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/optiplex_gxa/DELL.ROM", + ret = bios_load_linear("roms/machines/optiplexgxa/DELL.ROM", 0x000c0000, 262144, 0); if (bios_only || !ret) diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 442281811..0d50fead8 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -238,11 +238,11 @@ machine_at_apollo_init(const machine_t *model) } int -machine_at_optiplex_gxl_init(const machine_t *model) +machine_at_optiplexgxl_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/optiplex_gxl/DELL.ROM", + ret = bios_load_linear("roms/machines/optiplexgxl/DELL.ROM", 0x000e0000, 131072, 0); if (bios_only || !ret) diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index d4b71f92f..dbc59ef17 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -970,11 +970,11 @@ machine_at_tx97_init(const machine_t *model) } int -machine_at_optiplex_gn_init(const machine_t *model) +machine_at_optiplexgn_init(const machine_t *model) { int ret; - ret = bios_load_linear("roms/machines/optiplex_gn/DELL.ROM", + ret = bios_load_linear("roms/machines/optiplexgn/DELL.ROM", 0x000c0000, 262144, 0); if (bios_only || !ret) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 63d19c8c6..4c6d90cea 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -10549,10 +10549,10 @@ const machine_t machines[] = { /* Has a National Semiconductor PC87332VLJ Super I/O with AMIKey 'F' KBC firmware. */ { .name = "[i430FX] Dell OptiPlex GXL/GXM", - .internal_name = "optiplex_gxl", + .internal_name = "optiplexgxl", .type = MACHINE_TYPE_SOCKET5, .chipset = MACHINE_CHIPSET_INTEL_430FX, - .init = machine_at_optiplex_gxl_init, + .init = machine_at_optiplexgxl_init, .p1_handler = NULL, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, @@ -13147,10 +13147,10 @@ const machine_t machines[] = { */ { .name = "[i430TX] Dell OptiPlex GN+", - .internal_name = "optiplex_gn", + .internal_name = "optiplexgn", .type = MACHINE_TYPE_SOCKET7, .chipset = MACHINE_CHIPSET_INTEL_430TX, - .init = machine_at_optiplex_gn_init, + .init = machine_at_optiplexgn_init, .p1_handler = NULL, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, @@ -15210,10 +15210,10 @@ const machine_t machines[] = { firmwares: AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix MultiKey/42i 4.16. */ { .name = "[i440LX] Dell OptiPlex GXa", - .internal_name = "optiplex_gxa", + .internal_name = "optiplexgxa", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_INTEL_440LX, - .init = machine_at_optiplex_gxa_init, + .init = machine_at_optiplexgxa_init, .p1_handler = NULL, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, From 72a52318f56e274d6f66553d1a872604d07bed20 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 16:08:44 -0300 Subject: [PATCH 1013/1190] POST card: Streamline printing of the Dell ASCII mode --- src/device/postcard.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/src/device/postcard.c b/src/device/postcard.c index 27f5a5aa3..ec031c2b8 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -36,6 +36,7 @@ static uint16_t postcard_port; static uint8_t postcard_written[POSTCARDS_NUM]; static uint8_t postcard_ports_num = 1; static uint8_t postcard_prev_codes[POSTCARDS_NUM]; +static uint8_t postcard_dell_mode = 0; static char postcard_prev_diags[5] = { 0 }; #define UISTR_LEN 32 static char postcard_str[UISTR_LEN]; /* UI output string */ @@ -99,31 +100,23 @@ postcard_setui(void) ps[1][0], ps[1][1], ps[1][2], ps[1][3]); break; } - } else if (strstr(machines[machine].name, " Dell ") && - ((machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX) || - (machine_get_chipset(machine) >= MACHINE_CHIPSET_VLSI_SCAMP))) { - char dell_diags[10] = { 0 }; - - if (!postcard_written[1]) - snprintf(dell_diags, sizeof(dell_diags), "---- ----"); - else if (postcard_written[1] == 1) - snprintf(dell_diags, sizeof(dell_diags), "%s ----", postcard_diags); - else - snprintf(dell_diags, sizeof(dell_diags), "%s %s", postcard_diags, postcard_prev_diags); - - if (!postcard_written[0]) - snprintf(postcard_str, sizeof(postcard_str), "POST: -- -- %s", dell_diags); - else if (postcard_written[0] == 1) - snprintf(postcard_str, sizeof(postcard_str), "POST: %02X -- %s", postcard_codes[0], dell_diags); - else - snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X %s", postcard_codes[0], postcard_prev_codes[0], dell_diags); } else { + char dell_diags[11] = { 0 }; + if (postcard_dell_mode) { + if (!postcard_written[1]) + snprintf(dell_diags, sizeof(dell_diags), " ---- ----"); + else if (postcard_written[1] == 1) + snprintf(dell_diags, sizeof(dell_diags), " %s ----", postcard_diags); + else + snprintf(dell_diags, sizeof(dell_diags), " %s %s", postcard_diags, postcard_prev_diags); + } + if (!postcard_written[0]) - snprintf(postcard_str, sizeof(postcard_str), "POST: -- --"); + snprintf(postcard_str, sizeof(postcard_str), "POST: -- --%s", dell_diags); else if (postcard_written[0] == 1) - snprintf(postcard_str, sizeof(postcard_str), "POST: %02X --", postcard_codes[0]); + snprintf(postcard_str, sizeof(postcard_str), "POST: %02X --%s", postcard_codes[0], dell_diags); else - snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X", postcard_codes[0], postcard_prev_codes[0]); + snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X%s", postcard_codes[0], postcard_prev_codes[0], dell_diags); } ui_sb_bugui(postcard_str); @@ -225,9 +218,9 @@ postcard_init(UNUSED(const device_t *info)) io_sethandler(postcard_port, postcard_ports_num, NULL, NULL, NULL, postcard_write, NULL, NULL, NULL); - if (strstr(machines[machine].name, " Dell ") && - ((machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX) || - (machine_get_chipset(machine) >= MACHINE_CHIPSET_VLSI_SCAMP))) + postcard_dell_mode = strstr(machines[machine].name, " Dell ") && + (machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX); + if (postcard_dell_mode) io_sethandler(is486 ? 0x00e0 : 0x00e4, 0x0001, NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL); From 2b71002daba7a02480507f480815d01cb8c05aba Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 28 May 2025 16:35:38 -0300 Subject: [PATCH 1014/1190] PCI: Fix and delegate bridge initialization on Dell riser machines --- src/device/pci_bridge.c | 45 +++++++++++++++++++------------------ src/include/86box/machine.h | 2 ++ src/include/86box/pci.h | 1 + src/machine/m_at_slot1.c | 4 ++-- src/machine/m_at_socket7.c | 13 +++++++++-- src/pci.c | 4 ++-- 6 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/device/pci_bridge.c b/src/device/pci_bridge.c index 8893acf69..bf49baf14 100644 --- a/src/device/pci_bridge.c +++ b/src/device/pci_bridge.c @@ -87,6 +87,14 @@ pci_bridge_set_ctl(void *priv, uint8_t ctl) dev->ctl = ctl; } +uint8_t +pci_bridge_get_bus_index(void *priv) +{ + pci_bridge_t *dev = (pci_bridge_t *) priv; + + return dev->bus_index; +} + static void pci_bridge_write(int func, int addr, uint8_t val, void *priv) { @@ -513,11 +521,9 @@ static void * pci_bridge_init(const device_t *info) { uint8_t interrupts[4]; - uint8_t interrupt_count; uint8_t interrupt_mask; + uint8_t add_type; uint8_t slot_count; - uint8_t dell_slots[3] = { 0x09, 0x0a, 0x0b }; - uint8_t dell_interrupts[3][4] = { { 1, 2, 3, 4 }, { 4, 2, 1, 3 }, { 1, 3, 4, 2 } }; pci_bridge_t *dev = (pci_bridge_t *) calloc(1, sizeof(pci_bridge_t)); @@ -527,40 +533,35 @@ pci_bridge_init(const device_t *info) pci_bridge_reset(dev); - if (info->local == PCI_BRIDGE_DEC_21152) - pci_add_card(PCI_ADD_BRIDGE, pci_bridge_read, pci_bridge_write, dev, &dev->slot); - else - pci_add_bridge(AGP_BRIDGE(dev->local), pci_bridge_read, pci_bridge_write, dev, &dev->slot); - - interrupt_count = sizeof(interrupts); - interrupt_mask = interrupt_count - 1; + interrupt_mask = sizeof(interrupts) - 1; if (dev->slot < 32) { - for (uint8_t i = 0; i < interrupt_count; i++) + for (uint8_t i = 0; i <= interrupt_mask; i++) interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i); } pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n", dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0], interrupts[1], interrupts[2], interrupts[3]); - if (info->local == PCI_BRIDGE_DEC_21150) + if (info->local == PCI_BRIDGE_DEC_21150) { slot_count = 9; /* 9 bus masters */ - else if (info->local == PCI_BRIDGE_DEC_21152) - slot_count = 3; /* 3 bus masters */ - else + add_type = PCI_ADD_NORMAL; + } else if (info->local == PCI_BRIDGE_DEC_21152) { + slot_count = 0; /* 4 bus masters, but slots are added by the Dell machines */ + add_type = PCI_ADD_BRIDGE; + } else { slot_count = 1; /* AGP bridges always have 1 slot */ + add_type = PCI_ADD_AGPBRIDGE; + } + + pci_add_bridge(add_type, pci_bridge_read, pci_bridge_write, dev, &dev->slot); for (uint8_t i = 0; i < slot_count; i++) { - uint8_t slot = i; - if (info->local == PCI_BRIDGE_DEC_21152) { - slot = dell_slots[i]; - memcpy(interrupts, dell_interrupts[i], 4); - } /* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */ pci_bridge_log("PCI Bridge %d: downstream slot %02X interrupts %02X %02X %02X %02X\n", - dev->bus_index, slot, interrupts[i & interrupt_mask], + dev->bus_index, i, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], interrupts[(i + 3) & interrupt_mask]); - pci_register_bus_slot(dev->bus_index, slot, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, + pci_register_bus_slot(dev->bus_index, i, AGP_BRIDGE(dev->local) ? PCI_CARD_AGP : PCI_CARD_NORMAL, interrupts[i & interrupt_mask], interrupts[(i + 1) & interrupt_mask], interrupts[(i + 2) & interrupt_mask], diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 4129cead7..3231acd80 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -722,6 +722,8 @@ extern int machine_at_vectra54_init(const machine_t *); extern int machine_at_5sbm2_init(const machine_t *); /* m_at_socket7.c */ +extern void machine_at_optiplex_21152_init(void); + extern int machine_at_acerv35n_init(const machine_t *); extern int machine_at_p55t2p4_init(const machine_t *); extern int machine_at_m7shi_init(const machine_t *); diff --git a/src/include/86box/pci.h b/src/include/86box/pci.h index 462b4f821..8887f89f4 100644 --- a/src/include/86box/pci.h +++ b/src/include/86box/pci.h @@ -283,6 +283,7 @@ extern void pci_init(int flags); /* PCI bridge stuff. */ extern void pci_bridge_set_ctl(void *priv, uint8_t ctl); +extern uint8_t pci_bridge_get_bus_index(void *priv); #ifdef EMU_DEVICE_H extern const device_t dec21150_device; diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 280462858..2ac805bee 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -170,14 +170,14 @@ machine_at_optiplexgxa_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1); pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0F, PCI_CARD_BRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_BRIDGE, 0, 0, 0, 0); if (sound_card_current[0] == SOUND_INTERNAL) device_add(machine_get_snd_device(machine)); device_add(&i440lx_device); device_add(&piix4_device); - device_add(&dec21152_device); + machine_at_optiplex_21152_init(); device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index dbc59ef17..46c7b7623 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -46,6 +46,15 @@ #include <86box/network.h> #include <86box/pci.h> +void +machine_at_optiplex_21152_init(void) +{ + uint8_t bus_index = pci_bridge_get_bus_index(device_add(&dec21152_device)); + pci_register_bus_slot(bus_index, 0x09, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_bus_slot(bus_index, 0x0a, PCI_CARD_NORMAL, 4, 2, 1, 3); + pci_register_bus_slot(bus_index, 0x0b, PCI_CARD_NORMAL, 1, 3, 4, 2); +} + int machine_at_acerv35n_init(const machine_t *model) { @@ -989,7 +998,7 @@ machine_at_optiplexgn_init(const machine_t *model) pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */ pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */ pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); - pci_register_slot(0x0F, PCI_CARD_BRIDGE, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_BRIDGE, 0, 0, 0, 0); if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); @@ -999,7 +1008,7 @@ machine_at_optiplexgn_init(const machine_t *model) device_add(&i430tx_device); device_add(&piix4_device); - device_add(&dec21152_device); + machine_at_optiplex_21152_init(); device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x3, 128); diff --git a/src/pci.c b/src/pci.c index c3020ca73..94ab9d5f2 100644 --- a/src/pci.c +++ b/src/pci.c @@ -855,10 +855,10 @@ pci_register_card(int pci_card) /* Add an instance of the PCI bridge. */ void -pci_add_bridge(uint8_t agp, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot) +pci_add_bridge(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot) { pci_card_t *card; - uint8_t bridge_slot = agp ? pci_find_slot(PCI_ADD_AGPBRIDGE, 0xff) : last_normal_pci_card_id; + uint8_t bridge_slot = (add_type == PCI_ADD_NORMAL) ? last_normal_pci_card_id : pci_find_slot(add_type, 0xff); if (bridge_slot != PCI_CARD_INVALID) { card = &pci_cards[bridge_slot]; From 25f0a26ea1f786b299ad3e8bd79ee831e322f5ba Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 29 May 2025 09:45:49 +0200 Subject: [PATCH 1015/1190] Vastly improve the ALi M1409 emulation (all of shadow RAM now work, as does bus speed and external cache setting), and fix the "Writing unimplemented Cyrix register FF" error as well. --- src/chipset/ali1409.c | 272 ++++++++++++++++++++++++++++++++---------- src/cpu/cpu.c | 2 +- 2 files changed, 210 insertions(+), 64 deletions(-) diff --git a/src/chipset/ali1409.c b/src/chipset/ali1409.c index 5009a6505..619843cda 100644 --- a/src/chipset/ali1409.c +++ b/src/chipset/ali1409.c @@ -61,91 +61,238 @@ ali1409_log(const char *fmt, ...) #endif typedef struct ali_1409_t { - uint8_t is_g; uint8_t index; uint8_t cfg_locked; - uint8_t reg_57h; uint8_t regs[256]; + uint8_t shadow[4]; uint8_t last_reg; } ali1409_t; +/* + This here is because from the two BIOS'es I used to reverse engineer this, + it is unclear which of the two interpretations of the shadow RAM register + operation is correct. + The 16 kB interpretation appears to work fine right now but it may be wrong, + so I left the 32 kB interpretation in as well. + */ +#ifdef INTERPRETATION_32KB +#define SHADOW_SIZE 0x00008000 +#else +#define SHADOW_SIZE 0x00004000 +#endif + +static void +ali1409_shadow_recalc(ali1409_t *dev) +{ + uint32_t base = 0x000c0000; + + for (uint8_t i = 0; i < 4; i++) { + uint8_t reg = 0x08 + i; + +#ifdef INTERPRETATION_32KB + for (uint8_t j = 0; j < 4; j += 2) { + uint8_t mask = (0x03 << j); +#else + for (uint8_t j = 0; j < 4; j++) { + uint8_t mask = (0x01 << j); +#endif + uint8_t r_on = dev->regs[reg] & 0x10; + uint8_t w_on = dev->regs[reg] & 0x20; + uint8_t val = dev->regs[reg] & mask; + uint8_t xor = (dev->shadow[i] ^ dev->regs[reg]) & (mask | 0x30); + int read = r_on ? MEM_READ_INTERNAL : MEM_READ_EXTANY; + int write = w_on ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY; + + if (xor) { +#ifdef INTERPRETATION_32KB + switch (val >> j) { + case 0x00: + mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 0x01: + mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | write); + break; + case 0x02: + mem_set_mem_state_both(base, SHADOW_SIZE, read | write); + break; + case 0x03: + mem_set_mem_state_both(base, SHADOW_SIZE, read | MEM_WRITE_EXTANY); + break; + } +#else + switch (val >> j) { + case 0x00: + mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 0x01: + mem_set_mem_state_both(base, SHADOW_SIZE, read | write); + break; + } +#endif + } + + base += SHADOW_SIZE; + } + + dev->shadow[i] = dev->regs[reg]; + } + + flushmmucache_nopc(); +} static void ali1409_write(uint16_t addr, uint8_t val, void *priv) { ali1409_t *dev = (ali1409_t *) priv; - ali1409_log ("INPUT:addr %02x ,Value %02x \n" , addr , val); + ali1409_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val); - if (addr & 1) { - if (dev->cfg_locked) { - if (dev->last_reg == 0x14 && val == 0x09) - dev->cfg_locked = 0; + if (addr & 0x0001) { + if (dev->cfg_locked) { + if ((dev->last_reg == 0x14) && (val == 0x09)) + dev->cfg_locked = 0; - dev->last_reg = val; - return; - } + dev->last_reg = val; + return; + } - if (dev->index == 0xff && val == 0xff) - dev->cfg_locked = 1; - else { - ali1409_log("Write reg %02x %02x %08x\n", dev->index, val, cs); - dev->regs[dev->index] = val; + /* It appears writing anything at all to register 0xFF locks it again. */ + if (dev->index == 0xff) + dev->cfg_locked = 1; + else if (dev->index < 0x44) { + ali1409_log("[%04X:%08X] [W] Register %02X = %02X\n", CS, cpu_state.pc, dev->index, val); - switch (dev->index) { - case 0xa: - switch ((val >> 4) & 3) { - case 0: - mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } + if (dev->index < 0x10) { + dev->regs[dev->index] = val; + + /* + There are still a lot of unknown here, but unfortunately, this is + as far as I have been able to come with two BIOS'es that are + available (the Acer 100T and an AMI Color dated 07/07/91). + */ + switch (dev->index) { + case 0x02: + /* + - Bit 7: The RAS address hold time: + - 0: 1/2 T; + - 1: 1 T. + - Bits 6-4: The RAS precharge time: + - 0, 0, 0: 1.5 T; + - 0, 0, 1: 2 T; + - 0, 1, 0: 2.5 T; + - 0, 1, 1: 3 T; + - 1, 0, 0: 3.5 T; + - 1, 0, 1: 4 T; + - 1, 1, 0: Reserved; + - 1, 1, 1: Reserved. + - Bit 3: Early miss cycle: + - 0: Disabled; + - 1: Enabled. + */ + break; + case 0x03: + /* + - Bit 6: CAS pulse for read cycle: + - 0: 1 T; + - 1: 1.5 T or 2 T. + I can not get the 2.5 T or 3 T setting to apply so + I have no idea what bit governs that. + - Bits 5, 4: CAS pulse for write cycle: + - 0, 0: 0.5 T or 1 T; + - 0, 1: 1.5 T or 2 T; + - 1, 0: 2.5 T or 3 T; + - 1, 1: Reserved. + - Bit 3: CAS active for read cycle: + - 0: Disabled; + - 1: Enabled. + - Bit 2: CAS active for write cycle: + - 0: Disabled; + - 1: Enabled. + */ + break; + case 0x06: + /* + - Bits 6-4: Clock divider: + - 0, 0, 0: / 2; + - 0, 0, 1: / 4; + - 0, 1, 0: / 8; + - 0, 1, 1: Reserved; + - 1, 0, 0: / 3; + - 1, 0, 1: / 6; + - 1, 1, 0: / 5; + - 1, 1, 1: / 10. + */ + switch ((val >> 4) & 7) { + default: + case 3: /* Reserved */ + cpu_set_isa_speed(7159091); break; - case 0xb: - switch ((val >> 4) & 3) { - case 0: - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); - break; - case 1: - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); - break; - case 2: - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY| MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } + + case 0: + cpu_set_isa_speed(cpu_busspeed / 2); + break; + + case 1: + cpu_set_isa_speed(cpu_busspeed / 4); + break; + + case 2: + cpu_set_isa_speed(cpu_busspeed / 8); + break; + + case 4: + cpu_set_isa_speed(cpu_busspeed / 3); + break; + + case 5: + cpu_set_isa_speed(cpu_busspeed / 6); + break; + + case 6: + cpu_set_isa_speed(cpu_busspeed / 5); + break; + + case 7: + cpu_set_isa_speed(cpu_busspeed / 10); break; } + break; + case 0x08 ... 0x0b: + ali1409_shadow_recalc(dev); + break; + case 0x0c: + /* + This appears to be turbo in bit 4 (1 = on, 0 = off), + and bus speed in the rest of the bits. + */ + break; + case 0x0d: + cpu_cache_ext_enabled = !!(val & 0x08); + cpu_update_waitstates(); + break; } - } else - dev->index = val; + } + } + } else + dev->index = val; } static uint8_t ali1409_read(uint16_t addr, void *priv) { - ali1409_log ("reading at %02X\n",addr); const ali1409_t *dev = (ali1409_t *) priv; uint8_t ret = 0xff; if (dev->cfg_locked) ret = 0xff; - if (addr & 1) { - if ((dev->index >= 0xc0 || dev->index == 0x20) && cpu_iscyrix) - ret = 0xff; + else if (addr & 0x0001) { + if (dev->index < 0x44) ret = dev->regs[dev->index]; - } else - ret = dev->index; + } else + ret = dev->index; + + ali1409_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -166,17 +313,16 @@ ali1409_init(UNUSED(const device_t *info)) dev->cfg_locked = 1; - /* M1409 Ports: - 22h Index Port - 23h Data Port - */ - - ali1409_log ("Bus speed: %i", cpu_busspeed); - + ali1409_log("Bus speed: %i\n", cpu_busspeed); io_sethandler(0x0022, 0x0002, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev); - io_sethandler(0x037f, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev); - io_sethandler(0x03f3, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev); + + dev->regs[0x0f] = 0x08; + + cpu_set_isa_speed(7159091); + + cpu_cache_ext_enabled = 0; + cpu_update_waitstates(); return dev; } diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d13dfe041..ec026d95e 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -4264,7 +4264,7 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) cyrix_addr = val; else if (addr < 0xf1) switch (cyrix_addr) { default: - if (cyrix_addr >= 0xc0) + if ((cyrix_addr >= 0xc0) && (cyrix_addr != 0xff)) fatal("Writing unimplemented Cyrix register %02X\n", cyrix_addr); break; From 168282875c991cc37e5c16f70e14a6d3f60aeb91 Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 29 May 2025 14:09:27 +0500 Subject: [PATCH 1016/1190] Fix conversion to/from VHD-compatible CHS geometry not working properly --- src/qt/qt_harddiskdialog.cpp | 67 +++++++++++++++++++++--------------- src/qt/qt_harddiskdialog.hpp | 6 ++++ 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/qt/qt_harddiskdialog.cpp b/src/qt/qt_harddiskdialog.cpp index 9e5563536..ae1c60971 100644 --- a/src/qt/qt_harddiskdialog.cpp +++ b/src/qt/qt_harddiskdialog.cpp @@ -199,7 +199,7 @@ HarddiskDialog::on_comboBoxFormat_currentIndexChanged(int index) * than a tenth of a percent change in size. */ static void -adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) +adjust_86box_geometry_for_vhd(_86BoxGeom *_86box_geometry, MVHDGeom *vhd_geometry) { if (_86box_geometry->cyl <= 65535) { vhd_geometry->cyl = _86box_geometry->cyl; @@ -226,10 +226,10 @@ adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) } static HarddiskDialog *callbackPtr = nullptr; -static MVHDGeom -create_drive_vhd_fixed(const QString &fileName, HarddiskDialog *p, uint16_t cyl, uint8_t heads, uint8_t spt) +static _86BoxGeom +create_drive_vhd_fixed(const QString &fileName, HarddiskDialog *p, uint32_t cyl, uint32_t heads, uint32_t spt) { - MVHDGeom _86box_geometry = { + _86BoxGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt @@ -256,10 +256,10 @@ create_drive_vhd_fixed(const QString &fileName, HarddiskDialog *p, uint16_t cyl, return _86box_geometry; } -static MVHDGeom -create_drive_vhd_dynamic(const QString &fileName, uint16_t cyl, uint8_t heads, uint8_t spt, int blocksize) +static _86BoxGeom +create_drive_vhd_dynamic(const QString &fileName, uint32_t cyl, uint32_t heads, uint32_t spt, int blocksize) { - MVHDGeom _86box_geometry = { + _86BoxGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt @@ -287,7 +287,7 @@ create_drive_vhd_dynamic(const QString &fileName, uint16_t cyl, uint8_t heads, u return _86box_geometry; } -static MVHDGeom +static _86BoxGeom create_drive_vhd_diff(const QString &fileName, const QString &parentFileName, int blocksize) { int vhd_error = 0; @@ -299,25 +299,31 @@ create_drive_vhd_diff(const QString &fileName, const QString &parentFileName, in options.parent_path = parentFilenameBytes.data(); options.type = MVHD_TYPE_DIFF; - MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); - MVHDGeom vhd_geometry; + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + MVHDGeom vhd_geometry; + _86BoxGeom _86box_geometry; if (vhd == NULL) { - vhd_geometry.cyl = 0; - vhd_geometry.heads = 0; - vhd_geometry.spt = 0; + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; } else { vhd_geometry = mvhd_get_geometry(vhd); if (vhd_geometry.spt > 63) { - vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); - vhd_geometry.heads = 16; - vhd_geometry.spt = 63; + _86box_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); + _86box_geometry.heads = 16; + _86box_geometry.spt = 63; + } else { + _86box_geometry.cyl = vhd_geometry.cyl; + _86box_geometry.heads = vhd_geometry.heads; + _86box_geometry.spt = vhd_geometry.spt; } + mvhd_close(vhd); } - return vhd_geometry; + return _86box_geometry; } void @@ -409,7 +415,7 @@ HarddiskDialog::onCreateNewFile() } else if (img_format >= IMG_FMT_VHD_FIXED) { /* VHD file */ file.close(); - MVHDGeom _86box_geometry {}; + _86BoxGeom _86box_geometry {}; int block_size = ui->comboBoxBlockSize->currentIndex() == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; switch (img_format) { case IMG_FMT_VHD_FIXED: @@ -493,10 +499,14 @@ HarddiskDialog::onCreateNewFile() } static void -adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) +adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry, _86BoxGeom *_86box_geometry) { - if (vhd_geometry->spt <= 63) + if (vhd_geometry->spt <= 63) { + _86box_geometry->cyl = vhd_geometry->cyl; + _86box_geometry->heads = vhd_geometry->heads; + _86box_geometry->spt = vhd_geometry->spt; return; + } int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; if (desired_sectors > 267321600) @@ -506,9 +516,9 @@ adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) if (remainder > 0) desired_sectors -= remainder; - vhd_geometry->cyl = desired_sectors / (16 * 63); - vhd_geometry->heads = 16; - vhd_geometry->spt = 63; + _86box_geometry->cyl = desired_sectors / (16 * 63); + _86box_geometry->heads = 16; + _86box_geometry->spt = 63; } void @@ -602,11 +612,12 @@ HarddiskDialog::onExistingFileSelected(const QString &fileName, bool precheck) } } - MVHDGeom vhd_geom = mvhd_get_geometry(vhd); - adjust_vhd_geometry_for_86box(&vhd_geom); - cylinders = vhd_geom.cyl; - heads = vhd_geom.heads; - sectors = vhd_geom.spt; + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + _86BoxGeom _86box_geom; + adjust_vhd_geometry_for_86box(&vhd_geom, &_86box_geom); + cylinders = _86box_geom.cyl; + heads = _86box_geom.heads; + sectors = _86box_geom.spt; size = static_cast(cylinders * heads * sectors * 512); mvhd_close(vhd); } else { diff --git a/src/qt/qt_harddiskdialog.hpp b/src/qt/qt_harddiskdialog.hpp index 9de61c51b..62ec6e963 100644 --- a/src/qt/qt_harddiskdialog.hpp +++ b/src/qt/qt_harddiskdialog.hpp @@ -64,4 +64,10 @@ private: void recalcSelection(); }; +typedef struct _86BoxGeom { + uint32_t cyl; + uint32_t heads; + uint32_t spt; +} _86BoxGeom; + #endif // QT_HARDDISKDIALOG_HPP From a690870ada032332c0816330efb2d38aa3b34264 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Thu, 29 May 2025 19:50:11 +0200 Subject: [PATCH 1017/1190] Add SNI D943 machine entry. --- src/machine/m_at_socket7_3v.c | 85 +++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 5b5724e37..ca096c6ad 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -612,6 +612,91 @@ machine_at_8500tuc_init(const machine_t *model) return ret; } +int +machine_at_d943_init(const machine_t *model) + +{ + int ret = 0; + const char* fn; + + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios_versions"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 2, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 3, 2, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_EDO, 0x7, 256); + + + if (gfxcard[0] == VID_INTERNAL) + device_add(&gd5436_onboard_pci_device); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(&sb_vibra16s_onboard_device); + + return ret; +} + +static const device_config_t d943_config[] = { + // clang-format off + { + .name = "bios_versions", + .description = "BIOS Versions", + .type = CONFIG_BIOS, + .default_string = "d943_oct96", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, /*W1*/ + .bios = { + { .name = "Version 4.05 Revision 1.02.943 (10/28/1996)", .internal_name = "d943_oct96", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_oct96.bin", "" } }, + { .name = "Version 4.05 Revision 1.03.943 (12/12/1996)", .internal_name = "d943_dec96", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_dec96.bin", "" } }, + { .name = "Version 4.05 Revision 1.05.943 (09/04/1997)", .internal_name = "d943_sept97", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_sept97.bin", "" } }, + { .name = "Version 4.05 Revision 1.06.943 (10/29/1997)", .internal_name = "d943_oct97", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_oct97.bin", "" } }, + + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + + + +const device_t d943_device = { + .name = "Siemens-Nixdorf D943", + .internal_name = "d943", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = &d943_config[0] +}; + int machine_at_p55t2s_init(const machine_t *model) { From 657dd522f4053e18a90048386fb791bf8c9df5ac Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Thu, 29 May 2025 19:52:15 +0200 Subject: [PATCH 1018/1190] Add SNI D943 machine table entry. --- src/machine/machine_table.c | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 5626b0728..d9231cc75 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -66,6 +66,7 @@ extern const device_t vendex_device; extern const device_t c5sbm2_device; extern const device_t sb486pv_device; extern const device_t ap5s_device; +extern const device_t d943_device; extern const device_t dells333sl_device; const machine_filter_t machine_types[] = { @@ -11777,6 +11778,46 @@ const machine_t machines[] = { .net_device = NULL }, + { + .name = "[i430HX] Siemens-Nixdorf D943", + .internal_name = "d943", + .type = MACHINE_TYPE_SOCKET7_3V, + .chipset = MACHINE_CHIPSET_INTEL_430HX, + .init = machine_at_d943_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 66666667, + .min_voltage = 2800, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.0 + }, + .bus_flags = MACHINE_PS2_PCI, + .flags = MACHINE_IDE_DUAL | MACHINE_AV | MACHINE_GAMEPORT | MACHINE_APM | MACHINE_ACPI , + .ram = { + .min = 8192, + .max = 131072, + .step = 8192 + }, + .nvrmask = 511, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &d943_device, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5436_onboard_pci_device, + .snd_device = &sb_vibra16s_onboard_device, + .net_device = NULL + }, + /* 430VX */ /* Has a SM(S)C FDC37C932FR Super I/O chip with on-chip KBC with AMI MegaKey (revision '5') KBC firmware. */ From 8f551991a48feab9297056d95ad1d2ff5310e6ee Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Thu, 29 May 2025 19:54:03 +0200 Subject: [PATCH 1019/1190] Update SNI D943 Audio and Video code. --- src/machine/m_at_socket7_3v.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index ca096c6ad..7dd1f9bf0 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -646,11 +646,11 @@ machine_at_d943_init(const machine_t *model) spd_register(SPD_TYPE_EDO, 0x7, 256); - if (gfxcard[0] == VID_INTERNAL) - device_add(&gd5436_onboard_pci_device); + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); if (sound_card_current[0] == SOUND_INTERNAL) - device_add(&sb_vibra16s_onboard_device); + machine_snd = device_add(machine_get_snd_device(machine)); return ret; } From 8f78320aaf105f1cd62160ac7035bda70fa23832 Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Thu, 29 May 2025 19:54:55 +0200 Subject: [PATCH 1020/1190] Add SNI D943 machine definition. --- src/include/86box/machine.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 3231acd80..c8166a973 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -708,6 +708,7 @@ extern int machine_at_fmb_init(const machine_t *); extern int machine_at_acerm3a_init(const machine_t *); extern int machine_at_ap53_init(const machine_t *); extern int machine_at_8500tuc_init(const machine_t *); +extern int machine_at_d943_init(const machine_t *); extern int machine_at_p55t2s_init(const machine_t *); extern int machine_at_p5vxb_init(const machine_t *); From 94f49282ac4854f244e676eae44ed91a94bfff0b Mon Sep 17 00:00:00 2001 From: toggo9 <121191375+toggo9@users.noreply.github.com> Date: Thu, 29 May 2025 20:01:53 +0200 Subject: [PATCH 1021/1190] Remove unnecessary Machine flag from the D943. --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d9231cc75..a961e9997 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11799,7 +11799,7 @@ const machine_t machines[] = { .max_multi = 3.0 }, .bus_flags = MACHINE_PS2_PCI, - .flags = MACHINE_IDE_DUAL | MACHINE_AV | MACHINE_GAMEPORT | MACHINE_APM | MACHINE_ACPI , + .flags = MACHINE_IDE_DUAL | MACHINE_AV | MACHINE_GAMEPORT | MACHINE_APM, .ram = { .min = 8192, .max = 131072, From 3b9b96700753269ec0fccb3aa1d3e896743d3ef7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 30 May 2025 10:32:54 +0200 Subject: [PATCH 1022/1190] GUS MAX: Fix the internal name, fixes #5640. --- src/sound/snd_gus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index fff679e81..5044c6f54 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -1473,7 +1473,7 @@ const device_t gus_device = { const device_t gus_max_device = { .name = "Gravis UltraSound MAX", - .internal_name = "gus", + .internal_name = "gusmax", .flags = DEVICE_ISA16, .local = GUS_MAX, .init = gus_init, From c6da2caff2c8847f46fa20d00265b69723624104 Mon Sep 17 00:00:00 2001 From: cold-brewed <47337035+cold-brewed@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:25:09 -0400 Subject: [PATCH 1023/1190] vmm preview --- src/86box.c | 25 +- src/include/86box/86box.h | 2 + src/qt/CMakeLists.txt | 38 + src/qt/assets/86box-wizard.png | Bin 0 -> 8314 bytes src/qt/assets/systemicons/cpq_deskpro.png | Bin 0 -> 244984 bytes src/qt/assets/systemicons/cpq_port_386.png | Bin 0 -> 250814 bytes src/qt/assets/systemicons/cpq_port_II.png | Bin 0 -> 161871 bytes src/qt/assets/systemicons/cpq_port_III.png | Bin 0 -> 202844 bytes src/qt/assets/systemicons/cpq_portable.png | Bin 0 -> 140593 bytes src/qt/assets/systemicons/cpq_pres_2240.png | Bin 0 -> 166186 bytes src/qt/assets/systemicons/cpq_pres_4500.png | Bin 0 -> 132431 bytes src/qt/assets/systemicons/ibm330.png | Bin 0 -> 186586 bytes src/qt/assets/systemicons/ibm_at.png | Bin 0 -> 283163 bytes src/qt/assets/systemicons/ibm_pc_81.png | Bin 0 -> 295676 bytes src/qt/assets/systemicons/ibm_pc_82.png | Bin 0 -> 295676 bytes src/qt/assets/systemicons/ibm_pcjr.png | Bin 0 -> 296020 bytes src/qt/assets/systemicons/ibm_ps2_m70.png | Bin 0 -> 219165 bytes src/qt/assets/systemicons/ibm_ps2_m80.png | Bin 0 -> 265107 bytes src/qt/assets/systemicons/ibm_psvp_486.png | Bin 0 -> 217113 bytes src/qt/assets/systemicons/ibm_psvp_p60.png | Bin 0 -> 217113 bytes src/qt/assets/systemicons/ibm_xt_82.png | Bin 0 -> 295676 bytes src/qt/assets/systemicons/ibm_xt_86.png | Bin 0 -> 295676 bytes src/qt/assets/systemicons/olivetti_m19.png | Bin 0 -> 262763 bytes src/qt/assets/systemicons/olivetti_m21.png | Bin 0 -> 324694 bytes src/qt/assets/systemicons/olivetti_m24.png | Bin 0 -> 209215 bytes src/qt/assets/systemicons/olivetti_m24sp.png | Bin 0 -> 209215 bytes src/qt/assets/systemicons/os_archlinux_x2.png | Bin 0 -> 3833 bytes src/qt/assets/systemicons/os_cloud_x2.png | Bin 0 -> 1551 bytes src/qt/assets/systemicons/os_debian_x2.png | Bin 0 -> 5228 bytes src/qt/assets/systemicons/os_dos_x2.png | Bin 0 -> 3718 bytes src/qt/assets/systemicons/os_fedora_x2.png | Bin 0 -> 3449 bytes src/qt/assets/systemicons/os_freebsd_x2.png | Bin 0 -> 3969 bytes src/qt/assets/systemicons/os_gentoo_x2.png | Bin 0 -> 3845 bytes src/qt/assets/systemicons/os_jrockitve_x2.png | Bin 0 -> 3703 bytes src/qt/assets/systemicons/os_l4_x2.png | Bin 0 -> 4348 bytes src/qt/assets/systemicons/os_linux22_x2.png | Bin 0 -> 5219 bytes src/qt/assets/systemicons/os_linux24_x2.png | Bin 0 -> 5161 bytes src/qt/assets/systemicons/os_linux26_x2.png | Bin 0 -> 5274 bytes src/qt/assets/systemicons/os_linux_x2.png | Bin 0 -> 4364 bytes src/qt/assets/systemicons/os_macosx_x2.png | Bin 0 -> 3783 bytes src/qt/assets/systemicons/os_mandriva_x2.png | Bin 0 -> 3858 bytes src/qt/assets/systemicons/os_netbsd_x2.png | Bin 0 -> 4123 bytes src/qt/assets/systemicons/os_netware_x2.png | Bin 0 -> 4623 bytes src/qt/assets/systemicons/os_openbsd_x2.png | Bin 0 -> 6027 bytes src/qt/assets/systemicons/os_opensuse_x2.png | Bin 0 -> 7361 bytes src/qt/assets/systemicons/os_oracle_x2.png | Bin 0 -> 5728 bytes .../systemicons/os_oraclesolaris_x2.png | Bin 0 -> 2694 bytes src/qt/assets/systemicons/os_os2_other_x2.png | Bin 0 -> 5728 bytes src/qt/assets/systemicons/os_os2ecs_x2.png | Bin 0 -> 4796 bytes src/qt/assets/systemicons/os_os2warp3_x2.png | Bin 0 -> 5940 bytes src/qt/assets/systemicons/os_os2warp45_x2.png | Bin 0 -> 4476 bytes src/qt/assets/systemicons/os_os2warp4_x2.png | Bin 0 -> 4129 bytes src/qt/assets/systemicons/os_other_x2.png | Bin 0 -> 4271 bytes src/qt/assets/systemicons/os_qnx_x2.png | Bin 0 -> 6414 bytes src/qt/assets/systemicons/os_redhat_x2.png | Bin 0 -> 5231 bytes src/qt/assets/systemicons/os_solaris_x2.png | Bin 0 -> 4358 bytes .../assets/systemicons/os_turbolinux_x2.png | Bin 0 -> 4018 bytes src/qt/assets/systemicons/os_ubuntu_x2.png | Bin 0 -> 4050 bytes src/qt/assets/systemicons/os_win10_x2.png | Bin 0 -> 6135 bytes src/qt/assets/systemicons/os_win2k3_x2.png | Bin 0 -> 6250 bytes src/qt/assets/systemicons/os_win2k8_x2.png | Bin 0 -> 6322 bytes src/qt/assets/systemicons/os_win2k_x2.png | Bin 0 -> 5948 bytes src/qt/assets/systemicons/os_win31_x2.png | Bin 0 -> 6116 bytes src/qt/assets/systemicons/os_win7_x2.png | Bin 0 -> 5835 bytes src/qt/assets/systemicons/os_win81_x2.png | Bin 0 -> 6134 bytes src/qt/assets/systemicons/os_win8_x2.png | Bin 0 -> 6158 bytes src/qt/assets/systemicons/os_win95_x2.png | Bin 0 -> 6296 bytes src/qt/assets/systemicons/os_win98_x2.png | Bin 0 -> 6491 bytes src/qt/assets/systemicons/os_win_other_x2.png | Bin 0 -> 5454 bytes src/qt/assets/systemicons/os_winme_x2.png | Bin 0 -> 5959 bytes src/qt/assets/systemicons/os_winnt4_x2.png | Bin 0 -> 6045 bytes src/qt/assets/systemicons/os_winvista_x2.png | Bin 0 -> 6013 bytes src/qt/assets/systemicons/os_winxp_x2.png | Bin 0 -> 6340 bytes src/qt/assets/systemicons/os_xandros_x2.png | Bin 0 -> 3209 bytes src/qt/assets/systemicons/pb_bora_pro.png | Bin 0 -> 172596 bytes src/qt/assets/systemicons/pb_pb410.png | Bin 0 -> 209719 bytes src/qt/assets/systemicons/pb_pb640.png | Bin 0 -> 177292 bytes src/qt/assets/systemicons/pb_pb680.png | Bin 0 -> 172604 bytes src/qt/assets/systemicons/tandy_1000.png | Bin 0 -> 160013 bytes src/qt/assets/systemicons/tandy_1000_hx.png | Bin 0 -> 179510 bytes src/qt/assets/systemicons/tandy_1000_sl2.png | Bin 0 -> 213622 bytes src/qt/assets/systemicons/toshiba_t1000.png | Bin 0 -> 157081 bytes src/qt/assets/systemicons/toshiba_t1200.png | Bin 0 -> 291942 bytes .../assets/systemicons/toshiba_t1200_hdd.png | Bin 0 -> 291942 bytes src/qt/icons/green-square-16.png | Bin 0 -> 115 bytes src/qt/icons/pause-16.png | Bin 0 -> 123 bytes src/qt/icons/play-16.png | Bin 0 -> 156 bytes src/qt/icons/red-power-16.png | Bin 0 -> 174 bytes src/qt/icons/red-square-16.png | Bin 0 -> 118 bytes src/qt/icons/stop-16.png | Bin 0 -> 120 bytes src/qt/icons/yellow-square-16.png | Bin 0 -> 117 bytes src/qt/qt_downloader.cpp | 95 ++ src/qt/qt_downloader.hpp | 57 ++ src/qt/qt_main.cpp | 45 + src/qt/qt_mainwindow.cpp | 1 + src/qt/qt_mainwindow.hpp | 4 + src/qt/qt_updatecheck.cpp | 360 +++++++ src/qt/qt_updatecheck.hpp | 104 ++ src/qt/qt_updatecheckdialog.cpp | 90 ++ src/qt/qt_updatecheckdialog.hpp | 47 + src/qt/qt_updatecheckdialog.ui | 106 +++ src/qt/qt_updatedetails.cpp | 111 +++ src/qt/qt_updatedetails.hpp | 43 + src/qt/qt_updatedetails.ui | 192 ++++ src/qt/qt_vmmanager_addmachine.cpp | 361 +++++++ src/qt/qt_vmmanager_addmachine.hpp | 115 +++ src/qt/qt_vmmanager_clientsocket.cpp | 236 +++++ src/qt/qt_vmmanager_clientsocket.hpp | 71 ++ src/qt/qt_vmmanager_config.cpp | 76 ++ src/qt/qt_vmmanager_config.hpp | 46 + src/qt/qt_vmmanager_details.cpp | 345 +++++++ src/qt/qt_vmmanager_details.hpp | 89 ++ src/qt/qt_vmmanager_details.ui | 293 ++++++ src/qt/qt_vmmanager_detailsection.cpp | 294 ++++++ src/qt/qt_vmmanager_detailsection.hpp | 101 ++ src/qt/qt_vmmanager_detailsection.ui | 91 ++ src/qt/qt_vmmanager_listviewdelegate.cpp | 241 +++++ src/qt/qt_vmmanager_listviewdelegate.hpp | 67 ++ src/qt/qt_vmmanager_main.cpp | 518 ++++++++++ src/qt/qt_vmmanager_main.hpp | 167 ++++ src/qt/qt_vmmanager_main.ui | 119 +++ src/qt/qt_vmmanager_mainwindow.cpp | 178 ++++ src/qt/qt_vmmanager_mainwindow.hpp | 59 ++ src/qt/qt_vmmanager_mainwindow.ui | 224 +++++ src/qt/qt_vmmanager_model.cpp | 163 ++++ src/qt/qt_vmmanager_model.hpp | 91 ++ src/qt/qt_vmmanager_preferences.cpp | 82 ++ src/qt/qt_vmmanager_preferences.hpp | 46 + src/qt/qt_vmmanager_preferences.ui | 130 +++ src/qt/qt_vmmanager_protocol.cpp | 131 +++ src/qt/qt_vmmanager_protocol.hpp | 93 ++ src/qt/qt_vmmanager_serversocket.cpp | 207 ++++ src/qt/qt_vmmanager_serversocket.hpp | 82 ++ src/qt/qt_vmmanager_system.cpp | 888 ++++++++++++++++++ src/qt/qt_vmmanager_system.hpp | 188 ++++ src/qt_resources.qrc | 91 ++ 136 files changed, 7194 insertions(+), 9 deletions(-) create mode 100644 src/qt/assets/86box-wizard.png create mode 100644 src/qt/assets/systemicons/cpq_deskpro.png create mode 100644 src/qt/assets/systemicons/cpq_port_386.png create mode 100644 src/qt/assets/systemicons/cpq_port_II.png create mode 100644 src/qt/assets/systemicons/cpq_port_III.png create mode 100644 src/qt/assets/systemicons/cpq_portable.png create mode 100644 src/qt/assets/systemicons/cpq_pres_2240.png create mode 100644 src/qt/assets/systemicons/cpq_pres_4500.png create mode 100644 src/qt/assets/systemicons/ibm330.png create mode 100644 src/qt/assets/systemicons/ibm_at.png create mode 100644 src/qt/assets/systemicons/ibm_pc_81.png create mode 100644 src/qt/assets/systemicons/ibm_pc_82.png create mode 100644 src/qt/assets/systemicons/ibm_pcjr.png create mode 100644 src/qt/assets/systemicons/ibm_ps2_m70.png create mode 100644 src/qt/assets/systemicons/ibm_ps2_m80.png create mode 100644 src/qt/assets/systemicons/ibm_psvp_486.png create mode 100644 src/qt/assets/systemicons/ibm_psvp_p60.png create mode 100644 src/qt/assets/systemicons/ibm_xt_82.png create mode 100644 src/qt/assets/systemicons/ibm_xt_86.png create mode 100644 src/qt/assets/systemicons/olivetti_m19.png create mode 100644 src/qt/assets/systemicons/olivetti_m21.png create mode 100644 src/qt/assets/systemicons/olivetti_m24.png create mode 100644 src/qt/assets/systemicons/olivetti_m24sp.png create mode 100644 src/qt/assets/systemicons/os_archlinux_x2.png create mode 100644 src/qt/assets/systemicons/os_cloud_x2.png create mode 100644 src/qt/assets/systemicons/os_debian_x2.png create mode 100644 src/qt/assets/systemicons/os_dos_x2.png create mode 100644 src/qt/assets/systemicons/os_fedora_x2.png create mode 100644 src/qt/assets/systemicons/os_freebsd_x2.png create mode 100644 src/qt/assets/systemicons/os_gentoo_x2.png create mode 100644 src/qt/assets/systemicons/os_jrockitve_x2.png create mode 100644 src/qt/assets/systemicons/os_l4_x2.png create mode 100644 src/qt/assets/systemicons/os_linux22_x2.png create mode 100644 src/qt/assets/systemicons/os_linux24_x2.png create mode 100644 src/qt/assets/systemicons/os_linux26_x2.png create mode 100644 src/qt/assets/systemicons/os_linux_x2.png create mode 100644 src/qt/assets/systemicons/os_macosx_x2.png create mode 100644 src/qt/assets/systemicons/os_mandriva_x2.png create mode 100644 src/qt/assets/systemicons/os_netbsd_x2.png create mode 100644 src/qt/assets/systemicons/os_netware_x2.png create mode 100644 src/qt/assets/systemicons/os_openbsd_x2.png create mode 100644 src/qt/assets/systemicons/os_opensuse_x2.png create mode 100644 src/qt/assets/systemicons/os_oracle_x2.png create mode 100644 src/qt/assets/systemicons/os_oraclesolaris_x2.png create mode 100644 src/qt/assets/systemicons/os_os2_other_x2.png create mode 100644 src/qt/assets/systemicons/os_os2ecs_x2.png create mode 100644 src/qt/assets/systemicons/os_os2warp3_x2.png create mode 100644 src/qt/assets/systemicons/os_os2warp45_x2.png create mode 100644 src/qt/assets/systemicons/os_os2warp4_x2.png create mode 100644 src/qt/assets/systemicons/os_other_x2.png create mode 100644 src/qt/assets/systemicons/os_qnx_x2.png create mode 100644 src/qt/assets/systemicons/os_redhat_x2.png create mode 100644 src/qt/assets/systemicons/os_solaris_x2.png create mode 100644 src/qt/assets/systemicons/os_turbolinux_x2.png create mode 100644 src/qt/assets/systemicons/os_ubuntu_x2.png create mode 100644 src/qt/assets/systemicons/os_win10_x2.png create mode 100644 src/qt/assets/systemicons/os_win2k3_x2.png create mode 100644 src/qt/assets/systemicons/os_win2k8_x2.png create mode 100644 src/qt/assets/systemicons/os_win2k_x2.png create mode 100644 src/qt/assets/systemicons/os_win31_x2.png create mode 100644 src/qt/assets/systemicons/os_win7_x2.png create mode 100644 src/qt/assets/systemicons/os_win81_x2.png create mode 100644 src/qt/assets/systemicons/os_win8_x2.png create mode 100644 src/qt/assets/systemicons/os_win95_x2.png create mode 100644 src/qt/assets/systemicons/os_win98_x2.png create mode 100644 src/qt/assets/systemicons/os_win_other_x2.png create mode 100644 src/qt/assets/systemicons/os_winme_x2.png create mode 100644 src/qt/assets/systemicons/os_winnt4_x2.png create mode 100644 src/qt/assets/systemicons/os_winvista_x2.png create mode 100644 src/qt/assets/systemicons/os_winxp_x2.png create mode 100644 src/qt/assets/systemicons/os_xandros_x2.png create mode 100644 src/qt/assets/systemicons/pb_bora_pro.png create mode 100644 src/qt/assets/systemicons/pb_pb410.png create mode 100644 src/qt/assets/systemicons/pb_pb640.png create mode 100644 src/qt/assets/systemicons/pb_pb680.png create mode 100644 src/qt/assets/systemicons/tandy_1000.png create mode 100644 src/qt/assets/systemicons/tandy_1000_hx.png create mode 100644 src/qt/assets/systemicons/tandy_1000_sl2.png create mode 100644 src/qt/assets/systemicons/toshiba_t1000.png create mode 100644 src/qt/assets/systemicons/toshiba_t1200.png create mode 100644 src/qt/assets/systemicons/toshiba_t1200_hdd.png create mode 100644 src/qt/icons/green-square-16.png create mode 100644 src/qt/icons/pause-16.png create mode 100644 src/qt/icons/play-16.png create mode 100644 src/qt/icons/red-power-16.png create mode 100644 src/qt/icons/red-square-16.png create mode 100644 src/qt/icons/stop-16.png create mode 100644 src/qt/icons/yellow-square-16.png create mode 100644 src/qt/qt_downloader.cpp create mode 100644 src/qt/qt_downloader.hpp create mode 100644 src/qt/qt_updatecheck.cpp create mode 100644 src/qt/qt_updatecheck.hpp create mode 100644 src/qt/qt_updatecheckdialog.cpp create mode 100644 src/qt/qt_updatecheckdialog.hpp create mode 100644 src/qt/qt_updatecheckdialog.ui create mode 100644 src/qt/qt_updatedetails.cpp create mode 100644 src/qt/qt_updatedetails.hpp create mode 100644 src/qt/qt_updatedetails.ui create mode 100644 src/qt/qt_vmmanager_addmachine.cpp create mode 100644 src/qt/qt_vmmanager_addmachine.hpp create mode 100644 src/qt/qt_vmmanager_clientsocket.cpp create mode 100644 src/qt/qt_vmmanager_clientsocket.hpp create mode 100644 src/qt/qt_vmmanager_config.cpp create mode 100644 src/qt/qt_vmmanager_config.hpp create mode 100644 src/qt/qt_vmmanager_details.cpp create mode 100644 src/qt/qt_vmmanager_details.hpp create mode 100644 src/qt/qt_vmmanager_details.ui create mode 100644 src/qt/qt_vmmanager_detailsection.cpp create mode 100644 src/qt/qt_vmmanager_detailsection.hpp create mode 100644 src/qt/qt_vmmanager_detailsection.ui create mode 100644 src/qt/qt_vmmanager_listviewdelegate.cpp create mode 100644 src/qt/qt_vmmanager_listviewdelegate.hpp create mode 100644 src/qt/qt_vmmanager_main.cpp create mode 100644 src/qt/qt_vmmanager_main.hpp create mode 100644 src/qt/qt_vmmanager_main.ui create mode 100644 src/qt/qt_vmmanager_mainwindow.cpp create mode 100644 src/qt/qt_vmmanager_mainwindow.hpp create mode 100644 src/qt/qt_vmmanager_mainwindow.ui create mode 100644 src/qt/qt_vmmanager_model.cpp create mode 100644 src/qt/qt_vmmanager_model.hpp create mode 100644 src/qt/qt_vmmanager_preferences.cpp create mode 100644 src/qt/qt_vmmanager_preferences.hpp create mode 100644 src/qt/qt_vmmanager_preferences.ui create mode 100644 src/qt/qt_vmmanager_protocol.cpp create mode 100644 src/qt/qt_vmmanager_protocol.hpp create mode 100644 src/qt/qt_vmmanager_serversocket.cpp create mode 100644 src/qt/qt_vmmanager_serversocket.hpp create mode 100644 src/qt/qt_vmmanager_system.cpp create mode 100644 src/qt/qt_vmmanager_system.hpp diff --git a/src/86box.c b/src/86box.c index f54a69b79..c17e697e1 100644 --- a/src/86box.c +++ b/src/86box.c @@ -251,6 +251,8 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { .seq="Ctrl+Alt+M" } }; +char vmm_path[1024] = { '\0'}; /* TEMPORARY - VM manager path to scan for VMs */ +int vmm_enabled = 0; /* Statistics. */ extern int mmuflush; @@ -598,8 +600,8 @@ pc_show_usage(char *s) #ifdef _WIN32 "-D or --debug\t\t\t- force debug output logging\n" #endif -#if 0 - "-E or --nographic\t\t- forces the old behavior\n" +#if 1 + "-E or --vmmpath\t\t- vm manager path\n" #endif "-F or --fullscreen\t\t- start in fullscreen mode\n" "-G or --lang langid\t\t- start with specified language\n" @@ -732,13 +734,14 @@ usage: } else if (!strcasecmp(argv[c], "--debug") || !strcasecmp(argv[c], "-D")) { force_debug = 1; #endif -#ifdef ENABLE_NG - } else if (!strcasecmp(argv[c], "--nographic") || !strcasecmp(argv[c], "-E")) { - /* Currently does nothing, but if/when we implement a built-in manager, - it's going to force the manager not to run, allowing the old usage - without parameter. */ - ng = 1; -#endif +//#ifdef ENABLE_NG + } else if (!strcasecmp(argv[c], "--vmmpath") || + !strcasecmp(argv[c], "-E")) { + /* Using this variable for vm manager path + Temporary solution!*/ + if ((c+1) == argc) goto usage; + strcpy(vmm_path, argv[++c]); + //#endif } else if (!strcasecmp(argv[c], "--fullscreen") || !strcasecmp(argv[c], "-F")) { start_in_fullscreen = 1; } else if (!strcasecmp(argv[c], "--logfile") || !strcasecmp(argv[c], "-L")) { @@ -1025,6 +1028,10 @@ usage: } pclog("# Configuration file: %s\n#\n\n", cfg_path); + if (strlen(vmm_path) != 0) { + vmm_enabled = 1; + pclog("# VM Manager enabled. Path: %s\n", vmm_path); + } /* * We are about to read the configuration file, which MAY * put data into global variables (the hard- and floppy diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 76f311d17..488585ce2 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -176,6 +176,8 @@ extern char usr_path[1024]; /* path (dir) of user data */ extern char cfg_path[1024]; /* full path of config file */ extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ +extern char vmm_path[1024]; /* VM Manager path to scan (temporary) */ +extern int vmm_enabled; #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index df13d42e2..dc430d68c 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -189,6 +189,44 @@ add_library(ui STATIC qt_mediahistorymanager.cpp qt_mediahistorymanager.hpp + qt_updatecheck.cpp + qt_updatecheck.hpp + qt_updatecheckdialog.cpp + qt_updatecheckdialog.hpp + qt_updatedetails.cpp + qt_updatedetails.hpp + qt_downloader.cpp + qt_downloader.hpp + + qt_vmmanager_clientsocket.cpp + qt_vmmanager_clientsocket.hpp + qt_vmmanager_serversocket.cpp + qt_vmmanager_serversocket.hpp + qt_vmmanager_protocol.cpp + qt_vmmanager_protocol.hpp + qt_vmmanager_details.hpp + qt_vmmanager_details.cpp + qt_vmmanager_details.ui + qt_vmmanager_addmachine.cpp + qt_vmmanager_addmachine.hpp + qt_vmmanager_detailsection.cpp + qt_vmmanager_detailsection.hpp + qt_vmmanager_listviewdelegate.hpp + qt_vmmanager_listviewdelegate.cpp + qt_vmmanager_preferences.cpp + qt_vmmanager_preferences.hpp + qt_vmmanager_main.hpp + qt_vmmanager_main.cpp + qt_vmmanager_main.ui + qt_vmmanager_model.cpp + qt_vmmanager_model.hpp + qt_vmmanager_system.cpp + qt_vmmanager_system.hpp + qt_vmmanager_config.cpp + qt_vmmanager_config.hpp + qt_vmmanager_mainwindow.cpp + qt_vmmanager_mainwindow.hpp + ../qt_resources.qrc ./qdarkstyle/dark/darkstyle.qrc diff --git a/src/qt/assets/86box-wizard.png b/src/qt/assets/86box-wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..19ecda8c7d42c1aa6824aa28b43eb58535035ac6 GIT binary patch literal 8314 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/cpq_deskpro.png b/src/qt/assets/systemicons/cpq_deskpro.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbca68a3f105d3aaa534e5b32305be166200a74 GIT binary patch literal 244984 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelalU`BjBPlmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNPuSCv#egy3o@9o4cZzBt92OoPR0%<l1=Ucn}wLfz3 z`k#M(-){RCy?Ous$M2uT@sBy`O&ag-`Z{pF8~7v7g!{l~~Z-k$&G^!dm0 zw{M*9Ci3R?+_%RCWvdT<_`6^J+53BU-`UPzF1^xX+3FhGEBXDO_C0Q${PNEkw}<{u z|Id8?`uF9Zm;Zd|4!v#js-*5yzg&;xe#KT3QoAD;%>FS$F$G&bBTU{Eh zNM|C=zu#)xz?+(i;4^~I=Hdf}WIiK*v?S_AtLdx`9 zV=r$*F|p+{-<_?_s#w1@XTChMzK%{ERD(SmbEXOvzUV8mr)%)av%M;nIOYN!q z(41*}&g8Ss=5uDhWx78^WJ|BfYr+ypepw7zN|kxuHDxYWKoaIKGqe< zwWi`Km%xQ(rk{0}q(oV+o%voYw&$iq>a|C27KkRZUT&1g`?0O;e)v28>t_vj|1Y`w zra$al=F5NeYvx?O^mjwi{`l?o5nFBL?i}0haLVbKNK4NWd3}rA7p^t+POql!zGv-} zx^m4l;jgpHiY|oPUs8#9b+_(ab@d!mi@!;RQ|C?mk@)#c`NnB8bI&LEoqoP|*?Y|# z)t=X}K7UdVz4JZhP}%l2?CR-5Qc_|jKiiJ_@8j=g+|&3`Wd6ch-Z#$^KW5~o9J!@` z_|oD(Hfz>97EX?DV~v>cTWTiTx6>Q`-OSnf{_@xNX{T%Fud6qYe)qfN@9vvL_m{su zpZ1z%*+JuF6S{hBg~~m)9=SNpE!54=HfB2$WAwUSr#ouOtKaS1mTz_E)t2?z`!Z~M zRvm1s#bkAVzsU=H$PKpedW-TvU#)Cw1n@Bv|4^Fd-b*0zboJN-N>(- zp6(Mf?~66hG2Ph{?3K5@yX>32e(&GAKJ(94`nE~WoLhU2V`u*c+lYW~&kD=ei#>iT ztQ$T(Ti9~f>%W_2e(7rb%R1F~E88GKZNI2#{RG$hhm`(pXDE$)%w%DI_)*Y)p4ZD4 z?5LNUw_@U##|yr!o?rCh`GOyX0ru_7e;;}7fB4sYke~JB`_>)(zhvJ2eb27uOP7Wk z{B61Dozt;la`k?X4TgMDJgnxkt;?tG3hvxj7AKc$nld$ZcGt3r(#@x)O4zvt{4n~} zxoiS+hN4!|TY)%b1NV0JttF2Iex9@!`yOO*k|;d(N2`-_(wl%{1I` zEP36O-k6SLf&csBeyo@lT{FkySnr}O6`i-k%1;C?6#JVe;G53$xmTa*f>ToaBqA4llms(bA`uC{x$BLT{Z{L zJG%cadDrs(wNK2c`)-qKL$i+PF6o=;Fyo1nhuFcJ&SerC?OHMy$Xq(~aRz_;rFFJK z;)=~IYdmFVvgdX#xhMPeO6C1KO}|eqJ+{YFcw*%5$-B-=Tg^H#XH97EwarqzPx3wg zD;0VM+>=+o)U{ovwUWceLG5eL_lb@@+hlw0?>Q@1vf!O=vuTCyqg#5r_D8E}r-!>G zgmL`b@tddmZqn1XX%AH+8CRc--4xk2Bh;I<$YQGDGh1)<;*)ZVDx0Fc=T$y$`KbJO z!7AZTp2a4cdQaFK{F=+++*O=1&*XJol$_g+(>pl5UV5CFyKd^4FAkIM=;{}-gzY>$ zSw(=;hr7oi_i(?A*-BQo)|>KcL^aQ~7vyjI_h@zX{RK@kn`1qS1eDTPa-_0PXewQ) ze(_*xKd(TGvvz-7^34QxKaMjGr{9#x?5$%}o5|=j=fJwm?VPINws~(BHm2BaD02BU zvzmMQfr}jXp1CxMvHY6#ATULRqt(TYv7_$pk>3aG9N)&iNZRLmpgpeEO+N zyt-GLr(jLn^v>dwkw0Z;*x#2~|5?9}bD>Sb>#mc}icjR2}HfeB@y)y;VnmW1a60i<-#1#uwe6 z0(Ml3n|=D~(2`=@A9_rNV~bAS3&uHOifa@rOk3X^TX0v^y2R~c@uoZv^9g4S*DilA zT#&t>h>b}is@*W+Wr5iNk6nwMpU?8)(r{R?%=p8!3-_%Ajxg3XMkR22Cf{T`v5{Tp z_+O9Wd%{l2zZ>{X-mjdhy5hERreu+k|7KkCb2U>^IoH%xGeO)Hj10|6NQ9SzbrRvrEn2 zCVs+^p?_Jq5hr(1L{jz~OPR_fA=3|a2HAIc1DxkBxa*a9Pbu-;wWuJ)3x_;AZSHOq zG87YctnI(>$WK!5n()#~d`>O$d7W!>Q|cqi8GoNOoSJ-m59{`|tKS8Dn^bntPk+nl z2k!)P6pIzrW@LWi<2b0VbMVfj(1#3;>jYPpGW^?fd)@<<7i!te6(SXBp1dj7Dn5SN z5g4%S%z@?YE;VhJLg$$th~K(&j@u`PYbk0~SmFq+6=vccFn>$?0FtqMMtxmA4)?_Sp5xg`8j{L*fxHyv}@J{g3cIP^k5a)JDz z>DN;iDI`q{xy>;3QUJ%}c>!1SXN7+Kw|V`$=kg4h+Z|8n-f;BXsB~T_XHjCKafa*K zcW*WNd{hLyc@-xFb?AK!EPDP-<%?6$NneAgq>g~cycvCZa;M(w?sUFTwkTj>$u!1H z)`blD>-w~-mD`U`S$uNBi#6tk-L^cbizRaQ-g>pRbHeHsE8DUHUb^nmabgw-ET0s> z@_%h>w?kdrt8$0WYs7A8cLqCnu$UU~uS-|jdUTq(_=eLhLVA)n3Qr`3^gL9%6;inG z$C>zGCy8yz3*;5mY6Z{g^RHJqB51;@E&M)oCsX~-o)hoCrqr-KyfAV45&38Bryu0{ zYO)C|UMjMx<#veEuk?P!3%2QDFH)F_L|sy2x^A8@-4MiGq8j$mhUe3y-;>XrV7H9A zSb8BVUuQkL(^EcUAMN|+gFKEecbs-OlzH1!=NAvI&+&D2IwSs*uRwX{#qc%DCW$mP zEEYH(__SPZZD;FJPD8O@lN(!ROfJxrz4GtV9ns)6(WdRj%}IS9{G>M@6ACersA-Fr zE`6?%63KCeF>E2H^aR5PpR3tgni>LZKObH5|ML2G)8&uENeFFpNQsMou*#_O+oVdD z9QKGN`8Dchief8I_U0YCt~T9aYaf?ff#t0J8Lk{HhjbDz{Ja;@6L%o^UXjAjc@g&% zEDnV+{N2Q`q^f95OjF{r&?dV?huT#~#DrR9u7?GBFH znMYN*Q8rJG^1Nv}TDS6hgHA}8yl36bxKJc9OIRgw<BAv!Tu9mwNaPeo)qTpDDI!2nALIoqLqXW z*OB{4wt8Wly=Jri*jX^@x-OVouu|`dz)A5%rCI0M5aT$Hj>JWJNhR5n`af5z0o zE<$IDWX#?Wi33YlxfrTvv6#(oRc&6lKwqt?eTUE#Yb~}Jn;0}2St`D?-sE{?xPp20 ziiY-YPrlt%(mbJUqxSOqixr07HI!8hnqD;Q=A7G6cjJ)9oONRQ6HQ9hUgq#Px9Z5e zu(tX+%|r6WlBEn5t;%+azF$8vEKxdL5O>Y$aQ>aBoPU}Qjs58ijd@Bul2wkSEJezp zC)<2wjNEtlEL=3b>#Ig`in`N2Ci7#(!Y+S~UdjI_9uxV}n?v{ieUEm-aEE*urdN_})};$)(Q)Z*V*f_f~ombeS*i=*0|iCRTY*DVKvTG9^1}pY>XP zTt81%{S%Y(zNu#n7=JM>I6Kw+*iM^!p0A=@4d=u?UUlN%Q7%U2JBeHl;*^i?@ z>>enTSwCdpv2mJjlv0uSt?AwO6`daQgiSr}?y;I|r@|Alj`M%$G`VFvGK@RkAN!$Y z=+o}p=-aC6b4XcKNq(#21TS6D=B8URE-Cg2PlSqu^s*0lZDt8MSa*soqA*1(ZDFHq zY%0^8rK^lr?GlXWU3%}+M{BLtWGUm5vp3u`%G=?(rku$%tlYxau<){g+v*wW0(~t_ zYoezualc%kt1)+nDp#ef9M{S1iLoK?POUxD+}t8-eueu(|8wrh1xM~Yo-w&%zjErs z=~72-YB01MkTo^Gw0MO}=jB7i6NJxkvrM=wv2EpBjYTb`%xVGFk_Iqdi>B^Wob*%6y?(k?7f4YdNaS8_LDJU>nE;|X*{iJ-t{8#rOv#`R#TsM zh&mq)PjhK>-|_Cp&Bci;PBIehrm7zp@$}-TxYBE#I22BelcRNBE|S*Oa|XCkp0UQ3Dnw1u0@PS1#Enx^w~`s^of5@xM>#nJg8>!nJhEut8WLNh%Cf{lg-ECvjHKDSznZ^IOVxye>f_1Fy&637T zdEY6^omE{~aAZdCC-HM^i)-5F1THOJ*0p(_)-wx+6%F-Tt&HlkuV$T*Sdw?*!J?Cfrp{l>`_f7vQd9mt?k@-U**7t3G2*~^cRIrmAJt)zcY`$ zeDeXv-LIMU?h8FSZ^Pn_fNH5TCyaNrC`2(E9=<%mXpL~^+20cdZ<$!Ex*&M#bm)@H z+wSb}bGMzq;~bRwFf!bxWA&0#WhbVlXPD`I=?HCm`G9F<`;sO;E*3#XHHK8#4{K+r z1Wx$5X6>HSr$W?rXYmVJ9;;a_&~<0+k+t#@Ez*|ExcFAKY4@HVlaJZlDQ;AeC`|JE zEvd0Nyi{V=n+xoO_sb>FQs_ZGdQuq9>t*6CQjy;^M^53M%Oj3OPHihbg zIl7^KTMWbgws7ycen%T>0duNJ&$J1|D{%X&%%~HD3y6OYl=bawH6D&kTRoxjCFaEvJpt5JH z$2r6FRF;4v#sX8HOtbfzVWYCu<6HBTBo|44R&RylTd%Ka zVIKE-^U_xWPLix zm+bOpVw!Y*DGy_iQn{Pv;yDkTb6ZxXD~B_^kGa8Y@nOf_Z?76pluj0jdbe+F9RH1l zzYHdBR4m`>DCT#0A9rQ&W_Rbar;dIOTDds8J%DxUTFZt78w>i5`pozn(Xdm|?NRQk z=Wc3(@(m8n9TUsX{M@%{X8BUL%VrZlbh{q*Po6Bpb>7=2$!D*{rPW`g`^zNUrgf|C z??`wowUfjAiN*y_NB&w@pAEKx&w^U4*vq*dXkJ)2i}90BVG~nfiFCc*Bo9c54dOW*wf){%o(#E?KoVD>8yvOU|>bGGM6`+POL}KICDEij~fZ z)d%IS%5ZX?j>xmwvtO&zHR=5xKZXw)8Q!z2OIo|l9=%giQ#W{0Bg=1Fq4(uRWA=uL zAI?m@qvxJ*ZnEK(?xd5VP04oK{HV`zIT?8mKhEq6S1 z3bREvPuIRYyJLo#!RFW}y(Y}gbGLDKU6<>;6Q!$C{czdT?k5s*C*$9qlMO!I&Nb(O zio%+AO^a%~d_0cF$#UyoU&CFQYI1-zb)}q>iEy`rK;>@TZIL0>Obv@}SX6|u?+iaI z9TS6w{MGAik&=b&A2qKW#QQ{4}14V7mCE^N^CwZpV#JJ5!lu?>xtBo%B_uC zuB>S~^ma)J(>;Uwf(A3=&0eSK+5#FTwW~9f9lUtB#38puML1yhkLR3n3pxEv`&C>D zlRsR#61RQnQ>YMs>Ucp{9^_78r&TaFbA9=s{N1(Wc zBTw6x`JdQliaDv} zfA`Z(Si4ZfXBktWf??+E#a?=HlkXfjOzlng9<_Z;`duqjA2LRKHP@Mxq_9hCUFynvmmTMwPTtvN#q_TzT0(1?x9Ez` zPq+6grMD^{Zkc=~B43`7@v5q`TFuEbi>_Zk`s3l;qlu9Uj#pOpHw*f`{W8`4rjFsm zrVYKDS8Juu^oro&?F|M+FIGH%HQ@=*mlsbC zaXz2d6x?EwaOj84hDOQnJASovsc*E3a^5TVf_<9yf#WLL+P!ja+ZE+f&TJI(kYlqp z_3~#}cT(1?#Q#e37T4RK2^9&1~}8L1WRUtMykW{BrS1obV(4aJ8`fvSW4^ zmvCoAYOP{j5jio1$!hbFSuu|pBFxL#dkhwCINlt!TYlk&D|a7X?P-`%u(z9Cl~b>Z zxvKi=)|K~!b9+2Jv!Z!KFK%5Ot6g};IwJe+-&cuZtEa3xeT$)C`qtt_c8NU`{}^$e z)mFR~ZWi*>|B@pw!(FGK$BDDE&m8K#da7_kWN@v9%LFa6i4R<79-i- zvg%wd!Z6`Xo{sZGhBAk)TQdR;i#8tk%GtfZ{?^?+ufAJLRc>g@@^Rhdw3I#c_4}PI z$*S{Np7n_axf$DRVRJmc=+yR<6@4}A4ig^FDtY_waazQWQ;Vjo4L!gjQ!y*?rH)Ik zmUqH~!?%Uf*^G~MsW;UduH1N4<=6TTi^F*J8Lw~diF|gmyyE%7ZNdF#h15byXIwS8 zVqtoww&Uf4iGr(Sw<*e9N#{&ET*q)EC-Sz!A+0E8<`&m&e_g#eSoFCZ|IsgZw}^KeY;8KkAX4h1azFgPd(a9UqXx}D z&Ff7^C0E^&k0@Lq_GQ)jS&<(eEvqfO=5W?{#V3D#v4*DZ?v{VRd_|2%RnF|nh7jpvH_m+xaI;flP%c_y zrMbnGEm(4G+3fyHzFIGg{1imRoK)?U9f>w{AEexom6HiqSDX>Wc| zdfC(Y$Enp~Ywqp$J;SrJajt^v)@!SB6Mja@O)uTPyhnM5Pg2;Njy(YZ<)553^Pa+banaZ$IPE3r#Use4iJ6e?Bn=g&vOTv#0d`- zn6IfbmlmCT@8cUdaqBAC2;UcRN2QHicP9i^d$nv$e7K}O%h@jJ>(oA>31=Aj44R7c zGJ@r8)o06xzCPP|^s)TqdwCq+3 zuI6)8Ox~!la8}Yok$_$DZ&RDXbQVtUlUp-wnbZwi=eso*7an}ga=VDDKec#X^tLiK zp#>|_K3ILd_PV~&{>p^~>TE6wq4x3O{HsnDGJegk64MfGDp(n^TkJ_xkk6|2)%6nB z>$XPjy)wz^&gy$7*Kp-{p0h14Z_PMdW@CE3;&FggLbp%##Ar9gtIu5{ES$DyG>djO z++1QXrWV5X@l}C8o?p=wn{1Lcjh5w_R6<_7Iww-HgPrm3W zen5PMuWp^$j1RtnvNhs2zA={R%4s(GU3to8*VEv(i;?^An=Lk;K6x)CZ}DoFeHF{R zJhgBold|lZb*p4gzmC$mW!oqc@i)u!?SeSbCp=z;E3+(4c<%1*JAThmHuofde#`8# zV}CAi@=aO3GM`ycvvlEFueVcHE=m65ef!hvwxRe)P%j5L$L}b*_8$ESu0*MHl?;?q9WcZ(6Nb&yVnV8ExhDb9o(tIayRT zua>)Kd{uLnvPf^P>wdw#LV~WLOr5+p=dHYZmH8E0LVJ4k-ewyKA4Acn5f*RVD@?6d ze^ZZavwX(OyP|hq%%s$vHYtJ11uFR$Mt9qiwonpk90`wPH4Ql z*||kURNQs4#>74ogVN`#IhJ&sdbLM+?E}v{N|CW8XFS(t?r~&Y8#eQ6+*~WJD=vpV z^|*awoa=q`g!DGI3Bfrj8XU%3n}s3;^jUklc1vd*oGD;oRo1pXZP9A6XE}0QzLAF8 zC4zfQ8qy8+xZdb^d8{(lA!YUB3FY?LfzvYA+!meI|G{B@>iyh3VNch&OczkRy(Rmu z6$@MR%Ja;}g$1Rxme1anRj!`*`y1aCZ5<9t+l$h#4!_x<<6-?`O-f^{#Q(~4)y{2t zHy5aCKVonIQ7H0D04FNwg*j1 zYk4v~E@`>4+xV%JDSgv@cwmCXvdIq%-7lh!^4~WOZMKGKVc^ zzw~Wxhlu<4g}?UpSu^&mpLMgTis8Z5j#(ei2s|k3c;b_BN~rWH&kSbo6<%wPABjrY z<92%EGWO-yX2d)8ZF_X*-7ANew=89Z&8~gyZz$B=BiqEczW;hMbBGD&%$4(AEejEJ zXJ@(+IWaW$TA%#GM$1QB&Ki%H|6kJEto8f-Veu=EyFWj^c=1rycBctRTbJiYhEJ`X zolw@;c;K?>?q3UzWp^DuvWW3@z;ap56Zbo|{`hs(O6$SCbvHE~E_51i+Ld;F@%i)3 z)uD&Cnp<3LwV0t}H_}xm()AUMj za+U0wa(|<~*G-zPPuc!l%zMRgsoio1*WUfNtWQ^4=~r6GWlmsBV{ve6|G;B3ciFDL z0q3__$xf(uu3l&5dnrFqS=iu(>I+umpSf!?-z%*yH`~6zcFLl~muHkWO*?bfD%B$H z_S9V-UFXi_O!xUG`Qi576~^8(*6nBvDShK%ykpD6854ZG7x6?{>%ZUny>Cle5W~G! zMtZT*w@{2`%p>7U;lJ+C>5)^W=x z?lQS5s$<*lc1&3AFw04wMCS)?Z!bLM{gXD$c-7hUE6N2$pIvDBxlb;-b{*@R=n(JQ zRy8+Ej|C`mR4~-`F#dZqb>{2kw*I|B)+=TTe0_iHb$EIc*U!aj|5w`WUCJi>#ptx~ zmXp0d&PT8WulEhxEu!ZUD}Q93mtKo)@sU$0Zw;5O(^@B?vRYE&`bxftmKpcs^=5`E zsJHR4NT_u3PQLfxT*`KBhR=-AE`Pn9VnroR#ONAlox87bbj4aXmIY;tw)`s+_@Vts zVP%`ZRl6m{HzTil@0n$jaP{2gK4SxG&!ZZ>hnvh+vMqG8c-*mUf^Ykc2yP}O@tv!r zXFXW`Y~|u*K~EQ`2!@5Qf8F|c<%#e83tf97zVGwAuv3&*@ZM!l&POXsuLvk5ZV@fL z7a7p~Iw^_M|BaoJdcq{$dY$T(&Z1UY?b`%XvsU*mpSp6UmXKp_wZngxSGg9iucQag z4BfN%c!2lWt0zA$iM0#zbB~$zZ9z?X(^aMS8yz%vlf_U?J6K7xb-o-S@bfVX<4i-;l#$|ig*)(6Qwa(gl zQEut|2Mg7^3}rt{oqWT$uf_d#gpU8dMEld)^VhV_x!^f_X-L39&S?&+Uq49Ay<)Tc zyz7KNp=+eyad;*=%rs+)Fnlt1uUhj0vD&21r6nFAQrlk13MaEoTlKV7`W=sPFK>4q z@7$-Fg2HbvhWSjATCL!w-^`p@TU+OwaQ5H=oy?|_PQf#GJzd4O^z<5wxr?5J$42ze zPZUe|X)397X~N48c6p1n$~(?%Wq8qlJNEAL+4m-@#as@Uq8l|?-r?U~E8BPSiTAp= z_D{FiX~oc3a`B<0OT+IN$0_ z>d%Tjk?<{O`VQO8mn8Sa-U$*8T;&+x&N1O>ZMocc*%L~?OCQ|aVO=qMYx}fvgL3Bc zG8+%O&YxAhVXpP2Gsl$|&9-oQ{xRjkIkxK+odLJKy;r^GpWUAq+PvKP@}k)S{7gTV zv?Y~h?WM?z|;*D zM_yk$H$g=tano%6R~y#cnjH3R`6@rYt@#ELZ=b8kz0A5CAA94%+LFn93-hx%i-Swv zTwGl%y}M;1htc`VE1yg5biCH26ZlpA$poG&+~=D!1DJ(QwECVC`2XOeXH{uo=cJ0$nix!azod3l6qa?|r2{~DPtE?-?TSKiHDeCzzL zvsA?WLjM2y{bf3UE-0Pv&^Vb`~gDOR4e70P9C(>w3vsUY*Ej_Pt zjNRUFEL*bpo`$~M(nV8G2{+$T?2oeQ;9BR#EMlX%A#sLt09%No&z)7mN;bPJ6SB^1 ze|9q4|IH)=sj0t=q-P#ITVimz%kJ^P2qBqkv6~pfS#~eyJ1@M(&pItj|M)G%6+st| zZ7G}HS{LZr`8v>bg@b+bGynD*Ark8Xe-}9DYA-&u>T=`$HT-r5ve)jnv-o~I-cxUT z$%i>E{D(H$Di^jz#F@KXUDj!TMfd*OS?5hxz9>>}T<~~C!NbWXt?C=U?B>>)f2^qR>}CTP}Tl5;}W(%iM1lKNl!yeQGI7$fc9r-__PF zvP%dqb+DE5oE2HRwJG56w%$+Yc3WJ&`1rHl>hmg!`*s!`IqNCEA|{jL-uC02QXVf{ zZ^SvSk!jWm?`a9Uc3e!;DO6gi$fv#K!-1EwRry?HS2uHXa!!A=?CPSTE-8r_Or}5g z_qQ5tUH$O-p}_W{omov0+gY}{uPtA-LU`HhFN^nvo3q_#{h$)+GgO~sPn#plnk)Lbvod(;s>eZ~wwqJg6sD237 zOmZu|Cim{**8NNq_XVpz+1Hi1BXhyIk1nAaf6IT}AUflfO`nkE0Sm^1 z68ikDA48iP*lj9If-d>a%TeeS+*t*wh`n$x=_r^2TGUzK||&dua&#L5)^DGvL%Pn`;uw_rBAa&ncg=#@wI@q6Q^ z{r~Lg=D?Bh?Q5j>+PKnyn%ZlZ?#<_CP8NulPg%0KTIc?CcFB{sK2^NidhXA+#Dwa) z+7*F6_i(gS$g_prU!J#;_f74K%g-N+t90$R`<8j=@B85Gd;WhbOxVxsGk^P)d#CrY zeK*}QpZ%CuecQG>*H6?*-_YjyW3pj=;>*L+>f~COCe(|>Pf_`Uq|(|mOGxfih3w>Jtv&r}Ff97M+8XI@`rFt%hmI|q0=JHu9%GcZ)lshw!+ zao9oTX#C}At3qUMIUZ4TF5RS{bt!OF1Pk}lwHH=3pIjP$VTqz=VWCJ2H(#Ajm~70P z($WG^mV^8P=H}|I;+h}pJr}yJVL$%2qWpc~cRqnxq046N^K`hXqdd2xd*`235*4lT zb}a(V`;Yk8&Wt>>==qOb?d|K!1Ls}+eP@1hfaVOI4;@E}eav+p@jklg>-~I>zf4-H zr=p$uJcAcaNBU!?$JRZLDT;V7Gf{c=Jas-&@O5;_^$lIt$ZxH5TrD6t9}y;`w=i#ssNG{|R3rv1Ic_K$u9Kbdqglu`LO zQ&xbYW!(q+A9vSA&Y4#^t={lma>pgBe^J66wUh3> z$e5^{kRiQe$GePAas@k?dF)?KQnZ{jeOZ7G)BE%Gt27jOJ#~yoZ1!^%D}+DmgMd3!tfsi7wla=nSp_Uv%n*= zn1Ml08H5=tmfDvwFfg!}c>21sKV@YRwl-7P9&g9Mpuphi;uunK>&@Q3{dzYG<-Uc? zz5I8daq;`RyHCf~ou1^{y(C3zQ-Z345Q|%igqeUsL;b1wlj{{51zAqWFH~@B(%@oY zoR)k{1eM)JCgain$pNCjUhj+BZrZ=t_)&h<1q&8XSbVIPO)F#iQ0Z{K zK~14vK=n{@gXjU)4etd%zO{%_c4IUE1=|1ro)3%#bJM;>I@B>w&~{J{ZDnLJ?%;4? zRm##jq%zBA+sd5VH9K|k#ctZEhR$R1*uFk*`X*7M8(U(oC8gQ_+#Ubx`@jDF`e()a zy9Jt0@BQ$zhXDXrL=aGT3Z(;#@wYo@79TXQr{cctDgu#3OU z{(f(Exc|Im`gIS(_aAAA58s?^d|Jy%OLQxTi?$E%Dz@eiyKa4k`TxRB{qauw=5lpX$Ap;& zeHJddn97~Cc138yGL2N`5XEH%f*o3CdVEdp+un)$|6~2W-)_2JcOF_N;n6U0=AknQ z|DOGRo{%OWIOFCCWkF%%n@4<>S1w!qvt-tc^)osq1~C~oYbvU;ZLgnQsC3vQ-EYc_ zhBIe6XLimMX)sJze$-kVW%u)>zrDMc&AKImiy1)afB$QizdQ%@nLh2Bl@e;2w$A6X zx6-d*O~?+9Aeppej;9Nn`026`!E&sO@jRJdgi5IX>ap{-w*# zyQp}FhJ~&OnZdx-n5hz*eRq#NKZDY?5-b03`(LZ`_w${|o^#2^#q)^#b)nCT?HOip zWU`&%vGn(NDbqRU#AjW97mJm*Iy;KIIR7&R#xg$IiI0 zoiFgJ9gA6 z>B#=wEPtgI%n#F?|7gnl&{z6dy5XyiC3*1#h#uUPryy~KA++&ImaEFz*IM&pdLQ#M z&TwT}Rb{l)Kc)`l%OO(p5WJ> zH-$~Vrtk_lF!dfvs;?6eoH+BKbzYjW_bM-j2|@?vI6OJ~|6fFXov}O9t5ofAZ%R z`{V72M;sX3dVbVT570E~-(GV;GJvhehnM9m-xZc6ZBhc8LmLGWR+&7#EUfHx`tV(C z)1yCMoiq-$T{_2}Q{nIg#~;=P)r+>Og(^4y^tmbW&x&m#*NW1PsL)8pjFkowt8c#4 z-~Z|9@}yrq4cUUW-P6{rn%t$v+cAsdo^#Ou9=qLUi!;wX(>#{o#w75c z8O}3D6pUubJ2xzdTHN0GZ}AalcnOAFnd>t;{ioAH~Sd>Ktw zNV**DW{^0nv-*|Fs*45EH`(8xbtwtkym{tXHtU(Ua+HF#O{(0p8)i10307qcFb?p( z&oZN`oof-xW?{jzXG|0`{WP09jka$4#IgHmebjbOpFSt|rmt<&I%ayfM7t%;cN7+$ z!NS$R)9_1P?U{?ql&B)rO&**6<#(r?{QX<8*rq|r)BV!BSmP5sYsHk441OC1*(x!; zE$xueco6sCh|RvkZ~G@Q)aP8}a4N7fl^JCn*YdZB6l{6N+VEC()&1<=GdV_wBYoF1%uc z!T}atW#K>(;cE&hW}#*bnrTPf5{$hWj5LI@7P(|5i86L{L??CiO=VnC@ot{yUxx-8 zNkIw3T(Fd zXcke^e(mIyZoX#@mS^Jm4V3)WZYr#}E5CSA!0L=vNAF8#Ua;&kOZu=Rw|(P*f06yk z4d32>v+Vp45c1%I%^mBC|C4`d2DFM#aryYwBK=iq#|nmLt~@*|;yQmBvMu0yVBO#F z@`ttH)&~>i9RfZXO_&saSRrrz+yt+zS)nOCq3%6Q2}k~aj?nua^1AEu)w4&=`1A8B z|6KLyoBW}I!v}Jfr5{g~U1-Xn#%0>sH$x#zaVryB`#R=Hp~g+GmZ+KA|2k-X&)};0 zl`qG5gwISef4tV)T!10)b#W-elBmrcXVT1!H@hV5Fgr1I)ts{jYI3UiFAAM*7e2Lc z^^y$5;3O{wRV9N7K{f9uL|kg$<+ukgK( zZU95WfoHWA!p#l_MiHS;G@FH*MbiPFLjhqHW7j_r_p$SUwXknw0`#(V3^k19;9PNAC*`H7lwHGmUr{p#O! zp9=ne`t|Nz=&WTwKbM!6?_U`;Z~w09Lf@3|RkM7rq(4XtXUGfr;ugATrK<7gb*2{r zjhbham|V+$)Sf5Qup(%xSFl&k2FU|6JJ(H}uwa_zj1ZBN@-FxO7BO`wCKWzc-+y?L z(TejGH+7ayxnUjundO?$Z$TqFwKvK?y+bq4pK=stpExtnt8<2=W0&(e&NG(twwEV= zxT?4RXSYkcyRM+I=*lS;mT%UvI2=e=GADY`+YOe%pZulgE}huV!f@ckWdC!V3J$9$ zI!*{G>tVWfvAlc#_y5uf0S2<^9~mZ8J!Hs`$$!P^5qeO@xKiQ%By*q(b79khJjomxJAiHdX{4Y|4Ip`A|cwSS5v6t^tVQ|dogu6${0 z_9E3+Szxr+bzi#^Fmf?#Tlk5=W37na8!tQiFBGjKWsCtvv}Ub#oTNYn7=-&n8Yw~<@SY|su~jQY$xhl zIyIj?IKuL+zIBt74!g}Au7=|i%2nFuNz}@&xm%OCceVeKlzU$T-&;frd1@ZN?Q?L= z_J*e?Eg2WZ$!&Dr<-2sO`+UkmTz4r zMNAR8(!F8Y6TUmvTk3>aRJ{Jx{1wn9|IOEnsO?3@++a730xYRy*bbO}5 z)+$Fafo4hh8{geq()2kNNp)ZEJEUR3A~cmDkZH31iNK^4Aq{fQ{}>khuB(rC&RMe4 z_mtlnjvw(?zcNZmZR(%2=KWuG3*q<56-{L`uE<f6N}%qs!seR za-7GFt6}b&bhgdQchr`4zpwkgyW;cLenH{X6}F~Zw;#Kk2dV|XtayDle}BdM2(&yMf=Jomj#<^R9m^WyeYd<@xoujbq4{RRJ?p8tF4s=EEhm7h0XpO-TE z%uf?x)%Oj-ryR4G3%@;0%QC-X_xq~d`zL(+w0ZXN%W5t;@4y_THluR!+22(W%~u5P zhCSZVShQ!J#X>E{PT}m=XPA`DJr+;3bU(X@p=0)%gTH>WW(sVQQM=COEZ-$5pdqPH z_&D9~!j6~WACDWDXyiF|d$X}QPnFp=-L1h`LSlllzW%|EfW^_*+><%qyR1EYc~3n* zr(ebPIPn>VJ|a^rg-*vARi?|Yyvi5f|NTtK4e$3C8jWw2CrLRRQ+Q?(eoJ`X;qUCz zYS+B|`89!I*||CCezK?Tb%&(i-M+{n)H!keArS#x0nQyVUAb!wJp7;d-Z{QguAN_E z^B1=h*{li9?H%6)9bUOEmcM@aw{r5POSVLKq zx}vzVL_0!Ogk4#6W1HyfT}hE*C$=#@>u}Qiw?nB(tE+$i*TO&7_WzfE@R$Ey`>JK7 zvFd(B#ihaf86JE;9-9w}rw2vf58D5g|M&a;PxksR?)6`m&j0siu77T7ZBX{y8J4TB z)mY74R=V@~?%UIUzWdd+{LGAb_Qz{>9WyyU$3pQri|d)E)t_#b@0^=^&bG5`QskX8 zfBp8~*E!2G&rx$n@fFXQwG}@MI=QF(Df5=Ow0hqJcg=-nC$?Uz;J^5L)7GimW-Q)* zFo#pY-cmJ}8PXOmfbXQZ#zTq3xm>0lm*hRpHnToMtB zoo$T1J$}#Su*$|tZmseCZI|{x<2<|j!L$zPqKDSs@A;l;fA%2vkp7atH5VV+maMSt zQZD_b;=|JR%JW=he}6)5sH-mP(lr`eoz^<_?(XnkE1k8rKjE9iWE-KkGnfB}xx&S! zZ?kUQI!2Y4*trJ2!Sy}rng9RjE`0BLmT{N80AnaCTP@3ZYo>qz@1sv2^4;E+7#m*y ze(8cdZ7;z!uZ23A7G2}jkH7cJa0Tm9j;s#RsY?4!ar~eAabm}>_x@Q=9A7(mZWTEZ zCez#D)LrCuN;qy$g?#;c^LpkW^BI!QD$fPaJI64uZ}+{9K!%zl$&uN0KOfz#|6#rV zv-STU-|N2D|M{&Sx986p6JP&jn*OhM6?yq+s(bNh-EPX=J0VNe*mWgaf!i#9lR~#y z%U{$)HyvuUd0u>7%e`+`<>Ou!uYLR1cBEvo1$41Uq_!}2B}8*u9a;S>cJud5rStob zwJ~Td4C>XpVV!xv>dl&00ski2l=>{_Q;`1Z@B zV06|MJ-sO*HvIbC_1W)_L~oD%bzc4_?~Cl70A8tj=fGR(g%bN0y6b(EzI5Q^dRafa zRS%z}*c+F6KKil8&T3VIrqJ=NdSXjFnb$Zic~rF1{Tyd%bYS*UU0==l^UghfXPzX& zAph~lx$=8;|DM|a3jhD1{Qva-FU{}&KIvcg@$B|{RlC+@`?=WoPiA!M>Ta#8dX|?4Fb1+*PByUxFAXHHBNBY_3lM=yY5m(O~=yXW99=~4nNK2;I#z*OU zon1RFZ;{+}v2oV5whdeMs~tUigJ*^7oQA7uFS6!+2;y=(;Fprk8MdfH;Ro+6&2PL( z%kS;oK2_JMWJwm6Dc3g}+h-Cciy{}W_14@-JNNcuuP>i*d)aoO3Ez{=EFR?d9_-&& zreaj4`}43o%bmGFO#YXZFC{lW4SuvQkDXzTEu-Oc_a`Tn70+##lCczAX>j-9o1m=r z7um5Jr<&IJZP3$p(b^WYP;24_?X29*Ke#xLEb!u-`|nn7^%5?xy8+qKfx3d+8?9LSdubAw5=O3*7y8hqRiL;(L@JXEh)DXnAEc4JdJ&UvItF$6R{GhS% z@P^*@KWp=Af7}1R|NjGj-P>Wy{hz(_|NQv9-@yO! z<TaAPuIpG}-exK?z&RSb{IOzQ+;f7TUx4HkTw|cSHcx#@O zQ1P3s%lDc8o#AqAx2~y#`8`JYZzs!04`t=1KZkb6N3@<(TkiUrMvE74$yaw50%4hn^ zPE{Kz*%Yl@y|wg+s9Mt|&S_tpO7CvSm3Gm3_g*d_`{1s%J8X0!wzID4I{lP!>6(aX zqPKT3ElD`1k$QNSo?^^m$335uOJ^0|KU{D`*)i1cc)EG%{$FMHIwUmBg;sn~^ijUx z`GPCu_^yKi9fBcy9KIyq3;TF$*9td9HkAph?{8hStaoCGzLsVr@}#>UVnf1Pww@$pI(Y8VZxf*d?zWphZ_1CPdnYV++Vl* zrD@3hpuK;DpRK+xTYgw@F~g4zR^z>jTmLn$|MN54uDrVX_p{^k?Cm=_k}us8t=*v= z_SG`$=BtBBUoZH&u`hLuN(#E-ai??gwQQZhG`=<6FCT@5Uvt_xRUkuu7x4$Cv$J#@+{=r zy!ia~*fVKd-|B+*EcTm`?Nj%@ZgI5PbGHu%SFQ`wH(Hm!?$_hJ&S5jSgcvouwyblQ z&JpHqGyVK}%_;9isuXI3*0_CYQ}h>3xOMec)WoSws-G5h#d>tE=?{_#T6Fwe?ViPK zYZb0G@4hc+dGl%SN@2FMeO--ZHyCcDcFkNIpxkz}P?h0~t4~ zYK=gVeZRA}owhDyvsmYP&NoVPi^`F1Sy2_WJ9~E>-jo**yyoEBjOP;%2n5DVDdn9J_*(X?wc59)cyLp{@=^>bx+Ul`()U#j%QkkR%gnm ztJbx9q}Ot-Y+DeIJ$ogC&-DvAK9+5mmB7^)vrqi2!*VZIO}k+I z*Ik>$uB=Vcl=g~L4BdFODK}a%$&X2!HG1WQT?=!xLs(3oUAeu>H85$#BbLot=h6jC zXNa{gV{W|gW4Bo?Q}&{Rj!fKU)xp=ZwQ3iMx`-XuES+@crwQYXszYW0?wT=v<>_zb zTeEoflwa*g(kQ;qX!1GvxgEpD)RheF>a_|CzMKW`r|m7s+VICt-haX8xDyivpJjf^ zZfb5maL=|oBd32!ZIPeUb;i=Q|J~MQ&sLrzVfoaL<*XrBM#^s4xaaGVI129TWq$s1 ztbPGA*VJX1?h878S8^QF=4lhTuC0Fmmw?)wO^cPciX7m{^g3~J;uMjiGbfuf3M6}_ zOEAt9UiSIr12&HnXI7Ltr#a0_+f(yZXnN^K-d+v1*v1R}A9v+g%wJ!yQ^#@N6_rJs zJ9v~HfZA?XoK9CAz5MdiH}n1fu6^J4eeLoyHY>IKgP&b7Rr!2F>pqqW ztGT~;yE-NmHC^d4kE@q`?my3PevR{iCfRpRYKptLUanvIN;}BCQ0yX;<}2BvH-+Wb zzJ+aEr>!^LJAQA`v~O*vpEjMYl0Rb9`E$38lR-#~+SQ{)ZxU`K)wciN@$I?n`iE13 zfzTnH?QhBe_(6*f_Wc= zXOtzXx|bA*&)>Lhwj7hw?;A(>Qp|Wy-kTfz;5wV~XHLxppRN@ypHgTypLy!VduPof zey!NMzx*LXvU{oyUxjl<$esx)j{>?lR5TawxASm3)*m;yztc{k%%D+dw_n2LNe0iG zb_h)A4w=X}r$*%AC4qHKH|Bg$yFFZo(?mCk`UD^PS=0LZwf6lU1@Z8zPftwGyx)J|&}rq^=5OCi z?;4z69$Oi}$&|W1NX`({a9jJX-YPb3-~Y+=zs~=A{r^>P(ASq&HPb_vX3kSw+9VO6 z>+$l+_w|-#o4hq|Of#z%o1vj_&3faJlj$#>sO(BVKkw1iyV`%A%$0BEH29cTd0XaO z+%)cKxrcYHy|GPo(ysrSsfTyz1WdhGyZy*p&ebPhKI3zLZ~Q1?*<+S0m8=hm^>Y`m zPTi0ZandX^v3KjCf~?o8-?4c2?%DeO(D5mEuKu3k)Z72)t8<{k+3ydX>lMs(>woMx zF!_OEp`bzFt5*f{Zmi{2msMrh^ZGoWy0D{Z-L_no2?s?U9P#i`IQ3!9jDXkAIE|Mc z&Z`k&o+DrW-aSx(OV0V$!>?gSeiXlv`lEW{M=O#P7X_D4`o z;hSZi^On~BJGXG{grMk|TLhGDrHWNC3ap-S^~z+scCSPY%`(ybD;k5oz3;44oOpw^ zc8zM5Vf$N4uhgKBuj>_gW}SPUJ?GrMl?P94_B4X315TFYYIiph2J00nP+V{;r!0%2WBg!rvEH`VR}4j z{`*z$_3Gx_QM$G$+2rfH`|rO#x|^Yt!W6Rjv09T*`{@{M8IwCV%Q|NN)~heOYMDKE z&E!otVw|?CzN>wgBQLbYG2T%`Lw0S~OInY`6O3Co+7e9?Y4@RCrSJ z_p2C@X_{qUTubyd{%|JkK6+6_B48VnfWqqa+OxF0GWaBFR6??ySBb6Z?(d#&3Iv-KaY^`Q>?Xr33CDAp6Z{dm9@EFV{%(HMi$3_IcfPdeaZBWWhDJo1$1xKNS)> z!?|?Vl{`&WmP28zoj1A@1vfCh-qpskb$)*sL(XlswC6TcN{{}mahuA!Y9)9DM!!=QNQd_CS z=4(>2Q}i8-ix0eNGrwOW+;;2E!)X1hw)do~cXfXFajI^QSyA}T%P(?*PVHW9UAD}= zSY!23n~M3Vx07$k%cQKRkg;uZlHNI?JgnYx#Q(i0oYpWU3rc3V9*HxPj%j_sd^CiLIFGkbI%FswP!GhSgWmaGK^4kAx6|h#k?^liNNk zOB<;ws2ZF-(V3X2zo(n`XQd&-lj^4a6W!;UH}e&5_wCrKbuIPa>f7G~SFipatH(X< zsP&s5?QOY-H(3=H7rO45JDK7Bje@4d?~Y2#6m2SqSTrYT?bVCYE7{ITx*d4>Fz@=R zfTK@0J*cr$-00w(en_YKp~&^0tE8`mK2mIp@|K9=Y+(>RdbsG|*RPUi{5bv`GvD8; zU-$9zkFEOuxVHHkoK2TM`b1`t-#-0onf|c< z`|tg~^ZP&CeP8$7H*H_j(vZ_`t9DP(ah*QTdBL*C_gmlXY00bpd?nlX_vKFhSTn1Z z-_K^t7dy`GZ0zY{kePY*n#_ei+eh!O1 z^nQOAeAMA4!|B3zwQ2TGCoJ{l^G`QhqW$h@!?l8$;qnhxnEp)r%5>p|xtiBeSML?l zzrGenim#c@8ePhIptLx)xis>3SF&c)>8Fa<{L6)wbg&(7bSe!$ps32T;{7Fe#>t{EgC^{o*z21V`pX4Pn*P9MqwKje*LUyO4zaM)Q^AP>pS-UULAknY0<%- zHB7>Zr%qPNw<|R`Z7qt`XW)7MdFHj!$2Pt`N5Yjp?b>;ATA%e}P&Q+EwA}vRy~*F> zYd*-=fB09Ozv@M&!W+-C*8AoZ`Fr-CEt@kjZYfLR`Rk7^$b4)%a!qK;$~MWqN6&t7 zou9Y2?TBd4&j;uCl|Ngs_eVzTmYZ=5CM=5%-f-(zEReCe)qn5nI^Frsy87Q+US8Yq zG2*k!?AUHmpL-Y0&z2o|{$R?kR|`&m|7Byd-So&2hM*T)vsW|inzo1tWtdxBB#HQI;aiaGArzT%NUs3#UI4Z?^%5mOSJ&D8+f#CBF^go0_R)pefg**vwMGlN7ES5e6uM^XfiCaQX73pU3uRmE&ONl7 zxKQEuOwBD`0#Co4e>huRWOXO!A<`%$9Zy z%rRPUThKi)(6-TA^ofb`QqJxAd529-F^MKgNW9+m=<3_t8B#mV{%_Np@l5jeu6Osi zU$I;ZS}o0xtKD(KJ?nN?<-Cu#UZ4Niz5mPUif_MOGc;U&$rU_rZu^2u=Hc76J~%m9 zGF8`a*_qrYjvLiZ#Y+Az+PR?X!Lw&=dehl$YQLGxym&e4^>Uxn(;5D}++hsvYbkgg z&98YZ9sghT>aSfZ{hmDfI3^nelwLSbc>_hh=6tnd-B;%w@RUT6Jd5jiZ_zX_ewdfh>ouyQa6Pd}tTpDbx@N zF+CHpY{t{-^0`567v3fRPxLL9=_!`tDvI3h@rmo|)$(g69~Qs0`uuNmr?AEQ*26aE zXZWe7obw2F^9$|}EEHhXG&4ML_0^#ekEWYp-Uq|9mw22xtzEMEq3DBIAC`(tf2o^y z=ktdG&MT@WTue;)ceh^It0Ay4@5=`HKHJ)+ zBRy-^%vdJu6}fRWL)iCLkF^Kx9*+-S-ZO=ze7)U)?fXBQ+139uy>rK=^hl$mLz`FY ztfa_k4v)-i_EtU$-fmVF^!B)0Qg2bLp2qFA%bCZz#q~R9PU@JOwf210+Wel~k3d;a z&3yk)?xQHzy_ojq&yz}hYACE+V zg$>uARQ;Wy(G?c{H~8?TuoXECxjSOy7G!BG{Z`mD^I>A7gNviW?SO5%TYg`xeLMH^ zgZZJ(=JT&4u?Tdw*BtFRwCctxhm*cDXJ~dc#YUdLa*y?YXL4C}+xoC)=PK6I zRR>ddwiE_LSj;XzP+nfXWB>lcM=WQ2*PHrAYs%UcPv3K*)22L<`T=TBYA+>eZB*~3kb3#(3%8!A@ zo-{-lN`Iff_wQGH&A;XLzgGJTyf8T*yemd;#xqTmB+<{Ahu*$r^`B?cm{sa1Z){*L zX7k%B{_cjU+&oNIxiXGUSuuOUoaez2$GKK%+5LQZJ|Q+PF;c$3YHq;l#}p^Un%(Z`R=#Uy8+6H;@ScqkL;f+pnro!Z6KAn+)@!8^;F227T z4o>ji8O8;mK=Wt?PMySyXM_gvut3 z#V4BPEcZLNSEsz<->>Bxr;48G$-SMiOfxrCdNzZy8{>!1_y0=U@2Pp8|M%nkKOdK$ z+IDZroJm~@OI`LkEm`=pFX31C5|Is+Z~C^|R$RXDX#LgvC(DaHCWxJx_@ke%`b^L2 z&yveT!^5u|sKw|>zk4t5Fz4WugeRZYex4#DUA<-Xf%=O?~CSa|;V zVlBS<_$>*YQ;%*E%}M=wv#eAi(q%)=(a%edMa@^Zz?|>tEBLBKYLQdRoM-FwUd)|; z__gJnJ61-4ulrnBmYlU|JUL-Y!^xB7=QJPRyJ?=R$eU_;WMg{Xwk?;=zg4ztjZ|52 zBPF3pgxglJHRPbl^A{)o{$3mX#>4x;-b$1XjPzq+HH#PS^!!!C`d%&ShGlK< z?aeyV9m;uJd^R5PT4l9`!L5hsfwI8o+xhj6gYW-2z21I)(5zywlV@&}Z?iot!&$#> z)AXuvw<{u#1eDaIw*{47y5cxvscP@yBX3R4Rup~a$(;4!AG`blt^zyz!#``9Q+4fx zIMjEaK71+ta;SI5;+(r~;jBA$f8LvWec^NG?=Mug)aKW>m(EVNF@9KLl{ianO)7Ki zqz5KvXM8G&u z*;%IFxqH{vXnE$pZ|nLK_A)S*U7npe%V~+{uEj~sXXWL1wr}5Vz^pf&Jtw+xrL=%< z_u)sX70kE8er-Fb#u~)EdcBG5!<`woUf?+ z%2WS!@%%^G^&itKzAx7=DBu6%v-U4v9+vrs%@oBaPUt`TH|@=uitWW;*E$`uv44AV z;!MSDZH>GEUmy7t&q^?h82#h&#^|t z8hAL>?^Rdh6suSh{4IIut?zH=c7z!gcSROE+&lehF{fZi;q(K#K3!R&YhE{fzgH{n z7jS!nj-_wBeZIT9?}95nb7zSikkRO8l@j=NRxIc^i^QpOXV%Z2 zFD-Fq$NJrs<#(Ud&z_{RGicu1DlW~X`}kh9_9keHDlX_>Cm~vI($$&8)!3qA*woS< z$Me&$mnC;$#b;~u~m70HqgU1=ZEYNvc&3*^vQjH_usuRyV2`1n@6QnEbE*G`M)n>|J<(s zoL=$$?(`Yw!xiQ&aP!C%-~3R4sVHrOq*j*7j4g*hrv;R1MlN&XI%6&3#hDSd=}3au zm0b@v<*Z|x;jehpYem+ARgAN%!&ffasPDIrY3D94ndeXPsxKO@d)<_}v!pZ0xcuGa zO^!zvZDD#9wjtErbXzL3M1-7}`fk=kilGXtBJ@w6TdZNqWfuR_XzjY6{x9Y*9MDa& ze0ssm;LPUr>HEHZT;3o#&t`7z-HR`C4xTZ;KcAm7(Wo?N$uSQHQI_UICyNxgE93bD z_N|?p*?vR!L|sSWq?Kj;4QjuNT?}r8d1UX{Dn3EX#oqpUw8$)}7bo}4J$QHL1>Uc- zUM;Z>h_c`|^KY7C@rALBJ8{up)8CJiOD;U94SpNPc6RB8HmNk>T&~2|eNrmt`lm`v z?oN%2V2-v~bk(x*RDj@_<($EGm5wW#GQBpMUNrfqZ!v$KrIUfL$K=&oK?=HeHM9)l z?(So9u$aHT;x^a$<&~GT&WF6+oL1)R!v9#$GD(ENzCAH*{vYxGf4=Yka#;S~2VZ0B z=AN59Yi=Kj689~1+fr_z^oYfAvt9A~`a_q>?wZBKW{Pv1s;o-U2zK2S=($o=$6NIN zuWQ>2zi)W(>m+X$tIJ*qMq`ifqMD6O$|tQ%Za;hVyZ7dq-KT6)eJc45-Mn_OG03dr z$Bcss8li_PPTaifmiHkjltD42Y{&n1??mf9o%8>2uD`w~e0^L}toZi7SEW9OeXf1? zXff*q$L`s?fBc#+e9`OUOw*+-856`#-jS~|FA#fc zw(pg1jq&!+_pb4%rHXIkWIty1y!=M(^)~fo9z9od=R5D+-tQ2y>a_fGo`%FHFWP5S z8aW#;G~BW*l9{m}dWi^YR9D`d1xz{F#S_1ri(9=uw8$&*h_I8F!jmVP&U>6aWd8jk zgRG61T&HGZz-cj|KJcZ`{0$>x+_Qo}ux^C+?fwyvOw6ZsBs!Wc2*QJ8FNv%Z~s1 zD!l&X!=lQ&XEvRFExfW*JxFbZhTrnlb(2K|<2lzbJwDb~{z=|AIXXQ3B(vdsmy+m} z+E+Z!EWMq4BR1i~r*E};e!ttjBS!DU<&(YT6BZ;zO#5mWY#-<@5_9Ux(V}UoFW1zW z2T#n~xoh3he%(3d0SU`iL>)L{G2cI88uz>R??1Mlua`T2|4)R75YvhSU5U5#eq8_m zEB?`3`Ts2C-@j|5I&(2e`|_Rso)^g3z~VD|;j2fs9(SI*-tj3 zuJ=1bKd3FOf0kPN;*iho&kM_^Y;}CG_Ha*Eg8r-z9o_{l*)@k1?+6^`Kk)rax#7|? zn}3_SC^E7gXylnWTRZpa9Ttr{%(8ua2h|o|h)*~Z{w|w=;dTpH_s z9}}Fx*Ws$okL4{f*T=RyTsDY@RcWkajE}vujraLw-gocb zEoxX-@#zU0KmYd?j}|LgaU^WLZ!5m^)W(UApZ~r3Hdp@km8b=2IcdvFW9O|nxnn=5 zn|?m?yMO(+1p(lYt|&u;KOyT5Jj z9P_hWwhp`G#n?X0-gM0OhIPpSL8jpN(A_%TcYf6TpEF}aZg$DSCK=BA*LUu@G2;`9 z-^$t7=bTsH^DU}x?w_8_b0;iIZ&<3jtz`ub)5!n(z+UluZh67qH!IcW%`ne@+VsBW z`|TaIKbf*vT|}3ux}9RXG+}S=`C}YEW^gD;A6m3x_4BQHJ!b?Nxgzc^s?Z4H|HZj! z_UC|OoAfp^K6qE-t~7V|hmY@OIy;D(OL5KI9dK#$xefVG{KT)FT%qP@^f|X@O4{~G zxyQR>9vT=Q6?1dSb92<(8OLN^dQ^E*fa1ggUzINQcV%a#PB`6O#9+;Tuv@G#sOV-Q zOD2Dl<^$Hy>p=$=8!z}PP^#U-QOBdV1?UQ4_)S8*}%qJ*4@t#_p{L zV?+4%?eC-{#7=7ZdssFHH?51-KlWEjMQ8PId6Tt$bA*D}W@k>b>SzG9|BEGWSJi+0 z^zEDd&vV=NeHAl2XK=2~%kFe(*^WaKEPtP!{gh3K6`oQp|_{`=LD##o@uh_T>`F6CMf1Yznn%~8liPzWj zAKN>t`(Z%5`X+-}8=bdrlD@R%?tiyMS)LWMmbuTqlE${w9lJcI zu(b5p5l$smOZ62&*VPm5ExaDJ{ji*!Y?#1J(Hpm_=2({8JtnYp$Mq^*(`(Pt?&~Qy z*`>aJz;I`8P2;9@8^28pXkN=(tg$Qas&C1n)9=h{y*4iIkB~3vh~eq)Rx(;rF!l1Y zSK`Mj=E-i;J@EpxYKDsR+Y;rY6bfwqRhO#bQz&XoV|l=^wk`iFsGkkNGW zwx*`;2R4&leYzwfcD!@q* zexSoiV|CK)u=F4Po5dxUH71?iQTM30!sf1j!UD`$(SF+acf{DWRcuU?(XEhzZm$xUGa&5)YQ2c|L$ zFS9&c&~}Y$>P_LqJz>c?)wldNF29%Xk|l%b>6N!VS9L_bCMh>=R*zg@&Ds>Je1LmN zk4w*-;P#$a=Y)5hD@qq#HfgMU^>}L9MsN3U*SsTJm=^p<4mP&V(&~7#y41rX;lA35 z7E9@6pKqQl-59DERi*TLLfsDWTZzI>ixY|>6Vfl0=P|w1o9unfTubCx>&hKV4EMwp zEm2)Evwz*hCD+7R1s^K~v-MOfJ_tIt?*YtZ$Jg&4&koER;e&%%# z3 zDjNQL^5p$T%9Mpu0@fbP`Sv$&YMYkD#nWqJYWw!;NV|xhe%cfiHvLT~_xEj_uXio- zdRv}pJb$kl)3v9MlAO11-~MB&ehr_cwbjLr{Pni=ytm63XC|(F)!8p2c=F`TC)SMG z<-ZexyVupQrC&FgvE0%s;n0-jb4&C2ei!$c&k{8(esDce=Q5YU_4~{7G#+!6H+a0t zDxbp<`se*x>7^4amz@jYSKF()Lc^>}wm4vo@2+dj(_XX*Gfz`G$^B|uY2ArD-=2MM zFYc-|W{v*t#`pU0lU9MKCNY!!ncQLfyLL@?TywS4Lr3=)S8RY`O^!gi&+Jq3Kj+ms zeJ{JESoTecA@^xt`Q1+0N%>xr?Y_NCvVEKN?%Gur)y_mF_Dhc^_3e|mdEf84`ibCg zq0vwELUR_jWGF2-*ITg8QJ3{}QRn@GBA-NKqfWbB`svtf#bZ`3Jcf%;o#_8H|gf~LHmYn*vi|K zb7CAqSKptZ`K`5;BW2(3_@!1)vZTz5`64D;N#?Fyx|nU9OZ&WnIUnU>7p|Pm5O~NY zRVVwX^m_Z_{&kPuWf?H5I!H#CnIB&n#1Lp>qm$S^OWCtkuXe*c%V$@6TBbW* zHS6F^L)HAet`MI&3knV?hD<0rw)_2_=G2`D^VH{@OJDLNJHbD`y6yY@-bJBCJ9++b2yLtETv%;TD9@f}BF0oVgUw(I<#cnH^L;eplj^3Ws+vdA&zD3g& zCSir6v*Zr%c0KY_K>X9&V?()13Ewi6jhQA5E{=>ZZEMq8Zw}SdBr9i1gUb(6M&L7w}GG4#Nn%$wQ;xp0N4A%;;gZl{GPuB1Mvsk|7xqRK*?D(H^X6~6bWAm&FXLfJ& zi9XLIyMV9Q?{iQ4Y1ZJXGhue?0vHce1uQC_8QVG4x|(I~r^LU!7hUJAe&zL)0DaViBFcSOZT7mU3Bdf;Voe?_InR*PR~!Uihca+ndBLX&u=Cj(oFZ+c*)Fn z@@3&D^)`^vVb}WCTUBn^xvv$~kb1JiR&ZpNBsA;B#Z@djS>STT5%3#SfmDu&S=Ec{wAi3eUW< zTFx(e^G`m%`?u0^P2){V&b1k@Ce$m(vt8c*^qroD$YQBvu8s3&+^v7HdHd_D>dC)j z{#E?hd*R0R*qT3w`ihnwpDl3wdCv0%@{p}Xe|FCTg%V=p)J>WsU0vRZ^& zwVo-<$<514n_tWSb<1Ise!1?P6CsXbGwz<8ct%KS(T?4_O|w(8LnKzsU6r@+Q`)p{ zp$A1VQVsjPbq{Q>`?6U6?{53wH_zWoTgofAvCC-Znf?Ra%|4Afji;jKFXIdk4?p{E zzbaEuE>qB~-V?4(Q`E~j&Ya!1&xF71G2grJ`mOuj7Vs4`&v?)r@m%NgI&QHVW9>~+ zQ}(~vDtcESJnq%e{jn|qMMW+~LY`OWif^lWz~I@W!fE^c0dG$JI)_tDg;E#4+dez_ z?d9&feC>xB?^nIQUGcbg`@uqo4(3gpHt)*y&rh=p*~t;P#EgMy?eFJS6A$@Ri8##X z{k1J4#rxpnwPF8Ti|n%3H9Wq(R;rO%`ODnR?^3UJ=xWQx#wqVU-lS}%xpbE1g?-C| zE=*%PFypIg^}-|8&uv1tvT2xeaYWtx?-g9Z{j*@^=FeID{#h}tRiVa=7t4RX@?9!n zxA2aJL&BxKTm9`F4;RTf2S2&Jc<;JfY&&8uJgwsH4K4V2bK8pR$5XB26~En^()LR# zeZLyxmEx!!95-_phH~EB@Kx0F!yfkUoG-ZhkKAF1X3ERl5hA+rbwPFY?p=K~!V)g2 zCw?ws*&#EX?ZNvKU)I~m#_#?9y#C+w_h*W4X$veob@B6|>>Iq-5>-~r%3h_HT)L^O zD14^X=_l#?zAg*z%lsIqzkjpOntKi#JQ>Yr_x@h8``^94&#yLjPWt^c_*&GD?)=}s zOxN?~uQ^cEERpi$jGx1t)z%B{7U)jYZJ1cRYQmZ`M~e@nOfoEa@tg7dJiFtUm-`#0 zGqv(*>Yv&_>0h{dZvFmOk25rDRI?YJS>-x8H#%}{t0L3Bz73VO0UHj*zG+uvd(XCg zwP?el)N{td8pX<@D(-PhD%U#bF*>K8aMDb9?sDi;#8cyQzCHO9=T7~u#=FSHVC^ra zquM6xnG2(uGP}R%IM^sg`y{9S693O!xO`s{Lx@y+(z@Wz1qMf$r!HQw`q(zHnnkw~ zwyyAzRuQ?|EN`INYL?e^%SJyz!%J-QmTN~AWcbFNWBa;VJM`3RoixW~K3gpApIR9> zIjc|I`|_Thx328pDzVn`fMin2o+*6g<>gx)Pfc=gd%`g(c#2JY-kj-=FERX)wcNJ< z$I_DRkuRkUTOs^TOZfE_ciA3>Vr@_X_eQd`-s?7e>YS*7NKv)5n0c8T!4R=W4l zmj#K-4v6XMUi>Nh#N`;rq@EKS_Z_R8Gj0FWO;*Wn=bGMb+y1w{M0rWhKL-7{n%3|4 zt1lai@NCsIJNnenWyw0XH}6Zny^a=0Qt;wXvP!vlnhR1ENedkK@<+e^)AaqnpFW=- z?|m+o!$t46=AR61v&grv9-d4zyZEKH-y}VGzxAce%-kUEa7`sQrZa95#kt!#%o+9h z-tMy1+n6N5mQ!whr(Zwt+oHMEJRKsRr{$z+ZIFl(P;{A`zjThA!}>Qq#b-AkJgH)4 zIoZj?an6CMm)|IwZa&T+ogF`ALeQ}dHxq2`C2zi~uw3x7g;E*wvXg(`&z!SfK=rbfP(2vv+pOO( znKdx5vuEjtsT0%!8|OLS-{tYDYj2V4_P^P(->+J3db78CYSF~hRnJ82olO+2U;52D zbaNKRRS`RT_d7E*S87cty?W%qncPjL`zC7H71-{-ac+Oz{n>8mzjb$VuCA>u_LDMs zEW^3-+jZZEdaJeg7^Re!-3-xww7y!5b)u5h!Z44<2Px-Nmg#gJ-QILJeesDR(OCHp zkB)M0cpfG(DMeeltkv!3?u?03D`yEheYuj!%MQT5bRDWdD9s-{aY$o$DAj|4m4C30jkQy6>9M?KjIVm&!gfnJpIQ+*+>P*yW{G zTV&sGF}d-s)Q;EFW~Vj!UzNG*^{n>#OhsR>CWdmwl+7#O{_4n;FgSax?3_}9J9AfO z|IW>#D`&rLaSm9a{^MrKv|1@I3%UNho=q>Vo#w6Czu)PF)e@E*bLk0M>(=KL{C=c; zep@T&B_T`#2V3l>h9=Zp5HoG1Rm)1Klh2d=1!Opx=Aw8p`Pk;9vGx@{y z>2rA9{$Gq1g&{Gr0as+-zSjH6{r0zT=;gdCZtYqu@gW>X6|^j*684AhkT`g9-3GQD zB31rcH9ud4+Sa>F%ZqTDa4tT18q36%%P%?jRDaDraKNxMUcRHUh?(IAkF)^u@4s@_!^3a9Ex(ale&g*n1->8M z^8X~{>pyYs`+KmR<6_O_nUcHz@8X9)8 z<7gWFR59^tuubf?6vGsqt zK+&dSrcYzK_jl|}O^dviq|z;=V&dj<*+Qyaq4$MTzKg$6^lN>)|1!1rAD7J9aGUQz zf=z>fHOtwrn^#uEC{KW0IAHB-z|6A66H?LiQY1?kywu4NK({9}A+1Ec~Sxe%J5Bzoi z-#?!Jck};yvd=k|U*`OM_tfIo!JMH-Ex#fz-r@F0oRX=rpP0}Lin~PUXmaJLI66=3?Ye#p|xt*WH zYWA$p;>e53&&_-FHEYu4m?f24)=1n+)7kB2SG2~rVT%_J>!fyb(M3x%{l#AFj}g}G zoY?v1R%iF^1o7(N?21_l=lV(-r8lqWnNze^?#jjG63WL4Teu9Ka)$rzU7cQKeg1M& zNygr1LVd@X*R9JlI4|5F+wH}E);jd3UPFD|&gQs2Z{`oYcK-X4jjVj4ygRin**yOCkMH~)vF)?Y zm^?S^ws365l>diva=41v_JRrvx#q)U5xiyfgUkljey#Z%o_V+-j>ZiId3+@ywC5q9*sEi zgFiPhKYqGh$Csls@AOMOJsr79RhX&OG;+etFui|KVv&nyCPsd~rMOhmkZ-HR^z`)l zzb-6dhWj;GFWDsX^yo}p%i&Zo?azyir%=FRw#K{svglZQ&a6a zurb8>!<#SL{0uPMWiP}x~*_dmR{{f0lVoFI-^u_UnoDj+;g_9S#QQk zKQA|%5Ya#H-v9gkBme*G|Em`4wy2iyFysIE>DP?2b6TBURPVqFo@Uok7;q{xC< z@dA$<-v9Z=Uh(l0tBBz2++6NW?99^*@)^dY;;I!BBN?%L2UEaM)>9^H_T$gjRTcnWMj1yB?I<%N(hadS^aU@N6b$)ZJZDHx@ z9BI9!4Tm4f#iqY#+`Bzz;(^M2carswXIIClX#HnvUuF0I-}n9h|E;(C`9spUROyr= zi`sP0waX-{EL6Lmv3=5Kw6S{{HoM@q=;q0Drm;O}F*(0FDWLw^<*PYd+ZHj2zWEmY zojHN0x%K9o@74}Rm*yz?MVRc2GyLV*=a=GtxH!JLoX@1qK5<^!o~oZ*j|*L9rPusA zx!!Ph%18ZwkMuvN*MB;$D!|J1p!)uAxqVeXr&hn;eUY0zXM42zugFO2UibAGTfvRd!m&x1t<+b^rukp=G^>P@)ru@Gn`8^;-rKB` z_T|7S$Mqr`AF(E^tIms$QAocyEBtz#{nKK-lwIHEZz_)y{mVf;5`-;{?otPO+ z|BVfs<{y`^GBErlu<@mN!iQIe5B^DC@sOT*hF$4w>RGkW_wr5-_h;|yU!=iO5tzym zroE?VAK!818Iq4*)QEAc%<{10pKkr)=?(>k`wx<5`TalXe*gc!-^YLdR=;iMHq~d^ z1$8;~=s7QPuKS&m<49pyxF#(*x}(%g(W+-Yr@~6%ovJ$m=Pn8M(!0v+lD29=(>qsNqw)eI=`IU&pIP@6g5qHD>)I zHYY1XH=LDL`gM7$$AL==I<{~$wEuY_H7W1^{#84~O+zCWKk2zpnxOVP!9?(U$+kF+ zZwHQkRh%JP6xl7}5trF((z0oP{gXY50-5GSGd`Dkep)*zXY0RMMftXfl}wtcPp0&o zm}S(KyM0$#*HHuZhNFiTJu^w3qxR*n(*&PL##sxUcI>TfHNRJL?FYk`j=~RZ-7;Ti zP1`y{J0s}S(_5;7FGEsRud-IMig~wW`r{^s8s>iax-aYZe_q_b@BiAj@3Od`N-S1= zXXyGQrEt3?r;Cr9nnFj^o7KMkf|aK_L>v!w+;L26RcR0u*y%2A#bWO4`MIaiCP~Ks zgpsnZ@THQbj6)`K_c)|H7o0I$cBh=Rzy?XBb>FRB_->R)U!I)#2+M4t~EP zvcT)dm&^Abi0}U)@qIh{pR?!d8n@rC5#RswYWj~?-RnQxegDUL$Gv+G?0*+YnF z@?>^aOaB+l$#!=ho<3jC>vZg6NxzD4(5wl?v%4}T+f0no>j_ovu;S!j797qdBvdrd z#^dB1?wJpc7-)-a(`)#D+39Nc8lF?_cE;>0Aa#a;lmYh|Q-1wehnen7mrfUV1EsQt>+Sha2qv{h0pau>BwAJNx#q3O_t~mUo`*UdNsu zP2Yw(|M8&t`^QgLy-Q--?_QPL|LaRI&w92$ugv!!o30=4kkC_PygJaP z_8-sgzt^tuCKoIt&6|5 z%&RpDQ!7Y)$L>G*^lF2du3H0+qLho1|yh5XXY+tCCYa9?4Jk{N4_1uzX?inwqDD&s8 zbKqc^+7QVzms7z<^KprlVz<)yH2yos_f0a2-&d2VG4r&zv-rjD*K|~#%PpDns_S^t zCRQG&Nj(BgOI2(IW0`jxJIeC{G>)2o@8e7T|IePa+y8l39T3A`dw-(Hqp01xud<(c zt~Gy>X=eT`wKrwaOXhqmJ$-P}wy-zx&oiSQTs!oN%`|9LQL|3#q>q1o7VGEL3HS7T zG`Z#LZ(OC8B58QuxbEl2`wx1}=OxWc`}1gheV@AjyhnS#?`vK6`opWMy7#KTNB?;9 z`Tm2y-|rnwd$FHrOs$8f z?Ybip^P*6j{MDZpt`NI5xBTKSX{#;MIKo;xUwAcz*SuZLBT(_+K>0P1`nRu^ z6frO0KhrrwazdN^hXoHWvDfr`KGU#CPeWU*%+9@VaZY@Gs8ENZo~6E;PwaD-z-O;c z%nWk!Q+5%VU;ocC>CMDvEfO4a*_l|Mb51D^JEJw}cUg;op}+8>4G%N@qC;&?zWni< zp{{i2Y;e>5?5uzD|DD|bXL0?P%k%$UwVsr!Z`rChg`+siH@4qs?bKP1_883Bz3y@JM4jl6m?V1Ly!yxqkC{@h!;jwmdvNC6 zZU5!lK_lPLC*I6gU* zb%$iHn!}A7kGBSFX>~pwcip#8W6io(F+O!&d~w~M9-Vo+UgE)lo!^$^ZOo2iTGDVJ zHR08?^L|Vz0l`;$Q_^4O6m`hi?R>3#WXIMoex-MxNH%U@_GGiDED*kG;&3v>;GfnG z&VZ+@axyymesx3!&3)Dw+7WP@XN#MycG=&X$=f^Y`x!Xea$fE_xZ?MTYu_TTKXiTj z{Y0@8k0R*YWMkF^Z$N5Z?|Xf z-r8joR!s8fm|}UMsF(jhf(}{ucEsizXz6gQ=oTzK<-PgJuiM#|T{O?xe7pMX zLCPF<-8#mfik!aPiF{%|YBb&WPMe$hy7-uRdIvLzcAS>TX*#ZaesO%X!OR^}|0Slx z7clBqEzt|i*~ztOfqly>_X~&qrz)lM3HWBe_|MaH-T3~$&&L+ktewHUHMmMUQRigC z^An64Oyb{`cRTW1Zd&TQD?$46998C&u+u)LpD#Fg%`o>?QsHGCwpdnO4c;bG_Lg<8 zH{Q&d@O-1*C!GiCp+Dn$E?$e`ow#L1VG-N0%p(?k5^ao+Et2xTH!DQ$s+_0i)c_ug z$~^w?+dKO|r{(|u*!$8X&U@Bw0cFD}UM=fA*RT4%{r(X-Kex51+JcF*+@{}RRnHRj z-I)2H@oUPoOFcJ@p9Tx_-nmzB(l?}Ms$H^#RgM|6-S0Q5ZD;SDC{p^ddj3Bi`I--U z+ngPEUVoUePMSgRh(Mu~`sIk#k4|o0&cJ%4{2r@}+1p)wDqM0^#r8aMlTWj#&R(Ev zIpM=O>-UdJekB`}Czwg5+~=1tW9~aHoW#>nXlcHCwf61b#~XCG9P3J~RFpVw-kbVx z3(xlCaM9-9bL}T=w!CI&YqEM{a7N3fVvAjV`xK)8&Ne*wXlDGOSqcku+R_p}{*OQW zbdQ!DgTpD)H=dgfCAzodbAHSWXVNVS(8*Ws;QpSNw{HI=rp~P9J7)9NUeP~tZZ6-( zTWjsx6t?&t-pRf2;Ddc8A2aJCEel*DPJKW1I3?vbPi^UvC%hBge@#+$m)R-A@7y!v zkL6e&N&raQ#f0<>`-v4u>iUTh&8gGqSS6R%p<+_pI;{EkU z9~K<2=)3XFc3EM|3W3Im&|Q`D^wS)sKfc6JbGc7kKkm;%|9_v<^Cv&^-SQ^>(wcWq z*hM@6Kb3(2UJTzHc*6-{1QyrR~-9 zy3$hCi}8<5<`tBd_U^u2&B9gjKKlN#GUsy|`je$9vlK0VEr_`Du;O6;bvJgqO!3%x z{>Pv0UN^Ju_uK7f7j2a`=-s?r?Awlg`;J}wdim+}etRbxY^hrjKsetx%%kOi|e?Qx4_$$yq&ZJn`HO}`r_y0pZwI{lz*_+OAPU5zA zIH<+pGxhk!YrE|?eOEI-e~~GC^=kQ|&ED=;_pfGqk|W6*wm5U?%=L+GK~MS$zB)yQ zZ;0Q|y7N@;cSp@Hl`ofkxUhV`$nQ^@b9lz_pxbCy`Hwhfu;C>h2M)^8Q%_QCT_l)ILobrq5S*$ z11=pJ7jH|p|5o01`{1-3L#u@bVe8n656ltjc$@us&WA6*xZ?L#9E^RVvQ)F7Lfolh z-71$a9)6#m?vVK}*57UOG`lZz&-?$M*4KTCj<5aq(>U#2v}IKGrAvN4P1hVbnW=km z)x0d(2-sSHxl_bCsu~Tr*F*(>m13S!IZwC#UjDY$zk5T3i*|&+@=|PRcs<+p*S$OE zmt{J=VcSzx+P%c#ey)IX{{h<>)w9nze=*q?bmeBX3!BCbd)4OatbwZ^tyldgaUzH# zM>4+VBh#_qfYYJj%}?4BSNvo!H=GL9d zn#|_vck^u7l6ki;IoPoEPCw3nZ-q_5{oUFNYv--&w~rRz(tk6~`YOZmrE`nisthZeenR&6fIFPC7 z+)nm4S`EKs(pPb=u>2OOVtDm<-v47sJvVaLl;8i%a$scPd-40;CDpr&7i&m#eNt9E zdiQVb-|Ba}_+oor)QCE;gg?^B;y$g?G0h}H-C)&;sU0=ZpT2z8E5CZW(2-%E;&F?< z|99vAeL26jz(OYP*TUD4wuW=B*}c?Va(mfcK}mzySxwV4QVjM+PjXv#r;+Jz@Znv4 z^O*08)t?MIkaJ6YKjSKI#^&|=Ma|94zdoz1uI@gY*1TJs-6y#z%Vl{0AA%Vw=X`sKFs+g4e~^jpaKSA2XW%J-Pl{#W<>gzBxwADT3F2rf2d_&qy2 zB}ilSM+Vd6d1*^56^~?W+PmrVJYkQkJD8T<7jO(Kl4~$?z5ZyTt58rL*R&hi?@x(L zpXMa9J3zXr>A?+^%+?kGM;;DNwUY^3HTUnCx9x++)PsSo?@k}7iJKAb>bv3BtxE<6%T2|jflS=QK2^DxJd|b3T`_J)3lMcEq z2x+uaTCSq>e`h;a%PpG;v(t@r?=%KYsqNoiz{n%(QM{_~=$VB=IoyF|nE^}8=3Az- z#9h<-Y;*HfcBPfMs?eQ#cW-8Yyc*@m*z;xgGmDOtImd+C>JEIYXqnv7q_xfR`SMjo zr8`%H+iJWPA*TOs&i{9s|NpP$_OB75yVm&Jd36QlKTAb<_WD?} zy6MP0E{oQ_kfeLWx3A{gq50?6BxX;m3APBDS6I5Wc=_gr%tgOG%h&#A|8dR!-}$V> z53|}cXBqY?FRMKEvgF9$zqWke+2^=T=DsI?W=@8T`kCTGHqu9`q<(3I;coiG@$TGT7mCy9PW0BjuON;b8PA0rbs}c>D z+2VWu{;>(`dzHo5JqlS;Bfl;P_1m5`X*mx>|cv$Cp*ptKWhL zWT!lq|5soCD_y?k+s|}==EcksiULcg$X6WQ9*`&P7Q8P!;qRm5eHCZeH?PulRAub= z`mAXx@2aIQe2-;)b31UT>`~EW^XEnC?t&$!ZoJ)=7i6?^Zf3jX*&pKn&&xkNeLk*% zW5@3O#~=P2+*Ec+J27X^ z22;+uJm>Cf3d?_8?w{&!aJKkr&GuFk6GcNUrmlyLPu|Z-jbFET>zye&tmQF+6PWHsKTfW%zO=&r)Z>-|yiU$nziYNMd^EW>zt>R7 zigSa>>?ghM4;tpMelP#tptWn?VUzQvM<;D=ImNeE22_jhxp!P${{Pw8^0i+sT3bG^ z<&d#t3F5z<`StO0_v*`KT}92DwX z?C1AxlTQQ3RpDRzj-UN%+IL+1S>`#$!v+rutR9^I|CPVyP)t&kcs}Fw>6V5CGhG_z z=|~2oxt`i=ctTS_OR*sTa-`T3O-HAj-}_$d()ByO_^!j>RmP7Z@?W>uD7zU4&U|+B zx=fDQCNY5rVw*oqke~hNCii-esImihmK~QgnG?+9a6-nhDfFZEQB&_#M;Fxiv6gn` zy7|!E#VXcW z+N4QzmZ+!qly{4kvqejEZCuBy#2JuqM%YPVj-T+1cOU-zEdEm4KSgZ^b_ zVro##{d^+!e(J;{C$@N6zSk?i4(hGMeNML7^XEgl{oj}0-{r;I^1H|~%PWynO`|;;;)eWCpQnpQsANnK+uuhjto3kufRoU-yOXjQt zS5x^*y|j#WzRhc1_xb`q=l-8x^Do>jz489LL>uFz^c8MzzF)8S`AN0y#?`++Us~Ks zVPo4o@i9wVNyn01?-)E|i?3@$X`U=twzR$d=>~27o*C1#&lG6>aCLMnW!KmKw)YfI zQggj;^!jyiAC@(H$!v)DvLRY>J@=2Qt~if^*8j(~)elV52sdI7JDvRP$Kss&V_mPN zNi6!Wr<>Oq)xBrODHhXrkyBrvpV+2$YsWS=U&ZwgcXbOZ={~cIxxe0SQO$?ft0$@c zHC$@Ky{WEeQI;aNh>%J@nbyesk_a3p2g{_B*EXlYtzhUo$ERxT$BoTshzwZc9mCfu3q^~ za8#XtIlu15U;FC+$L;@p+}?luajCdP%E^TJQ#NsE6ioG$PQIa9ufp9Ocbj4IB>8^U zduLZ1Gj|mXm~rOTku}F8!j~vtUiJDBuYQoH$J@Bg2QK^cyna2KE4zF7yp^*)->TRm ztIlj8*T3z5__`-{S=}NcGCemcN^4tZFZb74zo26Aaf$FfEDpYP64p;temt2R|8V#H zzj}P%ze}|7o#_FMzCE}9pM9iH&^lO6rq6x$9*=`lVrONXIP}IKcjmPykGm%dyL8N^ zM+b7>;|M4{m)w7H=_BR%80o`B|DIRoUDIXr_ZCy}ntC~qW8O7~C!ubCPE8fa-uC~e z%N~yxtD2pduVxFsV{Ry#dt|EE)8-vLMn9IUSsN2_yR;!}Wd`?o{e4{9v?5>p;qLx- zM{vWNYx2?DHFJ4BI#vW&vR~RWeN%M!^O+i^+YUG^cu=43-E87J**yE?&bn9Em)83o zad=w$W7a}PXBQStb>V$%%7XLy-0$4K`}pnl`x~Y0fI5 zD`%bBD&V+7Xez(!CEf;a<^oGS-UHb;8O|)f`+R==KYsh4PabcdQOT^ZN-JC`Nc`@Z zrJRhPb_eNnzfIGBBki<3KUdvqt-0=1?dkqIFUKU?B%6QP@QEejL}T~EfS=}qVM5wU zhw`?s?O*ES_eS~7y}P?OyA+BX?w8-l%fC=+%fw#5@nSb$>=w~hCIKV&Ek&Q#hi%{u zvF&@DR3O50&VH_2j+r!QpW?j}K6>l9D?U9r#u>%^@O8-^_fy79?$!2Uy%F;-TNEZ< zoU(f9m#I#1y~$Z(%o8pL^&}-Y&pqE!x%x(8G+;1sm_!mZ!2vdbup%n!Mfm z!?UjF+Pvp;7#FF2Sbjq=`|#Hl{Yq&ogtZI&b zFMhgL$LcR@ZNs8C^)A;>w~BZzTC_}EX8x*N%f^uNKK_T%!K+4T(@d=r%@)2_cDcsO z$K*KaO4`aj=DA$EQ`|bfna`V8DCORBIb@sb*XJKPjv5*#&vNs*-14@pd;Pn-zgMya zF4{e>Sv+g^>DX_ev9ar4emv^dKXhEazNWaoet+__6_Yxh4V=VYC zKGVVzjs!M6m%$f_ zHpa^}8(tp&dj9W)$3H(W@2C?tb>Gu!n0tcB;3=m{*2+&xY_qi#;!WimBh{4O>n>0Mov?BiYQRzF|&V&7#G#T+XSKZee?xvH~uHb|U$!qVve_mj}f z=(ov&dm<k8^`rUD3u4#Wgyai&V z|7|%IzIKkm^B7y!h?PY;Ci<_NviM4-9Sw+nJnMsZLi$hrcaxYjxfr9a34b*`pdwKZ`zhv{X#R7s|Q(t&@95gx9xc5QDQMJVl z&YLIy=V&-Kb*BI6Q+m6PCB-C#EiYqE)N8XV{#?zq!}ax(jRziW+Ii?*-tvQUjCc9v zFsUYNzWdL(IJqL9w_w`c?^RkpTF*@5AJj%Jd**9@9i5dx)_Zwf%Tmab&~I$i<5#6QZXYG&%l|YfIj? zKTL7e)pbTH=?2@2ER}P*IE(^9nR5l#xSqTpzuJ*M{and3_x(OMO7!|4D|s$?`oCNJ zM_Q7YzM9O24R^c+^VTdC7g}(Qr>i~c_qGH2hR59!Osbdc@Or4dp{gR_#9Qf2QNcF% zbk^+U@Cxin&@gOSQtN(|XN8GZYk=351m>r_bE=u<_Lu`7E%Bj6q=l(MZFAA}C6*Hb%v}B4wpZl55TZ&k0%wsAyq^l*X@XtOcU(CYZY_WTt zv6JF8vtz1`YuRLW-t-M)T~z(SdiJgbLc!)qHoXCvPStY){mA3J*#t0 z@n>m<4GJ1h=WLf_dVaDfb-T|M1-AI-b=&iF9UgA1-D#3Nr@e6Z>1x5`Kd%ov%)1p) z^+0f=_r0(<_JcM8mukx9e$WbjbSL`3#-{y~IOnZpvM?}^u7Aw8%cMY%5tmh{a{-rJ3 z6ua?Sfq1n~_mj7~GXj@eCT^CTQ1f=eq?_FG{l~K=M}1py^xYQI{Y3%uFigKlJaEEjG38I!P8UkrJp?? z`gQsA0PxDuxWkKISLbYxmThBv{4${Q$s2PUrBwmj5AF(C7^EBbqNz1CR!uc%f2O{M z!?}~p30yl*=QQ$~%?W2+GGTj{bb{CB*K>?RF5mQ>trgLI;mwz z&&_bI)_wt}BVVtIDYiv%I42amk;<>LW_P}Btu-loO?K%;VMAki!{-hsoA&ird_HTw zcIFJVB~!9FyzhVAm%ddaQjptW*0YNbUw(ZO=~3m%p3hT}E48TAKk&S~*NF+$&&6-X zHNI#J6?2NMwfJb1>Gr_%^j@E;=ZYp;dZMi7mef@2$g`Ne;C$emqihw5g144+3O2L8 zShZl+CCM%Cr1mHAzs;X;@Z9R^HUH+!l(secJKz7wbIsb;v-!N9hM|+#*VL!2E8E-J z!v4tXl(t7t1&_W)!&Irhv%4hM2ya)G^8D2NSK$Lo_+xvO(J#5(f9>+y6z@;7UVH5z_rjjW55GkN^1lS}Uf#O1^HkO^?VbYeKZfNS z=cuQ2>ballS7Vok){;;=1o;L>5aC_uBP$KY8ioMy!=Ow^`xV zec_EfO~u#u?tiP{8)yA+R!Dz%V$j#;wYe@zd8{s1uU+G*lbY8sU%G4^3rFbT{WaIT znSZXRJb&GU<+--_)tKA{M)kjQ_x`_@d~jVmhv%*+YtioeOD#921#i@dD^gvgXCKK` zl=EcQ!JlSdO@C!AFtM$@{`gx-HfQ6%---dgU0b$z{MK>md9iEZzVBw&X3s3Fu1-Jf z^2YGI@h&~KMFOs$rmm<_U%In~Yx?7&7^#NquQ&qDXD7>qzJmNu+)%~2GRI->jR#&wCaXDpNV z8-Jdw$?dfFps_^HiL@LeU$c$;hu2MdARys%Y})*1EN3`p<@_~x8mudFGdFAc-`7q$ zA)%LDm#;ju$v-bo!SbqMhJ=~emY{{H$~Sy3cbu~nJruH2aOw^AqW*@hS3cEjsx??@ z7Q=I$xhde1;936#V)?8sJC5+K;YwV6DB|sjxl?~cyf~k1{r2B)T^Ti!Px(IEJg%@vI(JgqeR7o8`tB^%P`m9XEM)lpSv3_$RZWm&`l_@k@@PeT zAGiy*ygB&#_xX9-XaAN+R$4J3OW`{&|IzCGKRS~e=LY^?-5Fmh_W#l8b-r#5sXg7! zKU^6Ts@)^SHShntWin|M^W9Ci-R5RR=UN#%PfFN+KY9D@hyN-zEz)zi&TE!==+A|t zhl_$7B~+XpJ#Lm=Xk>QUSth0Ergr?j zXTfN8Q`o8F!jy?=pP6R33R*dAjbF>8pr)_gVw`p9%YxMZJ+rn&RES-h(3*BhC7yo@ z!~9g;hF2@T8?1fz=l)k)H9JDP;wYn&*5`fI}TBQd`?{-x%# ziTT>^v=Q2>$PqB*45$0j5C@r8$@*>1Yt!UJ=Q3VPvwPn9?{%2ev-=ZXx5P;;EvnVI zWcmBnoJr=3EVvVmZf0)0X6MhU!x7q8g%gcBww9NGEw{if`xw=_gJ z7l;X(EEKwXsyB7rhyA-5&7$5sEj&AY!LQxH3?;`dfO^4}k|%ov|G4Eo)TrFHXl~K5 zw>9Z4hMRU=`F;3e4YL!&;j&HFuV24fcUA88rz@xZ_U~d6JK8eqPyfshPp8K#oRy5_ zneqJQ<*SR<^QNVg`<$^aCIA(WI5!Ef-8Do<17e zuU+F)xwcfFum4C`N%7@^K;d5@*W^yKoG;CP|GP8lzxcIXb5bpDEXfksciTH$D09U@ zdzXD}9I3ntc8S_W->$oh%~PHvzT8Vspx!{P* z<+l`;O!@GzUH(=UL(hxJBCKw2nBw-?B<;VeaD?F%)3J{Xd_4lzpFd5P>^PRyZXWfF z`M|$BENg!kh1CB))Twc~bb;%y^nbs(SoEt>X4RJOUcaOMNyD0McBYM{N=Ljk`b=}0 zmK;65U~B6V_wJ0lcC9bgU*w9;tGgDYz`3x+IhC>5(NHP7Z3$1}{-Qg!8(#nFI@0o} z^ZoqEl}|54e%>)noLWQ|&9?qXVG0nSpX@L2HP5a#v_TN=JzuA^e=PrND97Wbl zFAnDeZ{KR$RDY9cKP=mKyybF6;8hvscX9g;mEDLCYvD=?TleCW`f_$&1VYz9u`gB3);9@YP;?B+8ndlkuw!$nMVAN+rIdY!y=!B zPAe>*Po3D^p~I+SF?}WDk}QMjxp{w%i89S#Iq6xt)Pv>xqVt-en`TU#^Lwgg?~N8G zvs~A0PUXdW*^LEuGzYX#VSPMf!_AxzbMODlE%B?K7-A_UfN{j@fuAT|7q zT4aymgR85<146$uGwfQozM!~Akg?@pXGhHBCn6ztKmGZb%+|R+;>7avY=K*u=4iL< z7fCZYm&?m8uxr!$Sm!glEG!=_3{J>p$E!=DE*(!FkAFhD_Nk z^)H3ZZ_BttkEYMBZL2g(Ub}5)V9K5!ue2kU9qn28_|(;vue-kO;$(bm@z})oMRI%a ztUVjgyLid2eAk|LnbBjqHF$<<{lmi2(xtoK`gMA6q%f@8HbFDA!^mRi$!}9{#=JVk zcb(f;GhyxW8tc@p=BI*cp3gZ`vtsK{RxS1g6aE)%Whq;39XqRkk&1@g>+|z$R~PK) zSn$5;OmP`Y^QzYOKj&?Y>|fK7?>ccqQm(l``OGVQ$Ca0zv|*3iSJOGic%EHtkVBz) z0MoYHvATYi(PmAGid_OLC70+P^wn&zwVGLxxc_!aMBL|3RpM@cgoI$9uJ^yTO-lW0 z@$}7n|23Z7Yo_r#^v*5lw94V!dFzQyhZfU8!LEzCQ+-thYo;6ZJ$rb+bm70dOQtOF zsQCDZHL2&>$NTRElG&Bq#Ff+h59dsrQ|Y&3|Ni6u)^0DbxF*w4}+^;)9l%^wdS4*coLYs_`x_%A(o_SAezt_e~ z3xuv^O^`XhDu`oWzpv)QU%#XjXFR_D_N}hn&nLorzTc~kKYcAl+p#~nUjW`}gvbN1Ty{XRS=Ppew^(sXa`u$AT)VMbn6+}he z+AZYfmgFl)-zu=M?(nwz=|=<>xOiwL%ebG>)LogM6}7y~C`zH~Ht+i~>zKFSckH%T zR8nZ+b;=3nl)P*bdj7Z3!`pG;tFjf0!;jT9{$9Us-G%SA>(;N=j$iQFDyN+J-TU{3 zJkGif{_|`Op0EG++3N4|lxOzl=H`AJDe-e=yySmWZlT)RB&-e2woeI8o`_x9VqYj$J0k|L^e@4wQc)e}>74}9@>weYW^l)17_ ze=4IhqZgCg8ow?@m%|_C?7mQXF>rN5-3z%0#`*PSjm*m|A6M8cn$GcQ|Hggq!_U@! z{n@bSz4e`Y_ZGcQy4=8Nyij=J+zy-FcTz!nUn^qyUw!_1^{Qse1YP!q)!H*wG{szx z=_>vCxc|rrU#I!A=gmIo%i|~Dv!FQEO380I=iJ#7YGid*^D-IuP8L3V>RqgW(_-=U ztAkd#tl7tZBmQlng&)Vp;zJ823gqYK8~UbQnH9oA%mYlWF;!EPLhfiOMR2qxNYbSK_?O;$B<~Z7|Jw zEqbzY*})){(^b#rd}d%tDk*$8Z^imMSA=yqTTaAWmGDtjzA!~O4# zIvvw@eSVVc=H?wS;i(iu`(Z)FcYiC_oY4PvcN5p|CZ_W8@_%-l{?}@CFs;m5zG}J+ zcv)fGu}}~gPe``-+wqN9-ruE>~f~g^r_@^^XfCf z@pCWCIQ!8@I%t8#%vCn^8x_R_zsLD+{UCnwipAUu{Cm}TC!H3N{QY;Txsmd&a~*N9 z*Uej1W}IBFE`O_YBim}`1wPOAzdM)z!9lice%qxPH_z^Sa%r>ws-~S@-|uJ~tNC*0 z(oTmj5f<|IL<>5)-x`;&ZZ&o{5Q~&xUv*~6*vB{s7czKua?9xD(n0aiM(X;d5%ERnmN-i?D_Z6Bx(EY8IRKy7ikGN zw@=rPfAsRQ`c;+_0y~vrQw3&Qr+qB8km*ZsGd-lWM>=8IoX@UY72qPgrsm%Fzw49U z@C*B$T(W2BipXhthV}|xTX&!RmX@{eSH!_xYu8nLH0J+jy2>@9_Vcw_G8rFgsuEV- znzbt;VWL@!@q<@c_urH@Kj#n7{gZl2f4$-KlKnYv-UhMUdLA6Qr{<@Sp&QTPfXSbq zRkCe-^zPlcZYP$>J6X?V9;(})eWF-wLrHCI@8P%JF7b{lqTV$;;pvM}P2Fl)#I$(g zezDC<&5Rcujav0-LHFvH`^`A))?F{zrNsJ0G~jhm_zq^bmebd~fBc)reEs}{S!#>+ z#@%9&)iOJNPUdRcPQM)CA5J-+O`SF!Vmo&D*~6X-JKTg`ES&W)=ac^LKTUBDvhQ%8 zt`0xD`WfQ{QN_~Abwz$$*B6>TFFZW|YC7liV^#bbYfmwC8wx+Tp0=)k?xY3pxBig5 zn*FopU{V*C@qtzIc$ZoRWgErqtztdEQP)~M{j+Ds>Zcj_D?ggq>A&%l?&a9mS{ZRH zcP5;?;oMTBDkR6({_9tW$nlQ}jT)!CX9S(wv3vJXcKLn%``&B0*w1A-Ki~fN-_`36 z%;QzA?2IwnqPkP&ta@Gh)WF`UUXBHm*;8AR za;M%&3-frKa(wlIMXEE4^7e37OpS_^EB|YC?W}v|g;VdR&UjfoJM}?N_2aC*TN&5+ z4mxj}GkN0XCTWvnPd0YPGq1Yjti61xZM$Nb0$0V)PfM5c?y3yr*_vpVzhnk8U;AOL zeYdJZnN|c}efv}l(j2K0m{|Aa`Ttkj-v1VMaB>l{D45ifw6iNT@8{vpbz+N{{?8Xa z;e1gtyLEN0xZK1bHdnjifb89jr8{hYi=vg2Eakgt#m7h9J&#we;yiWs z-?L}S{N~5RyjM}&Encmp@Qh^|pUe%WnJYT}J3Y0Y@;S(Y>uoi+;(}w3HElV*MQ&oc zmgb(#xxj2S-*TNc)eY{OnD)%znEKo}DcN}D=}RdyvQp;$i&z%uoO34goD7$3E1%?} zb=CY|fB%rOZ*VOQU}k&$I`A{cr|UHi#J> z?QQ@2bp1Y}##+)Y%8PFBZ&N=9F*-4Zo@ z>xv2Ueg5~HId%QXrdTDtmFoJgLK$9DkC{mcs!Hdy!Zpw5FaP<2o#Ee6 zScAL5rt*_Y{`P3jGg?Yf<+HY&n08A#(Xd`~SHjUrCEHZyn3}ufHiwFRno{vZ#@zgT zSXXG|O*x*F3AHn$rsXt>Wlepy?E3d(+xA=ceiL@s+=2one|#%tl@E*EaBmDBd^?}vPi6w{c6wIwB|&Ko|dO!hjMeYWoCt$rYv^Y zUo$Pn-S^JMYbDmx?>A0wnDyz1|&DH>1QGMo#(K4VKiF)hBC`#d9m z&HwZBcbf>U7VTNjppu#&!rQ9wjCDm|t3!bK4;SCh?(2jSCOoV9tG=C8P2-tK;|dkU zZA)ydZ?^q8f$Tu$D7H)-?D+w-^VDu`jx(0R(L=(g8*`fTp$o(G=B&J=L|5FmD4;&;i> zl)7iDmNn{ac%HOBD(FRqXMJ*GML^$7Mqh!>bF3cc=AAR09b3xj%Bh&J{jQRUUQ6oq z$ga(zzH8KOF?F-O3$uLN`ZeF@U(99J-1%15pDh#VzQn_@tV*M7pQ6FBLZ|z)ZC9tb zo6KQP_{qBM6Nl6*yBQn%*5)prIlb0ots&2xl?pn&pj>Fwti^*NhQlCpHstW?k>rVi#}U+w~89-aX?~bV#?Ryr-w%FCcze~1<+(u3U%AQZM%lg-Ri67R z?0(lQ$=DJyt261CbHmkoS8-)E|JywO$~l5oc&GI$Z`dQ_zO~xDF%NT!`F#3G2#`)^%@KBw7tHeA7Z*^!pS~Fg9vJY!e%TRO_ zx}dPIjlt=H6O*QCy4i);{9Vp|58tId&nWEUeJ8k`BlF@ZwnK74-|x+wmEybdK<&lH)WfB4=!YJv6es2&)C3fV|1!Bepab;#DwS?H|Ndi z+b4$p-+Aak!dAcLG>3^+i)Fv93`yh_;o)F-5*ix6WRc~OX&)-G=Ze_*MKv>@HCJ?) zkX@8Ax9Z!^vQ?Y~2Xz{*luCVZ+TNVq6#Dg>_wuC%>N6Y`1#DF5bvd9kRqk}E%tDrv z1qpJ^Qzoc7sxrnbS)0E4y|cmYr-^SG+EZm5(`Ko@jA5F|aaiEvpD!KHr;FdYCliy` zAlSwswoLzrYyR@v`aq84vag)Ej)ve#k zbYPaqX4cb}6i?35GFY4c{I;n;%pBnf77YHcb7EsMH_5*>Srxmu;v3H-@8ph8RS{9c!W_|~|z6MTOY%xQ%#IMfw#xLcS zJxw7KSA21k&|E(2f=ao9%7vK^C-2>!G*8`Nc9{dmLao1^aT6xZegF8ea9;oMtS2UY z%t?l4omPo!9_u*JGyU>O6N`B~;hUGZC@h^)$VQ}a*J-x-*3KE3mnaJ)(zTx$#cr4$eDV* ztP_IQojkB>?W?YI$Ga&W1?A=42U;F(aBs6*ceL=p=g-D=b$>eAm#Zg> zZhB+7{q{`4BZv1${|7CI_$ToVc7- zd)AX}TkqB^UcvU_>yHJ;vlsMfuw-3bx2VtmlyUO+g~3mZc@OY~@{6o`{61@M`204x zFFP#%8ME47h%~yW&b%t^XpB|j4uzDfb?=SX7QN&@F|)0)gmdNAo5lh=yh~25n{-wl~Av{~QZOMA)6U$(FTV?SV$5qd48|^%|W}j!fzV4{%+}cHQ zYvb##JzaLOgxg19`H4r*eBGM`nZjm$JMzsZ@{P91iF@J+cWcwq46Ygf3uSK=SrfbI za;NB0*FCEDEIqW&F(tj``0#4$_Ra%dLE_mDQr_J#D3fX9*SL0iPGf5W&(Q~4&ScIs z?7L{4=axEU&iP#ue@!)~9ZdBR&`{uGzPGI*^+#)WM?BGwXHkv>aJ=G$)HulG&fdb6f;)pM8a7Cio# z(Z65bL9vNhF?BVU{r^A32Sjh)ko_LQdD$d1q}G$A>TJDp^Wsw+*S&bVO#HW6C%$TJ zQ&te*Gp}AUWtBwW3#K)D`*%Ivlu%W9@Z+;(T>DmNX>beJbiUHsSQ;I9y(3?I&Pv_a zQI6iri!!+Kf*9+rOkogRy{hK(lPy}|8?t^s*ZVLh{6JJh`PH&pGMq=#zxT=pFf@o| zZ|%BgvdzKY)pfefukYRt(@GC9y?WX>ch?L3OU%!+H$X*ByCT;^f7-{N|pEz7;P57#kjE{9~y9&R^ec|8uha%3sU@2lMjh zv84XvXP9KP>@w$xqyrn6VqQ0SI491w$(z4m%YtBr+C5%Ve%&nIdo4((#P{D-56&%u zA20fIeE1>5@PcQyObUBc;ic>c1=^WsSvPFwdooQTAoRWB4wItNX;(yT-%UEQzBO~* zo*z>`sa(i>?LGO<+64!SFV1Ev%Vjmlje39kV#m5G-+sBQHSpCbAdcYJE&%+sNnJTLy%XV0F@SqHpIO_VSBtSQ?aG5@j9gXcd}l$?&tc)nDP^HsG& z;kh@H&pI{w>RpZ9jWN+}w{Io!v=gQ5S65n;dvN0{08k{iC=H1Sr#=uG|U;4XO3#D7|jm2xBVYD)nl;f#u!8lLO1-*&Cz zJdnND!0=RJeE^?Mt?8oLZrR*p_wqlLE>=FaN#*imenzd3iNDrbP0{+2ylLs4kJGmA z>OJx0&&<2AErfUnJ03x-+Xb>fa|e=!g=qd^2a33&+ETrsC6u+?V};jv6m)~O?)lhEmD1FxWm9AIq~{->y`9Ud&%W~MoIBrR1s``Ln#>ZNF1Eb*Zu^5-3}URSq@tGYdny)@ z%u_LMdDO@7xxa5^i7`tYOZdfjuS&Jc;@&-m`?c3s9ZFDgUH-CV$NrC}qSu~!_af)% zK9OgR^LON)&99ocsO)}GJ9EbO7?taMr?1_*?q(s$wYXYn)}(~{e%ph#?PUJ;$m*}e zVzs)b7hkx{u39CNP*al>zM?EE!FbQaVw)~@b-tL1f76Z5v0ixoX6mOiW?Smc=P0ln zm(AdMpO<4O8S-*-gsSY{8B4Z2){otvG)LvDT!d2S7sfFCH?i|RRVgi-CE4lSo&Gq> zGR!O4v+cB@{z;+dm2n1h#bmzsX?8f*{)^sp?rY_I+22JrG6r+i?(DsJanhL%?o}3Z z*M%{FYu>lF-jxnhx5YYcCRO+Lv6)KVubcW{_3Y~F|K#U(PAKc@U=d`# zk?YRA(D4JRkvQj(8}RQ3LrExN0iy`kn>tY+-Sf1iu;I(FZWtb7RqO2*T8mY6V0WhLp(4Jp507%^>WRFe1_FAnP`Qwps1HoOp9 zwUU`}-TBQ4Ek$ByPB-1HYd?P6eb3(g;b!HEVWIPuz0_hW0ku9w`x)lt=jYE0N!|E& z;hChDYnJ}e{9Bx4)*19fbbrll*Mu2CH@EH5as0E#H+RzkP1Pl-j<0@Pex1Bv)vU0J zCz`4<{p@=xtGl1)FE0%Z;|g6~EE+I(l0xd@k4Gi4Cfv_Do3H(9xp;PS*X++rrYPKW zC^dB3v&ZJ)?)?2n&F|MV@7`@)^W(!o15Q6%l}qQsZIjM%nm?U2LGym67Sjf%2~)q{ z=DIkA>zWDYwMqMyPCocfhJA&%Q1|KEOh*>7y)2sdwDyg_3XdTVp!1_wz|aR+?-zx#me*Q-h9wpd9PIH^&5`2LVcSrI#s{@cE~OH z&c8d$g`OAj|H^a7KegF*z1gpeR&AGgcg1T>ir3{7-@HZ7=AUlqmi^|w#m&1e-sov> zXMd0$e``m#a+1uMtwpWz89|4ZPZxgo?%juXx68M_KEl(XFvst*D02ZQc(<-gl=%1O z*}Hf4{D$*7CNLgRV!mZ&;wXPLlX-$xsA@4wYno?c)hyUrfG5dQ6JPYSJYX_i*WPz; z;Te{;Eo>8mEGKUND}I>aN!pD|JW&#nLJ9_+p~vN9_}F`rkDNYj{Ah>sgNtd4X39*+ zP;>rlQ*C{trRG_T$d74L^$vtN9CK4^DddoF7v|P_m31X^xqjxs`+vU1CrY@@@l(Gp zlkn#5lohiWZvI`78_js&AamRX2LY!wcPHi+U1OJFP72&x|JSWwZ^umw)!ALj(Tf-p zonL)lEX`iLZOH-GIZhj;+iu@#oBD7<;q#5Fie_^sF3(#Np&ET=nX`UC!OG;cI?A}_jnEC%nYnY>-ZojxRTYkI^M1LckYld(BKz-` znyd^<7r8!~;>)~RsH&{}q1}V;r+j9!L|zH_&$L8m>dv5JylX!{+Q+xERO!^_`~8`I z%O^L-?lffBBYf?);%cpDsmDxwf1LEMYnmb^y-q-oF>s-~=+51+aid2cpT*z1clYms zGx`nBELBz2L_@762ZWZ0s)V=fsbt)7&3^Z~nliS{J34$7QqFc9Zpe%)cs^~b2*wKOxk=0|; z$D*oZr$2Wu{4M)ZuD#op(yK_SJK?sJs~@PEcMOJSG{^P%v)iKQQZZpGhO0LKQ{+# zQQD$izBVi8(~baBGtcAyUQ9l}Z*s{0wGm3jJ1_P#Tv9JMr&Y)@Kl%6TjS|aL%im3T zv$$&+d%_Lz#}8*$EnbuMm{nWgROpG5tt~R*K~{DF0R=p6zS~yzW;hryW^=zwTauzI zwRq*NjYktET|ah-(Wys4sQlm=3AS~O|4U}AVl8`-v#I@VMuU^-UEagC1-@S4IoxN@ zl?AdSow?ki=r&`T$i!u51f6|0?Rh9sziySX;MwbUA#EXVhK?`$f3N@FJze0q>nA2I zv#aN4Un@HK&zt-I9xm%}ckQWrv)aV2+e=K8#*; zXQrHn^i3CqVXUveIQ%=r0BPod1l+iw?CuH<1p*=4C~aaQ=) z#IyQ}3xq#pR=r{6NMFP8vn4ifv)4Y8tebs7VdjCiPb_r*x&GFPkV*3c_6qa-XME4| z#rX51obq!#8YLEKcQe=*^hy1?`G4EieReaag#=ue-T3?F58bLlkp;2kD<6dY$T_m1 zOks&J`%!^ik6#tAcirhU`uW?dUv+_+aE#uZ16y^fCZt<(eoa@X4su=1=acUr%d@^q ztgZ3SqH={DYVW-Lv_lVn%K3IO>{PB!iPhXUpB1^(!q^m7yM^xL^!Y#UR1x!oSqw3t zjzRD1ci-|lou^zbx|C>g>w-Yr)cTscAwM?#@VXpmKmX(NHOsQ)eU_fd@&5aLhd6W8 z_K>;$Z~AJAMek)EZ;ditq_OnpZ;`yOZ{O-3Q%st9`%I;$ab8}&A&>Rr(&=31?%ox+ zW9=Y1Y1XE@M!HwSra7MQJ~XAreg5Xo_bcL;=QQUDrxsqGqQCzKQ^K(+Vg~FzagDzE z{!?!rC}dgkQgz15zz<&k_Z;3}x+9W3baCg@gutl1*Y@QH?Y(kKUyYL|W=>}OrM>UJ zKGS{_Qz$qi0R&Iqb+cU$J@-~AKQ|(#{*Sb?)J?HGP`roY@^o6>E-HG(T_L(UVHZBq&uILzI@qt z%EICJJkHtQ7vEAmp_w>SJmsVv(*~9WDhFNpBtu?w9(epX+1KdGJa#Y7MICPzoPPWG z@?lYSXsvMg;fl0uZKEGO+wV7J|Mq80Wqi4dOXo<@*J5PEqghRzT&)kj9ax#SrL@d<;nbR`X-}o&PE~yVcI{2sa$y%vL!KMG)&?7Y zG8|z@T(89%u_<)+=S?@VcLq*8TM|3pK7G!nkmUy|XYMh6B;xYFGR>@TfyBojKN{rg ze#p(Q|JQon@9e!9XC01O@z%||x;oDLsQs1eZ&K^MnKqQNzPWw(nBeu^DcZZ<^@K^L zXJ5g`1Cs7fc;g-d#~I3)I>D8YJ*;OrknW2K6X7dyVz1Z?ZdZynJ=5CZsfSRW6^7d z74_>AiY-`DOm8J~+XrA2S@=aYlr`XBs+}UT0oIz^?7!%G(e$G7fvgFX|m#hLuA3Ss1eV6a| zUB2VDnVF0qC0tusaPoT4T)x8%i5)-Q-G1-mYQX2G=(A(z-h=%2XLBX=2u7}49i-c^ zTKj;w4`Zp&`n5$@r@o#)Z|mQqroywj7O~c4p5e;Bz4&{TLde&{%g*2LZ#%Q&vGc)XMZ1F4LKd&VPCF{^z!+`)Z8o&phsay}|Z-ZR@(fb(gIa()f>T z{hqkxiXP*SE31xAyUXG^yCl#4*oyc3-e!MOvaJ^w>E7bJ_SoCfInm+Nq>3+j9koXB zlN#d=cxr#0`ti$`mdsf`Z8IxX>q3pH-?|x|Kku)=#Mi#Jv*IX&hQ%?7XOV{dEwdo-1ZWDVY0~9CbU`d+~g@ z_XX`K%F>Km4g~fcY^eL|#-))eQ&#=vn>CN2(n9YDmyJsfJvBdY#VCEwrKZf8y}x~0 z?$-4`e%NsPc680hqv9Ph27Jsnnr#GUGAAT_pZc9ejqOO`icOmi=e3{T_lN1ovwLDp z%BpL*nj1>x+Y%kT(paOJ`rq!H$Fd`5!`n~1Gx@VLzDDVKFRpA{(sg=GAyaSQg1Wb> zEBszMFMhtkTyIauj5+xWgI?|GdOu&9k5^#D-Pd`m|9IzCJlk+cIp_J?+6V6pnWDFK z)!N6(n8rAL6#we@I_98+p53E>?;>*!yl*L`K9QPjk@vVrog1;#|%5P)Nh@+zsG7#a=;zN z{>K;RcgwhZ`uDVOUlt>{z}_mZ&i8qPeTqSd%K};Z9W1}yetV{`N?5S=brknGSKpl8 zdHubgSnO`Ma9`h}BK+5FU#Q{gP?e~L>`Mo>Rmy(bEp(6#R-8JodZ1X)YI|osZ8{eOo248LB`u`{H$`JFDq2cdrtFIg<;;*-5r)qZBCl0{(-gnfz%f57wi8<-@j!3;l-w^^-L$;FqirNowJPd z_uh?B#|l{_LPLvZi9g}e+1ls(fbk4p2rpw(!l6*f8Ou0NCoOXPyy-&kLI=qMej#?h z|9n1Q&wn6)z4cr0XuwQ{Bg-E@{NN)p*{Ni8#I@~l-EuXo9-^gYZK_PsQPbAFEIhrb z;igYv+40!9yvFR$|C`tUxW>!iGMRnvR<1d@EjOn;*%EkhR-f(TfB$s<{d@mUl<9bA zz>d9pkLGR9j(YEO!9ny&X!DZydpGG^IN+hMLVAOSh*Qg&OEQ;&oH*3}TKfk7wPtv8 zZ0_m}yaK)!$C^upkE~2%Se$Q)N{f=je(y48JJulphu8KRb zxVHLnh0iT$vrVwzkGq~#^;TjB+t;}61^c#_O)b1wq!6q5Wa`JZj!p)_7e2=qNQJnjm&}EBUe=oY7O2UE!|L9sG^ke5X03YFaMD)tSxb96`}c_(zH7QU zoe6om{OyjnQvS<1m7cZi)Y)8LrYdmJFVxQZ-km?k8UFp*bvX{y_-K8dI`99Nvw#2A zYaQ@W6`BWRfwbQafG|244)-M}0 z-<&)(t=#tYv|n|lJQIxX-Mc4g;njHbX~Wv8yBQmPw`pr9gsZbWse5ag{^aP&hQ^OJ zzB4WdwTAjF4_?dEe>^$2x9=b$u2#(d1BLVjyWqWm;&A{nYGmU z)%4%T74%AWZ0(rx_(J&couaY3u6)~nMd^L>zoqw8qsqCqJ#JgOI_dm-{qszlZ~tP_ zHb1D87!&wgysvw4r*vl66q_X7+&gcYn;CYhWZz?aaBqS;qw304Jz7aY2W8hS^Z()a=^y_MsM3c`BkPB7ppe(aTzDh5J_nF7-JlzCltWTj4G zT{6d~d(V8wJl5D>VHtnRO+O^8&x|uO6mEQZdtZx$WM$Bv%HrsqFIO=+9S~sG*b>DU zotbgPu~FgY$D6-zE#u@DQ))_`clTky25UJ-pBwML@7TNdYgguqW!8@^lq$W;=B01` zu6oRX=f?Z*6~CYH+SUDdAY$dLbz+W!Guu=Z1@0@BpRNksaOc~5I>wWYA;juNRp4?> z1=E79l4fR(JMQkkbSaMgxm?SRb?3If{X5P0!m8wp7v2VCrv1IK;JE6VfN!x$zcd*h z+*-4|*LGXOp|>lVUz9(-R#oG6ac0!XcyDipu*F=K^3&Je7cafy!m}YF=}7b&=g@;K z(waNBY~Zjsve{*Y{Oze91HCwR-#sVG@o-N4u{WHDY|h_!&&I%3VA`M*vw=$>^3{&# zA3rkM|9$B{@$&YsHh*Svoi^f!4(4jd=HJ_M@vgJ=L4?_;cXZ zH(r@NQ**4OcI^!~KBMXKvun9eE_vM#%fGp@{O|W!Pjt#1U03<8-tgerGq&G<8>T-` zNpLV+zCSf`)iwqPv*$cHp{v(DU)RWaisiuKUCHL9#Yih1= z?cI7JRhOCf@xk_UVr8oD*DO03koLwlZONYekE^!7R+hWN`C?Vw@4EXz*Z(o@%J@^v z`8WREVb#tjxefM@-^C}0=47@{*wl#jjIn{y!LUuIUCp9kk6ZREM$5PGO6jDeiOSpZFcVG`gN}w6<%MH zNKRil?XbMP9q2H0%Paej^K1}G;xY06Je3vNuD*Rc+E%X5vZdqlX&u9atq;FRuPl-J z@>eZ;YOf$`we_ueyXOS0V^h^!8tNMPB-uBnRaHlE>rW~r!~6gp+wkw)|4 zS8+G<%=>m&%65X#fF3G^Txr-Uq-lp&L_W5P`KkDbZV4dB$ z2mW2@SWqT(>d&7urym)mZjfL3Md--wJeU7gUyC>Ilv~9$DQ-oLKv zhW!%C(^3zfKFyt%m$y-e``hl0=g%db6?z`aS*pJ|W;<<*!Wo`>Z*!W@-ef;?_Jr%M z*Ok}u*b@zn#nyk?61O|IboC;EC7YKhv@lpqc(aC8Zp|%!%d28#so4{DCE5H5Lopkqxma@Qxiccrv zc3!uvXP@`hlxf-&gLiJrk43e={rR+I&V7jhk#Ck9Ha9wY8m5T17$_{2oYj~*GuMP+ z6%UIjlY@s|CM_gM@ZPl8zqV{R2g^Yo(da;to!MgqKDQy~!6%0o^9>3N7v?<}^{j-+I zRdx@bRj`KzyQf^6<#6@Y`Sf3wnjWY3UYfOHCC3Wm&4THA8Qb)nIr3&H-^&Se{h+n! zgrxaq`R~j6Vn|pAIovoZxad-q^rbyo zCd@J?7S7}<`fB%;#pgv39TTjaxzSoiXKBLWO*)l^ z`+3<+W;;wf>2+A}_klWd1-8p4CE7bo{3~i|TrTPNig~f59{TuSGNt)^{33`IR6Fc<#`;WiY15bKS)#Flmyra6aaK`jKPY$ek!?@r( zqrt}MF~)y3N#2aHGxw4=Y-Y!W@S;N*Wqd_QqruX!@6~^ONOU7&7ay zK}3+!>by5yUEzjI_gFP%wEnyQrb0O=>dy@3vd10IQ&*mxw&JVHf{Y}G+1JX~FH4W& z3A+7ZI#12DA1uOIT4|2a?|yC*ddIwglYJ_8Y<5NVyYfl<3&dOtw;9*}Y>2rZ920S3 z-po1Oe+;C)-(_C0Xu89<;*@n&Uu@GB-1vPhn|aPo)4a2jtE?V`bu3@L_gdd%v*3kU z0*#BRIOcygZ_xQ^sFUjR*l$LvjN2LC*!8>D^Ej9>xj&t;>Dg5c1(wTi%y%VRjQQ}y z`N%FWhBgW9*nsZWOUwc_(}J0GtQd~AFA8VT{dU4dP43&LPf4xzp%&#(Fa#ZdP%=c~qS?On$D!FO%G z|E^_a)b)-FcbA*u)N$i&+cN0~jSPkfkzy?OE4uI3oZqkSurjPs-RE-1&aaV0s|B*V z%kPHiCfRP^zCF~?prt{lYYMBkU+A=}SH1+8fAc!dwQ!Yyl!w6@rc|L=OZHV#yBG9m zpE7+F$$e6|N9jmWb$R>q=g-A*be>$@X8%a)Y}~C^YkhOweE-($Sn%g}^4^r_nv)4D zmLJY-eyaK)cBbp~_rEu`Pkpn#TDU%XwoYu@gZ6uNmht*i9!jOHH3 zi}U^K=S2U!yH@4Bnd6R!Mbnj1%<_V!~@B*jA{?^i{v%uhv<~p1896)&WP~kkvn@^sb6%s&Wp97GJ_1aI`Nk ze8P9v#S6~N^wm9^Q=gxgSChQdtM|^^vapw%%D$Zr+4fY&Fw)io1l}xOid1Sj~XqMOtmC02rjxRdF;*wVL|8Kd(amLe|5+o{A*{*1N zh}Cv&(V4MqXIAJAGp1Gnw!pofns;N$Z-Fa?&CDM@*#G7K|98L2qjV*m-FN*aZd#=k zIx9Xt{bpU0<>zIU(@W?YC}A<`}rK{}qj^{9d*6iQvWqb2dAK zNd3r6F3h_7g5he5fDA{4&7<4z?>P$2ddYWO%XiMFI~wh>vv%)!XLFumVOZtCix(Sz z=mbn#vM}V&s{?j|2W@+j@K)Ok zEiJoNx_D-MiHUd-bSP+-%=9%4zd!obuMH9Pik%mw#wf1SR(-$gg~)6rjiq1pwtw_J zD0(H(tvu#$#Ht7OJlhWnc=jH;t*Ul)=7hVN8>FlgYu_hqxnseyr~dmv5w_*5k9W9p zFdjCTQ@Y>9=$K-H=g9)Sg%1;*6yysv_wU&g^Zfxhd`tg6>DHIu|LfKA<(EG@vu*mM zz@*H&KE<_rb+o^#(@MPyic^Z)GRii{teSoETA^>usS-bRW(`5dnF}A){7?AW-NBTS z@w_r})$fFv_k|xS1>HH&rTnekHZMQ_!|nI`*b}aPwTYH4F@JY3rTD^=IQC5oC-F9i zIxD*I?AcgxcGIJ%@3E8jb#JnlvAVECfyF&@@}p&tL|-Y{5;9({!+gKW)0tt*{I%Fu44K{u$Ajmb2H1zueEDd zvzV271+xDWo!i(qZB?${xii|w_v+4jxaskO%16bTmaEn?$8LXQy>Ousm$7a`gW8NK zik8v`F0HPSR-Sn(t@Kv$s+D(7wOOvXe(C*uu@9^Fhb6duJ9o7##CcxCjn8*q<_S1E zw!Qb{N<4JPc45_r1`Y;>k_kcozM5Q&OPp{+UoUs%Bv7jCr-=# z2W@=SuFl>RYV>MzuAoA7x}wx0o2QbOUrK(qk<>Lf-|?|b^iTE7U~9R@_wV16J-aoB zXC6zzT*+=OCSH!+jEV=IU&)?4T|)Vh!0VW8Jq$B`+=<>$~&3Q;0mr_B;RoeXlzAd+CF{qH({L z=M?Xvj;hKfk8EWaPVRbX5OLl4Nb!Y&JdThUIq!y5omZY&u5&nl&S?Ah ztuH3;Si8+7e}(g%H5+G2T0RXu-VzY=-KtqZ;KWQZro(w(v}!eSdd}J=Oq?|(O5j^@ z8k457u5r*T!!^4~4Y=QMpJ5Mj*mUJ%=&7K|)z2E*kMl3P_VRjG$J$@=j~eEPc})8C zv+Hrg^5yD#Du0Xl`}6PEySFqzJyFK3=EsMJyH0`!0M@?#_wQ{{eSN*sp-HX+Grvxn zULj_C`+?+qgTTV{gSp*1YFT|Qw>Cyt+0k0-iEqus*Vc`K^uL`@l zyBK=7{6fy2*c9fi!?dqmeg=c@SoUPN(m(c5gLg>6bN9J8l0{fXRq=kuMX zG5gB9l_$)}o}M(@VA?mo>O7w78*JIs+9s?K`1^Owe*1T!7mohAl@rPTw|Illajv;D z&%5Q<_ukGpKJW6a2$c^{q z5tmpNcyLJzCzwm5F{V6oRCIgs^2vqcF_TZv*?cmlT-L!fwpXD21V2Cjb=x1{^;xmz z`S0!jyb9m{OYzu4)#sLt89!q0y1eB5^ zb4&!=WnDNwPs!SFZ`SiKv$F#apN}pj9t!+oYrK_y7`m1WH zm0+Lo+b^HlVfOd3;|vBrt+m$f()ng(7ro5r-Ui7X3p#&)c@!}H*01?enP1Mw+b_Fi z_j|eU6|M%_p$EDNvuKU0LT4>j&`4KK(w(tM<)%<@&aq;H`N}i#iIk|tH zo)>)J`+fd_Lj{}WKc3zt(7p1HX#c`XVxpc3&t1chRPXOR{P)6LF>x)A%7ZrNeP^gY z_usO0>7tjG26=gX62}(?&Any$g6sJPQTtU_jkav7slP6>hox=N#0!hh%#>Wb-FtcF zs{eL87X`1RGEaY18!&0^t=+DxF9d(hHLr2Ge`wuY_Sk-e>6zCh@8aEc!+z=ll5 z6q@Y3r@#M?P<+i#R=N3dv6=;|&ikLcCi>&u?)O&NnHB;D*Os06<$vh%W#dNzu{=H! zt9)4OWcb_rI==qT&GY-J0x~x7?VFQpHQn^u^|xmx@dTKv zcZS*aFt;U^SY2m0DR#quxwybN%NM!IXU|5SO@Ds*PY`p=%`N9kuJ5(YY}9@D>{-X( zynK^=b2jK)p82CYj-%vn+dkXxLM_#MTfAc@?UUkF3_IHtr;)M$e(CjH+3%BL1y8j$ zglU$=eqxj`STp}+eO8FWy1N^;r9U%%75P6(HSxwPmOpwi4xSR{=k0%$c-x9a)$>hb z>2x8Xi>Gzky*tk>?(WS|NVUaBYpqRbhj;{g+Eig&z*kp=5RZ|#N2P$TulchjP1CzdD=Jm z+gwdaGCQ@VwCj<@vDuejeko@7f3bA=-gVhbAFQkyK0Tdo|I_^bpI_$hlREU3l;$%v z%?+Fzvvb|sGChetzti)#h<%*!?|b9&<;$}yk{2lN+%Z$@&E6odyyMYA43RgvuAiNC z`;76@mf5qV@7%j5@!-7n&O`|xZH6d!f%&)I=%0(UW$2tIZ=7qzY!;oXrhC|+%+WMq z`|b5t|1Qw(Z4S%r<~$iT{m7l%Z$WD#u2*pXN-0=(y&}}`^sCbF*bd+84<G$j z4~SsR|8_2X{*l}Q6Wa@0I2fz#uYgeqYylHb^Mo(9;^8Y{Pvd8O~BAj_T46g{bGHL``XDq+W$?BZ&OWJFd(2UCI zMOCw>y?h59^k3`gaOeN}`X9&tAGAM~_+7A3tg)k1?{`*=pheSz2DSOS(`KY-YDg?S z@%N}`8}o%bE&gY|ZEaY{G|ylC`qAfpPmZlj2oia?Bx~Jj5y{IvTXZ~5Z!#>{_++ui z>0=TH0%Z8B@7#GK*kK@`9CYNwMJ;7df!JAvya9#0+2uR0ZHv8>6t*E{b1_%i>RCrK z;&z5CZ^@gNC&&JIQsAGu8NAg2!h$CQnl`f5EIZA`A`qc-@X{mEClSVhyRVsj(LE@s z>ydZmomXVWiK^`1US=m_1)L8~$a*h*Zq+HKqRX50U%A;WT@)f>DfRpRztuA>SC%;% zPsn~Y+ueB?%TgBCpO^ozi*WJ%eRF%BbhUTc`SuLmA8$NEcJ6lwZnTlkzPRe`{mzOy%^#OevH^_#GV_0S@ftM51!lD5x& z8+pIUV)mj%GkiAhH)Ho-&-Q=rmb$>p_itgX^WWfr?SzpY8 zHy$_p-=?#&>@|-+qkmknz|7;zm$yIM1(_q*8`~gX|2};G&vx_qwg3D=)C8u?*s{Ip ztY&#`%>5}_GFpTW9Ncaf`uCG3~MPpf}#WVr2c|c$I`Z_Go15Qg&6u5UR$C&paf9Ql_${lnE}m_7t@`Gu{`b|C zHJAP<9G7j8Sap5(v}rXQ9f#%AHYbFgIGv>C@aTc{ln)*(C&j*aTBU3c5IpotC>UFMRQf^}40o)ge7CubP6R;rsN zi=W9kTy&oDyXe_F8+NYZ2r!ZoPv*U0Bq{w{$@KV+M2Tx9CIWrOXYVSUR#xqGlCghN zmg{_D!zH_($0jL#`O$S%X8-Kh`Bz1_c{i{(tt*u8l`MG4?Xy)|=|WeXJu}y@&n1~H z3CA}q3&=Y-bNaJCzHT?P;yc7LR!QVLtnd%O1);Z0ScI@!s z=FK@qZHes5I_}nOUle-n_Y~ICM!R1>|0QK8_`YoS$Gf|~?|#h(9&{63zkc7ZSNnf{ zHQ)c!tmUDkL*4^3XUY85;BBFocRjtc^HeG0&q)`2yt=pVU;63i>K9$%L7UJ2+0L*l z)l=Km;%eRFGKD0Q=ZALhwl4lEyf*CUQPuSg3$`5QDA-sSTgvz(XR-e0pHc!>w6tFS zcv1URLn$s-^rQ4;%@-5z`j)6!K9`c7-!d&^>de}ouO=_{o&H?O>ffdb7oyleLJ_R|J|J{4{ zlw`iFP;$@y)sxFUzHgm5G4-&K#>pg4i*0}YPg=3_ne+Msk&_k+O}Solfh&dgw0g$(*<9r(fmyW6$01UeP`fVBB|HT86*9DrZ4%>UPeK zeG|VO*kq^B!EtGii9^!Qy0Uk+YqfVA=uu?(Y~rz*J!iik6VKrtTpx}``kUuf)@Iv# z-wK&iaCy#Wg*)s&KhNA(re+#+`*JP&f^9c9pHy@H=s9_Tonqwv`%hb*Oe&6lFTa6x zNfeXRs}&2k{JwgGOXs=B`fq!=_;RKlQGGD!mE_laZ}B(b@;mf1xnsC~Jo^P9dRb63v39H@IAM>^zpSvvl#k{Awli2Iu zu3RSl>{!{Gi{&@EzBz1N_)aL~Y|z(#+k=ihd8{;{lw;Zyn~$fba!xL8bNKk-LxX^u zz>S>d=FQ;=i`P86!SF=&;g_OAb^DKh`O}oJ*o4VsPvz%lA3l8e5X>+?w)`fzj4XNk z?f4%1H~+rt*MGWPer8XKpyy8JWu;RCCod{BDY=_)j@dz0x#Xntw6MMBKlh~0(`T9f z`Rsb|E39Q#LZ94d%-idllesuPX!_;6HklQy_t$!O zm-5|__&Y(~TXHc^Uc{FB@AWG#al6bGb6P32opHsCvrAIEI&Vk**P6NGOXxMKqr@{kcGaz;oHL>fX9zh=REt10t+60e}C4WRk7DWTjw7uDcQdJ zUjMZ_{?8}(Wfeh<3M`sM^KCwGO-K)2yp^ZeXi6Dp);3L*4jqj@U+RqcCu(h~mT~`V zd9s*|9?L7j-S+M zx8cm^8Znlm$2tD;?3u20&+Fl|1OewGHv03X9NBg9{{FvbD!<=k>}gwP#%Gfi{q<8% z?7}3`IS*y7@ide+T$}1wmw*3`^#3crV`4bX87_R?drtb)l64!DY8kYzZ|7h2cjJ@? z;ZtO)?|58<(PhKd0O3<-1VBtGpmV3cBO3=3V6@k*$_B{k0ANW<;h)=yNf zn(u48YIDPTm2ph#Lv|+qt-FgoA@HOEy|J7_kPUxjtYzW zu=Q41n#;kO3(Jx(^Z#MyIMrg>5P1IiQ|TV38xh*;nOEhdNtnf*43OVzQ1voJuaa@A zp5MAC-W5?lpU&Vq_T)_Z!t^yYNh%wbK3O`&AYildxqF;ObCtahctyvCpO*>iYp;F4 zuNXCHuGkW%i@Z4@AukJfrbr){mg}Q(t6W&ZnfKj_MM3iRbtb6?98MI7db6MS_J+4) z)r^U}1<_wjnGC<}wq^M6`0?XVKJYM%_WqdD=j;A`<8Gki&lO7 zdv-6&qAr110e!3-mbZ_1eb6{n9yu-a>69R?Ge!RsOFvDrW-OYhv$Z!jl4t3hRnPV* zuIXOM@8S6MTJT+i_wV2TO@HRK^3?v-YhTy%9S&IS5$d|2!N4Ws)vZgdk2vgB@8gzp z2tBxNM_AN8)`R=*zu&0CSe9u^Oo-qw3xf+XumBydOX1K@uBQc@h6K;Dy&=6 zuBUOiN=<)L-db^$YR@}fLKjclZ+}qFx8m|T+3%Xa?wP$9iuX1!X9DAPrXq8i@taXA6d(ZBU%2_@OxUFNUk3s@v?} ztTsFNt)^=Bjd^vYVLzw&UWne>RC-(LU`wOG3L{1ah1HphMPEJK6d_b%@#gij`#A9H#ZKJl-w*XI?>a1;;g=wzoNZdn`|# zXfpqHZT^)%_a9jN3hXtFebK`eeVp;%)}t~pQg>6r#dr*7g|1iUT-DXmCVEj$;Kk!M zE#oh=Ggec%7{nf&t9I+3d^O=mvWq?vb}V_h3~?Nr;k(7(B_dD7n=s*}5Ia%cO* z=B;91OfPh3OuOmZIIZPM;JI^Kp08Ygs-aM#u-InSnapXsCVusFVEh^?y1&mUbYHki z=j>Yxc3H))UNG~Su7%cPqWiWLHx|x5a*vN8}eRHx_;mP_fIqS z^y&BBMhe?5)fa!TfcsvG=;X|AuY(=>?@oC&nQ^cCr|-u9yxSaVm98W+o$^R!<+zh& zbi%U0AcmnRtjB30!@Jh4e@eI3F1Wrw-Y#O@^8k&xK7!6NcQ^Fi0r-gml zq>{2R`PM3tV+Kwt>yIS52sx$5^t-p5i1^f_x_q;5wW!5uon6TsQxq<@~GPp2$ZnfG`K^EEL|DNXHg-X&-KrLlarj7e_i zGVMSUfj6gBvUw$D^h|r{$#t;Lw6jz2CoHIS)h{j3}PRbJvt z_oulkg}W$7Cu+W$q!$!Yy!1lpqAe;*&V1cxmdj>-!Aq@UtIo;u?$PFsm%OfY?t0?4 zv_?;IQIqPFMZa&|AFzhpW`` zdI`285+9!Z6Z>3qNTAU|z-3b4hni(^ahpSYoHa;lbBoIrYYRyI3~*KnPVm+;whe@lNND!?ww6sMo~{=R_&5VULLkW z@6wcsC5;XfLe4B|KP#{*^eB@WD|*=>fT2Nl~e=%cb$T(Rf@tKi!QJ5IHg7=3ra*<&b^4_o09oE7kC3%>@!)4lr!+Jb3DachkYNP4UJ~^Mv_+ zGp=cA=kHfwdGn}&hlvO@++H&^+mvrN!nxu!XR zYnPYy#OA^I&oPD^u7|cU+~ZohVS0dU8{_Z0 z3>%V88Y@}PSo>N;#9(URxi|0s&R{SQV_>wH>vy$Zwjo(kNI=Q7W#ry){Bf_LgwMJ2ZtQ)hwk;6PR{lO``nmv3yYheKtS)!=v@PL!kq~@v>N$f` z5{KiDGQ?-vc9&(x338_daIa9f?5dGG;oP}p|LO#5Hm&RYYr`6~{kHArM_Lza^ir<0 z6dG~qFS59h8Mb;3_xHWl*Kc_Wygkq$rsLhW&?z)+*2@2PpS+)YF*!1eeenaKJBpiQ zv~%xPynbaMD((Jcj$zrgJx{w@1r{{k;Xb@^`&^?%y$jbEn;v1*JiE1c0pAhRU+Wqc zT-|+em-@3F2QRe5nHF0XB?Y?n^`FpV=q@R^E7kucLV;)|Ukv%u=_{*%bOu@k-XR4&JrT z9;6&tsWk7g^4Y1OAL{nUpIknx+-7G)*E)@S(J$A3Za@FI<@xh;o4qy2VItJ<=o!aaGd({|Q3Yv1h-He)uNa=!AT*cV#|mM!aA zZ{Nu}FQ>6cPQy>P`m&O_<@!_T+NRH(nR&m-dC zvu|!#rKHRG*(Pzn{ey=O56)L)6)fbLIDh{AkH`7t*UN%OKL6{jng8$2Yx(+bU(e6K z_xDF_m)M^b(^a?j2JU&JJL{vY*35+2fs84oR$o`$SaEFOr={P2|4o%Ed8=>2`7m?V zIV*;@->anKzY7aI`1Vb#{V<=rT?r?LsY3Wc)tr@SuE`I+d~Est{{G{~kKI?yn)Gmb zd|hW{+=s{g_B&+W_uP&ymgl*5@qt4E7su{^Le9*{EYYb)ML7A}nSLe#4cpPvFI!aAWim^CKG~XEqW^Y^YVtfanfLDu ze2pbqo?K6mX|J&I{hh!6?>ERs&>!WAcV+tj-`21HdHVmG|G&EbCkq8!o6~HueAdl9 z_ZDWoN?x^Kj?B|ImLv{`HKJMe?V@*su0F76*qOx4HP68%XR(%X(tQ5sl?RJvX+K@9 z$`B&^Kg%G=^#MaHi@CY`oA1@^O@bT;UF(c0IznsL_2_WL&+pi;NsV}c*P>zb|lZ1S+c;=#khvOg`X ziyv%T%dpsq&n!CAf9jqm3n%QpwdKsDi>%^P)dDW}bI$N)Z=6tjjF10U(AxPcGd`ML zYu$bzl67grdqa+=B1|XZ*-L$rg4m1H<{iE>gZud`k^lVF`PZ^Nr_F7z&Gr{8Y_oo5 z6B-s8UTW?sz2vq`)FM^JZK+O7I$e`Ey9EBcDBu6{p#4Du1tzmU4toWrrEE-{Xp+G6 zOl70y#05IrJii5`Og{T+o#OL7pKYJJygA9A{Z_Wn$h#r;go^hL#+35VuxER}&*|8F zJ?j21zw~YPu(befK^;d@`B{`-oL!yaDCDxt=5%W9q~f$Gk3{2{?!7I3>N{as&<{?n z%hRsOOVZ{ePS9j>oxJ8Ific~r!xMLo5i%=`&3FGr^MOSlX_Zi=CrL#mVSBl zsj3sli{EnhzHbV9E!ebXv65$iz>NdlSEenuS9BI!pEJSu*F5|Fqo2Z~nV+vQ_{+>J zHD&3}a~u~>pMQO@t;JDL^6nO2W1heNdZoADXZY|teEI9EUzeB07Bc*^kGq@m?O$^{ zfB)R<-y+FAoGVifiGH4a#I&jWtIuH5}J$J}&@roq1Hoe~;040b%P&zWtC zEjYEOJwE?hQihQ0v1d>BKMgnm+UUHNw|6w*Bgk|C5xuPFS!lu|beobjgtk)(w@nuif3J zbZ@fO+6TAT6py@m8P65+G+@f!s?^%epOU^L|48wzUitmU`fQQrV-yKCvlmo8O7`d($PD3uZ*Pa|rDU&Z%9#Fr?Lgp_<0DY4I&Q zUYu@%Yf{}$Osp_h3VnKi;*CA+o%LL9nh}c=d)f@|um0F5US}>SSyixfy;~0 zO*&6vib>a!g33zHY}q~XDy0)96kl_jT_*91IsGnw?A$fs*F%{tm;&+c{=ADJp$!D_Ey( zo5Q(O>O_RyF1=%0e4BJy_I=uy*Lw1Ty7l{9RqMJY={PS=Lyrf65?}vbj!1g)r!%u6 zxch;>*RATcH>+|NE$>_?V$P~~MCzVN=pvDngwt;~h`i`jKWrwXP}4CZ>)XNA$2>hN zn4(*bysWnPnXWo*-_h{IntY4Lj{Z(l6fW(&HD#|5Bacc3bHwTkCSvP07Mwd2#k-W_ z^iiJw_rBMdzq_-O_dUBsdc3#1&iN^ZY}cal_@eUoBrIPXInZT)+Ve@XB8y3{^Zon_ z`DUV`+P*0tBWEm&)e5?iV|FLPXOh^{bVI`?XL-((6tv!Fu?gFj6gSR2 z-y_zB?fGwS?RLMq=A(X{;59RYa}O6E_y1sC_a^`GMfd)X^Z#7k-{syf_weK6qj@H77=T5$I*{E8exMu46zgpW9T$+!}cf6>Qt&nf3rj_r1 zKiK5)=WOU+LsGcMYq-Ghv5?zifP#|J(Q>n0J$x;?;ByUylOK<+^G%MeAHQ z7R9SfS#cyv_2y~z&IeE37&fh*p60~pW+Q&<*rJVM*CI`PxzlBL-IUq9?qHIg`)#wW z9^2O*epS?ZGbik-iDE>Bd_a-DS8znUnGuhUnD1db-cOrNe4D34K8gxsI404uAc1#1 z!xl}C$wKqEgf*|PKE0}B#WN2{RR@pnwfXD)uC0E(it&d@Ov*6_Q#fO;?DbFDmv6t$Z1CZzvCUZ)Q}^h7{GNYP7wNuC{5h-cgM`^$ zmYD|I6_&H4W|VlZ4p{eQWAL%0jSZz@)0b;UT+jI{^JjC)kqNKvnI7vn$p7LuZ`;{j zZu6y*KmIu?_;0iPPr*C&AK2=CE&p$~hyTaD_kZIy{*ZlK$Nqli+E{hp(6gmMPdHMN zd3J4U4)PJ%^5|pS!^$Lnwk8k8nX@b%wIe1;ay8~ky^Ve{W0PBgS=A&>i_lg!(F_@% z0Ol_*zNve5n9go|A{rj9*(VzQMBQ|7 z|HKooT^IZ*-Z4C+^rQ5B_oW;uJpXk*)rePSZB?#2`f<}O)8`T44wjokHt|bq{t~K` z^;QUOGi8gto@kbSqt0&r;?gtjh0_u%)%I4c2@|jQ_(w8{=aX$vtoTurTcP5g)k<

O5OYteUI6UvqhHv+t-F>8*|Mma<_P58I%@)p{m$f(7phVCj-(5B+$Z%R}q)tte;vG)C$8!$8PY)QjtKoQ?l2*tv0<)vBoM;~ttdj7+;U80OXHNR=OqAf$e6r&D zVpsoP*OSbw4?djiJZH|F1hd(bUZ|g+xV&VOdV+`a<~dxRDzWp$9RfL~wRqS(X}z3z zJd3GaB~nU!@r5>?*?W>5w1f;iU*;=yeOFm>e*JQ$49!)RE_;r3gkHUL(`tkGYZDe0 zMW5#5cO&zUDx2iRnqRn8^>9+Fk4l)^>wsI2-j>@PDBu5E>R!!fUKyLpuBlUVZ@Hv0 z9aKHQ_}JptU&UE%9Cbb3Pb&Gh8hL!)cmF}7TV#kYt7gy>SFU%Pl_b&)&1M=d2XIX5kM;z6t4wQF^2o@&P*T>t-9eRG_?@(TXR7y29vE@fXS z?cKFbOj72I_9Ip1_MZ0(xAJaDGyLn9&8&FA^Z4Qw>B+nYyJqx$E_(O;y3>cUBM;y9 zIC0#Nxa;%%$hUKTt2r41u9}us^&G26?dYAG`zHSOVQ>908WtJXvE(81%RriskkmOxUz}w{hkF!~9c3 zI;YAU`ms}ve_q`_jeD=S{+<)&)I0Ndx|#RAz@6-qqCGZ#3YvTF{72Vz!+YNMt5R1N zwf!!)cbmjz^Z(Ch3BLA>kY960F7QkBc7ftKfuB#W%*wv} zt7)zFkDtAndrq7^__J#cXJ-gkN@mxh>4LHP`V&$)g)|d&R^HgERcK{Nia9X)b)ZEp3O0Q>0ke7wC%6DBX1wC# z>GU{xK3C;n#wo6TdHDy|+_!&xcl-ULx#jm*CkySZ zoT`*Jzv*(>hJChQCZligr$$hyLYwk-MjkZ`Df4Au9;m6m{!c8cv0KP;Ms)K z%#=sRFV1-1XL&4vH$fsdEoj+~OVj`9{yC)ohpF!O_IhdkeP1#|rZS0ZN`)Ssa!9Xm zGFO2hXPIK$G|sH|?Ix*Bkg$Bd0ZTx;sVks{}9WlwyD0vFD`BUb78i zmGfNxH9iokRP$Wj5H=^Llv$BMQTA7}%;%pXu5lA2u12WuFgSN>r@)^n0gJ`^yO|PR z8ouEF|MT6ut@_?G&&=7J?4TlZCOH4DvDUS93-Tq4Hr8xkf;Zf+l-0cZ>A&#)`@@k zArnd-m)xFMbJv7nR)v;2qmU&_)1jFx75}c}`-m8~UMpWLb!FM?rbXSK@57Um!gJ>NE#&>V*nC_0iq`d_44$8VZuqfDV4aJY zo2F_7yVKG?%hdmTE?l>lEw@EI@cWV1Mz+4^4;-xctt~pSaq9_IS7zzgm0$WkoM=72 zdb(%RCY_C8PktQQ|7-n&rPJdN-Fs)+b3A!X-|>k1HyRAtzQ4bJeE$ER^B>;ZTm55q z{dfCAr!tYv!W;mZyWh{I>nl#p60L*+ODL_>+XXe|B@{ zK6-hXbJnV5CYIL&t($dRJ2P&tERbDlD3S82ep`4jx1tjBTq{wfTNe&3({1Tk{zK>V zJj;)T=QP`{&Oh-u?fmVD?gcR{>uq)Q_MKfB{lEBz!=dW+TR$z-^!!rizdYDS%{ZjA z)nsYYlI!xxrEA;W`Q;zW|6go>Fn;exXB*opu5=wK*Bjxhb)}LoXtTXIeMG!%O7sP7 zqxDhS_oZrC&Eh`d=eu1Z_F7|$S(W&2nXc2{TwXXg?b$Egw`fyky2;VMug~tCA5(2H zvDAU-fq4B#@sGv!--{#S>IPd2U@W_3?N=Y3=Q3*)4`5NH4KQLK^md&p(~BtCXK~PQ_Su4( z5|QJs4+}1s_{y9=y8i2oW54%o`;5 z+Eens_Ow1M;CT03_@JZH+VZ|#>-MrO6csmKf2UM7AfmiTvPi9G>Dl|g_RlSTaBQ2a z@Qn97lOn>n7%iGlrZnkzZ``@FbCJf0wHHh#hC61qs@RxuO`Ly#F=Fw;nXM1v*1ngS zqP4iz$WvH~JA(I_EW?NEY{?&#&a+&uL6+NX?g#$Z;{e;$bxmR}kIwf}g*V_t4_pwffVx$h&h|NO*CYuw7qg-(Ua!{(pW02_A!) zJ_QvO9ryp=l7Db^`@KVpkM}E9I=N2Hdr;EszrTd{|JU{ZxBobN{*T?aZ)JhkuRJqz zbC;gZ-}Y5{wLXvK_j3&*$0YXrc*OhX)%t(af6V{){J*FZgV)xW*1RIwn}%->Wp58) zVDDaR-`nmcIYaE#lf}<83$}lop$;%isO@vMYzt?y;4X!ZC{}s|;oM zK3;6De({~#!u`lGj4alff^l~Y+#|URom(8e+EhNX z_@A?uog%jD^4k`j7a=wR-7$g>zh-jFYED}5grAjR>rdG>m6?JBQyxAJ2y3z=|n8 zLMCT5yZ%kEikP!zb?Dl&-Ft7S@m4JKq$stGjw%FKydu|55UMkGi6)xXfM~*T63qe%sQ zVwYIRenkyc&V`n7F;A^lwmUWpO!?X1{_fX-sd-h&(=*)4?0DB|tSU2`UA>{#Vd8U- z%}mEEeAI$vWamG4@q(rN-JPSq<^M>0e{Xl-af!wL--qKru5I7fI@>(|;lID^8eNNO z_a-iq+Pl(pO3;rV?`r=X%m2gn@8A9Z?Fw_`zc5bKTR8R8QHH(zmtXQs*UL>TE*92) ztjM&~pl9clpc9*9_Qvsdifr^&SsHVodHXGe1v=?B_LgXt*>1AQE#|X0o?vjGV$Y+W zETU4W3qyF5ZMVlu`?pQ0+jnknLa^e*%${%W#OzN;d`d0ZS;`nDVl`_CKd03koAb#+ z3#KT_hCIHw*nQ%p8*(vw)*ab7>V)r~_}0bTJoxIB)}%3r^|G|5zTxuyn$MGme_?%_cB;X|7qK*&DrsVTVC)SelM&>BgV&A`J6?ocR35 zU0V9}Q`sl3^W!2k1ry8<@+w=p$Emy!ul@3y_19jey^9>C zUFr=x|6F6X<-2>e4a-*A)?IFj^gdaez@b$5eCE%%FFbr~dOPQfZi}o{G1>IbMQ`yr zM~+!DPo-RpKF?5pO5N4Gv9cqX&u^Oi&Bk{vE#@U+dp`WKdK|^jFJ5Wn*QBzWr|cvD zThEHn(CS^Yn42Be+dI@79LO;{y8Hd!et!Esoz>spJ^b-QWb$UoRjb+xQ_Lnu%1hs5 zXlP&!(00~%yoi0R$eeIbbOx_zCV{(65`gLSFtn&cl3 zj@utQTmOMSsc`BNPm#>F;Plw*1spAV*>+Fg{;~T1_3IyArPp!o|1pL2q{V>A5+m@MO+Swu$T9oOv#l=gFlgXAdnVruqA-``hyPtTrBXU4NipL(|o( zp%%{zs;ascO?S*}ec3YUOWJ16EkQGUmoso2pM7H9d9eeBW(gE2P6>MA<0*8<-ojzt zbC1a^rNN2S)!bg1`!5=4>1}EI9H6A9@@kn&XyAjOz$Y7~Df$}k|H$Mkd!$N-t8@Cw zr6y_xy3#FmpCt|mzjyR6lIeB(xNG%msVMe48#=e0l6d`kCgYsKq>>-+=1vi+oVNJ> z>4Lw%if`PyrLb^o@QPJJ%hiMD%)1cb|6A9+qqrl7b~yW-#eN4 zew+O6<-JeeIXqaf{cVxX8QsiVzVvRp?EA<3>7LUeRg7_`Z8B^)mSnEl zaiZP6bIOWrt&|q~sTaSCWOy~LEpWW|ZIce?#%L`AgOtd|saJh7atr?7tF3u``~Gq1 z{5_4cx92IHE#8tag=K@xIZumY2M*Y3PB>C^hq2PHu9}&5;-&W)bD7J}sV{16mGY=L zW_k4IED3#{%a>G|lkQ10+nj&gB(X~}i0jPrVxBhV^=0b*+b2A+n&8=_ltsR}>h6sbGIcf_`n~Ca z(#x3ty;+am-_&T0TYn(D{(Jeyo#*St*6;h3^=FpAC1;M5{tCXz_vaSQF|YXZgY#a+ zW8Rv_()SPW->*77zl(M2UP;yGg`D+C=G?LtMNBNO6}P_qY}0@7VCB7T>1EBw_Evu{ zD05pB_B?7IbHACzShFX)~NoR+GyZ_ekN!gG=rn=|;UOxfJvVX#_j6Khzg^{xV* znP&pbxsFNo99zA@dy|>pa@CiNd$t{rdhp_h#IcNmdB;jupFX+$+@!5Dw#IV3I%g=6 zUYoMD=lWy;rqsww*MHxSG+@u3;=kg{iroDt+xwiSsS51N-mq_9+v(}+6Ka!rU8f}& z%}gk&>RGnRV7`CgY9T-A6D`g~?2CD)1Xnx^KL5CQem(2rhYVM9oPMND2nhY9=RRr4 ziOn`yA}7jDDJ%?XDv$&&U!s(^Eu0TDx8n!2pjTN zxJ~))snhVzbCdRos4}4v`+Yskv0^N{{BF(uZ1<_aipPBGHK}!LK72T6>!Enz{nx_3 zzwFk%d6#G)p)`^2!IFKsv!vAB)o1vf516hxC-a2eu@yhHEqGs-`bsCO{4(U`yV%Aa zX=J`Nrg+xbtsCdrv7SHwbSaN|jbt$2WSzGi8w3h>^=zGOm)^vZ^I`w$z{1Ikg*&^B zPQIo!??BV0y_wH8IxN(PYO4xMHk_0A6 zzfUyNzo_ljAabHxRA|=0LmH27zxI5wROr`r&sjH{C%(6_;QbS!^N7mkNvy+gY5X<`!{ai-ad7z=zYn>_gys~eVjjc?xQzvct9%= z|89N%I6M9~^Pi*f|1|CXetN#aNbcyH)@=^?-F&CtOe(!zrRS=j_iN#SEq3vbe*9p0 zy5~rVm22o!SuwV~%Wq|z+A44;JLE{yhHbZZX4HRom8p0mBGr7eM2vay692cWYg&wj zr?f6K6%CJ^=em1tmWWz<@SflAepgggyx=#uwcK^rirk5v3StZmDxMQnI$U=a^EEr( z|NK4kOvJR*D=`u2jPscfNM^U5`}bE^PJB+P^;c$6vBYzO`EwrK zyXzcswI`|b;eF}F3M}rkJaX2pPp<#3HE(wvZ@Aw3#N1?_s{y|rl~g_B?iKO%)$DVf z=#c4b)4!-;5rfL|t!x&>J@H%q>vJ{C|8V2pt|w;ZX8v7^R=oP@!|btk>x4|H(Cur3 zzTKQzzuowPF551ze@}z|e|l`Q%;Cqp?z`;IIrk<`dMBn)myn{lr~J8D+}|_HH`agE zx}@W3X?wJ=lr7imN~rH*=6APOtT}y(e}aJXC7Xi^JGS>oI=_g^XXUo7zZNJI>?Oxp zy<@)jr@pg&#TOsG`OOi-&&X*oA#b1K?LPC25a#42ubTl;63_4T=Zl5hzq`e7((b}D z&x$pcF4%H#kB;Jw0|^E$v(i?a5<0G)UQt!j)7~%l@Z)0UJ>ReO7nGFrxM`zIy(w?fLc1-COan{2wyXT%6Tn!PuSNv=xByiO=BGD1Gn%Q&6; zd3<%1ME2ula)y%$ue71CS?!E(ij?CR%UQqN&-&5A1M~lUlz)8qdp*lxfd~8IHcSuL-n=oQqV@ZR>bu)gT#o!Km^D!$ zz>D*$iAEPw{SWv5EbI6E(yIHG{y#S-XU)Tli9|F=7} z$wf)!*;AS7-RF}_OL^EGR&hk@!XK;eGtKXDyli4oS0xbo z$IUXsxnQn}XM(MjWRKsWNx?ov7v64>-G8*&I>kw6S9?d+bz24%PpP>&sgb{g^)71l z7Jl5R#uRYv(Zj{=JH9^5z4Pyf@}AG%tbg459(VlaO-WIHoyaKv8%)wVCECma-W983 zUnI4p95eCV>vpnU|Gm#FQ8T{73_?e3Z$Un6+^`}(BnZ0=^q#=48jciDN;j9V8!PPVD~A#pW_Nz?L@ zN#ivh&q==-6x)?vAGBc8GnP=lAkP!C|Nj0Pv7lx`ox#D={}%lJmtgSY(aFoos!KPV zi#$0^EaWw-8__!}pjbDGKJ z&p-b`^Y?qsi?dQPyW-*<)Jmj0Q>}k5IUuv@i7wCCw>1HL!cR_aJ@)J7zAwwI-dVmr z$>co$=bXGO)=O@J&wgD~{AcaC>4u()-}gtaujW2%pPB#tiHJsymuX7qeO9)q`61BWetgE+^nj>?8SNoyC%PD0 zu03#?locO%t?HWggzsDu*@-=$Tpe~F;5wM-TQ0BWEt|0S#H=;FEkPR z{=vb$zbl^4EoZbilNOw@)==haV5n%3i!er&-S*G(9|d zP;uYqv-yv}s{k&#Z~yq?V{(Dsg%H!e{{D%nmRrIK>~1@7Jp5{E(`Rzn^l&ZHf}m64 z{%U3KIjmAHnuyL={D}FQ<4d-nBChPH$fHwFPv5w8E9-NeQ(0_x&lp}8mAm&_;+*=o z$n*uF%xk5ZSUEejt)nY`UeIrOq~K3_9-VwC1uQ+8^rZA!-A=t z%{O-8Dyd70ew_1`VK2IL+v0W3dUFHUi~C}a z4UFR6z9mrq_U{cPhuizh*Sg-l_TPvlW2g0oJOAv@X9|>wX0H?#KhEB;e5RyI(4%MU z@((^-RL;rCd-Up_sK`-?GlesjHD0{6{g$Tf`CkFTe15Es3PM%e8NQ#2R@D5c=bf21 zV_9X(SrwyR!^J(V8ZlOhEK`fj-L{KvGPE}jyZBG^=37I{wYO~*6_XUYC36k(Lt0KS z@T5jA)DvwH@kr^4%V$_DJI~JcSbW{*-9PSq-`{@Q+`i32C?%3{@k#;1BhE`>npPbv zuxRkn-Lfb`T1}$uucBzGA`cg5ubahz8IB%a%KI&ti`Pzb{&2;463?2e6Foc>on_QS zx))65cimZ~aN0Oo@q4Fha`(fjc9s(sSn|u;9s2v5zu@h!;v0AG9$s!2`rzbY_aEoV z_cbqGoSc)lCfP>ru;uIMBP;dGINw~#uClPOa9Aty%l5tRdy(aLs~7F9i#=nN(BoQT z`dxIAq0}wz`z;IB9hsfKk271tT;X))K5MDoKRNd=?71beX3d&})Ku2;cXt*xO)eDC zY<)F>egD#mwk`V?FE%#uWzJrEy?VtD%VQcJmO2I#ymoGKr{vYK3usr_1)xFy9wkC-sqCaI>{=WSF zyUv8|{XT^SA(J{fRM{Sw*F1f{w#;Nvi1b5k4R(n++#-=|#~N&W4deFqtX=E7W=&7R z+U8Xr)gfWQQXd-^28sqbc4Qor2~sqOi$8emm({m*?-R?v8?B4q-}mv9M2tbf@jrhV zuK2btTNyY_R83v|N~V{E+hIkwX1N5OQ$IyM7j-ROoXpdvec>8|pTL?E7fT~Fb6sbd z@T`P%zUKe9asPh!3Q8>BS^G%Yt5y6|bn=8WOR1-Un}UvAKk1gO*!gOSiqXPWf45@0 z&`F#I&x2WXb6=aKct>fQI>b?@dh{8Z4q zb!5`F@@-<1PqxG*m$2KZz1eBDt=oAZ_%}=#y z6VZINsxOv(?a8v6S%zPBE=p^#Vq%l|8^lRWfAO;Rs6FRA=J*SfcF6Z7A5T{F9OQCeh4?4ocMKWmd)4nJ!emSsNZX&d=sYOrDToHM6Y3^qI;KS#f{~epicxFLf`z=Wa-Wy&Ml9K3q_Kb&%y zCeQgH+%kbvL5Qav_LuSB=J?xVk!FDU4Q2qyVN$!rNd~MrZXR$ExSX)mo`1{MQ z%GEKJ@ts1;;fog;&-M8y=$88KFc!FU@Cw&4t0y`KuPx=>^XJm(9d)(x*4DQpVx^V6 zgZViZf4>^Vy;x+*rGV1jU0R7#)B=}o{$j_`H$|0YR@W@aMwOEnwW~Z*yHw5wgo*m8 z1?RkfbI6gw&*E51YvQ(fp+W^mkAABPWcXuR%y8!VwQKy6>A|@@VhNgsYL+v$aetWg z?qtnQZ2|jtKW8hp8K<;#tLi$6b8PXEHIdzT{pY&ozU{ZS&sL6{U>tGZZ~po8ia$RX zc~+mat}f-D!`yt3!SfRHbDqp;71HzapZ=b<^=VymGs|;MSK(r&{39H(3<+Bry`~+? zX#crp*-hh~{F_?#%6YB5=Ypy~=2#squxPoqHgsjCl*My{*%N=6?-7ffmYA9$Bw_u0_9pbnY(u44-rrpHC)CQ8z3u-8&(C*kX?OjmBaQ`EM>aqBpVVEhya@ z_vTswAIC47WFMQU#`_%^WX@D_2^C*4E3--AY~;STGb|(d{WhJ)zq2(`R<2f2Hj=;f zV1??IEzw#^;$OAQxGqmpah;V~@vl{U!#1}S_m+K|y?2$;;=fN`a9j&K$QH1}_pV0& zq_1&R$%zu3haY$ZTz@Tk#m#$e za4f-Y_TqJ!*R19GH}19lR9qt|tMK`!O!_aL$tNY#HfwT9zn1C^dcdu0F8zMyH`7l? z_pE1&S-yh5sw*I2vUKak(nq(>#Y-rb=(f!%yl?wp?GMucOUVZn9gO8a+V_9v{|LGj ztK!oW&S#%3SFKVy*7U#f@JFt=UuV(_?oSg~Y^Sxp@P#;Q$zlVkz6%o0hUbqh2r~7_ zeGqY4-qGg75z!;@!Xkf6BqpqTbZe^Zo0xlS5(Om{4TqcEFRW7gzn5W?isL-)4BrBI z&4!B$`X4@3oL8MEzkbgrqix%_Z``-fPj*SlM3$@`N6VQ%^IVwMa)`cZa%<-{aAa~$ zGWXcT=Cw&*-IL3JZK>=jw}&ZZU3*?6?(vdUI2f$)_JYZ+Yo)J!`)kcmYcu)%+U}r>vR33``la){Uv1QZ2zg>-Jj8% zA9L&hly(ce*WOS?_Bxl`?ho2 z-|I>(UT~#n%GoKQ&b^-UR!3$uUvmsTn7rEdeD{r2SEClM%GzXQc!?|JWmh?ehfT!? zhWr1X@qf7WeSiCI`FfsQNw&p?5|3A8x2l}Yyu#qct@1niboz^3T1+wSJEl!|Zo_n4 z>T=NMrqu_u7tFk0qvSn5@V8Zo^^5Y?^WOD-Uw`_>UcK^*wf0I?E34yVlvaTKry}iFjnvvdvWaV)^}x zO|Z29k>T%!-@CsTNPO_TB>C19f2}nQCY~R@e9)9z>3(9} zzYfc7nv%4rb;G7>$CHsyjEzh~i?pDe;T z%i{TlTMO1n&zUpt!N0%NH*VcpAelSMQBBt_+^f^%sgGz1Y7J5u2YWu#Q(_s-Z)QPq~zj>x!7Q-~o zw$pQ08hlq>5y*Fp#n11&!Tj(UerXz~wdN%WD^7Uc+RlHmEp2UQRg=kCgSmc-HcU2= z?dF?q5N}@hWU`89dUDvk$9^t*ZsxS@T9RsMFVdf@&f3*!{O4wm&Cf(; z-fOl8wk?>=#~O4j(l|+7PlRLslBW-2-|`A4)U3SxJi^8Q@U9u=iEGRp z_RZ~5g6P$23cQY1o=gWVUM*`Ak(pku_wdqE-8E}?F24V&nQ{EGpno5~;mkP;bkbKm z7Zzz%@a5Oou;%{hg4+L9aWx-Z-@JR5l$^}m>?mJ3?MKqdAA&R7VkJXDJss`4wuoL6 zY_kzbU)b%mOOkJ<*OHan9oaT6H(RlqZ4KKb6W6#eo)s%RtS|a_P4Rs^Q%Z7&$h6|u zEgQmCy5;BP#U5dZ7h(8c)PMHu*_+p{UHfuvZS<_-Tfa`kwX-gYtzZfLY^=lZ{9Gw- ziTK3NA(!v=m;SH+zT`$4V?;!5;^9XkVtV{<1bP}dIiF=XW^QR@b^UQ~cR7Ff`naQ8 zv#%=%buQA-I33NU;>o3XNu#K!&2c5$s%0tr1wI|z*>LgLX2yuyv)Y=kc3EV|6-WQP zypTB{)YQ-ad_X8K=eaJquw&5%*B+gmtp4L6|Nidk@A8j6K4zXXZ_dLPFF9XDC0~#~ zq}X`kw+c`5r{}s}T$_8EnkSpEi+_=l@O|^I;Me{oa{%m`DwwZ*aI;s)JkR~Q8* z>EF2Rbo}Uyb=pTmPMHUNFYeTz>B_TINHOfX_@#w2as=z_#d%pbjwNK*3eW$2W%Z3)w_1X@QZ1V=^7i$6o0N9CUA^EnxxoL&oxYYY zI)CFDPfyo>_<8<+opo>DKm7DfbxEdJET5wQ=Y`CABYVfiD-r^{98G)WzZS-S$#`O! zxS=;FVa}VD!wi*SgZ{wAN(C zV~O=^AAOo?3fgjU?QC?#+pqSA`tAP+Og<@c?NZasrIxeY96MMlCoW#2Y3bwPr66qN zzS!i1*;LnyaRRpsj~x(xxAWJz?Z3r$8%^AMVdi6P>8O`hzZN+Ew#qy6a7*iFYp0SV zzMt>!_Wv&1vS4H9MZJBG?jAa1xp~3I0zU3LztWG{dox|s>(v)}!EX+1b z)^YQD-y=%&r?@{ePIDdxc*Ec=gKHrutn|(KOK_KsxYc0=8d18dto|b4dIayHf zL*)LybFV8N_sT!GH`h8q>_z{vggHN1jG51=%yMgX4`X=Pad6Lqpb4V-I#Z5i81OSq z3{sfL@}%Osy?1qU{I0BeH?99o%%Uen<_n?)JSHBiNLf4kT*Luk)w_>O z)m@oR>mCq#wM@cSL3W7*PrF2axZ(V83v1i2=UAOCdd&n4CAtQ>OqzS`%hoM|yc4VH zTz1@3o6PCw=XYU+RT)21oms_`=*Bgz0-gFQv-}QRSX9)?;)gXNyx&(u9Z5M; zmiE3$!8GCrlT}6M-Gi3#0-KIyAD-CVvQAU~!<(L}U5ySR)@v_Rd|H@QqN8>wbJx0; zTRkR;xK4Ar>bs;y&B!sAXNpW^l~w!B$4vq9nSetjvE=`qV1qOGlMYq#p0RyzGj+iP{b-Aw;@`EP9O;+VFZ}MVgn~EPC%hQc*YJNzR zzq@nrxcvR2Cr`5UaHmu@-YYoVuk*qtSBLpA=h-Qi>Q}dXS?|iBIB`p(*{OpT+?uRA z9>ksX*%5n;F?a9N?q54U$i)7V?&GN2#ygACRp_PYpKMXFw+>MviyrgF>oEOfn%iG4 zr0|y~Vq!vfSO12K(FJbk!=S$Z3U}xff4cm$Cli+vMlB3};+B<^I>I{?mH_ zrRJsQm1ne0NHE*-MsttWw&#D(PnzTwzbw$MpyLyJijvX`&72F4)FYt(v|13c6LMs*TKCvCf4mg@Pi{^o(;ZOdp;d1 zzHxUilO{`*YoCp0z}e@ZG?~8H*u?i~qC0O;zk8T3=S0sv9}a!qQTVv>&HJ|xFD>={ zVyDJ=u*O1krJH6%dQH`W&e**if=O>Zj#z3fVLH=Q+~-)|VB)*@wX3xAHrL~dDNH9> zdcNlMW%1?eWUYN@6Qgt1n7?8X-{Qh+>4^sSCw#nrW8z{Zk%m(e59esN2u$B{Y40w( zyYoV?7Q4pn`TXO-gRNIT{s^0;k{_G1Tb%X4p~tVb{{8>{dHuiV_W!T0|0jRl&(DuN z$m^iQlgd-I`&v?RqkDDky}7&obyvTbj`KaIE4fe0{Qul7*=lgv^x7o#Jzb!4 z{+N^Ul$5kwUVdES>#q%!QXHG(F1RgebPJ!N5q@r=sO}E``Eto| z*Cqrd*~A@vceU0c`{U#9^*!6~{S@C({a#Vdwx;Q23D;uXEgLUPJ5u6W&!NX!lDu$> z>nqOGl1<`u^<{RV24{jAZM+{VMQXR&ygu&Ya*RbPbn*T7mz89hq7$M&PESraRH_tp zJ4vsn)wwD$){6)a4dSuBqAHJz6N# zv{m3u%)R9$ObNXb>I8o1BsW)Ix#k^->YmnGy}p!w`>kr#`>`& zxAkFd{0kwsxefe}9x|O_Vq5mvZc^yQDBgE3>P+{Qss2i9GC93*Yc1>V-@hZ`WiRhi zka+czho4XG@GG|T@%#su_4l{*p5CGKWqZk+ z>74&pUobI!wX7}ZYtshfef~a71_n__vvoa%c-oyW)rcG^ThQ0%s1(fM$+;j(IwZ9> ztFCR?W1gfKhpG!RQu+8o6t*;F-uFy?;=|~3Tl1Aj-?a!1J(f9V*KQ8t2#i>KO?~pO zsL-=@t1?f`_V4Gfzw!F(Ki7$0?e^TL)8}GfIFMjaQ}O=Y+w1qL-_Kor|Hm=&Fw5tf zbDoyyU%q=g)@Gid@X^#?k#F)X7S7$?z%CfJ{p*gH1e?#r)6(`m{CT0X^(XJ#17^B%l-A+b5Kb=ReWzQo*G;n~rWe*VjTJmkN3 zaQnWWxivN4%~T(qlx{SpEOEbk6rtCNyL8Jk;f6w=Y&;r)N{Vi zzP+mc+A49D%vkOC>Awr+1wWa5;lh_YcZ{!}|CDz5uFqwgOwCCOx00;az1Wk+bHt*< zhRy2YwbI_*HYK24d)+iwQc%n^Y+}K@5!ex-u_~>EOT}c=j#jd zUl`ea(l<+-^_jzeWRd+QOPlYE1>E;%?}`-rTq$YH)lE?~9kQ@yP5|I({mn z=VC?2+_|zjdHKu?tCk(9F*}%3)ONF^$t`rls*fVhtOr?zI7ONn*TvjA`0s0N&8wf! zHo5%k~?mywiy>Lp#E2+{@$JK1-1eV9J1zw&$gKc13WvoP3ul8Q>%7v-57Is$&p zc&DSp^Wfb~8MfEAV(ijd=bvW}-TyjA?M!`sn?!?v;f}Qin||B1wXW)&bCr8nOM+$2 zetCu$tcnkd7Tx}|^|GvT>D1*ZuNT*p=}F8e*J%k(@5wJS+2(Oc=3L~J(pH=0tbd+7 zVc8qkxOcBDhhAb&ci@%u$;KgaKZ2);F1s8l($@OAmuYs$mUp@$j&iLsOy!T{5AGGc zcv+)2}QVT99ykMFlf zEO>4BLB%D0dqzU~-ltOpl`Q71vR=pftRZe*Vs0*P^z7&e$zFpu{1@JfYdkl$sVrds zT-3K}<$~F41!8{L1}KhSwQ zS;kk#Wf8;GbpNeUZ0yHaE}1xA^Ut(-a$lL`2meE9YqyA2#MMH*Mo6aPs<6&AjLLx7k0=|Gyl6w0nLfXQbhQ zimyg%zIUo;zG`%s!hArsR=$8wQK%rlR!MvA=e0Igo!0Lj=vZA_6z1|=#@$lCFzW1w zJH_W8POtlT|46s~zLvXpwKckA_J6kC-(3Ig{6ChxayOT8YsyRBEsrYpPupi^6?SB@MQ)btq2!Eiy-tSdo)b@B zIq`I2NW_y=p>>AO%nyl~`(B^xdijdSB#~8NH}2hYn3w*dzwN}ODPpPax?!m%Q|_Pe z_xBGxm%j1tYnexyyF@*@{JL+>mG0ZxvCC~su#ryRv1$JA8<@*;x34+P{9v85PfM$z zS4HlnmP5^RN+(ouX$FUwZWMHxq>%DIuxO$4tmh&dS|&_LXI#D4cG{%BO#iGrFInt+ zFliT)(ZmZ)Ht%j_Xk=g1uDY?ah_l*y`o;I(CoU_|3iEpW=8J@Sdw;<6V2!m4wzNIw zVd5*bbf3l%bMNM{&-!m3AL}+R_V$PmSIGgC9SBoc;LYkKa8T)x~drx_^M_!1?s|f9CH0EMND3 z?e=@OD&F3{uh$}S$#VK!^?gxsB{QG5%)frBKli{o^*x(E>aY0IZ2o&r@Vu92mNl2p z@$=zv)7~|8&xx~^4bg0;b%M?QnF6uk4+}-9&+9`_kuZ`>a&~=tui@#z`?wHmdK6!`}^kq zdpZALy8Z9SoSd8=XD=NIzJLGU?f-iJ+W-HnKk|J42dzmiRT@6KD=qlH2Cj+|4|3*+@#Y7seGz`F(#lMJDQOV(^k%jrXQ+TK3|_{GX5f7q82Ta96*wY0ZQsLZ2f$A5Rwc zStjhGw)w=N2R#=q$C|s`_~C5$de64S+96BM@UT7pawua7w^Np|@J54IOuHW1e4CkM zyo+J~moJs(Z}%;Pdk!P7{?_f2C#?=rcVDbHOl*x1>AOo|Y+{lCWe)TU#u zvd%AL3eTO4iq?*ZuZX$1w<-Jjw~hPub(wfGdN2R5d2+JMG}VyH4y&a)84{!l_@1n6 zG2)VzmacgDbbssgygeOz_nwyEt3FXBd2ojiUu@=q?uMyB7S`6i@0}fT%eQhFJrr5L zmRDA7PO}dOkC{~Oft@XeQl-9;f^$Af90;vWe7!X$8SYKr6}lcndR z7Yok+re1b(vcr^bemqi<%T|6ldzhI9Q2 zUq5q?h>SdV>=;{D-Ffk@jon8iwz?m*OrPT{kt~!P+F!iWbmpA5(^G%${8{s_b@S%U z>-*gn=f~!ptrzBIm|6Q~&hNAF|DOI&`TODH!3WL!_s;*`YnMMuO)%)gyR*s??Fo0- zdv8emI~MgO{7x~-?+%xXEctqqLVC`2I zT5P%_{9tspLeQ-g{&{kX)_6y(Iq>7?g$UVMGYgI#v}%osShJS5;Oo=u4cCHCu{0a< zX7c`ZdZE+&L}}BxrAwNeIoNVNuf}}gnv%-dU~|Uxmis*Kn0q%5PMv#tN6AZ}xXP!Z zF?+Z5zg=58XRgoQ_tA+~a~JD)=j7!noz6&n^<3!8{&!AB64^D$vxS76xupsnzrF9> z_%Pze!JU&1S)6g1yVPu1;l!OCE*wG^SzoJiml?f%TRY7}ylI!j97C<5Kbos^9hJpc zx;rPGu{L1($S!+y_tzx5{#~X2?W^;@>0B?JTUl3ak$kT5bKilZJd+e$Crrs{PmR&LO_*zmOZn~kVE60I%C{bN$h}&)c(Kja!=l?(-%{L}dwP>fkg%rL5uPR%y@KO1 z=XbQ%Mf{#)Gn3)3&dLf=o*;&IuFovhzsFUtegC_b?N%v|N_wea(9&~^S5hOF6t@Jj z6f{)JH1Zr^I8xZ7(It3X@YY!x{l}@|TZ(7uHEtpy+EB<{B*FB9{o-g%nFJ2I_;lHY6 zy<*8CmM=4t6F%%<*R*U>i0b5c*3-;+tD);ou1C|t%XyX}>z-Rli=BMJvvkqM8S1Pz zV|&}Sb{$&8!rsz)ocT#4o4vr36%CA=Q*!qdy%hTOmzSqqT40WqR^_e(U%p6W&Pteg zF2TENlU}#b2C01$GQKk92!ha)o!*x5S+S~!|!m~dvcZN4elrQ;f@b!Y!?hCrEzpp){< z%*;O?{<*v2@mh0D;RWU{cV0b;zW+-t@BZFq{raD$Pfu(UZZ(R!m9XYn!%{Wj9qDWP z4qOafcE@h+oVXdf%dX4I*Zg^E(e>Ypt8oA2muKznF8eR7$#6$0cHTU>|2OmhzI&hZ zZ~p(^|F8Lrb-s6FxRSHp?8j7Q@%7KQyk35!RQ%vCi3hGx3_Bhr{7pG7aiZshbfa1i z^O+zH0i7PT`XW)Y!>_LC?|l5qfp2ZX0>v3iT+irD+`R93b7s^T_QQ7Dwv`utDB;s& z5#jmc5LC04xh}#vBKGYrp-Yp$W?tBpa`5tHV}oM_|6Wzrd@Ig>_-ShPjhlB5AIoS- ztaorU$XopH#bNb~?a@1mfAi_Z>}V+8_t&gNq~o!~UOCotTXx-*ib-C(Y-fh@EYUd! zvx2^U-nI1Ht1ZWNaR-aWT#eZo^yRw7!Y~$_zT3{L7DTpiW$MzWxtR|(%UE34act94w}e=O=aq6iS_`EQFSx$^N6dL=f!5MV2`fc2jr>qPO=4FS_qw>q4+IAU08 zAR~68Lp4jnB@;qmSQJmcAc51=E*xhDe7PZYv_{~ z<-03hE`7bDB2(UaxAU8~Z>*X^iB^b?naI9Cl;(h!3oxB_qE;(<%zBYbyMuG61hj(7y3(Pmkt6j~#xXL+N zI7d&>|Eyh4Y!rvIUqjaCT&4DK6M4~Y2K`g<_5W7CG6<=6yW-g@;uxd-MB23@HM>u6 zRnmh>IkC*3{3VG32^JCp-mz0f_HB-M@Z^WY3i5`&(J2wiy#5v39QL6(yF6wtBZ9ma{ zy4&@W+q~!R^~5&IA1(a7-{9Dn<+s0`uV6eNvH999`G4j6Kds+i{`%b8wfyhxGk(`; zOwr1ecvmJFEO_V5=h?NJ6(ZEPt(|{umR;Vh6LWRbe3Ju8r7fnhI3?dam2*YPS83DN z?;%G|GkR>^B4!e*e&lNFEC+`<#u1APKVDL;`76KQzc|MGg2KzDL>7JpnR&t4y$T%{ z-iqs0gE?BebMc3mU|K{1K?@C>MS(UZk?;hVd7K_QH z{~Q--)J;!&WKtFA8dolCQX&}t_vrkf-gq*N?HAtv$`wB_SbIBwHdk^^LE_s z6Kr$Y5faIzE!sCvwxN)hyY0Z@#zX;*nEl_3>^|S(joDiy`TYF*i|J8k`L_#izX@!=&9O)z#!F`sOSfy2 z)8+dgU#(s*$lvkBvsqGT~7pco|=g_w+QD4=+zrTO~cmMz6^)e!rVn6oXH+ph2>DtP- ztod!b9tew{5??v*x}t;j-hbjclX~w*{hJkg_sOa<`Eu!frIjy2yXO`6rEGMVq+&XK z-=a&VAD2$enrqm$_wL)&Z##uodnyKM@jfgDwWPw=#~$5T{Cwm7ddBPP;@xGApA&Mc zOJ6E7ujY@0mnLYweXsnUZvEPq-X|`z?)&q!zV-XPTK;|S6ED0!7}fmw`FUmUpgVhh zS{*WI5oi10JU?J_YGd*9a}Qr$R_E)zgBDpUyF`+Ey~%d&6X=G<$7`Jn!NS) z);34(R`VOqKI;+t*35aS=o(XwCI-)KXLhXr^Xh+4cy?^W^%h;--3lePv-^6)MfuL2 zce?yBp{K3%Zi@j=cH_J$A{nJ+Wo;^+7YaR_Qq0dBJRsouu&Z^=EsM`O<;g9FT-9dJ zn&uJ3_g!kIL)?=Owp^A;XWZ{}ZM3}MP;YVM+&4a(^Q^&{y(*CpZf;heG9yx~V-dq! zKklVL7u4KeaKCw*^YG42+nAkIlGF9$4<%T*h_DFAm@?h|%z1Rqvtk1`*5aE9@3|E_ zem`{6-qyAD*rsMxRrl3bmtNOZozdF8XW7QaYu9?uH%y*v_-T{NJaGmK8%@FO(JO9e ziUou^p0YW-?GO%k@J$j|FPU-B@+}7Ah0k%HSHu*rJoeLK99h!eXnb7MezrTu-4pn zpZ7eZ!z|eBZnf~7!xFtGE11@bzAvl(U~_)+HLmP6CfAP5*|_gwRl1SoZj<;Q*B|fr z`uOqV$M)~O|4t7&z5D-C{{M2m=XaO|I23o7uCshO zJ^`Qixp4wGPH%QZm$3T{$KT2^X;7HslC`1oe=i;thrtD!-5Wru0SzMvCEv5 zJ>I8O`YoMRCkh886`MHCO3kniIPEoU_iHYLb9a-DW^LWLF3D4Sp{&l4Q#SiQeVHBQ zdw%DNsZY0Y@XHHAsJ~;cG<;uGTtGVaGE-<^B zlw_4`ip>mhn5E^?&X{prw_%}T!IJN5r>rU#TXksBtl9fGT(;(UuMvyCp|<8!>EtcB zJCvRjbJm6?ZfSWIuw1P#`Nux?WYbA1Yr7fltIv*|mj3nk>Ml`D)u&Pt%;!9>&R5|U zD%};fPm_1a7X<~y87qVpR$q_VZRoK4l}6Wwy?cA_&dn{^9m}%Me^DS?&++3IQX5Tt zHNHtm?Q@@37OHZ=>Uitl&lOLPov!$KOEf3H|AKspU|V4B*_bq84UJf((_T|59d9Il zk2-S8qIEIj+8{P3FP44$`b)%WLnXAACeD3vQ9?*QP4cDmsZA=o7jP)DxQlE*IAg_4 zk!yct6L^?T8yF``NE{LBO1)G2oXJt*`t1BkOSf`NdtfgU_{2JDIooD7>)X)+cNU4Z zJ(yGC-uT?Pi(&fucS;;d2PXdOig{RK)_jSp&cO=gcg3Rx(XYN097+gZe>meYSKzOn zseZ}}d)?+Om+(Jkx>%{J@8Wy@o6nAQL}yzvw+I}1+{1qC#X7xBxl7N8YCi3?Iltd{ zuHXL4Z_D=od>Qu7ID%oxNgK($oPQ7V|9{Kxe|Kl+<$n*F`D^kv9<)?>-XonHnVSFT zoOxXCAJIE0du3yE=Ujcie)*NP{hVP@YqvBX3=z}3ZlrfwsOPZe)J(O!HHxNnp4;S} z?)ar5v8cphv1w(&)OD+q&&|2D_v3yAjt4(4&FzcSo%g!*_m8jf|G93>73*w0wQ1X$ zNTG|-c6u8yOzR*xAqisLOwq=n8|KECcRc!6@`?4mlI{X*I_j0Qa-?J6# z<_UUR325v5(K228Y42~lo|%rbwc;Ju?D?N{cs1AjRk^oX0@mLC6nEv~BEhc0?{0xj z((#8TuDU#P$|S!u-W#E+R%;HmX7SleEcu|&%975sYKcYG!483!p7MN!4SP;ZTy|MB zNZEGsyLnOEYLY#n0&?tg8bW?CZV3|b5qNp-`^L@No4J2Kf52{6qj@LuVuF?0qlIQ% zUZPI~F8&m%Ji~kL?YoEJ|E}skyc(XLP+rboc&AN0@^M*Y(QS*j4MAM1mh7zCn|a7= zSM<7yOH!*e5_OxWEb5E-X3H-(Js@nMiRz_ACCbW-**ap8T^}o$Qccz*s`T-w_9QlZ zcy;!!uw17ytNY76|2BwC^L|pvc>ntW-NhR3*ygO%YMZQbbaB7j!mD|TeaTyH=T1p| z*buLm?vkzH`{P~E)ED1=3G}SXx9$@>o?Dci(S5R{ZB5BysdEQeEUl)PE-^KnlH&FK zrj?kpu1~=tk5_Xd)*8;7lV~+Jd1Hh^)@9>q&!2qbI4q!kyjZ21HSMzD?He}^Bp3)> zlL}j*^r+|ewXPGlHXWaFclP;i?aeoztnIh|_v88RzyGS=mi_+!yTtpyq!z=Yu;UB| zYV7`Aj{keLUf8Dg*Os~G#Ovlg-)r!ta;rtvy#7mP1y=VikbD~D+7{NG5Nz_zN&LXA z8wsHgQav8-JJ(>oEicxLo8$2&hE=|6e=XOU+MQDB$GBz^Z>I5r`Qj{gznbkr9=@?j zIQJ=eF8lt+DdiEe$r0TOJcU(dZHpHx-`QI&KL7up=Yp+_HU0@TRXw}Q-#2jgtv#zd z=l=b6@n0u4%Upgbadn5ESEt{8?(^Rdh%|3h{q@&wla8|l+gFZdFQ2;0nl^_%tyg`N zowMxh0{Lx+Dvo=J{psGp>l>IjSvsM&HT7HTt_jcXZ{M?jP2OWO^P9^Y3jW>;Q$R9>- z(t$_sT#riL7;!~<(euhDX$EYO(d}k*wiz|0>=fq{rOq@oVk(0NWpS~#4K4r}@6KV5R zA8O_I-fP&E*vq7KTHNn-assdWO0OlEt^clZES7k?;%S|j=rkV>jq8ak_>7N5EO{x@ z6DU33`uD2$zfGnUT|d9ZR`^RxZJ=T4N^wWzNu#%ub9S!S=fwy5q@ z@Xiuw*6l8lHRmHmNw9+vvl@Wt^MNC~+lEac#Vr6P0{<`}XaYA0v5oh)leA z%=@y*vpHWS9#>y}`Q%oO-Tumgf)B;}-v4(MV3FT``|X>{Z~rc@V{wRoTlW1gzxRAcq#G}RA+>W(4XGe#~pX|Nrm(<*n|SDlcU=XEyE-eR%4F)n4{<6Q)Ye zv$b=1A;x^W;=D?S*2>d4jdk@Ka-_9`7l&%^T3cvbzkToJWy^J2Qt|@Lw1ZC0nwPP` zXxGZ9LuV)Y+Gdv~PZqaycyayb=Mx#>C)X}_3|kv>ZhF{(WzmVTw&$g}%a%s0=eo2? zBQq&qdwrehAp_o}wz(_rbnbb>6}i4D{%lj(ONIr(GX!KdgveZaYLxO{WXY)uy&b8W zo=o&s&yc2~i> zJFGFgY6Pe2#U6O~j_=l6v!+vF>7{dJB5r=&Vy1U%M~xqc*L+Dw&bD<5%@<1*UH-F7 zaN70#^s5UpuWl7C@oZb8Fn^zx=#npjExO?!A~JY03NnIAQ-TZ*8lEo}s(m))UwKgx z=-ku2dwc8ZJ35Sy-}$hrA?r|2_+!oOa-NzGtL^H(-0LrRY;1lZZ~IE)<=n6K6>fVI z#c{uMk;SJq4racYF6j)+jRt(O`bU-Yy)U<|we} z`uoQ>56&!Rda*0jdZv#@VYaSnPvb%j@084kVrie=yA`tJF}~xJ_|dVLc%3YfZG$-c-&GwEGW%jnpO7o zS9sF0uKnjTmkt7-W3VNM0lm9-DQ{@%>M!@NVp+frolp_5Z09=>1yXyRSF0}=0`8$~ueS_T}Pu`kZDEc!; z=CQ*<9pAN%6Z_^KWObKmxpDL6!F%`QnCu(ORGBP{d_GHi4NRo8KMA#JCHAhhZVGjD4vS(A)hSl4 z5kLN>GOpGt{auSsO|4VH^SpWUpIM$-#4=q@f_aI!5=YA4a*1R{$B&129Og|Ah;n=_ zq`rLliA^H&o+sM*zxwfElSaY!ceyQrEvKiiOGq|hNS8A-mvSxss`&6)Qg*d;{I5&X z3knJvZg0;^{{P2rTlqG@ZBZX;`5WIKc2YiFw4|~xX_W?-j7rHI$i?vO*D8)j9CH{`XA0k&vn$FcTTLQ4M&QdK_M9bK-#u@=tKIeJ zRE=G&uIID&DkuN^waEMbcX{+*|4POOf9C(cKL6jx`7wW*?SC}CbxPeBc1$?NfFVYD zZ<2ndQuFH#U1>5eZ=Lz?%INf($tn13?ezOQP6-+meB6F@&b-4#eBQfHbvbDJ3P14^ z-Ft`Qj^C1L-d4$1e!VWSx}y8RM#6ltncL$Wn`IrhjSg4XxJ`TRw^mxIYf)6kWHnA3 zMZ?)=FXU}EoP9n)lAWDh-0o0Eu+Mr^j>l!XeqU@H*A(Uox+yI%`t=e<@ z?V_t$SM4`j-4u2dDphp2AAfD_`)6O*TQTl?f4yEjndj{czhAqnt0lhuGL14jEi6*m zwK<1zt+$82)x{LXrCd`|8^g2@tzI8{SUUgCk*}|>Z!mmw_;Zbc-U8p3i`KBVzO~4& zV-?n#yD5(2p~bhHqf$|K#TAcq9oSf{lVRK0v%Wv-0>qO(|CBi2C2d?#u;OJ3*A2Z$e(u=vvJ6>~4@(vZc2>XLsWrE6 zNtCkdTG@s|jWp+pM_lJE@-X&Uo_yvq3%`7A$Kv$%8~5%V{B}<4)S3e)Pa58O8`gXK z-i;T@Ca;o4fcPHvy5>&5L>bI;k=?|S-wiWoywrrr{R z_* zHob1WIIC*%^2>6X2fecu)*j~HZE;!0`}O53RgO+y9J~aC=dt^8h#GTOeg6$Udg(;rfRXqzv~j*kLNKSj+xf7bY{iduO;eM65CW>@9di#8+~W> z_vocNLnFCF8k7}OSoyc!mVFZWuxZwc*t?nE17-<13S7zkYrylm_ku*TiRXkg$+NR~ zdqs8#Tv(TI!S6;Roe<)ETPbIwIqhw&q(hb5U(3gCrBhqaMx|8t{Y>gp@jkew;Y)2x;OtGZ zJ&r3)W|STZbdHqR<;Y`WX?e7K|L<6XbA^AWPTx4={KxS6&(|%s8#irbi=4LLzWg=8 z{cFQ|@|JVo|D2&`H&fy5SAjM|8_&gDo383z=Ue|vr=YKF_gfh+E*`s6hZb#U74|j$ zQ5WFOrX8!dd!mzrgOm1Kkw3RYS6;If=Q>%_b+e@DXGxb$bb{5)hX;@MPnatCN#}Tb z|GQ)xOE>jC#TFNl-(O@hd1EtvG`6q3$T54ib;a|y?*+tNv!_(@X|`UTBcZW$;m9TC}=<8>zOT@-M=N#W0#hYuf$w+j4U zdH?-<4n;dz-ajUy3{G6k42##EUBCDD-}n1V|KFQiEdS@n@m#$fDQy7<*-ra*m`=I0 z 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

tOjQB+tGp6L! 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/cpq_port_386.png b/src/qt/assets/systemicons/cpq_port_386.png new file mode 100644 index 0000000000000000000000000000000000000000..4c55b355970ca6a646181696c56e9c2f9c5161da GIT binary patch literal 250814 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ℜ+;80|g0}$Pdrv3Wj^_@iD9P@9wGn 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:d^4PdVXo?yZ-ifcb^s< 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⁡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%0A@k_*dR>4UtcE%?j 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/cpq_port_III.png b/src/qt/assets/systemicons/cpq_port_III.png new file mode 100644 index 0000000000000000000000000000000000000000..65d2f714ec6e4124aa4605928d63da6319791ddc GIT binary patch literal 202844 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelaj;ey$3MC<#g|S12gTPs_|n zRVb+}NL5I!$V_8ksJL}@PGnii_K9uxH*)DSe%>I%z&Pi!^^2$9zbl`dSUd?XR-o<{{=dt-~IVsAN#$({*Q9S{Y|HreznT_`e(YkT;V6@@ALmZ`z=*d7r+01 zcl`dpFTcM#&OI?+b>H&y+t(-HY3= zCCTb;kMXv>c>RXk7t1R#`Mp){AGcmV{d)V-@00z_e}%-@%y&I`pZibgGyA`L1-Z0i zO1f&)RQ~TfcK)u)`yWD=d}Ka=pV6(={kHbs^8a)GAFluZ zE_c`c`_Ffu{df8f=l)Z3hv+noN`Lb>uM}D`-=$t7yTzS7-VRmw#`nDIbJ%y7Qf2I2C_U)J~r108* z$Ht`-bxJ2C3U?jJf83wV`F_jexp})USZ-#$C&kRJeDvR5`*-j6{ESOY=GgZ?LVKOI z*6zjJQOB07-_zUC@_Xxwr@9}$&$s`#e21Enhu@}6clnPWT6bPCjC23PpsGf{JsUs# z4gR?B=5@vhCBN7mGbVI2tXJGAl=VUPm>3iHP0kBXE+wBT6l@IeGSM@7HbrCN4drg@ zpB~)r*KRy=etmnl))}Wpvn1n7DiN0ApO!!M<2yUaOK<6wOJ4em&&*ntwf&4Bg zt2S)A8_FJwxYD)^kgwX73xi@ScPViEnU-T+-`TW9Xs#o)N{S+(L{CE5P zj?eB__8t1Q+`e8p>!EhmM^~@>9Q#Gb@}qy-xd_Y=Ioi{4REF#7eGw)hE3LGB?Q<3@ zEuZmIaAlX!&J&9sLxlm2uk>7G*M7mB_Q&6b z2O4jDT_>1)@$hoCgT)CscP^*D3BL0C^!s<~<9_VE|KDEz#k%@!JoUfq4!=qJ*|x>= z#3rZvKbtO_KehAjFBURR^7?k~O7qh+_M9zdSsO21mf3qvG)gVCe80wmjrud@Udwu{ z!nI+(*yRU164wbkztz4yYtF^nY`@puyP5N5^P_jNcK&yNJ$Zc9B4AfK-@V=I^B?w1 zI=1V=@u@K@+QZjp+Mt?K9BnTy-^e)38Gd1bxduJWjVccz{%s$1alTV-OcM9j;3b$52L?|*1<=luoG zGybz(?PcqCJiA@Ka!tuf9ijbqPj9{ZZjsWZr8~Ih`@W97zhm|0Q!PrLy;gRvUOJ~N zx61VRN!`7_JvP7E?Oay)eqyW6c6n}f{b}7#AG*C;ap2^m@2TG>AG^1qNjleHG%THxTE4Pj1 zJK<;hWf^AgNn5-2$F-(8oA{0@pRieYQbtw$b?sqcYyNxF7$;t-id@S4FEZSQKhSdF z*V)D!F86MX3acV^R}Y!Zc{5b+ zt2!(1UbcnrM{m>9@akPGE7Y~;A2Lt*RkQW&|99oz|2lK!7E9btElS;5#J7)``6p< zTHOVkW5l;eF0YVo57F%Vq}yDybkW+_NkwO}1vsnPqST$0j&EX3pSWVBM))su52C(hkncwTFk(~5=B_pVy_ok`$1IOE={m6eu7 zm2yH$I*ylfTTh;D@P|+LP~(G%`>W46#!bE$qcKNx9*^Iy=IEN;bwZ|}rd64rxK#YO zG5H$rpAT^wvradC<73!%g6m<7;;;0EOYC=^=uD}u(|EAQgyBYLgQcGY*G~4Cn^LUj z2H7@#+%6+zb?%(5X~64gPv5o({LE(MKES`o>~mkM_ns#WNJgm|lBs6{H zU&^H;S3Hyb<|f1N%J845KW==r=Dg66o_?g(N<-57D)*6{4VM{q^gPcF;E40(VYwNidlPO)%k@ zUAUt$;^&P!A?hK4MpF*@f1Gvwmr0Dq&eHE}YKl{*i5M?vVU4(Ly1rB=<$`Exuk7Ph zoRd^IerUeqIp3TUb)ix6lHC%wNYM=T)+yezH|A!Y`MB_MwDYXWm#!16?sQ#xe1YMc zEki>0qmPRBLcVR^;<%0L)7uTpbc&B@?+%<8lg7BwVvlQ)^9#|x52x*1a7lMs=52+! zbDptlhbjBjvnv1p^V=un&$I<|Ca-es{}mJRS z(^dIZOM5)dq~A1Pk5WGVtMAak(8#TGUzW+P44r?Pq3Zm;D+gnEFFd_Afqe~U+~U#+ zproD=!ky^TYH4HBD7#)#4hFy&n`QCWU)-jcXs5KV^~)^ zaYrl9BZldoLFZSW(%i!6-x65-Zn5HrUCdLYc5LW=!fMxRdd5S1lE(2m^T?jo#=~VV zg0w7yUt0!LFHpz|iISX?bv<#`P6ibXLm%m_0u15a(u*EjxP1ILYe$lds^jVBiH#{& zn3-qr7~Yn>v}}=`Kw4<5K1cs6_QwitCj`#+?zq7oztwBfq<00Ydvm6y95EABxqBjH z*XoSR4Ubf!W|qjsu>G1-bhNJY9^0iyBCib@4hmiPy{jUDJ3^$dI zI~}BB+IaZt&UzJ-3mnIEgQh%)S3Kx@A*x6)k>PRFn%-a9>UqsC zXDfCtTf2N~;I{`tl9OvvdfzU(WK{(779*y zwY{`UR=qLFQnEZKRQB?8F`h#zzx9d~S7_X6x#rO#yV>G}jD>oBbjQ{PIhQVngPeVy ztD=uMyC_{#&~Vun^y?}O*a8VD-ksvmXwn)aq znm5V|B!Yf@t=%3mKSErBze(`q9P5DTi%v4m>S<`%wScQ?V{@b6!8m>|R)@r1J&W$& zGs`zHsZ8iPE8U$<`U__LU36r{#*G^@ zJ!^YsH%OQI=o^Wj?YuOhr|D5!Kq}KVU%xd+nkHN3d9(Yix#o1_TGW;f3k9yEEx&FZ znA69)n)OZELQSOupSW1n;>3y=eFfH>yJoshmb)eA!yVg6`IG0BC**o;ZTYSAh2sy~ zwDw$aAt{Tr2;bHF1)^u<7)V#m?cAi}e!%(Blb}nkmmgGeW!?sIlU|lQe2@=RGlZM%C9lcbpIrE%5(~&+bIXl6D&V0Rn{yl z-?NzMp!^Y;)mQ#LlbaAOp4Z(KSEuPXPw}!swAh@G_-E{w=5w9rR-bfHTw%$ZqNg(i z{Tp9vPMI+)%6&R}uGCXm9gY*Td)B=LJ49k1-44S2X%?^NOcp#?u1}9sGnYG_}3p z^Z2={Z-J|w`@0PhuhyIk+;~b>q~wrWmUQx|ud7`Ij-*$vO5QqY%886D238d@*>5Kj zTU8GjJXfF>lsd?5yS3wVtYYnf-6{akM=Z~1Cd1+NI*v4UH>hf#dRGK zy?~+WjGk(vtH+~yU!ONVG_$DX;JhBso%ZkVh1hJ`8Nk0?=qBy!`m`&`n%ipP zJ$CrE>u31-mv8}---l%`vTcJm!nkguRNu>$bVD#0sC-+1hyFICdoyI zCT=p)dCl~`aRF2I1T(9AN%2!|I*uEEbNJ|=uCV4z?45Aj@T5(JiRzVg?la~#N$&V@ z#W1VUHlpL0tJrOkTxZp!D+vZn3)YD)T>FZ{)NcOfJJO9Cxj4m2%p^Sm9dB$R(38xK= z@`BbBwD5*5VXH9f@V)DHME#nN@6ng+TJHjkulV|K+PR1>co10T!o0`2Ql})xW@lVR* zU=@`Yy&KzqsLY5y&Qe%cD{;Nu?%`qifG>jKZ)Tf?_swdr|8nk~zOSk1p4%Nab}#AU zn92LT$yj6auQ_5hmv+`asXJZ1!Ai33YRrB``)s-C9bW!6_tl~138p)rUd`vbKz-2yN6q6+;7ua@uXFKx4gxsTUO@o!r$xv?kY%Ihl0IhNVeT;JgZ%ey8-jsJ@L%M9rcNpqzFPieTaJCup& z)a?%zZuU{p|L*kgmrjePOtIoW!#7t>TkOeo-*J*h%3<36t+x477)u<3pIWijEvM^2i`*2!1@v+0?{G@fGdfBIXCpD05`TvAp-{v9paL&i@;|>4IKG>fqQ_p|8IwL-?qE$VGfz_ z;8a!u%bnIGOIDgX<~{q#E%Ezv`FGxAhiqkc&hYiJlFHL&F{npI*lgUVRI`BFa?j3S zm5>z2li7BQB8Rf(#e*B z-&SIWe5OBdBS(a6ZmrvmZAwlTU0bGI66adOn!Tc&3+9c(tdPzgJoVmRTbZAAO}(;pplXU&`*|8~Ov>*X6-LKdXyPTHy~e^>0g z(5E$9eZRI^q`A4)miahN`S~fsBQopr%LPfVR9AZ~nBgFpH=)H(@?gKabKr_EA40FR z+FWZqf8bITbJz{uuiIB>rmAwT&9e?vSQ*jt^_JR&h{zB6Pk6os{q|?fc~`iybly&d zylaf9Yxu6e%AUoXGn3tyv3b$i-!&%t11*k79?sXw6 zwLnnAd|Kyv%e}VOKYTgwuw&oZkV~&Ft1djVc~-#-o1A^$7DOtq(fQ@OH9qaYocSu7 zt{lw!F~#t@+%dOwhvQ5PJn4&aHU&(rse18NBbJjfan?JTFD<&ePCcmp%`Ou1dR^S* zGbc{1@GlYOEdElR8#*!I-^^qanMZPqS8er>T(Vc=)Hhy+!0$#M=2kwB=TUx>c3`IV zEme_?f^&`YkN&^5ppj*jwm_922Q{HvdB&fd+tcw$TDtiKP+K3L98y_S|Xqt#;Lx*h6a zF^}t&{w{E1{UbfWv^3S@(acD_`tY*~3Ew_i8wl6v_!l0#AagP7arD6u{eMSvlkFe8 zTe{Y&<(i{eNl?J;e6uadpHED>bu>lcd-MS}`AL5w*$#9VJI66>F_U>vmZMcx8*d`{ zlIL%>_3GkDhiltKIt02|mDMG_?elAiI;Ng6_2QFPji(N6cKQ*w-GJA9ueIqvQ{C6E zE2DS{P9?5%s1Rt~=V=jBJ2%Du5+XI8w6x;^i; zkm}_&mJjxQ&p2l}ZN0+l5VD%JfV(`ZdGe7XbHi>-Iw94`^DXGkiQRjz{Ox%1(!=hA zrTo{`58s3x|IKwUCC2>D#yRfxET#emrX0VbS2)e*_LI4&v@-PKQFSh3x&w@MqklysD8wTKVQefeG(&cgTxKFN*J7 z(dqI{P-Lc5?ni~y(^p?;TU!?Avu|~l55v*UTW5vh6jv=#xEj{v>?<_)4!es^%?hdT z$d_AZOn7P$xo3;n1kZC#wlhqU%-gdJ_*mwuh;S`jd!9q^j{o2CO+p+O3$9hp{`OpP zKg*{Qm(G^A&TclpH0N5GPm?iVO^aaW+FGp;mUSsY(5k zwTAk00+sJsEgGa!Jj5XeWH?7q=H6&Ef24#&=EPIB77Kb^gc!{NE|rkAdKp$8Z?t*qI}v8AW}+?R}G zj=g&ddZcpa&9Bs*VzBS9=EVs|W^v8TI{1w7a{Ht1mBD^`n?rIrR`j)Te%qFtBC+C_ zb$H~ie;KN~`KEo=>nh8=S$N|Xb2|Hvs}%<(7F_4yuhM=SB%<24?5^vfR--N5^Nzo; z+Oc4=Y-Cw3FO%g)$yX*z7xtE(jIj{pm3wu?FZyZ8kD#rq71VBfGrzgP{q~B^rB@7Z ztJE4={Ol$@oMmzQLT;e?g)5r%D_8EFx%8x3tnW0nmB%=1%Wu8l_O2~?D73R_>eV}3 z*(dz7el|>Uf4n@Z{+yy@-#_NyxK%|P8QKk^V>b%l=h0eMmKmq-Y1(jW&i97+S2tMR znrsm9=8f2LD6oBojB4y3%ME*sOQJ7qmW*>^mh9dhu-^ETQsb>!jS?1t$xhRnZoCr7 zS#*+d!(?N%%;_D=mx_3*o%!XkJoEWpxkcBc|NUc~S+g`q`&D%D#0G;&?Cwnwc~SAc z0*x+yzGr$}7D_c{`!SkjJy<{a_|4+tThA}gVzhRMy>`y$YIql8SC}z-7mE1ccfpF53H z^=#x-_2n8nEW4P5CfH5j`m*gxmd~P8{ufyv`2I%AKJdJ>A~LptQ6=%DRAc6mDCr4C z4yFpbj2o87NvBPoT+|k|vGR^mkwk_}-^bOmzaK31 zH8J+)n=^HbwAfXlYkOi}74GJ`zGrPThgg(#)^Ejs7Z0x0e)XVL{!;aA4_4k2NzSIG zFRoshIMHRr`U|l~Q?oa-eE&bw!0DM|_&qE06PublKJz9!xJhkv{*~n}-pnj^)Y{SF zUT>^9hivr|^_d5+x?XDLa`a=leD2ehP!;C@6>Xlknt_^`Ju?G61zO*z9@sPO@{Wb) z<`r?K$Yr!>=p8UAJ*2zBU*SX3qo(W2w6rT8etoWbrJ(WJqGhfNlxNDFIch0o_36^% z?xh!EI-i-Go~-#pAR#bVJ81q2`zZx0uQbkk7FdhTV|zfA%pHU$4>~Wh0WS7 zx<~KROp8N2I*nx_Cc7K*ym)P{?~{_dn9I#MkxxwNxT(yWi&HpU`Z6DLCNuS~zhb5; z6xecg$N$z(vCT~1s-jw-mhP(25M10{7aMVMdojx*7T(vPsq@TcGG#e<`^sHi>&a56 z|9a`YGA6xQ&PQ}wY9=&Ie0Dl_LSV!bzON>47cW{M5EN<4A|oj2^y8|%xz~n9L1sU- zKMlO!IoDMkalX&pd>|=&!*|bYJp)T@XG{D0PHH$i@fsR_@NsAT?G+b{ii^ja*V zCZc(llq1{U$f;Xut4gLWEi&aWR;dhpZCkjU&my$-Dx3Jv6+d$sJQo`nET58n-81@? zh+>(+}0PsQg{?EQA-k!u3e zGb#VpON-}7HpH(#{Ib9<&u)^(l=dg)rHqwvt$S9S>zgs-HA`-FxcP|=ql5^n75y9? z6LurZV3 z6QAw95HX=BkuhLnf@^?rb@qvWxixJQr)`Trsl49L`_-*?>XsME4lmrrWwc#3_t&GF z2biW!eB$`_wAV^)&6%G6n4do3+224G5d$TeA)-qSmatlCKWOBSR(0Uuc(zndFTZ)gs$+XL zIv<_$t<*$p&iy$?ry>u}buQ=qk#(S)IZJBgvnIueAA#LVZA4qGS@y$os^;& zeJ$Z#h_TM%Ni6QG&acc9Rx(sJy?>?kg8H`LI}cB*6t7QP`1(ain^lePdHI9KH)Mn+ z#?(|*PLn=ZYNei)@&3WY?Xk(+cUQVEVszbqNG#>#>C*l%uQ=CeRw z_40m|k0~m+=3yzg+>0dvHhTlq2SQy}v$)EV?x@fMisgo4Tv&7#|oh@ z4(BUBq-LC1A-wwV&z+WrkukDoQ#bA_ij%9HcW^?-3ug_dBU0PNO-+yATHtk3#&+UG z6G5ga4`!@Lc*SC+I$dSEukg>xGtUpHSI*vXOs4VP30b}3HKo4qKXMmbRIvWK zMP}9N#m5AuRD3(QD)Gp*`C3A>r4*Lor-HKk*3jHP}=0zP7RBv6l zdt#^MS&uiY&e=U$6MjyvQS8;enNoFtEuAybr%=LS|JF@=r?_xTW;^?iL8O7-{K}cb zFFYD%vSk_<75=>F=4z{CVX||x*z~361=llLJbw0U;UcjfK8K91OPThfODfiJE?(o9yBP8}KYA`hwa{ARCS(x}VQ%AOKhw>3a8{b?3q2-wco>!a| zTDx?X%ZTU49hkt@IW^@;py`D4tp7}$%ng%s7jXR(3SYB~bNTUb=UE#${wMD2c-t)E zo6J@9D(#@T#{bo3tYzo-2)f#GIN6+RXo`E6|8DBkXFbouuFmLB488Dy_@Q zTPHla_R8>6Q$E*DH@mGH8BH6bo0qOwAz)jiY2he*LpQ5)^RkbxZmOD8e!H;A`E&X; z27?AmE-hK1#;z@k;}*T?c^PS#^Q6}K!y$`>yUs5g z5X z?5a9BUBS%e?p4PSV*!q+|d1RNUCA+^!wcNJx zK~UHEW;@xQ<3C(Y=WMJ9z5S=bJA1>I+Y53g9~J+uARl2~CP=lUY*xxrhehD z^kWRESo`b0`8}nwdO)}S*wa%yQq@IJ& z^i9pxXB{1P$eq3Vnf*lc+ov*J_cR!D%*sM^pSfJk@E5u(yw$XGPeA3qpWCzY*ta^Y z`z3lnjPXK@$h$k;S2=Zd`4?Zib!%SC@_8LCIv=c$t#!C)QS>&(wLL_-YL=(fENO)`jj&+Fq?KEanHj z>`u;3(BxgQ|K`VL4Zj${FPtmHOJh@xuyv^KzSiO-bU8EXc&};ttO?P~p)ap)=lOfK zJUP$7_-k>yoULn32(Npp=+WIL=~>F&~$r#ZPdmx;;Lyz0uvUMo#jozMuDyedDL=Bj%i zUf%wF_`oXG&N-~XtLO2#vxxAwzqtRy;m;&F;fCuL3%xiQu6^J+dH7-fbBDQK7=0oy z7{{}R_b;F5l49Y#GF3Ba-)qx`?oB?QQ!hO_Z1sIr@?95B zUFo}gY3{;Z_R%-LmiHgtxqnXK%u^fU<~1o7&3A7xVW0Aa;n(~4iv4AO;!{X7SbiR*hBPcdWQMS+3#l+n9IpyW7^v9Cg~hW}U)Tj+wl+6ZT%(eQ~Pn)43b{ zymd`Wxvr+%x)f2&wxMwP>fGXv)K?o`l>Pr?mYFBv*=+P8_wm6wnfG#5_A|a)V0G@` z;un?WT#eWJf1cm`=5f}&;LX=Px1CT<`#ND#>$)|P$JYu3Y`ytKqeLY-z)Uun)A5yJ zi&Jmt*Z-+*o7iH%p5P1ey*)!c`+K+qLzF`Q*DDzg0{NSGf3Ke#@%HuUADcKZLB_Z*CwR;WQ>X2`@t(h6b zRW9;|cp9V}O%e+?`#58k@Y-POs>Ym-D^-q43r>GEVPlzc_+mrp&J&S#l3y5Fq8zuGy~VjiN6EWk&2}7GB0~ zx9HzX;TyN(*3Cb^Kkec=56Su+k&Ci^rBD0fA@|^^$?45sd6q9x+tKpf* zPyM)FaPY6Bgo5bD=*;_>f2UrV_4?0}uj@bEtrfC+mH7FS=KlC8UcYuWB^>x&DP`pG zY0u_e``0Ynzh|C&`rnri-hFrX->-M~{p5e^x4){3y~8+|s;f7CZU5gW{=NRA z{*gcS76O`?%sao^XL4tqX<5B#4FdyXYo@bvfTy!FZ22bxL&cohiMAex9VFWBFPql2 z#o~tJQAOv{O$u6%G(vTnS}%oVTs`>Yl6}Ud2}^cZaIIryuNPa*r+03b)ef$v2mBqg zXHQ<#J>^GiP=?@R+2gi*zVFp9zt8Bj`Bcc}bfy5)(;n)NlJxd#vBe86kUS<(BV_zF zCC!lg{Kry$`TOsaY)7&eL-tLO#inPm@EZ+;eM??m7obNo&yG!At z^7Yi|_bsN&h*hK=IkD_{r}B}cmEBME(o&sO=c)B+t#bS6bS|~^vsn7psPwnhpTyg^ zZh5u6-r_dlfY2ll$Ce%|trdryddhl5gfp%BtADi1)_27i?bJ$m65+tBrE;AAAN&65 zY_a8Pcb5dnaO}D9?YM@(9o8t`+yCsgy}icypq_2rmcIShSkml0^Gmk85WKLTHzuas zq>_Kf9Y(hKB_}7yob>nB5NrHy{A-zwK>_!dwL5FG=Rf|!cp_;1wETu<=Y%ybH($%W zfA{v??fs^2|NUiP4=Ae9$QDz zz3=YJu8-e-w=6oBS#es!0p}?SLW&<5lqOak2EsZs!j>EvdA?>)g+8_AV2{|Lyr-zW#T9sKCwtoA0h) z<#+%8r(Cy?(qB*K{Pvx{{rlR#DHC7J>Cdg6@Ot^epp~2sOF!ivJ$m%9cLJx%Z}pJ6 zl^m0fHr2~9uVt=s_}={fzci=APv&>hY7DG*SNLuEq0L&TsKr zs>U$&)OJ?=xSAsQAFdA$zPsOd`}guE0*wj{5eoPCxBWgC?()sJDZFmlzGw0;UQc2W zoXPa#|6G=Y{~K$JIS))&=5Eqapr`cr^!J_rE#iFhSWKGToH#6=2cBIr#Zz;tR`cvt zV&AwAL#U;4Fv zV~}uz*VF&!Sswg(yuI=G?iZS>H#|LAbR=30@2zZlC35EY0S%=Vfo1Doz7}c_I$fOf{{EKz-pA{&oBq{ZI#BmXasSWM1^rwvvV}Nj{<~N0f9_{k>0wKARizB4 zkivTp=ggk>_=ipY-EY!yTUlIB6_;E-T>tWCenW9+E#sXV)0dYsg?>0VxhPG7t>~P^ za}LD^d*{pDo-wEAe05Ea{{DIE>+epT^Yz+q6Sa(Uma~>IPC2_wJ$-3r)PU6yNH*QMg41DXQ03Dvr9U$|m#r>h+ZvoM*L?on z{7KXQ@cz%-D>LW2HfxQrdR^S)fITspKb8qMte@Pl$EU7#VG>t~*a2Hj)gr$YQ3r0b ze&t!UBl_T^NhWvK^+XhXC{4DHR7_sm|Myj^mg>(Pcav`J6-&O9V1K>R{hCitA=jDT zo@d{xoOyVs?vUcswCYf~-<(g&zAe#VJhAl9!;`C?ObThaprCa5{P%nQ-}R?(U99;3 z?f?E&tL*u={JuK>qp5)4wb!N@%QBrSZI%35u32u<()^|)=DqLR>-dN3|6TpxxxVJ- z^q+m_YxB0n=+%FV|980l(fzugU;lN=|33U_sr=uQvqbhRZ22V=qILhw%m3NzFFyR9 z`}xhf(_HH~-X1%!u8 zn#Yj!!^h1*cIsJcyXJ^=SUfL$bfCZg_B)mLp~lO)TEE|ayZ8UQzfaP>&nW%AQ^ft; zIvXbMpyZW-ihLoK_V&-8{hIaou(H(qojZ5^Q~!6R|4-wF8Tz}nz3w<{Ak7i~>yrHM z&eOlv?+0f(({n$|8}#2c&DpnaLKt6L2Is!u*4p>ypVoKmtJ)*``_3$HrH`|s=I#*^ z&Amt^zWTjFjXObM{BD9*S$WxoWcMR`r89^740oXiY0oogTc4 zHRyNk73Gv{=LHqlCwvNsa_a0+h`KZ{=ljzmtCUx;ri3c0x_#yyE;qYY>sXkZggw7r!M{gct3P{(ofhR=UwLEQv$t>BO|&aJo`_^h ztoz?=|8xDns>|p2W^el~UH_r|-<$hu!kcC>glOGw<7{{>^7qcWS8KKxGlqtgJLdMh zwTkVU$uvQs?3HU=@7v&)J6N=L{{0@TrRbw>f3(;2^~&Y?lGX>UG?xd|y7uglKk)SR zbM_SumrblcKJpgKTHbu)>#q2fbw1{0Ecy@19Z&Op=6lY(>X(;ml2-fs`}R&@y7`AI zc76X=JXcwD>w4p-TuTEKR3kNZbs``n1RK0o8bLxy> z%TDioU+>JV*u&4$+$p#Bd&`6TyX%FwR|}VfuQYg@GH(lu;j-AEhDDLf&(A65TcS9f ztLbkJWAC>cEHxZ2Cfv+pYg3$cfW4;&zJV!*8k_O zUpH6xR(1LNGhcJ!V&y#-)+`^V-jCQzpKx zns-{X`qj&>Mf4;|Us?B!=VH%-Cv)DYt1r#83hJxSUo=a{ z(6My$%X;_ATlOFRop93QT>ang|L4_z>ffGwp}E<4rtb9pA0GezS6>&ZFJj8LBIKS$ z(Ut>`V+8+9*l+Mc57ZdU43(YSLgdZ z(?87-Is5Y3AW z{?nEm_XM|_*T3lh`_3v({;2y-fU(6aiq_qM;Y1e%tv zzIiKrW=n8;#c>0krM?ee{MLPaR;++UKH|(XlXIVIqpQ+y*>;IhpYi|DaRUoM45ciU~di`!YCZ_-$;utETRyddTf06fk+%{#?>)&!Gs-4W!S7mEDdOyA9 z`Kff;{_RJ~fFDllQ%n*RH(l zQ%tx$j{Rm6)K>0)%PM<*(qqmN{ReNACcV*o;}fdyT5YiN^Th9~7++3h`2ES_@#*;c z;(C5ul}jub@2%_Vc%n3K%eJ0pAv|?mr{WZ!AN1Sg7*}8PJkG$_@Tc&K?A!HP) zl~Q%lOSAq`;g0J|r6!*#e8p2c_x}Em*SG9h|8#4iS)}8p>l<>TC93@9&)pQc-qOxW zOR8bd=U|Os!NvO>dM3^g%DufILWe_9AoDsD%@yloBEsDF%06%2wE6bbIigo?`s`j( zl%unYb>^MlT?g|2+qst?ihh{+KEGtSrb~%bWr)!%k(kQVJ@0xQ-krO?c)|P9J6cb( z3q@qkRva*4f4bAqF5buYe^F*_&g2Njq%ZL|Zr^Uu4xLzYy5vRaWTE|%!9vB>-?i6v zO+Pa`?r+|2nU#Kv_T$I+t>aS|G)bG-Z%$PwOI4|Qt93Dr*rD>3;Y&}@(EGrs5(7mX-`UPg80Kd#p{BP zIixYFJ|5Jxe}0_*M?3zn{=dWWYd=D|d}il%>UW>uS30|j_w4*>A3s>K_3q^^ z2}|`56b)`YZ8B}D?-a4)fsWP-qwd?hKgQ8r6c>6j(_BgIX-`{P*Tn~Z(+#*-LOosg z+TJtsS^g}x;`ZF;(*dy?-_<_d6744DuD(0=!mV<-lq}|+)0H|-_rz92&PzD7F3NkV`a@5V5A|X6?`rFRq3h$T4)m;2%Sf%Cb*Y_f%PhNP|$8)(= ziE}P*H#_-)XGe9Nwc)b)w*-Q=NEzA2PrdDV>YU+)y+vKuZ37>jE;<};)Or1G+WItx#Iho3%8I-4fTP!8m3wWq(Hxjg&KF3(uc=y18a zTH){6quufwo#)B6$}V1^b8)@-k7bH2%jRsc*}muL#g86O7A(oU7TsldE>B9q_u$E?LK|j2d*ZpFV_7tJ>oVatr;j;X^~t^4DbnZLVwhQ> zxx>$|J?hxQZ%SLs&-tycep+~3uXDki2elhH@A22%v%GYJOOx}YM&6uxjc;szx&QxX zv_0?V(HRU+cI^K9pU4Wb3@#`l0MV92- z=ZPB5ey}&Ixo>|z=kZ+k#V?l|zS7CNs;a|y(sKG-&S^X5#Lp4_-B>B!#d$eT%9X|B zc1Xvw6wfRp#ncad>#{u!i!Phx{MPN4vt9H$ZA}=rShwZon?1YB-%l#``+5pe70!G5 z=-aE%kH`Ou9atX!^Jd=Wdw&*8ih4h{>iH4T;#qG60vEitO4~d$cfa=X=;&#aIUhfo zZj}9Q&g^IRbQfoMZO{_idhboj#Gc^x;s>=F$>mE~9~_@t&KdRe$$W4BiaG7(6L;Kv zdh5=P*;yxdi|xK=we#2%?+HyWBVzq-CVO03^Web49G*$BQ(e^0xBLyr5}jQ8@NvW? zHr1?Ky`M#0_iuG7JLb9gSkn84H~ub5(Vi)}_xJG&dxT}*MeCog3r*(Qk$3%5!t@0j zrfa-i#kus1!Pb;x3~^gH^xM;KdhgN@JEXdB(#6Dpt~}<4OXE)YJva25*>kSrG9TBe z>g@F&*JLa5&6#Vfe!OwR8?T#7w=7lLyfmJ^kah zk1gkQofU<@s`{#>NPp#9H^XG9(2E#J&MS9cEZt*tV@Cep>U%Q*R%c^6id@`*-_r zq179YZhZeiqk7h$MVCPokQ}*fX&6rnS^0uO~2X-ix-fzqjYd@t^NMov!?C{oHb2b-wwk z7iHNQ?$e#D8P$dLRylu2l_~J&cz(R)@ZBu)H}jvB-(qL)y?xo{$;tnA>2r_$z2LKv z_r~i}&bKWD_KRnDYsk;#JL>E=`RltSZQ&aqb#l%0ku!=kire$j%IoT}x@q%EdLs{r zUtDr{X6^bnQQQZ&meog|-Kp=SrJlR#(calYR@`rrjTUd;X7=v3()+r%V%keKoxPyt z<>Ysg%UL6R`SO@~@t0Z}%8h(izbR3#yyc;BplrA5u@gCFhpW$*?SA^}*R0K(jpy0d zpKF(|^XQpae!q79Z+@wFad#g+d7?6R?mW9S;qBnGYxDj6{rnoiFGnpN>`^Z<{)jMRfoqv zV$RK+)ABIw@C2QXs(in^E}?c0y+$Rz!lL!k{+oW!V=4Q+u;bMmleb<)25Jm;6?}Yr z%Z?nf?&sgea@^XQ^Y^kuvv`GbzP~z_z2rD3Sd;wSTusdH!@h&n3qLMwDYIU`Y)*%z ze^H*>amoYUdkb<%i$_U=bn>C4^p({3!j>DOwhrji;XSn>Az&EsW< z40=u;$h|BhT$nm(C!67s69zM0Tl?Qh>JQXOr z^!AzYtZj3ry=f8PShz5E_DZHr`zID$32za|n8kMAq$2Z-)b=R~F5hyizf1r5xpb2K zo;@2ZR!!Qo;HH~sapXa5*P55E%W}IszfV_qE5zIWsP;go-)_Ng{{Qd&&RqNciqH%l z-a94L&t(nOK27NG?5sVXW7xjNrt*`7%gpl6a|;UJZ{7a8qeb9^RA(W>k_e{vT1>}} zA3yWFm@mw|B=-1Wb@e&(<`tEd`CUJk`)_sx^8NuL{(jfFGPjq~*KUp#g& zo^AME>ejZ!@2j`G=e)b;#xE-)&faU=#olKe`BJk_;>dx#y{q4`-n%K%pJFw!Pqa}& zS<^i&*ZrI-qsCkIgH!*0<$JEkcT=bR>f5wm$8Xw{YIN4s7HglZxLft`g2|JVsa&(= z{j0UR6<1yO-Z@7hHF}S5vf8mm6FtLQIWO85PWjV)J5kR4;}Ng7z8Xv?=cay2*?H#N z*K>Z`tXmJx;OOC=Hf!0;RicV4PM0s3@h;5tS@Kfm^Us|3BKxxYcNpDWxNgq8Zr#rr z3vZjrJ!d|5&sF=k@)FI;54#oeBZVzp=X{^+`{l>2o6`Bq3%<{iNfnBk_Rzy!?Ws$j z*p*sgkK3l|{_};L7Ucd7aoprJC3N<&PS@?v^9|ld@lE3vsQB?hQojC=V7t3}&4+{O z78Vu>cJUX^q}6;l$Zk_zcI>mb{wvpo;K5GzeYt|~Po$W57G5hh6M1Iy{a)2{JrkRn zKOOD;^EO53yht;BjX86^o3SDFT9Kw{>qPW;Y!!{Ihn- z{o+$gUnQvL6wO9ZfiSbVf>xz^Pg*srQ2N3O^%wH+8nIxdvCWO*ShZE z^SWvO-!8A8)o=H!WBa|T?!}9h9~nHD-L@{XKv5y}bnI=DGtZ4@tyBFGJO8fb!px|& z&ok%db#oY0_+Q@kBVq5iWtlJ1Hs9s6(7wl7bGh;S1m6`m%;egWPcSz&uxM}9o+*-h zHTPJQ@IB}I>&wj!Cdb!iF;3||`Qz&x@BgvOQymzL)&#&mT#679!h3PH)yQjHwFv>Tn3THj?xNpKDzhl}3~x-!$^`ODvO zDKh`9-B{<%nX_SEWbx*GYO6lH`O;f zEMcR~gJ-WM&Hp=d{^R$5*8XpP|94+~!_}ITFHaiJDUOMczxdtOu0`p}sV6ghPQI00 z$N6H*dAo}(Z8z5}&b_r#|IRjD-^)Jpm~t=sgtEyqS*qPymVE78*U=5Rt*_H`?^U*$ z7`)ec_+r-0lz^67Quo%qeX*;dxYCN(TD+i_RX+SkW^(F-)aNy+<*UjjaV}c_O7z=5 zn@*|kemfrL=H&RFm9kLPo-H1I#B-1NygT3JPOjS&;P*>XAx$lg>@SG zo%GS`*A?w;%~G4FF1YNjyHe`ittO{lT8T1iysd6qYxKtQU+>~ZrG-6#?|uq*g!1Qz z-7k^2w>!vk!};DHlQ|Bo~5mI?XMRfPkycn z1x=5AI#&Ge(Z&518UNbVgQMMNCbmD3S@GfJVfUI}FE+$aD~7EF5R|X`wz=k?wSD-M zA8K5;^TLnJSQadIQ>a1W@{Z_^uLctY_Ec<}&AXQEhFg$SM@pW_38j;X)&e=`=mrYC- zDw-rl6{V==@4T8V|NEI)+lv`n56;Wpc!&3%|1qa?mQsZ#9-6y<-&XyX<2^Cy&BZBa zoD=mwM70IC^qge+V{!4om2DcjTwA%E)b768+JCO?n(c|prykU3FPQ$y<Q?^Q$%zZo|vWn*P-X6%Yw@DdJboI7QSFNNw2wV@Wo5S@fP35 zAQ_?79sAr)|5%ZBnYZP_hKMsi=AEzaTQmRRn=g{$&(pumHhr!ix4`o9R^x2VL^tm= zmM4Yl9BUMmW8z{8KRs#r`qi}j{k>GP`G(n1cf58~zqb<)H-CHbWaL){a6G(q`1jE5 z$?nAM*VT^si21*;3XxGiKkwtCqulT0XPcM5T0YM@i@PHybv>)* zbJmNEXV1<`?0CZB$8?U>MEmdri6H+=_ttc|#_d)-Z=J7Pr(}`d^=DgV=Iv?QGS_~& zTaotJ^6eUJPNxLB`BO{x3OFU$&Ax1EEWP~8H8x3M9^K`a*Kj^xDshG7O6n2QRH?&d z(gN=PSvD^9++Eb-YnI^>qc-)j<>E*8rk+{d6Ib=|a>bliYu_G!vP4Bmz&kt9{>Sr8 zFFH;ZU4N$@*{u?-WTYm1?)J%j@3%i=UO3~ka$3ZcB(-B5-{&p+nDbj#GwLhba-Q0F zErV$~DbszYGg-)b%x)~dU+KWnx7%G?FYeC6Cr>#0 ze!JsAr;^!zIi^QUzPE+0Jj@gwUfe9H`DXQ_-`250A1Kks&L zn%nezv*qS(+Mi!u9U(E-LIE!$#u`L$u&;4e4i1W-EMMFOYGciy+ygR zHl5n}L!zQOc8&l0<$F11dHr^lIp=+I8N&<%$!Ma<<%D z)4eOcu=2U8!sAB@%RAacRhZVCv=9o#}c_Vdbjq0yypS!c$4w`K_o0-|< zT%#~`trZ`?WyFWF#%;M7Di_aLnf-Op`nG+QS=O{-7t_cJ%_jXo?SuWR`?_cG9powg z6!!fa^NpanW+j(j-Vxv1@bzNxOpY7T5-Jlsk62tVx#uPt?9w11d{{tmPNqh~lx%t^2&?ZO^hy z&T}(YY|4Cj>)e!IlYiYmQn@Zf#Yyse@j{8;9rJm5=1kAz-8kiYSy_fCa^JOg+G=yG5>ivirYn?f;Sgzy1G2JGXP^^k-Ba&$_C( z$mDb1(WH}$VmELU^F3$3W4Y(>!K`yhS2tSOq->13b*?dhDg5>Wmk)L6eUmRIsON2+ zpKHhDteJjVTe)7X%h-A0LjNZ@ZHBkire99-6ghJ2cFYGckE<6gmKHMV&pUQ|_IgnY4pBm8siH1rBs8ix|Ez_;Msgv|U8_bzSo_m&+zc7Cc~D zxApWcPi?oxw2P4|435YtUM|x;{d3OI&)() zU)h`CccfHpS>x*0y5fnw>JxtVxMXx|FXS-!Jni&s?M2TrqZVZ9IG8>?uNWb}?{(Ul z=i6?T?u^+OrE3|n)*?dg(pjr#zS*z7B<;;!v~8~AMB8%zSw1WnJOf=$m$iTiN{iT2%_JyN?ys{aeYfUv@_S z^79v0gooz3-L7sqbMy1_9P{ixzOb^1{*ouVQZ~0=eYAUh)7jqX4u)Lo_43zM{CK&% zWy7O`7Y(^>ri<%G-jv@t3|_a%7f;)8GGHoO}lU-VwS4#GslF>OzrILI|OtZ&OX<9RxGw!_4Ch3 z>oQ;Nx$yH*)C|_6!WkbN3*tC?EB|@>JXJZfB_QLAEQ1e&r1Hts7`?ulqjlj&#Wybz z>TsP9qBCXr^=buPrx^a=uLqWiNI6|ry!SBX*zz9!UQYG7_s@Q|zO5-R=lIkk2mEe^ zZJbfY@Fb_~d@!e~^36XCTUoNSOAX%gcsz=9-*J!c$QHGu3%4XKQJK*B`}?~Ot?&QY zY<|kPC05Yq)+2fMpE{9VX`&3NpCkoB+v=LLZ8tydS^fFBjb)`*hBRMa{|Sxj=H@!n zxScL9K4^Tq{JdJ#=GlF_U%q{0m$y;aSTt?pjLn@h*VjHh zeP@26|&30$pH zwGsb$iD~JLk{Xq%hL*2)R*OE1`;c^*?RPY5A)n}M*Y~%sO?&HcfHmGHUnlazIl+cw zma`I+oS(~XzIo@C(77=6?YZ6D2gTS+i=UllJ^gf2pApIb%o@0(k^wepO+{C_sz+nXZJ+{jtinVDc0 z|6q24(ut&%HO0lwUYz~8`g8Q3ui*36r+wX!=%E(keS2XC$M&4xy02ee$tq^;+-RC$n{E91G*4l| z?z$%kylw$!$Bs!VsoggdznF1M zc1zr%B=?m`Y|Goo-q$5dB`kI*amj?UtDjx5cswcCmp<=W<>Ssw8ShkJ$BU5 z@)28qK9ilvj|+=(JiH3!MS{%2?KgF@AJ^^hi#04Na!|Uxh+*4oUUh%}4}KX<&ySv! zI(u>&|4Y9!FT2ZeK9Uj=px=RDHQWL&f)lhWCHotKIk9 z_&eueMSVa2lbV7}Kerqgk!)+6Jv;kW<>_kqJ?$p*)cyS(j6dIOQroh|-1hvrbGfS& zxX*3x$iH!@^7?mKf0>JMwo&vmiJLL8#sB_D=HInm zbbn3ep2M8m_HKA1?qIl{rK>E}t0m`if{)jSv-@p8UNDh$Y?+c|cy(iW z#91RD*=jaE74OQvWTVXWGfxMr*RK*YS(s?{UZPF6=~5fp`yBT}7F;`}6;p(!d3{tb zNV-3{ZC-b`IL~d<&o^%$Ik=2Dz;yc2%#Bk+tB*~+viS9atvbiLuH{*#f+y*vj~_ky znD2+}g0ug$Vs=04`+OrztMUmd3pEt)&?uC|lBGIzXB{*p7j(>0#VoiJD3+V!ZvRI8y-YN*h<9dEd9nO5)n zy)Dww;hjm-EEA1Wt{KkyTDaxC1+3zJDiyo!y;e6f&45o<1lz`s~*%6CPKE1n=;mQ+IOA73M9=KDjFAcjFAB zeQ#epX5Ihqr0}!y{+r(py?n{~_p^6eicCt+dqyB&U)mC?-K$4w%-EH0L z(dXYB6+3$>?Q-$vP8TMn37fuNoXV4_!M7u|cU|+G*q8F!kGxoJ+%9nE6x}%|=kX0b zP3|Ti>4lTc8_quNSNH7S);CAt`MMsaXOEVvxO$$?NVA?g_v5_TXAfLWJ3T?THvhco zF^_n&e@k<|FHTzed1I(>sloccA=k9q+a`!~&Ya*b-*jvXd#tzd{EJ)HhT0!{Zqj@5 z=6R{2Ct0{LXHN_hr_kzOq~5?29ZWe%f_YDqS<_ z!X@`j;T|!ZPoB9;BroEfcQwiLvFuI9H}1!ezkD33wAF`u;+bS4<9*2)ZcUGm9_5y+ z`&76wn{Pqq+imG)@exh#H;YWqCHwWVc-y%>T>1H(z3|8Q)zhJqik8n$uFReDe7@B7 zRHg?nFE6(cY`b&0O!sXP;6$ z?IK-;uJVk)S^f8zE-PQ0#L%<7eBRYV#dl13G$$u5s<<;@ONd0#G4^;f&0C)(l9u>S zlwc1!^Mt4N)EaZ!*=MimRFsOCYVp`EIpL-}`>lhR!27jbir3o1MX&wk4G({=GUex^ zhNneG%??$+ubuY5_sNW+XTQ>TBkF5QI7(bSc5?r;T5BN|&SYx!)9T5TjNNTdi!%Fq zfB(8T<;2OB+DBd=u5Y@zJ|j5BldVY3K{$N+bermL6}Mz&vPG}1DJbyJnaok0|MrUM zP5-)NAA!&HUzXbce7>4706YL?{h>cR#{6BKzWBR~X4flUfBkoB{oh@=YlDA$ILu%9 zd+l!-IXR)^C$FBdeNAhx-usqubF#1D$Aj$hpPsywoL}>Y(|rFo!}k48yJbp>Z#|e{ z>A1Q1!mSx|xn{q0n9nwAN?@1lT8*6_Pt=_JmF9fxqSt}$-bFLL=5F%7=PP9R+W0+7 za+Kb;I1zE1MJshK8SZZi@p~(h?(qI_Zt;Rmi*6{Jocks(z;4Yl-PQb>L_qhdRE?yP z2aC6eFA3pgQE-1|x4_rgXX2D&>{+(ivk&X5mr70+QA~CBnzw}4Qq4O5cb}cs;RGh< zk8-6>n_O8s%6Tjc3u_PWy1(gVb>6k?ZHKqbdDgm& z*_z)Lo&UaEvy7T(!=<(H>XAj&-A%d$*@7&~L<;vUd@B{?W6`SMT5r_XpJ4odQ~0*| zSwEJ=9JF*$e*IcI@0z)c&UB5wh5a2BX`5NYXY;pXgm6f|dSC60 z+1IaaT7Iw6UG4LqFH_Rb&--|feg4CHd#iJPnePAeRKNKDJ==G8c6(<;JKesxyyg8g z9kJqHbq97HX#V~F!;h1a{c^S}>mu0_ud;~=an8EIBfai7?@iW2HI^^=LmZNoGL=l$ zY95<>tMh(k!Guo%IVn>GWDZXM`~GOkamC=N42GurWIbB%h&Pt+)16nmcx8a*)@;kS zv%ltOdDr@M_BnN3WSV~@sIy>qR!i2#KVPd`)1=dd``_9KSRY*VmVKVry-nspk$)H@ zb!VNfa=kKr{q{88HBv8{C+$uUma?00&`mz@L*EozZll9%6f@JT*LZkx_Oidvm0Db= zGQ}YJ!K`WR=g)Pl+t{Khsx1F}*}=e2?mv$;Z>?OkEJh>IetLwRo`}|Ah9{2>CPXvu z)feV*-TD6N?3q*EpnPu{COf{y;rq=&eob0+; zx>R;m$!FGcJ6BgZf=l?en`SH)u;#p~aFQn4CSrtv@?5#MLU-NeLpJU{d*9=? z$zqw_yLP2Ku3DF*RNZdkB`>UGkS$##&=!}u)JG#HFJh}~v)dy9PRAML&-U6M(dF^F zY*L}0T5scVrc5aGrsQRd;|`lHZGXqQZj*-lk`N)c^doalWgQzE>Gz z7s;Cr)G+k1LZzLIVZ%>mI@Vc%0Vmq_t>v@-tu3jM~>)aLpqf!1}XZ%{&*lO^}`u8kT zf|QoB+=(3-gfpt+3uy*77srCn&tb-($41Dj~5g6-T(0Arf^$g!o4jz&x*MjHfmg2 zyz;g2(vbIWS!S2qF^EsQ9D34lqUzy$SuGoRb2F z!*Y76sp^EO4${j~oO8|?q&NN0{I`6LFN?#)v?-AlXI+!xpWQ6>S{gO+V#28(Cl@QG zs;H{mN;?#wCb-6S(F9?|sgw3>Ucb6HLp$ZV;e(xCoo8!~KKdcozFIkLGwbZHXqeY%XS{Nv4w z@8|5infCAeaeL?TiW6xbfBx#%AF==T^LwG;qaq~>|5JP)=QTeSx_@@ZuAPcYPVD)( zr?$l5cEz^l-emjAFH>Z;*F0OxuCn+1d3;ap`v(2G zkJXm7zos1TmwQ|wqr=De@YSbDCMjvBEzfRRI{R$IcV>0<^f`9+?wc3qraxe+l_}es zeY1CSrl8=mjlN21uEk4d8yr)exu(tMumPLT%s--CO|sFow_ixScvJUx$trEnC_Sd# zACJUK-87r~;AGI9ucu;{%qUy_Zjpt@@1)F~8j$Sa%b+#Ye0KM0e?C+G|6b=dMRNtaJ=&!9dcL*${=1*1 z#{U%M3um{f`!VC|GWWz!C&TlvUsk;JayK_`@2xrip6+tLt!w`DNX7F6PlugW`xC5P z%$`sGAu!|X#0$BgHT*v>r|Ue|y}r3E_puN21L>q&i;jNO?N}_h@O|~C3&Jd6v8NC2 zNw&<+oO{VKqHNx}nT1=TX4EP0{b+su;+^1IqX)MSJiXdB`*ZQR;-neJuFoiwyrX9s zy&-Up>l2|r$F6OI~!g!9Ns3eEM+pU9n0)<0;*3#v^bxZmZqiaM4VQ6J;R~(Q&i(* z2F=3KLeKq?;^GHgx;E-8(mLd?er;Z$;^`SIQ;ut0Tjim7mD?E<)cMVy_W$_(>Pvfj z26yb9?V+13qqz^X-~BXWvU>l;IX_;7?>|8W2Ig0s~l`?|=>og=|4Tms&Q6EQ2KHu&7Lg4p0*6#sR3|z$H5YoQ+*UDbmT^Ba zsc_DU=EWYIUM-cJZY~NH3~~&tnjD-m=_Td2@7BJzy*%%Fz~TBIA3yvLU%U0YZTX7_ zCg0wEoxJVb&Ghwq!$Q}VzA~?64{!?%HNI8W{e7ai{`_X6Ew_0UOKj@@^{l&lVVkxJ z=j^l7KnwkL-;TbO>pd&F=Vhne#cvart@Dsb5~{hLUTz^T5&JAi=4EQz9+L~!Ubm<0 z61DO8vZ252|C5Dfn!5|`+OK$7ZXdo{bLMmBimQT8j{7}fefR#A{j&tMf;m^)?rm3D zkR{bqY`N8Y)-vVGmZvo~DOZ2)KeJl@$FVtAM1vQtT`iTKTPEqVF~OkBioGlFc%nO( zK_;8TcGy~gV^6;NN+`I^+01i$TG?jBHizJ=kuz4kR-d@Y(l=l|PI@9; z^PR6ygMqKGBfecx>HgHzCvH3qTC3`RKFcW)`yQEpEhF2)+WvTGan92XrzUZEGw?c} z$*7TM`<2)2)%A7NQ}a2tkA8;F|NL})&CJj0vnD^C({TB#6I|8u`!lQQ)^e=fo+|o9U-AgYW};wuDK?=GJ<>g67{>4lBwy(=Wc$p ze4BsG-1@Eeck=rO@vmavdb~EAzw(3pXRZlL`))6EziQfjv}x6<7pfB{9jbZ3cxQdj zv6V+(h|DNeW!n;DvYG9<%;61+st0e_K0lCjeGfBhn$5wE*&K=vJU4C?me(GCdsbJm zVomIVt;ee8-<0z5{lTmj(>IE;|<(DjIwJLAewL6*Q@Ozf9BFh@%Gqa?ULp;Apa)0~~ zbBw8B#^fEh(mgpOUhmku_vy1=Qkw6kcs;#t5O!bR>B{P73X^jJL%jaJ_geX|pxr`* zq21!hayc{woZ29-S z{*C?r<^1LC&Wr^e&Na7``{rI;m+W(y#X)@TkGEx~f4|><{N%~Ze@kZ^Z0tJou+LDS z`FxwT7uUzL0=Ke)xRyBc3O4& zYToJ7r^nonxx_2?Tx-_PriIN6*+p-x>P^)qZxZ{lL+Qb6 zv(S6-f9gHH|M%o#T*~Vfd9C@l`@@sc`AM;CuTy_D{c36Mx7BU&EYv?OtN+Y+)vi+| z#|!7WT&q5jT(|6fa?g<|2HWO1dr2%VjAEWRdv^A=*}Ug0MP{Czq>_}ojG=G6{V(%3 z%1T!%>?FP#*MGWiZ2#li${-4vmI@@o$XugfzUW#2t}#X9Rq%`(nMl7HG1rY-rRBA_C)DQ&OO<$0A$PW2ut z_PVsb`+Jz(5{@4!6ImxLD&2CMujk>Pt;Z#jjUtL#JZvgXEqV9-|L;wEtu>!;OcLNc z^V~S*X~)UtQ&J2oT)J3aEH69SAX1sO*u+hAcjnRyDu1euzWpj{$fNU&*W(bs+|o^} z66{&FTy}Zyov6P1Wou8_bv6%)Tt0JX`g$$Gpy{c}U~*2<%_^iPvSX=y)vv?_MQqQd zwgkJ#e}3QAv82T)%_*>3=+}ddp+~c}K6>`7?fUt19?s{#y_;rcc4VJ(l7r^yqPmtH zQvcsb*1afvu0Chp+ya}~jy*9U`WtT*l$4zN`7?Rnzc-e1{WTsNY)cEX)M>k=nKt$D zpFcdWH_fZLop&?uUBnqJxxN2bVlD60f9nw!FAv#V+_Q4ivpTPyUskJ@aCZI8*%y%c z{{4sl&+payEBzN1XS{!-o!Lct%Em8-kJcvbi&)U3wxq*sna`QyuP14C$VUcc%(YK` zIwMGE)v3fS%jAnbTHf;Of3UxhX~O@z3rfX)oD@0q#`VEsgDu+IZkxKXWcyV9({Wx? z@@@Hwkmio`En1V5)=ioG-$K!FbM43F&N5sL&N7dJC4Zl)kJ?@RyFTE|^Wt~!-u*Zl z|HpOKs%IH??wtbernZ4U1iF;se*DAL^YmR+w`jLj=nIj^yE&bE7o@d4Q0zKt=4~)5^tN!) zqYSg>KQbCayX-3Z`uh#GDdk45TJ`A7lNsjrpVcB z8fOb5CD>sDsA&wG7aT5nz6Pu=_f zVr{Ifo}MgpzR;!8dA986*Rx%_uX2U!N1W^Th%)@btREj^v_;lWJIp-W$!EoG(bb9@ zJ~l4lZDy!dU^!W57q!^)&N}NHQ{|3DpE*NX6F%52Jd)shHplFF-fc0{eUt7SKUeVT z{pUK%^z|R(-E)5{)my*q|8M{9$Nqz9wd$XW_cKiB*VOrDD9`_2MtR~)Sx1)nEytHH zk7Qm@!)L-D^Yhq!p~;iCJ$a%Y55r&(=1ZZN25v%(+U6znLYxdnP{E{B>io-fCg7{Ta5ajJQ^)yp{j;aQ?5O zhh-lHFvvU-n19Q{y4ro+x_$p{2Tzd?|5ca1a;xIfmaRLJPe1kd;M~9L>%>z}|8C-+*DJnFu4n5S zbJ@cR3w)RD@!ht`Nb}HL`;CDQ(rV7E-t^tRX2Siyd2w-(3^y$)&rg5z!`@)7 z#_xh$ow@uhBFop?FPwLF>HnK%-WY|6|OvK$KKt^d*d#KggX9vztqLF@}f_J)>@NA zn>)|e?0oV%zP|tTY43SDei2uA4-4#wUO%y}d7aO+`mK?v=R^CB*6>Abymw`Z$cl7h zKR^G7YdaZs?Ai6SYIABwW5kl~$qbr8K`I;*glbv#X9bpsgvT%Gjagr{#q_3}dCG;E zJ)FU*raKH3eXg^<%edPM4uUAvC%f75YTDmHV=*~?6=u6OfZ9#*w;HCwye)g`D$BkGfohmsxrA3h?geBQ`AA{Gz5YKs9qSCQ9R~Nmr zX7an*ASL@t?$n2UTAcr0nN9oM`G2bY{~3=SPmTTG{5aH0nQPa<#jj^Az8qX)c*W6S z(gL3{`90>GRUe8fkK}zY6q`KvQ=RtNoNEib4Gm+Xe|8j0T@Rh)k#cL+v#*B(s{@mX`-*6xdn ze23MdxyKf4^vc++`|u`L^mUi1FRJ}_^X6Qiw`-T9rt@|8UlaDS_XxRNw7AH%)~B$C zIrr6^oS<#{LT`yJmzv8hnyiqyC52In>u8RT!>f5u@-3h5oip>l-6LkZy8r)IN3)zb zuJ-Zo^}ol|1tLAvkF@YlJi0h|)=!?U(oK_iSgzbOdZFAOJhjP3JD5xN!@c0E({`$Z|rH18e`8WvfSKj$BsP@zCB}GZ5pPXbYjw#b0HlmYTaAS-v7V3dEYc0{y9NT znR^Xy{poMNeF&1FN>?@Pby-yE7AKv2;g%0;!`8l2JKq@gYrQK;?%sZV?#ey={F;|^ z`filzzPGRT%CLU+oL5WJh3A-QM!Lh%o?ZIq@=i+sdeEuoy*o|9Y01~dJdUI9t~IPR z;EDL8XYu;*=_B&~N|BQlIPF|j(iX(&1zahaGb#ViWs~GL2Bt>3)|)QhdBHtna&pk) zl!Wxk#Xr*e`mY`@`>_5JL&eqiZ87rvSF zp}p+gCh1vE&W9_s960&1Y1vAFO~3C)OkBkoxZu5Qr=i(?|4j4022skMp!RTi`Sy^~ zWg=~f3@3}OiZm;}zQeAjyh@~E=9P*6j`9C_;s5{MVcCb^g7`ku!gJr=-%{q)X_@eS zmBy`YPv5nefM^)1=?)|YRDa%Uau4kXj zC{k_e`M29Mz4Mk+Z1R@QzYZ@Z)twC6^tjwLI<8hYg|Tc!ZG{K#p8v&PC%VqRbG!01 zd%UxDTb{#|hkrh1M?4R>_T;kbvO^Ca7xXKyEvV@fU@~+|+bmfcnyyoSFmeU|`tolt zR=Q>eJyjAE)Qj75fM0g`=SVSqFUkCbH8UkR&fR>&ouDJ^5ct}M-G|HZ&ck_-jN)H= z=bqi~xQRdVeUmSAe$MMO^jVQ}zm(_hv}Jjp_-x&_G^}WO!~D=A_?x$(g3^s$X~nh2 zt8N>vetzYe(dz7&R8K|k_iUasPlZl9?#4OAPuI)s(Q2c2S8q*8;Z;hVA5$itY-D_D z!j=W9>kXVH>d008eyZ8&>2+BvBYRn0vC53zllJf1uWEnEy|kp+-izt|>U*6*)%N%O zH~ilH`%jc-;JVDp+Mg+tTPEs#H@JD)WT|9-$g!D@FRM&fRVY5WFZ;4*hHtK{z>OSp%ahlocwAUgjk*=NR8DsFZOjPMm@3MttG2#r$qx~E zXa)Z3zl_&kwJCqymqgrAoBHDSyj3Uf=ER1t$y;CXe{cCg_Gj*Zwwe*tgw9vN8Rf`U1&Tao?nBrIQtV4QNUiU?1 zQQiJeTTf;;iYOVf@<^^+cj}Jw-a`xpMjIv{3Yz|#)2E}uE7Gk}KT|z$$)tLBzTb65 z_y4YZZySFsaYc1*(X;c*YyL1L-kGvIsa1Qo%IdX;-1`l=R{Q>ooaFQN@~p5H>A;e1 z%kIg+Y1^DC`L%qa7$z$HQ%+S{QhX@f%l8C_($h-TPUd^xb;OJN`uh}AlXx;jqHfOJ z-t^>rnAWB<497G)B7cQ<8k8_^ek^(SF0cRnzgmSif=rihaqjkSJbF*RSGXK_s~Y*}i)ZSUy^r@lpIzq|wtUUmILp&%o1gtH-|v>OT}J-up2E5#F-(a!(&jR3GT+lP z>%H3RbKC;$jUGxGt{n3OKJneO><*eWfo%(8kdlX4{>5W&7@1~XNMC&R3@59o|F@#|D;bYEH`(5T~Yn_e*{a%EzkGwIyvrW z%RHINWcR7?{mVM9)60B*A7AOVA?c#!9(Jxh_GSJ`6(_BJ9e?@1Bp} zxl2PPuK#NhDrKq^GPCSOk*qU^j`&T+34fngo?x6}``p#^RH$}Oicg2$r@i{~?31@f zT{M~bSUy?PNoApD#N3SxyFR%3?&NxG`21_H!pDSv-!r?K7admQ`>614-TdD2pKooS z?kJkvXDD{I?Ch(&qgStnF7%I_(4n?)`Q1Nx^As{%GMN;-g0Gw2KHK%&|NirohZUbs zYTo~uoB#Rd_IV#tZWcsI_pN<&Lc?#)!2L-q z{F3{~tX28wg3vFs|IsoNE=+dnXYuEfTWoqRYR%Tl`!Ri?nY|jWK1`mX0yEBCX44Uo zYtUdmr6e)wlFHIg)6ZRQG<5H5n(|zELD0?i>H4ZmndP`AU954tfB8ZERE6{ZxE?(G zz4iZ$_TVO-8F#+#nVwlS!L+U{qUGe}j7fF@E`m-cYX98)X?Zrs?B(ZGws(%sxN%iZ zGU1O>>YrnNa#idcIkO~vW8eN^j$6sF!meOm)Y~b)a~OZvR{xvxwk(>f!6{ky%9IeD z2KQnG!4AWTNo@1qEtBI~dxZJV%Ks1UTlO&V34{9Lmqo9OzhC)yv-y*Ezkb@QE8VZw zKPaM7=Cx9Uq4D9to@`H^HjR(mivO~?}Cad8_dMQuix4Cf6ndO+H&%` z7Lg$~meG%@4sYa)ylm_FZjJZ#2#uR9B9>NmYDW&7o-STt{`|)iiGY~cc;$*|r@3-v zWBKh^w3ZvXJ!YTp*prel-^E{~S;%ze6Q8@!UOX2TUNXa$MNRNm;NyCI(YI&6PJNTQ zJ9E;c_ES-h{FD>qSyp^g6RPISo8@<6ec$#46H570thR03E+@+uGE?Y7g44vC{GOUl zLTw@k!{*G9eXP~JVoEw!mdO7=SHZ$xB0lwg!jm^$4%dqB&UvA%BeuEc@r%QKY8^Fa zrZ`V!nLl~k=4lc(`tf%6Yx7R8m(J#vUXWn_sePdjN72z~=0d`6CaZjEo&P7f{ssS^ z3-kXxns0wc7g7SQ?Am-h|Mb<<<^MG&esOI)KmA(Hsno^KcWs@PxBKa@SF=QvOJk>| z%-p0f@7CM8nU_wk;K(r8=9YPQbNcxgyLCTb4p#a0qptazT)N2SU5BK)P1yt!CD>}t zWaZwV)Wx3XKN+q%* z*Is9_e7uXhdAx9kK33YXce58K&0oy4rwWM{nS*^%UhT|4EIe9`n5U!k8pj(?{n$*9#+?# zm;bBXzWW%sU0iq9y`y~o`|5hDoZa(-QK<1=wEqAsBLL% z@^|g^ClZyomg-&$t&smYHU6il2j_F1yJe?;`_JDrfkiQ3XV=jjzq?m77QC+BBflZc zc>dXl+^B1_P5&AMoG;owW749+zMpFz_NwHR)W;Bw#70HKu|E{o5Y!VtR6@m?px)G5MEWmF(S^F`?S}Q<04PCaxQ^&1($i`l&g7uVtKY==uDNPA+~P zC7u303p=}WAv-_K@l<0xIhWzezIiQgY($P{Pdi%2WLWiTSK7uI{@fK`JC6vbyt<*P zy2Z4EC2w8ar%y+@#Wu4go5ad*_MB)InH2Hp-QR}0Ez8#!1}!XBS`nmSwe(qiFjcFVP_tNeeb*PoaFxAJ+r^(jbzpKU!6_W$euxAm28!|R?-pI`G+ zJHBi6ZtH#Tf7dM!TJ$ftrQS2Mb%_nn^`6DgGu>?7{(qmBzjNQtWvjGSty|Z z>XrP{Vux-??ArG{JN~y;>C+jeyn#ac>()iA*ptt{@%YZZRYehNJvF-zTP&V&mTf|d zyj9W%m8}PNcu(-S{Wat9j@Y#Z$1deXvlO^3R$Zi;z^fz9o4#EA%mgX*e%N8WZ{e-jqmg=i&9fp&hpZ2lO6WKLumfPdq-=h4Pe=zO5 zBg(o-`m+CA6M3~q#q!DqoF8izaA;(iT?d@znm9Qs7O;b~KR+^vj>f)k*NBFvy-qO;UniKJ~^4}v( z{dl|Q#q(>8qZ!%_cJlRYyC(chaq9igD<2pNDYp9TmFZ?}S+y-^TY1I%|Emm@iyanD z*|jqE>*oJ|>pu$Dt9A+`Uz}&a_FQIL(TX!m0u7fsYJUAR|Nr&656=q1t-upM>#Od> z*j0-(g}XHuw;eqh`TyVb{a;w^dF+)Y{R_?J@ikt&>dxL4MI|oHxijySGi|xXbSQ0i z>h7CUF0MNGU2w6FTxWd(i^2*)$@pEX_r2b+qvBkSS+ZSxLagh1Q0(0imL`_aCo$`r`@9QjyiOU(fl| zC$>VwGVec%7?%}4h*9y%4Z z+^151^{!)4?fjhfM^7WUbue!|4shq$L64m;EeU))zizu zf|Z7=mT0gZE_2=ea>vd+4&IN>UYFmTYi;-W+ieY|d%yq4AHH=bvD*IP`%VAq_nka0 zQSpB7_ZvB8bN2pBGvx4c)p2{Ad?<{~_0+mNwa09~?3#b~Y}!*%cXIl^nv?lI|5!^r z_DEXsyf{SU*Ajv3fNQ>o^gV+FU!A=7(Nn1Q%Z^ipMc-yjo~-=ng77rvd)4p4%z3G?Xg5E(M~yeyN&bS{#3Prt&9154axAJj z%xbpiQkSQzbQE95#7#ZY;jyz%BWdH@x#ypi%rPSiDT`e9xypUG9pz-trWFH{CjNh688q{lcoM9%IqfXLW^awiaJ5(VW^c zD?G?(rx4ST3D+&$v{l@azSva1e|_e8@toq4Sbv_0j~5Fwn7uX?N?z8tjKg!`R%T~5 zQ>7Ov5^eL|ZaW%v`s3am=PO}r0WL~5e}5s-IVodzgCU#zr!2)|Ga7r8*BYuiaj@Q* z!8l1TIr?0K{MKuKUhwG`=fB^aZ}U~|#DA8c{?&aGcRrX??Dcy8)-|*KOZ{m5|8xDn zN@b?iU)vTxuI#caEG#|v{@1_%0et00K{J#2jTQg*uD6r=^I`eit5!=rx)iHddAkJ7 znDDOlzHzqHGhf?<>&qWM{oR?ogh6ZRi(m7;X4$?CIzBsW)|uch^I~$3{hO@R)uSjN zIM24akM-GS$>Z+oXVx~aII!Z(^ywB0AAJr{e4CNsWe~M+inFw_sDhwtsJV>n+=8N_ zNmH4Em*htO+U6RxWYwn3iQnh#dn@6zWS!2DBUz=#zdq#_nb|Gps|1~Gp91(vV8GMH=l;?-ygJ37=_F^+*fnSQZHN@{abQSil*wTJYy8ZF@Zia~) z+grjf-rsjo!m(8OZ~hUb6`5QUxTl|F3u4F>SnFXZ*n7~FcipN&*ZmE9BOa=&={uBRD>hb4VAjQMSYgr{n) z>e_w2;)7kjP>7yPu$M-1L8xobL;>YxQIl%E?FqOwDJW_8TZe?55k+-%=V~n3S>D^` z-o8{S8++YPm}ApaCq0|FNfMiwlP1WnOWqsDJZss!{jEptdrD1l3%=d9EOJ3^+Wi)R ze@_p#+ke{sZ|i;u@z0hEwrnlq(EL-gPB-PFc-^b^|BvtgcmIE7I)C|bP=xwdb}V_! zvftQyI`?0L3s*$7US_&$dA``D>n~@&aMszE?M0h!?>^W!_rZ;&y|S<0ex0@Yb@rBv z5$Wa1uiBH-w+8n%-}!3w*u(SV*Y*2O-#K*W>X{hVRGE|2Yc7ST2|CZe`rOM&O7z7i zjhz+DM_hQi&X)Od?EJj`^(=SwzEv{|%gVfZ8h780Hd}WnCP{G4$2pZfCU+H>R6b#A#` zRtf#~XmRr5jcMsTOEw*uDDH8~C|WO5?DL}Q@oEB|Tvhw$IIrVbzAoOa;lYn`RbgkP zmIFCv$r~elSWoSk=B3#iRLjqt8w%N9sda;FWcuW%>G!X&^n=YY3$KGvyw|DPV1{&^$t4%7uie{x zcbi1Ak-~PLr$LL1u3g-I+ve?O!Q3CQZjsYIw?>_LcK`3^`j6_n1)7B>MrHrq?!;sN zCI3&O{O{TAOb-Owe~7qxEt=w_9=apP@ae`ar5U*wy)J*3y;m(a-<~a*BT-}S6^*;Q zZ(r|Qc~qkL;^BWg^ z$n`ducf)ng+CZ};m4>biN%kdAm+AXlZdEyCQ1LEIdde*$9_DkFd;HI&nL76@5xJRX z-XidMiL;1Zqd(_-mD2~MoHs`lJ$8eeVP>v7TnaQdMd++}HOu$* zrh7RV=C=3Pc?@QsEpY$5C~NxOXYBL2brzc{bS$2OSzRW z>rC-G^?m%aS!#03?etzx_Ti`x75VMP<4~vnwPpS3Idw+`l#)z8FIL_BbB^t%6SiON zB~4}I9*Hd5FJ9yF@PE5OLD7~anX5K^(|qQy+`S+`-EG2>Th`~N2<-}x+IsDX$j)8+ z9zE?&uen}c^ZZJ0_T0ugk2LNnO_r~XrMzW~v=u~7tyJ>g7j))zZ=J-BUHgt{ICD&7 z*n4!w6{yz7E@5PCuLtmfTXXNpnXM6q-W^4!tM7KOii+zy)d9< zimdi$Exwu$t_qs#h1+(VJs#Jk_*^R{^!fRJ7t)uWnIUjVCXlB&{lmk#AB!idB=%IE zmik?6|NW@^{xz%ILPJd%#cr>2by=}`*P1_zwqD!!L-zl({lE7@lEPMdMvWOJ#ycMz z6_^;s)fK;S-|YuJN2UGa+BJ?$2=EdwnC8=I(;M~1>v4?Vp78MSHP^HK`umOd+lj3I zHbr8-qFBN7o=>|L8Qhx4^6uTWJ^#JqAN|NUc_}nR$Uw2Nzxt%7_^(LEGt-yYTRoCY z7MS}%)9=!{o9${3QhTHGckbBR{A79Gs@$}k-Es{JUuWE&CL%0ut{o*G*t$GETxzY( zvZ5VP3p*?9FMO31vh6jVBcpF&Wu?@T{A=IxyE!}e>`*##;^)gr?$7&IJU9OHVCUYQ z51&5em3}+(toV*yP97~1A2c61pYRMlWO8a=$lqg6)_>Dzzr)U07ozy#)OmKF1N#km z?GPjq>MQwj`Jz|Tmo3?U*z}aG)Poha1?M#lo+hoG z`E=2x<&6@_*BTdSc-M7QyzcwD;IoLcX4}H&KQAxO*{;3nmQd1y_tk4oRx}B;O>z;P zWb`3$dbhIS`utn;-Sp+lQ!XkVy}YQ&lJ6~``p`x*25p8s_l@zc(Xo|78et|exo`*edMM@ zHl@laL$TkAJV!*Pn(bl=yZ?K4-GlGF@6VtAKXrcK|5NY(Ia-37@#c#eZV3AYdp$p= zmbQHRsjD3t@A9ti`FJebrt*(e=7%LS0$kngo6n@ESA^%S3JrbS{QT)r)`Qj0HcLij z*Kj?3nj&?3nsxEAwyBW~8~dg_c$atd?6SwV?Y{HPul;O#&njxcFS&f%gb$h*-Hl(~ z=jLp^_jpQknAk-pfnH5>hua}4g1cC1#b5lA3*uL@2!GgIP`v%zTm`OhOOdYU)3+B? zc3+%z%5qL=#@d2wMyqA4Du3m9OR#Obt$R$O?cU?;e#4(``!b|%y`A>9tlMp6RR-HO&|5if&_lf$o zn;b6KH77o2U9jxCiKpDh>!rOx7k)2%;P5Wk`@6@~?_5)5YmJ9KANK-gKqp)a5-j zdp8*`QJMKi=g)(ezZV*m@tnTDtYTDw z-2UDC3p-Lg_5K9sStRl7T%h%6+W)8L{~hT*dU4~$V}HJUuetwyfBg*5B82-(0v=2a z5|3JWJV8Kr$%{sx$CFv^ZhQLYkDz+`bIBhnH+l7~f2A_ZUEJMb)W@FxF0b-iH(i-V)kdP*~{7Yh!8ucj$SwB`boQy(`Lyiv<2k8j*)vReZ%=sP^kiM`#_Q%s4!Pgw zW45c(O3%qQZ|&oZoi;eCI3Y z7Un#u$9%@wSvnW3i@x%DBp5A`n(y*t-WGwVRQD4bmG9=5*;N11b9Z;2oU~X)GpoV! z<nJ+<%Ax4v6WhCGXXo;NiT!t{_SxKW3rovXv)Spl5{1^RzHm&y=>Yru``>4n^6dG3 zWQMGcV5@26u7owNw`c9lUNLuZ<}9O+%!}V{3F|UU^W~g6Q|{QAjAy)tDa9`?iYp#* z;F)wyq7P8%(L`u57)cgL;@cf>^R$^UsPe7|4tb)DIgQ-f}ZOt82R!R*X`aIvfM zqRpiR8=I~gh%#1QiOFlyy!_7N=DBMc27b?(97;6pKJ5tEeK$pA=APuz-eablPjaa7 z$qD*)2;N`nGugXu*D422!-{L=vUj#+uzq%R4!(Y8ZIp2v*KB?|-zQ{8?RR_C)=y>pN9POoY@W6((?F|y zrSh{Q!sVA+P9DfuzeRBGWzztzi6^$b-LY@qlOIo1{MolSiSMiHC=_DebZp9Jkt810 zx$6s#8L;#R&Dyo{<#yTlpHKA*w?}=Px&8jLt?K>-#~w;DWW3T!wx6TDOVnUXbPJD+ zkKx6ijc2RQe)Sc*xNGmuN8f%;yMFJd&g!qT^lScoJ~K;FG38BXmuCN$cE)tsb*pBa ze-<&jlw-}cj8p@y>JW`wgIiBlwl-|#b9wQLFFZW5KvT8nwBPh|x7N&%Fg?3x;rneR zwfnRPYjyJ=VHI0M>Wm=osrsQlbA^#7}|9#T_ z-@WhuFZkb)Qv)p+HdnO!zVm(5-imLh>!T*fhia9F8%6F)onIarDl>m>^R}PWd)3b@ za$}zVo5@&H^;)@h*lN+uyEG5%h|$Sd+8NcMxv`wVk!SYJF{1u7L$Uc9BhHN*h)9lDXOrOqrkh zcc0FUMa$-HFqC@zsn=N5(dodV3wrCd7xCY`Yq0E3zL1B<&X=t`uexN*SE+UenD;$d zm>az=Z~GPBd6QJ;FKsoqTfC?BL{g#8-78!6swZ8PnzTap-u{OBQ=at2#2KFb|DyJP z-K;CYj*VU4Te^oL0aYZY4)7io1XU|*su#`J&!o^s?&49@#a}ETy6)KZi!BO6UqC$&u+c&t!>GBZ+^P=I$wah%tdl; zX0ct`%=FccvkwKGi0i%fWbXcXEt3{(5`BH+Q~lrG{pbGw-P(Bn&$s)}w*P&+f9~=A z`5R`OT@e#}!(i6!+ot~W_c~0xkr%$@w(0BL(RuIJ-OS6&+&-_aL1MwI>}kvMi#Hqn zIUE0Dx6X6#eUGj8F-Kee5_q{=EKHQfBFVLJVqUqJ*5fph|hSyO^BH)^VwcRu0``;ox zCVIRRd-Q-)$@TsH6vgR<+q;xn4qX0zFL`&=$7kDXt+ftb_;Z`I>{ zP5<~(^{aQkuRa;l+d8Wt-pQQ%Z_nH)!f6iarbjGXOsd#(f>*7{JhpCM!1qZ7dm;+zijHONou$*# zo_OMS?pmY1)H&Lkt(5^UI#kxIl>Bw%bhq}p_hvQ!xSwyiz5C2T^(MBrB2@-1jR(_T zWh>N&`96ISp8aaoA&s*JE*)HpWnOnTN?yoo-T#++|B>1G>wX@}|HEYHnwK|!^WB_? z_2GLe{+0f!JN@}P+cWioe=kZ)wjR(uSNZs><>$!5YgSs=Sv|VA*x2v<`A@5yG_T#B zR%Q42$(J=R+$DNW{*!i-Hj%nt{cD^0u`>pSN9QLWG3^lA653*Mq0FxT&*gJs|S_N8A37Jn|jSNYp`&$nC3T1*RX8?Aqyq4T=z zLD}xa4{}R+-Wmv;dJ!)E@@mMEu+*aN%auKOMhU*!jJlUaoTLSecinuuRI=}5S&z1VB z{BFJcrFT(UQ+J;bS-DpFZ~d}I-l8%`GhF{BE>vv3nUt_O?&Fu2m;c<%yuIg?B-^W9 zYAanPOqi^qmh9Xm=F~GW@r23F8A8`ApPg1t^02A>ZyA5<(8{1McAKK|Ev1?K=i5Er zyZrs<@BhBtUmO=UXRcguD0iQ@`ktTHdXBHRe`x-%?fmCk((8-s>dxJ~8OdffYfsXx z9J4cNo7ZS=yu0b`?vvIDb5cZSK73i_Gh_B4i4XTKi(g!1A;y?`-TvLP*GxIG+zp+n zo4#-TKeH<_{lD!jM^-_nH=P_yLOv*FZmOH-u=rZS>#luockJGqye;G3C;z|h`~Sb` z|EFI6@VpG9xR7|<>*TUw>S?P#wdZrp7Oz?r^V9x~2CLA@KhN)9JlOQU^536Iw-eUZ zcPC6$T7B$gPLEJ?Q^=FZT0Mp>YdI8)s%M8chQ=x@-C1k?<=|x#W3l7MEuw=<<+jfh zTqJV(o@lsvdCL?d@x4!s_D_heYSU=y4Dml(V1>F&#yhg?gTy42YsQg5T1a9dBX$D~@e9>auBEC+gv z&MCRPf7y28=~LeN_tWb-B|qFW@AEjdp|qF9o0XpZoEy{@d=K-`@X_dB5kg znY+99tH`r!R$V-2v|jqx1LFpLwzk|E=d$N$god_i23^@TL+hvn=e@_Z_3x{eOga8} zrH{*=^XLCg5Lz|mkXCO*bXViX*Z)5-IlN_Ly*#g<(P0V?Utj9c$uB3jF0y=NJL$sr z+If6GcoL@MI%R+T{qK!`&HwPa2mSwd{(lEqb=PvlUTuK@(?NDO`|_m^Uc6ZGVsW|r zj)PpR52JV8DrDM_7abQDEYi&OUw0>ux2k zwE8UDHtj=YNB5kpW0?B6^1Iw-fm1bh>Yk5Yz(LjPwZzDs7gqOdQ zKmYLmhA00wbpK}8GC0;(CG_E>zW8K=76*@sM{5oi?bKm8yJPyB@9WMoJ1%TLz9XJt z>68`Or;B#(DZi7viCeMe#n-$0&mC(B>#W=R=;rVE*NFQR$^OL9+N_!>EN z(<(KsnA=-(%%p?7a?GUJ+c%XzlE8Wn(jSsa`Z3LgNNy9^@mKwL?5%HX)(Ag6AiSxHY40?#Tt&t zFxJ}p!IHDL8ZCPM>(?*&>W`0(+H*p)Vid;|KjotyT#T<}mZysB%)FfxRcwFSX3tE9 znE3e3yLLZ5`O@;(jFk)*ye4l^(>~M|>%PF$9l**^K7fn{d|1f}gtj5LEjJ0Ztt@$mRmu%fv&OEjD{RVx;4F@$oCJ@TW)aT`_GwA0>Tk zmQLbaB|ElXWhV|r+8OX1=DT8b@#~X&r8mr-Z|QS=3)lWVSxmz!s_@OV%je1-9Xz7Y zVz4&)(7fDFKkANzeEXNWRW;af(z{AyA6MUxyDmfpUl)yfegC6#{fFv*=jZ>qx&PaJ zXiSNm+j%FD$JY6Namkh^A15D|cy2eLZI{)V*ZT`4nOB&4iCk|h3n6<_Sz z!h6S)o`-hEew&xyw7TA7(?5&s_^*bnN7Vmqce)t-sq5t-_Bu`R;DsCvp{G?pFJ6-- zk?hhxX&=AaSN{0_iHrty?~bK}UjLeMf6ssGYZ3UN%{MJxBu^dukY{hU9feU0;`p0+tQv(XYTG*TGvG7*T>)Aw{NGm(=DCz# z6uY+kZocVkBfr&(2yBER7r z?&z=eRfdG;hxQ{-W@p;?=zLE+5}M zp_6aimv$s{PKd0T-97j6+&6zq8T45W?!FhCF}+$KW!K4H(|ISZ^W9REUtT@+&vdm# z8>E-Klx{e$(PjT?XWWbU?}h#*c~zy|2dA>BIh`GhWTwwK8*-Zf@}9n|v#iKLoE+-WZVCdPPg{_oJ=d(+=$3yYIv9M{-Uj zw-%q*xsm7yJfP+j~_qt>@x?uRr{{8<=^*} zuj?*cHSr{mYuJWcF6kRA4bF*_KTCes$91dlSXHg(-n&U_kC(~nHJs>T{3n}K5PYFW z?cEjU4}sSDtX^(HlY)}^>lN5TZ%?gy9xN17Kl!frk#5bxycHMssk`h;O1gFZ3HyJm zZM$|XI##cH<)74-XQ9~**9CXf+4CO#H$|^a;drc_gGXNHM#b)jejX=t?7Ho~+y2yv z$(M8bBznW~-0w|WUiV**@}Af~!*998dp5gM0WM4K1ka8MHTkmMS5?%@js5h~r(KgT z2R8-0*ppON(tY?g|Bm|qd_h`ilbKg#`AielSXp4V(C63#*L?9g6Fqyk+6g8kJFnc# zBd#MZ{ygIKOCRUk+e%`)i`9J3_X)^2IZf}{lk)s*g3p5N=vP(J^=#AKJLhh-cpspt zaq_+C_1(|+^f&c|9aH?F&0BB3mOuD+z@5eK5B;m&VY9D-|C zPdy|UFV;Z_;zgt1A|5mJJQPXu^A7LF4`DJ1XBVW(>aN`+cGL zA#Xi#?pxPBJhlJEyD6r)z+&l&qAn$QxoL)c?-y+CygzYW^8`t!BTmb=9NOuy>~WOK zYo4{q73WW$G(2bd%6G1X-jO}WQtsZ_fA80d_~$&a*W;$%sq~+gJ!h-Q*J+D%KHj@@ z#dKzn=AP5MKSiQeD(+q||HIzxoz;tlnl?nUe3jJ|4M+B3&FKP1+P}5y@q7Ts ze98G7v!xnEuXa6b-pv2wYy5w)|9}5~$^Nr?|DW_9r^5GpMdv@BZPMBrv)`~qB<_;` zLv?laDXBZT%XY@K{Blxtx)mQ4BkrF6-q!bWL0#RM>UMUY(=y@tk-zwKbsifnpW%11 z#4%k)-nQ=8&8J<}+w&S5uKqGQ_C?L|YSnH>5zA|qR@o=Es$7?PuG7>LdX+7`K+#|8gc zZ_c+qhLywf!^r~ojvEXo?iHBxY}&W)=j-iiR{DXFeE};uBEQcHWeN{ivTwzc$~sle z4R06Cj-B?TK=Fs;r)}qJ?z?MOt+1(jcRacx_WGJ|?ORv7PQIC7|5yKy(&ECSRhu7u zynH<8wQtiE)>!G(Wr{8@SNR8&PJDSIC9NoX~;`=lGaoeM3_-T1O=;>Hil6&6pZ z`Buv%_o?~yyxphn+)sX6e(XZtYsZ^HH48S&`t4lED8w=6Zgl&S?@_l_Cb!B;efuZ% zb+UDXuh-nTTi3n$s;B+WFzE`sSt?sBF=_9%jnm$y9X@)r_}n?aoqJ*~NqNUjd6If= z?O|s=e*VheZ`)UVsoHQYXqu|;W?8xZFsY^G*I$9+*8Dl|oS!v**GuQjkN*(=-+aH3 z$b$Gk;{R3m{d;WRcaD43(WW=Ij#&7xy*w5wqI!>A&bG=WG<4#{{J&GB_i&#qw|QGR z*SJFFnzT#Yqo%~Yk)I#7pa0o8zxKo)odqi`qt|SR?LKEx8EB}b?y>O2t65IjUTXuq zlvWE?&NE)MYQ;^t{);o0z20R}m?G(MaM{X>k&b~PYqm+Ba+>_S>j7(Qy5ZWR(aql( z#cj@&Ry^Xnw)lgii}z)@D6t}g&6UB=H(M}Fyz+C?lMki;zlFA0?bH7f#1r>-@2}(^ zmCfoF0g-+V4;pHW7RiLau#vWT^n3PygYWMbi#i9-i1;;A=E;(cIggPA+!8cz^cXvuk!JWxrOxY+E#uU&Ph(c9~ANHp8;VhV7d*x2uaT z6Vwr(zGl0$Shs4EvCs1fR>>yw3jX|we4@#5zQknNN#hBIb8}7fG>u(D(_ZKtx9Gk$ z>E)Y-MXLhRkFSt%yKJ=VM`i!Y?IpRBh5p;*7F9*B+csmH@6FFEJ$9KW?SJ@r@dSqN zmD2Oo{&VkE&kKm=IX}I}!-1ok(OO9~PI~L(rzuWxQ#IBWUfaLKY{$KfFZF$_x)Ywe zPT^aol$d)*_I%prxtA1b|NUB5^;~?xx&@33mGg|}pVjPU;+V0GnJIGR%<0Na1sw}^ z%umfR`|9v3XV$E#m#NnSmEsq~R zZu9Sn@V>8W?C6?zaPBk6A8Oz82+=9Qi(ByX8 z(Vwb%4yICxy-TyVNnGB@yW!@Mj7vo(i*jdkND80$WU|!ie1(bIsYx-~0)0L#$3oo} zitM{|V_lEoGABjXW0TX5Z|PmQ@^(h*nvyNc-@chwd4Bf(!oBDCzL)a+zb^JW+>Als z#q7EFI6Aioe>gFvT_LqiMCy5TlYmc}@TpZ@7k3$b)Utd0v1o0<*Q1JJ)u%H|(ru*n ze@eeyf5w)7LA~$0+gG%fYN#bI2{>7yrl!rMYOpLhc>P2cqm(lS0*2?xLZ&|1sWzFb z>F^c9RmRnlJr2Vd;L` zt@+7a&zgNYbt$X^kcb~uCkG=2z%T1r2eQmbx>#u4`%(-XN_AZbRy<@e< z_4cOJ6?yA%J z|Ni(F{JtmKwQ9+_*N*iyB_%DHWz|RG;$=<-^nLzZY&M&hU;d7~#AmOQtLHK9HT37m zSh;~^i-Qv2C28Yvyt-RM}zK|7QN}v8bXII-f6OX5y3lEpdx-JvA=lUW< zW78U!)T)G(>%P5LR4dmN+)HeBU1o9BcGe&JiJvFcyfY4HdM)=(-<)Nh!j-&V@@iXU zkN8#f<#I^857?PzGk2nBYDtXG>t_G#kYB~NN7y8kl2@-%(*GnevF2>$rz+vg-XZHx zU+d{?J#jnlgb&}rqcfiS7|uKM;auQ#*~J$-jI;$BrZqj_sk@SNYf|n+MUENgTz=g9 z{^4I9Ys2>nL5^cf4VD^IxVJu0F|~N4`l;oGrBU67Sv{)+0 z+H2GQALRe4El=m3wpw(0H@BX?U%|FzI_^`h&M-QEqFZpWma=yD4CaYyb;)N0;=KQMZ^X1}guXXRa zy|16$5nosp_}}H#ztvM14!?KaA@t>U=KpV7UpW20e?ggnlZj*Zn#OxVH+N(d1)n+Q zlV04lNkV6GwdAez*6(kuuYDCLzh2rRu&Bl--Eg&2hyT&2xJmz)HeD{2jZHtuT{QRT z$@`X3mz6?QzP|K%EF@`aAwN~%nv2uIYa)?tVM2||vtKO{=}fs;ce$0L@VS2uOVfwF z2Ku?(lY|uhZsRw*HNE4Vy85q##We;ynYaWeL@g|~ee>S4f8lGNnp`XQ%Ujl5&))V` zEL}JDx)O)aGGjje=N^?F^U^t=nR6^W`MGAo-*3KQ^Pc;p8_%<=Jaqr(?f=G)FLKOv zjZ6xhk}}zIPnp-!`6nkouY9uLN5eH2&XlOqFM@}|b2ln4+>pIH(Y63KHsP{_weG3? z-|YIQ`+uzdf3n`pw(euo{Qp1gk3OvN+q{;s(R)Hxta-*%{%7{va@h~}gBoo&Ee}SY zTGSKywq?ua9?Qp3Zn||}r1?1{zwgtVxX5fa@A-4*e_WcoeZ{G!n>lWI*{{mHl9_yy zSI%a2dQq{sSoc_Y&+)|>X2LStH#<8OT#0S=-hFM+nU%+s=P*oh<2d^AsAc+dZkB+l zqG`LAu8j_uloT>)+4(R&^G(} zd47&Dk+Wm|hS*~v^8z_+CU>g z8DXW1>~>!@4wY6u{0vWfZ@^vexxo(;hB2wuV{iOPs znVH#fy?1{@f9<7CC=7vL$AIh1kc}Eg7bglAoGi z&v*Bdy>Gml_x9Oo>oN^}XYbG!Q&o+e7Cc2Y-?pOrW6Gfwt1irxTjzVbY~r2kIUBFJ zsHlHr`L?t^avHB3v#a65YipxZX7*)xeW;lJN4louSWn?YuFGW=D^HvjT50N(?ego_ z#b)JSMl0^IE7b1M=$g&;;Mtuy=9Ta6*-d)C@3&t2XU_cnelhyr4Dg#{o(q(Sv9$xXeXR3-Y z3 zJk_-4lHn9p{Xo~w*HLbZ1s%Pw9aK>DS!S%Z*zlnBtX-+Q?_Dr4{ochiSF>kx#O%bJ zgK4)n-rT~%?v!Gv(q6lJ_7ro2CqgRrjsKK)i#*)>GBif}-@{w=!mq1m2p&G*EECeM zB=qgu_wRrAi!D0uF3`OG;5nC-+a2Gj&iNa%>e2Zo2KnH-N)iGF2QP6Q7d!s&p-gPp z$Io_t%@ZwG{qm~cswnwp`tO3L8OpC)7N01d7JE3wD9LK>5hiJewio*EgWR0s|9s!c z{X4s-!`fACkI%a9dpB>)$Z%b!qSs)myY02WLB|gsf)hNs6;py*DrO59bWUe_En|1X zk?m#87oLK1iFe}mBN1t{r()e*|`u;=5 z<^MA%CLQQso4ux+H=p5-mpb%ouX-smF*V}3p_$6vZK}acOH=O@Y6n!dO%tsQ6P%N7Cs+8o zplecLP)H=B(&M8aRpsON9k6!1@K-nZjqlZ@>0h;jm^VDXx-b6A@A})%b>3d%S}E1> zcl}NONxNffwuEzV+D{Ab%Gn_lqtf;)CE?fi`s?4{b*>CMox-3Js=`tw-My9nq`G55 z%i_?+wQbez?I#u;v7Vs##$cl3t7&tjCWb$1WEEPg5~RVxc3mFAK2c%XThSG0a;IMgyz@De>U`3 zAz64=!F9@a)h%kLji#Lz(_|`te<#sK&QQy1)uJUDr)H#Rsw~Tm&xZO5+63J$_NJgon zv0K5}#uunvRQtj>xAvJE*t%ck#}yh-U-;_-1PTUNpi$`JOv(pQjv3-fbp!O6 zozCy4%h&M7eZPA6Ush87^ZnVv-}bp~DQIipuzRMJB6+Z6#m5etm;aYe=y`L0-tDbE;QeC)7k&fy)@;R=#4SYT~FAaPP|!f=ev$^I@bn| z{c2MbTsFmSvEDZ0+=bGMLN_Yeqg>nSxDI^GJgT_G;k3*LO{<@`o~AAc=F#vF_|5xx z>e+LmH}6;NR5@+5@58<77dm!kx22|ad&|{+YT>u9IWk#Y{_~T={6Ftb?%3^z6tXpEd!R(j?vy*32$F?JirU6P%Q!1WsJQpOw>U8>shx$2(WhRaj zQaUH*M2oOiS}x5~;xyoB+$^RjGJQ4ovB!l^%qz|>(TUWJ?(6Tr&-9M@Jftsh??9l} z#LxmM&2dpSA4XC6<1Vg)YagBxKL|`Y|t;H>!z~X)TMFbDT$0cubybZ*bu% zzMJpP=`k7oXzY|1{`zN~1E;+D>4g>@+5hWnjTMg6P4c@Dz4<`DmTS#i&k0M)H}wY3 zy769TNk@;z%8v&Fdfm<}3+~#pW0LEKS8d7HgIe~s?5NAS9(6n-hUM``mbp6^*Z=;w zF5l-+T&C~^ny~_cZO@WFgm_r;I34-wzK75H zYO6o*-3*gM!V!7qIp)u&xOxVPn3M{~2Uks3RB$;^ChL3q%S_(-clUpU*LCgxw|(E= z=g@czU>2x(@NVwzDUSosl)kt6w8-H{#x>#K)9WssS`wCHrh9&#U3Z5=WZcG2dzkb$ zZ|4kGI<$7CQ})rKjSs$jv5epQmEo!FK`9rl1#udCdMHyhJ^4aCF9;pRSn0Rjal4Hk~k+l2$q_#-DK^-625#LC6~wrB8{c7$7|O& zDQRzxM2RV&nCjUk>-# z*O3}MlV3RI-fJGKORp{ zJy^Eekwc?fX_laBQ&ebZiSO>~9MwI&+U$-Ua*`?)F@G~=nmw%AJY@>c-u;gLOU``m zS@!bBkMeD2MECrC*YPo>?OfN3SIb4Byt{nd`+IivuA5QXyvk^g@s->yk<(mrzO-^X zA4)CJyd$VxEwUhgN>hK%f1Caz54PnhGX`pkb+gXhT=VCoa@Orn=XSp@cz!O|?%#`c z7R8HNlLXCY^SVx)oH}b+=7}kf=9b@kcDMYV;Gebm_t$_%V=9H!JsOV}7gPu&*ZjT_ zxbbqKa9L(j?Yiwe0r_S&^&ffWn(W&vcRWtIKYglNR(kU7_x)%7Mi(#R zdevQ8;$Yn8&?lzqm9@l6P48Nwk4h0^guJ>&d&1o-5z@lE+_5fF5e*5kEtBTDvUZ9q zNv-IZFylsM*7OBNypD`g`8;#q8f;^>iK-TmdhPH;QtSGSZ8sf1A5>qWn99X-dEpJ; z@;IK4`H&e~<&jW(`55`8Oc?=ozcP7bJj*19!kd-SVa%W|!!Op@?!*|t>ay49zY zH3y?-CoQwT|FOE@|J3=eF`+pbiWimky)T+-C>grv|5wXv+0Q;JpW1Xtb)I`c+qTyQ z%NFNK&tYF!9Agktc`m~wEhKbGXsd|cvm%wu)gG_*zeegFURcE$TitQ%dQORoFwQ=oTr;&Tt(jj_j1p5*NAJ}N(} z`Z1`Y{dZ!%oy}66)fLR2Caw|Y&0Dn4yTzeYXM)p$k||2M)3wj}`7dVuV5&S_j`4=R z&OP=5F?E*q&yvg2)91v`G1fJflR5kI(cx;DP|4YgC!NhYTJ-uw&VdpY(S}aft8SOX zm|T{f_#~st;-r>5&t}sdR>LFhN7CF`x10#9ZS=7EmhoD8dC*D`C(b#YDeluf*95Q# z=B8LP$O~-pH`>f1`TbF?uz^T%S;~$MrVBg@o%Xdd%K7US_iGxO-#2{nPl( z*Y_H+yg&N3PKxP*|EufLZLt&ULceePUb}RGp)B9Q6r-glKJB~0uhm-7d)V7%!t2-U z^G)74xp>apI_+hSSL75!E_0TW`xBNe-T&T|FG)U8(RbCvwGZa*|5U4|ckZHB@RFDJ z*!|OYIkwBkA5ZXM&+K2jWXavUlheIF**t&oV#0I%S&l-dLk-lIYSfttJ}!;p{d@kp zdg`|qER0=?4p<*9+x+ZP(aDpSz2EKmYgQS!;a;BMF+;iD6I+gz>H4YgGfx$4Nm4G| zB>paAciTCMmI9AIS9^o{?{#iizNMo#dfxMrxevd*nKSvZxaMkwb?#Hbe2yn~eeBTR zW1n<2=f}0}b#wLieAoN_?p~UW+~$2djcJVQ`^zlyIE_m=l zP!mJ)t%_zjp9&|T`Ac8iNnA8Jd@`eR%60Z5dWGxb*)RN$tz0V7t^K?H|Eg~8>np0~ ze+&5{cz*q-H{zaMVnIep^NsZ3xGn{|+amhTb;2qaE_Wt?&W~LY~?{fJ^rK}$g%h$DtH0jsA^bQGijlG`p zTKC!w#j8aoUDicYHQwEea$DT>n_tdg_PG;AM=z)QU+|jPTQp~D=GUn`3k&AU*K%90 z=a`r@{ck{Lxg<}Jm(}IBJbg=)f@fW{SoTv_%zK_)J!8hb+UJayPbzMEU0}xcO(R{- zw;r|@K+`evQ;f5Gx2;LHqEyz-8ysJP_lsZTUcmqN)4kv)6Q3u~JzS!D(5%NTdD&*? zu2o4ka+9;qX4ov++IHICtmb=pUGw6@mhboc70|qzVEtzAaVhU)>rYBWOnlFZ@BKaW z`-Am<=!z0GzuVh-jwic4{@B2A!i15%CWY-guY*#E=F);?-e&U!#r8}JDC=#tHQ3PV z^mJBL^x{o(K7Z!Ewp!IavTXzJ*H3d&l`ncW$M&Q>Np*c^yG_8yij($R+KR@=>&hrQBjY2`)^@Ork;^6 zsJf-_{D$Z%g{toiozo{R5Dg7=4GO=aruKMtf$QrJlb93ES9X+rJDFt3(-9)?EIr%r zW7LWNRl*zoZ(l!~F>`Ir{cYO)_UDUt?K&vc?U8Mw zs~T$R_KHVQ(ohUz9zvoTWc7E;X*BYmVl4Xt`U!F64`k&zU`wrKH zDE2-qDs;S_!{BRbyFljri&uP`V}r6GlI`TaSl{??`N?AbWu8t>%QVn$c>+I=`19l1o3 z3aYv5j(-zhdBOVq1g}L)dS-sM-E4nkMmF*^&EOd)Q~6|U}^!hGg(I}0m(vtf4n z&|>TPXu0pa->uJ1J(*v@6{Im|bA{wZeof{XD&^j-+qTY&E`Mhz=@?}@+h{IeF8cF$f;K5nR? z#o_0F?uY#UbM_DH|MCA7}eD)lP7e(`_&yFEthOm!ws76^*jwEx?j zC8m?6gwK*n=9zgeW1H#BX(CpqbaOW^T$AV8xrX7r)2Txr4!>Ua|JphC7xAp~_xUTF zHrZ$Fe3?~o-}z?$Q_ORVL>~QSkocz~EO<%kaMs>uZyqu2jJTMy%_R18`Mj8-dcMy; zr>t7FBSvRY7K3DahmLnPpZSxvHP@u4bw54J1s> zgelzPR@s@d+ZV3zo<7aHY~{tE2~$~5b01E9z9RMHroPGH(_S9o{m^r|Y4OVzrSnO` zi&a+$u9Yp^8MP^LJ;yc0rAZ;vB!mmDJJ_jDh3{{+Q*7itd(FV|Qpde1FccIBng@_7$LosRN%OnD-fqo5*g zrJ2Grhto5-Uqa$H&yoWNO#AQqH_nf@^>hDj)A?0!(zPJPW{+KMHxwk~U(89as&I&$ zcJhuIPbG^|tA6Z5-aSc1;aYkbx3(qP%@4XR&Bxcr7P+#x_8n8R^Sm4JOF1UywEqp5 zQN@%!Ep?6FbRV~;4XgUyl+`A4KK?l4^XK9%*Lsd8@B4Li{io^wF6}@5^QYuJYdvx9 z9>XVA&YTsWo@jo5cmKKmfA;@;k!lfo;T<6d)^43rStEZXR`}yY+q%c1wmwBwU12PV z?jJp_JD;%Sb9)rECDz?=-jT19f-cTyXk58)#?k;;&TH(mmK}^TU$eMM{fIUd&G1w6Q42Qf_GWTvRxq z{gV6SoNQ(0TT3}Yr!L!iV{QI6(3yReaYs%bud}m=Qak^?`|7N>+uXcer;3Y2PMmZk z>0#dOzR#z5)z#AzWFEh437i;gu6tbl`J9;tt{wAqeJ#`EoF=Erx@_IY*ybrsNg)AG zMMDD@Xq=2;b_@(v-c)lc>vB<5)xo1byS5bMaa^WHZd5&Q4|V=^ zsX0c+@1OqRr}Np~cV9orz*yzEyn}V|d+jNcELi4#U0||HYhsk)jbCaiE1!4sd}Isf zShV}NEO)v4wA7MVlWCH@$1WDAZT$XSc}3;Q<9C9cPFTcVI{cBNufPA|_xF?1CB-!p zR;aIi=6bHg&Q;TO-t#?wzgh43e9n1G*qUkH@9yk7dh(;;&Y+r~r{j}CLPA0hw#(O^ zV7LF#(Ek11?GQS{xBSjN`=_x>S9DF%373(P{q)4;^X~h9_s=|gOh)d^{uRR-8Cv)ut!E=l_{-^eEHIgIn4@cdKTtKB4+TY1Yq(R0F5Q?!kTU zY#$`pq{W)gsrxjgyIVLUGT?c|pryzW<3QGqz<0pUFBPG5t+abV|qdQ<3c|$}5cG z)~8g;Osy4C{JKE#y>F+>2aS-Ja25G~H>7_Y*~7=7+IDx7h-Rqn8;&MHzdjDPEwi3> zX`W+v``<2x>F+(27kkw$`qh5zzb&vlsB2D^k!$MBJXXb{2ioq(o5#3neY-C9vCy4) zf!KTI&p&%str4<65bw%gvA5hYe#M^68mcdMP2;!!(a?Ny#?PE%6((w@jm&2A9zTAZ zg=zB5mSveguEzfj{desCkJo?Bod2V9|If4ekJhq(U(DaIwIX>!(5Bp|d3!6)?X51a z{Qp<~!;i=QYZT;aq zUZX#04}{cyr^#}*daX`8p5J`D{luf=NBR7@W_Ik)drxfic1r8INJmfX`vlN>K!nG(9QyJ+vD zj`LgprbX#0oZQs(__1)?@^HO7H7huWFU3rQ}{qg@mxs{(S zPGcuMjJZamW3mPjwx(Lg*^sj63n$Ve%awS@q-6_XvoyBd|Io%gFi>zPw<#*AZ z^KpVMTi6s0HLnUTOp==4daY#2Wyz~4b0ofGvI<^duzzp=J^cB%4e8x7{Xt!C&5j-P zOW&+`eP6w8-8If?fo(#Q7U^V|NrUcxGOzpd`iU#!YE|FM26Fv7tH0}AJ9@o(TB=RO zhX(tf>h+Ds`{h4t@BgHIXJ@I%+pOM)kKXj$|7E}b?9G==NhVL%|Gm2Z%*Bg>>BrSg zZs*2?{*VX|d9p53@KKiVwfLrgzm9J`b#G~<@B25^A+E=+Px`92Dk`KTWr~)Nf$i^o zvW5(rUzQws@R&=%Q!drX`_R1*J>f&*xl(2QcPzyZ_s?0JDYb`RMozZy{XN?yQ)>Ra z5WHRG?eO8r7tZwO%m19atZU5p|62SXwtV}VZuy!IjHR*0^8W2@hphY0C_TCsDLlJ- z*>C6KeDF#g`C66-9|V?~9@{;|Qcw8J^e4`CF8hDqTOF%uHktrj(p*>*meeX`2lfpOn!w6<^J(o<4oe zb=}4pr=AJVSugZ7R%Jy@i^B`%Ob@-bAcat~9gjT~Ic(P}_1RfB&&G{+DXq z&*}9ucik%}Dmpazcz@-elj>`xdGGsjRR7c0_4RXKRvg+}y}k0&7eo1)57m2qf5=^x zb>!wr&dFIWfub?%!cBaIRm)?(=Dz6cpLF+^YinY_{k`$u&NQ&yZ~pR+yE(P6>fY48 zvXe$^A5{eAmyiimT?&#p4#)FMQksMJ%2to!KDp!e`+o9>s;Z zS@Ue`4?ga<2d9#=mBGtbxmDU9Jf7*zTafD?x41miyZYMGqLVjoM&4SS&UsE)-+S*j zweuNjDw?MRW3Lw$)$klNo`2?KiCp)hPcL-(EkEbB=SrVaa@T6z*mv!S!!#eyO)<%H zmYVV2t8)3kl6})m+N^caM%_k-X;Y^><(aCz>+Q7M+>F@{kv%idde?Ah>^*uzclEL4 zJ;$Tk-2L6$NTA<~1&d9JNwbjtdSPy6WbXA9dlqPLvq+_vEBYLB^N7pt{mk=^F-YaO zt>8DCw|}R0{;j8fC`Ra$1RePa?MPMe$;<)ix@D~klX`IoQpK7YR4 z#P@JCzr0h&nre>bIJ@&kF&-=HuM0Ljv6B6!vZyxU$?JK%iU$N2O)1Sdu2dqoL~7C8 zqf?)U@?4*KMdsH7&VABx?6zDNR*U{R{_3~LdAWlgLZ|*^PfzXK+Ls&q`QZ2dKrS`o zgAX4vI(hUxV_#wO_}bpxdn~LUo7aDq-xyWft6%q#+viwv*z@kh2?9!5GA%vl?;ot` zt9Z`+;s2cb;JM;GosVlP{5d|(wrg4Mawu~DXWrc}?l7?$@#j7^;m|r=k z5PF79{$14d2RAiNpE|Lr>1xs8j~`zOEPoZ#FO|_WC2(<$;c}v5og&rQZ4LDXy);O>dX6>Tk&HzPW~zE$4DmX|sU-Pr)SSmITgw z3ruDFj{6*EHIkTOSiR`RPR^rjMv@s zXzJMm&z%^8n&yXm{LSH?WssEg^K!;ULXA*G_1-$B1tSVDOD z=bJgFGD3L!8obgpTQ9`V{IkAp;oLX+r$0&j))qY`aca>L9dEVImZi7VmNp%UY@gKi z^B^NTdwYzI*q^=oznA}6rI9XPnksu`W;OM-1C#`n}-6q}9 z^RnVOyW_iN>QB?`i9f15dK<1Vuk3H(sL1Ek639{d)73D|ijV2XUeg|h)0;eGzBIl} zIpqK6$@CMSnG{(Uf9$Y1&v|X*t-KA#7HoZT?k)SB-R09iX0&Vn>luTt`gYruy5I`+wh+SA2V87?m~8{%_0EN0apH zUutKl{(M)y&wKC9Bcc%>R@kH|Ry@z}o&Kcv_i7QgpNrg8b|y^<<@5J8s^k*9*!kZ> z(8;}Mx`LGN$sJ;oZaxUfWH*nuwE3Q837Bo?Y#!ZTBvjn65r;x;1mhj}41+&;9uR|5W`E>-T$( z9+$5>QnvNUwS$abt9naiDo@u`O_%0MiHVDIJf9h&obvv={v%&Ej>c($x0Idc9NAM|VUs#DxKC@}@4fFI-kRkZ z8mQ5EVCfPY`A~MwT~}7A>^M;MI5T^)nzy{OzsZwSIbFZjG_%=CA!m<15_&8f zMKJS4`Ggps8TaiE`hsQTyx?h*RnLWN}LXRjYq#Ka5sF=uo5UD|3I8@*u9p&3#O zSvEIIxG#7Pi^k+ zb?UgdS5cDp=!qy>pPNovEk5tswbWVMw@7nw@SkFJnZUBp(6Q)V-pY3}g#{HI8^ly? zF1^3TD%4pZC)&vuIPaSNuHTQQotfzJ%4QE|$=rt@K5!_CDjL3Tom3%sHZ!U4i}TFn zjzBJtwVu;_E;<`p>^eJXapuANKga$b%m2TB|IwT}hrlO3YRd2K?48Wh!}4AJ&hv8@ z1)rvz+Wmg7`|WLO!nF5&JpZqFPsO(>+u{~4Rk}Rsf%QDw+EecG{~DA|pZv6hF{aV7-Jcitf@RpXp;Q_yNUV?2Y=4Zp0Bd*^d_0^l)GkY^yf`{o}AMV zv(#yRx}{$TgyTzEB$HSK2kM*v}@;g7_veb=Asn&I?&YbG$*i%@)|Ni&yv71bi zw?}S{T|434V;nELmZYnHw|a9Tv20yjtL~$N5px!rAA=nP29gSoEDwy0|^V`LZ8~8s>{B(BWS>=Dt%xgX+j zcQPJ3cE#_edPLM3<1M)Xw;G;&dNgbO-*4?(4s7OGww!y<_C0@--%mKJ<|7^)7rW=t z^}4s=FLzBVpSRalN%Z$77Z1-#%PML(;)FQwSuXh?l38_~;m+LMpI^>no?c}m+tc5( z`{&)V(^XrgmNZ>+EsB2sPR-)Q9rtr;POm0-gq82vwTn&V@=2X1&D}57Ki2h=`?iZi zo-1~bBbTOwW47+ub&GSNdI~k>Zd$7ol-=|Bg^8<1XNluKk)#&ZbCEvRCvna2@1C&k znW?X=T8t`l;;PqCWvVJOpS}7t>1vVZv}YgFUV2Pz$?d+XdQ&BFZ+1c4qRBQs#SdAz zC+@A7^LB#Ki*3PcPb|00T=sF%Vnf|)tq-Psp04^dr9DMRCpNbI(xj~TAZhnhp;@~) z^>ROb_*|5Dv#;D>w#c5pA6kyCIS_F=Yv&OO=SfdZd=FneJL&E=m9xSVI7_9~0@PKW z+NnJD)O8fx%fqzy&hgL*8)c0y>iGFj3|g>6CV=mG><8Nq5ASn|Z~R|jDD#=2$~)e0 z3ER1}&jL54d$SIG=AN8wa7gl`c&mIO!^G{6Y*tS2kTDOxz9!83Qpo2g4~@_HiO-p9 z=d!X#=k$(UyPn;S|IfDnn}2=#{!j9MTvu&#d(P@VZ(pyo(`AE`%=HIuYL@QozB4`5 zq;c2U42iw)($(?`?OuPxRjzRo_vlIOkN9 zwMn>MNDk9VNYNg+|S zs+Sj|CYAy7ghJ{GI*hPnNLl|MPV>+k!o_F#5vd0>IU zQH`b76t5`my7o2AXyOT#DNN~xaU1fjwtQAl^>Ub`*0|t0>tVs?HoyPMh38(hm@?^w ziHd@mZ~JE5&6&rN_BmvptgCN28aRzRZ<_YB)w1WfF4=5K78iDt8drl}s9c1Gy*$-Tyxa@_7#o?7)Z zZSV41+ZIl|XlW+Kt9dZm@W!QW#}uYKdh$hO*{ROxbLAg5y8PQ+)2!~2fAzL`<-PXU zug#N%(=JD9lw50LlH?AXF)82jdCz~D*$Y(8dNjPPI$X9}@!~8K&y|mo?IQ0epDuc~ zSu%3kq-Vl)ua@uknYFCub@crw$LrpFt^ie2Q?5oAqEe*S`NPfd?KR z*LVB-Z3pLzm6Csp);+)cK*{`Y`<0U_XHRU-`LW$rGU$8Ce!IB_vphT%+3Y!=%XpZI zeA{U6Qm|OW`Cn_XqCn>U`^qdfJL-?^e(&QMa;Pjk$Xr(A#ii}@B6Pe-qS!0SC6yv|Da2r|-wctib5e45tX(}_cV^$X#v4~TCuoLWz1RJ}-Yi}0yQw&Di!k5r zXvM=OX@UpO@72&)rrD`t@Pe`U*@v(~-D^{(I;KxJFTQ|vSz$@Fe=Pg%JBr=+^Ub1{{6JPIHPi<;G zG;H2{`C!e8{5Yq*rOjJ5{V#P%+atR8j{WxcS2?}}?-V)ywnu_Bi_`E3v+TqyNlBH; z*Bg!rt(d+bWW)7Rx4v0jc9$$;l${@&Wl8;du8pt+@c#E9=@mQJ?>PE5b`1Iw= zl*)CP-&uc`Hf2V?TDJ6^)U0KPwwP(i*0lSHoRhM;{PDv_;R45HQB2VXhEaTbNTO`YP*a*=moeD&8iM^8!6*cNnK~xrER~tsKq(kaiV(S-HkEHw`@}*jiToS zY-5|>@^|&e3lZ(YT{cAJBEKIxG7`*Bq1ckFQ9)Z2Bi4Y9k@c%gU3N zKdq{t@qLqwufmM8X$KSw^BU%NMm3(0olToGjGXqt_JF66(3(($f{18!z%N3|IbgVecDb;a@l64TIhu*)Kgyg74^k zOZV9Fl*qP?)A;RvOj!T-9XC%wyi<@yPiyt}=X0KDF8}VoW7p0{@BiNY-);ZBxPIFA zd$sL)XIGvwT3~fi{7AL`b;()VdiU|4ge8QNmwNv0OW7H-XsViiQdG2xNMy3p#O>@S z3T+ZS6b0{neD#NQ<_8faf~F`=Tbzs_3qt{}|t zWYMg1o1*hSI8AzD>E-=FZ=D{Wz=y`4x(+WA<|zx!*}kUCba!m)2Qgj6^Fg0%)Xx_Q z%}tihu<}n@xHXagjZ2ej(wc+bvNP^(yMA4}YWu!zo45Eje~??sTAdvEK6_3sL;tl& zx!a#6U0!fGyToYW>ji79mz)c*TDtCgM#_{Al~cS5j5gd|+j9A+P1{!)|F6uA0WOo} zH5ci8_YG>PA_4b-0K%je5ai5d{`(e{eDj$L(L*p zhx{F?M<#yF^I!JW*-63u_m99E&J(_A)^2GtIF{6V(6aklQO23}t9NvT7sSab+c*^Qjv8>zj<`xFk7i&_@q7|kd*(GsDRdn_`N6Sue zrf$by8#Yz{`oh`&&c31kQ*}A-fxA1c?X%Li#ueAro=q|0e4_E5?L_^KkG*+y51&0+ z)V<)i<>61Cn$rE{KkwW=|Kq*M?j1$`yVu{iCc1ms(mY>|(3h=oMr==b_N`EQV=gRu z#$$(1jW^jO?!TWf zt8Lf1ojdj%*(&O~FTrT;g)Mx$rY+0%;F-a9$z}$7nU>$L1i@sO2SL4c96}FK{hwayso@cKbLWYdqxdH)8O?guu{dMS^##SE-BF>_ zb55IP&QfYwkSEns{DR}-ZjVRYae|oz{WF`!jq0hxZ?!oJ`h>+sE>FhM4dr6XuvF!5T|GTgdqJY!ZAY)v&v`-0tt^!pq+2 z*4t+DzW&NKS7oB*o5yyBoGt4!Zc0teR|?OZAXEAN=ezd%il;?BdorF&$Q7S)xboPx z%p2EDozxyw|NmY$T}SDNOwlXXY^P7Nt}#E6acB~lku=v?LqO}qtZk{jJB>ZEFIEK2 zov_^cRjq5}v^n#1E@Zk*TDs&~fQYak%L|>y&mPTE(X`n8UtrFo6syHqQ6HK%W!?xe z{j%P@WZ`EgHr{=yD*Yh`wc{;PCMgLQCY+CEzIQYuveQfD>bj)8w-*Vw3UECSZt)5H zxbvQ#-QMM^Lk`BAd~A5{@e-G1oMJ21vJ16{NxU{td+}nT(UaTN&C{4xvfMisVz2oj z=)$83k%!)-_|04Hcvs=c!HN#%?E7u1UthQGpReVvqgp*X?@xZs=bFND-bL}!z+i~e=_O@_w6~iAZPjoAIUsgP|-CrcC26Ej~;JN>zMU3}~vQ-<>A?`mebYns0K zSyfSBb2ek`MX%yo*(IUx_k7i9X>!@IKUYd^v*fWE4s369ygCjlD|iM^nWPh*ZTIVg zwauI}7W;Rp80*g5sN!|mGNYF_c*`V@wN3wSusxPv;^rxOGH&8~am#wIiYZSfw3zpV zDtX+IF*(+@MI@Q|;RREVQwpKXX1lxIEuOw)rQ1pYvBgW5tdjLpvtYa?m3Fyl^W^OU z9P8HQ|2S4|$5CCtZTBv^xy|ZKg%?Xn(wiS@do0e?iq<(8x2SlieOw^ya4El{)gpu~ z+sRm@XIhhI-&Qq`55KN*+bRa}2``u5(OeiLTBy{wOy``{lrI&xk2a|k#s!q>&aQR+ z^g?d(&76c6)#6{CHoxEV=I`I?Pxn367O>b zgkxXq`R@2`CG*3zZ=>cIb|@Vz(S0s&dwh1^=FP_i%5OwzFWann&nfcV#GpxOlIPYx zJ{QYpb|c7GCFYy)ONPbO_5xAAzjt3-7!pxEf&Jb&CyQBs9$UQ*_`z@eAp=OMqfxGI~p7Z&PfPD|R=wrN$xzlZPdL(|0bZ@jO}Iz7ESW5ac(d$SnK^;t2y z?Qfp@tmQuGjhVJ@B$Zk8U2gnulU|arUw`Fy)2hP$Ww|@!)=uyhe-mBm_WI!QJ=HIr z9pCIdvy@}jXN_1lSHJM}3#Zwhu`!tPJ4v#8eTQ|b=7Fd+;vTQt4~2*6?yeOzx?J71 ziNnC{_STeJ50AEOGd`mx95gqQzdZ&AVetMS71#RARiY$q{Gif%B>x&L4Bv{BmU$R9te>{oa#nIa(= z$`spf$~HG`;mNL-O}3eQ@^Q)8Jgct?EfvXJ_0p%ie1eMPrt%eUw!YiwDSN1^?RC6c zK9l*6ul$9F4}VpStKMG|FXZsiaN-$TDf_BMwqhMcwhp@*mwQPc*^eBEYJQ}!y+m&Z zW6Rg$h0Fqf4DV$BI3lt0<;hu-Pfq!}FJ-&-&75mFdU-SE`c}R-&YzeT8FF4krLyT@ z;od82!lze!x9nP!u=^g%js48oI#sh0ZuiyhbmuymZvQ*-Uga;d{lC`!|GbWIhjsb$ z%XtjHX1~j=4CbgTjEReVI49L;Zkz1dVhv5^g{yQfMzKHI@w&XzF@OFt$!nEit9f&; zE(-Oti&bb{w0irGa|=~(RD7SzvLc*Qu;_iOb5*<4oL9dNx#{HcDauTeNSxDgVpo4& zp^=zBe?@P&P$$>6P1h3V9<=E13|#&3szlkrYnDb=FV2|sw9J2%aF@>ESq~f)S`N8y z-`0G-cK;F86EBWk@_3kZ`2qX+@6ED46YhR}-Pb&GQp%YW`#*2mw7yh*y7Qv2@h4$qcLPr`sDob>~EIF;5-*))1 zSjXaHsvqR;2p&&*lVah=@4_+3U(~_tM*yWdakwPzywK!j8(Iq<{dBksaXHk z{?GZ!|9{IP@9L~vJu5SiWy*z{j(Z=>aaHG4F`m%6_HWADp~udhVU z-TdJeo>JLX+P7*|oAgNq-7ZHJt3&^v=AG~EpEr3GXOLRO%vMfwQ^i#w*)8H3g0r|> zPs}Kf*uxw5If%vGN?r6?E9YHq@nsKQY}bEWci<~)+v7}$CjwQ*9v1@?vs78$xxR>D zoOI4oCQ<*6DPMM!N_CfxyQlB##Vmy?k*~QEHmtQ@vc2+Q@~h~Ks68LtRmHz7yw=@( zt1&K4eCFl76Hia%^u5pW<6d?Ap0JV>{`Bg?53}TF@vtpkYUs0m%CgdVt8xW1PrZ3E zCCTdG4Ly_S^^ta8HCpUjZeA9@Jwrr;U+};+%Pp528574z2r6A zJK3Th)qD^L__#4V^yJyIrj@h!URIvl`QTT^+Y1a|S~sb$6^t|e`Q*ypqJn}-uHdE&DA^aztxvA`K~3z!t5E4ExTEi@7!#5+vW0d9u6)l za}7NdXC7m8$Zidp^mbj^-kX=UHmdB5T>s--r7Q2B@bB-9b=7Lhe=AxQ8MsV|F!ODm z(08-O@A|bl`)f`<{VB^18btH|Dx+h^FMPuyI8O8E)t}yadU}`vcK) z-fy^+ILGxyLr{r_(8@NS(!P)=zMA)f0!D&IGVaOyXDS{0-N*LJ@tIzm?Z1N}>1Q_B z&-?QTw8Y>FELa<8MJFvZ~rxU@nsKp z{+wu)a%Wk`^<^(T4HNC=C-+FMJO0nLBgwytbFn~zZw5=LPSv%l6saGIyWjTREjzq- zGONIXwD*qMzSql|Th6+dAKVu>wOQo+{)Gzibt~%UJiWhv<&XPL496m6Y)?IYd~}&o z`Ll20Ukddv#rxatUl70c%l_+8&98auj!4got*O7b-se#DWeMk<>ovYtugW_A^{M66 zdy}3etW}ur^YfATy|m50I_!U(V~-I2!@Nml>D}-M>6971w;vU#WO~KE-MMe)!>6a; z-vifge_qe{$Nsbb`})+A^{=DvKl<}$&ip@{?a$Y2OeijH{@iDB-r$_VRHo#DYi&Pn zSY)zH+ob3ne6RYu>@|J;g}h-4SGL$(_4(A3Iel_Q>x8b5r5TDRm#SUWjAFRg@af>= z`|Ss&#Yw5Uol85%x+S5(oqus)4pYpQVBX**(--|;tr)fSe73N|tR)|lAErqyNK4wm zXYurL$hk%?fz9`hGB(QA>ARU%2wrEl?W)t5us!ccTo2cB={q0q{CKQn)91`}cQ&`r z{Q2z@oZBz5ziN5r;qpoD;%-}kgR{;V%=bC5d~!2O-j<{f6Q3(A{`;|E9gp{~>pRu< zmVU`GOSYODwDn-%>pw-l^m7xh87c-nckszkM5(*(kwk-|axUwwgn|96hhqg~%w)mu;*{r!a$!Q(4q;KYh zPNzj4F$p)cRXw&is88ImjHxPrj;)7Kwe8ko3-&|p4`ytL@72tdQ44*0u=~O8XFa?N zPuy$jdCj@f!K;T+^Q-i-w;#l9y%TTjb>sRcF;CoGIQ{`ki_*Jz>4!%RSihN9Gx|MP zV!wdZZVCUl%kl9Zdv?5C^8V4R#q)2ex<_o{;9c<5&S8I)@%-~AKQ-yidQ|g1>4kt( z{hIuJTNC-`sCdqByRElwHqSAMIp3eSwwbowO>*zS@b!dcI$KRlGt_v39OX zMP~c4v@@G5oI2h5>Kw%+9dCVTG=f6Hpnmt?fdTQ?r9dTdhUD1;@ zTf-J`c}`59^J30S56`7)XG1pRsV@7uQlS2p|Hp@ht(|u`}i_MP#Orf0;}RWjYKn<_}; zRLx$NxO0!=@wP)|V(GF!ORR1@>Eig`zPDZ>@79j07c>8}AG*`QahiWQqs1c6j_VUG z6+<()svpH)Ip`%S#o+ljD!KG`_K%BdhpYQb_fEMWAK#R$aOn5q=Q=G*a-~}Y&OA3> zwpsJ&5(b;_>(}3$;{E-1-m;t<@3zI<%c%@JRR3xIKXIFiiuw0{+`4|Ew1eSV=P^^q ztx7CQBD)S07ndIX>3;q_c&OlCsVPG;$F~2~$vpPoKieO_`BL-w`T3t8E$)xdTOYYD z%*1!Xp_e9!Ml%iOpR<@fcT%e4=bJKfm%Lfkb$4IN-rI$N?;_^R35fQ7F1ut_`uqLI z`|Cfddu%x*;T>AOX5FyHet76?)AYB_e_AT@$u&CO-+oVW@fPc5{rz{|*COXhDk+mQCmeT` zPJ5VpVbc3@kF^3(52M<@n^`ak-TkoS_$~=U9scW<|8DHM_4}ccWlm(0VTscphZu(X zke7#7x$v}w*IGS@sN-fY^8ByNBNU{{(kZ~Qtw-8aM9XB?zYkvCD;+YI^h$~r_AZ*@ z_G`ka;}e6HhA)y4=26?sbh-43@7aB~E|<#Qjy>tFzps1q!|KrL4P^||fBaovKX+GM z_vFdKYLy4`HgoReKgy!W8k?^1X--!Br%z9{_kH}mzY;RZoO$?v^5aPlbi{hI1tf%L z?27;UYJQvj)0ew0JiUMC&WBf5wb!j*AF=-WpKJMl#lp?A_a)mMsXno3%FCRCIdz9h z%ob`G`7P&nO8nYroX~r8M&H?G(o@+_-fT9$SNB{pQ>g1l+4iTup3Qn&cJ?#>{?qOI zzn8XTZ*s5^Z>c(p?fkO?(3q(1a)~yvVyQi@9z%K>P zEoLVcwFs2h34KhRFz;&|dy+>{w^Wf~*D=|*(X}zFmqfMi-)1}cPVe(44Z>e`zh~C9 z_qdm&6tCgKv^;5V5!3tBC*~|gOZw+@$UXgV@yzn=_opVY=ooN({qQlH%hg0!sN(6( zQr+vhN0UBw{Jg0dIjia85|$+?3c+21pAf z^_%q?Gwo%UHN7-Xw-MFC=@)2af!kx#lr@ zs!m=$&VMu1dRChM)i;*H7p{g*sqk9jcVbG~)}0Afa}8(DPgt|qSWN#&Kv3$F5DV$q zY~?4mZkQ{pmVEihvsES%(tAuMnW%aS@7l$i7}M$IX)p55X8w^gtb&t%?pl#Dv9R)q zO_;@=FDpVOiE{czyK~Ne_~%jA`%R8k%|~Uq`F~aa{e1uTFJ$h~|KkmNo@1;x)|h9k z^}IaAM8Cpf=BE!Ah3&rYoZs_F_i+5Lqx*d#r^Up_e*W}FRX={ugR4ii?S8y)eznVq z%OX5~Hx7ojANw&7p+@KW6%2`1vmNWf4rl80 zwCG}%1?}_Ll@}gx;}9r2&-T4tZISxpp9gRMO|ZJMm^Ue=y=u#%`{FAOOk}wb^gw0H zy-QjiX~LJ3q!-j1zUevoap@!eqSJ}OLZWhyMK2%t5k4t4c9D?pqNYhlBHbg~)E=Z1 zI!$9$)_QF=ECE^s8-KgZR^}meAv79`;tsA zQDgb0mY{uwTa6+F3o@3qWi&;OW$=crPNmw@1h- zna9F?naJ|ZO>c5fK6=9PTz}`y_fAnu+m~f$-V$5m>LI(%STjla@#9nJPnZq*e)Y~{ zP*gZ^{A)-=ai(tJy@f5$yW@Wu`uUw-v^uG;ylwK!mSZL{F);LcVpc88RwQQ@!GuJYl(o(p8pD`EZ+-&ho+|%Z?5^eKO(#CPjzivzH`)d zQ{T%j9D%&QudDcinjRakefszN{bdv0-?bg{@4hVy2|b#({o(EVzrC=mU%5wG>NLD@MSpg3)nfGU_WjuxO&su&h)}29!9PfE!-S|z{ZY$GIOPBK+%uCz;W z_wbCq`oLDbn>8wX)v85ntuN_3eeyN@8=k$4J z(++?A8mciZi0{l#ozqEiM-R$gn&DtJ=j`*tQr_C4e?^m|P1W?iP2MQtE_gIqc;39% z1#eb;KY6ag|Gu`sla2}MOQn`{>n+RAT06scc}nE56f4&P!FBV0SghfF5j-umVrBdD zOYzQiNAzE=Z533C`E9pGsYPO@QKWUvx+#;EpP%>f!$sjqCXb(Xi--KS^^M+qKQD5s z^}gSKEal_2{z?D;)ERWzaM|Y0b9cBd&-_s3p6;wFdQWm)e%_7TZT3c`-$BDz|L5B~ zb^Q0>*!2EqT1VaUzf1CRJ+=rd|Jbzur<&)Xq>T@rJV}`mb!dH`{l}^L!Pl=|koc0_ z62AW2&Rx5Bo+&8p;Pz9S{A0C3Z{U(;#y8Gg+9LMQxx;7DiwE)xR4WY?eS_65bDqCf zXgv_nVYhitRZZb&S!LquIk_c-eTf58Z#E*_Gq`$Ae5;)=8J`mOcHn>uuTTyzotN>v!zf@!$`rLfEI` z8~n*;4c7;Q(_BF_1FoCS-S{NZN`z&pic`fDzC?Z3X@;UrJ9A%JIj39QTP1yK+p>Fa zR-T?zv^#loRAAoqHQ%IL3N@52YI%BWRq-$SWTNUV9J0!3;a9mi2f3}^6jx6_ zzN7UyELRq@F$)>|+FMYVB==N?Kb!md(}6ZT_7+-r-^t>vQwX_CNRD|1FO%y=<7ae!FQ7EY}ls0 z5JDvzD4>AS{s-@@neg)63^JJa{;uRJwt*PXzrqPf8rr&O=n zmKgs|AliSCXy&9zuUcHRw}?FPtSb2|*78W#O`9>DX{NTzEjh04a`xwDD_>mhZ;#!3 zgg?#EJ@Vtb%a^21=a{LU{^W6H z^T8RN<`p7$%r16^v1uLRHnOYB*1cz$wpnuW$(CI!n|0SVUE87{ z{fkvqjL#NE$cg_pkIeXA=*9Z<#Di7&AAUV?`c9un%Q#}%TKd0T9)X}_GUO;`24Y=(E|?*0s{G=A|UV2hhy zW3tDmZ~s33cvkVI@YSMoyT8}Hzs_aU#%){uZA$t5T7H3&*t11jlPZf3mxTxAc}+9- z4m&Mc8oF`4cGzmuV_Q-x#r7Oi=8m$K=BRN>+TFM5-tpP<)q*)YFQ^=yQe*a9u5oGp zZK=y!Zme6XEvF8$niCQaGPjNY&&^JXxl%w77x%Rqmo|j)K$=0$c z|Jp9T?gX>>lb_pqJn49~^ZLSni}x2cA1yflC#d5ImzY3ZQgDBkKLN#x3bN) zee1Mkxf#*c0{;AJ-pY~bH9J$j9DZ*ra_suIx8Dzc-&j|@wo>kwhW)8Xk;aww(_XiI z_v{O4Gx0sSi6`UHsk4)`*lyp~NbLN0I`4zki%P-6R^A2?|KxO5NdB-(>=o{5k+a=# z-oNIZoad~Kci%X8gsoQHz3EVb<^GzZ?DDan!vEdfe=a)T_UWTPqEek-*>|VE)>*gJ zurW9=&wS0g>Ckl`Z#LhI^M3#L`P!|gs(-|NU)!i{*0i-<^J(&ei-nsnv`=B#UvHSQ zO5WFMV#W?_@3Pd&FJCX4JiYtGcj?9s~O+i>Mc(B$QkQUM-Q-q&7r%q#^3Cb#Qw^tQ53Qnl_q@w6+ zdUMGG$3+*l4*s5SO~EFmvMuwQiEneUnwXdO`J30HE^lF5x!8KK{hJrdFKbRRs)&p@ z{?Ju+p;Z2iZ?*H41S=W$PM)_v)%4G@?}v_?GbtCPx=ft&+*E~E!jw^o<S8=)h1Mx6WBxuVL_qh-63 zx9&>YuOp~g!j$KgF-t5v=f`)$9V>F9KiM3wYTqb3dC!9E?6}yNPjA=%KL;5@<(I$o zJy`L_^8;Ug&kQ?q{J_6tmIuBC88hb9?6H)e&Ch#b3&)0(Nh*hr|4!~%_&O?VwW-(A z7bePc#pc-TIDUEiypQ+N@2PtRf0#CVwshF)Pz8y3^NUL>52o!--FW%KY13HmGe3wA%#%Qm0?dj#ZI(EEq3jC@wTmyS#rI8QC);?hhz48w~PC1 zv#SgE<(~5GS^0!V2X^$;Z zR{gKZmW|THFn>=$>=h#?0F5LS#{!e%O^6YH6JNxS| z{6Eg-lHD6r*C9RMSFPrq`o0tPzi#Q@hfHu7_}?~T_-P^i_c7P+z`P$FU+?(;`^)lW zne>?-->%KRbfoIoTg%n%8~I!RA6PRjP<*Md!MWga*^;(RYn(JD2yMBxU}=(B^oI}s zoUc4ry(Y11+v0WEX0uJFPoEw$Xa456^*^4O?>}3$_35)T*V|?m*`Akre%72y+L&N9 z+hC^O1g#Sv=kW8qs!iXpjhiR;p+M(?S5lWYv(B&lW%26~YwfOV-q*8L@BceyesgVD zj=A-#Ea&pei>4+;`5Y2?qtp3iiPgdrpEm59kmaE{Epa70rfwq=QxA)xo6`m^TU9y=Tx}Y#MrX!_D`VKOWnkym@l(1|}h~hYNF~F4^#| zJ17$~;poNwFAoeK>{ZZT7E+c&WX-$?VQ(jR_T9Ye_yZ2GWVs2 zuG{DIuTM7rUNTu` z?(&+~hxsQ2DrNUL9y70)_grWC^*ML9;)C&rfX6-*eWEkMng) z?{2z1RcC$vjy-#xy!zGk^s4Fe@aZ=7|K|AabmcgiV)XEd$_c6Emo+nIE!rf~&&&7k z(&Vg8p)Sy&r`${I6(`u;cv1KD{*U4r%h>c^?rQs*b@=O1)^Kt0n7Eit`>I+CWGlla zEM?7HcQV9nTE-?7b$?+Y!5v?sxP+Dl1})fgK(g6*njYH=1&55zDN?4l0;{E!Cb!zV z71xy1O>WpS&(A4YC(NrPPGPdjDxsJM5+`o2ENx${N|T~qU7v`3BrksSaPjq z2l}WT{%7eaWOiD#U*7J~#lKANd3`TWcy1Zwc`ECC+HS`MOwIdqnJt5~PsN^0+pQQV z_3-Ec?LaTZ)~>LlF6SEpZ%p7$bBL1fx}shg-{F6AO`6WuxAE)u3BI@`mh7|PzN|T) zprB!HcYx-r6)!7-la1=$%Z5qz6gh6Wlvt~*YX9x#`48&;fww)^*_|_{E{hr{r}?L9*t_LB~i`SZu7dX+`lq9 z+v!5jB<6!BD7IIQt~k>rTl+w_59w0@~3__2RUf&396`!d2!sck>_j+*L&{gNmfrh zKAlc{%5w0Gx=Mr9s;u)*pNfWGH*ZL9?#F{u6E!r-txs(_BIUg(WP*}r3B&!@X*Zo0*58P| zSSptNhT(WyJl8_y`hD@<1#?{GBc7%Ga56VH=MbFBQ|dHJ^+_eiVoPi5Zn>w7TI*iV zx|?@AYv+@zM_Kjb_dR%YRXcCp^exYyC)%$PUN)Iiefe^oXT@npMP9lpaFnqrnrz#= zWv%45U&pMLOsY_{sQuD#^CqYNz3Tq;75(OYwUL{4MQ+-+GqJMr=+~pH+g`tTC8o&| z8D^kabV;S#wZDOfqxITDx49a3>r6C}aKq!x=1jllk+_8KSZ;sVI6L zG;fqn=so!Q@bR}6uXe^iuPpyk;mnn+?`f;T`0bOse5lptms56STJGPmyI`L$ybAJBKvlo6=@$|aPqP#+f-*=XuNxz(J zlHqU5x~K7f7el+n*9?zkJXrbtpYZ*SdD^UXA7;<{k#hgd){FBKkBBrmx+=Kj&z6dK zdGM-43M+k?om0k{d`~8iXwb|?gnm2UT?~GfgaoxM6e2J&q zq_iiQVk$|VUdu`%q!lzK^@M0nQ8!^SGGmK-P#__x)A0FZ&&wRK6H~XV2fuHgl%QfN z^7p*nrjv6DJk;5(W(IU!D^scTnkX)~@TJD5o^825Zr4A5|Ka{W^ZMrfKkxr9|8sJE z&CHuAhw}fgzW*@%|IPIVGv|Nc{(mh#!EXM>*nE$zPHJ6m^G>I2=Dg&;_M_dOnyQqe ze3SMC$aHp2U$|jsW5A0!zmIU%+X@!XVKq=Y`ETP4#;*_d3&{VU_EPd!)I=4j#)H-F zx677rz2LbgHR0q#!@~#ocdk9O(NHRyFXPrh<_8MyJUx@oR-Juc`+3sJrseN#pS|3? z{p9B<$G@Ljv0Ey3Ny$EEH}L~1o*T~bo|={*Kkosj-`vP)AAfvQ_PKpek)izgyFUi~ zL0Vt${ohg?SMy2wYT~Yc%BGC(s_#VpJ#Na$9=m6Xt)iC8eWvDJ3KMSfeNtsv_~ZEh zmN&g2CSDpX(>)fp&G{k_l+6B8c&_!P30FIp&G4J)`dQJY=GorwH{XAEJhbC(Vd2NF z)!p9PZtGsHJ72Xot+H5HC;PS94c_INavqae=Bh26aq7kc55YA#b9sZ-TRinmEA~r0 zk^27Dg02@m3)f|@+O_btRhYT=wD9X8zq`(6ojhCBoE9KHu))`I@ik zjPm6dT`T6z{y%;1_pYs`w(oz}<^O!8wR?Wuxid43jUVwW4Op_`gwV?!9$`6-feSPy zHZy2C6v-=?J5IPG!B-=!zSFDt&5_2(J6H;tBFi4JY;*CP;t@F2M3c|5_p;yZ(yiJ^{N5^MRa0Z= z|3BtCSP$=W7MZ~2ol&XRInl_%FKg|i*Uv00EFRqIjec^J<2_Goy2lo$lOKM`$9<#Rb9Z+I9eRR_1%bUAd9z2SfV}D9{Y016c zzwhmi|DLGuqd8~Mo%u#g6(&FO)%ed>34ZyJ{$g!i1?RK2U6=CjWbMB#cWc_hB2K1* z2JG7!I;Op_`|u;yL#ah1LpM+>p>=M##AU^lHCtMaTl8n@ZaI6wZED;G)0vZ&XfD=C zeV;IY_V&C>+jxC1Z;H~jw6lBoBXeoDpLDu;t?8tRAI&aXZ8^%uAOgzrwKHzk`5 zr@bucR`D*dd%?uV&;RrM|3mf1_J7>`-){cTiSlWNvkSjGP+YvH<6Lo9{I6d9kL&k+ z6|?_w(tqMI&2th{!mgCM#;#}kx_={Ewr-|Wn5XW-!6^!nMI`&W zevwXckUTrHX2ZRE_Z-zFj~_oi=d74Tx`nmPk?iB!@7bg>{yDQ>ZjWW!H8viT*He$_ z%`$pgc`j?~gS+MTpT51WZ^9t{{L!C@^VYt+$MeIx-Mzftk>h67`+wXI;+d{YURfx#ue zoW;r?IIB$7e4p@K_3=fKm_t^gPu%P#hLokYf|QF5;Yj zWQgeLtfSoL_ljJ5wWKSpk@3vsZ1E)lfBWtq`~7_f_aXtUee!+VUK?C9n$@EmDfFQ) z{{N-*#Xm3c{yQT7|8dA_QU3S$pZ|>B9-;H>&*S<}+<&hA|ET|Y=J|gjQSD|%EC>2G z_idgWoO63ZdgL3Hor)U`t|b+&;E?`wZocr0bqB)?4a1t=tJHm;zunzBasPb5h8sWB zzSwq`vI&G+wzDMst$lqAlwD@`hcV?H5-(`8K!zbNBwwtqD23(l+=Ug{>iyUUAWnIt|TIP#Wd|_n+>!qYATM@ z7%q-7y>hneY0=Rfv*WY+TvRi3Pi|^jbi#A9%v#Y-uL)ikx9XM#w|DOnSYeVlDR=YM z?ac}qic|Pr$8bJYd5;?QPu^_FJGoA|SBUBQ=O0VCW>2rn<-R+a zsdd5&73b%ym1gOo#t}ar9rTox5WD9V-}xcVq5k*9RVTX@`b6`X9p9RXu^w8#YaKV= z{Cy7}9(JyK|GHdI=o`OU%+Au*%t!+*<5PW7YmMogIdhV7P9I##d}(!f10;F8Pf{xQs~!LUSN`9-M(6W<)gMbo&bm;_8|8Fe za*y~DPtVZOC9VfotuwqgSzLL|*EOp|m-@Z%IbAX3p_TLPYcEWA4=yu~NS<)%VayH& zmRHeBPILB_$|*LhS6?nse36&%wq{Sq_Z^XnN}Bp=I+sp=O}*(}wp&Qr?)&qZUpqFu zyS9C^bJK=>8>FSLKXNJ9_*z&*Q+1Nu9jR*Tp3_OPTVi`JX$CpXTm?i(Dx^eeE3I>QL8dPnWnlPD;sGnfbbFd)#lS z%NJ*?)p@wodVA&D+4mpR|F-^bZU5c;KcD^2_kSzj)tuLUGC5XgrokyMEz9L+iv0NB zC%@vlzP0hobJ^pYjYFnAnsOkM^V(%I-6)MM965jLmfbCly&>|U(S7~YCF{a1(jP}H z;Jk7)Bl(St#!MES$pSOhDSJ+06e&3u@WQ$8ZQ+@QPYQb^Y?OXq?0mr(pfM$&BD-*I z;?^j|4?V{oPbi3P-0W!1)MvtZTmD+vl|tDN^;s@jyOue6wt58Z@pCf0S89W<&OgZ!In_1;NcCnW7DXs^9^Ygu2rF#E=r~Toz z(dH3z&RWFIG0-aBq;p5V;b`*56E4BqO^+`>F0S0rU0k^DcDmjC)#dxYZkupu^ZxB; z55D8uy*v6zra|z=ZJby4ztz|zGR5sgOBhRNb!e!HRfA_syUIzX3Cpuy_?YONG@f;B z(cHES^Vd2Yf@xo(GOw_8mCJ6FP13OZTPfT4-jhLW&mE3WlhpHsDk|5tRbR8^c=)u9 z$1#v0E*AL&~7@b2#N zo%R3i+}+*x)PL8Dy}e+m%K0F-#e$&QI2YAy)=9MC6aRR?eM3pEv-pY$&d1dPXBmZE z$*#V+A@Si}cXdtIi5E9cJ60{V#bU zCl&qv`Ml!eIqsUrTd)6+uK%3>@%#U4_aD30e_Q_J$akr81#Jur3Jjhujv@6;FVCs= zct}oHzIDwdwDMHZzLZKc_3N1lJTn%Y4bVF1)%sDl$stANfmz%<=7($C8TQ`TEI#d9 zlaIhRPif8i50~qETB7go5`LII_l(=e+>(Mf!p96GH&}>^{IQEtmcE>5&D`mBM8&7$ zYt>`R)me(|@0xPy(v0;wy_L)6uXU;e6SpU{aKyI$qt!+oEoFn^IzEUl>-*Mdf{;y-MOa+B{ z=gNP-dHY`de${8+uV3%~*7B;s5Dg;Q&Jx|)KB)o9)gWqDW+vAs2ueclK`R=H4XLI#7l}CaNmn{AE39QIy zyS%k6GA`gQ#h8Fpep{q9-EjNvP^JK?~`R_ZMk3}uv|MMq5 zy?u3xgVFWSvs1IpC3@W|Y)bDYSe=&tFI?Xx|1;VC#Pt1t{C{TG|IPpK^!_gy`>*f+ z&8~TKwSRMY0cW>TsAjbF?dD{aphC0R8>4hjZsO4ld7}NpBKY2n+1io}md$O6!JoGs zQ=Bin)lT(}efDhoH&=fj|L1Sd_xb!GnTnKMn{FDu+Anr4l0|OiBKHQ)yavbRitV}` zrVN@^OnGZ;zh!S?ezV-Xv+Kl*fBSZ=<7V^n+7zKyZBcPs_{7%IdbQdbVbo_PvV7y&McLD_)-Se)Hz-q-Uz0VGUOlgin2(^7k+E zxAL-ra~Iq^dbhS+U3DnRKXBTTNWW~WJq0Wc(F?wLE@V%fxjC^n|Ey|iLBZ`1&q@~` zrYCLzcJT{&>(4D#er1vKmD%CJVdnDr7He)Z_IpaqSN)M6_TQh2FKFe1BhO-PaCL~k zocBuXOuSafdZzw$T~Ak}n8+oTmG7*3Y;|tNg;lvy(^iWvS69EYw|@TP!_Hx$M;|_P zUd8{aap{7Rf@jjcYB~PPeNJnZ20yILXe~b$V19OIiVMf0syf|eubWRU^LM!(Su!bM z?ZQmyZQHkNb{$~YaBpJ2SKj@dhu7DB^#1eb|JUL_=j-49e`f#VW_|1X%BP{rqN8)( zzqur3F*7_TH^0^EZuOp*5xUbs_a`=OowhAg&|{JdzhmtIM(fQlgDciOez;d!sO@3< zal@VWUsk@dcwl{j>xV@f*W6xrp4vUf%h(=X3y>Et|5<&pX>%UK?=R8Pe}7-CH*XP$ z5Z0<+n(`wiqqDqdgQ8jN@f|XTGkqe~P22PRU+le#zk25mrEt4F7CaeYw9o9>&)eHi zx+&kQc^(V8y?d(m^c%PDvaLPL=HR1t$;AEShn;Q*{{6F?&iAb`ezymM-npYc^W+p= zzHk43{r|%?8r)mj0_R;U)y)mQyoTqT3CI0KseK>RzUiwT=YRk4*8AGtwQFsF zFW#meysdoO4X0q;)d`btUprXf;u*52S)n^2PN~Jlyf~))u7pbKogFe>F>C()Jtns~ z=J>N8`qx7ziTK|O7WZHGQ7-eZ{X=uRNAKGF4wOI3|DZDEQ$XV>je;KC(&sW?LJq$u zc>d_mPSZ9Qw%2jG&fQ_2o>5Ppq&9xo@K`o{UEI^w>G6lQ$mU+Zc*XSd(K(0P+wbhH zp5EThA9+rEj;@%^j(T}b)#%HdmD3h&kuuYsq#|*F<6s->yPpa#mG&zLh(GplRJ&5j zTcI{Nu%P;j+|-OqHjh92Xxabk`ai4pd;ePfe;WVC|K#SL)7SGp+~L;WuuAG)<>TCS zvGsi~Q<{urqr7r%Z-~-!5?aZ8-~Pe8QVIJ?!TLqw2ah$^h;YA25`VlgL3ZsV+eg;# z7;0{>`e!{uEoa%5*Da}kInCy}y4E!&?B%?$xNGia=kkQVGS{LR?6x_xEnFx5;Bi=I z3^(gs{`*_E<-WA?p7?anr&ruPYL7RpTqOE9u<_eNGkH6kC7D`rKkxMye?3+@tE$!9 zF?`|HWqDFdOgMBeI9-%HeDckdt4W21Ogk*ZpDSBkifk`m5ZV-W&_n%l*P;`iB|;lE zWja~jN;0|m=-u7lf9B8stv+Yo*`39|D?cqtNUv_6y*;ns?JM3c9p%$TZj&`#122`a zO=oUd;dUptd|mo@3V{*BCDhDp`0c z%qeIJYnI8eUk_efk38Kw+q`n?UyHdfGhVgbtT}h`qT%MBJ-grUKb~XP?Nw?2Lg<(L z+OGjm^WQD|t}sh(_v~ev1(S^1Y|d-Ct2(iqZD#2zI`Ub6-;wkGAD=HS=H^=$^YHTg ze~NPiY%FR{i0}WRdMW3~{C^w6Jtj}t{B+XVmmPVc91YhbTBek2{JmuI0keW_+x`2p z=jZ$o$(i-AgO}Z2pKaZd51qGX2>*3#-hbag)&8~b*9Y_Cx)qaB)!WSR@JU-SOBqhIF``WI1(~Nrxl(ZEUHa0tad3ANQ&$8fi7HVAm#GJng^v# z0$j;5vFQ_5#s3XHSb1LC<~~PnYml>p3-P?%vud0#72nW~oO!&bY<*Sf=B^*YDD^FFaIIGj}d8 zG4Hlxo6UIBe(${U{=bp^8$<)uAIKjT_SpC`Pg^egyxr@Uj(YySOjUw&zu%}(6f?>Z zGXjwn+p$Eh_7i{yL59S%lb8(Q#XG^tggo!2~;21K##DUjK`CHHiR z)lwa<76C_x4B5&_pZ;){|ET}>@chT={~pCZDBk~Rwa>QinQNbh@BhI%Vb=Vg*Xw#t zhp$hXd-#UH6aQz$Y3b<=?wOv^kyhCnT|#SxU+wBXxrBqSWA>Fpy*n%JOMO4*`rx9n zyyC@rr+u4M9(exGFS1p(t zlKA}y+ok#CdL6=ltquxvOj0>)>3>~P?6l~$YP%i38@}KBD|RVDZjKXUPOSFJU83dh z@1>gPwZEHpsp`Vw3Z+xhj*CPtznl`iJ+9^aeOO^UUq}1IrdiwKc*WNg7=9>O>)feR zqq`?}|R@bH{pPrt+QhIi2vn^lQc8@6!zFx0uj{oCc-@5kgX_2EG&v~EzFq;4C zN&1e@m%QJ+d%Jn>=F=(J=?3YV#~04MQOYMRdm<*}^Kaf8Js&nc)&H|I^q_C>ui}%3 zldne?zS}OXl-Xi^|MEBI!;Ut44L|Z2CQg3xEh0c6<3e@E*$a!Ny`GuBzgsVP_5SN@ z8loT8nYIZEEoSB7xkc951!`(SzReSaWbZedoIi1T&fmSY9}-*Ft;$}t zDrsi~%c=)S2Uo4Ku(DZ{_o~5qo<2i=-*SGc8z7gGZF2T1s$nk1j zQO${@Lbqwl9g{c29Fr_-n#Ot0^x(??ubkU%C;IO&i05{Qnw#)E(&VjZshBq5@59AS z9UrDDtvOH|!KUEy-?qkOvB3Y;m$+mVq{$qujMrF29^||JN(_KL^zBJ=tvksW~I6Nc3Cl_U+3LvaT~dlWx54$LaqK+xHcU zb}q@(cDrn=7r*=H>Gd`G`ujf>E{l#f@%0Xywj{D~0#}L@Q{9&-{7Q%J9j;q@;=7%| ztJZ*pv(g^SZne-gzx^)J?auj+wJ}?(w%pa;WAi>hf;IH-xoed>Z*0$g+I4)&r@G<> zJv04ZN|XLGWoVQn%jR@2$A;|q?vbSQX@R=vuN%93x5(-3IQQGp$0DTtquH!=&Fi{j z*bbgzy}r*S^VFsk8_D9Qr=A}0c+oWN!J98Vp<9#6%pT{I9m_FG-^iieqs^@KU z&K197-Y9tIJo_(qMF;;)=jyf;e^G3k{(ArY6;FOIDJb6U==SF8&n1a}W2Ocjd?aa} z!_czz+}8OFP7h=^u3=B^?5l16`?t0uSu>d@YPG_RGps?cUhK*=T)Qy$6=amA|Iw4mjPp{-6M_xc>ebK&p-PAWL7_Ae=<3{=05))O}nozhN; zic00ZZuWDw^RLY){+_(X)$UUSQ{=>AM!nOUHtf2-tz(-kQ-85u1kZBG>+9nCC2lUT zU9r0BX3e>qFEzW5Hm!=<7<2CDv)Aj3A0I1yx95Y6Rq&j1ek)hCZPHjQ;A=2j|D@6B ztFO&}yqtahVZ*9yi`nNt$X(Joyv1~--+}7B{=P@m;$^3MH!ksPn>1@zp2uXKWS(W& z9+yOtn}X*}a_oG!cX77$B$L$AZ4R2PTkTl3&tS2X{&>M~W7KShwV_}4UQ0AS`I>c- z|0lK&fdwyG+%tCGjFHf)yZ^j--iZer0?P%D>E8RT==t8O3CgUzJY#{!vBi^au6erm z`@P3=x7WQ_Vgxnj7F#%9?d)k%-g&T$UtG3*`Bt{~I=;6jsC4bosdy?TV{7wht@*tt zx31Q%i`jYP6|wg4+tezf8AoE{*9~n2fG4byWSemOfCpL8bEfZ~FJ15>rbt13)F zw>}Y`|3~GX^|rEYkKgT5^b|c88CL3Hq!^%n{#kL$C5|SsMfo$OvkUb)1ZQ7uS{22_ zr+9EiLx|hT1?dtl#c~|7jdl}1pJQ7PdZ(2?r%KpbC1=g8lf~9cKHcG3Qjub%FmK1x zk6W(#E6zJx?BJH2@&3+-A8QR~?09ywlueP@#=GmY73*uAdp8&4b{gx+o13iZ&Fhfn zOy1!4u5()51-mb@i#FU8j1cjhrIb43seQ$V3FY@HtzQ|+tad%Rsp;)%)wp#(?%w|! zYjv4rVSMb-M@~VZq7|Jdg4b}&6Rn(8^!Zx%ho$lRA$_lP^$$X=VtV%8Uz26y7m=bQ z5cME+h5uSpi*(IXJ=5dKuf9*`^v?SKis|k02KKxBCoP-edh*;k)n%7u zyONH4dnadYZQY|DTrzFa5>+kl4YAGU51E#=y14Eyeyy{^pf)t<_^NXc*B-a9KJ#j7 zP{z~?GxXRdYbX~d-Du|5jqLp__EMhzPd{6$I%7jyR(zMe%(*$!&re{sIecpo_v`6# zUByhU@^k<8v|lXA=GZc~*rc>sAXnf%XMooP)mhEW-WB;PZ%@1VhbLRt)sAbytQm!s ziW}}d?mc|F%EPKk|JOOoDGe$YWn||W&7P}Nx(jRPT&C`((vx{`W)5`uD#Ay|mX>b#%#l)Gb`}Y2qvO3!O|09Xze%qds0< zo7?rVP$i!V&=AEs@K zD=7QZa53YQ#pOGDelgv?eOqU`cVA!M%(*rxmeDP9-+#ZiRD=25HW~jJKHE>Yt1dn{ zWsk;*Pfax@YQCFZ+*{6eaEh^6*MdVlH(j^yQZPC(L8wdTDC4znOSZV%Ua4HB_5Who zhY1=L^>tr9C>BO5?9-m#x^L~@Eyv|-o}X1dWFlWGG4XTW0W;lWQUMB6Wga+kw1-Ss zCM9m}%ak6UP-u~!JYid4YGUUi=zY6*N>6Wy;loJN7m6&2Dkykrbo?{x+Le`0&#B+McboS{eDaCQEvr_Ym@KlA zIbI<{LMA;uea>8&*dFk}h=$+1^!=Rw&U0z5XEFPKi~UZtu*{(v0pXKp%QPk|am@%< z%G}Mj(De51={ri+K6{ZJ|Lk6~@SZC@T}?+fIW3jc^0u_Kb2ojGOXgv7l?D(LA5S zcAr)((ct>DM#VGOgy&Vk^b9NA7g5cHVh?>E-1x5KbU%8D(9twT5q*}5-?C*l%$qfz zoAW$v&u^>ExbVX{Q^msYK|*tM%#QDIQ7`8#H!hRyNh*&12JlmhF-hw?5R zdzTh^7~S2F#g=&V;-kWIM;JW?_OHBAYhh!vBs=QT%Zv+azN8$wVECc=Lh;<3ul@Iq zr#8l_~do`U!!Z)d2zdag0HKrRPz-1 z{BzE-wHuFZ*uVYs3YpDOYhRRaTfHlBYtDzhg^T2Ux1IcKSh>)1(%cP`<&GwFKb`cn z=x9;dshckagH~S9^a$=+lwu=iEZ2MT^PHF0#46`aJ~}@{eaX&4!Yu7^8mpEatd!)a zby~O3M$aYtps-=Hf9`*KO9hvAr`lH?X1%|Z?ZD69cV0xWINubQVAg0{m%P`{ZL5{t zmZ`#X6{d7-E;HuPsTNF6;BwiOkfLCbKT+`EmD#smxIEtb_{9qW{|27Q_ZzM)5SA@F zqujEhevR`jC8r5IZ034fwk>8`kQ;StowDjJ%V=qz$K{?0yOV}!zz=Wo7DxV*XRu;rZ{tnTjZBCc#Ki7PiYvS=)k`lD0R5*mB! ze!7*^$Nqg^9zdEpyKD3I|M{r@=hXVTcjZfi>NkaRthYVUoISHZN#I$}(dY|?j2c~& zR8D8?;+wi`fhd0;-^tHC)8i^Q7r?vh>8~fT#WLK5D9q1N|=NUA)5Udpqd5 z=<2JJstUbI%g%I)WXxT#C8@f)f0K@;+hPVysos;_lXUbwFU!nalELXAS=Vypw*lYA zdF~1urKf*ge&*MFF`Xl9%N=SwQuSHtBdqr4+cQb5I$+_>e`8u)YNvRU$=L=2=l7L@ zhRhviRf=m~geWgvlqpt{+Z|;1!@}&_9o`*w7QZt-%M@y>nwZCw7C9;)C);Lrj;cz>@_jn3If@uU;nr{QTlFA-JTCi zJ|0c@~Ng?#0b*PIx+%m2EmxGZS$(5_3l#i0J_{=cXBujwW6gof;h z)7;|c8PfDs>749g3x`t-lQM7jt(}`2wwg8m=PmOcMPG&NKQPZv`2L`w%JBKy_5aj% zTbp0lZLJ|vIc<~a+@MfV_2cRsiZ}1yKQ7U3$fqd$Dezc{l*p5)oVMPTdzfX&n$oMB4 z891g}K7J`OH)Vy2tE%JQo(V7J?ND>MpZ%d&W;JQUg*}pW4hZfut!3I)xZ0l zv%s$nf{o85KNy{##>FAYv~PQz2a||V*m1>*yg$h;Ni$}Ck7bl>ovxKPEpugH(O#eB zOOAbeW^zxllc$A2O6EwlqN2c-(!)g?d*)lRiPp!peciV#&+uAM#@>fN#9KcYsW2az zxuwdZLtdALa#gwTt<9X9ZRRr=G*mhr&UD_9 zA$zT5E!(0Cg^#;s;tyM}88rV5Jm4zbZ77!iR!Uj-&xe_!(tHhyj1y8ak8R3i4p{Yi z#@x9@H8n1VH=jLyUpsS?&IPZD&nK<%F^ntNR`TY}n@!ud_kWpIwN;^Ww%go|9H~y* zHGBmlrk%FR6OK`VjAVE=cy0OqI&9JAg}oVbj$c^6YHi`(W7Z*)SenJN4RgJxEh+IT zEZX$sZTbEq$M-!?eP{Du#{QRjeNTMO!`bnFeYaeZdGofg%*@^E;I|ZQCCA`RDu+2G zpIz``7MjY^7;dO_^6|Oq^rrJQm(47)E$u8Hf63|Fs#_U1DOJ;pO?bA>c}?%u`921P z=c2Fk#-?XjJKx?iXRb_fO^ry@T+g;EoWI%Gmqa>-^=O=Kvf)qe&^hfK9ipzWaH0|8 z5d|?G-LS23)!ro$>x~yiy;GhuMQao1FTaMzg%cB3gjE|osH#4&URF4{>p{fo9rE&? zYii$`XMFefl#sc1J7VhZA3KsdIs~^G-xaW^PDr+mn- zj^B3DCh^vv3>lja?u&H4cO&<9q(DE#L9~-*!DAa9&@P%qiM^;ozKO zGx!#&9VNUt{ktT7Q`h^Q z&3~Kp`G4yA`ur^H>Q3A{$e20HKuXl&x#p)yftH7MC-lx<#;WCMX=&@aTrwzY+Ul-F z8Z&*4`E1{|qh{$5OZU*LXTnc2ELf?#I!)}T--1+z=Sw`@<}H2V>NijP$$pKqNM3liN3)@S%=H-i!VFgruaZdJK@+bw4y7hm3`@y1he^ur#=_hPMCDE!pBl7 z@#CGn)lR|JLrRZ6`Z443WmVpS9WCott_;_{wTriNuW-cclb?0g2>wpsjS1zoI=kcF zAMX#Z%k?1%XA+-7|Gc|**uU}VhwR8XcC9>K_}drRnHemOow4h+wry9Jd6WNfru>Xg z_qN}AWWLYjS?ld`iybvH<$o>o|9pG@U+bE`Th|wTy`>vcr1{9z_VLO?+^wb`AH7(x zD%$N@a2n^agD-0iu39xyKWxh4Njj%JKli*{E4!_H+s12~qSmsN?%3M4jLYWt&ze4w zg=-`GjxEV_o224gpnrNoz>bb{u{vVR|F*0Y(@9@0G0RUmUm6Bt-?;bR`?2PEG;zKBNx@`a?q`1!i2=h2Zehk*5sUJSFPO< zn{2g5ea&G(uSaK>zgm3C`HRCMU!Qe0@*97%WEY72`Jf+_@v{5uzB9`E1zNTW?7VkE z;3AWCja%%459+U7*0jrcE)6)uQmn7P;lvGDj`PmmhA#v{7QK8W8r$-P#kMhSeRWxy zKv>q&munvW_|X9>8ZO_Ie7~>ME6!=sp_DC0d&TD^o5&hRpZ)pv{x9EK%hK}8#jlq+ zdgSPq#!jBDdawLUn(-u;&!0}~Ph86R=WhHiNORr8?u*ys9C?RpuU)j_j{fErklsH% zXi_R`X>{|P4Ov-M*^<6)G5dciZN41*PF^mk?-;0&_dITo^VL$7)N@&e&mX>g`G6zL zT=uEQN$FI$}D-~T)7X0F9G+rK9`in3mJwe!E9oEG>)tv2T7<%L4_$1^KJ zI!@kt;>LD;_p)`)PO48QeBiq)RKKrGUap%z>z8|G9W!$xGxwkN!m4t6P1TL1pFHF) zW(Qt7U+$5x_Mo|JP#R;n>~@{1=|}EyXx!PyXLbGIUPTo@BZkH$0URn(>RaYM{PAN7 zzuk`RbHVFux1YXN(lu$)>*@M|K5j2;olej2T#{_wXvVf* zG&K&5_IIs2O@hI)9Cfo!E1mg9VYc3xmX;3$=c|Z*}he12w+yfjsLf zUbP(&ZeAe7!Fl@Wq{D}uH|cbT?mjB%KTFj^GU8udM)?=UkRvW%|41!0Y`dBz8qTp< zv0#4j?azg0K1Jj^eYth+_#TU=U&5ZmysUDY@ zGc=YI}9_y4zB{@HS><+Jv>ADd(L)pS;uzn|##Vv>N;x`MWM*E38WJ^3+X`@O2> z#q8hz-P|b_*V5em`Ft$X0@HIPGtSLjoz?Q>&Z;ZR7Dak_28!gofActZhNYSnBhl4-&HPH)}Zkt~Z*wVefWnt_e~w5)4g_J@cy9}jPHyj^;w z)HPJ!vZ~^g`2G*8J(lh$`YCn(er4m{yUd@~D4h1{N;;Eal4x_&ZMkG>;Dmm!NhZ#j zt;#{S9!1GHDfYlZgDYBh)~ znEkXMV`cUBlhc3J&Yh6JRnRD6K6~z_{noA;lGnboXviM(zZMnaWAULd*D&Z~$6WsR zhj%5-|KYgcab$L2oo||m;Sc_mXOydF)V4pkc+Ty?kNucmb9E$^|LwFqq3 zy!U8I$RTmq1h$6XBGa_XKB+qn>}0%kk-IG?-&m_(mnZK;y3;u_4eO+HxhducTt!(>+s7WfCnSl!K zjw|EMO}nqkXv$t+AD6Z@%1F;-vX0_px%*dj!bH0#3-^UIUD1r3HM!rd=UDQoA|FFN z%~OJ&vld_CSu4DS>-7w~JpLOqmfVck$=6$;DfoQCKIzS`@}*0E?{wHNr)GBR@4JZ( zs%DcKzlJ%j1>T%k$&Y`!!y~tO@B4T*pJCp|43=XTZ%%00p6j8~^Kng> z_9mO>KcD9do4G)?qSUA?kN1|I^I(aK(AC=?l_WhX3a`D8_0pJRqVd2wJ>wSNYuh09 z+c&nYduio;TVhRn^!dF9r0XBQ|M1~MZCSZ~;p1PTb$^ckm&vqx`uYF;{DQ}~O!My5 z@F|)s%l26O^+VClLsG}TrJOo=FlED$wY&S)Wgm{&7u9;vdD&W=+-iHe>QRoJdso6{DI2b)4u5q`&uNBgKNj&vH7q+;qRTHQb4)?`LKOR= zglQ9>OYXkC+vm9Oy~^LbIky+JC#iOIG0tkyIyB3XgP9}(ZR)H;gTbkZ0DId{`}bSu~skQTa&}Z_btb{ z?mxU{)p*uH&nZ+lIpj+}tFGY-hNHq2zs?KkxK4Q#dD+n3T6V^lYuiG6oBf2A1SR^% zwLQNcesZ?V?}z)=N^g_i;wLdxdDEH*=0YZ^d}RjveHu5{Ykf2P68P``=F*6Hs?Iku z9)7=n^hMYUvv=3I#d+!)&b2%_Cc(e#u%gGLrZpbSj~!NOl*R0p{??KF-1by{Po{vQ z$4i-OzcL=EtVmD4v;Y5u^|hawxgMN4TbsA1sQKfLlqeCA$xKsKZES4i68t;wyIs-S8*^fFjRJda@r29uWPT^ty|ePI)cn6^afA3vi z{QR8kwrypaU4p*1+xj-OZ+jPU%BteXa?dU5z8;r(yf=uhy)`Q|^zf;PF9eQ+@)x}n zeH=7#x#c2(o<+O%x_;C@XqU^&EGPX-TZ><#jXW&u!@N zc&xKrqJO5(c8ya;23(t_n4I_6EVDFdLRAFwm$(Nl@yAUrhR-ds)w)r#^ShAxudbWC zg(o)VJ)XDzp1I_gI^~>Af(}Q6d5hDy?%;Z{;oQZL38uWIS9iZz>a%^@%qLv=S~b!9#dT{% zJr}iY4>dn%ze7>`$VCL-YdBJ^dC9&O`+f1%8^jX`Oc2Q-gbVuN4xrTJXfymWr}N_Fz;iVd)^(bt3PnY+4-{QODc%1gX9 zT$>x*!+xWO-$_UC+aY09&n<@{+IyS!uFIaGdw#}TnI#xdytM}gU!3*3_1*`HMI|9RGIn{E2^-4him z4$b?e+*n&2#>ca|x7Ku5=E^lmm$t>|R(^OOXMH>R<6n;Kel5>}d&z6%Pc-JR`s`n*=r{Uu;cz*D4<082|qPWEg+3MdUQTMH)$^%2OpozM6&Y zY^wYA!tmIn=am_*-lFSf2e~;VNQJF$QS&Z#d)o1{=w!{dgncuLAHQnR(TzAW{f*Cd ziyOBO?=Mm3c(83{=TT- zXT!Q|=81aSjyu+Y zchq_MtSJ#W9%U8$c#Z3-1AQ-c@hOJ9={sV2X`cE+)_bdakDTP`>n^=qU^V-))ak#~ z<(7NOs!}^d0#Sl`t0m$ zkB{fiZT$dB3jbyL7|b+^W{bbBm?;%?+Q4G{SL34}GY+xmN=Lo3I#?MIYI-`=^>RsK zUxbL`)qI`Us}t2(ci-ME64|ynaq1ck_l&ikB~p4Rd_K1?UU|DgN_A_W?oXD5$wiNt z?<{>A6_t81>gWNHdDFc@9{h9`VUJp4JY(BZ(7v5c5erWx<^$^f!ArtGX9O8>DMhS! zYf#9$Vb!!5+m^kH3Yw~%zE6Ei>x%_TxNfnj&X{uZ!pw}@)0WM;Y{I+xvT(^H<)wT&O^X!ddw>4FS-oBD zi@u*Yac0#itx(UbmAf-vGq)wMtx1=VFfcGUyx}MRANIVT@^=zrKJpvz zNbfk1@L<{UYPVU8rQT~Nc`ZGaoFemQ!}mCKy?tA^y+5IK)?xdxO=s1@BBQ2GnfXxe zom_V9>)-djSGK=x^Q~{pmA+NitbLR1*jA0j-1?5<*BXv(%?q6JT;*kr<#k8LLXno= zcAHPFIPaPFMALOvl6B2?-MIYuuV>fW{>go**Q#)LmH<=x;e9e)MRupohFS%1C+cfo zi}VyynG$Yz;40V3fK$^-j+ei`_r3aKHv56U4h!S+PBrAUF%eC$rcMBY^ zmr7VObzDpPcIMs`y*SatXRKRm_6si-FI>Ulp31Vd#J;5WP}>xxYf)+TpI=?ouKPE6 zev@&Ip4{h`-|M>fW#9a&dw$Rt~IH@Wud{lB&H4sHGRRc_g`ZrX=*-Y_J8spQM)x$}T)um1ww&dhn<<%)~DpL&bF zuQliCxqL)sPfpg#TbH-$nPo@Z9D-#o-n%`cW=wp)|YXADx`Pd%PA4 zukcH}sqVNuYVpfi3k4*-)sw%q2+UA>D14?aseaGHZ(56cm%g=b``5HAd!uiAcJ!_~ z=lwS?^4t2_U$AK3$a^d5Lg$(-5F8=${sHqxtC^;Tarj zo^9L}^15#4Qr((J)k6!nWmo=u#9F>x{oyPB#$_*mytzI9WAy&7v338;>-*Qe-MQO# z!`-}}i|v0nJMMaR=4FA(xw@p1oyKbiW99*RsMb z#|*y+B}^((Y5laihly!YPMHinoVd&f9+ax0rLv9Cg3PCoE2V{&sQm{%YrY;uCipMO?r1&9+uQ z>~Ny-g>vR=r6sdj;hNH-)1HD{6>3X+PF0mAL?-clPjKPB%C~PB zdqnl~*DFrWV0+ITzCLcD;IG6m19t!0+rHcFHuPM#M{ifl(|{{ni)!YHN-pM!dcJwx z!V5y;)4k(Zb)Oc`Qg|A1^;K+%(f57x?^g&0@c#@F&|_`5_@natN&#NR9%Bn_`@@0W zVy!j3M&}}XHH!8=Ts-~!oDvo<72_;Thb6J`&wfUIesj}3#;(q1|ILEp+S6aZnqI%2 zKa;O|-;b-}e;zGO-#vL}{o`4#r!ScBw%?X^;@IM)G$&Yy-RZVT&5wu15A@}@8rr{Z zxaZ9nQ1k3-PyBtccL$wc@oxQ7f6dD7?;GQPkN-b;|M~Cx`u^FovxR2b|5$AQ^71a65@A^#@v>;z&7_wPnwFh;%zLV%&%x4L;nC(Z8Edl(-Ga^r&HSj=X{@}Y z$6hXDmeYyusVd7iYEIs)Jv;N*@4!in$w{-CIpn4uvgp3dmdaaudBNPpnY&Y;2s$4* z?!eXf!1nre_8d)yImKUck6$R~Ioy^w;da^Q^HzdUOI;34y3qP7|3u{UyaTTiV*KR0 zlI&0SPH)loY08v4skq2g;<16-MoG3rMT@hpyB}Xvwv1S=;M&}yry^?TFN>nzD0HTeodYS^BJ@)JTHlP??9uVb&$eRu7} zeO0rF`J3Opo_{s!@{YFJo;{VHg_3!_g46y@OuRjz%fWw5PU9M0tGUlVN;C(h3C3le z6=L2aQ})&P?c=O}`>X!$PxSfbtK574i-kksJEIlFH4pYacNBY*AE(%{HSDy9`^rm# zjjo3$bUQz)^O@M=t#PI$i*>DMZ&Y^8jDl-ZKgK;edsVwHzV6_8`~R%%haHa@X&T$y z`p~}rd&}Q1ZRhR(%Pft!V`0f1oUmE4;9Q}V9LK@Uck?Q@++I+`^zVB+(}P6YHQzri z)Mv8TxOnN&DU&0vcW5XJZfe@4d$QKDQ+1__=tzhl9YsXV>cB$h68(evJ} zWqiKzaYYPQOrh(QD@S^qV;D5o^ZjqR@FD15R8&&!yzi0BKh5tkp12t?PjlGJKJ}f@2(dysmp*HnQkyP_Vv0mL`Z{KUG{dVFR zoL85xJ)e~owD9t?&?lKfvlh77{5zHuqil9Sj*;3F2UXJ$$;eYVhlk({jCyHR3s z!Kp=}8OvYJmPCEzP%mX14ZRf$Lu*u5Y>-_h?t!zWW!xiT3JjPIxVIYMaFM z$=wgu-SY@ne_8Z6o-cH*>(V$k*5j8aZVwMXQkhm=sTj)=`)1`=wo+t< zXo%@~=a`?9vwAbCzb#Dy;q| zTh*2wkzsoLM)LT~zh6Za)#6@1pRsIVCi|^*+DvD74;%dB+AjxN3vi)~d7bQy9Qnn$ z(TgTWOTK+E$!mp(n`YZK!B;VU5o;Ar)Y!3~ud6?P^{S|)^XsUZu7*gijdK=>EHr#j zdrX1V#rDA(LyPQFikhvHuX#OMHucbq7Nhis4`*gi30pj4)v1`RH~;T4|GR3_|7Eul zPjZNz3OlvP{i3!*_}`i(BJYg3O*9st_$70Aj?oMyo|yXlq=zEX%dfF5Dv4*AmFi(7 z!oAi>^KhE-v>TUSwq(nk-}hCwE%Cv#XS-Z--~YTSvg7XkkDvATJ*txbssF#Rq^)nc zvY2bSbW&H+)2-9yq?(92Ke%|5b@%<>%>S1E|E$OjF77v#9ljv5%TGhuYe%7>YSZ_Y zDKnF&%w|0C=cdF3C!u2B!zZh!OtoC1ZMfP}HN;QFUU>4+uyY5pHg{_Z3Tq^%?2EBE z!POlUwkAVSu=9x!fAsulPjg)*bwSgmO3#9-Or5WWzC9axbN<#3@4ByBDt|Lu&t%oG zoS|^aods*Rt@hn=M}_mplp~skY+r01&2i4okUIVDqiX#h`9HP)PR{?!X^2mC%__D@g-P+9G%O#e0 z3+%O!U$muhFaMdz>G3;QO8xf8vTYF+-G4G+md|CiZPEu1Et_LG&+p7V? zo^(kg`Q_ZFZ_o11UUqni&x~hBr>&Tv=i@X-bDh}K<;wp`9$jSbzsYNB$Qp84z$xWe z@hn?OO*EOPkeVSIn{1Jbu)E{aVE(A#N3wissKA^?4X3pWfk+-CP({ zvTVx5V+*$gXl=dLB2#emoOJLrlk+CM2^*a`V)oXap1nHzUd-O7Z*OO>yT2!C*U1R> z{eRu}AI{wM^z;0`JVlGLqpYqkm|WnzMzps-qtR{Fx~G@@?Op$CzgY%p`2Y33R(ARS z<2jGxGuGB`ee#YM<%ormmU@X-lAxF5TApQv75Zh4YoC^-H%ws3S{zs*zv0-l z+4VEmYh`X;EV?c;^^cTs%1K4@TZs+JG%f|-EKuf5(g<6owB)qTtp?SuvfK~X#1^yg zIQL~3o!VgVc&V*cSJ}pxqnBJ)u&2D8bi&tY@x^08$qvD{E^8VtWiS*Bac3a4;o1~>u|)T88bd@<=krRnBMtM6qgNtw+8ht(?M|JizU+`Q$30^| z^=FTDf7d!?9zVN!x`uM#nb`e_H}Y=gmFJj6-&%LrRQK(L$2r}1-z{07{Xb&v%;Un_ zuU~&t*1x27y>8u{f@2eERnFF(OgLd_$nMV(7Z}Kw30e`OXrZgrc_ai`1g@Jp z|EyNn7Pqc1lOjC&-h8k2EB_5`C2qC*^W*pb&;P&n|Ld2xc>Qm-Y3~^+=PwI29x|J4 z&&W0WrE|~dn82S+`#U)_=PReDEH@!VVv~b74+V11 zQGIT@V(GEDMgH3xPOVURo47XXP~t~_?F+|}*4)vkg2;@6%3Q_d5DN&-dd6 zap}kpa=k|c|G$|3xA<6Ligiv)l7!cUNv7VX7G2s^QhU05yPeOf{d21rPR8udl$ujo zk{hm+Y^=#rqY=|!@OZh?S?!4X5_>e>NV{Jbo##-P+@g_t|8n7^jqYb!ER4^4bxb&x z;4OXMvfFUl*@UISQ!WQhxKc3l@I#Ld;pKlD|GpJ{HFa60%7Yb|*0c6Ke>5@WRDPLt zz@aGxxreVf%=jKLxnq@x^~;z9tKF;^0!agrikUxuee%&|SEsjOfd(v&@ zZ8&%FJF|p({Av!{r@0=k7U5TQMSXL^80O}SF)b5)fy1MU916{P0SARCY_Pzb1==n8=&VDt$R~@D8Cz;E0 zuR3RO#_Yb=tF`NXO`iYZ&vW}a4RGtQU#j8n{}1>7Z{IKCXMXybmTr~fi(@lRxh*-x zx^&3{%i|TRDqp1rCyQ1`9SO_6|9xi2vUdv;ldYC-yDHuNeV(Pu1*z*>imIK=E`CkZ z&b_fmggNwj0RJtioF!Ye`={@Bi%9;eJ>7Tvzqq;j$CZqNkH*iFE*Im>YR*f^)30Qf zP5HR~{5|1d5vzrU8M@ooM_4PJ&MrE)#C`Rn2#*SRi?)e#CiSRhJqXl{$&k8LQO6r> zY4TS^hIwYC`X?QZq}Z-zt{|gh8}4!x*UwUaR;g2B&Ne=O<`SGP`{=T}# zi=7g}mrWLlwkW*mn9?QJ(2}il&MIKT{@sbQ{B8EtocX@*cW%&^J9oFW+R9tX`QN#F zx5?;@ob9srDvUvEANPm1FJS7~#4Y#pb@Jce6V_CV?fd$EdUKd(z|o)IjXq>=VSTLRt~NjI839Wff-IR`t%Lvj^g6GzWS`1fP`L5&WPiJ~ z-FFvFNvgLfu$X7@=KG&V-TFUY#@F@vf0+OG`OYQTWk)KHSrsN;IX6AXuj{42jytxG zF24Vt`|siWzxw>F;3i_WX>E4W$2-r9PJjD&CUClv!nCv3lcr8>*|RP3$IJU$6uZK! z^$Zs{b|h=+8DH2XD4EP@w|2@YuC=}ozgQBNG0FMDa+X&^x=p=7whHX8}c5R zX*zdB*KSpqGnYj)GCNbcxmb7hzR6+59B1r|&VKq~SJC(Q#J^{4w`ZGg$vyt{b=%GJ zdn$hQ^xOUF*k@?-`vvoqupfmImJ;Ud2w@aMU0`G%5tv_ZS7ATIWYZDhr zYWxwgc>4Uu%Q7=(O|x`~+h29|eEq-ackae*-tTSVe7ybsua@oR@gM!`zBo^5Q=i_? z=;AHHp6jE4nCgZxO&ln>uDS1j|weQp1tp2 zWOwn|S8j{n-Hj?bx!}6D+RsWm{kbf)^J?3-Xw2Vib$rdaI=7=exly~;X|MHbHf(BI zn`FDH?J=Dn5?)aNsK0yF>eiLYb;Sp=i%AapD8u-S?9@WzsoA^aeg`Gb9eA^O+FA2Z6tK-scD~Kk&WEP)ISF2 zjepO!-M?q|)34p}Mm*MS|CpZZh#x+%_%wG76XkSF9KBdB4W= z?T5Qei7!izdaS$RQoFA)xTEFtkDRNXE6z=mQVN-WyH@1G&&p<*ds;V+N(S)PC+fdQ z4JljSyI_Bx)il0|d-B)E?S0a2|0g(Zzr;sQGx5H=Wv9#SZ+yC0Zuj`nN!9q8pDhp4 z6-AeMJeJv*(ei7dbGCBRX(PW|@$tofpM5>d0qz3qe0FlagW#ewOL+sIeVoF4J!{sn zE-x$AXO&JXnbJHxZ!LSeE$DmD&ZW-wU%ajDk9F{0x^}jKe_|zH&tsR4iOWClStO`+ zK;)O?k_mxo;uUd@KgIs<56W72@9Mh4vn;}+@9laNXxRPMi|?sJ*Mtdqjh8lkd@a>I z{dA9oW>MdBN1d%N9B+L2#l!#Wa{V9mnAliuJM;8EHr@4mTi*Q;se7xt$!|gMBqfi- zuYO-hO`axJb1w9Vg!hghwYHY;LLcWir)Ct!2ef)7zc#GkjZ@*Ko zRol$tid>&|%6!qIu%y+mclAx#b~?uLn8HGne@8yP6Ps_l{PC7ElcqN*cQ-IAb57EFy3|^Ef~RXwI@hzkb-%6O zN7nk^v;FhFly}#M1ods;$X>b!Ww<#{?oPw)Nw9kx;X{{H3GlebOUe*5A!r580{eoTt5`>Fc-Z}h)& z_kZ*M{FXl7P_9pP-_1*Ahi*&syU!8ce(dX2>AFwP?Vo)OkB3gyoL@TEHMQ|)#%qHx z2W!QSr#YYI&Fd*`qqLOqWB)57gC9xIJ%vcWvxM+!zOXa`N@C93iHZIuqM5L?YyiR=i$zuI)TTh=}zGv^g$-Q^XX1L`o zSeB{4Hc5PSTwLXu`??HU99aq#4SqZHd~Vvaw)L0+k45_Fnmq>GlX^6=0yo&t@%UXU z+264@Fk3fv(x-mSj|X|5^YzHAQeOTy@!>P;^o*$RIZRd+N{C#Qk2fHQ!&)DK-9ScOd*_wbHGqiX|mt zdsj^=J@_j7-r=hC7EE7%Ui;H%^{>k?X-n(^U;p`b4>#x6AA9;#_1sRQd%GS#Jw5%; zPyhNu@pb>^yq-Pt|08*i?avFgtNRGg&F1>=yor0)y2-UJ((__$9=$9({{M&i{whdI zF8;Jc`^LyaNw?PB`6aV``*xZB8zZ`@^JUfO?z)}F_oG2Pi^+%ds#V8ygH(G-zLjt ztu11IcPIo-pHq4z^8a$*jTuvK>aVuA7PB&Y=F5^p5w6$o*3T)Fv7GC-CHJ)a|GE25 z&t9#)@7F8swnT+`1*fAs1^zrqOew3cdf_9dK^WMtUvSBxx-aQGxgBfv!-?| zjz6S=Z++)m?8Vo}^(A_*L!Qd6a0Oq@)~5oua<|XW>R4@leU4|&(aZ^pQ+5YO|ENw9 zx?geGB&dV2_V!~R=j)o=x@Q!p&GI|*IOfQNRU)m857JK*+>pi&9ZY+yO#IA{LTCLMdim&UF%*;92dTo z_inlTwDv@e;Kf=TvRI`^o4XfY3)ZZ)J&!P9lx;Y%1 zYTWiG`b;Q};+VTEBk`JS=h7L0I)zufw3QzANT;dpo16Y?U96Df?sba``&O^kj@wst z_OW@!fpJw;-$frbZ`(GFP11vv(`D8eE>yOBN(+s2P_<|mNdp2!b=8w1c zf6BT{`@J8U<=21xd;eeTx8K%v-+uakR1}F0J3X1-E@58UmTPnT)W4N)S6#T4p)4rL zn1@CFh~71m)Ojlc+>F~BjAku+Jd}mR9sq=tzx%3Mbd3 zYvsE)JbB%wbzydg{{EJGVM?`I9XzCNJ0E1xU;BB6rzS^|ncJTE7iL}hCboLA)|Fiv ze~W)5daF&-bL5>HxMN#tbz!67H2eSE^NoHt6!QA28_0y_gnEfDYtUj1X_}GTsUp_i zc=ZwcdY5F@*039fy~_8vlV#VQyyg9IiAd)e6ZZg5ivr8bTlOx9)Bdf%meeGX&Uhik z!cVwTCNMIB;acRzQ<<7xPUm85c8T~D`}{D_k7XBBJ@q4XUQ2AiWwEsvGjb){+;hx7 zS)Hp(d%-Sw(}Z_pgbM%T&cha6Uv*StZgY67$i12ObU~lvnw8fi+kE>C-MThqJ}KDo z^zH5KOIL{6x?JD(C6-&W&_eFQsgEx{s{S>&GBaS~sgn=qi7?%}xM=ANul8dirys1} z{rCSaLx;T+SI@Z~*IX*O@yz$^8X}cuEOl5R(|q&v>--)?k?(y6b!vK| zYOXw&a7uV##?;ESkR$%A*PH7c>@L|!JvnC5NgR7>tIuBj%4@!Td(8elOsscXA6`7# zXaBFdUObt1{k=V6v2I;+{M0>f#gy9zDXE<|;Q5jH`;JeV zC+@Pxz0>n*_Jdxf=V?1#GasLJo7%ZKKJVFSo_i4`VlQ}){(hg{|NT+(_GJfu3)}zu zZ2$b~Yx6mN>U#3_ZrX>-HaklnH96}Oms55+w_lXs;bp4Hg_~@-Cd)yi!bc)^=9;hF zA=*>?<(%%_t{Gl3`Dc#k+|Qq(W_d*H(|i{_>BZ*-FE~2rs?6l~-<*DCvw_GaCf+zt z$MoKVX1SVgP9?V$A6K8GDu0N53sbV`xf?+|9F`ZX+|_G5i$uEbTg;uYJhOAb+-04G zGT~87FLy*F-{gs2bM?oIPRD@FwfA-J_EyfDv0V80x=*M z=()_jeU*@^V7|Aeulbjn-`4k^7F3-2`qgxK^M}WOOCFU-%{(UDzB{^aIdlH~xWek{ z!;ib&UEV)!n;UuSveQNF6ZdC`3(5vOP}VN!zjM-aiR+Fnd=7z8m$%8Td&_Y;C;rwc zO;@K6r{Au*cWBlz(e9+UycL$}e{7st)(RWWT+jJ>iV@H3FtdG&;@0i_{^9W3gZ%$w+Y(Qoulr_vZ(r?c@%VpTEH+goj<>h*tUGu#z@@Nl z4)eX`hd%W`dih+2d-f)!G=s>C65gk}1k$F&1qx|C=3X6ebI!|pO@XAiOP`iZUDMU= z825TxHj9j~H%rl0b0P5$XH3p-;0rctQV`2++p;WI`R+UcWzCkS$L!er=RNt@Dyecu_wQ$wamN_$oz6}>ZltG_ye8$sc3*Za!!MlzwwCJ4ULJW_ z64m8vuYT{|yPbbN95H@9gS*LmeM4~M)q-bR878d1`{(}O_xn#py=KT>7@YrjD|6}= zH&xvO^E6^7G@a3y%NOis-MQ6bYn17JKJ_kEk)`Kf#~tFHNS z*p4rT3%&dtJ6^8Ij5sEz<6^lwrm{XM^S`^tgwVt@*{)olDxx&kWEXtBw$jCXLXpyx zm>(j_c3ia^+B7@o?~^l|c151cyZRmw1>@4(*Y5nbI$ z=Y19L3A5_W&&-~ATsSKG);8VutDgwTd~*k-^oIoxPRIY7^!6!Rwu}~gU%T>U3(v;P zGoLo6&9RB=5M<6Vlin8F{g-!N9VAxkTTR;={0048vJcBJUy~@?&F$n<^Yv=@lNUGN zwK0A1 z@x;F$9d4I?soj63b#;2JrApFX({nwKGc`Hp2w&Y*?Dy=6roL2zKvE&ENBP4Nsp-+d zx+YuJC3iha=8xlAsKDAEb@xG$-w%Pxe}7mHFMD2n|F@iGYF|6E`F8U=_wE%IZ+?FD zwf3Y_ChHPkRJEOTxPS8d)or@5+6!jgn)UVb9)lkzb(GevaabO~wPMePC&@1(jwnsI z?6&8*#O{QIV7~6AJM1r?SUeBdrE+O%(lH6|b)cE^qimDb6dlC}p_?PQ&A{P~=tU6$|LNKxkZ zY0Q7N?qc*#y8p92{MQmkzAM}APCMs*@ye6Wy>}&;Z!NfZI&pu=ge=E}Uv@4CFl{xe z&#g&Zt2*Vo!SgeB@5){`2Zcs~mD~x9HQ7I3O!lw*c9C6W?#w0&+otc{g2v|=ubV6~ z-@x`*r`Pn%apCLc<~_#`J2QURAb0I|%1tyLel zFII_hyL@F9PtT2qPLo#LwPIUw{_c%W-$UFaouj$dODzjoJALJzXNoRG>vR}i3Y=IQ zJoV9nqh_+X_r0IF^v0X~IDI)XMx^%u&xpj)JFFj^jX#}R9IA^J>@ZZgy;k_7x;<2aO z;%|RF#6F?$^rW)LuE`Nx_PIx-x+Wg+URtW?d+Pg^4BIa|cOSGiIka`zL8<2KS(A1e z6xY_CeSLlX#bcj-oNUiAV~)Lk@w=?EeZk)S%CeJ1*8858P_papTa+nvQRJzMeMj5l zUnNJw_2(5^L1xne026TOFtJhE3&NbI&5UWexY+yg4T$H}2h$u=(aS&F`OPh;~XRr^p;Xw0wGe z?)6386$WgAzGve?{xhjq$)CxN-&_1H?)HAUG)0zUo_Q9#@3L9Q_nnJMob&vV28ZB# zcOijVjYeH2?M=sYBAM_1|M&f=q0@s3n@#uM@7%lh>8n?|@&7(~&sz5I(W9n)uPaJE zcC33XW?JgSxt3=^*mi5yn-e-u+x+BNHPK=5jtA4uH|cL#WI9dcvXWAWS7P}3&GxRG zK3ehNM#`(=|JqEtSz@cno^;}pYG-2Q-#>5OZ=G@5Z3o}BjS}U4sUecvY?n?r+45j! z`uUe8#nt5p&I{ju+x9ju+HZYP_4T%W_cz_;`Wwj7DE#@&%x9ef>cy=#_l0G=gv*nCe1Bb=){qsF1urf&~l4OA~ioQwnu!`Im|B)Sy6Xg%3pow z(MeqF2Ojl*-g)(%jOTp*hOFJE+f=8OGEUb?vHB>rJnQ>onS-;7wSMKh207*wv^s^K zteT`J-sxo+x3}^2_7dmwWxJO!SEckg|C^t1S0T)c4bqs9F8ho(r+4C-3< zxY0MTj^}Xd3$%2qe+wy0XH9ojYhd?=gJwX#4t$+pA8dFDS|0^;BWrvYE4A z-+r{;{7dcWw9N-C+rQ7d{IMlh#`kt|?CA|RCmQ=)J~I2ZZN_1lMHvjQ9640~ncojz z_xY<#!~K%q``HB7aj&jAVAjhlKO_D8=lSPeyc4_2W5Ky}O4Cx6zgG|c%~swPsu;l8 z_u^~g`swc@yCxKWR6i7@xhD3qj_jJuSudh0@9tif_|DAxpYw-#4^-n-S{$~&y_sVs z<5zxWat4dpZrQb4|1D$&mCV&KLIUY8X0^=_E;p}^%D$ObCh^)rrcZ)*W%(J$sMDvc zj$ORGsC9O}25ZBa1ED8X`Cp#7JN;($61Ig)7fBi%>o{fW#eFMvrn&hs!yNM?Jj)9o zmCTYjKJ)c!>6vf&p6~pb_ub=wnxomN%4q_NGCwIvoW5R?+g~hu&Wz{qh9A3LE6O@) zXhiL_yf!;)t4!W@>z~#a#Z^A-vFX#l#kgAcT4vHo{}Yn85}l(py6V0aF&yhC>=RJ> zZOzHMN_v~|ql5LIo@h>=-oJDA-q=gb&EJzUFVA{xv8eZ$>AE}5v{Kx-3??zn-RP&& zZ1_X<(av+dxw8CIZvHXx=Po!Y(Y#G8w87hL_vYNST<1@%P!QotoZ+;w?$)H60lPiK za%I*vp8d9{N4=><=BUS)&XqDUZkoTg2`-vz7IC+$qr`R7ZHwdYE{1*KzI^6k$&=OV z_bDxHDehbMeui^Qro$6cW8dyPtFqm9g}#)0dzStsif{cY3%#k=ep>EOT<^wcdj8?v z`t|kwmwX?{m>;ZMv0)Qe*4~VitU23?^9q;#v0zyL?nZ3N8oixT8EXnJY@4w~Q9RaL zO<#F^vDEV{o9SPJD%RY;T+ZmU)jMo=D8sp^UE5;2c2$0}NPfwEw)op3!Iv@3hJ7DR z5_?hvxA?k$YBV_4J>%m-hKdOO*S2d_tt_Y$33e$b#1(Tjwykq4Gsr}*=oT#nPw04Ss zW4PCg2{URPqR(f}+h}(A8E>rlhMO@7Yc(D`uT=YSph9A1zp;iRTlw06C%4w6n!lMg z^PffEBu@KtEgui8=+7wi+f;n+qSf&WUegzdu@np5?X@$I^*?I0^u_k0nh&Jf!t$0X zRxA?t-=&aK`*E(e=i$vl8y0Up_BA?(@zDvl==>8?*UtZF^(aVeRigc!+f&5%?biLc z&ebOJe@~dy?HNujn`QXQk4UH<+x~j`?HaF60q2ho-31xVbg#`&71XQ9eEeLda9iw( z&d}I(r{`b28f*CbX~Sp3#YsB18jbgvwQ|P3nRhI*XX?3$zHT#k3?DnI{B-b9x8&$e z5t2~u`6Hn`x&KjAhK%@KRdI1~?|F_rfmYESzYkAMI=)<^lEd(VY2Qk@X_^UJB7{sk zCooyD7fs6R;dfe_l6zI#_3*9i_?1jott$N(bR^=#9G$0LT|Z%seQ(F7u(#Fr-3!)b zO8eYC_4_s3tapNe`*r%H&ziVCdc*m-$BXl|lup|W&CZ!^$2=#cMw^(eyr8)C+6x{# z_n%dcg;K|zc&BNDYrcg(6i_jU zoIF+c(JkoOh;2n)?GFxf3&q65TrlCieto-4pRm7u&9VL8kJtCd|M^pVFK%yQefjaz z)8jw=d>;Sd%gf+d$1aKctT0O#t?4kjzJ1pnyI{2^4t_<(eJj~Mo>-gkNidn&PAy8r zQoC>YM1lJc-ppI}Qj)8w;>ETdbN}oOhH@UyQjry`@j?Bz0??Z*S-i?C9ET70u&a z9eszh?BTxSM#lYyLP2W33ih8}ch)O$eP^AL2zSa>_B5kY;SCpE&MkT}-G^nXh(M%f zz$QcfT=mcI7xgcAArf=@(uJm=Mep=@KSd~~Tz}|$Dj~X7?ETuD%#}9wn=+V1xHcDX zoZH2)Go;(a(5=%@Y(roQ-#ioU`3~8dEJ2!lSsRmYx5b#SA1(`S2r07QdXS;E^o+&1 zL#-FsTt67{)+$Ly^-`>)`@ z3+r2953H}9>OB|9d2VL2{-ITyeSI}Ib6l8{y}`FxI^DtWoSd!Sk12u29^Ptvpxi!N z+V8SUv4vRv_nUk>Zf?!U<@({u_v&Qzv75=qIMdy8JXMWZKi-;ld&-%EtQM1l9{u_y z6+7khRHKYFsS<3O93penJl9OVw!B0l%Q2w7wATOJ%(AB*D<0Vjda?z5kPzlLIIo){ zH)Gc4GkaetO-tD>GcAc>>PD|F4(DT`zf-399f~Y=bTnLU?5MXo^hHn9C!tqud*(@B ze;zlN<$c@fIY$fTFJlW)?nAfZ8cu0DFU7^ zeN4YNI<;TXsG72@q-58zz`5#jjZ7=oWCl62-7-2qFW5~xEbB+;3cubPYY*)gK{J6Ql^3#)z3eo=TbszHoH;A8~|M}I?;<|r7 z&sYBY6TYWTH*DLw{G)1DzMJI6oAo+5!$j+v)4K z--#t&d1L$7q_F(PA7!sC3S$*Wukww<0avSFM`5TR}j5=he_BZ*Q6JKUWYhuMirr zz2jBLu~%8aTPArX%({9^Yum1nBh#nW2XJ@2%D3-6`emjrHSv7Mzce;Y;S|^vQx6`^*RFxN%PASe@klcHCC)?VmX)=4_pPhPI*Y|zt zjMJQp-#Tq!4t+Br>=;vSyQ$cGrJW89R~E4ZthvgV?fNI`OZoZ@Kiihpoqd1r^WE?a ze@%-lM=Re85#@F9p59qY1pZG-F~8o@t5-)Kq2l_kHH`6H?*sU6&|vukZ1X=}{|>`rC=N zynb2m;M==zb2eQw+2VWn=~Ll-f8V~}w14-*@BcrT>c{PS@HAY%;^QC7{Cj(n>TeWF z+1`FDcGqGT(+S-zbeCCt% zB)=mOr4oE=TW>Fz!Xh1*)1c{kQ2O{L&gI4~p3<$R-{QI!-C)&?N>4L9yLigM8KGM~ z6>5501EW@<#+%NjN{`r&Lat&YC+OL=UzkXZDOzSJhH$AQHGn~{_ zkH%U3#>8x;|)A+4{Ks&z{Z> zXOZ7A_xp{@9*>Wti3O`2DN2~oDfmZb=CheIHgOydQcByg_ja+xyn=O!62F-KzRWyZ z+05e_D(CbdZBoldtJC?nr!CvMW7|>FpV@Z*FI#M~mvM>Rch~Di?^dH(FRX4=z5X^& zg8BGk&ZSqKc1#XXj8@82m8;l&S5LV~OKr~copU;89g8yC%fWH|7&%YO)let}Vb&8?enNATV zMc2x{V-u1hZe73C!M7lDx3Su;J>|t5Esw$$>^b*hQB(M@d7>MR{MV_g`Jwjb{jcl) z_cJBTmFn2_-&E|otK@Qq9}faOW5lc<999?SncZ0EWue}~5WH`?MAM$Wy8{ zN#y_Dnopm!hwJMekmA3!?QN0pHLojw9-9=}%vEVQS{ku>XT_J6)5qmM+$`UBd|?S+ z+}^r_-QxN`|9n3G^Qd@y(bs3*%O1S6`uN4%Zx_?H+!yA}2b`RedQ_eF$e&Wv;Q9Uc z;ekvUZjWV&H*#+9Fdx34-|En@@W!$uMceIVJPa?E^Tvh;?2c8x$&l(3Fqf%(`}Xf< z8#hnbuuxw?&i;IhiTAag^Jk_Xjn5MKIFZiA~t}$&MR2t@|R~B^OM%wr5T8?bx+yrrZpfrfdRP3-*bJ?)i1>^zX@* zGJRj1-EW(zu8NNOm#C_;_D-WuRIQ|=>3?4>M({GQ^`E^8+Uir*iZMp*oh!AtaNSYU zw~w};w=A5c_DE5WeYr~0+Z(ZVk3fqN?$({(|M7SIfz#91SN!{930jA;|IZ`ueO3Qt zQVyjs*)1StvEsS%i*?MO%|;`?zcV(KYn8=<9~WjjRafU*|x;ZtSl17 ze#*t33f6P|dLEy+d-v{M=6$cNwk`du|ED2y=2_-$wgZ-xJZp7wvsK%6T>8`{_P}6n z#qV!vg3{NL7U#xzu4$G?JN7v9=kCiYXPAAb@7j}ZzVDa$c04F& zhfv?+BgOeoU9xw-N|BiPjMKhaExxIwXUo6diOzSo%KBcve|p#Vr5P7*>1=-+Bl1l0 z-PU(YTVvP8Mmd3;lS zsStC&M{nbmWhKTrw=atBzG=c4YqY$l|Dnz7Wo0Ih_A>8Y^>2UYbpHD?0$=oZ{j4u$ zJaB31hlO0SXFpXgzjJJ^G0$w-b5hSjbmupf`Wa40K9Z#yX1DZyVP?Vlt@ZE9=gjxf z+8^;%CF@{-@}8yI>f8Lg8Jbk&m6O(J&fkCQ;>v61TY|pbOTM<~RU!*$P~v_M-+}N0 z_E)_AE;l^ZDjy%cvXrmdN>oV$ufn~ruSl(tuOR*Evl%Dp_ zAFr6mdZq5^=RTo1m0{6m#YNM0L@n+99;2UBXS7VlAv?WUMn|eOjBT~Z%@c3p*DNla z8Lgiz@O(oQ_uq@$f*Xxqn|94$s^fbiVIg;X^U~tW57#8mQ#)44mdqMHXUY+U6;~G? z|GTZePF?f;y~K4tvPBuPljaAg&R#k-F8|@Do0Ie|RMea{ndfm!RKzqx`Q=Pab)U-j ztFjfZ$8@~9wc@VG*RKbU?!JH2X!mnFnHBRMSf<fzq=sD`+ z(BOMU;aFRvWHP^?Gs}aSian0TGjiV~u;olRlIF>*aYXNsjuUr~_ui25($Lb-)X;bO z_p8hIKbQIcac=Sb>QGfhLybGvp1fSKV%3{d-;M6?uH66rckTXGO(Um`(|YV?_;a+h zt<(yc+Nk^KnVLWw*Yfjoj@;aw{-G;;4^#ZdW#*5Lot6G^Wb*t&*RF|uwn?7`T z`|OzYeFu>lK0*d*f~;A2M<2*1iv@o8(|A+ukop}~$A$n;qu^Dqk4^2D_@p|?Wa(Dk z=NwM08jIB0Qxariw6^SKtZLfn)_hvp~&+Mh3Q{kZ~3;lQsB%@F>g^PmKrx($Ls~G)|}Lf(CA7pTN1?Qz|nSM zr;XHliIc@ClUushcpos{&~aP$#vY~CQ$5-XayeSR$aSa*PP%XW@pn?Sz3p$AAcNqL zwbP@le&0QI{{BQm$z+YwLQRE70$JoA-d-TebNPUh@2=kgTu*v zi6W+kcaFIh8YjnIO7OTI6Wi!{agEOut_yt{fr4!p=B-+_VQa0lzwKv{V~1;brd3xw zoxX=JalwRTnyXf|n3`Io&tS5UITp0zP)KOu6$Y8Pi$71YNEFG(8PS{v1XQ>b3a;&pQVHahnWfGs(Y&GUh5v_9$GIU;EXT&2ID2 z?N_rJi~9~AcAk>jX>z*2LdulGarITV-FKZN+Lq)LoOKQqDR#7*cj39TaK6ToyH}zt zo8n`qt?0V5R7C9EYo&M=Q4I~x;QhHp99iOB!HZUDKVi2l$-R(QE^z$a)`>z3r(E9C zwkl@|$5v&1DeFQumqnRYO$sit)8Bm!yZeK$2p%u4<4uGY5FJvMI_6f`VM+toO^Q~!Zp*h8*--*7QO71adZu2qLr z&Mvs~s*AJpfUAgcLC7+u>fQ{k!=m!x`3(cTC?V zrl3dFK9+i6^j+sB& zcwFva=j7!RR5>dLqLg}i5XJjkhHPELDw?B!wK41Mdr@@#qQUp(;&^}M)7YeGb158Az(%xGnwY++5iwk&QaO0Z+J=r%PLxRR(k|_*1w4zQ?aW zvmU=oJ6!K4Izzzr6lGFW-MRV<^_C_xbww znCgeKW^7-Ylcb&1vgfSb6#Q5sc|qec%|wPZD-(TqSxxNcUyBryo?gW1cq}3{a?zSo zY>ppNY@U8ne6efAtORXQmIlU8Htp-QQ=(b<+LLo~<5(|?o|{uIvcB@~>kk)}dRvs` zNd9K8_PESx_p#GIDZ5&F@=1yAZtsYwC#9E&6|+6_h`ko&5b#Gkv;MB%2}TSS!pw#VgzHuri@%PN zZ(5zdQsn@{$z`XrF5ln|p0>o4Ej0FE2-}>-3O=Qhjwy|d#ZvWJ@2;u-jeKRKu*50# z)y(zj+cX^(yKML_^0(TzVb-F$`)Uch{?F6m-ov}#x6Je>FBZ4&Esk58ZIG=fs;J@k zU|C)4LM8!=E54qbYAQzS50_6iQ)IiR8L(?v?_J@)uPwzwLltG!chpu3PoKZ1b22~I z9Q*HCd)}3}_V3n{_{4oqgWxU9&SowDj>)%lB%eKbgvR+R%8?g}28x zEj!V?bA#~Pf4!3@8ZLkR?ArYq%iWab#Z23Ea?YL4EW76FvF&9QIj+6rWo8c_e_=sE z!^46O70(qX#8?VXNjA%!nOki8n{(=Fs~$f)MOsX_cN&8e<)3?dh5?d8m z-9w)h`!y`SxFS&W$NJruUz*gG6q zzFF0Mr+n)spPVs^U-b@eCD+5>C--Xs++IdMe**LI~v4zj+lBp4c1*0V2O$te`G;F{^$N|jdY%I?f_ zdvn*fKF#}oo^{IR{BOLmt1lls9rusr-lwba?T-7~PbkJV9KH9C@mpEBp_HtWuewF) zGnJ~n5=JUTdXHry-MFL_S(%nfv3ou~v~I>@lMB@qQ&{kdxPF|{k_e15(Qd$HyIw3}(C8k@~`eqCnB za(cndLX({XDj}nhR?wI&h)$>tO?a2+t{Y~Xo z@gEjoJG1ni<)XRD=PQ30KM0B0b7kEr?ku(nH`iIgA!~y+aXKxut+P9R$lk^#X9q)E zqQTU7#$DG|bjci(Sd#h5qdezakp&0Srr?tGNeaB)9dJMX`3my>~k%1xFi z;WMxQ@@-LDyj+7%&{fxCp~6uS&6&9cuXefRa{PPVBkc0tmT5=EiJ2h>EDITQ?mpPM z@j{q+>!jj74UWGD{P%t3Vc355NvwI11#?C-SHVHYjI!GW2R(Rw-akma?-6j`D`h{M zOTwME^IDD9WxBoJ`6&PWyf^--ho8aL0^HnlZ~n&fN&gq|fBjm@anK;*1(U&wEel1?+;UB5 zcWlnMxYf2cR$5uFx&_kUvdXV~Jll<7-{123@6GGCUz?MCG*?GY&y>}NO(=*VHFn~g zQ^#jHoxf+6o_D53isSII%Yuqb=QiC-UluK%s-0r2$f0+_(_p^Pn^}jXSRy2NPMp<0 zZ7|bk)-na(&Xw_29P>U;$t#&wb|z3nxr<}l`AusK^#tFwz3yz=+*1=@a=M49|IdET z5Qk+(#@`NBP7au%;CZR-fxDs!R}crwTffI~7QauwPmz4gR~z7~{BXZo{EW|g6oM9B zJ2Cgtp~YPLK4xx>=Kb?#cKacADPOIW%0>s*;$D{(B26>h63k|-xF%Bhrn{>kvnGZk zon>)MG>7=3#hwcnnD&@?T;{Q>Zzyyy@cQ<6jz_kW<_ZOe)GfiYU#M~RM?bPMcpmq- zyE~q_QE*{z($Z98!{8SJnmi}=_5}+mZ041E&}~2e;3sM81he_v2GK{}@Bg0uebT?Q zLuF}Ysl`VNw>eZT-xGN#H8yCouvY8Ur=k&lFZ`|M9q?##xMbzfyl6vk`kc^ds)si4 zDn6a!{xCrJ<>OsD9Rfve++Xg~A8nrhu)xA4Hv7wO?ucmXzA~G$_cXk-_Aoj>^e=e7 zcrtS}E4Qi1xi=?TMNQ2ny32qH-ngpgN5%91S*so~FR_~YxpJDmVD^l}r#H0Nni-c& z+R&2|YdG1JpDlf*({__{Kd;;>J@)7DuB{D*Qen}{P0JJ2r>Y&dPF~2=xCLrpSG^PAuqS+?z;zXZf>@y z{-#s4S8mN#U*QMpA1zPEvcLWvoThndk;|-ruv&q(jGZY?=U5K~Bo-D*hQ=-~*j4vP z{E5fpo(ev%1+v>`9q)@ye0*@dsi}RWpI)1ixPVRO6~;#IP2J4`g}dKANuIT6qV(eV zLYebSg&agZG*)WdGv`Y5*{vuS#l6I{Z_la&#Sdkej^2rK^6ETbD!)}(_gbjykL zaam-t=Ocx>u7Y*1n0A@1i!|DB^$M#2kMk1GOMiSA-_1LiUZm6qu6^U8o?GvGe7m0K zK>yz({r}hh*YKS5eoyJ^Yi>rKhrIdYU)lY-ksJ{p@1B2Qe)q4ONyi>AC;mBCrWQZv z=Ca?*XG^m`7ds|(CH3xs2Z17{!8;9Gs}J(B_zw&0jpN@N$ImcR zh?k#l!|wh4tw&jN?(J)Scu*kH>fphDda3)l*;FlBgxv9&WeS}W(7 z?{8QcQ=oU^geG^|$rif{8t09+&sy>90>?>KmUNetH|_@8+E$us`TBOOGtCMZusTe>@iZoef!*y=yG!tms=}F18=^M#h z$sJ5fxK=DIjf=}Xx8Xo?2xesof;<7ATrrBfqz^GsaXCd>e zSv{+nRtmW4&ao(D^7i&Vn;rQ?(rvQh6ou8#6&CbN*tPD?FE@uGv&SYD(owCJOE@+d zoH5Z?tmf2Yym2x2{|lM9=WFC@zg*1Ue(j(9u^F$9bP88|T^+wR?qgT@gN5yKPTQ|D zKVCEOtm*GR3NE2SlD;0Ey-nq6*(WZF`FK4NKNE59*CXcBF{f^%{}4>&x#j!5PH497 zgnNg~eS=j_O0cs#=e&QDlwZ&PQiajNS>_mrQqzq@UEWz~R%_3`zMuNJ@W0KyJx6DY zOjV8i6~)jP^y2$(mq|rM`ic@g>t>xlDeLokxthNF9Nm3acxE2c+@QhDQQ*N5;gi~Y zPsQW6$~HHv8Oo=NrldN?hf6FFwS00Y)y7BoLC)obpYMmjbC%(2zj6Pz^CPuLtutcRCdw|Kux}^# zBlqN~XL=tmx|h7)e6d=B3)h)qr^RCI+`SvGzPe;IukM-Up8w%>jIWo=Imm2JuyhX- zlkhzz!PkD_*rK~{AAEUvIU?G+?Q3taMeQ@4U4I$f77K36&p&iS>Th2Ep~WR{|A@*Q zoaDLu!G;G+eJ)XfuNJsh^|)&1D03-YIi~Qgbi>}=%_Wl-+<%{(n#t-WeP>Ul@O1t7 zV-+^Xc6N(j$a3X4EMOpIV5;`muq0HG=gRK?NB#G_elKgv;Qsu@o+Ia_@BMI#3=iG1 zb!+Iis=dMtaW6`%C3JWSzP*Xu^U6D})m^TR<@D*(EWA>^h11Mk_U}#%@%Ll8aA!;H zMKPxZtFoU&va#_kZ92cpXio2yxlZd^e106d+r{MJX^{K0g1Oxdc&uoKcC^*m%HmMXFTQeDSpWswU*;<$57pJ$#X%GoFfvaR%P@|N;{nT=lZoHmy)~|eD2p= z;t(2;ApAJwL6+~E`uiz!Eee@ZCpI2*^5k@Aj^sUP(X-M}vfn_8*HDsgu%PF&E7aJjc-y9*m)Vq=dMpN~EG`~GKcfkn&)50$nX zm#`a}`Pp}T7MDNta&vk?&0m&BVcfgc8F&iaxwofxw*EbrX{iy>(T7_<^DCVWno`NA zD6;mE&fge`;Kf%|U+r=c;n*bgOsq6?(Fvmi23rn^F-an8?`9X`rD=#lENJ?go%04nzB2hvxYEdn7fKrJ5T($=p;MRJ&rTnkQ_UjmZ z?!>Q;+fnfF&2jsGA0NHVum647-~MmO|Ch_>AG>r(=-fQZZtm%N4-OsmzF|?z=3}6A zWU1z-MH$~F+&Q|z=$HVzV$aqUr-WvH{`=g?fz$JoQ?6ZhyPl=Gex-ceqlkxWTdcP- zbmcH-Ny=~Q=B0{Ey1d~{^UCjgv{NFdnF=pg z_kLFS?#uTgKeiXnHIq~h7S!`6iYRd{mR#!85_YHPLQboSZ(z9TvBjKi&n9$*J8(Ek zuyM3F-O1c7yRG`K%;o(Oy#{F_lUJv$XChV|ydebf8+xa@L@2lAFfBD(AR8g3#(ZRFDtFh2zeRuwXn#&Ju#oldu zK6l*`4?jsZ#hd)mo7S(LBeQmu*7VFoMV8qo86AWd8Ru%*IX};Q?%TA2)1dfh{kQvd zdeZs-E&i2uKHlNUDbwp#@hPg4>vu(ts73up!8v;i1jY4Z58di4&9W$Mox9gIW@i;^ z=A;B8DP{d4kA)kma#*{$QzAmAPR(8+>H9tEa1@&+Yg8hOi(=2pfGM1-wAk4%y#2P( zB*I0a<;LB+$FH4@{?Tp!-`l46XXP3lJtwX<$MS~tKX0u+`s-Jrho<4Io{xvP^?hpj z-$^m8NUX}7vzYBc_k%s3-S^G^``!M>eiQr3|L5QTld66jUOU;gD)ryD^G{DtU(e{U z{PNGPwQJY@xV1Igb@$zW&*#^@x_tk`Np<_qsmaF+{v2WRn{(&D((dU6pRRcFRQ)~H zxn83vBUz!frLF8-ql}jahic;7sq42kJjv?Qto{DbPo2+V{+F4vixvl)i>#fcqIpS$ zc{$L0tNJU~waI1Dl3-WIX{M9+Y_;S`4w&?V&E#cKMy#{65vP)}^wX{- z@#!DhQu7_FbNG@<)IBfl5MuLEET~~nWO-!J#Ctbng=yAyrI|iz7B*J`^5o^&7!NfF zG%4^%yEc`jIPJgwU3hnR&=02l1`+}_@u5eu3tI1*n{RM<^JZbK@e|$&HO>ycahLXl z?VC8G)OkwKqT6rJiSCMQS+L4Wq_R(>f$J{UaYY@u%#UY1V?%ivi@G+PS;I5OX99P+ z@EHk7(d_v#C#9Je?e5-i{qN+e)_T9)SzuflZ zQX!+zi!KYPU3w?W4>I+58>9tJ6YVl$PG&3AK62{QB<`S78#ixnKm1p4-Tn&Z^LC#_ z&dsrH4NgDz=u0Q>k+l*lbQkCzdu*8H>-&F>)1gHl%V)gvh?9Dr!TRC<=FigmzZk!f z{(sPZ*K?t&=l%aKm)rf?bX-0nI{ts7d)&`w{=fVGUzFcFfA34*`tK_we=yB^|M%Ye z+8@VyrS*SbXtzt*wtc%cLw0`c?d$))ocvmvGsmt~`1tjWWq&Nf!ox1S{(54=(p8KH z6SRBxtW!9kaG2qe?~PmkzS_^*9QAzn&0GKedrlXR4>jGg?yhhDnw*2R0f8QEh6(Ey zSg-%Daxlecp=ZtBQFQaEVOZ(MpH`%81vL9HVw&(5|fB!H254l-R{x#VWEK#wv z!PG_QY0vIG?3UAm56<9MRSI`{&z_+5f1kF;(igJ?7Ok|>*4EyztnERANE1(44)4R9 z#p;ipdHBBvsz`qOUN%wX@v@yCPB1*qn4k7l( zCI)Tq?hB#4Yjig3uWwj;SGMPvazyfhsYfnd60*8$wq!!bA%P&zN2yD$oG=O~S|q~M zb9vQT4Xub{0!NQ1PV7?VQT=3dw8BYm&h6;iH}2nVeZ+OVZ~lQ#pSY~{ifu8xd_nzm zLiS~o`CBhqSXek*>6$Z9L?K~fZ^=1;48 zpH#E{h04F-dw$mcm~8*2`PUid=keS2ZTt59{JiRhc#HCRW$nlN5-T$~-}>m3jvs-)bo>|Iyu82M6m8|n* z#{?~BBX{%2?BoP#O$Ad18HJ*S4>p7`hdDDCBoy1QVdo3Z|2dTwaI1o<--XZ z8tRs}mo4u#;7FM1IxBs}CYc^%jdcfjBW=7@4_X{wdp5d5hI4|UgF$zRk>kwg0ZsdV zx7U5T3mPx@{B!RAAFucSICZk(PipwQ{eLvlf3%l|UWzl}SUB^bvA=EVl!&SS^>V+^TfgnLa=sImNiWiZxt$+QJbLtK`drKEFx!%siaP6c9zQub zIU+XFRmMHwT<|<@zPCD6Z_}F+*LJ5qJ>=Q_r~T}eY+12gYC`ie0+`-S-<%Try6Ecb zsKslvE4(AmC-l!bw_kR9U}#EP@b1_z879Zhz2o~<_I<s%rD$0JBBu zClSL1=}-EfeCA6^n(n9ev@1cvh2!uF%^Al66jz^;sf;`G_B!*@jQR3f%ipWl|JhZr zvU%6BhZ!vABpwy4(g|QZdHlhh2cK3s#D?<*J?P$2FXun!^LbxJ=QO{qfzwpg7N5Lg zbyHR8SNydom%u9yw>Psn7o3gTY{a1=;qc5ektO1jfW~RArNzBl#HPFnf1MfEl+R+Z zQzj}sH>am{?P^W+Ba1q1wy~-B&prN#GkB)q$Dc8x+25`H-#jn*N^Kp-Ql+BnM^Yo( z&Ytz<@D%u0VZ(Ibf;>+_R$=11(zKpytd$dmv+qy(GkNy|wR0I?59*wZYgT9}P`RSw zX&}>EP+ctin|=3%Wo-gNcjNfGmruL!zVxM3f>7zwLW@}rx23LSc^ng5!N4>pKq7fg zvC2^+wSDL>nabC1n^sGOo|QS{pO+cb77(P!wV3T#eAJnZJ2o_Iof@j*+0^~~ z{Nr=i#MYR3OkVP_B0tYe%VB|&`O9kAy{ylxj`6fPo=nJ_mFHCRiEHb*Ifdt@NW6I4 z94TV?zLfdg3DJwijC=a*IhZ~*J}(e*^^xDNG5c$K{l83&izaS2jsM#IDy%5DVZstQ z?Q9{#pXb#sN9yh8tq(B0T-Unk$=Tvx&x5pD1h~A|e4l~ih_w!R44wrWrPTQlWaNvM~ z%F`SH^|Y4T(d7kCPo?@y;uM=6wqehnrsU((Ib%7QI93Ks6XkOkHYo5AJYaR*FMDtK zp+B#mukXCM|L|^=nq>y9i$xDy+vb9Unzoxl(&?c>)j#z!2Q$$q}kvs2nUKWXFkhOb{AKbUi4>+g2u-J3TbE-T}> z$IUcVED#&)S#2KKgoX;H-oigOUqbf1iZ!dAj!NMeC2Pmizzz-haOCM|=H` z__|M%=hvKGIeB^9&6gz~jtJ`?f9!A5Xq zacs@POLxPL#;v#SR-3Rov2&G>YJHaih_ zFQd7uvUPNH8X|)jJroa|$YY;WD6x8CkGq8o??iRsH}Bsj8A+P&{-wG4?zuvSHCMkY zFdkuCaCSGh!VG=uGY1ZtXwO@8V&e0ca~ApqigYZNSnJ0vj@GZuz+Jm9*0+q&Z2r&Jl4Hw*V~XjwYdRYy;6!FBlsx8EK(V48kx z(JE6dadzK+)xhhjD$7H8jlUS5&}IH}zU^`Aot?$(jy}F~S{qp=q-(y~)bQlb3HAps zYQBB`vfQq&#%N~E+@M$LPD`t-XPbY#6FmROzk6n$ZI2}O=J9WTmy?*7$jZO}P2rl{ zIW7`g4Lyw|B1)`fIU=rvHa`3(*T&9%6@H-6pAJxEkusTmI7ceDRXXHXGH- z8HUev&&TfjvoYv;;jHJ2-`5@g?%Q{7rv90q^Xnee*L-@`JNvkvefiE^pZj%SjAL1_43)9 ztumF-$%+-s≀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 z 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

w*n2NwYuxSU%e-c3U$5Nw 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/cpq_pres_4500.png b/src/qt/assets/systemicons/cpq_pres_4500.png new file mode 100644 index 0000000000000000000000000000000000000000..edd955b5adc9a5f00b4aa43d3d274fd2a053d4f6 GIT binary patch literal 132431 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelaj87gdEslmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNQ(yCwh{M<)qaA8@nQz?gi+u`%k>-s9%4s)q199S?I}-wAwH3 z#*=zDipz~9LcZFGY$$oY|KI!4|Lyj7)87|mhE=bfXTS5g9J~FD|9>Rk-#_sC%lm%& zkJVqMKYsU|d!lpa``T2F; zy=nI!zwGa*^ZTNl{wjarKRN!V+aJGtp87~%IqUiJsgLKoZwces@6+=4d&cDE-1a<7GGy&|8r@(M@{~T#CE|v zi}$~|x)syZc7C)y=6a;`Oi;J2o^R!;UtH#9)2nW^*e`Q65o&*Yeq&4d-F2@E4IiJf z{%}shLQ?YU>*>G$9*F<@>#584RTG+uo*a)cT(=@8O`>bgzo)S*DtF$`nP$HKVC}xY z+g(Bvgavi-XZ1?U)YbVJdjC+~eyO|o)6tLD-q@!K-1;}KLG#hA)`KlBEH%6Gp+I$NjMu^yT~p)Ot}dIkI%JkY#g;2Y+H1F6Tl3XSCvscT)mbx3rER~lIEi1+ z&c9prKDprHME2)Wd+G}kj?GM)mwN5yva@!_m1@J{Qmnr}s?W~vG`k^3J9_2^PQ6l>SnKGzed+sx^51Vm{Ph2; z`#nAM=lq;gweLQ>pMUD_j5YhKwZ0$U^M7yfPW$!`@8_KQJBzpeZ^*mvM}B25&*FV7 zo?sbW&vam;w8|0g<~#RlgBUEP&bnAQlWSL{&Wbf}NqYSzquXQO&&^-qqoM`Fqw zHftDmm6g6)Z~WzQS!?9$b&|7IZI1f)KxE(IUZKyk);aC=etI{$w|dpGq<5XWW*JW1 zoc(mcd-Z8If47`>+*xCBA@^m9#;&Qax%g5pgr>dymuR-APGY|Ah37J}KL-48QGI(M zXX_rR`MI_?WNW8x%3Wu3koEevS=|$vcshPun2}V!O7Zw<$FzXA`@%kGZ_`$^T(2m1 zfn9d;>q^(`7uVc6d45a&e8(Lp7Fn2^*)Y!JJKr?z@x2qvR@zU? z=G}XzcB28?l*4jA=4{Asn_{4vc-Q2j+R~PDzo*D2hqG@;`~Ob(iSFFOMTg&2TJAIT z6fM3|xqQ0WEYVL<;Wy>ORrz{#BxUEm+@W{SO5lD3cfxmpqq9DoKJj;&%EqhhH(O*p z|GI{3c%1(HuxpR- z7397rBya7jaSpYRFbfu*Wmx35GxK(WypLVwMYA<#n|ni?kJ^6=KAgL1ru6pzmnz%d z98tRRuDAKN&Xl6y*kvboYut`>=g-#PV->ZL{naWq>)B6irpLE3{hZ_DGJWxdiM>xQ zUdl*!mXo;1SsnB-yWMui8kSiKMl;V}sz9HjQpMHg{Y3@tYkdOO(q9@#WFy-QZO{MqM zQy#_n9QVF>Yrcr`CFz;>BzWIxMBZhc*>u(K&bOBH%cV5A|450veiO)Pw8`*qa!7$+ zkyBQd|4G}cL6g@+YW$VRJGQNOjL1OOvVubGD;Hqo~tuo2f_VPI$fBZBywJ*Ch6P)4EqbFcB8h z50}~~9QBGd_Ip>FxXWd&$v^kHCL9y#yIH99#P#AC|EY7mE;j}>@G>rZ(sAVBSIbtL zhhHu@XwNr~(!5gs>aur6jCy8N8N<&!5;U#+2Pc# zxjFp$O-OoYXnxJR zcw*SgvnDgQPUDeV;WA;$0t-gdv@qKRhe~+vrAzFTJ@z$K>;=Qdofm$lY4`g!$u3c= zJS*Ms=HY~Uu8Ap^zNyLVY?$YxS;_Ro`)%N}-79s=*c>_;j~Z;@eD-Cwi`SW8XSwrs zd`q~Cj_zDh?3Ee3P{uQtt%7U9E>V_Sd+wd6HtK8+y13-$&CA?Nk_tqlA2F|Abv~Kl z)4NamCqx~wGrOX#ENr{F;^P(z53UvA8Shgf+Fu>=4gOo&=B1{?s-@K%tZQ+^`=HbB zGZH2e%AsKmKld5^bgr8J({VBTdgWzP@2veD#Cs>fCHwHT^5A{5B#r*txrN-E=*Q+@ z(!e}J?ffMnQRW8S=X_i{ukPqPuqN&*=SPK4sqamWY&cVU=k`03gg#D*>SmFSf-kIj zH{S%jeG)El+_WOu^&Gdq%ca#)c83<XpvU}F&%!z#an!Bg~3Joy`Nu<8u6%BpEB%jUmgkei+;FzYajV%vv% zE7o0*df57{Ec{=S>#~&knx(>zz2w?YsngHRNME#jUdjh2o-gf(>`$CK#Q9)dM1v+z=qnWk;ovKQbBv!iHyH-( zN?)*EFVp@A@5}hbCtj(f-D73&Vp;#hX#Jg;!3 zUa?lw|4_)IG(Z2^F`g&NbFPVbu z?(HD5K@&-T>2Zuq!NQI}=;1pSu$ zkGCS`FJO0TiICHlJkn+|f4bn;F8_Ti52Z?PSrJ*~6|~k!ovCckAs@wCS7$tMd-W*c zo%j)+%>COrZcOVvAG+X>?)>~G<{pfjg0??!RrG3^>3k|IAmzs-p|;&8?35MuScRU> zO^WCFcY{apiCaj!wp{SCpH8>tJIruw_E;%*RVq2!!6Bi^PgXsymr`f?7GdR%yWb@lNR$0ZwI&3Wta3oD%*|?_k)y<`!-5Wwmp$8A}^=@V2{!w!KT!@XPqZ5RdQP# z%#?85wdD7m4yS#yE}hb5RSK~6I1#-5YgK@aN}i&T#^!%js#gRaySslZU&y*$L2Dsr zgZGzchePw1%v>i~S@Yw|Nv?Bt2j7$?>4kFt_6^_{IRC(uvEr}eK^{qkl9&IMM{lV} zRXiZ|py}Y`2w7*-51z4!t(6Z?7+ujgX<;R}@uwjxqoVGyD(Rc<*d|!%O5^0 zecH*={PNuq_X@2{ZcB&b2flPnQS@HX?y%@|)xp|F;%68)m@nV-EcX1-+&_$5og#1B zFSd3*bNV-D=0}Un+Eh_tS?e^ZRC(ot5@$c2Z}4+l_K4T`cz5)B#-ROA`_(x+EQR>D zq#qNwF=xBM@n2I*@{Vk?a%)vM9Km$KBTZLz3(ub|hB}V5(t1BMB0Z!J)l8Gk|Cu5_ zt89gdYhOgi+{pIZs5_ zr8w3lekvjjf&vTg*d3I1xi#SqU!9SuU4Tk%Z#sV*zlxx)$qy}YP2v3Tr-91rGdD1N zJF;cwCl0H<2a~TCu1Zl^)5_%>*Hf|lN>8Z52Jh&}x1}T-oK7;@$#QVWZg;ABY_rs% zk>~nsbzxP%ld)<=cLLN_GJI%?l{OW;aGN*#q{q50c@e)?gcC3cs&zq^~|MuEEe)B6v&v^Y;E7KXDChe+HuI0Smd+Eqb=K2*Uq6+G-BspG) z>5ALNl-`qZ{6s|vLxcU+D{~Gc8}&UZ-qFdiX!UxBpvA2o@+a(-76>*S@K_+z?H{0}4=0vMyWr9m8^&;ESn$50sJ1ly@C>`@@$J9+LDi}KQPulA_Ob`!0mJ;)R z(=Wj+=H%2i6K$b&nTn!r_8buvV(cDUl)A*jf<6{&>ex+SyX zQBR@r&z8wXN=pTr9GFuY7d__N%I3c{%kuGM_eV=q_>XP5H)Hvgij7+@=1(Z#^72Sg zuG^95x8hjQwv!T%7P-xkz4lCGL9+X6rJWtQ3KN++doz!$7Zo|m6#r(zgi!BuQErLX zdM@5C`u(_kE2E0dLY|GxYV(%*&`!`|Yx5-@{p#M9dBpJle74rbC{R z+RI`~_pNOoQki8`{Hpn$y^J}&CF7*f-S+8|JUcoxVsa<9pJjD-yA|yG^0EJ_@XgDU zc3#LT_;iV{HTR@~M+oz^S5;ZN6-{QiIBSI-m3q$3CukcZ`B5%nYQFr7?$RG(>x#Ba z%v>yOb4SP{l;^;uYl@dPi4?WpmOgobL4@5f&1Y$|@64I!4~Q>WAS>6i#N~jzmXrFa zV+$^rpIo_ef9%?g9C=fJZYzJHc6?Izi=}7NzKY0iHV{7j;x-50v)XL$3^|whIX?Pd zj^<>_WPZ|I8P~{R$uZL#}Yy0=SDvAClu)1I88}A3jYu&4p?RJIz-{ZK% zdDXF1QmSX!9|*ioI^=A+ronU5mR%AlWsV2+_B-`HJAdi-6(L(kcfWo5F@ixc-|RV_ zJTX&TKd)e|dv2Wg429ftfm2hW!<~daXumQm4orNjI_dn}<3_KQ_BvcxYt&8>%8#v8g`9g&*~ckrQyaXvD;P_L|~zj){Ik zt*7n?P26(CG;z9sr;ziTxlva6A?iE5n4Vn^J$dk;Z3xSP<#V>FZIof(lqTcRrsSAh zpe`+b?!Kn)nrTHL2o6m6w3K-=&JeViFec?8%hZC|x z|4)3w5$Bt9WW$1^23_ZJO1C;~-1)w`v?sX=XF#PWV0{xWrRv zSxs2W_UR?zZxa<5Sqsw+FLeCdSn+uA#B@&6Wl}ljt4h{SRbM{WY?6(&rZ1yGLd>)~ zaTDb`Gq{fhZaJ}Zt>^md+!JhGpIN{!>OZ3+u*7Rh+TRQZGJ`C}x%t}%U5zS@B=l`)7Rn{)31wdX4n_oQY|j-MVtY{w33tYPt%q$*nu4_?72j_SaXR+O7qjY+lvv=Y6lm z+*fxl!{y-a=BTQJD<*i{l4y>cCA{PPq`l!wiyN9t`AjEm+O_nD!YcXsuf1OuZ9Z}H zPuPbmGZ^P3Kb*UwRClBE+ZmEKceqU8EA3Qheg18OO;%a3UI}wq#1yUbi`?`JpW89A zzp_gdGH>1?t$bMEVcsR~#|Ju?Hf5?sWaM6-m|1aIt@-$kizihiw;NTdKD>3Q>FjM4 z4aV{n_Y_N4_lm6Fy=~q@M+R#f)r8@|ne9nAomt7v}Cdq zvaJRM7R%IFlf+f3KX=G-NqaT9ZN1dKDJe%LZOvhsO}P&b&i~9j;i$r?w{ItI3DJG% zrte_5WYV;i+yBkEcY*23ucMzA@?UW)k6Ylwxqw-0s@B5R_g0-2`aPPRUcHmOqgDop zPLSU|Au!mg)%ekOp2o{96CA!AedoaYWAlQe18oWAbk7JL<<8IlROP$a6 z}zmCEeq zasJSTod?nOJ+zFur4{-b5y+bq@OkhM+E&vZ_E*4|j9ylz>dvdK=L z1v^fBUMTy&A&~QxcfO-?pQ@0OwW;=3 z*B(Ag=lj;Jo4R%C-v-464Jt7^+&46o zojH@_E~9+9d6wJl*2SSbl`r}Ym>$lo|MXO0&$}w!MY*g_eLtEuZ8|f-Z+#oP(8n^} zg$Y>!O$Yb$>P6Dfxgayp;q1<~U+%BZ{uPOKmvXn;Q?S_e-^oKewfN55 zohGVMyl9KXGS;On5*PJ2T2d~4+A^m^j_;xE?k7|(+XC*GD^%@yBydfj5*otz9e=R2BC=w!@rc@X}_ z@A9{Vl=y2|41b;_Y_h!adG!^Mf|UZ5x!;%daq7OZeVsW|aklGU#yZxcbDst*l>fQF zZSC?$4k-)1Z((YD@W5y8`yfkpg@Y#_oH5?g&D^_Q^^Vi2z=u2PeRWJa^ISt#g>!Gt zDve#TeyNs!!%vqs;YPX4jHI_$7ppAfxZ)S3$8=Tr5YHT?9EAs-eybS@6*6|XikeTF z$-~Sq%<5T~5VZI9KHQ#Id|}25uaHZ62TS?h9u`S&JTlYg*c6Pf_l51cjJO8O4?{+*@ zb=bwjs8cU!`(x(nPL~bIGAmE7X*YGKG2u!Q5z>@yUR~>WXWuM`GrhY^Z_QuC$5DRg zr>B^pGAqx*&09HNWW8^_X1MZn>s7&ZRk_WF^YuPI*c%qp7RDn`;=?H*@FZk{{_gU% z|93CA_OW8M59^iRZ+Il564Z1*DxA4`O-_l$=xJ*-OADt6-_e{5-My|Y5A^svyUSdc z8SyImzl!*M!eV05GFzTsjW45w=4zO}?cDW^CF#;RhKYUK7F)jMJ-*sVT-fT|EZ;56 zMQXTbmmKnm|H*pYCq$soI+peAQ*Q49NopF1+we?W% ztoH353!FU|!yY`jT&`g2p}?a2=F7FMyS7zTiB7I6PJO6ibkn_I<0H}DRy`?(jkOEJ zG!D74JxacHvRL8c$8VD|18p*N7x8Q@&b|@#MYH#+Gmn#*4})}5q|ag+@2qcre-EPDRe3(2VQA%DgC)FO>9-zMwL%4 zOkbp4nMO~oTc4c$pZD74*OeXIexcky6mJXK#%%p45bpnQQta7UIgJld?OBbFCh)y~ zYI`D3yGuOd@QEbLuRaF@+n+Z*pLHXK#k@gf#++TkDH4X){+R{|+2~f;G%`-IGiUR8 z&|=Yj&E|aFT`dl?jMI6JQALY4m~b-uc+7t2R_NX5M^v}z6<(D)5anjMe&srDhVK9F zZPH9$+bm8sdmFEqS-g6+=;a$*7<*rNY|UElUtg{HXyJ^l$!xnH^7FB}9oX?oFtq!Y zdh>xavnTs_YLDzKscFx2?VjDVO+!xL?ORo+ZJEameVLpeY*z|8*`}p>YWp7PJKcM3 zSWVn!G2!Jr@dvtZyX>6#Gi4)r7szd5+<8CgU6u90ldm~0YcQ}ze|k`3u{Gp7OId-p zW>dRGA#8S8Xm;Jx+dHI%% zeKUS2KKOE6a#|kJC66zA z?p#^bJ@3fuD37IAw%iR^RZ%yMVci_9)-N}kew{8(d3V3^!J6X964M>olwv;kPH=kr zehGv0qq4MDT(A0;r8%xET%@)0y<$}QvP-94t_W}b-aBFGwUzHK=Ee6->wi`{!Ov-~ zq{8w{hth-&X^GSuCyiA77`L7G^Y)ynEq(IH&D&ftsoqRXn=Nx6v-KXY{k!HzuH))h zxvdYMdVEqX^*5S1qxsshEv|PC8=2Qk>sWBBOlEm#@cE9JVZz3fJ?G82(0Fde(^L_j zRgStET|%plGGuw1*_D^rP7|G}dS^j)=x=eBuR)KVFvYPLIi{Xo&R%y!qil)mg=OcP zlw0#vA8_BSII#TmlXIna#k`-c**77R_uWhD4W&QM#H=uNPf}DmnELwG@nyNeOXl5S zEL;6*-xh;sOHMpkyj{YdcY&3Glx}$^?-u5*j1i3-%YT=i z{(XM$+^URYS0?}ZnA5*E_V2&7XXbp6W3~BLH*XO`_u|#JSl9L56>@VvJ8|XRjQQyu zHZ^nY_>Es>PAhkrJuyIbemdX&@JCj9_46#RES<5idyncbj!E_3L*5xb+h4C$e!Tu! z$h+e9`u`#Cj;H*+8@$v0+28kbPyMxQsec~w?t0D-@#UA?dcVm{WO=q#fl*v_y{orF z)1tSovKOTHm<9R=Z%<14^TmFr!_((>hPq4bzPIgas8Wkx@j>Xz9sZy`?eEvltQ5U< zrSX=jU6E^Z#_NRi2Jwl!8~k}hX3eqYUNGU`d9e=)0t<3=r&a}s>sdQrc%h#0kzwYo zoy(WII#0d-$42PSHFVZwwBSZHrGo``0Y@vu$a%@U%bo&;0v;{*AkqYODU< zAN7Ck{@pD8@9z8m%Kk2CckkZ)&)o0JGTHaL(0&F6#@0+{=KxPNl2*Kv{ z92aC2in$e4moHhq7jBPq z4eB`GxtJ|>!jFlsH=WL(bDEFa#yIDRQSp()q>Xou7Kv}}S}5c%=q?hvxJL2)rbCt8 zo1<25{$~4=+u1eO@^op`Vvi(2%_WLXZnB|Q5)|EbyLEN)%vHDfqugijt2Z+y)S&20 zGP9P-asGeo`>V63sj1&t62Qc<=f=0=5(0Nvqj+!sv)lIe8s~$0wsl+j>KAjKshM=| zMaD$sgaqjwJKkk{k}KHB%wzv@lA`6L`O^Zl7~iLV@nubTA@(A=^!GKp<1d*fERNH? z%fQ}#pkn5x>o)i9-oCrNKKs_+-;A4$iw;`#-HKsgU|>t~c6VX;4}uH!E}zW6z`$AH z5n0T@pr;JNj1^1m%NQ6K*h@TpUD=hE~jVN)>&&^HED`D_)b#ze( zNlnhk%g@PA&rB^=@XSlrQwTHEGcc^X(9Fxgpuphi;uunK>&@QGGdVX)Ww(8^EMN6& znfdqEYMOpRvnOZpDXDfXTH-QM)S^k|2%`}L+b4Bf~6RsDCC+R?oY z-|u~2^=kF5(%08+zFxEU+r0({1py8grp8ffGzh4W3SKnYeV^%nDiWNg9{lF<@`D7c z69Y7jF@j|rKBNoIoYQ2#+rrlNsQ;fU`#;5&$ISnE<-KFJuKWZC1%VDGg$msRXNqFL zZeo3K-e_L+JIg=W`#(%K%d7wPI)2};N8S2+pFezgbL-Qhm2-+$WlCKs^*tsLwf=g> zEVgS_5!n|_c;{@s;N_gjo5p7Btl6q_`9hTPX`?5VeKzMOq*hi(M~a>J%oLR^l6r9S zDwoJ9J}!M6D^9)2&aeG-H(qJc)5Uv^`~NwYpI|rtbi1wq2TMO=5Ze#ij_GlAlJ>ug z?e`b{=00Ed_0;xx_5WnQ%g?#=^5x394-Xo*UE9|?^Zxdjwd=0Fwqjl|r#NM;V%h=A z_GK#t&7U5VhhiLRiXZ!I&f9N^S@)%Cuion_+i1P;?bA*_eY-3(?U=;cDM1V!GaX$L*k;5^zgfF= z!?mW42XmZjVy30O{ja>Hn8BE%VWU{D;fWHqwYG)*_}<&29I*sr*0p{;yCOS=p1U8XymH>@&`o z#U}sbf_v5W+MnF>&&ti4C$@Zf`mZ-{WR@>q{^N}NzllFT_WyaopBDM=;?=CbPl|Th z#OUbVt0^q}cqMD=JmEk`7fZpX3`S|^9{iP?HS=UK!~Wmw4L|DB+KTN&AIxbsWIOlu zq@xN8!v%@Q%(V*KY69&3I)5H-3FnN^d^+Q%)pH$VX@+SXH>{4okr5W$Y|p-=!{W5j zwW!TOrzQmXhK6=;(wKL4)0;}AthCLiGS^xL@RP+YuQKI_%9+G8`MuSK0bb2IwhuV*)n&)59rb-ZWK7Qm#@ zx#G+wo$_<33?jzb3|9Yqk{(r{X;=h&iw)gjTIsCEQtNV*Z$+1JrNrll% zQzCiB%$XfI3d}L)yuyOQg4St8=eAyDJQh`UW={G{W8dW2yYlp=?BaZ2d*%(p5rwlK zE3TcL)!FgcraU!n&8IyTmghgq>z{hG#qijQWrbdvWjT&6Z#)GyZ@sp0Gq3gcOUwU1 z2$pC6Fe#>&snJ1%;b1w>`^x+6A8z{BKe`b0+qpD$|I4I}7L`9fe2MKo`Y3nx)mJwn zW?N?)KaWXVJJj72tg+PO8Qw=9>>jI=y{%5wP{(?sin6_MC^nqk88H&m1(I6v|{gn~VFHHYO|;G2UE!Zl}PHnH@3=5zj5` z)~n00ok<9KBBJT+lD+iG&TG5QZP}*y!kFP&6f;X&8r$KQI@v~R~5R61WgCH3Iun=+|^I~M6w*v+0RD=%OB^=0|K@7n#JD(gReuj394J=v-+ zz~RCuz`!qOXLD}T8|Ki+x*tz|{J2(Qw)?I`@m0%k#uIb4c6FF^m>B<#wR4WnJ}KdR zEh=@cYPRkTL&^Qp%OzUoem1KAe*9a?e?4A-{LRwaBVQkQbATZxfPYGmtS>J1J{zU!?&YX`bm6bYhqk4q5ps=GI&BmZ+WPa3aHmgpN>p*=)URiy&E;cuf8Eu7|Md00`G0?{ ze{gE5_9g}n7AJ;%^&ge(e+e@%to>4&efRBz+x7+L&N4jVV6#hGR%R{xkJmbviNRLm zJ~s>F$@e)6YHK?7Idj^-x$|(&{Y3ZT1O@R8*CsQ**6Dd!!*EREJu3%SbGR~3&&DTf zQrQk#`fJTv#@AnN`*`8~m&TT_1@2XAvsoNxF}UQMds*ggb+=}_i%x>vGIOSj9ru{F zT`Rh5^7g%2mrG6D@pF-{?|5D|$=`4->iC;ATXUoiAFFCsv35)5d9^Dod+q7Zcc!H7 z)Hwafc6;94s>Y5m-^)9m7QLLc%yC+#j+l4G+8WQ)X$wzqPYFF)xyFFs?N{pJrVC_tw-X?b!YQo#hifow-1P`2OS1^L3xjmcPII zKO@%M-}*V<%$;4k>y?!D&%Dd?Eb-yega6GxeLg(@^6@3#`|nO;IT@BGr}roLyzRF+ z6K5RBYF?IUvvb2dmnANT&9z?Tbstgsdo${~o%X}Y_3ul?$NYSSMLI(_T4dX@zf^Y?+W*KaxBSHpu<*04*=n;UNn+Amy&Zz=@yzP)Cm%l- z$uUoFiBS$uSEtj#kEZ^8{pR-i=RZj_C@V2PSQhk3*Z1-jy#<-GzEvh&IKOF4E&s-=Caun3y#`pJOS9*UN7|cb}gmso?F>HgkI9G~3@-g8i-5 zZnhU>QV`%^6ksSgC)!u}PGq&Wlr8B zxJgy8x3M^|cEgi7>fFbE)YozyZn^IMV%Cn2|B|u}9z8IB4!hj%820ybn;$)3h&lWD zPVY<=<&{$V>Z;zln5yj6{hD~>c=p%z&{!syt!f40r^tzze*Hl5p8dhf>zix7K>e1o3<<>v&g z)n4n|Ff{jl?CE^DCB*HES3z`P;@alYY0b+WU5gT}H>>d9Pv5_DQdV+JfYh98yQWv& za9z~)bapUH-VJ7@uMSK4`)lPNS)S=Vn6~-*_SI*p+oWd9zIC%#_f2N| z{tN}_-*dkd24^C-?7ln zDX6W{>|f4W&Z`2w|C8SwSe$T+LHgf>`FCENkT`u&!;a%bTx7^|5d4|_>SL~88W>&{$Vu^@I-FUPyx)2o z_xw6+}rtPTyuGf=!XvvAZW6pP8Zg;e2`)A-} zrMl{4Aw$G#9)|B6*^y!)Vn#Ne;IwAFCS|(43d6=2?UniSOV0cMt)GAQeZV>YrC)2A zf2T6N+$XWjw2bw(_X@rK8lT_uCfD|*8|yMM?3uh^Y3_{e`w=YP4*gPpmKXgt{Go1rsx0cE9dAe6>Ie2qLwW?8 zPfyFvGq!&B+wPm^`G5(JF28>E;)3~aOZ)u?4!84fj9R-Z#-9JV$BwzHPS3dC$gyHo zSNi6eH7{A26d9NlUcR4wC4IT|Uk|1vzOpkrZNKon@n&f2{yzxzD%a>tGTk%fUG8eAX2jSiN#k7l3R z=`0*|XXDK!$7){OdRLw>TW|So^%MS2*B+NT<-@vdrNfroTO1(Arn<`kL;Z|F!Rro;-PSMNr|)yPu|{Cxs{6UDncL`+nW+__L312@&Y1_#N4=l9CbDQ14SR z{IsZb&xt@0*Y!?G(F*sb3e7N*^;;=CJ(Rc1)aF)MPVlK?QxuEuf8VR?%JO5G*S}dM z)$_aamW71NNknt0%ksz0OJAo^6g_PbBw*?uw&X`lXSs55g}}2*)l34O&Oz(s-0vO} z-TAk&y|O@>QKH&sjgQ1@>kaE)*J)WS+h1H#(Q$iw{^KuSc)q{Cf4nB_;jy#QCpN8_ zy0m@igyi+Rdnd$v`w?`qW=%{%*7LpnP8%V1I|9gM)?pkeb=lX@c zrC2yx#9GP7HE_nNRRL3zm_#^Q7&snzd3kAG^166q!&DQECp+)6&faj@>!LqzfVDw; zQo%i;8QWRk*EU@=b4>{MzP0gB(Vw}KCkxwrJfh36@A?0!lZ68^lBTe2TB%nae6ad9 zU*-ISy{|XEtaV<0Xx-ym;h{IKU3syoMcFRC9qx#ZA@|z z;jKp{CUP4KR>k&Dep%OiU1ne2`sgB=nj>d&KHJ34n?K+Fb0dH4lle>s>i^&WQ~L7} zH;WSk%Q8c&^P7A$MLiE(V>9y7l#!8HV92)mD%Z77*B+RQDLnF#QTn#|X@jpTBZKPZ z$AVe=+m9~^I@b7i*83h!*<`uaO(zOpKjXc#r;yntHuFKiFL`NS8!>_Mrw7{Kea$^} zz-(n*^nv^Cg*UD@Z^*B2nZm$pD{ebUQqKI0)6p|mzLhW>*kkzc0%O9`E2mRu*6Z5+ zW0wCR2yxoJ-y5UWeptx=|4H_@KdF&gORp$4%$XTFW13T9;IfShi?$wn_>i$@V}#yx zY3`qToc5|rg&W_O6*&5S_~i1bTf$fQ2IEGB9KLf4557Kj>)*pdUQeI@H&$N%RIy|A zeM7JEW|`i*=3)`wGv{o{yuaymLqi27`ZfQ*@otkUpKIsg zX3HMKjo*J|tgW>=o7Jr@0f(rgUqx)9mVfTOJk>ByR~Lr_Ef)2Z|iSI=e;tle>KOy+v@m{Gg1zD zJ(hclpTFamIrDt|?$Xz3d=AE&y*v(ND0F;3n`S&CKx#+STDRV$m0Rq?cnwSiGP)Fg zTsauAl_8&{QdI|KvVVocnG2+Fgrf|2&qNQ~K7jddjNihlxyQT#i_sUh*$~L!-sTPg_GG<8|x) zm)8q7m@9EJ{;+eo@p8YPX4U*_zjD1UI$qv!$8x#v`m}p9|GP2cy5>onxtGjK zZ*P0qczel@ci%S7`{sN&PTYD*&_DBSKa|>B6!WYv-_CGPn5)FN+e)VIr`Wcc9NSO+ zNVa~r@?76-ub;=H{^TfYzb#yPS$*SftHjUG?im)&VBug`<0S5I@VofA^XET4mj65b zd)1rG@&CQb{{Q>?Cuw6q>05J?(%8ju>jTYseJ&@&USDYY<5|h6#L$3Ua!1{=SscWAnU)@vy|%-HafS}N%L)b{@$py>#me8zV_PmYN>B&?Dkh#f3CCFU-w%j^KHGy{@EX+aCg&EzviGV*d? zZY{K$&wU_k>#?G(i>_w%ey!@=6?ggOP0Od1Zk6-4t2W#&+8S*6M(1=vQBl(_!-}6z zr*DkWyM1SW{hDUOJd^Z!(=O+-oL$0|pi>e5?7m^r#?^DyhOgV9~Et`+v>b=f~^xP48}v(wUyMGbZRyapA@b zr=M>6wY2`vM)_^m_N`p^`tYuGr6mr=#$SKe6$F)TO6TvL_`d2@ve&-g#HwwNZS->{ zKIdNhb@TtH^&jW&`~ToUg5m7YWvjI2olmc+sCe@1^G;h!yIudEyj8dR&zxWRTl;q3 zL*f0OrDvRf?!>T9Tu@J{v~c4U-{AD9mpZ3!U$PDIntYARYRj9eUaH!v%?>lpKQ}n( zQ<|)3^&txl0*A{+-Y4#@AWm5AA-bNH&Z`j2nh_xGmH|1CCanHzX;KkDbTHD1~& zQO=ro`*ObiPg`tV_dF*3PPXcwx4Zvp9-6?Xb1VJ&9^Z{Owtn`DUtS*{!`GA<7^tsp z=;N6)=eL4#QH;NZt@&TpcDCqev6IEiB_%J%@$4@98ui-KXxrKN2TX}`)wph#S6}=+ zY2KBJHItZrygOR8m(BS7-1hWmhu7CU?7vr0RaTa}F(PSWOwz`PBMbVDCV6%rb(%YW zZu|-;OlYInNExclP#MD*&n2J=bofMjor27QJ-J$B z6@BmApU}+kCcs=mVybR=rDmI4b7J%SA3xu0{(N77q1x}?>{|tu{70Vsowpz>(q-S_ z2)*eB#~vu#|1_?){Wn#7zHQyhrPJ5VnK$?O>Ze^v3Gr*EMa1a5eDi0{wb!Np?ElY= zuSt&+dB5?R-Nu-;CrsL2?Fu_)vO?Oq*W6t@`R$v3huQttU4Q-h+AX1mFt4Lu(*J}D zPUI2|DD(|Yo;P>pOnH+_)2hQ$&zhC$*3`=|q_43xyLK-vP5O6~!j~Nzu0^f=x@py^ z<>{Mmp7y=G=G?h+Igw)9)@WJJKdYCP`t|GnpXUF5<)2Ht`sr8i>vzAtzOMQD>grYY z`Y+1o|6Bim7cXbK%>GaF{oLjAxEO!vIlO-LeYf_h&vT~a-}PoVA#r(j?0j~i1ylGO zMc3X`IlW1R-8ZD&=C9uI`j{D)8O*EJB&>NYrN93Z*Q>8qdk^b>O4v}m;oP>jt)KTe zOcd8Rd|-TAvv=#NG&$CRKc(-w2Z$<8VM@#ndH z|NcMk|NgGF{U?3CX5)_H?{S5Ng$p0?)ozVS+!>LuG3L>un#S;Vdz$=fU-8>#t*Ja- zv~$;{xb>N_*LU&l{BbpFZCGRK-}SJy0INgOdMy7un!f*2^XaFbe(hSvoxZm3bppq` zi_e!hb%nSy1bB3nFOt`qz$p6OfBoru}dnvV-#-8@$H zgYpa!*>5G@ZOFTJ{nf62iVZppr_Y?TN;h75y`8=Ndw*Zwz4SGeCmw{xUVnD5xqbbg z?e(AY{{-!gn}2st>FK+BDw(gZk1c**as2Y?*W2UnFVUQ4|Ko3e^3Iq?r%rYXG}I@? zTVyjTWxbN>HJszMQE^A$l#6S(?#;|N)3Ylt>ZSdug@Hn`>#y5ZmdwBT{&o%1F^L(= z9OqTGYd0QH`4#r zZcU9`q~o3OmUH5@$RC#f;=iAZ{Nr@|y5zSR_rqpxIIC}PO(#=6_24bvM^mR=?|rNB z>-)zzJI3cSca9t~4P$iZWLh}IDKvEYEKY+vj7N7uD0ChUU2tk;B)H>jz0sUwimP2 zR2{5V_s~q)_1;_Klu+d~$IPp%c%xQ-u$HpAtZ3`__FVay9UZ!krSp&b+%->|^X7ff zCB5$5r`2k?J6q=EdoR?}=M`rD$i!>aSW)9!$^L8ue=P=Fc~e+kNxD zcQxYovSpckbBbp*eeRt(HQy&~YS5~JYjPIPx;l*3ZuMd+lUgvf*iZ93U&xP|_G0Hp zdUkgo9#? z_ORwxL&Cug$7Vcx`0}N2_t8ha`ul!7nk8adIZglh=b!#^^78fX>VL=oyQl4MQ~3Gd z&I=8 zCXVddOrI%NUoUeEzP{ny*2Za7MYS0ZrR(~HOtx13`!`==&%+Gm@6WPN><&9LP4|Mq zHBZ}pT#XxfyBs|`D$AEDXI?t-naS$%1;YogkIY|SYP7bQzp+ZI>6&chiyE$r`vvA7 z7jB;-QpssIXR)kv#g=P}P5R%C zcF)gd7rl_>c<$Z0Zl=}w&+kvmIIIc0f8Fx`R{Ot)_-$%_d^oxJ^XHp4Z(8b#aa-Bj zFaP}c^R<}r!ot9~7@c{)-1mRk_+4Y^yqI-iw@lokvrj~LUyCX_r^#?CDmpTGy;WH| z16P_xwy#FqrNC|B3)wqQZ8|euS$(4ZU&D#N%*(zgw^-hNsQk9TYQ>F(xd-d}74~j_ zwblRUTM0)wyPOXaenD(6-x~_1z7cm*o4|Z9bFHrN?p>Mdj5e3fE1i9`=;yJ|pFeNE zv$Od5o0;kJDkq5ly#D|7|5xkxKD{QqUCiJ1=aSvEzrSg}|No$Uzne?Cvr~bjkpjzu zKrwd)uWXAP!^JIkZ_IEp%?U|do6UJ(gX6iyC$`HT+>qgOd1|6$_tz@k&hv28W@_TxGxj6eQW^VBI6sf$(_RB+Q(*&{3%yzRE+Oi(a;aXd+&ExoCeqqug zyUYuB|8^aEoVj{pVb%Bhy;tT&`5dpZWN?TSd;9MH)n`*5^YKZuY&QRpK1rrzRsL$f z30uuhZ(6fv)uyw>d!N_JOWizM$8`Hwd`-A^^SOt6<$r8^`?@_+Wd83v&-3Taohv(c zZhXSVh=ADZ5$msSiCe!hZv9Ei@IU|F*MCx%*)5+VReZz5EiyagvdNPFF zY{`4$glC94br)YYxe#^ypY)V9rf>7=EEG!~Rppoe-CdO&6Si~L8@HDiJq+{r^dH

rQ*e`bqAL4fn+5T~3eqI+5UX2xDNVfVcpQ+UplAuMv*-wP){e%$?PnPvTt4_p2{ z+kAfCkD2Fdz7^Mh&;P&HzV7eq`1^al>gMnJysdoCbH5Lo3=DNYlmBzre`veT%~-MK zpndFDwPojWlh+@P3HxK@8t<@X@4cfH<#*4Y*>G&p%GYM=TpmZ{Prqi@?kn?J@x8Q& zy(v%771kSl4lM`7I~>1=2L!nasQx!gP@lUqWRb}d#&xEiMvPNT{>rk28#pkucXs&v z+k36FcbVba6^&oEPR{kY&3OL*d#V@9?tThcWDQFXM^^ywtVxYoxbOTTRncV{C zPltFV>1;Jvv*W|@S=;3%g>OD^?3q?B_tS}U|4TfSdAV=eyI)g^=VUHj$MB`?{@)+# z@6I{@OfRmfGS1|E#rNOmIy%Z(FXaAc_Wxsc>V3id#;aMaSF>8@|C#=;ruz2b-S@A} z|NYqBGDDq*?e5IE!WNl4i+ORI$zWqU-EBQUz)?)>T*SjZ)%X(fu4>&Ih&dvPxi9& zOQq)qKl%CU$&)9C>aZcU}7R=Fy`+pX2{Lnr`>E{QtN6zmD<$|FC;DfBlo?;`aZ! z|FhLSo&V1$&%V%`Xevc! zF#nn{GhnM+TcVZHSN$!kT)bthK22CQ;n*zoQWob#yV(nMx{q(V-1)O!ZsMo*l^u5S z@2VFG1uqEl%4AD_{q@(kmoHzQKbv-yH~USkQk0OO_STw*!SnyjjsN+y|L@`H_5Z~G zP5N71|6F|KDy=7#d`m^T7G<1W%rN2kO!EuBe$VXq@Q?qWMZ8-6za1j&<@-L*wXoUQ z*#G~T{o?sQR?dHVzV4Us(dqj?Ezi%G_3ZhKp8=YSbWWE<7V&*}cv^q|r!8B*nKgK2 zul;Nj{&4Rx&IMc!ZZ4o@Q(J;^b+c^3jE+q(oOWtcfNP)z(~5P{Tcg(B&gMUCD0${c z=WaWpz2|;2OC)P9({`RU=~0hhGEdF!&!V%AUATEu^4e?DYo)!r*4;MM`!)ZPT8cAk z$*Sb%7w-JhaIDE%^n8lehW_hW(vFfhUtByQbK@_e%Bod;abWkK6hA`2Y9%{~zD~!)^b6{rZ1@ z_W%0)<4(GrCd-3DwtA_D^_iLXLdv)0vM_$wyK=M5YhAb7B5iLkO;gvrHba2R{Ii5i z+1Vpke*SHGs9zf;uVH?_B%gy{wV(Ij!5>n5dID_M)w!<7PWRfwzE`%uNz1C$G55)# zP7bfteF{tLTDQbAKG@5;h|ID)dOq;$9|f87Ozcd8CPhk4$wEex zPyE`roQbWj>)S6ck%>BAGEZ#U;~kvAy0&Irz1ix5r>{cq?^pELka_dUYG39a&%e80 zt=g^TaCd5APoUSzH|Or|W{>}MY5M&?e?IHSgnQ|Bt_bupbtz$dkp9W$_o4q^y8j<$ zURtwQbgilT*Q4xPWzO^&-#>mgHS$>0>(*Pemk}8>ZXGddX=+@r7hfE#&B+cIaxjB8?wNlwzQ`RpKdHCT& zM_*sxf+^bB<$JyB*w3G=dU|>brW|@5_kGs{IfK~KpRaPAJ}T6Glu5k1RsB+< z08e%3lJ}W6uDrVX?ne3Axx25l{9P8WrqZ->yI9{;=}Al*AD1;xsf%xac5(rm28(mz z2Z1f3YzK`E*e}ePH&@=a;>U+4+V#J#E}s&V|F3)hhtGe0p09f)Z2#w;yyaAp1CP}h zlz9?P#C(s`Y5(rpe0$x-t-oWgoU^njYqk>2yZbv-lGF11OuyS+U6nj|>33V! z-($rtpDy0lZ+htPap$Gt1so|tH~0UY7dX3Goo6riL<^O+V_}INz5Rx77u=r5ntLIP zOG}IUph$;@L{xo?I>)>-E&qkT-uWlHk!wD$#FM7mc6ah8ziyxF?WP*Mn(Ih%?_Z%$ zHpj274ljIstT&-)&mO@nuiIO$9kgoSQl+@cVdckyH&OCa7`JIMxVG%d>-yZy?dxL9 z(01awxAs!0wO^$fZF1Mf3QW8jWv$<9bw8l{)+g_BEMeA9n816Wp;P1%fceX^NHs$4X#kzHM>3IeJ|JB-5 zd}zqKx2yB;Vdq^tb{uGC=id;wK5*Yp-x+7qUfy!K7Nt-z`Pynxv2Im4n~H|dpNp@Q zGB-^53^&6ws6>N-1*cq|N(0BKdC0l#cvDS>Mg|t~n<3eX4)| zV{+-ejj!LP2y;DHouItB*Ujc$jlJf?2NPYQYV5LPn;!oCA$oE3;)(NHi=pF|!@O&6k56$7 zF}Ss^DUnI3x%MchjFV`(_GUR58I?@_J*#9x%FniFF+7htx>)x&bNnx<9CME|S~2fW zne-+pa7Qr;pAei_dM>u~+)kHYDSauLGQklM$@i{UK6A_dyKR-ueb26QTd%2|Hqz^A zTD>Z1ZBy4GV>P97o6byB3Ku&XyY%Yw|KIoj-(Qz!HhZVGx_aM~q@^OVGH3MdJ{*+) zZzZ_1)|T_!&T_$vzn^cuDV-K-YJ6he}T}A~Z8M!lse}8Q?J6>N?!m`$M)&&OMg;#fm3ybja z^A|onCr~qB+g_hc_12u{nL{oVaz`+ESJuo1)S*{u}Sq zIlXGtD!y(T`-@R;d)_-S$R$qfY0TPj!nbsZx4g01*}k*6_uVwUX?A2-3ziyGc$la{c%Z=+rwIsag_ipI-{ z4uPEtO_w4S1Xe0eidvj9?fHq%IyT~N>4I zujdrI9Ep0lO+@>&QHocyM{(ejK9M&E4<5{_GpNs>_w;<`+Ue`hyq9oI*?Mk5>P_wW z|GvooI~M=b|KH>1*H&Ns_3G;C8RygHh+A&bIbLJ8_-0Pq&78K!j~_oeb@JovxT=>= z`5QmFDOo8j+N9C7XZM^M+do-bm9lfC?pQ91p7cf0w>IqMZ_Q6ktFLl}uaC>ERZES$ zaPgwxr$rf&`+~ZX9vd>){m>J$u(CN)W9J+i`u6$j+0#=G+T7j}H|599=aqdwYx<(i z^S8yV2#rnN81d-K7m@aM_8DjSK&952>)Chq)k=r2oAV>KPUyk4*P>$GuGUt6A0;(* zcXO|~o^6tNC;zfZ?#mRFhJD{#Z%KW4ywy4+cbV3m?={*~-gYo8B=hJOwhrT}Cyi=Iz zgOotS4_8UAxwko*rCtWwp3{l{%QVj}{PscpH za1X_ahyGS?w{1;SSf{eP$fe$SM_5SECyC2EZyzUr@IT?AbC^YAib2|pvsxmq7d@9L zUwWK+wc!X0Tk@Ynum5@)ekfBvu=8K(9J3i(T{4mHiodyDoT?fY`m$NNp)|H#-g1H_ zE8FTNb+aBfy*$0lYEtLA=hl^<9DM9zA8bB(7cY4L&*YiFxE?@UC;Pt(V zyAe#YrWqeM+{4MpY@BR2J8^H+<9mCnE$r;vB1LALPd~AVhn<~$#`!ecrI#(+SLqZK z6kO>0)Vs3zXwt=hJ9k7R?2K8oE_;T6M6c=I2X>}cO;o#Yo5k+lr|kUH>~G!D?4tKG zWc=T}`@1uD)-u_2nbjIWM;9ws?h3zVourc@p0+|gjwx8=Df8N|n~%G@b1O2eZ)8`f zt87p8|GkPm`RAW4Z{B{qx@KEc<^GoJkO}WyLzYCpzanzu_DgmC_hv6NEpOC2iMLt* z{Sh^%r7UYDkBIuk9m_3Bw2nX9SmbSyl%|preS1#XdbcLC^O4onRnIOx?|n7lb6uMS zqtHT|=@-(4CUU5F9@w@>@ts=L+S!NocvxaQr8GXOUUs>?ZuUCXMrIEe|4BuG*CQd(KOnn6f{mYH)`yT zTi^R<^6v?E{E_YZ|0?wu&N$ES;IgCeF&iHrpLx~9BU>J1#XdfGIQY(Pv24gUe3?|{D&iN)eHXqDiv{MOv_`wmbCNBrP|oVI^K8c9);yI+`PN{yVC>v zBa{8*9=`anLEPte@2Q+0*AGTDA8xjs^^E0OCDX2`wVQv5%sU-%Qdj=kw1&O&*&i6ivEJ@W zk>0k^ugPzB_q#)?{2hmGH1ghm{~_>hYhU9U0cNwWKaOoM+30R**3;JMuh7eM(B8pA zcIRFhr%6%{N!xCF*ev+%@hi%07XNY&l^F+D`7g7uynm5@qRVo>DE})0TP%NAY|K1T zby9D~s@oShtEM*Ew;CQhy*6>8oyCmD=l|~HfB52s087)xeJ&R)<$eAuTf6s5{@SBSI}a4?Jao8y z`HmesUVKgENKp*-+E~0Uy!-9-qURkiEL6H;isJ7G9-m~J+jDY8B=ZG3=Sya-H-Fxh z58HPnL5SI7x|3$r@%3AeUA!oG@86f(1^*8^&k&H{=i@7Q`s9Yc?%LO7#S@=f&RWKK ze({Gp#pf5U%zon9_jT8?q>T)M4_7XqcPQB3uJQ2U!(qG3k3IPEhUfeH>gI((Qu=$p z6n$WndGz4}gS&hC+l||FS2p*j&iI$|EUuMlw+zSp$USMZmK{8KvT(JHj+pnHxpN=B zd9%h>QpY(nDa2fPWyg|C3#01mX}N1&r+X>=>b;%wdgX`f_TSf)|BozMZ~gMdvivu* z?p-f82vC#}yy`m9{>Og%ZyUK8ejIuKr%j;YxDKOA*2lV?ziP{4y%y>!-(ITpCij(; z=GvPRj%OObSQIWbBZZ;uALBc(sBM#(Jp{8;P%`6IrHVhy?D9q1Tz^-vU};%-CX4TrTxVhyV)&Mc-F7q;&6E9JE=g=qmEjx z`)0jMH)AXM(GU}=dhgRR^M|LdY6s-DdU9Oz5NWQc*2*-B`W$ENX>2n2<9gAKMnm0= z8_rGKY$n6LJ-74mYel_HA5E=KPMsk;e}4Rh!|nWqWp#Z=i#nesb$J?y!m?$u=v)tLTV*e|ra zuFN=gkJUt>>)SG;h2FI9{O5P;E6iPqv%S%~#U?%yG~1Q>0ij3)VNJ4@yV7iB#UKW?l)nEYs)FMRD7mHbM2bt-%TPv6a` z?nN2~tJ4bJ6x7tTJYKAPCe8RoiuwNRyR&9puv}B(and1#XVoSadD(-O?N6(ET?3fT zojYGxR`%{PtE1$K=J>>%H~IOKkMJbxSQ*Dnd1HAdI5Vo=#pLzUCA(**t*V~4{z`@A zHHmkHRhJ%_dNYKF9{qieS%B$-hPupS;ica+d!=62i0aQc{Y&86XNHoU1<%ehNSsZM zT~{TcnHg;U;B2g6elXLdIW_04C%9}qIk%?2qb2Is7MFq*ECth*GCUnVMMx>i-V46K z`hK41MB&d5+tx1#_L?Ad#p21+Om{DplbQui4H*mAwq!P{#6DEwoXfGQf7{^>YlZ8( zrf8Z3U5ffWB|PKVk+t>tOSq$6Le$ zb1o>WyZ7!=@TTXUOR|G`?)`Y>)^F@r=bQTbVP3rjV{wJ8{kz!uPkZkAFuK~zJ{vQS zo3WzTh#~g%jVqjgH4aw!Xa+1X+vUDD>patU{XYx*`Q@MHmocn9^5fXuzOakSwrqIF z_h8-I4{0*;FZmDronsd~D_j2eBNdaT-!B^^d@g)84bWduR%HLZT83ql!%4n*zpR`u z?MW6mb8+jDrB~)Ry!-pbDQEqhNo?yc^M5hnX%y8qr)x+QpvVS?t{-M43^Ef!g0 z8`ru~RwGw)_0uos^k&?iFk8Pav8CQWndZ>g>wAmOD=r8PHGSzSvCjANPZ=*w8CltFx^?LbJul2qwy(9X zd!(5!v3#>mc7ArhZi#fy_N9-nwI7$d9~^VLub;2bVE)6e>#MnZlRrFo=v?!4_4$OY zaSPYYz7`yKy;OgyQ2Do)esyb93vX>ttvGk-v#l9d^_nSVT_61JZeLql7|rU?mCT*1 z$gqAQQ$xbL8|`y_H$J?0+iCBQ>`5}OI`1hzEZL%+pl^Na^h)90r?<9WIlGOqP$lB~ zP3QAh{T9FMShqTEQ{a0hYc`bxgY|XJXFJZ{^m2yxVG|TpR+p9tGlh?(v>*#WS8n47RxvN-*D83J!o>fY(Yug z{CV>pzIh{(uwV^nd+n+<0cW*B6vgMWox5__;_J6#vly2?QJdC%G}+qLn%OC!`(I-s zL*GHox@{l-z3`G}D_LJQW$hv%Z>Gx%v)GPQ^!UzDlek~(CDX2a`Ej*mb^q;kHzPbJ zE^}YC>PXVY1Kj#G(#w}G-}^iG`QHz}WOi@cuDLfaMd#0z_k5lQX589v*4gap8ja9N zt5-GUJ1Vj~*c!;N;`H=)r{2Cl_51sb?-f1we*ZkShwGf>gs{DjWu<;q9P+uo{rSSz z@)MpMGhgy|qAbsHM*EYM{7WCy9g+7`UJ!41f!F9&*Y~Q8EgaJRa=))=_k7Xt@L-sD z{bpu>(9L5n`dE&97MkC`a=zNa-YcF}=8HEQTwsg5`D4xEH}XLYSr2sPDb3#9lx}jJ zk>|9YXX%ff%v~ljziVo$vW|ynHGRrmaWmIrsWkV?4)bJZF}7Pqr#Ak+d`v%b+QEo? zjXP7OJAZ1k7EPUAWVH3e@z~mFskzE?f9AB=oOjBcb)K=gHompExbbS$)74UkHY~4* zU2)-+jqS9UeV zeYkh!pSq_*$^Y+t)jC3bQQXJox2py5HP2&_e&$pX%eb4-V~-=#gu07DnbpQ~C(2py zH%aue{ko!l@GncTzOIp2$E}j4*Gwh5CgdvjRLAN!9^Dc5@4o&Wj#%MZ|BAL{XJvD& zmKx+vF}<_&d(`erb(-5_Q`GJ@O5I*yc=m-v>MobLZ|yR7=$wvf|660nf3}>%<@(;@ zy`Uw$&DM7pt=ub6hn||X7DuoClDqrKO4E|rr*4(;@Nl`#i9T>H_n+gw-#lvXC38!Km1lxEBNt;uub{W9UU0D0R)yn#W?ZXU|MaDiC_|zA^GR_G zf3H8^XEXmCgTo`y4&}ynM*C35wxZp)_C4r3&-1|Xl)^`roHxsUFRk<_f1t_P@%Mj* z@vD-yyjvch8UAv0w6G@{iyM7WD)BkG@U>uHZ&&M=2*bM#owv&`&Yj%JIXU_7`SM+x z7iad%&MADmQN#7ZOs6@oJr=G`G;!^X?GOAXE48G|bLsC1GYmZ~&hGss($<`rlYivx zh9i0LD+JAL)Ww_SjizjMi;}-m+kQ4;_j_xzB;`_}{ohYN6?$FTyDQVl_TMJn3wCP{ zCK?D&5NCbn_~@%+g!1X#Apt6@S906r22K9PA~DI(^iklA@@pse9juBzFh{DwEOpE5 zsNmgcxyy28u9$9r)cee%zqt5E6#M_&w+jVlC5DC`b*^t0XgJ=InB0-O`DuM6Q6ioC$@W5U0ykD+udVsyRY-Kx3^nZEjoEO zUxjn^SEo#U^6W5+U=d?(Q-4>G28vmM=}Q_l9$T{ZLerMdl|Zu(2! zFPob1`|~qt)}?1V^p}gZ!M9{DB=?2qKdJwIa_W1of0qvyeV?+u#L)k}xtX8ekv1;I56V+hdY1}4 zdi{K++q~2juhU*HIg-nq+TTa;|;GhfHrKfO?` z#Am^v@VxOe6}1QxqEd_NYS(LyXW%i3szF+i#^moSpPLdFR^W$Ak0xj|rR9pED*mDt#|5iF^BhL27|e$M5GB z$7*i9=(3Q|y>j)XdfI+DMbDCnB}_@jwRilTyN$JAz0ju5<|_Ghd-@%0_^)W{?pc0j zKR;*2Ro!=5GG98*CxqX;wOHVW?eBT{D+)Ag>TdT{alI7OQai?Weo40Dnz{F%>3hWI z=Q!PsxF9dL=$h26&5bATZZrS*Q+EIKy*pL!ADcC$dwbdq(8?L!Yo)!VvCf)K8{-a3 zy;jc%GQZ;G`f`qCh4UtZtwCF#9sN?=quEw6k1c=V@A9?Ne^0u-B1JOW*>mCT9c}+| zIxn3$XSsaqx^5-=`DfF<^FJ$AWLU4tsIb)G+}kNnkAM0bUCZ1*S(0zb&py_I_+NdE zc3xK&eB^7~`;W2t&i50)A03I`5O{Bg;E&(2EavjY)AA*PwJMypJ$sVbHtm38G)oV^ z&?{3ur*PSu-v!FN9Oh?y`K0f$nl;L}#$V23GH>&2$&RJ(4c+(X7Q~9}ySiSU&86#B zYrPlW{HP1@+%t=(r^vEzY^dCF{+OMp;O{+o(aYst|2_P!YWAwY>%KQSizSTj#vbaL zWHsqVs^3@lKzGxG8-Fxx`3q+yT)&Z>Amm+lzKtPsO=D)x4917m*QMDdHJS~XKKuT-}(Cbx|AZr{l-0~^*jqtDOztWc&B~!-B*c4amusKnr)x+ zbi9G7d9bVu388eY=T2$cWT%>4Tli~7W= zW>w5RCc=xBs1zx@?-!Eyn#B@WuMudz)G~K*Pova@>Hl{NIn7dnNyXu#&lo*L9xD+gA zRzyC?JYVv$h%?#PO|5oYdo@u&WCwJ=Gg)n!PNc)`uQ(i5%YkS!`gDpgBi@>t1 z$u^fJ*eo#bKOnJQ>d3~6$D&LYa$fvkb3DZP_7`;xb%uo;a$P#-Cr=S?Wwe^P|C^Z> z_l14O6*qPtf4RnW@4AgKYpb3ezwQ*d*Qe@rVY@=bsavnT`t@~zgvI}Emp_zVSuLM!X!GsY96#oFr~gTtbsyn&^qk7TEA{0^Y{0GB z4X3Anxx#S#?Sd70R}ELlWo-W2JjwCh^3YuukJU1#if2fi`#JG&T~J)PlKj%GCAUJ) zx9)p!&i{3D(3M`bc{{|)O${Wi4lj?nJ6-d%RA1QJt2?AGuXgF!Z+vZKZhX+>y7Jxk zzF2O#qb{@>}u&pVMz^vhVN7{<&IY zQ^4!_?S*Fwvl8b0zTH(2trMOT%pmdJ;*?CAet*rrNTsjxyOk=nZHvPy>_RREs6@I&qImJ0@bg%n1ckbb$ok#9ge=jK9m@##72G5=~ zf?q<9bY3_5uw0Yj`JByOE5ANGcu?!!Mt{`?fd==4vcj~As9PqbfxI`P}_Dy`v}ozExSu*n7Kddu+3q)Ul6x7q&TOU3gcvxW{1SO!?UY7GgJlKYqZTTfg&u zZ2p9%2XWT-k9_o>%{j4mp{w-PAFI^!zp$xYPIKQ=w&KFE#`5Pjx{8Z?i;lh%4{ls) zuCTIp2J_f zZf~w_`(C;@>Ub^F^xTcM({6pZAKIc>#dU3`nW(|CmL;!`Y+W55D8{<)@1yRDhpplp zW9GHrs<|z_a?Z51y(`=5d|zrwKYIR1l({#<=W5hq4JJknuP2oTzn{+3Pvl`yKJ2w=k731!2aNl^-q~Jb#j#JeaL()xQLN8v_r~@wQu3*tFFfgJlzAVUTW|rJnab|IhMc zu|@y)O+3|5qTV&}cJ)h!96o_pwFf7CW8Lf7wD;6rN4}&4hA-R#UyFYI74i5K^!CWU zEAbQG{Ih&}>Vm)Tk~(I&2`jcqO!#%>==r~o`j+HGCT#mE@IH3&!{+jh|M>6LbXEM= zy(=p3_fI41x4G7 zeaL?{wdcYIO)b{VtForHDwzm>3T2Wk`LTDCM%1Q>TD8u`akms!mHTaZH&g!i{mo~$ zomi=L=uE-OW12Sgp;PajPSE8$%(R8UMoDC%@`1$5G5d|hP4?){72m6Ub65V$5E;+BwbDE5Z#)r~$nCg(o-<+f z!9GnzLC;SMrvHAvO`L)E*VoG*jyhW@%-z+_Tkjap>#_S?uC(-=KFxb?SZ>U>>3A4& zQ01z_5oyi|dd-JUs_Z}abZ?|x$H(ujd0Yv%{4B3>bXW;LxZ+p+{;2v+fgQQ5Z~C3L zPX4MKnCyyxP}NU+93sUmEFutcgzeDOpjE6FjwV*;<(I5@`S#cL&poPX;bBUyoE!}f43WV{&P{&Y zD0GL9sUqQ|_Onm!$9`J`{hHk5sPg<}aBfpeu%UWF9Us$%HJ2<8e*6CDK&`20ta!(L z;iXJ=?MT{6-#c@ZV3Lg#72*xkiRD zN8kGKtNnlIw~qp%b?-GVu=|Uuus(Y(a)ZNK^7-4cY&8d$2c;MGOx9etimThTb<>(7 z_r2GIX*VnBh#!+*sM9-l^K3qjd+~2wdY7$f4z_>4i_bUq@uNpZ1@EPmm)G_2Ps?^r z<$CHPeqcAtgIULmHeOhAWq;1BZ}toyv>Etj&eYUn|NcVQGJUO%ahkT)Tr2Er9sLj1A!}K8HlYuo_3#$^-Av`#){kz!d$+wdN_a}sHtXI! zCjvxfzTbNMdL7r=V6Vi@cON}oKL5eb?&LexR)>DS-`n2Y?3}YbI%m6dOl+>rlec%+ zl9`tNjFlGP2>$%8@RN#mvAaTvXY=L0%m^Wk&GhINFPKkFe-RKtnc|R~=qV+N*i7jkzm_1*}AF*sv5jnPp`#N9161UXy;3tFV&Y;RwcGy@ z?BnDA@ZzF#N@QC*zqD~s`1KXpkNFqm7TE9K@x^7wHq*xyrFSEo6`t;&zwY&(pT0cb zPrvNkwa&Hl&SK_&#W%9<9{8Cib0ze*-UIIy@qTJMmLzPx`QXhNMWMFp01?X$p2)(T zpuLJLZ(CRCR6lyuvGVK;v*yQa5+cc$ttY503)ttdVoUL|Cr^uZif<{L&hVzN=Kc45 z-TC#;&F?BzF+Mo6jbTeevWs@r90`eV_H&)uW!GIxKlKZnka`ML|H||-gaThI_r14w$p||^F)?0h}p7ePvdRc02zO&J4!-*T$)AkjW zU42rj#+xV2*}=S8kx^=s_}d!>>y=qdc3e9Y<8d~?dx|hmY3$=4PrYlt-88nTD3Cw> z^bnhC^4;5FtYY1*>)-5NclhAJ#-F>d{VU$K)>C4}*&BDRZF+FGSmyU#PuAV0ua5Co zbL_MCPj_M2y>sXFVvlwg<}>$C{@Ww(zGl^_N$k}n4(|%zov$ox++@Ibf1v=whPd?~ zpPYQGVzuG4=Y@sBx8Gh{e|v`Ur&-Uw#J{$km@4^f7Q*t) zea{a`#=GG~U6Vo&f7M!cZ(CZyWd&X1+wHSetaB%@oOmD?_SGikT>lqAwqq_uPxM#( z%5;!;;u2q{!`Y#{Rq=VRita~Cm5$by%=0apix#Z@}-{RaJ!%6Q0m+36HTmN~{fkmtK$ThD1*S+Vu<_a-Uv1=1LOm7$N)lQjt=;6hMo@^}Z zll0V26*H{Sm}q?Vmy*-}Ps!P9El(TGd(Budo#D=h6PtSOwz@a%wpZ&g{8qg)GIK5a zwxz`-XC~JM@|Ol{d@+{lP!6|U)N-v}V3zY$+pY(BUBBO`Jjp-K88q3mVf}{V$5>)- zE3Vr0^t<9DhMt)sNAIxrePPbI>Nim`K&gdayK-lS4XXm{@8TPMA5Xe2`BcWcB||0u z=2EDlB^p0n@z;`%Z*Cgb z{CL=IVPo?}bZhhT%{^6?35`-G66DqEqq3)*xp3&|dB=Zx2h68AKX7|=Ya8>;2YF4) zHY&S?e3ibq*e2o1>F;07&iGaTf5r8D(Tc*W`vkSLbomn+4>vQ1gg({&zewZ5hl|cN zAC~fe_;9e+ev|ptL!P0Z=K2QBVVv~jdyU}IhPy`RKgXLP zE*(-zwAgcQPf@|-1O0oy+Zsr(iR3xSul?X&$FlZSf-YsxB?Zo%IlYbP*RP5IQC8+( zmt<2oH2Y7oC#zU0c=^d#>}`0G;AB!{!IAeyr(2k_JtukxxAL1t=ADV{Y%V(+wir%h zRPmGWs4zK_;=5A1KG@^lM6p<*r7OPoOc#A2)4nZyB0~==<9v^R)&e z-{fx`j2>GUk`%?iKmYSbNWZUtmltI2ep3F^wdr5%xp}FpR-f7wyKdUuSf&qE z0u2h%^4?5I$MUpxRA)@k5GXt7yUL3H>bF-P9XEWsF_Bl#Mh?!A}6%|h?R`J)TP8Jisc7I!-B4uAIX zx-bVz%M!zGLnbc!oC{$K6WNb?@hWc-Sym|V<(3V@m*VGnZg+ecdpckGus)CW+2Jmn zCA>$X!R_`|xpi{4zkCm6@=;g5Q*2PyA?`UdX{m_apBKtDwZE=xe&)L&XK{k#IvJd)coWxi9ONQ6u0ykNU2*N}c z)~j!1TxeRBSx{NoYGW+S{QByl#fsN`MM{@nG~>Osjq}8WPrrXKsW7hlVB+Rb8K*DS z{f&>YqL!l}I>bh8ztrTZkLEAk6pAM9WLbCmXt+9OQcR@P_myp}jhL-exA* z7;F<)bD8yT)32}3>?FdDHQu@@;P`!+-M61AQ+~6ZbZrm|FwnDj(b3Vp#IyZX%?sg1 z0l|W<#*3!Pe7E#uH2*02Wxuh^R8$hF`F^Kc*wATa^u34j6Qz8mC;d3n`890QlbtHT zqE~L*nm?K64DYd^z&swdZ$3ZPN!yg?N$c9hJe}?JDAquY{eJh%Z#$ko__xKkdAYy+ z!J9WNr=4C}e|O#Mvy0{|DXcm7sq~S;G$-z)cZVh7Rc4y7#7R#4wcy7+t=mN$QB2={ z-s*djS}CWLd@X*_X3<|yuc~f&w;@XZFGtdZlurfcXL;Rtwd>f?r>a}h{Of#TH`h+; z(ww;bcER*JpTByjF+{yC+ZuIM-#_l(L-V?y)Bl}}W%?l1w{qsCEBniJ8R|cO{E~e> zl*xxJVB<-4%_CC8T4R=43B$V8EE22AXB~Kd^S^TF)<4^?N$LCh zfBf^4drR)?uiv(&S%g22SfC!Ty-%z7`>ev>39t5)*RG2#+NPQLS@X)_g<_kQKCEEu z;;5YX_|GF5@#*3g5%MZuMGpN={C?4d*KBrgc%Y1P-2GdZ>db%6c0SOzdy|fRWo6N) z{ORreeg8lH|J$Ede{MI+12$cTt|M_llHVk*Ov~b5@~e2a(S=y){hMZU9FN?>|88M} zZ$i;yId-13ABHb>dYkUGD4uTh+j;))lmvfG2Bj-!{aG(ubn%vw=v^u`?}@q5!G;MA zFHW|a@cDjTuvhTgyNP*C9CPYZ?ln|f%vi$xkoRfX-|Pr6%jUOIk1jG8Z{>@3JtTWz z@1uDi)vP$1)^cA9_Ba{BonP?(`ONu!0WEWdwyrDx|MB?z2XEe-Id?UE@yU)m@sG0K zUEBRrXYV|_&3qE?izh7n_ub?T)4PnfJ%(QnXD6Dl9eR-e@5xR{@s!(#BG+Hrw^Xp2 z{f)3qbiVhQ#rGeV3SC?2+46eb%IrJlNiN5krn*?2-?W^4^;bg%o4P+g_!uj$wx_(S zsy@qdJDzP(Y|z4ca>c7=&F5A143?7BoBL$3Z_4rzp$Qv)q$*izKYx4Sv4Z`Y@9k=K zf74}BS$Q`6I%uH8|NGzL^HU4#*;m!F?ONWT&@m;k-<|2#5zR%OYz^Hx+$uZy3i*UH zxZ4*w@v(&-j9Q%ibMA8H)!)3@y);uQr}^X@*E($|xMnBE(K%fZd_OqjmZ|oB zk#P5HWo8}L;wR7hZi~L#nS1@=ar=LUuXY_P+S$W0J7mFk`PcWBulf+8Aiu5EAS%Qo zCHMMwhb!whZfv-}SlL8^f60-MhG4FoS!}n@ilv6KB~R7lZ`AZ*Y3n_53NMfoa|f>NxA>*grE+j}41h}GC{$Mhg#v*ykKuNz5ztlzHi)*Ihgb-!oM zul|7P+Z!zekIjt`WPq*(F!`(V%Yc(3`s3b{zU%dLX8o_L(N#21xl_{a>9os@|JPi> z=?mPoe|g0haf)azT-Pq}vmyAo^2f?UUA7|9T!I`cy)-0$E!8#c*pEwul3y8rUpL3i?E6dg`3)DV@9kze@Mk*PslJUl?{B0}@9@xyoXpkm(xtI{ zTkoNi;*3(g)nzNWA2e0zusvaEHk-}c_2|$GwkJEw?Wf%TJ4JflpPs&$9e4AXEnkEv z+&`}Md)JCv+IA;$;?KBF{G7D&&i)B|xu0HlXSkzsK+nVE-OHZTjhY(eS;ljsCd~ZK zQO>gOVTI&zp}l%*BHI2sXy)fUvwpbj`u@u;&pwe3_m+JXDjad!ySmpKGE6BevpsF3A0f={eN+4T84Fw6!|n35 zJ?nA{|2<&jeH&{PMunD!`0|o@qYcvy|LU1w+$_ef?xbE-MYVQ zEAxz*pKYG6TJ_CtBB;~dF1)^gO*VP&+>I0Wix}UY$Phd`?$3?6n>SvJ*)-qKf9FG9 z*}|h5vl>3LUz~W9$L!}1+3y!F^R~wcnXlX+uCA6Gs*rJEQ-k|E&5!wkS1(80lzo%u z$mAk)ZF!5WqLcce0A7Qo`&jyAzBoC^EN6cBX1=e{F*mpM*;PVpyXuY)gi<6>~rPs_IrwlWez6m=deMK7E;poNZ0V|1aDBsm+t$f8gd#$#dt= zfePn66@@)V550IeJ+#v`G;wQG)!jcj%KCh2!i+O{mP}}VcK-Jbmm4k+BP?e z7kCZ)R;7FrNcAsVq$td2o$07KzwyQDSw?ebMekj*KKn+V=hr#$u3wGCo*Ym6nf&DN z&PAEhQ=XW1EPOS46=PcDyZzqcFCIOy^I+J-(=Ts-=Qz-g2Ayf%Q^HKwukjM8Y+PmZ%)+lW!0FAqxanpGoDUVY*msu2`Y)M! z{n&{wMJCg<-k*vKGkSi> zov;t}vu`t;@o|m3@M<0Fhbn&cg_^4yZWyHM#XLD)HG?_-_mxMp_pj6rNzHs>`}q6Y zrN3SF?|%RP_dVOAQ>%YOBpnN9sOfAlZ4h(db>dx+mf+o^Eif-iaSqQW*8_)E-B|UA zHz`}^v-H;ou8Rb=bJ;{0J>Ur_dMCefTk~{oztvxtKB;dM4BdZ4`cptm#sPH+1;#t4 z75l%;EBEd7QJo#k)`bY{abI({SyFuW^tVz84^0W_ZWk@|LU0fgZ zM_zel^n;I&-77vFG1z*0+tHIRHU0ejK0G>V7`LaQ@%j1q8}sKjacJm7=538i+!`gh zf?{+`1hPYTKlQ?mQu5!4MSz#n?ld8O%5wR-oIiiqi*;8{oTVCA1dzqbC7-C zh8;WheBnI!@uOkf9*bkk&(B-9jjz15lsiU0+``7{$iahBr=JR?MpjkEwzEkH#j!a! zbDFq(d#su?!zuPyfW-Fcu`w|Zo}Sd)a?QdbqIzz9_|<$fX`8=Kf^}ALz2EzNUHx92 z(;xoa*%)YZS*4^hey)b@#FV5U;!BSpb&bEE8 z|4v+S?CkzxhIqyge9Yf-a&mR+H?SxtD=0giKH#44M_2mC^fMX^TNIK_y$-M)C}!K| z-?RMN-+QbdIvRCnmL1}3FcvWR$-~0Zwkelw{u+<<4Gu@z-4m-bZDp*4mbFV+p71>J z-D9#>L*UnUuE|PD3!JrjUd?iy_@wRl!VrN7_C?ysT$Q^!7H^D7y`GtIw{a_5V8&l* z^|i^bE5oL#z$`Gd?m)FYspY zXVA%Yy~|+HevFmFl0#HlzgTUX4a*Pvm)jZ~xaW9GdU3b?nPcs@BaWX$UjP4ob@v%t zjddk=i|4pG6ue~?Zr&GrsB`juMwy%T?MK~Jq7D1@pO4tOmp`iXZe31H;PI}S-$jbw zEYqi^&THAZx@xv|yNtT~vHP|z|7R^bxV!93?(Vf4Z|2optu8HX?e6xDiOaok#dOUA5_pZtEtEy|MX$Pc*y^+ZLp`7U^6RwLd@4zWtii_r7ZUg_j$x#zsDBwi9f0Q>h`xcY^yAP z*{CV$bx#tn{>5-dmBHMbVFqX?XMgCkU~W@ZeWUFAkLNboJ@0XoTvpWQy4B%!S>RXs zu+1ihE7@1R)vw#9aEx7yGl5|`&mTd?dYO~g<(Phi?!MqSSoDK-c0;JQkN%XN zIJY9;TxvkC)1qK2@!t{Q?>8Iz*@mlM;VRd><14HA^}s%V+a=fDFsr}MDm@{$ZTGoz zX5Swq$f~qOWnU@nUAqq*a--7&s-f5BjW~`nD`vnBg${jU2P)SN}gJv6&bbKCwCfH7W38*3LWD zr}ug@tgC!dd9JHt`LncC{s6s0g`MZ;9kpQ%?G3G9>|s$3kDAiz$q;mL?&HeRi)<2C zj&d-iojlOxBf6e(4&x7HKGXjnmm!cwJ$!i?u_B{05F|hdUc@>=ochnb`U;KqvN0;I{=+Zf<$Z z>)0!C>5MCbjS7FoQpe1-)@-Hyj%$*g?2?_#l5@L4LS+A&W5=E&X`3Bmuiv=QlDK>A#Ve+I z+o$i?vBTy1){I%#CUZTNP-4j09(`wjJ^xPA50+LoCada7A4gAkS9`boNeuIR+j_nO z7QS&YF$*%KrlcBr|IOD@xaQk?E9`G>wj0ywO?#%T`A|Ax;dM@_36keut=g1xYLkVv zMMUg9RfhF~i~*6$HtSq2&c73KRW4^joVE2{&1F@)7E4cit1VX9w=KKs*L(xE1kca> zUotOFzASV#``Ce6BgfFj4>AY*Q{ot{tuo}l^U1vAyJ7U<(*FL&|Jt*YGSub>eDF@t zVZ6c+6+ZKJ*a3ZpAEpdbYn5Hq7NqA)>i(UuCs}v~-?F<2a_qmQmhJse%TS*+v3Wi7 z4oAjiZ**M#<8V%*8f_4<6Q8`dzhG5)kdO z70%i8%y;pH`s;=pbLT&pe`(hDIoXavz8k*)Wp+x1fOOIOy^>Qp_Rd*6hA(&F1U zUR1x1do8dcr5cmDq8|9pMF>)Z<2D4|8!u{)j%3U0fdyTETp-1-j>4%YU2yzw%6 z{QAkYLuJv?-ATQ>-tBof>5hH1Y}0l1x7D`~%I_5|*c_vyKhL)M-`)H_OY{F-jAi-| zWo(d<_HNg@*Pm>jTSRyZwMQ2es!16vGxh(K@P7A+Pd4t6Q!{2=`*=)f!ctczA>BgD zBz46P<&HlNgnjLjIM48B-VDyLvVHc<1^v2S3BP|VS9+Nsp?B~U+iSL-wp@qpQ-7!* zsW`7D_5J1+k$1um-M58qNOEIO@NQ{3+jOq;Vq*c*gX3p*Yy}S^o_i z@*6(vYwpioRFpb-Lb}19w)IUPv<>#Oonm`-?6V}#qK}FV{Y=mP6(lKmurwW*=OmW2 zg<+q%Z~?=NT>n{2-+o5em)d-AdGGS~&yO1+T&(7(5r&#(DatF-F9P{Z|- zl*lrs3*1Uu6QA)-yn0R~Fw^HD{{zR+$-7oQzr*9Vc8!kq>mJph;|<@Ze_)-UWM*6T zc7E}Br;lB~@BPtlx+owi%aAswxq#&XM_i=De8wLO6GZDeIoXe#V90T_VE-UDyK8=; z8pA&R2Zqc`Rpkz`J?&4N#F)DJ>-ikj_|9nu{2hPD-v0mJlEMAj5sl=@2{oJtezWY! z&Tl#9^j%eQZ_`xU>%ST5BoCaAc4^#cE>I-?m2qauqgn?0Cdup;h0C7j9zLi}F-&(b zyqqw@#(*P0WXAEH+;6|X{(oyOrz+>!_ri1vU&F2`sW%Lue3H($ za?;F;S9o8&6`T81G^G2~Vu?>tZ;iQrnTgKTWLcnfDt*^mJ%$JT|Bk-Dqsp-Uv4xGz zkM4E3|2sPVaW$}?S(EGEHgjf@MA)ICm1irno>gY)m1i*g9V%-66y+nveRU4DfoW-TX&#mzH+k~gTwIymWJ;Reh|L5@ubJG9;p_g z1J^k!rZ<{O@-`JSXfw1=`6p}k6AYiUw<7{Gb z!ujRH3+rZ7Z&pxvSRwI_nd^Ywmr8Nz`sqjW{!2*trmc^Dcz)%fGRe%NZDzT**^=W| zirwZx8a=F@SH5Dipi;1=+~p7_t<7gQmKMZ{I=pAexGhpSFF7#O zqJKi?`NRkFy_j~bin`Ly&aM+UV`uxJyBn{6+ro9K1$x{QY8W0ccgvOJ{Q4_@%V96Wg@X>irOjGwZ#evG zPpIMV`932s((16-0eOas69)F1XTD|U`6I==pYhoBgh`D&2RIuO!@rp{LGKS z5|`rH)U}v(W_+|W=99c(u$b|2JmU{`hJSL#|0Ip$Zk!J=*zln4&qVg`uRgphbzpQC z*eqiB>gjBYD=+)2J_iSD{LWjpk11q}@r8KzywY_OPRXzECD_NSbF8kE2N_UUc8(P`JBvfC2V zcj-@k)Z*ZJE=wrua_sX?qh#AVwVQ6NTCpKU$JM5jxAy6N7pVg(Q?jd%+ivHRX0TTY zervbU_K#4S(E^5K#}@zGMITst=BGC)O_tcho{)U_rmaAcnd5gR2jwel=NW5~&VNW( zSR+~Cci{b@Gym-yW;+->uG{I#AycxiMN)N*?yUzmes8Va%glXUSi+w1VYR{Yf2D=C zF-4PaUu$4{$aJ8!;bpYh69;3v41p%S5dV({Z=e0W+29-J6v^fz+P~^r^%&J#dN_7W z)X6XE)%2>^yPApbsbUdr@n zLG1~NinIz>pI5;iO}C^)XKu=x_v`Mu_cm9zNeJ7{-ahT-rhnE~e4BTf1+)99-CT2h zOZ2mSjlZl8*#}?$+UCJ)Y%E^6Q2gnmDD~p$40m*jFEg0TPA(}txxYNtd{(DbMWBDm zp(4G?>naVWL_YcWhI|$|x8vpl69qP|9S3ssT9VB|zcVMT(P`et5FohWO3!kZKOH^? zY8Z~yYD;X{u((l@!E-KTP7C^}$s7f~Z6~ z!#T+x*#@3$j60ItxGyh?n8161M`rTN^YWXHF*m7yo_eNYJ_mR1BylzKw+lYH*yM2^ zV_HSGv(7kWZ1Bnl&W(&Tw zUFrW<`P4MwLiu~!H=#v52C9Fh*=@hy331YSKYPl?UT>F(igbxBKI|uhR~@>0eQ~nH z2APR|temIT`Bp!Fa;|Tc)!!#S=8OC>zp8#~d#Ul&RX%_7;(PzrGC%uZnRjO6Hm!!W z*L`;MhMf&r{m3e}+wxF>bp@Bu?x%as1n8_2KlNUyL3$CRm*!cgqWdspz8}4Rv;W3khRO=LX)EIoyUX;pat7QX#?Fx zp_b>Mu=fUB+lL#hPRLO}r|p`-Tss$JoJEF5f>73a69Y{{+sBW>XK_FL8b z#_zhFhRMe)1?O#^$uU8SK_=ZOiM$oaX!!{_}~(c#3^cK&a@n(??^OKJ4n>q*J;3Zk7MDl`08qR!MATxwpN3nwQ|| zMJ}OJ9jD2B`Mz?!9J6^WyD9gx`got7@Yzy5YenxBx-(zC{r|#TQRz={iT`76eAjaP zAue{yKH)*c5er>E%jTIc_ixc{f1V;&Ezc$!kTA#i;s4F@Ef*%g+;{N6_LDw_Pk81C zf4Jnwx#M%-3*BCBiKh6(XkH%Yl#=N$1RKg{_QvQn6dTwzIqH|ySx%G;I3*^za+?Fg ztvBwwW^cS287zBx-SfCfW&5x1{F|J!N{#0q8{>?mxAEp2$G;~p+vFgTKK=S}-__@L zE60|euHCYZ_s@F~)~QPCjVzYG{ZwiB$faWAiVbo13mM{m2a2@bma)90k#YTz?CLAa zHr=Te&z+X8(PiVp6nSKl2Iq^34RJs0J(%{)*t_A;(*ytV44UU|5_xx{i>b3^G23Hj zC3|;&vjwjoJmuB;aNDOM37(?H4t2DcSMqLK4w7)_>dImUS;%SsNNNEwo7M$+l3&`z{~8yH3BhVioK9Y2};; zvhC;OZM`-tN&1RNj_J45U2&^^JM~U8^PRNonL$b?$IMfIUZ2zOtlk}!CV1trj_86W8(W*id7BjxM1QH>4`d?%87Q#rNQOXCasI=l`j*1!6X4>d!g&fnUH< zz=}o5@{+hN@B0J^_8ljp6ZF2=Om7kYa(^Z}=jkaM&a7VXA^5%N)o#9H;y=G7dhrl&{e70HJp0t!~Y9vygUDvr-?FK3&h z-5s%0JQi?twj5Y!u-pCM5}sE#*qoUjadOlssTQm0Ww{k?JRkGjE{;|6i=thX(u21w z_d+gBOg;9_Y`fX6;)y-Gza4nX<}UeX_c@9GCAr*7dswRGrQXOf+qdA?p7`x7CntTj zd4BW}A7e!_M?=b&^NJ=*&5|`!6t^BLw=KW^V}kLM9p�tlYU3s_P_=I~3oa?ly&` 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ξHVBdgDU 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

@EMr`bb_rh`qbF!dgv9;7FPuwan@v<# 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 c_`1n|{bmQRJ{|J>)tY&ci;e9L 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 d@3E7p27a0?n*s!4S1 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%0ARw&U{_j}7WPN~ZrWUp;q1>QJVR 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 Oz~JfX=d#Wzp$PycMS`~g literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_pc_81.png b/src/qt/assets/systemicons/ibm_pc_81.png new file mode 100644 index 0000000000000000000000000000000000000000..4f398d468088aa499996656e04cdf03f946cf5fc GIT binary patch literal 295676 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelalUH&lg0lmsP~D-;yvr)B1( zDwI?fq$;FVWTr7NRNOi{C$cQYvZ(F;#;!Offf>`AKgzs6aQgdqWzW!+ZFyU7^H1|q z>7H51uJA~nsqyu>`v2EU|Nl5{@6<6Z=G4}yab3^-U#-0Tp#7PB{juLtHC6HZ|KGTt zU;k_G?~hF%SD*O)qjKTY_5HGS=dFW&{rdZ>hQIm#^ZT+H^?U8l%#XhjAD;U5HOs^0 zuRj{r_&wOq_u$<1*B9;dTh<%TUoY;J|8;rv=JWnff1AJkeEy}kR?j7^n>D>puf?oA zGU>5Fe3b8>uYYRZe!3lPR-bQadTZs>^S=MyPKx#XBk-nxLHp{v@7-nl`Q_bT9X)k! z`!Au-y_RhMD(#Ga_&#;ImA;`qrtH_eweSD0KlAw99bXgcnmhZ~f0OK5QLo6iuh{7L z_LTYY{QItbziP*>thXbY&tiYy{5o-#`X8Uyz4(7t;^%t9U&&9}_IKTpxBshH5dQPe zy^r1Vnb-aK@o)Nm{-6B&`|l?&G5B+L=Jj8N&*s;~+eQAkJ^$P7{nh2g-{+mb+Z!_D z&8O1f``bU&J?cFZ-Ss}Xbw3a9%PT+D?Vr2o@E;l5$+@{#h}_CHJ>Rti9cJ&yd-({_s|*>N^_+-MbHT|G8Ed<6ZIm?fVjK6Tdyo z@3$N{*ras+<>~)N@9($0u$O6`K+SK%u$bwZ&vx>howM(go|?*?_ZFw}8}|SI_p$$( zsZsM!-r~n>?eph5pOM*@zW(wHoaaYeYdK`p-6x4 zw`9^18`Tzd?TGRSIa82<=i6y0VE*x5!tJf4pLb;z{$3E*S-jml$LGiFe!qrq$1J3Ij@P8i zpI7jCx3akXQTl$i5TlH{OFibq+`q2!Hk#GKv;TJVN_AhgZPyFJbnC8EO^>wux9(K> zA+|WZ!?JeYAC|Dsd=OD{va~$yVugH;mDKSka(#vB#Y-=%e-7NaQY!EM#p}n8pI9$; z%5`Jt-B&AR4GnKI?Uy<%;qTKd9erlAJdax9yWbbp-_4l%!f*Lj;Zohi{=#+EJYw5D ze-#|rEuge~TWJ-~-x~SNdz0PtE(laTxt+Vqzvalha<)Udans#R*G+W3V$hrX(qZbu zDAV`09Z`92B67-$?>HNMY+_sZHX^!h=dvx{r8Oo;k3~Q0;bg6PCEB+yBJs)kwwFdH zm*zShdRF6HUDtDxYlVq6um#dJ%$rTVA(c+nIUd^U;V^bEaE7*1Db( z`1#n6?^8V|Zta*8EmHn|fsbzEo~Wwh*~?AXTJMK{TD!R2V}oVs^1JoNjxarbE+H(? zBrK>td0|+^y;CeaQ?B$Ix14ji&MX_LIj60A4R^qX%QH1P>a1HX*(&h6TsaiO^FxVO zqW)3W7RyI_cmL-7XUxHEDe+CI+-|1r)Gn7T$!|^^v0Sq#|Jla#0b0VQN_FeZ--I8} zi9K9OFVw{Ybm?{2<%$y;b2Wm)I~qxAmxBJ&0<2FA&I{+7nX{mD();l}-5=)Pm!gZuH1 zL;vu8-uAm`kN$z*c6UB7J1AG_ew(;{YJk-fVQVXcaJ!;EI|T*fwzp17H#KK|T)ktX z>_p8T=Q-xvHk;qP@cfwDnxYTWR(uWpHfOo;qT;L99J_Xy9?5iC?)PANU~fZsqzk9} zTL#6C_wo;O6uBMfSfep_y41vb0*14f@HNG*IK&hZJU8yn((_EMOJ^U`G&H>T+i!RB z2QT;2r*0R_Tx7}@9HkSW9?tx$SG%-$wY0<49O+xk97nq&!|iu2@mnCQZN~8agGV%g*3;X}Q9*>NiqPVvB-gz}){+-p<;e8tmGZMM=x9yf$)PBhQHus(a zw>KVB&+x0nI67}Jc7I&ev8qZ?$Lrh-$G8JCI`+25C~i{ZtYe*0Ceq?pddx*?O2I3p zBmL_wCi+^eDgUx^$|MD@iJD9?N>+w8@1`3!YHss9@woWSQ;CPZQU%OCik`F6c&{!# zu^@Xt`-@$|%S4MTtiQA-t@hZo*+{~2#!sf>#$Vc(%;&b<;_;^8^0E0&_x7%}bzp8{ zzB*akkbR-rhh;t?xkumjG}%0|Ej0Sv<5J-3JuD_t$Sl;`^HI*_HB++((I=LLqD zfg2+Na!#ESjN;Q=J?G>4eeeAa39r7iuyx8M4~KXLY4ft3ZY9lIVjsE{tL3h{(r_jJ z_*rF@JUhWT(&0bm=?CXlFH&Vz5)1OnYqzR>U-2<#@11+EA3nAywdb}UaMvsV)R|u)K{@wEm3&ecJXxu z>KU6pBuXp`ou0T|Q6~OxX1Cqthc1u(X=NjI){MJ`MkU>+&pg&lcALvISA_*78AGmLD6gL z&N#MnWIemKhQT$iKw7N$b@{nGx0BId)VLf18@9dY;gJw*iMZ=BP2HKrxX|wCr^Jqm zjahw#Mg^^{&m8u4o$^iKIWT+p_}qvUjVbbuvud zC1oq*en#t%@f#L~y)BG3aw~a7`TrmN?ir!0*zbI{BuzBB<9!m#!oG0+Y9ooe?zcYa zOSy^66fSSw`$rXHvA#Z{OF8ANw0wuAMWp*5JPKdfC)C|*4EE+`p}i+g&dDvjxTM0dKF#uk>;tPq$qJQH z^B?xTKNjpcTh3Lqr7!Hx(FIylbR5pih<)BnyBMfcrgrFIYI>9l*CHv|5{^qp{FPq$$v7+e zq=vgP7|r`-C_GQIynmU}R>>TWe085**+p9Y_nu$)&Ze$iqBiGFv|BBEz$%do3F>-0 zYv<@HWR-c>v^l8lJE(kuN4el)wy>hAniXUC?yAX6t=l_-+~hMas57j6#dMQ<^^(9R z3LaNAudujj-P8_DNj5xZ5XF@sW+3~~`o{v@|5p=v9%+Py%1 z-O~iueQ@h+_he%_!D}L*l-uXDtAM$J=cGe4gX%ff9|8v^?5LUco3Ve1k2Gj^7FiG0lmYu4^ieLo}EP-mjUwCzt>wYsaFLYVKqU|~LV^6b$o8ee8? zwc-d^eIn}9s?|o`4E`bu-j!c#dA7EtzrEY>iIMSS#|ulB8BWP`4NCNgbxBrrUBi%Q zq}F&PVS+$nhCv_StSL8@T`nF;`6{L5Avbjbrvw+PdEhIHjfNXn)i5*)OR@&A|IFAR zK09X7!Rx^@ch-t;mtR&lc^}(e*_H>!Dfec^{A0@X^l`~m`{vyg(zImPNsID5CR!@t zk*m6n9ay-sMNHp3);8(yoV2|9z9#*S%_?`CWW=T0_%+G#2SNs$eS9wDY2W$eWYh zKZ~_&R=8T*NGL4{@ilrA?WkqLYOdd>{Q6}25r%yX2c}hV^zHE5vHL)3(;D$szgwkw zQ-8DnH<+I48*te9z@D|Me@%YS60xu3(61K^-@h|0oO(EZHVgk_j}oIAxxxdgKT3k^ zA87qh6g=3mqbq&u8{zPEzjP;_?{O~P$0>e zwEhrl=zH$;&lyKz>N!Q^mOuVD@xvLl59a0_gr9oL^Q zNws}ByH#A_m(JZoTVwZpICEle7uU%^mz}{THJn;IA1iNM^yvD^TNfSQ=BdoglfHZF zfwD*B6vb}lGe1+TeYVs;T68gs|2|9S;cp-L&UW%#dL-K%&AHjG<&MMT(9n~e*VL{v zsmVBbEogT0b?s?wj@LYKVZ}Hd{31 zO~l@UO5=jrJ+^t5Tr9(%FD}mqQ|_9&n05=G~)@= zTGlRg+2-oq@#%TiMAwJ1tLB(ZHM}F#$wefl#$Of^c6-87uO;L)O{vVT3)?tb zZBNXWs!16;FQ|P|RAKP`AlG1&5hIrA_|QmLrMP&(r2}#dhFUKlr+J>{sb+as$#XS! z+JO|wpY8$?vzj*QWZo8G{17g-*?OjzlJtoq&(62Ie~+K}<_-d^^MN=S67f znG*(TLD^g}j9*T*mlqz{yM<59e;;$lGnX00{Wh~ADsnc2#U0?8Gf68_Lv@O+yeel{ z?Z2s#=dLQ=zAz;tK`88JD}VoNNA-1GE@^IT%IO=eXNQN(ler^xKsG&F`iK9_gcZ;B z95Yv2A65SvJx==o7;kHw{57CKyS6U&Ybz4o}1Lvh7M zyARhL%y`)DOyf~3J>L|1p!&=DEX5CTFK(C|;AiL*;P%W;xF$AZrCOV;jp)J_HiorT z{t`0JmP~*CHZ(w8;MmLdmNoZX+rKWj@K;Wl{muMSCMPDnn0%W3(uG24@mInD-Jb5h z7xM{zxWHcCqIW^)+L=CU_pctSpC`B2eV#N~E080xM9^fN(__O=oE?tpjyjuP+C)g( z>|)wrP9;6Dy=b zw=upAPd#*^nbXB4aOZN9w{8h34&smaRdZM88LBpzn@5F|Da9YijhkyIt9oXF!aSD4 z3L3K+B+eH8kiR3({3Yg_%iagBGuCzO4f2$ckY0bOEb9W(MZ+uXAKMCBzSk(5w;A#H zxMc|6pEqImrYmwo zw~ojxp4}bvu}M`ro~ei@bjo{U&)y}hwSsEltoovc-|~9A4(Ofj%$9$xm$TG4Xu*m6 zC%jt899PT}N^Q5_G<@DX@v+0IX^Sp>dSoid(K&UYQh>zNaIQj@W0}6&k`8U{Xy3w; z8>GPcJt67c>8l+Fl`PCI9$Y$8-{4f6apcoo~ z3VT{y#ACK!y>g-XRKcsT*B(2=x~E`}%O2xh|0SJ88>|WeZ(S=2vtbmQPxm&SQVQ z_2KJPM_HHrW9^^7ddciZ){`^_HKR|AJKb;8aY^xhd~tv6gVjg2X;#hMkd=CgS*>Q7 z^~_)^0Llgxw7V9 z`-eHI&XseQIF#zd@N%tY5;$P(CKYTa)X=J0_{4e>^G0UzW*hDc-?djol^k@GD9d{o zsS__ScXGYQ+`s+rd$>7PI=CmXPK{-p6eqcVrIm$~NWcE^wP6y6oQ_JXNWED0bpzAJ z>|JlgCaDX%dt~T|RU8vc-pf_jn*8<5Tc*5b&QMmSxmT4f3u_#_=FZr0PAozFlalXL z{)>}2z8u&f_i)Wb@t$R2Gk!b>{kW2ODd$y&7kXbaMP}T#&|anF>g3GL%^)4jd+WjF z37i{LesDg_pQ7=-QBmn@<=S$G$GVlLYtJQcG~0=*$@k?8T{@e(#B!Qqk;RUm3>P_8 zs0B&2PT6^eBYc--w^!vw29_HiRnCcMtrX08*ydbxG(E2(^W`0HpDmxn0(MQCpsFI7 znW43?kU=j;C3%*2&|~J0ds$wl@F=`KVeQbd_+IlFo^sx`^Z1qSGaT6bE%Y)Qr#D|& zL+koFZP@>ifjh-1lJm;D?~N-q^f+>7+>Ywe zF7J@hnH=V2@Wwzo#rV~M-q0AU!lh5mdJLw?X`P?-=cb|8jWc?)mDqQ(e}8CDEzzf? z+M07z&TR_IoqmHb<5_uM4A!1;Z+~y|fbWNLW#5_jJMOuhp4!K6=s#WE7CB@7`E3i^ zSYJrJZ2I|ZUb>@ZYTC zm6r08)@+a4g2u`btOZAA9E1&=fz7T8%p30~7<*0-U+#2NvDU+6!fqz6 z7{mSCK|6&%zP;AvW5vL~%I(0n1&-PJd%x6Roy)AE!D8wFgxm%!rH*e;j8Df zvuFr)u~tj?P7{iZk4v00(ah9nf~F_8bwE1Pe)h|@rpFs@IIQ`8_Gt8_O;(#(>TXtS zmrJ!EYhZ~oa&pfkB zQRF_bOFHK;zh&7Wt1M1IA^V`af7iw?nk!|do7iPA?fgE)?Rf`&H0Iq1*FDGmvFlE7 zmR;`)eHSLV$vpWBeO#+LVpcY+zTd*QXPZ&ci=;zyZ&>ABJ;YHLA^3;MefOztHv-*) zwevR}jk=y2>E7!qtC9_L4Zq%PW!i95@Id^%$?8jve9$UT;5X1Szw9Nt zO`&GqPz|mAFT>Pwd3ELbF z`?a&@E}C=hL11I#fiMS+@9RVr4hma&X>*=XDCuy&tu^aBGMJ7Rj56y!!fUD%=|+_|UdChrC%J*!wwtLk^t zZbovXd`u0np5{_>F005W+#soAa-+kml}|lXd_5zb*}48t;SDg$xx2&3KvwMRk)qX} z%q>;Pt7giJ8_XAGKF?CTSM22N22%}{*E+9$+|0^3Zs2F5vFORxLX}0VwF-*d(d-w# ze7(lOzjSwu_LD0vv1mPO`x5;8R`&iC zT4%f`Rj&MXZ=up6hWN%qyI2@*g>si?3YGlcvcOS=U0Htj;YOqNyS+sPO82;Jt(z4z z#hJ@}X3-v1_Stc#jm`*vsy)8W>0eM`M~LfVi&%kaqVv>i7|q|XcV)hCz1Q(WId0Om zr8Dj*yyiKtS5cOIbnc5it1=H>jXLcX{NoZ|5liQKCwZYwE6*^zHFCR@>-u&^*0~1v zla}{VqHYDf7cvkQ+~K#`<3MAu#2>|J0pI=nePlm{tdcx&z|B}D;t1nPgCm~IY!Q3g zen@XAdKA|-DNrNaCGA?&R;ddt%&{Nlcf7XZP&Ft`VhwrKsw1$e&A|PlQs07@I~T95 z5i4zb@b}@$+kMl1D2M3m@7mQ|{M(ynYI#S{quEykGmE9tx;9EUH}l4|to5q=rSu2U@GrXtdqVQz zKkjUMMYcX{nk=*Y_Yz}=O>@?|l>YEIlrY`&6h~c2j_=~_TbeItDJ`G%?OK9mr~6dz zbquCHi{_}QG#WjqsXh^J_@rm=H0kT#ZWwKl3V$iEKEwQQ%YwTYinVE5{Q5Laq%4fl_)JDrcdf{ZM>T=Q*Pcm91U{=; zt+?&4l9 z$NKO=*WVW#9GCFDa8O#Aw{n-(=AeU*uBX4v4sla9`_Q;R@?qjJSB@Jc+)-Z-IXN&1 z{j=7b=6H7HH1$RMRxXZ=og$IDUT)0{?y92`JY|om-A)j4SKx5oa_g9CjGM+`<;ffofS6W%6+9k zE%s$)j(-BH1KkYfY!iIb!pL4$wsB?b)!R)v{LcB0&J~9)-WFP-CNX30u7@+46Icrz ze$94TwKA5+T(#kVqnJQXgzHVAH!Ry%=5{?e=&_2)?ar39R~JrlX^B}LwOD)et?j>D zelTxWbeouZ;^5+1)`qK*-1Z%cwX2^QC~Lhl{Vdl|b!x+5362Fxx7ykI4to4(y*Bq2 zV~EuI6&zFV1bbR8z7lY2;!aM+rv*K;FMmq8_~=x6M_&-n3Fn2|`OfTI$ko+ZWoCFJ zhIg%|$_Hju(S|ycrULmCr-!Q>IsGr^tX%fyaA%i5pReOkBq*DwB8f;SW**pirb%5S>7>LKe)qvi}=fd^AHmb4zbm@&=1;Ada%^QzYJPoc>pJN$t<`Gp zZGuGpUQ7SHs=%!;bn5Z84)%8(4Db3hjz!9`#rEn)T~SM7NE6=Rzw_baN0+o}-b5}d zI2*1XX3BTDfA#0}o7SJ*ID$ZgK#2X@8qb7x#R%A3g#c0Vj$vdyU z8<*?IkQ2gw`L#@c#rq)B>34c8-$iO4SpV+I)f1Dp-rugcv1h`B-}N)UzxwR$d%Lc# zH2#qK&ONJ{ZL}`spFG5&cS3t=xtuf8*(lAghn5@6{Aj}rU=g{k`>t4d zuUXfyn29GQX#OqM73E9|gbzwiES~r}ZiB<+uI`k@(+nO~%slv$E1yB()`^c{ON6)g zo2i%vD<8S_*&=Fw?dJdmn>K+EhL4N0RH9iQE$m9Ij4fNc@B?W44U6KkFPgMOZqaKDeXwZuwPse1rz-?6+NxU2bU#q1EPCR?50j69*7FasDEMb( zDMx*Nw50OO9+k=6ZDr3Gw|(JB<=>jV+Bw?VDL&p{K_$Ben-NpGOxVW6SN@fE`)_S^ z+*5Se!Qrs&*_3Bn0u6j!x31V&ZE9xd>CiYUUc&0x-B;0%FQu*T-204adzE#?(~<*T z+lYZsl;Ue%&iD8_w&^TFa%SLR)hKL4umg3*Q43>9vJOIh0|SUPVNXWx5v ztNlK&)~yScwQ7~jWv`sK&CJ?K-1Boob&vA%d@(rOAlX+j=q!jVTF2Uu_WgffsK(@S=@xy ziHjFl$TR$N4`1rnZK-a2<9K1to|~UHmYLi5o)S3yd{y(psT|$fd@k>?8xLjMmi%y27T)}$S#IORtgXru zl9**XZ5I@UkP|u;BVDV+8-QovV91j=vZBhHTM`Y_<$EC@f{gyAMU3Gf9 zqV2r4tixxiA8Wq^)ZnkXUuL~tQr7Sw8S5h9aw;jvYT%9O+r#rk?c&k2p z)zya;Ocxfv<86-*WR5<>ruMF`JT#H};M35{*A|K2ieGK=>esPZ37iWfTz-Wd=N9Dn zbbrna)6(J)=hDP|wpp89Jb!mLd@5?lGE`Q(Qr_oyLQCoH;jQssyPPz9t6ey}+84ZS zd}FxQVNv0&AnxMZ9A61C~M3zPuO>royqhm^`ftsHWof} z_U=uJIO~4>7~>KR#xg-+-ubH?o}4-JZ_9#jFVqgQjs z-j+>kUbgk3+RK%qo-UD`)&Ip5o%G^9~9tOTEuJ^t0FbMpRLFIb++ZI~_O5J)~c% z=Pi5?XRp}-sgJx$FK(M(%L6$zNr*(YHU+{In!in`0L-V*Zn=$*wdJC z{k7xQf3edq1?eo#bf1~7>z}Kkmnc1F+ZzL}5AGIhk0yBv_v!@c1pU7iwNf^fchl*D zB?sQV{VA%#u$AH3rMiga8xx;oE5F)p)~6_TWl_u2sNY4aU&tBqj<&FO? z(|0oJ+b3>wl;!yQHc$0Nz(K9=YPxbVQ##5rlVv`>{Goa^vFP{O?AQZWC5uvLTm6!~ z)0pRSRz-(-$HK4k<91l-Udt6Nxc7F;(ylpDUuV2uxpo@+q0mJ#e!RL?0a0@&P2AYI z!ab#7+xEnaZB`1GGjEB=PxHFBXU?-gYr9!2`+`rx_yvP4@h6lK0Ly~MV_blwfCqC(eV zfrS!Z`F>t9IG$4cf6GMCuO=(1a`~(+@ACyIxNCoR4fe2cIup3Ick9cDuqzBpjx(&7 z>F%F*;okY}hmtn030XJW;_Q-Fmi3H>)m~i}uUxa1?}N*loXL8DkMFoOE>Nt##AknI zcV@4@ZqBSa(dS$FmNRzUn)`2-MUZyT`i>LPfs^k#xz=or+PbDT?qI&+atXG#_Hyrj zY?OMo;P%W(XDh606qc}k(c=r;I_GYj)a7CEElW^yJ(;!gRp9R6z$q)LZZ|5M zSU=Oup7Qlt2&cZ1ctFdy4<4eN4Vy#+{CHBr^@StX*nD`$c;<`a+yl~EPxqXtn9X(R zp-fLeP!HckX_nI^rnw#RJekhM{JOVSAH3PSqIT}GX`;Ek!WRWzE>WDs8u8}A^9hTt za77=>V=FaTrQQ0mCF*LUm&9||Z>ujyXY(%2P+g;(wo%kMG--c|SbJ2K`i!6nDW8_! zXlq@1rS4|wy85~O7d<-|HmuEld|M;7f33vSWRAdx?mRc6{)&3!^;W35Bz}sz8a6ZF ztS66}dcmr-Iu|a7tgm&=IMk!KzUoKcthZO~7oYWBBJgI{ZXp>?^D9#7)0NsAO5Ehv zE}NEq#WZ1dXwk;QrCa>9{g2i5uef*i+1_J<+G~I0uJFj+?$Q_iBPzc7c80>#@P5Y^ z4;OFOYFMGb7ALEA+}t$(uuFM=cp<|q0R|bZG7+Bkpxy2sJti$X&%EX|Vd4?dKBwJR z6z|G+amg$1?5Ib3T0MB8mR_6Zb3uA`+tK6e%>6AAa=E?!&rEOVvAL>nDl_NGN-JF@ zHM48d*Bq_tzTIqYjYv51am#C|Och}8wedeH>#KL#NE#~FwX#yeo>IWY7E4*yG zV8MBGnVEv}Oz&^Ev{!Aj7EoQ?(RZO|;kK@q=kvoim2pnHX5jMb{X26L%QfFtE_rl+ z+jX%f+t@3|a(+xUTvfHGc|mBtWmLe;R}Nw}{#U$?mn@q7@XJzHy+Wx=LW?Ck_1~M+ z1n%8>X5z22TVp!?E-=p#$czZsGA}XVLN(Y}e6QF3-z%^Df8JXj zHLvyK`UE#qMwu&D>Vi)kE!GZBwX_vdv23%*%f02~mh8CfTEv!L^1RFMZQ06vHmv;8 zqWlZy8wJGICh1)|v)avbRmt+XosP5F?uCUO@N}))YB%|)timSWeX+LBmSjDDrJb(q zXSC&z@9Kq3DUF)38P~roSaspeTXyxeZ%prIyopN+=(0a)cX5XD;2F!3BMle^&~cTkL^Fp!)wolp5+T(xtEdA z@z7sx{#{lp4!;gu89m!C_|P_u+l{gz9j>C7F5A}bGR97tdXsgwB;Mv_(VUt3=j_hFb)V%C`G^}7n zx&5=N|8zXkziVyCofX??`^{%-p{dcS5Rc<48lRrHZSZ+V=?Bh$oa36>i{;c8K9|od zwr+Dj-z%B_UwtwOd(w9dT zwol#T`nvOa$oeDE8)aX8-@rMksZ^p;L9C@!&AI%R7<+oDEn`=KgXr{K@yrY5R2QTu zoY3cB+Bki?S9E%yb8q;nl{?iuHp;WF7U~S$o0&S}+Wml4_q!*(?6;j#|NrjaKioUE z*4~meQ~zerE5@VXm@B-hD1hVI;)|<^* z^nNC-+qYt+!t?X{-gm@{yiv71#t<5Eb;Gnf(VNe{lCr*~-&AzX*?dpcruc(tjP4rD z2cGBTZgB7}G~i>h6U(_8q&V$M!TQfLXF9}WZkJKNbE!OW-#97Zyby^CpwEL#>|=(yuG@h=fD(2)63H$4#`?v`a0v9&jVB0 za^Wfo)&K#EHXhD%OV!0rbY-s=Deh>AnSMb1O8cYQ7mU$SYgA5eU41drQ!GznX_o)O zqIXP3UbTDOs##m4bZWxSqX`FC@3DxluV{aNVRMjG*QOVqR<~9~UtM(2<(lgx#lWu) zE>Et7JiV&?rSOz)Rf@;1TVAIe{jL|wGNf>v+c)pnk7;_H?h8Yw@xFgm;dFl5g4C^T zubNf}9@^Kn#4#*$+rP?vNBGrW)O~amezXh5B7$qUT)=>^mWdxRnIro$e6tgIoq?0D_>M}@A2MN z-*t-h?KTQ(UT^=3ZN4vLcUTiZ1*VpfhXKa<;TWkBS_i>H=yWH^afA^RNgr2XKeqWjYyw2Xv zlV9YAjh*Jc=SwGw&2QgZ_-sDkbGzfe&+|X8tFQcj^5LEN@4wZTTYP`M`|o|(bARtX z_`AEk_cb}))m5X+wrKPbLl1ptw$Q6I!&#Y!ZNNNd~!)Y)7^x65h=SJMObj@h#(FY2E1WB-y1O2?WX*X`N;eMdDr$62mm-}@{J zvP_jl`#W#mStU`?DsRV=z@gYVvr1|2jK&ci_4$*vQ@Y|vRo!@ z`iS?@%(Ju3RnE6K<2A{t#?L120&A!IPCe^C$986HK45&^{H=2Z{FiHrWu z=&rx1$&oIW?*38EbxddW?&&^HED`9ZU%t=)!&Mz%WPPJ0VC@Cqh($`PU&&|!xE7mK|%+AbBP038u%P&gT z2l4bl%B?(;a^nk<<4p}s4fL`K((@i`M=>xcFnGE+hE&{ov)6M?YGm2G?`yYyw|jo? zyONR7YOU_86C!oJmqc#yxHUyFYLe>BEq6ROF)*7wNK25|z{o6DnQ}mwpXaR2*BhVC z$laKbbGm`mal#FU2A++YW=Gc z?_E3pcGmyY(82>nhqgcUTb8M`^hl-Y`P49ll|PP~-Znq8W~OAG+avi}S*LR|r%W>Y z^U=g#-*5Tk`*-eKI?rz(zRV?C+cMpyWtZ*??dz+S^sKs6?H;;vZ|r~HU?#z+>@W9b zdLO*&scCrL`1Ynaec>5XJ?$(0e!X5_<<9`}a`JKcsxR9-PO;ZN-GBAWyp*%@CELz- z6_luVe>kLT%WNhXskeV~&hwLZpIY2svv!_wf%1;!MV~*-|6+P|-w9`@WoIfs{hfRZ z5xbB3xvo8(!gwwC{Qo8W7q?wb`MRb2RNeG~YQw+(Yk5AWo6p|==ijsM{k!(pFeluO zJGb|~?LXP`&-G82|NB1o-($J&|Nh;4`;YVOjgJj~6K;QG7rN^w?_2eG?f>obZ*B`N z+Iar#(~HyV&oj-d7M%F%otDzK-G5{m?Ko=~a%O)#KWpLZTdal!&L?!dr+&X*{jbgR zH=|}v|Ed~}n6uUvOG2bFUaj3#v3>XDzvu1t)qZ-clT~9-+neUpf7>%Be$Tfb z7vlv~u3me$|6gzU|MT~D*;jqJb=>~vN%Q|xX4;!?cHev3{*2}S!qDqWw04wafBI$} z|M%Jbef#%+KVSDQ_Sg-9s@KZ(JEM2o-+Ll&a=R$|@B4Y@o|ntn@A_N(dgni} zX?BUns@KkcWpX}$)j9tlugulY_1E9NyV-o+o^KHz|NkDh|0cN8^4#;kx3?twGnDSxU<@>{x% z%kQ$$&+Jt;_VayrA*|_LQ0> zd2=iG9bLP5tM&Y4ccMf^^|{n$v21twp5EcZ!G1pT)v?ZdHakU6rY`zztI55Vt8Zen zj@sJNa^X`U2Al6yXRlJbyG`fSq$e2x(=6QoB-{>* zob6F}efv{SUEVb3=*!s9J?5UC{I{foR!5$C=5aaixp9)7-RiH&TW6(v?%ne(#qZp+ zrZuN`m4xaR?|fRbs>nj*b)8elWgFXRQ#P%?eR|){+|8dpZFM*Qe|NIG`TMi&KU3Fl zljHlGFTd%}p*pEIH-sBx_vcsqeAH@V5I*N~(0ZR}dT$-I}_aynXdf_bn z(@nc4e|GV@Xc-o|CYNRP?gX|pQBQRN^_Px3{6SmX%Pp6-%x>gZG&|IwefsYB{>Qi%HyC{eTyg2LW$#D2g zVSb0hd#`EEG4_H{%qfhQD*k$%nwYTCXA9dbUW1}pk=LqH=dIS*d;9AQfzqn@X4~Ak zllssfP3-xk{cI%aeK*S4IyyYF;X z+`e@y#B1}q?@9kcV!{fHKfj$UU;TLb{rdNN_y5{?zJ8y~^TXTb`&oZuNjUyr{oL|m zt9vrLcc1=U{@mZ@@3en2m!FRlo2XT}YRj#Yt}9BPe!JLs{oanJ@80pux-{oayhh}| z8P=9BbuLbOJLBs_p_~@xw6gBSNNJ}h=AZ7!E(N(Ctg1*Ei*s4vgOQiVNdle z`^A=tu_rV87~b)gC_lH@QEauqsB`wYol7)RRhnX04&4$vbKZe*QC4Yjkk*W^is@bd z#Z>sd#xbVMQp;T1JzFJE(7g02XGliw!99ke2c>qThN#cd_qp77>)fMz2lEQwuW*{z zb4}}=*SX0K%R>`qsX2yK^)Fds?z$!5chl{*Quhx6Wu6Pol|7mFx{I7KI^nXG_iD@R z;8P-&MsB_{l{?z`3VPV8*q@lWyC>GbbeiPyOZ|0zZrx2D#xsR~)I-|}u< zW|6V8@V(i}DZ*#(>Mq*9d-j)qd$xaj{rTC?|VMIZ}Xoyv#K1Ez61-}1mhSVXI>nVHOc$Cqx?PP`ENqTcNR& zz0-QlOy+Tc#f9iC?}E#wSZuf}D|2zm%w;Qlwr^EB>B+S=G{jh`vwPdl-G)=8uYK+D zD6v1ql4d8Qvisi}>4`ITEaEIWRdV})u-l^GjoT)uOb#m1_R{=v@8qluTc&Fj|0mjT zu1K46A;9l+iuF4-i&Z_}?RL53sR-qLlzAro&UmScjP!Z_wfPb3<%+59M>5y;ewX2F zoq7E0iGvH@>~;Ts_;KlKwW#|}ymy6XSzTVUgZr9@O8+?*_Kgc?PxnZYSZ}Xd&~MLC z5wreU)So_sdEW6aTS_PSeOdSA*^@~DZ)b$N=&tK^KYlnM z@#)9ABiRB6LrP<(eSTSCVH2Le-)j2Le7nlGU;lr+cy{sk@00V7&tv!_cx=<$uLiPb ze}6vyyz2MN`!&y_<^O-He*eGveckJ9`;Aw`*Vn)QzPED5^2)kTDW}%kS5AKX$7-p_ zk>WF(qLZV=pJ^7ynN6H>!1a!{lG{o5IW5n6ubqF);H|O!i=B_tq{6uQ6E`!oPD;;u z`{0y`xM1(JytPfwBn7)qZ8SU5TB)~!YpuGM-wgMHPO<$9Cke1#%=lh?ev8@@o}Ct3 z*RIG*4x3*fl5zc8Res^5RUFUywg)cdTihEn<@x#fg*NvleernTbFHjI#pI~RfxU`V z&C!dt=KhIY{-kqln2U*=zPsoR=_y8nh1Qp&9k)#GPQ15r*$VDQ7rpu&3|3`?1stwk z^j+q9jOji5rb_nAk9K=6xUaUFB(%FMTj8Nty}WFr-`cOYWEY%Wp#4H-YQ;losnLZDgtGHg*j(06gnPQ zGNVnfS7H_a5GS&Awk( z^~i%llx=p^ z_PY1apAcwtXjAAZlgrvGq;@(?a{9`5>ruj_&M0lw^Esux4Ua{AA4Xh_Qh$CZgl~uN zL6h$pODDYuTi?XGRHXJyiz-CQLPo;PHEFPvA&qGr&%w${NS zf4ww~)0#?|*D6QcPtc9}YIN)PTGMS+N|_6v+`jni-IFzsx4J#mRoZf|;C#bE&8WB6 ziqF(~KdgyMV%xj!$;m}q*KuYGUt9j;f8C+d!!tBwUhJI|wC8w~_TKWo&w^W$_9lxl zD&2bBwBpG2V+RZGT+*JpBXKWFe`9#;)hHYPurrIKFGjh)X;{Mgy{%g5Ip^yIRu`jt zs?VIixNw5#N9G@iJ&a~|dV`GodOGwPPoE7)yW@37S?Id`bitapMfo>8wus0kw{T2p z=y5rAxmkOTgr?+Ot30>&O&Mq2v~s?e{9L*xo%L76o|Xv$7d_q`S*KSzOT?T#KY5PO zon~)q`$@A-mwuUOaqVLT=R})(<;%amef1~J>{!|&<&_h)%O8J=bZ0V}#lLRx?BvIP zIrQG1YJZV-uPR-u-EQei*XV8Yf8Fb^eY3yr)040BZ~GsVt!Dbr&hz}~QN^cMme)k< z*I$1XS!@|q{{N8v{=Z-Czn{Cl@8^1(>iwzClkNUIG_Ux4R=wuYWBKK!j;@Z@SIs}jG^TEu;3~8= z)}zsH`-%y77lrQ9IlXn0*x56|%kp}I)TVuw%B|DA*e9;6{$lT?TWu$KQmWRM#Lsxn z^kYRt>Y3KXle97qrAo>+D$mNDa98SCpBD@7=ZaX*W`XOw4O5q1&G>08YU7?Aqknao z!lMU<)$hU>7yD%P$m@8dYOX4rn7QFuZ(f_nmd$q;-x5`{5U*-3JsRuj=@}Vuy>*Gv zvo{y{!~;Jxt-6>i%jqF?J;v?ntHnp>uVY;Mec}~?>$*(ciOPjLLM|+FdG5gT-tbYt zRF88S5&h3SXDMyy-?r_h*vY`t7o(<2{9dtyV?x%0i%!!|e>Lxa=XZO?GUmO%E9$${ zj=#C&DfwNN%jLFR`chL5sp~;3A+mvsx0-2v;&^4b)UfU1$6~M7wv$x(=XrXu)F%i; zEZ3~ixz;*`JMH;F`3^sBp*dXJAEZZYe=x0N;dkLx6Khr&F;%+l>ERO*JaD(L_gz3u z8IN|XyGo+%F^j_fD;^W#Hl8=FR!BYemBsk`lB`9af8YFc|Hq@}_TT4wPrO{0^zMdm zgS|_{`)SeBQ`&DA+39;*%JF@@t$$tq_fP%5r{>rF|9SfVhq_q%o7?|o?7shOlJ}-C zR<*(~ua$c~Pu2hY%>AB&?PXg&?aihq{N;>8eLFL?_WZP6|9R*6dj0wTzAX1B@-DYn zE4?@U*~$%h>B}Y+6kglf_icsChIge~3?9EYPmAY0wyV(SxfyA+=GE^!Hv)h%;;k(P0)aDn%h)6D^CkI%QdJo`9LYO(R8%(X#Y zTPC^cyIAgLWB#105?8wCIp>}u&z~79&E$T0aSyN1!_<}w>mD;buohx4XPtBHdWGKk zFLIArKYLxWxgu?6RDaaGAwVT=w^zb-(n;Id@@H(!YMj(+Y1nHC-Pqk2)Z9 z_m;$KiJdC1uDRbhqcAnk?ULoaWg$f$C%(8*TE{nY$wD?yWzLGL@q2$uL}nhWs(u=E z{9H($6&vPGjbq~yfYM-IM|KV0m$ea0RCLq`7p4Rr&owVt2X3uFLk-vzg*k+x6`Gr zgg>ts-z2-enW1FctTUHo_lMo8=&=s! zs@$otMegm>ImI71-5%6(H1QX|Q`pFA9dks`pa1Q>i(zKjOV%ttD|^uSO6J*hqBUMk z-t7}vZd?s9nABQv_T%o4QI!h3znl$DS{{Gl(sFP53x*v*=8Bn)DjqXdiEXZ9Ns;vo zP+dCno>sJN|MRPYACxmcgliRTmud6~yVG1eA&4dW`wyR}*hh9B6@Gp-J5lgr#T9GM z^fjJ6Tub`&+T)rR%?>(M!+T|V_0y{?4ywIgRha?iwd=Y>^VWL@kPr!ucy+hK9nY+G*XynYTz>A9*LLXW-{ z?@TfgU68i)RxQ}O@B>)-hQbN`*W^D)2Dr#j9$b-%Oy_v@x)1C5Y)5n^S1B5wq}#wxm~w7ZXFaBXepI^Q)cXv7^}6Dk{c$ zrs8e6i_4dvIq2oyab&@n8N5cb{C22jy>&h>chJX#B`{Pjxpwc%{;j@8Uq4M(=DLYknxo+2Vb1*w4%=lKNF-m)_q-*Y;JKdia z_B-f?zf5_Px%tI8i}0ev*9+?$leP%0Vw67_C-wbJ>-R}XB3FLDc(Z4c#EzBR=I=h8 zuYGyF{$scOm!JCo9@Q0r3u=XmtAF49d-rsCp1f_{@0*!F&sfL*eAWMd@BCjo>;KPP zzxV&qwYQ}o)lH7l-j_G&ifY7{LIp)<>9uWD88h^!)}3_PEb7^{-79Ew1IIs=C9nJ!S~4{i^N! z+vvI(_uTI`z7giHq<($araHxaOPM_5Ue^O#t~pOqoqkO(;(OPJFnwZ13SYZP2#4hHlbUkkoyT9^UGytd zvc_8dbeA3KI$M5XEc506L5l53P&#sxZJ&}3u zrP(gAbHcHhcn|0G_p)47C#OhVEn!|+n7@SibykPUwylMUbGPrC7<7W8TDWN4355$^ zpBdg4Tl%$4<@nyV>j$QKa4uSS`hA*2ZqH1aOS0EkCTrgMt+qw#r00FN=gvBE#;%8y z=Cyy>5d8X=!>q&W?y&o|{jyx=$p7xZHr9=L&m~G-c&@*`b3bQypL0=PW%YW_?=D^k zuV%PmR}159N(t-aV1=nwqJ#=5>*5?bW45zL&RZe_VBN((Jy#LqeUa zxJ&OU74G(6WlvW)CObW_;lkZa<%JopFE?M$eZ78b)@Cn1CEr%wj;x3f!R>*Ju@P6@^xV&w zRW+Na25FY4uL=uW!)-aeV1e}2z59)>mx*30eHwkgYW88C{JJl?lkPrPx8}8*ChPVL z|JklvCj~vLiPBVFG2MpMxjN%W?TbhHYkp5@iJI=Xx-Tp(JCJdy%&)rFedRmf{Sqtu z;>2><;?MS6+0P*>-ufuTu2$O|m@DX)soH(Oh=X`+d+p4=BlQ>T`EM7VJlFND_ z`{|1p=cg?Rinu=YaH5>ix`)XNrhjbVz1PSq+Ss#dt(!rAqoHT;mgRy~*=xSa99-zy zTD?kC^g_t-p2)_`kd?dyDMeHbl3IVyL&UAXU3E_>nY5=c5ZRn*ThM}p+z=* z3yTh{b>ohoyH@Y|Hmkhkf3|kqPFEXFNKEB0J7zNLkf48oi&NG0XceiCl1Jy2Z1!1O zXL_-5Lhdemk^2v26|QsLtE#Dc*W0z<$oWflkkIE(CQ~&2p8BzW&vb4_!%3Y#WTLkx z>Mgl0S^M7Wn)?jr%|F&OMa(>udExOa{nJKPdg6x`@%S^ZOLLn3Tln0Sw@zWQe?&@3 zc>cV)cwyDVNy@(zB)5beS{0S0!qB$r+2h~mjbU~9&mHW z?2Rc>Q8o&eHj#g37qs5>tWv<$!eU3Rf^fQSqIhDQE|_({P( ze3#gqSY#2VJH`Cf;lmg9Y~8m?zV6@J?RLMX|GTl={`2i>kDD9I8UAS=HMu|U-oI}z zPb}$->b*TXI_mz5yC3XUT@=~2{_7%%9TIao`ey!Iu_9P)xy1u7EfZ_@*LY>pkR>eeQ&!L8M3U!Rj;bCLUSvr1#n$m#bmXG8Z)8B3--D?D2{Q)#-%6b_+NoIF?At~vi=f8ZEk zBED^_k?7KEyxz?>)a}xav$h-QNJQUTpe&ns1mt0nhZ-QHy6 zJM-%vC8>jknTx)8c^THPOXivUxp~g|ugA9OKDN8^ASu9;^W5vq4?ICSzEXD^uPokd z@Z`gc(rZf_MTe#X0Y+zOcJo_-FokMxn3)?l3dml&F8Oc1CC2*&g;*x zSB&UBvNUpk8AH*zD`A#r*w5UW@%*(%U-FZt(yZJF!AldkuH9P1oIL$pxPVk}S>gRt zQGeHd{(HCn(YyLkr^&mLK?7`ciP7gPXZ7dCo;TOh@#UBQeJXt4H~By7>p#E$)0%I; z`~R0~zl0~3WuNWZ<#FFE@a3Y%3LR^;lI6M-7JoY4Tu_o(t`@j0m-}Zx7xQPO>eHH^ zA3Z(xvBF`7z{U->t{G?7w+Dr&CNuhV{ruNGU47rzcg6R9U3u;iWqEggJIhNOu`eyD zx%tv*Q^Ue{g?a_ON=xXRWL&zsL}vO5smmD~znSg1eD;Oys-=3ulbnj*hrQU>*JaR@ ztT{8)a$(k->!)n)_sxG>BHy2U$VArN;a#|8f_(eOZR_sbIhIovdp)7-JlCecQ$DvB zX>EV^;!0qXro8UWsWv(Fg$qlMT~avuE8*AVofD2P4P(3a_+$V8J}h(FLG8a8NEmHdf0Pn;$1Ia zePmhDHFu}arD&@?pL_G=>YudNRq+3_{>Jj)`_{Ad-~a3|wJR@=+xP2q{Li=M*Pi~l zU-$ER{pa@k)pfsC1j%*Yd~)PL#2)WS2LsMsl=>2w>9*VM*1uVon%U-co9$@h(L0)` zd#~L@E9$e-slRtS`Rji;|0p;z`CyRW$~~7B$t>9>cGCIUjVHzR^^ac1{};>O`_*&a zymyu|B_({XLg$&BH@>}X!y5IVAhF1gLXNqyLafZa(?0E57k>A5s&niXJNDIcboZph zoYd^;KEra=>3w#_*R{NdWob=^TGucuea># z>so#B+Jr5#%MNX8({kK$lW%Gx$ zz0FG$;$}U36#hE;`;18AwBvQApCpyL#d=CbRiBz1V?TUS&%QulTduSF0pCSmcJbY7 zcFfySwQt*{;BytmXRci|4SZJV6k<95d_||AgVd?^thV5fV#dX*`EGe=+Q=R9JpW=} z&)a$z_YSAm((hh#e2`3c{P3Z2Lre9}sCVD$>Qg^*H<|3sE9?3B<3VSI{3n;4_xfkM zD&!wtazJNPu$g{L;Hdps}fme{-Lw>M2%cZb2TxWs!_`JE^W@2&@CS7hd`$lblmzKfyO z!=<){{Y8e5;o>uwzcjD?Zhm{0t@Rz5Tz*|}@?exV_`7s{-QQ;anx}8q|6BRpuHv8a z-gWZd!umP=FNhj?KB@@z5R0#4$xi+|Q+iTL2*<@&-RmArI2e1o^QD&y_p|R8oZQ`~ ztd#N4e73){o9$Opj`8uhpAXp;oOHYj_gnp&>-T-m`SX?E?>1FzI2Ij0lYeF@Z`!wA zb2VLOEIV|1y1s|2`&I7T(=$q9TCJA&8u49jKf=7GJvd(L(55XH++S-xyJ8i1y(=v- za@)syqPs4xZPR`rQpa%mZ>0xY;#R->jUvmpvi*9X8c^A2>TWu@wC^s%nK|40PP#4c zOEsP9DLmuit(jBi?B4z2L)*;Lsm~o$Og#^?AE;8FerD5&(BF4=Gwa@Z=Vw)XAKlZBz1*Qu zu{d|4%P!4|<4c>?s8pKFVRUCtxbcZiGPM23B@ZQ?*W7H*hB0QZQ@0;*%9olg;(GDp zuF%$9>kO?fcqBxw5{vTx{#=NN`kd#YJ%M=v&t7NN4D(>T-n2_IqA^pyH(6an!LT+ z`SX7l-e?#5bI3~0WuM{A-nEs&dA;K2=YRb1@yIq!&%=TRvFcUaWkoZk@0!osA7d#e zS8TVodCxLMa}j0FMBD2tqC_s3rhT#HNnYby!dFo(FRIviJm)HpzEDmj_oT3VLt#;^ zYvCb6xgR&S-&@hlJO2}###Zwe#Vk^}Pne$TdK9_I*L`eDh}aw;9W&>*O_N*5x3-Hn zw;9a$)J&;R)a6!Mu;Mt+ZJFGz-$#O)*GxaQ@AqdVpWw8}cPA?sg+4d9e<^o|R9d3! z$x9|@H|B0M&&qzVuzJ0z!~?_q>n_&5C|)CY?(3`E`>Wh<&t7pX`+ak%+_gQLsa4s@ zPadrK>!NA=x#sZCEpE#-+*jYTX*$1c+v{(8?!_CqFdW>oK5@`LPAg6 z`77hIJ$RX3rD0ft_zVZdZMDpYh?{ zb(Xb1x%RT_FXCJ(bHmJea{tvUru(ihb3SUg&i}gN-M7~RV|(Hkn5jQE+%}L%89+(!IK}@9K5GCj9qi{jBy+d42Dg3wBs0}ng}FqUy{!Jr^I1IA9RcyER{MiB$7TdF5H%+R>|} zJNh3y@GvjRcz8(SSnsaVNpi`70TVO!&fa)+hP86r?Fc<(GdH!;8HZb*{of@0aM1z> zs~277hw82`h+2NVFG6QuXYR4Xj)qHLpKI}8niD1Yz5nv8;MIjQ@*=Mbzj%62rufgs z85$vqJx3jRTD@47g?0WFSbyt<+PdA6d!kv2`RyAP-ceran07_vbXOJs?}X^gt;SOq zhP~MMdZFp_OYekyEBGT*OPCMs+$8<@-u2gdE!U#g$bS==!!}c3=8I(sjs-E-+fE%0 zvpfF6beCMMMpV?^H5q-Zu3FAw8g7>!cw9-l_)eg*z-kJ6u6>vUW{UqeK%>F$_M zN{O-WEadXqzc*ga=606xJ^cRu@rU=1+w8pj`;dw6nsj#IWyvd8qGH{ps|3#Jn0=o+ z{e_%L=$`mLx8&`lrQ3~f+~9k0_=4)?ZGFo!B5x<$>sDFgy4r5()Ufa~Jw}}Grl#JV zQPjsJFi=mtuuVV%R@EnDQmg(ED&*#G=1< zk8KTIn!%)dWo^(?pZDB-6H26xoGnvb5t-jndV%|7VA4ci`TzIYbk|v|=wH%lD7R`! z$&S27yHz&d-u6Jk@@(RY)fZ2m2s&oh$WgKPSRGT(>RB$GdNZ^3#B=m{cshADKTZ-o z=($CrbLYj~kLRsB-LdVhOssML`2)N7XRczJdTs8Uyo~I2LoFep+U$~*KB;We1J*t1 zR1w-E+A@jz_O@g97-|Y+6x5gQzEr(~q3e{XqJQK%y~e%?pIfTmu%1wL(>r`AqVcx6 z|GYnv52k)WNV81?ZkF_j{>NC<3@1A>-yff^7U}Vgl zb8b^dUbQ1w{0~$^=7e>bx`>6Diz7n*D0Z|q<-HGPBNImKDWVZ{lQOsdIy{? z9geX1JmJolxQ}M7%2I~P_ILO4*j949EpfHM($2Ws9$7-(Q%+AfCZxRn`q^U6gR@xF z4cgB)c)RK(>rS4esPiPn;?yp_yH%ee4(eE4V{f3ZQVEVSd;qlzQWE}?GLAG zrMI2oHD12WMJ_uhcLgiU@u)42&p#Kw9HL?Q@RFXY!K^lxA}hA|h1~ve^*-6$uglWT z3AdZ8#qHa(c#6y0b2jps(do0)rlq>Ju>_i$@jkOTp1!_w>%G8bAMS>GF8RWu)6ZLP z`h(%|-xX;R+><0;H7OKG?OiX^Z?5y)qoV(~Q+@_*0&KYssb=l!}W^PT25uN_&Ee0g5W7CoODm8zw3j9wuEpEqi# zFFd(^^Nnu)ojdw(u27OGc-j1sXTl59#gzx|97ub0?a-Q*59`ERWg;|fb zPA+m@+J1b$b*$7RR`JA@Z6^|0KKIU%iA}%uZ%&afzIj@J%V;T@`YPlE8pF@Th9u`s8OuxN<-LeCp$~Y4_UNn-8r2e@phR*fP#@uVu4qkJ+4`^G<5#nPirU zE21MTqRZDvKkNVKxJ%>^^TIstN$)i;AKEtOxYsk6*V>WkYtrw0zVYxv03I1Il9{udD-FXXC z*X%v^ae{fn{XfUdPoJJ%E^oS7rj`IJ2#+#<7(fxOkl>we@p# z9pvw*+!b&B)KSjtK-p8q2Xp82?U>V4@|06u=2wovF@2pMQEsgUT*p4=$z~yIOhpy5Aj` zaCBzuv)#OIrZ;!T^Y*Rb-dpviXuH_7RcD({n63*AaT9lS7WiGVW@4#O+r?{AoV?oS zWIfU%=dRhf*Vpv2mO)O=^tYR`zFV$sFF&v?bkF(Z-Ze?Oin_+WUTY5iWtb||c{Aq3 zc4KqCEi)#!Z+A{RW&FZ>lG+jVDE|zzghgkzSFG>2yLnx@3FlId+uLG7WvtfDdDk;Z z-aS3RkdvI2VPeGL`<^SA$t13GKsbAOH7`hslLC9-*~yol9U}X3_Ggpm8UEI-IK$zh4;1JOfIbp zx;Yc}T9*pPooZ#^T-6&Ee`)Q+;u`VL*7DESe;kef6KeNwqyLBeKd=9b9e=ERCV%Cg zJ?|bmeA&foJcY%SqgCjBy1=%FJ9dCZ$7;ksERFvm>i7M$$qeg^Ns4zf6_>uc9dYQf z@(1?E@t0GzBjmC}l4IBYPA&g^^n-Fo^CI!HH8*avHAh_FzSz}PEw}dYLhkJe|JuuK z?r#kG9%}z(g`Key>vJXl$Gf7og>g@-x_gXmi`|)yMOx1v6~0sazdK`jav<0Bjm?#N z%3nUN|9IL-*kF10gikkeX1FCSIc&b*_?^f?FENo`(VZoirZm`{Np6xZNIbKfopIx4 zMV}qH7t_=qUNek0m{VD_r=8`Kfv+;7^0oc5CNFbZJN5C|##>@VdLlDDA~Vax=ke;c z8^`-^sdD$v-#j<}!#AnA&oh4i{+{_(wOs%H_M{QZHtd%oYRUh|rByVKn{skWDI z{mwZnXj!mpwU1_U-LsNi%dhnsiEi6^EU#kc!YA%KRL@v%buTD+_S6)n{Hx z%-?Q#@9V5L=h|;92`^!rf79>w)hj1zm|N5e^~?S%T>IlEoR_VVGkZamLaG73esfrO zRrgXC$2n6HEky3HOM5H6+Hm)5(UR*`vJ1b?dpRxRUGkN!$DW;d+p@%OmR9@Ad51rG zcu7v3uzFh+n|Ao;g>#zO3-;ObA7yWTF5GhJ$2wm1?f?7!m~EBfn>HSexc0b|iH5T{>-#O-&OiSw7g+X&^FTTG{J&?? z?Y>ICx2f(aW0cn_Iq`DSsgOl!{+R}+l@-_$^}bxXdsva*Nb6ycxlPdp73W=|(@${< z#ou7@?>KVDv~9B~-@UTP|5C4$&PHXdKh7xmuKJ+IIm_O%B+1!#Zhc_g@ndy6Ta4bl_ui!ZOz zI*u~Q3Lam>*L_1F=xlrU{oPIcwObmVxp)~z^X|U3OX_u%`$=hW%zGAuVnCT}w9Bw9Txp=i7D6NPXsqRU&&;pYAAkk_a-4 zKJin+F-GR8M|85xhPh_Tm~wY>JF67mirBI_XZeFU8-k*b<~qN1xN@spvHCT8RyM!f z&wZ0p7HyBnpDnN^OGEMsyW&;By9M>0e!{t@o%PHYs$Q&B&g@y9BsgI~^Mvcy%%)lN zruwc`lG-O~_^9B8QCW0L%=)FjS5I%qS~Hu^Db*>8YwPhH>tn=D1w^dinwESr#P8wO z3ucbbTs)6YkQDOlz0vcm`+ak7;H1JCmlfux?NPmA-L848W^LF6pTMR0V#;Eg5f*_H=s%R$@AFPE%29BF&)+|1l$-Bm{(Nq9E* z#;g}D`P6iAU$S@u*A$cZ+Hy+f$zx z-5rK$Y3o9#@BO}0ez))K+{-JDc5j@Z>dejA_$&W|cZEC0!aBD)hOf*DF3#S26c)R2 zq(rgZ*%aOO?d^`-Uq9}Yz4Z=VduC2?4~N`7iR5Ruj_c0z^VEH6qcwNct<~2~%_)A? z)1kkwJK}a~@}iC%3Xd4HMV$)GQloU2SLxJD@MJzET57p4x0PkbA@-=2jf@{fqa@Up zq%}xi=FUF2>*C{o0U~J!Ud>v~Rhc6c^B0 zv2l^9)P)ryInm2BtOOz!x@j(3FzMrZzHaR(Y0p+B?z;Vp+}6Y}y~sTHSkzYby$jPN zF&7<`13$a|>BO%)`#|bQE9=SgE8jkU-BfOLzj@+;y_O8k?yP$h6gqY=Y)Z)0{qO5z z()A*|@v-g2*>4YQo$-B2h1b4oIoj>%&Q_9M265pGB8FB>Oa{CbVZR(Xq|6!J{k#hIm=tTkz*Q_kHwl8y)YjAU| zXg#>##f~|=_P-8_zt9a(&}5%>Mp@uXMuYe>#Uov7?H9gi&MBGw!_Vb}t>lNgJJJpO z1$(N$fBV1j()y(lUrHW-zH_lRe#gzv-f46CYKks4z2FmfzR3DeT9G zx#bTrF8H1D!9TAteM`Rj>H3wX%Tp&Do#$D(B}O*U>2F)MfWw9lfs76(Ccn$FQ|*|f zl=h3?g1sMNI9U|u zP5!yB?~q1`T*2K>F=e;d54T<64daPFyG!yW_gX`_og(Y%Zj`*YkzC4OxF~Se$32s5 zCNn-4_I!0WvDC5SQ9+f%dnV7PoDLy;hyLzfq429StK-Y>2>}a4a-_filbiRCTb9*U zy6~h9gPHlewtaF6{OcLwKOC0-$8!J2t@DOvJH+@{7R?NsajxG$gKy8hwx`+a`zS&vs5xu~h`OD`ocIq21Jm$<=Uc%}#X@T4YsjZh99X{)y`1hS_ zqVV$bCrT^}7TuA$%ALXO()WS)!w#n&Hp^wI>Nh4T>`2<}vPfx?i_dAM=9vx}OjEKV z^s|LjKGqzcdufv+PcuVp_ne%Ql@1)&N?k3M&VQ0s;!wHnrRaeqH|zK|rOvHCKVRAA zM4l5f@oV@K>$ot7xv@Qz1R$zQrWXiL3 zWr7qBV~jQDgy%+Ee_k+I>NJbTv+e1Yn?C11>#bDpwY}c7Pi*2JhIvmWPH*@VX|gy; zFx+&_+!#sYX7caPR;-NMvB_iE??;Qc?}UHZc2USOqwI2ZbA{@v$!sRMpG^W5 z&EylhdgIaojX5+_T** zeIRsV+o9^jxIY0)4;W}`MoGO9skl(?Q1o9;$=aMbBvs*mUvRls$i(>fY!{VP9OBta zqHNs{Jz`!b|J9Q1OI|?qvYA(trhcF69hIoQYC?zo!gBws-cGQCnZ>a zlI+q{*mA`*_FGz{r_2(^z{XV%8>VTi#s#uJWm+oaD&+axl`}(yQEckpnHh|M|f8|2`;>EB4+0Yybb`@)x^0Gg`K*++6Bj?)Qt&>apQp-FkUl z=fa*3FK1+Nac?enSnG5+U21k$;^&7R&ubcXp05bloXD>;GcLT)(tJ?nek0Pvs)Nb_e+)tIUAd1yKuwX54vpvM^w#%K^rthqSk8H>4P>Hk;GO zD#yDw_sr_)3xpQ2$@y{r+r9rke?g`GQxtHcWCqx}@akM|E`r0X$uzT5I1=Wm;nHyzRT6I+FGD&$( zkeRUg-Xz7z{tq)>u6FQWq$JScrqa4lf6^1nbwOJ^lniusUE~#5{Ci>J$)bi@}PeAN%=!+)_|5Z{k&X_##WE;vRR~ zV#W2}3wN2g1?W0YbxYyVKc8|ST|)Hi+Z#tdZf@G?G~4%s!Tc`2+WXVKjByTtOF$ z7R#e^m>5DyDgT}AfwRoLP7WJp1QTAGdDc<%P@MiZt6Y;rKZxo%UH7~345Q_JYsn@ zA%*9~95KtMm$y~KnqPV9qAcIJMXpcfU}NhktE$DBoadS4cSL9J6ke~fX$j*g#)q== z_x?1j`~SU8{J8VcpG6O|thpYD>KQ8Mvoc9n>{Kb4#h3B$WU)YcfESC6Cr{$xu<4qe zv%c*U=_!fSG7D|+ry@^Ff6#Fq-Ua;Lv|wD!6QDIGVIrxtghQ7hp#>5 zbnuY+i`vCUv-9p`uayjPF+a9R=ca_GS&t}(^Yj}3trI)f@vh1>YwOs(rJz+7Obydjx4GS-n95-gTt+P*OnU`FPz)Zow85SWnXUj^~St?1rmke01 zzhZ;Wf99UE%km2D8@Sfy(pS7l^wzUBpSK@$ALd1T z>x+G+AX&6L#v?*l%=`sw^zvta3sj7E>iwzQyF7f)i#cKJ^Ar5NjQ8a+9DQ}CayPrr zOcxE!swb~sCTJ+?3T70kzwiw_#VNR;G42WS25l%03mAKb8HZ~plQk~14U z7%pr&A-wM_rxsiLA%RH~tee(#S}7HH+wJ%%TyKW}>4S1D5FcW95lLPO~6vvV~!O_Zpvio3jxap{~0f#%>vDaB%3 z8JZbyeO^fBNLWfvG7;-Edeai<_&$Bo%Rhoy;bta^lUvU(66!g*^;m83YDx1mq8*~| zUfJ4MD&Cpw9WZ^p*o+icizyexuDdNg^Fe!^!=-cEm?uoST)Qf?Nt>lrVT-fPCI&Xu zZIN#xTeA1H$0RGx&cAYoX~(8UN7vVlpLag|_^@M_NZfU&;FWR?<;`57+_q*qOW$Zo zsjwUW`f{2f&(dyj~@i=`W-!Lt=ldhf9yO@`V`CcuT7^@&larmIP`+) zvd1OO&1zN8bX<10<>>GGyEgx?HN(H#)tTUon_goh=l3J9es-Ik)#C)&xffQ-XxbMk z{A#Fa=c{w5&^{UR??n4@H4!b_)Yg;Y9lG=F=Ol#8U_HPolyR{$K#Q}k#a>eJP3F7H zX6;c6J3T(Jn3OMGyyDxng+D*U%|5(g;X2u(pcVR-^*`tRomZWqJ?+9Xg(SvReDAZh z*yj9v-uYCoy-B|I*ZBvZ_=NNqzFZ@AYU&A}Dq;V&T^Am1&|Xx~6mF`)b308%PKzO5 zV@GJLz%o$|lVZLrJ*`3w4+WQYNM*tmcm8mzSs6H)6Geq5TLSrvEGu2DJw2G zv`bW;sTPtH%r!0lIGyV&7N>YCe5lFL+-?Ui4Ap4ij*B;&&S z#T##XZ}o6cEmlgBNMt--bl_ots47-||GzmESe_3u-A{DWInyRL7QRdRLzeC$QALix!V!jDoex$BuX zFSKtski29^A{zs*OM`5^t0wE~vXh*qlVZeNQeB0;{C@_Euze3XwZe(#UcOVcTT|2< zA=MR=L+_<*y6h@r`?w>t;U2@(S+9AURf6YRd#%&nkv8FrufB0q*=?&RWf9#fpTE|k zf(8dBRttD`My(6Btlcay>*JkivnH>Q`g)sbh3Sg26>+Qyl*RT^slY< z*wASi>}7TAvv)h4O0p>bcXGev zi&z&2pO?2wo40I~e7cJDorao)OrK}Ml#}`icQzT?UXYy~pP;ct{CxGbEvdoE4XZiC z{(iZv|31wD9Csa$t?&QL`*Xkkhi!fR&Iz?TvT_Z)9NY3eg>I{cBc@86k217QB|4s-FgJ*+>VBGGkmud63Spd`8N%mU zmU}Dsc0^S#N=}fSxHYoDdEVPy-Wy*==A{ZfxcMMO=HrL>^-o=dr%e1c-JV~t)BV0q?%+MzqVg2!791>cyTaqvbw&!<}-5;|N|(>`u7W3EwX%1HgiDRB1UZPCvz z+%B4jm0vBsoLS`X{*TUrgtm-Y5L6wcQzd$MzuV!+8IoLsWXNymggt61Ne>erjw z+&*!|^cT$uCZWv%uOe$sn|zRZZd6j^cFBNw;;er&GDM|~nh&XecMjbkGvnLNbsmz7 z9+X%uyw(*YvbItv$NJv>-48xKe5_&;c7S>9dIuS!Z@2S)uyY09_`d)D-=}e5?~dT_6&pUcNhs`U51 z9n^R=d`9TIb!!)F*Jf(EW>mf4z3__fQ-oKYZSr%9a@K9SeAv*pPi9$DP{yXq+jJ{g zUM`c6{XC^})5?JPyGl#4PArV^?zm>Nn%hZLka1qNG^5sK6}R&JWt<&fpRjAVL^*A* z{UjLD_NH(0>eHsqy>UwneP##0dCS%C!c|GrFih%kh-%OL$5n>DnUAJTPW~iZ5(Xh|^X|4ylo4)K;d)rCy21a`JlD&4vu<2`o$~PO zj?A!cO14jWJ+|Ad3!iYR@6RlibKl;5uAAv`^6dM~(YNfQvDVe2vwt1g&|9SSTRfx<(aTYNx&jV8@i;6eO+tvO3QO@uu{rjaN zP{;NBj~`DKUl#xWu>Q;Zf9LQ2`DI=w+Spt+^@L8oDEpMk`%^w1ZLtbWbU>c-}&vCWFS~m!GI_keF9wlylfqQJVL#!P$o_GlVxJ-(z3X zdCW<6_gihnA9p58-?oq!*pWF&{`38=Md`r`YC9J^Saootc#W34)OGKKJMWEG+kd>W zFZxqJ&^z^(vx}eaRn`31qiC;u=iX(z4i=}m>pEurs%*Qa!YCH~?q@XL`j^@PR#nD1 zwXT|?_qfkU-LHP*+fbe2ncLaMxR5JTy6Sa|w28Zar1GWjiz=O8uy(Mum*Hn6A+r4llyGK8FUN7lm3AuXi`DgS0FXjI>{y7`} zGrHU!+_J5^cKq?-jk&k4-nCv8>G%C{;;y@Is@@)ZyGDKXZM8%%HAjJ9!wa6C^R~^O zbII)3(QUfwwW=>a99yX~Ddxz@Nx^Tftvji4Z&Jdv;1w3OALdRLy2|id#8l$R)=T;K zUQOhGxL~_u%i{0P#WpQ!mYgqS`{rD$TuOfY`qwIFL~T{;6P&ZPAILWK{;pi_U?87R z@tiOB-v?!hUqu&nEGDu>vh4y?f1Dmd`w?vU7qD`qdlo;bG-cIpX)A2 z9NE5c`nUBVH)c0lPGX$LH{s!|$u<|Nl?8P~`2!fO7YGW*8qQ&;&zd_$*6ocw$K|{U z(s?WRq@T_U{`VuQ^$`ny%0$U~|9x(8>-OA`eHOON*l}XP&uP3oKMi6`pQbCu3g4BM zUN~XpF^Rr1=EeuJmI*x!a6kRs`9Fi0=kzbE9EZ1UTbXdP=COMIu86QtW^=w5+&0UJ zc5`HZ5WApg!KcMB3VEOZ5xZF*@h}{Eqc=W~Y}dVmB^SziNujo5eWu(}9V+26wI<(_i+w z@R3CE(wmB^yLND=vDkI^5lG=;H2nV`XXdnQ%%;Ug*ru=y*%uqsOLmy%}Tj zR>Ngg|GH!~i_}7v#XNZC=hvOQhGXXhdqo|qkn$Vv-1RdJ*L+dn;6LEG?Mce+r*<}J z$|CCoOt+Yc=shWH*|O*R%CZFuKQ~=lsWdTXqGn~z7d4KP7j)WLUtHDSV)>0B>U++) zAOE)X3h(s)nIpw}^w6SJ(jmi5`YhAN&Mx6@*bLp7PcM|6Yi3z9Z^ODC zi*E}e-*5Qk8`JqmLb-ownN;IkKkakRxxFGU)cCR-E!sanF?8-usoT#iWXhBmPl)9; zJSi%dvG(Ni`So?{b)an>>GpW52^|mdp~Y_X`(Ef#bx68-2TAg2?qrJM4f$Nd-0ED zQgQ5&&xSQ0CSKdhC;o1~rt_00HfvX;XM`U3+jB2`MqEIjt~3LKt>6riof`wbroX?O zUjD(;x|w@cdJ%;mWH z^W`D7z-lcenOg2W_17=VJ}}uL((B;q>G~f&rOwrx?!xk-%%eKZN@AOwhUW?yuOk;b zbh+OjfBcbQb?cmIN!5ofJLSgz_>nEdJGqziYNQG$a(YG#HKW9eG?x%~tt2hfSdUiPG!K7C16P>eXzImwKU23qx z^9yH(a;$W743}82r+m44q}Hu%jy?fh3v+opm{}x^7WcJ%|NOkS&86wuX@;vRcRt2n zTzk+fjf3UIv5b@t-BPj&i~Z}Hu7z(|yHIYY-%Yb$FTd**$UK;<*Z8EL;reOG+T90A zk3Q?$#uarxucOYy_|`q!1?J6>jgL9k{+DQ2aE154q+Tsf{f_@Wm}$7l1}Zi_jXYcYTRf^UY?m^rttt#0Gn zc=Odm4#Ak~yir^~HN9r8$vXUU$qMf(g%?b{rRy5pk{3;T)qP>-zTm{XBMy~1!fdA< zFW#2C&~UY(WS7^ps~d7vK9e2Io zuKN4W_4R)qEv_%o*9YbCKRx}IUw&Br@S1>-oV2g?oyj|+E%diKyx2a~a6iAOKeJBwMcu;%dMQfr>!lyMWLVuxRVnm3qT$H(W!k5` zQ(8o=RTw9#99cE-Op(*Eqg;2w6+Uyeu}n}@om73V@7>&#WhWx41S2^2RP0QMUO$sb zV`fA9^Oc=Dy+tEVsYSm!t2*L%d>7Lz}E6Vmrq98XtMlU=^`oir9{(yZqw)MTq?wq1_yVg=(fUs-C4iN55L^Fu>9EB&g(TxOpQ z{vp}UymaGT*2Zvw)Mk-&8MoP1bA9i+w=Vef{oTR;ru7yV&tK?mTeD8tMKp}-mse6u zHt+k}UFYrgK3MGEC-7F&cZz3B4?~x3#rJQvar^(NUCVu{cfVbAlj9+YWu}KJR^%Mb!@EtVAN;aFJ}2S*v^NhH?)~0Uq5W&yqXLVCQ&{(| zJ-_e#joj_e7<7!Uo8EjiiQnd3^4cXjhT)QOvTOOzH?i8St=b%zX*Btj&%_V*d0$@0 zEj#S2wpU!Qzh9im`1)Ju}mAeqRcZ)I{tKc=6+<@Zu*?_(^MtACcJ@fGw zK>X;oQV+A^(_dGAi3?D9zfv%>H&!k)?DOWpnOPaEOXW7KyM8x*@vppFt+Uc%Shwm_ ze19jq@6V^=6MGUUw$gWYCYV@&BJ}|M&3!qb&Ch z4-3O$F&$9_i9gCe(`ULEEnmYiY1;Bh6Q0lb#@=kD_Qqm?|EbkUb_{NMzdGbp#ruUL z_!}QEc5JVxsz10%=5kN(Z!c5VoI4xEm=jVIs@XOK>{ENOFELwu%G0AQPc#4D7Ak#V zeur_s-3#0DbMIugUhqBtyX&6SE2WCRzmoqH?`hTgf3{Ngb;qI4W?h_IDmP-bu3aec zxJH>}MN{g+yII+~U$3Z~SjoLD`$2`xgQ{E({V7&%hf8alZp>gLvl4FW zW$b-ib@t>g_O7V5ZBta#n}pn6o@APCyI-y^NGpX^N+gUwK;un9MBg;4@AFPDF1HAE z+?e|6P2;Q791pDkEhvd%F}mAhUi zB0zWcrd{l@yl-t+%uIi)$&zQ(qq3nBVE%sS005B+X>!5w1$=hgbZTJ!F$|G*b>o%j9xc^h>4e{8n@ zZ(Q?d*Q2A|{U7cB9=?C*{Qs@*7peKHvrK+)GbqpFkmoG3)>tI$5Hc!(@*c_m}u~fSkhUYl2@;$Y{FdrDeL5&cM^SeU0j6;E8W-JmgHA& z71LtF6zFH6~z31cJ`RBt$j3an+ zW=2(5=W!bnm?USKgr_OHha6cjfzvfv z;^hv9?xnnpo8M_xn`D?Vt~z0IWX6k5u7sdqqfX7n67!CwAwi;sXS=;`ahCJ&Gj%^d za^=OGNs*~PtbAJ(Z9VgPrnpU7@Je`X(vP47_1Gsm(F}z%PfpB4|5iD(drP|zZV~Y2wyl%;DYajmj(4;v-IYQ^{G1IUA zCkX1tKHU&e`d2-Djd!2RNcW7VJ4s1KTaZ#@9MByAw?pxOuIGVWdY8;)Uelg)_!qko<-Phe&8n!Vm zZ*RBVka6Xn!@e@rd?(v*eop!JOUL3RoI+Ne?MMv0Eh=I(N8}O zR>36o<*xZ&&m`PsUg$|)oE_wFr$Q${?SSU(OPd#jPFYy&zvu?X*G}n~kuC?K?^L)m z1bMG>u-Pkg?Cg!@wI4k`IZH`wWV|6Pc-TEAWYT4Y2|^eC#3by{Sl-lpu50&cdEYft zR=6+A>}#9aajN6!)b!tbv={G` zYY!4RZdUmJp47kc;C2R`VvAP`7sSe5_dcxu=aBxR-}XP4|9o0s!@U3V{{O-<{_>C4 z|G!lJp}+2Te_`z}!w1}b?co*mb^iRU@@;{;gCCr@7!bOptnqi-^5x|fe?MxQgja~` zd}VQT{%(4HvC=FD?^Xxa#>2)+-x|ImN;6deEaKYsjrU4MVU`+Bht`#0uZ|5Z?N zhUe!3&Xc^6?YnXvzfZ|sI`Pbw0^dV1cAV)p?=#fcYEGWGSDLkWp{ShO{i>@k*~~d} z;sQ=_PXF$&$^Llrn(w?vd6r(|@%Z>~=Put(}k zTAo&0xP9C4(@9U3so(Uss^Z^M^V3u86MM~Mt zlvN)O;+lN#()0O;w=TFfX(orx8|BRWjXD8*S9;=Q^%}A)r#@}bI;GSXal-Th_nM4J zzl_2ny(bA=HVQu(ctd*btQBWP^$yvzD@yykkahmO_KW2Qz0amoojC7(ZkSu5UgGek zBj^OHf{NbfxJiv-8Ygp_Qh%wJyw@n(?e}3z_Bp-d%EbaVu9&EMrQGOU+hE!`Kl78a z)k0m~Hw$e%=XB>>aVeb?^-@t__mwLXpD^DK_w0D0XA$s1L_xaXb+UreikX@htJ}Z# zJ^sY>e0l3h?+VyjfVOb`{+=20jBYn9*GIh$U zTa%BtU--Id;aA?flXr9<`h8W~rSff*TYh%kzsvE?x3~R0w0Fy${(8y2`j_RQN}s-+ z)}Qx}C2o7vv>kc*5BC*r-@fs}mw6Y~immBov{{(&t-@}N?A)@|oHxBK7JV<-7J7jD z4)@xia7UJhI5F;=$ANQy2WPx!p2m~Mbn(kSa%=)cYTQ)oq@Q}Fsd5_XBMj`$HnMAMcPEpUqH2fy4FfJ|f zd7zxq@qXjt8LB}62~}sV8(e74QJVZjGi^c;qpiammJHS{4mpfllol-!j$c}D|0-tY z1-Iygu!U6)EswhO?>mI7jPS7MTj$Lu$#M1Lk4FrK&C^()d=ioIXE%#4Jz8pQyy28c z)XgO#$s${S2rh4*{^PX#Kh}Hui~rnvU(Y|k?%s!Qce($3l;797;=$wf`w!h-e*VMH z>GKos?sLf2{>!+az~4moy|r1kOT@LU53AHNCuFw!bHpqRx){Z{L}7^nTh}G)BU(PeJozGc&PK4qOS?H^M~VRJ}CVTkdX*OF_^J9N&MeZ75c-ofRM8_$$FPx_;@ zVe9vT^#%dAb6g+pH59zSae7rxyJ0xfVvSwKF|LOd6<@3^o+Rw5%Y8?5uel5#H{WT- z+41=)lg!I(nDwroaS~owZ~g7-W);JCVQ&qD1SPkaEYmqVLBZy>GyjyMvM;SCux9(s zdE7X+uU7J=j!{z4<#2@=TNemT2vYdzsrb81KKGAZ3AZIy7@ymIT;bx+KUaUVIUe1$P9sccXQ%Dd z2-Ywwm+%(-9xpfcHBY%ZoqDp16M9Y zDYNFj`MCK-YY)&DH&^-Yc?~A+_kPwU_0i0QthbF`Ey(nRLX~%VOT! zFy#_Asom>6S-kIWoc3wS4WV-@BSWett=Bj>Tg}=?=53HD(WSsf zH{jN-B_;;Xs->T&ioC!5hWX6aPoM98FyNQU>j*o>e69TQyn4Z1&bg*u3)SZK&NyTH zm80wWCU51J+m>^rCwRNKXE+2d3(0=*;cha&<)pv0cf|fbXSKa5U3r(|`TZqaN&Qdf zKJ#|0XPCGB$IA5+)6d@HJ2CU*6E_Av<=Oo~TXK4it@8d9b@qC9VO(tyN8ap7*TVPl zot^6R=6mAzTr;c8h8^*bPcW!2Y&zESszIPJKY8xOg_&<}R~;yEtT@1@d`Igu@08x7 z4+{?bTq&%2iY;#jo9^kRdqyYJ&kIXW_9*2N$jhibyt-fR!*oQIf4g7FG}ve{cGA}d;2?SO-asLZii+)d%rNnW_F;zO$B4hgyTGE zlIN0*f9fxMuu}9pSFh^C*1iea-_OK-`1CP(&U~q;_=~^U`ltQ+F>#XkK=o4rxp>=Z}nI_Yp~&aq38h z-=vrNRy!D8TFyV>wB+vQnF~eczG~b%apKKA1x~%`AGa_1eVunl?6d#(H@qv}?YGn2f2A<{v}WwwpN=YmZ6)h$0u)!={Nj4=vejPYZ_838-o5B`QpufD zx_!5qam2}~uE!#;FHJMvI6FRaor#O-;jSA7{l`4n>lw_S2eCesy(_ymKX~pzCqJQd zP1g2bLhtXfy;}4~Ds|EPOvUA!gm-d(&)j6{v3pso7VG|G_o2UQ`EqXFUE5sbrtIP2dA#bQ{vws* zj}@-3z7Ac$!z??0&z~E=FL!<57LYy^o;5ACT(;Q%+E(r0<99BYwSRYbEqi<0qgVbf z=1G3o=-*ns;f~+5q<1!lBND<(YB-Ni@A%hpZ(UD)EAz#S-B~pWYu?JfI(X^x9is`Z zpT7S*Fu%3bMu7PpZ*H{b8}3i+w{BeyTzlbh9LHRv?1W~Q_BMx@#K47~gz2d-qkf3oxTqGN2C=H^D)E1$+M zuy81xm9qDbdq>OK(0u0lwuL@ErVW`(*XCd8Nn83wcL}qXunNDcyL*T6eTB(SBV2@C z9aeD$wMBT(_4zY#mv-a^Ro-PGZWp_B{%qU)qIJD?%q5Oa&zec=CZ=tFZn)!|q*AD8 zi-whm9@C5iT`7Hyhq;9RubJ>=hk3{ew};ylJ(98}N=^#pN?!SL+RX0@*y5SDWE;VLAxM!ep>L! z^CH4LuG(AlGLIe3&UOn*b6Ngni@At(!fpw>s;^w}bw7ny%>DRb$D@jpJyky&mdaeX z#(TWkDJamOXOA26^{8gmger=I$-#T_6|0-+68A z_HSRy-{1TD`unFM`*+%)%@Z|0FQ#T+e;dFW6!vS!avdFqa(ky4mX=ik$LFxl{rAIf zl4#Ez2LElFj~K^()j6Z_z?R7s3cw4x2HZ!yRdeGdzKsxI7gS}^D-y~Q}J~Qof z^X#pk8Xnkw{rPZ#-ENUDGiSKF9&A~ERD=EW-?aDhHre00$+yL!#r5~o)7L9L|9mcB z`S|tysz&?2_hyQ1IJ6_~)*PmI&JFu#TKrvRC?Q<GrxX_@ zU)8ZUO|-wg{=S5n>yvjjkzen;ejT&*LE5inPqnY>F`jp8Y%MntYn<}$Y{9bF|Mol# z-x)MFd3{gH2zEREEMxwm@3r=7n>H#lZC}mqb9eXh=EYqH-W<5`NZO7~Q19O438#v+ zYW~apU2jp(bMj+heXmTH?0a>t1x%*?A3A?dGEADz8=xO>@LYO=1iymnU6;=t`$b7cN~FZ9lP-PPXCzNh9Z z*ZX_5ov*hh$F9Gzt!@90&+?C+*Z+I|;X}aXkj(PaIdeDNPqH>rZ5Cd{*xQu*_C{D$ z-URbWzAG(~4{Tm}t)RnXhQli%{rh_=KlfHwf*0U1%lyA?|L^YqeGz~8l@3*BpZfc_ z^w!UFw(qW(vYR|Dn^O?MP*t1}aQ(c9ftcpyISPNx?(Yi>N#|BPx4_RrrX(f!K6j`@ zRkp=kxsTu8KCejKe%a_h@AtPR%AZOkm*m^4Z*%BfR-VjE_;hNXy=^-s((6S_X* z`@0MS*-Zyq9?q3%4A+k@zW+*mPetW{U1l= z;gVPF9!cJRXel-6^~@ZG8#6@wZe2CD^jo&%%Qnd!xp{YNrBB^{Z~g86soVw*=_>_O zn$piUol$dF*JAE8VeDEz$NS7@x0wr5{xzNH>AEQJ;qAtQ7Z{XEKQH{VJ*%O@;Szr% zW7xc9Ax}=m=%sUr+?71Jy3Hj|VpYk`oE1+Su63N6&>-#UHs#9GeDfuj{7hQit{c=k z+-8|xeEjgsWSME~e_puff9T%-N4DhouH4x58mT9LSM0A_yR><+mS?|~%Je4x_3)I_`AcLLH?1241f5+MBOZoNaxm;{EkBp zCrDhDS}wZ!=eF2MEHi3ywL9$Q@$H@*pDo*WSGHgHz^M(hS$dg0=LISHylGH2_L0Yp~ z=d2Jk=9p0@d-;9h8s;{sWPwQMyx9%5uV%e!n7E;R$}?4?WYz1DJ9Vd|#N2QQ;&N_H zVbyt{n?27WDC_XnDU#c+F}~02N?q}_A<0xw)IB@=%eGVwAz=abNlUn-{$H8(eTlz_ zmePiA`X4`iDE;%p|9`xUe}BdQZ(Q%YiuJ-YYx_y3=Mmn%VI@y9ju{ZHrDR(*W- z{K1qvCz$xfo-i!S(K>eDRb`_8bGr@O-Eu!@_$~e*d9tmT);DyKu>$6Wz5VuP>t2LGX+6|eKvrG1s zddXCO&ylFw^gdWtL8ZsmX5W#+hqbq?eR#B6Jj3stQ_EYehKhAXJ9IBBo}=9TyW{C! ztvh=Ue>3M|ia2IIIkoQek$;&}9hclKN)euB{rXITK%j@@l64+0?g(z+d3^G_fl__@ zoq(FU_{~NqbGO&9onBcor~TtSk@NAd`$9CBzD7=*pL9yFa830A5#|XcUT=@BN-}X- z`esvLgJ$`=l24nD8hz26EYiHtGF6{tpr8~)&7YF$wJDR_-QSo-C| z5xM2=noZZ3lp`nKX*{6+_tN?Y1uH75qCT$8uN9wP_iJ)a6wBRctG^#34J_*a_@vJW zUd7t>resIduJReI*LpMNbS#uuUw``r>miF*x=Z&&@64&%F?~9Ce)+&h^Z#4xMeBdG z|39<+Ygdr)K9|#>sbzoeO}1Pk;D5RA!5xnK7K!|iuISj9N51GfBf0--uluC=O5A3? zL0*9zQj4=LDo)&0%Y6B_k|oo+6{i^+PxDA~y>XpT{ZG9mVp886gXhjCPo8+Vaj9&9 z@}rAV@-Yt`yq28dS?g_g;@g`qv$u0~w#NO9N{cwVmi1G7sZIM)_nIP~w3l0^`@X2I z;JV|rwxFA%CiVaS&>4F~?keVYO8R^cB5WS1DL-mEE?_;!{tmOd5VO+S#>Vvc`@*t99zvqOb&?h{3NS9Y zq<()5gJV6bnKkc3vC9+ZecS%rP#`0B?)ueRrKca@aFMzBL`^buslt`{@%{x_Vu?9Y&x8H@Y*`hi0BpmdYP_Who6Y^9GVezpjuh|;7j5C zTeQ$|Hay~^QOkJJrQ!ds9&=#-VpAlMceZMi0RMT$Nk2EO{LC8l zWtqU|4O6VOMC2y2YO1zc$_Xh>imb>Fm)vshuCdY`*`P0OkM#wnbE>rP`L`~-tS@oU z;j>InMV3a_#)+aYJ0fl{{MfK2R(RjCT}>RVN*e^zPt5(N@oD=VPHUM-A-Cq6+PvdC zxg&NWU%&d76DB8AxE4KM<(0Eat0AP+W63U7;l{vJmk*aOv(B%1`*?~_-yF6@p?evl znX}fu*mrP^T9UiFokxML>hhQC9pYOA3w1Nj2Cnuq(l{tJ$;@{4=e>c+i)BytKlr;y z`0mTznNqBxY>v^^BJN-QvCb7Z?4i_mpvYiLo$vOG9(8UTbMNk}hD_?$G&sB1{q6rh zdH?U{tNvbpP|B&Fv~=NdRZo}9C?@qeGm|om9es8u6d1{~Y*q>8z4qB)zoL2n|GiUG zZyP z+vMZ4bE)2*bs7fMCv1xuQ@q*A6O{um9bq>KaPphP~FYY<=YeyVA%a9hpX+aUP}G@!#DNXO17p4&nWpmZC$h5p@nH(@lVdrH9KFph$AvqF@zevF+UJ*HQsDA1vIl?ZD3}$Isj% z(=I-IX|VFkC4gjm@-wCAIQxrguX3Ja-PioLwt2x8?(r zL$<$9le6oNXU+1NuQ@mU+Wf+x&Wtzhh|nzAbu~UIw|z4;4$r!v{UtKz{nMg@j~{c3 zHI(Enj`aPtz4A%3!HSh)3~t`H@3mg;SZ^sOS!Yoq3n>-_a_h8GET?t zdvtA?@&;=oKmM#9Hr+Iyt<}^1=3KC`>E5+@V&K1aP~w6U_E@Yw?*Gqv>-ad-mezzdVJy_;(sTvsk*_sI!!7V%O_b-?RIZ za{EfTcTCp5y!h@1gA|{;=hrNEU%Z1o(N(J|XO-z0mg{v#6BCVHMV6{(ZC+jC(rNdV zM_Ae@xSi2y^Wwxwrn`22{#mnL547B-rbAijRQR#cg-W^*v z`QF{Zz3cl*PQK$M?6X@mr)vsIY1Y=9DCuC6nXVFfy(S^~oue)H4~2_?sRa$!4{VE5 z?4Kg##!}TS9XZqIcleTRv)?z`uug5dC$7NvQ=q43rtXSV$J-{gpIM`%_Cz1r^@ZVs zV-nBe5`o^J!>)?r39;cecKebP=43_5p60cVD=)gf_QDbX9P#Upx6SRn{3oW>uv(p3nJFd4xrS$d#q4c6k{GwnI(y^XwsdBLFpKSa^+r2c z<(v!LYIn37C$JkXd~@;7iUjqFQyPzUziM1P{l?ms=c|%`7#)c@-}2b4a)b152L}GR zXQ%V#q9fbZ6>xsxlj-BmvRoiC^P#(7UupFr?$`@+*{s)o-SdrCv2U%pluN7A z=8tkI`vj|P?eFhezp!J;kr1OEx6BC*-J0j7t50#dZXYEiy!O_%slEQ|yeG&pG|xUb zfBrxD^A*a9a&^-g?}0YYHij|0-T!C(KgZ8+xewfHUC@1;D|lg<{TsGZ^7sCoI2kW6 zY2(fpFV>#fAa}x4Udi(5W3}C~Ck^@yANI4S`^)Y;zep*Np(JVZV2)3XA$(xzG1}u;DLyThnB`9 z{s(q@zq`jB+-D_q@#3LunHgvP&Cq736uWY`t?`KUD^2fBzmnI9`FLq@**tE}@8~Q% zJUKwg%uZ#spuqDbr;aUGS68dAyY=SXo$iH?&li9AzwvvT?Y7*TGcTAQo0I)kw(#6e z-(|Nq8J}LasaJD)&lzE-Rcv!ug3?Uhulni^#eEes^C*1o zo7oh^5+$M49Qoi}1JjI0Re?2sE?QrAyP%pz_v~#SKknbhT+sb$)sZ`s`CgR^S&w+Rq0^uBRu@6vcKYrO>qGr~pU4(0@y zX?SnB;xAA%b=DNQbr!Nq;`>dGGF_13oAlzUS>>9-eKx03I6|6FS%%NIOUuapeok;| zo$Vhvo;l6TKIyhh+)p?dOPJ0ml)2hfDLg+ae(rg5z+wIcmra;&JrWUr)yXb+Fs$?W zW~ZsU-!PtN-rv73M=1A^9*4`)mhY_$5ebv5el^{dI-!*nyK$bG#=XN|SQH(8GTjwb zlHQ@Gpl30cxBvZ>_seaYZZiLiy8qzi%dYqzN4vHOmt{_LU_7I(5Pm{$LM?ySn}TK) zr4FGrI}?JIUTxj0KQxNS2KMmj#)l+{{PGWAKCw2Z~yn5 z`hU9v`99(THZy`V9XHN4|910B@~XJAN2@PcxG(woV6xrA&U5C4y8>RZNv_-YvEl;1 zYN*Akh^kgghJxRX+4BzR=dBTn$>$Zg!K3upal7%=1sRsNB;QDVT(i3-U5bFO_NUy$ttmb+8bd8Qa{hv*|>MY`q_>~)|_iir!%e-Nw9uxCo(tEV7af=N+0$USF|rU^2_kG+I(O#zjE@S zLT2pKJPRJS3k5>OR&&ga4{&upIDcfaa@wy%7FNS08!sQ}tZePrwP!2WIg94r4TnpO zXEfBNzxir=YSY7R{kop_e~%q+$X)PB=557sVUJ{w;yvuQ62dHgAKq=X;BKLcVVz;h z^ET&?hQ~8(&a67~E5g@zqmF3^tNHQh84YV13fMl}sXw1Tq5j^syM_F_O{VNB`NrTc zc5m}uV+NsvKi%j5-EznegY6ttdKT z+-o-J9NU8Pv*OwA`|yb!Z%DZ+`QE+8!26A-SNS||eU>*2S1vxY65_x9&OS(`J?Fjm z#U;0kUmUkopV;wTr$^{*{q3&>x;0A#jgGr5-pgO2JjaVweYL@@fVBq$7>jWF{$Kyx^7wbkjx!c6?JfUf z*(|`RUHh$h{+*c&-%I@&?2i1}yZSkfa&%@8Vmj{>rZM+e3JZ;V4 z`L^38u6ePimbXLeTlWFGPfJ>g)M6!C!&fkH#5V=`B^a3944lr?+P$)1;k|dQlH1-k z1&QYFPm1)*_|01Xd;7kA`@fg%rKgx3G&nZ%KyqBHU)ie6YeFynFNrbYWj8aw`7x|6 zHvIjxDHi8Fw752xKf9U!Q*X}WYuht-db1u@+E)B|<@tB+0^Ym!sT-9sH@)Vly6kAk zGoeZGXr+^|!s`DQy5D>B{oDL5WBMc8d4CpcUuyhu$6woK$LQkEs?udAV&fIwZN7D6 z&w?+d7G=q4T+ecsFIa7QD?s$j{S4n-&ktNE`tUl0%WCU|2M)n~w_hu{h=%6AS|fRD zT||y!cKVvvZO@;7H;874nv*Mdiz_CoBHCxJRdH-X?ft|@B_E@P1A^7jDFMheDR!U?!P}Sq=x77sz0CO zwB%S-{`3HiRf*wxpFSIYt+d*it37cyyV=dT|I*pEYA@(1jop|lwaA>S;PC9vlHRHQ zY792}EZZ;53Fb;aU!rCeHa$iyQK58qgqnkG#dIOA#@4`TO+j}q+iCxmi23AN(%dW^)8M}pwG9Y;^^(}pP6huhWnkDSN6V7&A!jP zzbksyA+Pz}-_BZWW%c>pW0;#gXSv>u@7&+^I$o_heNmRdnSVz(Bl-~FGZvTedu0yL=3s0(+Yv4Tg z=4wXG)SwMI+}BEv?wYsp%65%E*M8nR&9v@nW3-J{Mc;n$xD8i?xzZnP@QHsaaOSzz zH17Qu_&;kTd}$6qZKC1;f(tZa>=Z$vFx9B@n_x6%2jVJ zo}bIK+u=>DbhqJz*7FDd?72IyUhaM2m5)J1Hw~pf8(#1&I#Qcsuwv8Y`4fF+O-jxT zICN@z$wnoo!eFI1cGJlct#XbL2S2{gHQ!VJzo*pleuq6{R$QmC`u6=TGp{bVzbbP1 z$*T0Drhh-rG%scA{qjDdgDq3M(CGA&q|%qU+V@-+ux`DgxiDplR94TC8|&Y_RCLnV zb7;ziGG4Dt*V`Owd;&Uq7+Rjb{Q1)QyFhXLcfJGcQTzXJ@4r>|<+1$iTdbEjN+q3? zQ{*N{%2YjJTd_UCn=|&?gWtc?k{lVA+~`QYy!={kkWSRTm>t?14jKepNw{HB{7r0Q zzobjl{Vg(QW!lV_Hb~qkzrRCfi)qZ0OH=gko?UU}-Zv9PcT4Sn%9m`00X|za(-|`| zPNg5+eY)@RVdZ=F_RWzWKTO;3@_I#d9b*owlx}X>>0o)smS+d5q5{PG&hEB2t0mMN z)O<<&;ISW4j2qb6?@fGe63DGvz|@wk+Rd{m@N4P*mf7q2l5N(UPd;1l;#@$+iSHNB zefj0Wk}H_8Tdtuz+rhBkye{zU?v%}pQFl1?rzl+hS;)8LW~_eTT<;I3R2#%rdfV@3 z-OT-AM^s#6*6ZAwt&7zfeC5vGwOHA|{=#k#4#q__yw@c)*3A{PXcDP?wRrNq+=YJK zTkYO-+^qPzVAb!wL!z&%4qfxJn0xQhX8F3l{eN%oZ~425{h_+Ug*QyB>*>4i%i2agDw`dtPv>P>hwM(r0)Nhy4EgQ7TuscBKEkRzcn0kZ0Fr zI?4{{P7ls!&`joOJ|S0f?9%P$pKIzEr<^XI+;&UHI^c3+vADRMu1<`usWE;P;iQOw7L@$^L1oy}y8;->!`zhSTT| zyH}z~=DCaEyBW{7u{%U)b#sV_aURMjS|zoDVHK}iLBN`KjjoZ7Aq#euF7-TSxn`=g z-t_eje@+M7yu+b!Uc9BYyz=oD^=~RoAJ1Mk598XmuYKn4UFr<-34edi|9`ap_N>3v zY}L`(id)yRmkQ?3Z2r<(9m^&#|M_Qu!k5zX7K!!$TdVo)Z`!deE^ggozl0kqM;^_d z!?*tX4_Q4vizg=q(m!m`USfLSRO4d5E%L`$r!qAkNREr17P4XDJzE8@${QRJh3oP} z-&noRzc+8gcI_<7#UCW+*Zetl_3W(0%VVqWf4$8;o$m=V^XXkb*34g=>{xNKR(-*= z;4}R{0~pU8d^PQPod?r0$=|uVt%Xgv!;dQ-o^8>btbNzKs>>ojIBDaTFgs&Qi%a`> z?F*)S^F4m_qTg{w2*uJs{6Oc@FVZ1 z|4#*6f~zCaV;G&bUZ`(#Q1n}&FQQoeY1);5Oa|{AIqNKLGtZm9zi|ui^2w)}rPJ21 z6zq-rXlTf?@|;A`jW@ppbMs>-Gf#^Z>V9`=$&LzREz6$F3x^m^PM)+S(r-gSQku(> z%l^Dg*}r8@dv4guyQq&}B6j5wrdE;7-FXjQ{+%pvv5epNd+Bk8KQh;!emXM!v~cH( z{?Ltvo0rDz-)?#{{Y*^t2mQ%YbHchgeTo$Vj2LV9Zrl=GRlR)X)u`o>iH>W}eGQxZ zW3HjL-=0Qh2JRGng*6kza%-jUcFxJQzE#IrYTmuA_VqJMJ+CR2GR{{;Iaf;D%4^W8 z&0Aem;!O4LRj?-KrN0ZGUYaW>LeTV7W&el~j z^QJmq*!TB;c+*Z@wLpGisx@vx7Z@G{QFPSGmT88YgVpu3~6ezPPFG(aLHjQ zr{V2oYS-!cMq=B)5tzr75AI% z-Th|vo}|PXD))@k+M4*COw%6DnIW_-@uc3e3-eYj`0sf)-!VSm-zMS7oYLa_N^&7j zBR2ZS&R^1IrKZr3^zpxfdArbOv&{?JVn2IW%RMa8+*=N<(b{+ejEs=m10 zY5VHF>JFix!`IHU25208!Nn)!)2w~*S=g2fGj8txQzMXF!Fa^7Y-U!c{@iWM`{k6X z^Z$Qe!tzY(Fb{{M$uY(iY}!KaAJ3_)*JlbWR<$?PDLr`kGwW`SZwtJ;<_q59+v29! zCUX2_^bf`z6M`q}+J&=SV09B;(Q|HkcFBnV`xf;l3jb@m-x=P{H!!h}3l0dBSl4)$ zL)D+ni}A`j1tpuk`3x+ratBMwv=en@k8lg++%~;;-XZGM;oJT7|5v~LRle`%vzPNY zz@w9u>+OFu+hGp1Os%Um~v>eqeT$`EDEbc5;To2#t;IgGV|xx9=s84YHy zzF@NLK;T;}pNNstyMvKOb{*``FJsGO%}w@L z9T54e&{9JG*>9mFqxPE_Yz7T?icU#@zz2RHm{j2EqJdrS^{=8p%Ip3V!>$Ea1#bvI1e4+37pRcb1 zZ<{Dx`1kcwtMbf6ioO={-!DdgzjFHVa~0OgKRZhu-c66UbDZ_s zXiHk&iPY3B=bDqIKNd8$2%RR?A=SWO&t`pSw~5I7#CKax+ud7ugx!KIElpm;FL9*- z_acKIp3e^mv;~ER^DTYzjp0n5^t;Y=GFwz1eRS*g~j2pshMY1DL*);`zYDk@}K|K?Nf!PJe|taE+x$? zpdj-=Ws`ICrKz)mSDkSU@k-43&2}|7B)75Z^|kGN%dT%QmSumGx=AYeHfwgaErapZ z2VT_ytB$6BNMf5*GRt|t-1d+DQXdMc4*1WrW4<=y+Vt<>vgy7e{v)K-tEW5YuTgU z+)n>n@Xzb7P4FbEocT-~9fxgSoM${C+_uAStKN!I)_{d;7ljAA8enQ29VMmkrA zO3Ly|uaM6>yxvEYEL@*pr@_nLa>ZW3+i*?pB>#6St_I~N$baw$`S!~vF7)eXlMaS6WVYmD<;wS6aVoZ*GOy|#>7oZoV7 zkl_ zVfD6$A0Nst(OvOWcgGyZ8YfNuyZ(w7-$j13USI#=(&g*5>-y4UnO z_U*u)%p><0J63P~!q-~-_Hj3x?E3Sk)dSSx9$t{2JY`Fl><#AclMkqvwAATsKW^Xs z`pNt1scSZv{NLI6XnWY{_BRjIgg1EZGIv+hd!@Yo&!TTGFSlORo%XqE>ZSLe@3a*> zRIgLj^!(rKaY*!{qr#L;kE-q-ToVyy-m4^)U}N7a^lk#H%hk6v8=a)e?b#zEAWL{i61$*N2zd#_GAHe*Bpb^|q}i+dI@)tM-^?*u~5;O$p&&UzM0l zcPPt7OMKPnFx4sB?DYL+%EP7Ge_P(Ud*^TsqbQU3bi<{a9Cub`@8sV5q^4No&B~(f z_NImPSsL8Y$?vj~L zN|vmQV(>`6Sua07<JUB{kdVTlzv64p z^X2l7?jC<%P#I=m+w!n~cYYTam+`C>@%pP3tQ$=X*wPrzJ(jv8WG6W9jX}E78jYvKHaP`og%eH13j`vSoR@+w2>){-0+K|-Pb#ME%^JmX<9{jp| zL-y0gj(Nvq9`BgLmyyuGvPk?&tD}nDZuJEr36Yi!J+TR2FQ}EhExDiIEqid;=f}$# zo^ia(xc+&CLUq7S$F=80_3ob8AHTTzr|E;tdAAcz{`Tv#O8@G`9=d;jj*LP0)SH1j zU0+u}Z>(PW_A&d*^Ve(ge*X7+xutHs7SXxyLrYe?H+c zk6lUeG3{rDH>R-2&g5KgD7uMz%H8QQy9+J~oUwekW!}f5;_(Tw_ZEEES#4raxc$o4 z=XOjRO$G8J!kS+gZ~H6VP$pn5U@bNOGTUxz&t+3Km#*zux68vh>Nf8_9TW3Er%xOU zcM9xW81>=obcV~CcUabIT(w#F{Moa(%KZydwgkq0{gPe(SiJtPT-v+W_ZWXTWbc0U ze~H)sX_9hFx*vF)FV(1han?LGxOt=R)r&r|#l7{5#iT1k!W-k>&z5&uqw;*WQu~34 zvwJdL8>d`d@|@8-^1>`P)k&fY{TN%?Rz)kVZM|@0^)i+_8|Uttw|liz6u-dAVEeR{ z_qKgG@M2X5TlfoSahISymDOd5DizO_d>fygnv(8PTX0O+cp}5mH9p>7Z*KHpQPyjm zsS&(jxwG`1@NK_}bPTq?jGdzPBs+LvA45Ujqg#z#+l^ma?l>=UQSwB&^cUlwC-2Wa z*s=ZdkC{f-`=h@Y%&xyVseYwp!R!f7&ZmC&aye9yx#f-Nk-S}p7k=tae)ImK@KcW$ zUbYR1>56K*J&)uG%hVV0?>oKf0{h`jLi>I`)0`v5yEMa~^wHLk!+$RdryUYKom5d( zRhF!C@xnKbH9VFQ{&{b9vGXQOtqs9akwaZ{}&Ym1eW&d*$tr@Y#<+%wzI{bNbDFF3~r*tGQ=q9$lArLfJRK z`{GozC%)sq%Jy0-ktI}?pv3!^wcN)=vsaHh3i>$dIH$1;odu46WTx2JGj zMNLKXwL4-n4pi9KKl=Oh(nn#IV^>xmKj@1V{{vZ6^qxN8EC~4V_{xXvg?H|1A9UIzE}K!t{owM3NpmGRi<=(gro9Yz zJZvRlktHls%a-AEM!xxFw&Ty+R)QSOO63JSZY(PnUoYO~5c2qrXiC>X(IwM;7O23u8`C$HFuY*M?yEj5Z0CGM?U5#*r{6#C$@u}( z{TZVbP8sB`%kW6Fl&Rpp8c-MVbouhvbD1jQzY88{kJ|tDc761>zk98&$1_GdY*E^I zueC9Xr$x5of4k`h_hWvpNm_S{uB=gV{b9Qxy8K;n*Oc@3Z3Qnpc&#kL~(C{#}dTMz7?V9b+&p zX!nJHSdP<72UxUPKL3))D`b4fUAoPZ(PGt)kBpXm=T=|$X!3f&c_r?vvcOA83)_xm zhoehk4qQCvyVRCFC5_?Gk{#3Ehia7{Rta|9K6PeB(NC%3(&`mYK5t!~cWPm$T@!R;?K zewcccIS2V}O;+a7pUbv+>$_L=g@2vSbT#ujuo;Mnl$~vvU-QqDBV9tYgK^PSQNAe! zcgs38Z@=98_TJV-tSzbm|CieD_hFgNoDj24`tD)KWa^f>=iC2( zRXbGusz}(+u=@J}rHz3N>jN42PKPi5@RUv0?~f5vB=7b0LXO>mZv~H@)7aM3%kR3O z`{a&-j>nA0+D@LyC~}SE*edkx@1q1wR*rO!#|tE^0`#8m7Mr8I{YY%gZG|4c1ilQb zoO2u2-B~8fYj=LeVr9W9&UKf<3-`XWm@mIDN@3H(v$stJliS5A_!$=DXL`Hume#-c z|NgaO^Do|P z#}C-PNc*yi=lyo?&vKQ&ICW&0Oj%p~?;Y4IbbP(Xw(ip*Ki=>5U0der!&SU0I`rU7 zFH8CRjDISMbxnFUO%k8~Ti)I&!B(ef(O@>%(JR;V0}I>?FLPEvMMPpeb;{ zv>=bTzribbmN`y4|B+E#h^ssP#>AyYwM!X9Crj&AZWNf&lGOfN?NY(cn3(Act}Twr z_`$lvXUFBbyOSMW&R&22zHr0uUHuGpSE|0hdu*??CSLI3`i5_hM3Z`7nVyM|I?J9FI-!J8|s3`R9f$h!@9$kuFp|*N6^NvT4`|Xc@ zzTEHdw5i>k?V>i9Tvea3_Z_KL$+IF7&lap%#++(@`{$?A3%EDE6MQgNY`(nnN@m5E zY%CUa@yzT8VlRcQ-RZzn@I}QT%A8N{=bRQ5p*_{t?uVQNe=xQR#VXNK`g>AP}8TzOuymx~iJ)--$VRIjsp zKHZFG$`zq6(ZB97a&(jznC^P_{wJuap2twL;H&=sr~7}L{Q2?W-_+lCu3hTMP|SZk zeZ#BNh=@f|TPDxUXNj4hmy{?oWs7FF!V%W2Hy$aIGVIsaYo3Iy1ql8yx4W6QY2MQX z4sVqV(+ad>zxt-${x;)#d&h|s_Se$OEh-F{+71Ln90*yUp;vqA(TNn1hO7N2SCzAN zI5hHWh;CRWm(uN|nbF7=ayOCZ&82|pQp+^Ep2jGwT5-rBaYbOb^^z?)ykEB@R=;+P zD3uTtj4^!|X7NIR&}i)(KD?mlALBW5Nt z^<-=2p>alDX0)}cO6Dw)0A?fLfCi7o+L<-ETf!rh!s>RZX&becbz$NGfm;`0-PW2Oh~ znio-Z=)x7(7OtHer4$?xt<$j;!m~T=wo% zK&j7yo^Jhs4PP}{gENHrU{^ws?_kT2h^LTsyz52gT`(4j6TG@TJJC`r4GPPmf znzX;wf(K4rT=nfj-18@wmT&Noyz^I@)zN9!O5W^*MXby0PJi_^XKCX~E}K*=&)nGL zbjsxU!IgWq@A@3SXC1p^OV7%1^|MktDqc_0C@td9DEUyAzHUOAg}sf{*OOs7Uwhe) zSWGtx-B5gC=iKb+3!+LbujwuJsXekt*f!h4bg_CW4}0v_!oO#j449 z8atsN$#rF)CY`dVQ5Jadg=O#SB`TReBDGGOJo=t9EF()H>cOqsFMAXtWS*z${wtaA zOlOmZ+JjpKR?JHUwso_tI4At-D#OWnZ87>uLPY(BGHqKlT5gy{)#?bXSx(!y?;NUn95A<7?B~ zESoX&iA%nDy1RvX_{@cm7OAhzWGR<9Q`lybz0D(epH%TF!|6E!JDp0qXTDmI)~V$c zx$Djf$qnzrbAB7U$o|bQd0Sk(j+aAZYsQ5wUFFh#&y8K?TE}{ozT40G!@!hbjjKV1 z#a!+sTj$-7=_zwyKfH(~qSV#3qggMLJ%j)1p2RPYLQ^fbtl-SM|AynW(XBt7ANDVl zw@PMW-^+*VW%cU3gss8fpI4pBya$ZZ_uf6;ZH)CA)hxuM!JLf&`gO4*@E_NSl z=?-MQ>f7FZe}Y1trs$jF&*ll}9dw8lc@g&I`PL(4Y-wr{a+5PI)V$L_*}b^P|5w)b zZD|Y{3Su^M#l)gt!AokEs89^XdPu%BD^C zkg8~4tezdbF}r!=&ikC*`FVFMeUxqrtjG(9bg*z&AbF;<+(c9kmA z2&na|iwe7PnQ02|^|#qIzg|iUn2V$_T$247w8?B`PFKm%$tUBkf4%ehbo7PH?YFC3 z??g#o+PQMGLo~yhMOthNi$1QmDA${Jr*PH#)=$#L@?XDPU0QrnC!=*M`xeWFG^Gj0 zQ_Uaj+Ue!@D{@=Z2_s??K^7 z_wT-6qpqL!Oin=XK-{7~nkD>6acghgRMNY8C&0@fK<8!K!rcefsqB1TcdoU&|HhOg zpC^lzBN$Sv!+RN{C-jOg0$rYzy5)mt0{g?xH!ECLxMbv(7i#sgSZb_Ws$&qlaXW9; zd4);L8IvOpENvA#D0Iy3nyJwlDKF6}sqCj%W71}=YnJrh`s0n7==K9kl6DJm?PW}S zyLj_8o>i<`TvOQuou8J^(-D6B^U{m+_P_t!`?nvoRCM9B@B6>o1_rA(?G##Y^v)z@ z4$I?_Q6HZ)h{l-3=uKaDG=HJgHD33;CH|YUN^c1_SF$Q<_=ert!Y&h9ZOI~)zqY7h z(wg&Du|4jA+KWGMP379ufAEW1+Nn>Aw%#doKR4YqVTZ*ht9rl7j~$#ZoLCyn$$P+H z+so&sCt2oSD^~G6uxsAMD@i;bs&4<6NXc7ST$Y?|qtRget7hH4_~5Ivmlpd@o^^1& z-Lc{ietN$*Wd6Gu`XM`~^=I|=u8EJ!zuf3+=ZTE3K6`w+LCLR|7oyJZtlGY4>-E0C z!#_^)EpC11n{fZ#r*dsin>w9-)p_@4Sxk}5vYsKi{PId;m1n;z-^ksG3-4YxGdiyR z?^kh)x!Kkb&%df6_UVVjj+lAs8T2Pyg=B`o3dD@7IP&Q~%9jxx4C5ZFEz?Z@Zgf^Vet2yWZip-p1MMF2~Ah+m^a| zwx#)pxeTUnh`W}z-)8>%wf={)bL*52ZMxDt&uRL~Yl{ViS@+v#PO9Wjb9ngY-)G~8 zAuiibn0;RGcYWQ5!#`x^T_}66v}0xHtDpJ`T6SEEgu?c&JO1&{9>y?65s$+QL)X93 z>n(bG>E-z^T|ve2D-?8W1r2zndcD3oYsm(+3zt`}T>iP~+PBB)>IaWGa_63vbj~{9 zU;pW-?IrM7NxRq4N#cR$s<|O4cJ?^T!cTZ&FjMsr4Ki6&K ze7y9z?MCgVE3@An=2>cy%5S*afA>ATuUWS=!(JB7`=Tt^cubd1wF3e) z6ZN$pJ;^!zsLGW)F1SI%EUfqEhwRN?Wjtl3d|9@qb=kH$wz}C`udlDVdn7UCsy)*q zhh67G|E=ZOFw4&|QRelX*bn;q4KA_HTw(p<>2FoBvxy7uCw!L7xlueOtu#GR-CS+lGAp)^KtDpjRhz{0-FJ{+AIhah!J~)~CVK zOK@$}$1i(!XY`2)_$kZ@IQ2-cYHee{A^oO+8|iO2PA4qma%y$^I`3p`{rtF#{l8x) zx4gV3sdRCcl|{#sowF?~k2^GTt+=+~t@xX_LbAPodXB$Vv2MHE&~x(4ho8@(ZCLi` z{|D>;$bWnp^G#~eyc8DU>%#6ZSlHknc0Y1srFZRonOhoH4oIlJ{P##f zabiZg*N4ZM32c1Fj1~EwwArYy`N|{O$;EAW_}t8A&l+VVHXVMGu=v`x3y$g{buPC# zmGV+wEm&cr_gu4o=J$Y8-pj4zIZbA8&dRCy{EcxD@0kOebS`u+igN9=bZGjlTf?>M zvy$Wyr;PT?hZ9s7eHwRf$mxE3^hCqq4KEkGakp!B`)O2z8q_7k3M7HbNh!MVbOLDx;g?sWL>wO1}W=FT(WjZElO zxg6BFG5jOzGP_HkT$OeZ#5T>%gZ-B%56Wozb)xdTJUpodgJpGf(HwV z=dAv-ZmE2eM*?5i=?~i;1T6@dC+t-ht z^G=`s=w-uh^xKo`jVSH1bQGo`fWy;EN0?Q#i2FWtI5)0~{$xib^gn-+>h z?f>;l{kunT{CAcI&TH@gT6_P{&p!f>QcVL6DoPmTMjYwr>SbKLqLeowmhD9HRr~O^ zR=EQftS?@QJ@J-(`EK6}=Qfk)d-omO^+_(Ulh0-Dj_dbk<*of{R(iWuXJW$PpqQ6F zAs4?rI9MJyL$zDr3fB~?Kj*At^JaxlKN)cR?>p|SuV$Y&i4<(rn{G4ZW4zVDvkbcg z^j;jie6aXl?!&r!MGMwf8qPa;;shZgJhgD0>Bn5bBvqwcTX=5Kg2Q`lEhKNH@UgOOU?^*QDdceX)?|j|hVRzx z+&HtJPsh|jhQlg3D(G*3%Z{zze(?W4X#ayBG_m?mYu&HwAD7gYvu{ z`&S&!*4=yY$RxG*2UX3Bv;-cma9iXkv*xqebnl+*Rdx3RSMIGc6>z!B-r%tyY;j;>#_k;JEM< zgE7;k>~DKNS9e6MzwlP{`mViOoqzw&uPIn|(db@tsU zK0a~Yllq=l?J*Y#+kc@^I3Re7+QFoV4Oc{`KTqHD`^lZ>Up=kwepA;tm%vx!{Xkhj zhxPcGj6Zz4+!}-V&u%w;{KD$Pm9Lh4l{TFIi`Pr6ZdL2J#U}V_u0mh-w%l-)spfy( z(vBZL9C5~e&+_l@@7I^`n|=o^%D>{dRz80IylwVrSMOhrT6pnQNVY<8_>Lacy7DPI0(sB^4qb_=K5ZTSUh{yH zq4nL{eg5`;Iqd(u$u5X&Qe7Bmd#U?oNuT9}2O6mwzn?^>%)cS9Z{cB!XDin!&4}%j zxV7(6nf%mGIbZGS{|B6$J^%j#{YB@`xRltq)gno73(>1C>}uv(!YUv-L0hE4B| zHUG5axf{NE)-o7QpLXuN!18NNhGKDlZu)31U|Ny0f_u+pH_;8Otvr)n^)3?#ys~M> zr?`{ZQC1bdFPkvAId7)z`f9vcj`Ho z`%+$pD`EpyIY>K7H(JzK<_R?fEs{>{%H4g3xAEO;JEk82-5s-Hp879+E6unpardp} z(){I8UMzAgi)PRKeQ9;df*DT|)Gem6>%BdZJbM*`-j#`mf1Z5)=)jJU6~-AS=IBLS zcaNE;dM3&%{6q1C#3V+6;}UrVOTT3uYmWQZ6YjWlnOE$T!~#_Z!Ix9q1lOMmd8=@4 z@hgRurL_*4>MO)-Y;1OYua>@TA`S` zZ_7?uyK=WU;j0H%&u!Rpb1vg#&Jf>^GD@ZXO?_uI5<5gs{F=0Gnn|zNpUB*`r5_Tr ztzEv&C~iN>x`p|jPJx_eVvghaGx|40ZymRt7g5N#gX5G}#_xCMJwv|Vt5kRsJu9#B z_ui0q->$jzyuQZZ6`jCU!|^@+T+bru2cF%t77Oo~qPJ{HEGO?7S528$^)n|--O+FP z*nG?0#QS;^*Bshwx`EkowXK1YhKc)vACFe+zvF}~rQcci*u1{jxc^zh+lBSj$}d;h zw3az$SDUkZ>`k#~yLq<$GtZZ@a}_ggU*i4y_QJ8g#}h@26VsU(+ON-*eOz=;+qZhD zp6`ZSU6V5xqgP3$OkVe5N8{0>A!@7conDY^F<0x_Fw8NX;l}Va$$e@cg?q5cjtVc^Wq1m*Z)nOl@q63-z>)Z zmq+(OAB+?mzXvS&F8#bxYy48E003MwlnLjcD~o0 zw0!URAG;$awp=Yc_xtz8_UG)s%TtqVdklTfyz=FfoppVl`uk70b^Ch*XDZBgGIPGY z<$iVR<%-U|!s@%6Gun%o^$&dhb{5+HobdYh{r~@5XTM2FYq8C7Vt;;H`{1RwRWo@) zgl^6`aB$|LX?3qJX@6wAG%Ky4#jk%><%yje&%{*n3+%r9)yp|{P58lmCyUGbgGI%k zb$%;O60}l_%W<-}%u({wx@jKImSw?Pe+d=1vAlVkePxxw?Srl#e(b2&FpcGttmutj zY*h=6y}UThY|5<;>7F*-PaHDA6Kq%(MPIlVv+*={;5@##+2`J;7Fe$nU*r+oy6)D7 z?b;#VJ-aH>DsNPYm z@3MjupV_va^f*+%r|FcWuT)v3(`9cBQMG^x2fe>)UDR?AJ)#$SN;TmB+68aBUe~?- za+t4(TekM%1y+u0&fx|r?{xng&7Lo?*!1Y^?dj`tP6Wtn>AfqI`?Oth3YQ2E>(2Du zJB5u`~3KYGu7r?4nh3M%Qm=9_ehQLpBQl8_!VEh zhi6i^HBYFE;r~4VFH(Yxw^J~WPX`T!$&a8Ur2R0Y>vhzr1wY*edYds+v z!}Gf8(9=uH?$1w6PrhuwWLN)cO(q&B*vPWGaUNWkw8_YHE{;=!Xfh()n7JgV@leB2fO1|BNf{-o8)! zW+oL)unt=X(e_t*#URIGhYw}+vt-oeJPPoRE+L;7* zywwn$sG-f#v+Z}tx@)ZO?;q!IkY2L&-c}=tZ?(-U7QXGw|8R~`wE30ky#J;$tn2}s z)Wdudwk_CvjhXpK=G=dgAwn9a3p}1ga@uWOQ0pegyukDGZ%4j$zUF?%IGxvOZME}j zn478j{#yLcci;cry>@GN^^TqE_h-Fcugd-4=P#G}_1~I5``7(i{OPFq{T;jJ`F`5i z>8JkEWV86%M5)bZ=P>`~XEmC|9K4`Wqs?it7LSL7(8swQl>+SX)~yX|vU}IR?)v`z z{$uO;b7U%(?z<`V()abR7ti0V$aHo+xGg_Iyok4f;lCi`?R~B984_c&w`5y3wKxCr znZAH`*OtPS>Na*22A3E3)ctzKyYB4D!;t zLGJI;#O!_fQ?723T=9W1WBOvr?P|-yZ~b2!K5_B%+YVOujF;pJJJx?_DGzuqc>cpA z)rsdOZx=fA`SWz$e}X5B8Pc16O+PL2|G(Fq`~#hyuWkAa|J+nNlsLsiUC&a!{G!~^ zO*%WwoY$__{(jQ9?$gid^E@^$EO?tdc~AMeV>k5WYyVxI|H<|acr_E_v<{v9KThxe)cyWm?H1vUX=U%;`poSKXWR69T3PC~ z1v?maG*vh+s;OP~{c zF!isy7M`6qb-SbUxsu%+x1Jr}yj|NN+Wpt{O$`>Z_u5Q9_As1(ckF=1lQfCke`-Ho zyybl0U83|u;K!d`JbVAX>zE$tbbaH(mr-X$_wEgvdM{+^eW@)5ANYMj!DNVF&yiXNNZ2QaLK~eBFV4?*;DemT!yJ&c2~sEK&Be!+&i<25X>e zc)~J?>K4X{-fHpI^B9+CY+b0+q&9tB!;Iqr;`{yAzRlS6`TG4kjSb&R-!s%q`1Do)d~MJAF}pW6)*;}dWdoYsrRSKxpECb)VRu~}(+$6g8V6R(`ElOidcnE;7vF9(lUs$qUi7@?pTA*V7)P$6 zPH^8rBbAy?jvVKCX4*#&t&CnU_j~R^`}YSsbk;=1zUWw~!t%eZdj4G2<^EL#ISig1 zw|;QAa4P6F-U{cDXK*G1Z}(W!3cDu3n97;5zF zNHb&!dMmV>=(Erc3_pJ+65yR=XSdI43*~<7sUdJ7kdm=&)t^ zucQyje`U(9+;G$okxS1^_1B1Hi!_?ax?ti7yE*h; z3Y3NaUR)nP^B9BOboDum$;VX^TDLq}H@_$0Rs@HZX~c<4X~`=r-YajkTojTQYGvA- z9c3_o@9N|4au1%q73&WS#&O?R)=-Dmq-j5P?On4fG1l*{wC&28 z;?|i{4(3D(X&zu&%zMOo#SWRwe|ht}i@iPsnLEu4yybptPMh+=?eDk0ZAw+0BhTY@ zJ|p+=Z1eXH2`k*8`1^O1Bj_usc*-_pw z-|?yKf%67iUR>Z=zH^=f(|RwJ^Rm3+OEvFT-OcY^@T~0LnPnAotxjCzE&f;cD!hdK z*t3IonyRMX`hAA!5w};M`OHO3&)!T*JsKa7b#Rl!tE9W1D%`%@U-kR0o%yP+ZOp&- zIp*$8+sA3 z|L4NHhv0$g^Od>RpV#^A|CjyY_>$=i3|64#70;QUwkh!crEjbAZ}2SYs=duWdsq19g@^UmO*$U4dwRos z=H?97+qWC#rmgk5Sa#tWyTIpv4=4M{Br_N!u==di+A+`Tf{J)~+hf@Ue-##66~Dc@ zly`aYggV*IH@7EkJ^bg#?Kh42(eDpWadW(*bihaS*Td(wFRn%LHJZGPURAAeZg0u2 z-;v*rWQu#g>6;KcRc{iP((<-KNj9Hz?Z>+rCjVgAKcAan`%<+_eUhH99GYA) z%|-!nYQ6`$A6POh|8hvSFou8UK_-h|_peB*&kRUwcxxqcP_N*Y?(xlahgR-sJ|%R} zytVF+Wo6wy2UQ8KYYtDo?4P20@B3d?iA(OHud2jj7ITL+JvFLf%bTz2&n5Hb*0Li` zyM0TT1jWnm-_Z}anRwPA>fo^k4TUbILo4-S<92Ut+q?Bsv;3c|jx zdM)*D@{G7$Z+F50=L3y-JvWTk@;n1jAqro<)~uAIq_C zb}`^&60DDM&cE*(TDv)feNJl9gRm8MZr{`L+nsF1>YL5BJoWZna~FI2{N>UzowiXg z4z}{Em~C#}I<3_4AyaPK@pgBUoiZBDD-|M|QW>X|c)VNtB=P3!hP4f^EA^LMetSyf zOpaIBn+yNuWxt=m-SfLhnXg50-Q<|>f(zE1zclxp=icB+x&^N+T&+)hy%%<9<*#Sw znZI+{@E8734Sjy;=J}>14?kbucuuVZoegD7PgvYqTmLnbHfz~!P+{|zpSvo(G0tDE zK5W+%W##7GDK`u)Pc&GFh$GC&nCd}!O+E)AiI@?2o7h7zn{}s)> zJLR-UVT|5x-!ly19XoH|zwlQ-V^zkY2><5`=X8i1%_{sO?O?q_g7MVat;g$szyG`U z{*Lz9zkjXX_U~3AgWvPxy8r*V*Z;8pQxSz-K!|Bp@&fNJFCM+=h+P&sm zQ{UF{-Ya`mpT2dblg3P$Gt#Rre~emQDyU{(&9I2egIRb(uC&~_{=KLCk5ua3dK&2{ z6{_AiIZmB7cliaTg1fcM3p?eDHG3{SpTo78&FFi^a}JG{HP=FR`F@yvoPEo;H}5ja zoYrO^x%!u|c^ zk%9`Q1;T$P9#b|G>Zwq>%aDHN*5_IihLw4CDtsBtr5_iqJ8}KU)Aj1>?$3E}<}M@O zoufQmU-Cj{cz+e-RI_PI_GeMPdDZ9FuB=UME6%sQtzw*}ddKSO+h*T{UCy`UPJX#` zcBfZr%)D9Z?e%q$>e!Q5nm8bE>J!^ReS{|G)P4 z^7^W?y*Dp@@ZoV|z53{Z^^)dd2ZHY;r=3uxl*G`}zBh9l!sV<#yS}ixYpH z(2V}0nO%Eh%ZeT69k_SJ^&Z*9u!bcwuW`+#JDf$ge^tN#%^F|#Z|VKQNX6bntsgHQ z_kZ}d*gfYr-y=3X>sw~W*w((~`*KIVu(pn^#bHmyCl4-(#UEa!g-@GySL_~lklpV$ zo2&TE!7=mT*Vp%dcm2)(|J>eC^=)5TmhuC^X@`%wt+bpc_bpITUFwePBQXIjm%q{_;%KKd;7&3HcJKtoU~x7 zjxi1`cK@|*PrF>j+qSI}Ld!21E3bXA|MTXruiYP+UHH{9^CIu&&eR8OX8+#b`O3vs zB&VNJov+%?UtD5+NwG8C^I391dBI8x>qiPjE)rs!XY{EH^{sjJyL4gr297}9?pBr! z*+Le2Qx+Fb=&N?#KL3N&w?|^k1$)@9-2Q8&8f(e4lT~zC$JBcd#HLOC@aIp<`zi5E zpII+7MxQtzsL9H8@ZPePqY}Hcxwr&Qt|^zBv#LXYIq2rEy+0<`|MLHsUjI$Mure>= zy66RVgSj8h|Nr^F`F-7Y-f!C;{@(vn`$zl#bNAgZFQ0d1>B}iI7j9T+P*AzALD+;x z{-z}N5gC^kLAQU-(e_fU`Fqy9oaaF8T|)+W6UHB3?{7WcULKuld`QT+v_;Y5t)p_I zJExNO<;h~kh1WYHV=K?>F$%s}yX^MYf9fB?L%P;YSbmXjOSg&{)#^_fm(} zwr#&{%$Ls6jCwL-WghQ;`Rez-v~N$l%l`M+jN-Mc_I|f~KJWL7=WoBg-DX{P^sT!= z-4oU)j1hkrCr;2|6uSR_`H`@Y(tieyBkUp*0-8ElgeG?6$hbQxO=xKlF5i%B%~_PZ z{qoywm+x+WzxVmZ)mdjPk3BdnQM_*Fs&5NTu;{9Pb& zLDZti=<+wZf`z&-^j-$7s6MRh?vwxdWqSEU=d7)3sz3jpGQVk!S!5x^7 zQe5_9Y5YIYnxE!%+zE&3b{#F!`0?m_z2F(n|NrWLM z`u~UYAHBP%oMB?Vl_SJy<^tocFb>UCq7r=ydInJocKx`e{bcRRLRF@<)_UjHUwu{; zBi+FNx#Cl2f9=!e^!xurrv`CwG|RR4*G*>l*gAiY|NqsZ+JcRnpSM(7@T`sdzRhW^ z($?j-cgoq9XNGj&GtDu6;=5LTYhhO0i`7?7AIcT*@Yv(LNOCJf(Bc`3e?AvprDLJ{ zJwRki)u;Qbo90MVDlOU5HhYEcxpjV0th-Mhz2kp>;UCro%FAM3obW9yua*|(+hw(I z^0Nr@p08pX7HyN_FYQb*pSV%fQT@xJFB`ZMKL6V9V<^*`pdld4v*K{nixtJ}R&EI| zCfKk|-*@C?&V2b6E2#*XEw?ny`wmN}-1tw1m6W#d}56#p_;2 zzkg)D?^9^OtPh|5$$8r{vizAF|0DXx^nX|6kLv%mk8ir+t+4-q|9|UxzNaMzPEY@S zZv(skirQ_A3$Ab}AAI;lW{QaKwV4&{%Xp@8ZGDvD`YKMg#NuxJ>a$;Wm@&vdb99+z zWNREOy7HPw;+607HhHePy=iIYAfV-S6%OX~Vmu&|37HoN$<2xt%CqrTI zxu(DKk`2=D+`H%4-FWqEe2|9pl_x%{o|%7qw}1b|xycE?Z!_!l+^+p`!pna8v%hgd zwmcJdEjGO*%B6ee_{7N?KX@PIPusF5>aX1w>pK<4;Jg+iB>jNKKkW;ocHJD z_T|5#&mSyXB==ME%*uH8-0yN`PPUR8Iz#3-zYw-Ho!|WVy1^ud^H)TAjXxUH`QEL+ zKVO_*Tj-V0WznUXy=&bBraXFjdOF`{@7~WE*=N>unlJuXnQ<`0C)mWGani=tlm1Wg zB${)W9DdxoUMFpN-r|n@MxCa^ALT-M&%cj<)N4NP!TNva?Yr;)x)pACS5>6CZ~m{9 z^}PCa6`eBLntpv9Gj&hstXR$(b+>5uPI)tCb@jDvPAk?g<~if?T|Yj~lHvN}TMRWf zj;GuImek#P!z|(WuAI!Ca9QK0PtU9q{SYFY+<5Wjp$p6JI=DZ&yh1fT_U;#-!@dHM zOitgI>^=N3)u-~w$CWc5Jqw$-$tlNi>SF&7&Ac0z|4*HAbV3FD#V#AmBXcbrS2=&% zz8WOJ(X*%X0=OT3d)B#{Gh||M*|~+U`I~e!W8L2i*SSu;bobUVr|rMC zdFLN+n^FI#*jO{`nQrd<+fQ@SpZ}9-d-pzex8`=+J$#y_y4TDsBt%+{MomArQ9^oR zRCc{x_UB6>3O9TX^)5aUd)850_B={g)d2oXT5v>zPoa0bf83P1vX3X@V36qhJ)bi}tRK!T z-^X45JO5wpo{z_@4H9kkRrfsp>pfxaE~6vG94uSqlsH!<&6C`!XDb-IrD1YYWs|4! z39b-r!{n+@FHV-vylKk+09wZV`L+DW37x0G^Sfqn)=V?a{;$6I1z zYyCMpHyy6)oVe-m)3p(6TO8j$Gj_?2*&zP%nVh=fI^IsHkfH{rO8Bgc{%e6qXBw={*9Rrqu$E%knqAbF-* z!zOP=?y)+1W*!aBE;$AdpZy13w50Dj^m{e8^e)FUW{w|?O44VsusA+D$r&-l@mZtO zvM&xycR5_!87>Oh)XuCCTK>USL4CSr%7v@$imTf+Q&pJM*iLAj5DE5ry{+k5C{v`{ zCLS@inF&b==kl_-Q$qqpI3t%-2|l|~Y2GP+!sevl*$W)AU&OU3n%_+S`hR}MgpLW8 zjf;Ld7exQsH75m-7g2qLB z|J9soABdd{^?R5lVZWG*aYIMayu4&lA)EFK@8eiaGD1>jghe zR6-0zbXTZV{5xno<*?w>f+k&7fu<|M_x?U8pHRk~C!hZ3PWZ4Z4+2*{jvi^(r<+tc^z)r)&url<)d&RhOR|KGXo`{u1v zeGZQ1j}@=i_SZLOZ2xh#*~;d<%bu!dY+~kHCnW5An%j8u#Ugj-DY{lw7ryO!{kX?E zK)>(Yz4hrE4@-8IpUC9D!KY;@cfN}8y@0l%kUxi9)SLOHJJ_XmhqlkWy{__VHFKrc zjAbG}3f^8@;~>dZd_!3|XM*bEwErAhQqR{W&1yDy+1;YRxUTTf+l?kk#pl&;mM)rl zcFK;K^Aa!WEd0ODd-sF2+v<64zx3dK$kSD}Q$cdVtaG&m{y7>R?yU`Hcgie(7HD_# zU#yqqC4r5d%y}n{{&=sa+OBK#^V6K0hqc%3VEcOT$)UopTa+Y<1gr1b39tRQsCV+? zEcd%_YC1(VBQ2zk?fmervUdIkFE!h&%8<z?HD*1W$O>iWYmfTyKsU9A~uN#p^`y3D>=GuV;F{_dnDB_v`;^#nt~3 zvH$=1KewFy&VxZ>9bz3iD>gZNVewP1u=ZV#l9yb_-w;yv+P)a#aVlc;VXH3(P1|Rr5LZ6e@_C){ z-Cx&_-xKy-lsen#`3vS!?zsIAuivQV`}gCYZon* z3BA0Z^Gb?dA5CpNzC5%4?mIC}!x@ds{qq&8KHW9;^~mhvNcz9`N|9LAjj; zzgNAt=f$=|xe2S*Z(+aZ^Z4+?^Ha^mw%6`m5XZ6T?#sMNpvS8TG=meyP8(v zTYTig9-Ew-Hj`}U#+-cMBA_{A*`2@*WtLV(Q#Rza^?gE8>qjUA-j2 zer}h)&xy{&tq-p$*4-v8$X|3mwq{r{Qw{CE)iXZru6 z^=<0@-)5va>#E0RM|R3IUfQg@N^FhF^^70d2TT%YE$fx{u%3T<)06deZ&zRMDz^RS zAp8G}aB$t9<8`0D#{aoA{Y^oP!F!`6>+O^-Pn_RkIQay@4~ zXBv~#+7i>0yeGfEOq+QnC;6vO_CCMM*?fDtzRa$AELd`@DnF`5eXd5V&!x9>cK#H~ z{lS_$=}X6rP_OG!`-|oOOq_gS@2|7DHJvM^KQtV&mV36$o6RJD$Hdz3Yej_D%ic|^7O*7mmn=4Y{UX(J(W%o8OYg*R zC1eP^b1_{szx^tYRM+weRfnG2eV6_5Dtw=0kn8?`r(UwG?3sQ0`p5bIm;V>N_wUN_ zkMHbj`RD(6vV7KHk_x-P}&br=jFX{HNm=|})TwnCt*OmQP)o#!2 zwp-uNXbj2f;t$wj7s< z(cU=qyXj?(jNhBrdUPD}EWfp=x4D#`chkKYW|{9+9Dn!Dea7yOlaA-5OQ;#VJz(Y< zd}mFM<{!Q_=C`tzt`0p>rr@(em1k|(*LAx!3YsQ1PJZ}tv8>(SmHtWdc)o@d+Gs7S zVQ+i*;Zga=FBi=}{CHRUr_=r)^N)-557`5!H${n9zGs}xc>8b)|4PnK{<}Ue3oJ^D z*G)+a|D?jI{_^^nU1ll91%K`T-_zf-XWATaG#+_8_x#?!uPs04pH7+|cKJ@p&$GYG z4f7RFZ(DAwK0}eoH)>MM{b1o%$+`aKN{=RU6`mLKu$=M8aL+vd*}l8qnR}d{@}1}V zo0;F5ZFPd#o=&(mQJgoU%jvjI&VdIxQXl8iE_8rO+WV8ew}lJ*-dkHC+lESlj+Xxc~;_zYV}G? zr7vQCMV)RtE_ME*N#*7zf%|!<3JMrW2xo0vwzosj+MOysos@h9t!Xc3XuTOUGSDhhLbc(NWlK+xb>K(d*-)Eam z_{Nbt`|1bYj{lEX7FU1x!gNf(pxT<9Q->o#Ct+2B7XQ5OpV?Nu|54b-G^alI-fr%x z2X3s{8gb{dn=`Z2wj0NV<+lA$y%+Uhp7`0Yn2Tz`i@AgDZtGaj+qT>F)HlnmpB-O6 zv3>Pn`#-^Jl0W|KGjUQltm3+H;<@q+m!rk7p zu76%3?`igbpDkN4SM%y;d7W2Zbn$8)*HRP_Of$9f7hS}fw)FL%=t=WuGlynKvc02#Uw>7>V5i@Ci zvDMC|LrM!LUo&;p?9#li@Z3_wvDkjP*!<3nIUOB8N~~=EZLj-v|F7`%NyWD7I1aSe zocX+GiB6Tpy>?E|9qU)#pJ1Wl%EfGI|4UBB#WAONvJltw&3FEkge2F`TcnV&<4|G5 zj$he&LQZ#E<{97oBwU(qG*$Y^rMR@+ol{W0JVMO%)a9E; zYC0Ldv?bq2pKtu5T9I#w%i3KhFB-UBo{@CDsU|}=>A4Jpl5E*MvmI}43W!|zc9sA5 zKQHbRnVb{OCT>`3o#7+814#*Z0!KOby3^E+aHo204sW0{j3%U%f^@ZJ$f zUQ!XYjLopsb&KvszOyH8R!_8uVZ6Q0KGA3QmTdf(-A@uP<%PERBx0tPJdTaW4P8+EHOm!j9gJE862!=P~Fs`n4n-`(ylE zy7>psGRe;=Ctfya-gkQYgd=v|9kbhagprgOHgy=0<&+RDYY z#akG*w3)K5PUx_k=2*Mw>7JZQ2^*86Z;Kzf+3G1yDbV7Yl%T-o(zm3u;&HN-0QX^M zr=t@$&zZcMqp4eg*HgIZ7Rw^Z-?OFf+_Pf~bn~k=@Lv$1RG`$ck3;|emUV@PSTDq9 z_b$tlProc^w(-($_3x1%u3Pwi-mvcCJISK@9s8viWBaq2KP1ZAe>SfF`aI}Sb4S!{ zuZ}l|7WSX)tqoH9{&`x*FO|1Pi(4a&XUx7{-z4;F`bDu{VZ6Edo1ck6A?T!rg#lXI>xZVmGZeph4s zf2Nvpx08zTv!9$UR}Tlar9D&J8K+-x_e0FBZjlT;&?})s9fMo7pE3l0uGaX%g^Zre(|G9jP-e!mLwuI@;Dam(lsqvUHZr;_>bGvS;{+6pjR~LtymV8?yqN9zweh#1n>HLpWd#Xd3nu>qfe{9tvdF2&x@;3=Dtsy zeGh0czfrB2vEX`xT-5Pj++Pxo>gk=|C@#a9UvoF+dh#*n$BI2anchkjNT%-!$jmus z`ey3;gYQeXbnaUE$}sgn+Ke*|?;LKpziXQOcG;VZ%O+>nt#5b!rgu2^+J2ErCb69o zB1W$7if&Jtt+=Vl*x;0x`-qbs6Yfnn{26iPVnY*W+%R6)U+^+D+4#JCO20D82>Lzq3tO;LPEjq`K z``OED`4vS+-ujj`#msfEX`FO0!g=2GU#FTE%@CBt2K_zRN!!zr`@8{!7f9Wor zxKma2)P|(Ol*MZeJC4=XXx}S}T#?lN*7q_)Zu|H5!pWM#&l%lbe#sl|5U zqOb+mcvkLIx9oE{^3{9y(k)r7t-1PJntZC>Y~KIo+n=qQuWirnb$px9#lzg$u=HE; zTl+;PCZ0I{@!rq(1~W|R&TM@H)QfiJ+56AML zK7j1lgB;k}nX?Ln78;4@BliK&c-(P$D`BUh;^+DkIfSTWX^JBEnef_~)`p4Lp zY0mQK?%7xKZ^Uo>o^bs9k~vBO>eYMRzc_Pjt%QH!=RGaOw|VF1D$Hx`me;HlZrEHP z#X2SI_|DMpb{3ynCH$h)p@6~>f6)-IOZ5yIxu-iueqEtls#_h`w zZdrCU?q!;J$1=BS$8S?l&zfPO#`bG}yma^HB}9J0M+h^tKff)bru$oO9?$X1#Wq!+)TV8CHtoS?lbf+w?@K@D zE%|Dgt-HWs@2t=bA(C&FoP650r&v0HRfVIi<3*OKLkZ($7C-BP8@c|MWkdWQyyJZM zM{#1)Qx%0b3PIM#kF9_25S1}SyqQC|lOxvq+}9mS4DycxpHAp_@p{>}ym@MgX~k=| zZmzq1_HWGpdcCW=8!VNNESKZ+IveU{B)(sWFW&fR>^Y9?hsIVaA2LnYr^jn|3h=ve+Ov3Wmo7fN>b;}y zo~s9ni$7MYswey|{dZ^EeRuQynN=S@haP@$-QJDazT|H2PQHvb-z#qIE97eT)cQT=I8iBlA;7?1a#Q5tD?u@ti`W#_X0Q7o7a^>5Tk0Tl z|E=mP(hOOv<=$R9cDLL~dsdWy)z$LwDt%8%~<2?uxHsr%elV0qpK6TKVL0v zVV2yyR(V6zuVaU2vTfcM`N7EjVf5Q7{rTUgJulpMS4#cAXvjjpTQTzC+t22ncbCYm zzWDdo@#hz=`RW#~zbU-ls(zmXtChRsg`GxO%8ZviC+PX7>Zm)OYq`Ag*!d@V3)gHd zYgVlPpt0)j&(I|{?1~$XS-PrkSv7Y-*^$$~nd`p4zJKgv#Rr?-h)~bF5C643EU`-1 z75U+qwExG$_Me>lCiyVvzx(`<*Ye<+q)08VScP3Ijn^5ziX5KDdog7S8-vrFlJ775 zYk$SFeh^=u`n)Peuz~;OjkkF$40az^E|+gm)J*TFQuMN{JlM4JSOoX2u8XhAu3K+f zmAy9N$_9>wO^K2lR92*DxUDdA%xo%ha%^=7TvG94ji$)S$BD`BUmVfxjV)9WG;&PP zP`W2_;Bo5hFBi)mr>Qse8^{DYZZKK6O5EMK(fGflr6I@FSk9Y&e;rlPNfq3r^_f9# zwpC!@l5b6~&2zu|p5WYZJKcc$irAV@=C2KR8nk6@_W1T*bn=BYzb8(xQjWe(LyW?ZP?t63mz2J?1N>kIJ_^;63Wr{PJ$n^xwr_=0Dc^ta9P#mVILPat|$99{%g! z?rWEC{yIGKznog?LH3JsdZqW?n04QK)>iTFZ_p{pCIgY|PYSXDjqYyiRookY`OTL+ zy>Z7wQ5H|ekmr?4eD*%{x_KbdaSw}5w6p^f*OpEsudUz72P zqtIAKNki&k++IiFGrw!CWL~R72lx9Q{J0wbv)$f(hTkeh?r?pbGkUI3!Z#Kz5U|&1 zf2HBzGjXeo!q*#~Apxx~XKkLRsc4uuulPK7KC8?_1&xQ?@mB+!m)+3m;w;|5tu$_`BKH3x(q&%^H-?ZS-^YR+I&{x{2{coS2 zoB#O7_s6$ZC<^ee&2Y2$zh}XIt=^9d51(&st5z+4;-H&UbNiPA%hs^}djg$A@6R`W zKF@kW1^cp_o8<#!Sx>PkHFE6AEmfYoD(uRxBhwd6YdO4k;S@FFwJSnDe)`#R|EGGF zfBmQ2KMUXgv)fbQ_v3KAiubqGRrVcx#ci~`WJTcJtTtuq^YCv?meU^kaYG6-31z0k0#q3h^9>4(nm&oxGS>^A%$d+cjxLH6?O zbn6#47HcQ%`s!)zzw`c-Y~8=_-6XD?KH*w$Xp2R2lxWc1?|c5f$(wh0+1Hlq^X!^l zY&^{>9k{wstLWTn?l_T_((N@XkIE}P{oJzut=zphOWyCtyh6>V z-tJtZ-M;m}ca0b9DoyKe-8Zj%#MUMMZ|`FJMv)0|DcU_x4o=Li=R4kCb|87r`)!;D zwWT}Rzy3eGQ}SZV>C&T>%?A!{h%f)9JZYiUiJP)InyD)UdnT=~edK*aVe3a03AJ?v zh9VuJQ-T&M9?kuBXO-y>qkl6&6^hl>3CF^w6dlH|Ihr- zqx*lk zTrg4or*b)4kc#;|PhrN~CBNY5S z!23<%(oT&pxBi+neYjhC`}VY!G#-t_bJcVF^bar5*lC-2eyw`G!VZfgUXR|TJzRf| z=So!Iw4-yMxG1aN{d(nv>rsVWE&h$(kM{U+21UgecmJv_`F`FsdCB)}q|SYR>U(v;U#WncC+&)!UrI0h+PqqQ{%;$V zwCOC{WE_h>EnWG=KHEHf(L0G3Z1wwQWipx{h+LeS{VMhMUG0T}vyYt;VNTq%wsh9y z1z#<4ter(;o<7`f{k-S!U(U|rHT6O|b97xrm$oGeY0fa3k$13jVzHB7kI2diXAK3C zo7r2l4xav<9x<)DgUc)S(dp|#_v_wo4}7)#!!`9Xg;^i}{1jX|Ct#Z7=}iqg6#Th6 z{F$?!XiR<~b$rg`=X?irEL1nH%Kpi%R#IOz^K4GJuJ!fD{HH#icNIJEvSh}y%>Uuj zj{e&_=S8p95f_$IETXcHqIcf^!uaKGx$-a5rm6SeOgpjn`a8{cPgL)(U$!NUxq=}e zs(iPL;Q3d-y;ca%mzXFjFSs$U!)Y~d&ib_?$-z)#%v}1Q|PY=uLoxhJXUrFuWcJ+yQyP2QS znU`hT=I6Cexh}mnnJe+Gw{);n8ZWzrluG65nEa=V3wEFB6)x94wODq;Vmsbt(-$7F zU-KX<@KA5T^;v@D`7sac>i-lk`}51@%pV#4{vKYQ1+Pw)rx~0+JjJr=V{*3viN>;L zS3EJvw4p%rjOD^>M<*MK29#C5i(*kxw^!%--)1<2C#m~(`s9UEg!_&wyEI5`vVA^N zX2b2fN&EL7{r!Hv!SeJScWdR|?2m1B73)fTWS!nN=GTB!*c?7`-`Nzf$Ru&<)rs$WxP)J^ZWKmYk&h8(HPjNCUsTQh^~^6Z zS4!^t(xqV<)oQyP?&zf7Sh>i3XK;Ukt$MKOPGRE(VG}0(|M~CVjm}gC_SLuU?{Z5j zt_*S6oYlNjRj2gg+z)@+-to21nPutQ&1UxG%!!+}mx|{(E4^5mf7Z8bR?&eg>ORH= z^%hJg_C>!}`882OT&5-J_m;hW*Ucof1YLNya(S&>5qhZXhVhHLKB)z+IhU>7*8hCl zVpZ3B%#mO4k6hCx`7fXCtM4DD!Re4U z`|grnUB=*tCniO`y>=sb&GanY2_GKim)%-@=Ylf4r`LoB#0Z_A-lk?+UG?rX{;Y2Ca#k6Om!G@Y>Y;W{%n{ z?e*`(FYU0J7SR1->k~*+$eWv&-)Cvqey`^Bhd)1jFMoJ!u<7i+?{hYo9ow=h?aCv& zC#$;Vlz-fuw`x(E0ax43%mPlgLkYVXxk`MtZZ>sYcW{*hA7|XLj}`J9&6VdWxzBJ$ zhAFYGXxcr$@&|VSV<79tN5PVYF3OYd32Cgol@{EzkuC7T{K<_IXBeiYpHvof(JE3q zv%4iq+oiwa@5^8rv3H+r=d&!=lef{IQ?|`NZ<6I^2a{b_40#P~b3IB71=^JuGK}`C zrRT8h5sb|!+IBUe<6PJO)izNtlJ4)Xy)$)zg%#^Mjwag`2frUV9$ z>o#3=n6#l*SIpqQM@x#Aw9%us7ZxmGJFA+_pE>Z$ZnNTB`+Ra$)rH8%&az)8ML3%{ zE&Hy|bWu4d%pm-V19#EA%H-F5p#dvD+61q;^2c!6(-tl6WqX*Dp5NOe$iS?6xUOD! zo;YjA_fvNn8u{-D%kaN{Y`w4hLw5X6E4zQ!tbaU||5tbC-n}GE_8Dp&dJ5}Sm$RKU zP}DiidBi%!ulBUjyv5geDwrn(zBY`9_9rhorquUO^!8#bzw64*kU~EfDNP7L6w6ljX7K_OIXjYx%o{=&hN5H z;v6+~cCSMlEM@%z>4-VOqKq?twk~@&%fqbZ=-yl5zgF+;n;D~^n)mdU zN}EU|&#qIq^P}Q9Vt?EEARBh#c7-`6E`PbKf`=qp)Tmr9hZ-Ru@l*z@f>5( zI1o@i-GJfIY7Now^*f3UD?iL#cVzq2=7Xy_1FiGzRxx`e?AW>``jeN5nr^N?qqc!& zLh=d~fwF*y=YGC;Eh#jmO6H!l`l@SD6F;#iyFI#jzVL*>Oq(^@Pg$5~9W*jjKUf|1B@b-Ln z1ltmgb-rtD&o@;ldL3U97H9wR)6eXi;I68&#lAmJ_5U~f*FO_p?)p^FaB}pQbp;v8 z)!Xl`d;eb7=+s*4ua(>N=RQ#tQnBE(Fsss5YMT8uSo-X*eU&PkSIX_>m?*vAMgpJl z``G&Pod-R4pFAz0b0r~cW5ah&i@97O?=ZbcVy^}f^Tmn<%S#zV&S(Dq@ow#gxhKqPxOzXYIXU}M+Q-#GECD$>4Y5V9d~aBs zRrh;%JK^sw>HCw5AEcP9$TFzgtbfmD{|AMPuBp3x0?rCv5} zJ=5mBF3e@Hd-8bq{^#6Zo73NG3F>@&W4=J)ndyuA=$u3MCfhjbr+?Y|E28B#??mh0 zm8bRIR~5WC>NivJgmCi|xjXL9=M+To-FTm;G^OL(eeqk*-#v0ax%Z^y&iD4>A$!{| z${pz|Yq)dp!rX9{C2R#VE-dg}u~Pl8spQ>Njd2Xx3TGco`Ecy@`h`>OADNGbSJ(6L;`8(GA6~!o zYoD9gTR-=YwyZPVxUc9YpYPISd-C$rPMeZ@+x#>C-fa_Icth-e``Z5S-I+U@m~O{3 zwbyAvUl zn4dfg-S;oqoU6N3!MMED(U0?}4$o$p-qV_iE4|OR8k{vydSdhObNc!9l?>n&og&Bi z{~Y*!egDV(|JR$Im0Z5`3&ZR=#pb1w+-J4gKY1Q5|I5Ub-{q+8yEUdk#Ncaz`?vYt z3ELF-74zD7LgE=y)GYk#uhtl=PH`>VJm0J}NB19N^6^y{xyx;~zcYBgyL4mljK5Fp zRF#Z)_LN2M__X$ep5X+|qf?v%IOOclS?p7}a_EMCf1y>{8@acROWtuiygHecp*<-y z?^}S{f%n%1damuPP3MbO?^$M*Y?yV5A^+03u4TKDow~b9`54U%cWLc<^uFSTL55Dt zVzK(i_7~!-HXq1+!CJ#BylqR`o6Bzkj&QP6yKXyDnY=+!$%}9L$wz*@RtjQ13E3W( zrbX<`&63g**u!>+^?Kr;pX{H-vn1Y|sGj;@9i@`L``xrpMgiMnYxb?$uYTvzW@CoN z6^)mL#NXL|+T-wsf!W$iY?5oJ>m$yrw!1bDpDlZI^0Mu;$>!pg=l6M>?6%Mb>a7InMgimKX5kr&!W`mJNsBp5=Y@ zQT4|~Wq#eH_OeisoV#%Fv?KY&wbQw*7njAR<t$S!1nY<>(rCrgQ1}dHNoj z&YcNo1WeCVwnvG*`ED&BylPLwOTBAF)dyG>F=$w_D=ht2*TrG<&A>8op7FQc(gvR- z1usqb%)3TviN>cVoAyl+y5e`^thq)vL&PD2(}#WrIo>#&!gn)oP1mE(PIudG8JxG2 zTG&+oYxi}J2jHS@(&PQVz3YGePhR$X&Z?#^&$+iYiL7ExsVsNbcj&|UAlV7$lHBRxyGvfy@GnqCt&c1HV z)5F;*%-7CpZhrZ|k^av3?>lu^0%y5}aZcf-&rCVhR3nlknGMjpC>%U{pi*Bm!zPmJH z-C@5**X{Su&uI$OIZ?UyVA<-6X2FxHIC$plN&issFi4w2c!|)2BgLmU8aCN#^Y}=9%I=?R3gtI~bt^ulv>$%R!0nw<-jp4@GB@VWwv$y=W%C$v<2aHY zr0jJpnj}5{;MErkt@ENpHdr!596RuOcf+OJGduD*+y2&i&;9(Ml6TjkPtB>HBVOFP zJ|og$f$y!9_iV?ewf{VronfMGb^XTvEZS73@07(Ukt@O_5MQ(e~4!c{8gf zt2Fg7Z9PA2MbnIlMQqO{HTS6Bs^(c^c3Q@ZGoMALXU-KtQ5B7A8ybh67Yb(q6F6JGt`1faT_SKzo^$C6T>%IlX|9Qm!V$bYW6zxBGZbbSFG!l&kU2fJQli(P>A{tpZ1Z_9^H}bDXx8YcT6Q*WZPM-cA2P!y z8ZW#OyklFW%fDT+tAu|&QadK;B5X0~RaDNZbh#U>ig~LqK0oMZnv>4yq3J&HLy1}1 zp}g(vjT4L$HQo1oe3smB_^@2`=J^wSuKioR>lxD)rig6Ut4v;8USemyo=6X1yIf+X zyIuX(AO1s9)9=1G8e&yE@9<=YB~DAe{r#i$v-o9f_ij^-ktaTp~{;6_s>0!Y}P-+a=PeKZJpDG->Tn!zYBi&?r2Hc zoX1(mzy4hp5WOH`mu}(gTe6jx9bfIJGQJXZcXqR=0-IrZvo_c1hjNEf*2!h8oZPv2 z{^W#z%p&u(r^hYZbNJ(vcP*h_d*Yv~oVuzdHSgbydw;*}4(EeRBOm?v^L(w_zl-*N zmhR_#%(^U1C8Jqka`xNkmbIGYi|1$FI&^LEnw(b8@M|_Fe)a91$ZT6^&?Vt%!YQGX z^jD4jTAt$T$)|eesL$!+P6#g72s!HT#48}NLv4j>2g_dHTA?+ijm8^o>r9ubZIpVG zuX?Ea(Ao`u^)Ie!a`3sC)^wNmr*9Q{V+^9Cc-@4&oXzqiOjF%@nwK$$q^9AgDTmgaQe9s; zFYs{O>=|tb)SJ9&?s+gqIry9@+5P_!|DPB0_ktG0#xmBp98b6V%$Fq^94w$EaZ>Te zj+vIXZ?wtoHVHcr zxp9j4j_NJWD`tdcHyX3=GF!Mxs)x0OGu5-<97DMJC&397cRPRQ%{;el&%-tB^YdmD z>02E+aP}-;`(Z(?1CQPF8FqEsu5`%|%>DKyTafFE%8An4|8IDwDGQi=S+@Add&QSG zZ}sdnE!wQO%x+?4{hMoBGB0oa{r_WIM#RS$r`r+C6VE(O)4argRc;%*+w8x;RvkDy zoow)u4ErrWwpDk{7+uRBZ zWh2}T`0t&IgkRy7U4MUyH+lqqmCNFu zA!xAe%d#cKqL*f6Klqib-xSJcaOK^kYf2N`)xL22?3%{We>o#(jk#u8QxJb$-;wUh zQ#_YBmu(hLoUmU__pagjU8mz;{Z2KP{KU3o%B91>A<@iD_lxh_9=i4V*AmC|g_)CC zZvSK1di4M5rNXLvpH&5BUHH%Hk}o5+Q&3#?`iX5T;{3j@R^OKwW+&}5?`CA$!Nb*m z3%A?-yUo71qrK&z*tgAprT+P~J?|Cs&WTkm{P)B1dGD9f8h)K+HN7jcA2IoJV{Z)y!7$|8y*5jp=n4m*a;GV^2dS^pAG?{ubZ=Q+of` zby1c=Cw5Gn=a3hE`|>{~JN{h54QEsG587tS=p;PiOPj;$rYHDm<>iO9k3`BAN#t!? zx7pu~@&7Jinai)(G7c$Ju}toXO4H!_G==R^*r%687j7+HEIHX+qUwuJ@yrPt$@7Yy zv(DJ*b5S))TWX?^!<<@KA&m|(H$UT5cOHLB>o=)oxY~8s=I|0F<;7DTO)}H4`25S} z_o^dHODv2=>ie)3KK)mb|6ZgZX^(=WzTP7|%!Q{8H((U-xS&UQsCgslG&UScr$rXF~%u@jx z%QBz4*d=WU39)o-T3Y3lxS%Tc()mt<_sfqJe0a_Nj$y^DMTVYwjk(viOUx)wU+rWc z?;W|$&EfjvE{2+rNVSbXp53^Nd6{#fc3~TN3DZF>y!kpK0EZz>gSQaJ54gK zsK1%uc5uRTmJN%-+=ceM{Gd6%(kMPFYWmPw?4wNU{BIE@NTqMb4~Cg58Bt?>=s7V_$yf^I^^e!E1+3a_3)O zU2eF0{^uh-E+UG)kALrS`+sYhaHfZ&&toAQ!RVV`T$uXyT3p<nY??vM8No;9bzqfPF4)fH1<(g7kRM#vL4!U*J=IXNl z#qD18>rMx)3w>S{BiPXY>c>m_@A;3!|NoobH_K&u6fav=RgJ^7yEQJ)%w)e>zPa__ z;4<5?SgvvM27T(A=zmz1x92%jTVR|L?V3CcI`ms6b0`Ci~ z!uEXo!gv4Qx6dago!9$%s7mfiapS@*3<6iA?sPj^U9bCgM|MNxi(Bt6u8)g)9Mt|@ z^p)`cpUFvEQsT}(AO0h!86%&hf1 z%4z}}SNlAkZRQVrXXNx;qhQU+oXwA3{Flv}?jmJ$!%b#c;-%-kPq&)Co%bxW%9mvy zsPC?987KEHlj-gLKTqTT|JvR!|3`6ZgO2qV`RY$k9?EBNFA#Jxs#$P-$IZ}pPuC@%=l^^0iR66q)6ev7l)vbG+PnAg+y{(Ra?7q6?DNe0 zsvm#zzTUwi@q=5IorrA8;#3xQIyc#QmcyKGt~6&&_Z4~xR*tC$ZG@*?W;$2B=j*lC zKaQF2V@-?K4_WD9lgRUY^S51}uFRev_By)GN!vg<`-^E;#`yR_q#;~`W&V`mLCe^kkt9d-U7vbd^>9^u5 z>%QmJcHRE_|4L{I$5p@O>|<{XaZ+u*$=Q}#95*-deU@(VpsVmea#}NVrwOqF3W4_+U!TqFXUav_x5A{-T35hX{#pdD)ZG`p5PWRtt&Ph zHmr5`?An<(&HsN~|M!)C%^PdGpYFmJ@0m;vV~#kO$YsqTzrx8LbIOliLHL~K>pQN~XxCvr4Ymp!ald420A zo*exHDl>`?KFmn4dh{*NZLMhVIX(6zJQE+SV$a$g-+AnCm50EgUpHoJa!ze2b8#?T z5NUkglOufoMvvK9=7o$~ZOgGJu|R)X-xP0Z=bJz`EqU+ zdr;W(WhP0nM|hUcQSdH&BrE8nCDHaYphi7z??8uPDouI`Hv^|Ac@)9ibn&ztl9T}{Pq zjulQS@s3Lr=Ng>1-r%ROvO!BItYwvCc5AhuP_-IkB4~lK&mFl}$^^QtR4)knvA277 z&C5G|+kQSSSC&bW;d8%ZJ1wDb`98IbT{(UZYt^3|xlj<1>=jV#vF(a52m6_Cx<22S zyjo_jsqi$OX7%{vV{4tK4R`ado8HNtYV=9oMd#bPM7PW8&q}q_WB>j-e)aSYDGBv^ zSMw@u@|`pMCmc4*sd_NAvuttcyB%^76T7Y!u3!E-GW)}}-j?Xoadz+9r}9jH*|xSK zUM=*NZhQoIL`>5N!D@uPV30<%) z4L94i;eP5t6Vu39!n2EJ{k~`Yl*QFnyWsHI`$0Yj9CW#}uC6QJ?x*wk^o(ma9-BW3 z^tUqh=lC+U+0~GHlgMtt2}iA59&Pk0ohYNux|HRzv*sfTg-K$wQzt7iYsyO%cMK1rFqlKqC5l^mJA7ZpQvRd~3?TJ@*Jhcj#e?s3X>{++k)1t41H!bFPbLi_dKaP^# zsq3=tW4_sGZN_PHxF6N+-uOD*!&Ih^eaVp>JI~%YFPXpRC!5{3kLDk*&0hcbtoePH zwW5~qH|U(RtNi#$qNmR3ot?mHlhW&i2~|FFP?r`@I?dfsI>%?&^Iw(vGN zre8eNr`3CcDPDmiTJz@9*ZKE9|9GT3Yopk2(bUXWO@g`tk-Tjo+Ae>sa@cHR%~o&; z^Gj)^9$dUz_Fmm@Uz^&$)*p_|&QCDE|LEI0!Mwbh7X9T-Q9K9UEVG+z{q1Syd)_o& zeKu2t_3LJ`Fh6bi`%i6?!7TsQ=bT$k&hNN;)_=~LlbWu(l3vxZq)7Vgd&DeO?%uM# z*Ct2Xj$d<4WAf4~Qp%2&f~lwW3KLWy7}^jw(e^)a-@~^A8O}S6!^MK(O0-f;v`27(`vDv zRF|#=ZEy7MMJQcas9-2k6t$uH3rB+f11+W*?{7Rm8P4D$68UNSf{v9-OPC`%>t1X$ zcdj{f_ioeDe{7dR7MAs!->>NUe$W2kr0Na7xfVn+uuI2;{g7w4A*6FKl=sYCN8hUx zg85V>a+m!MHEcMTRetqO|HfU}$%SDu&CL(C*0}O>O#hx1o|Dny-WswcJo;AFe?yVq ziLD!ced<42$HRPy{c-E>l)gQ@98xmBICSqEGt;U0KbPlX@b?}Do~UV|-!iz4^hK98 zNidr^FVOg^>cX=7Z_n)5V>Z4&j;PzUF881RXzTU3!#3{=zGu8YdQ)vmE2GeqDwjtQ zOZ(-x6EFL4@V5mVUcs62@tCoyf4tAlwF~9n=1)vdu$=qh&CO!_{KVgHE}mdp#uUN0 zMUXev)_K~3us>EVpTz}M1oU^T)AG|=!t=VVURR&-#F+&$dj!vAT&(Ax$ZW9?S>4;ZW&qiP2rh0Wj}3S7yo^}=zP1I z2Jcyp=`*HH*ty0tRAF{a@!Qv(VIkSN4{DfS=x!03;y>d#XXo;B#sZnHEy?*WFK$|@ zHKSZ0S%6z0@W86w|L5;5=ia7keZG0$fBEDyJFnf^Ui`9nSF~>F?&u&9@4_7ApHlHt zx;WcHK2AC$qPX%=W5`DrQIUKb2T_{6r$uMYwVS^8dsK0s;lKIq|K*d$g6i_4xmO?MoI3 zcit47=$}}8?Bq+f`0CdimJm~NI z#Q*Spf9Ie6habJ3u>3;t$Nsr&k8D{itY)m7ezYU}$2#tYd3=8@`{JMZCEL{2+syrS zT+VjQf$N+SxjLdA-^5&_X8jbaatt_?vL#?+&mYV5*H!@s=d8CmqyFH_7ZGvs=R0bD z%jMm*Ji7V&`@}mv5^aocwjOEgFkG-QTO=t;)NbbwU(fx0ry_!suKU&`o?JHJQIw$f zqdU3&6V;2SN?5t9zR%9Qt1+u7t4PJ~_j{&Vjcw=io<51Ie*n4i-L! z*Bhp!{+tqUiqS<-bB#SNzqhjZ)14S|<^#7&|8mR! z5&Ike|EB#}|8L=!ZXMmSed5;UIf52SZcZyVchB!T8uGRwFZ%wY)zd`v{cW$;@J9Ym zy!laEr@~alBIR9Y?d8N{W!6&9dHz|QulX%^tvSy=_;#Q7)*10!YJZd~5_#5zvnM`I zKDs@pO+(?7-nq>Q%6*($xh|!M1N z<(V!{ele}Ndx3xC*B2UF(sR%LS?p5!HfsA_Tib@eiPsKnt^b#q^smDE`cfnD;|HzR zUVN8n`mfOE!}V|vd)qBrTK1JjOx*Q1@8N$|r4(BpjX1894|P1&%Z;?2870m;b2BLG z;LV$S0-xayV-4ws^(TZ95l-; z&Uz6jQna|~+D_I-jrNKG`MG!Ae_!EhaQ^7Rzpck2RxEyz=zKI|uGq078!o6NxXSA~ zPrMRWn_1@8FO=85eQKF1Pv()d&7ZHGXS&!lg^ee%{cOc+j)|GxPSw4qpPzVP{;c76 zzka^oyxFhQ7%HsSt$rym;nLOceV=}wZ+-i1ugta;QG%Kaw#j^YaXakjrvpcswl`HQ z{Z%%#C^vBXS^b=(&0(4~B?dqD3-_xlANy4Bezts-vVu+5RFg*rqB-S@4`08f`||Ib z?3cDIA^Eo+XW0D@(qGu|;M~iw^NtSoU!tS#UXqd6+v-=ndCnyk0cRCuRkto_pY|rj z+&jhZA6gjf-|w{R?0Q8_mQU|bdza`}3oVLrv(;W3bxrK_{mV+*mp-d7Wmx+~=0)I< zxAnVN`L2`-^)5BNwNx&5x%*G%?2U_}R>$dHWjBgtTJUF$U@Tip-HGy(2R~IsWu-Lt z^tSi^ZD94L)ygdgT(*j~c- zm?6RRMdjlq906X(Y^L_bJ)Oh&QRL)~Bc9Qcfs6tIO|O|(d~u&8aXd{Uu-x3kzuu&A ze#CBh!>rZIzf`B+>ESR;+T-nI|0x+~yh)Nic% ze9=+v&Nq_bOHD6I`O8|G+_n*E35v2jpP}TsO(J?(Li@&5OXnCV9_^ie|3|=*gPSfa z3|q&Lt@xj}Uj&;l*KB?5-oo068?e~p55s98GUnE!_SGyj_ zZFr>Gn0s=my;wr%iHmOjPO@70H}*C4zW&NQGfMeR@IkLT2`Qx>v%_AtsJI8zFV?#v z{8H>~qmFOGr9+Ev7*!^$=jVCzz1qMyD5>M!-v!1jotg^IyF?~mblGsQSwv&A(sUjs z<=&RfpQCrwzpsp$bN}GUpM2%>cea|C5$t6GBgZkyp_o-Eb>D!#lk zH?Q4VY*VJ|eVunQzYB90gl*5$n)&zoyPq8rN=ZEuml(KM4cn%6vm}J{2zoFVZ0hx3 zR`?L{BCf>MZQ)l&(}+2S#$M+tUiV6~Jb1QClHuO8Z1W{t54i1rme+r2|31C{-uc-k zMu8_H9Xk6IB3Fwq{im>bt1h!fL(VQ!-;$>fzcU{?<+4M)+cfTuoKK$Mt5Z4E2WBS8j>p&L zJ5xUFJfjeFXK!_%`Mn=XGdO1F9!N``cw9_ZC*bTl!{GBi5w}E>m&eNZg)wcdVczt8 z(ZN4k!y0}{xE<-qA3ddYS zZoZpX_F?<{dWp7wzcZ4Km+pOMWp-Oi?&%8AjSDq=e_gQ8*Q(F3DLx&Y!EDO@DeV|j zptE_^?>KIqrf()EOW)>ut>l+%ym_>(ML;QuXRmj{#)Ze$`5I19YMQ+FUSa}|bYlX) z!ViVrJZg7XW^8p*DbH%~FyO0!S8%fHzR#}zFme8mGglwK{P?9aq|UZSCp}YWmDg zvip`SJkGyTtL3cuxt_ioAG~&KzbDxrB znGorDGFp>UQmG{~>cRgg?y}vo=g#>Rl-0FezO4K1-rnB3Cw1q{ou9B<`ph%79lD_f z7BS`iRhp6u4zlYqZDv@wL)g_p(dmkY&ehg+6XzX2AbTnQe)36!0H4cuCaw!Bxy-dC z<7((df#zvuJFeMBa9)@HTe&rduaWc5Nj7Pr1|tV!2WRoQ%Oq-c$G3GzOcyy{DD(S( zWb%teUd}nEx~?&MMSe2vDJx7&k}_D*TmMY^P*y<3_6bS8=XZ#C=!hqKm@^+ZTWZX( zC--{VcH1k5uO6@eSO4$C>hJSr&Y#bel+u1q*1*K>{HBjjcZv2bO=oP2lly=hqE*Efg?A?fhzA+r#^(NGe7xul$^OdwY(U z#{I&b+{_A#G*-D~@<@l@F?U>a{Y}M3e#={lhRb!AU2o&yV{4wCCCQj^4HmlU5GXD)>;JA@?bbi4g>Fk;_<1XBws36QY>8(1ePY*^tkcYJb-PpZ zNcZXbX{<&0icbG#IjS)jyElb1Rm&X^`hL6aHcL<(Z`M^)A>S98a^AD2@4x(sNv3Su zf)zZgIG4`2u<4p@n&!Xf%-e4B9y5G!Zm#u?9TvxruDvaBocG-M^Am#(8RYz47`ilR zUiy`&0*i_TBFFjWa;6HOXSf-L22x7cUq7rEqc8%ET!RqUE7HhZ`nvXhmP& ztpA@O>)DgV#dmoa@}G;Esb9YT>-@jR@wPU5 ze&ro0^!8A(vgCPRSEIxcSnnZ!_(ffU=1zw-rKimUZzrvOePKn#@*VP@a>d^^nQrRs zZobSGdocf@+8IX0oQd8C4a^D?U)=jzy2I}>>y|PH)(J^P8$-YD2x7vHgOpPQbspI`Zc^>I#J@=hrt?W|i=gl)Rm8zxB^F+lGK z;9j}+6x-F=2uV7!lgB7VvgB|{J!+Q2* z%a?3Yt zNb9+3d2N01+`-$7F_3jd)q$WbVGJw#mT^35UKAp&x5Q{!W>HJip1fZxt9hP$*RI;< zx>|Kz=&m{j7g@v2&2@sIQmqS?eg2R*(i%Oy!mdfejc2Q?_S>>SMmOQ?WeQx|F=hc5oO^}(-O zBRS_+KGUoFJ$b$2QQjF6OEsAIzin9aLbD@J;{$K^!Hh>crV4Bpnz5+zPPXa4?U5%# zbZ4})D6uxK43_fVdHU6ctZA0n6Fx3HG+CxI@YSd9OLqAwTj(hDZLnBAXY(3`obE}z zib1yRWYrJkf-;VER_RgOC9Ng%6_d5Rf>-x8s|G&)t_v(4lgmS-1 z`O9fbY^3M7FI4@um0{L{IeTq29^U?-q``fbJ0aTcWfCiwcUEkdph$_J`q!$kmjY`o zS(*;-+8I81+9W~tqjMNnHrwC1rfB@IWBt0VO1u}1?;fq-3)(IlCSduU@uO~DXJ77N z=D-rkCe^Js&r8)D{#152Luo^%l>+a{<|v+Tsqd$3Z{MhT)YN$?(}W~N_Yc=K*s{Jf zyDr^vecz%dp(c6^PZ^T7KA3Uoj`(Y{qpojmSXSQ%5WUm6Fl$N8?FX(}OV~7wW?WrW zS1Wz@ZJCAb&fd3W?Yqn0gL2>vA-%l0$r5ZlhZ71NH?5` z;q!}jiwU0@Wo)lrIMlKG_CbyITdd{1&t6(GoITk1wC;4J)47{Et*k4y-gq7C&7~4{ zaPBs6Wg-&U-}vEX^l+UjC1+dPYnMl(U!4v${ZuZzcrzCzq&g_6 zHGHjO5N+}(p6y|OLy<|-?e`Ihz$KO{H5QjHB`=xH-5&d(s;VlOwE$fD{&scguYWfG z&ll?G zs&_$0Ve0}#P0>T5zMei>3WmH)!7W17921lbolO&F$vt{>EobA=)&p|_RGY(R{$dDd zSz95?j#HPy z$A-6M%|_x&LKu2ZZ2iG}H}P3gKmmBnKJ2`*;{Kt>}FfCvH zyrZzY(5GXfK+uK_lHn)(Cx6`8D7lm?z}Kg2#(GDEB?1f~EPe^^m%qQ}^zD0~Na({y z{?-!N`3@mdUO9V6#Mqt}cs?V#b!{foyo6b+RqfkCCr;$6lMgqkUCPQ?`bf%KaA`x8 zNh#yY4AFxetG{_z&xn4L=iYYb)GapVd%U%i)BFD2+R>g?s=^zlzb8d*%fmBlJA-u6 zc4uw79#}pj`|X$Jkk~oO3vc}ul2Gh%bN=~#t73{vPnT9#)B{$B26fJx4`zz))XI7v zpz$|O^zQ8r{X1U;jkuZe56A>$9ke+s(ZrcvJnzlE^@72oHZ^}%)ZFG?e}{z;GQ?9G zE5A-p&bH=r{g31FKTmw`-ThD`L`h)b5`pK3r!V-o{K^AgUp-yUwYS7{x1~nfYV5Mj z+_<>&|7W(D+g{!I#<1?+R?blFkZB#4!v0H7a(F2fs?=~%!%d7`_|*8B9VtIK6k|_xlKec>444I zcTN_05!zcDR^|S=vpAaZX|_h{YO8CEfws#Vv_B=XwO+COcs8x!%A1Tcn=IwmtzU4e zqtMAq@bL~;DWP+I=L-u98}FWE+kH8B&YZc)5^gzW(Mx6+@${YUDJAZCS|$t4){Cx=&xfTKx94YxuS5B4vrs zDmUWe7jFqtpPTEjI%R+SDzgtP3Tp41b_pdBX|H;-=HzxjXUH`}cVm!#~oJ-_V>etSQ8*1G-RJ8Z&7c1JH=#LW>8dw> z^)6NZIrq}=ccabsoT_Gv+i7=ZF))kx929vN z^)_)`UZsd>twVFlQSS_<+YE(ebxo&FHwSa>+7$MydY8^S1v#rH+Mx;_V)s|2Rc_gF zt;s~iKzrM4UMH3r+S_i+nmy(`R@goHE~lTLzhPf=&N10b5e7>bXP@Ov+Q55*Z!eST z71ESBH;#7;wqf#tXDwlZ6RfIXo` z$F4n9SlzrVY1X&86Viv0YDF$FPl?%mlijB8;M6}oL94khJrY``lEl1}Wd+*=w*Bn6 zi&dle{w`1MbQO^~`o8j0b*babMf_F1Hn$$t%-7S+oAZ0unHMiLQevmF-E{1iYfy<2 z2xgd^8sBqROjGsr&F>4Bgsc5tzGPSOf-;shrO=(En~#K=Hl{c zrivOn9kM}pSLv4 zP)*vF%Cf|y;?C--A6+`L1$U%RZ6 z@XOmWws*vIXh3N#x*SjanUJ@uME9;wlm(%QaOQOui+w&S`Zn&8@ z@secLTtQ)-4pl}6hjX`%&MM*A~kzRO@84ox4RsEclmpw*|CNLZ_Z6z zsD1CPZKTe`BU~4mGRE@gaI zN-i+r^`5%zM6i6`A)88J1^tt~E1Kr0Z_hMZC9-DrwCl_c-r7R)A7=G#opQ3Rp2;Px zBW3&7bz9Vu*2%F2JeSmQ<(uBG7yt8K`TsL#H-d9*J=40)Z}XTM>c7VS&;Gx*Z@0MJ zuhsj1m|t?;b-qW?RG5+D?+4@lonnqlSPIV@Ea2dIl5{FL?fwRZ2DZoFc2?M~`1tkF z*=kKwzOs#n{Q1GJSn#<-xgCmBO>rig5l=L3$8HF+gZ-tFIUgI`!3(@ zx12#T8*k4|-fYRpelRV${a>0jQ>;X3SBzHBtuJc@*SOza5ytxY+JiC)uB3MJ>Ym+^ z+|0%YPB#iKGFLXc-X_3uwks^)?r&YW>(Uz>*M8ft*`X}oB%u57Y*Rb~*FoiY)~$Z~ z7`HL|PuR@)p0B-@|Io$@i&eE5Qj|QTC71=A{2wJx`ez-+lD{#SWtnJvp0n@OtXK6? zi7WZsB5y26O*;0h^tnTxrmR)^{-yz!c)7?-3-LvDG7uJ1fR(LddGU z^PR#LuYM%vR9rKoNxoy@O|Qw;0gGzfN2v;QGnB6xA(xy$t*-%Y<)`7_x5cmKcKg@2qHdnVqH$XU67;c=d*f>Fkd zBQ*?aAEJ{EyqRCYHUCyw#T}P){;49fg6=5!W$W7hGA}UsF&EFWOqde&#Kk`{rpH8ud(ZnMJ-J+TuK{rdn2-Pt~U2Oc+1(We_eQe>alrd%b&{J z{>Ue{=cmMBkBWb?=N~@}k2_|-(=8;^BQU9RXIGR0A8WxDm%~b;ifr{8ZoBEdz95lj zljrJnuvDV3af0WreTPbO2!X1a!o1YiO+9t*G5?~H7{nnb2@)T zXRIp2T&sZaAI3=@--?$$_`bS9AXfO2R&)3No)`^YRx;Csz4%_%!EMW13s>2IQc$pWhe&|=ttm^o*pw_bX zeR(36CRDC|OcV`}3gMH%lg)g4Y|9g%9@7luMzc2Ow-7EjszpZhe@*+oB<*fA7gTaQ=X^acJpz0#-LCrJ-6aV|Hm0=yS+FZ6`wE}sy^;K8N@HW^r8{RmzB&r zpImEjv$#2zA>~|KPUoB1Tf_4O3l%(mCq!mTKVi^(^_}DAoQUvQ!f*Sg8yL)x$=sl}eBR3Z zN7lEOSx#W}4P>0~cU}b3)-3J{q4T02(vAeJ>SkTZUw%3)zosrd?azC&yKNl{*|(-` z-+jyA5?h9#<22Rx2a{?R7ytXZc5s)_1(UV4S%oxoBr?D{*UJW{{H{?{@;!Id1eofo|&TaQU4dS^^L=ZA^x)2 zU-tffkvN<0^CsQtQQ?Byx5b)k&t&bm>AX~yPj|vGBc?f49Cx<+SO+kl^2xiH^*?Uc z^Z9#vmY8p=e63)-(CeVhd%;CcJjXt?mtEEkDe$QKaeLXlrskZ*rWRp07KAL5oE`h= zz0jJjFrA{S+cY=#2+rQEu(WsO?Z^PF36o?exN;@kpC+#EYQ4h3VwKWTdA}>>3ErG0 zSB|tb=&k#5=YP=A%Ifd~lT$flZdKHU z{rQ&FE^2aYcpk(l z6zTtNWIrph$ZxOW1s(71%?nr=3^y;m-MMiGu z*Fy`kF7A%Kd-q89G_CUI*Nkt>ou{DY(ERJ!em_B;zwft}*&O(JeN$W1Z8w)6U;F>E z1>I_pyz!3bnXlryPtTcG74O&eZm8yWdO7>XEThQ$62%t1eOvz2eft&r_}SU15B`;P zIDa}|lU_gH)?!)bgM@W#wXc!|oUDY7-z?LdD=n^H{|Z>N_Wd1Yg{b9 zkB4jNWn~sNcQ>AUPA}gd-ofdSX(=!>`t=-{NNr|)4&IJxof6HZ)jw7qwGH3BJWFvo z_cdD)?m72furA)1VR~ap=-*FH*;~F@OZ%`~yseylRnIQ9@89zyuiLu!FJJ2XjKMK1 zw^2+bbz$&X*-Ht(%o3sk!d|MzDBa6iA@+t@BP(;S4C_)kow%s!tCH8)J?1@_dBt zI}Sfu>s(jKuv<$uY)P=oL6P5VE-O|TIZrM4`Gl+d{k@lqmI+jrYFrSMzg2OrOyTaX z9j)Eb;vLQ0yp@#)wlhusR(egdgZJ4R{w%@v#hmN+{nC22vq3XSM%e83#Yd5~r(4++ zJj6{VP3MX%O7ITpali9(S9POh1$WZdN;O9n=ZS&cKN4MMJnxZU^XEJ>Z_#t<1x3rf z&P=^1#2o!hU1WCRZF z==yr~UsN#Hiqw^}VzpmM-+$9oVNrE&=gZ}tM5>GZ4h_ZIC8`K}keRXr_fXMJ_&loMK? zlUDX@bG&3E?!xHtDW{Vs!{KCmS=cpXv(_+8TlX7;bFnQTWFdj^|`>Yug7pv4J z8zfU$wy*KTlWE%$402AWv3M`O`BmZW$pCGKh+B-IOMkCAJ3ao)wxx9eKcs zBQ?j4)lzB8mq(nb%UIFYAf)W_$~mO_P+wuhgMuwLo-Or1=q_4cza^W?Vy!?CFht+rlwn@gCdn(eT5-Lguj zt^R)M2X5O>7SA7f%y`WdV0fOLC5cBfu_JoU-CK{Y-Q+tz_wMEC_kI@Dy_>6F`{Zc& zz2EX@756!Q{&MZx6Bot=yO>WKET_(X{QTLk;MI&b{Mq@Asb`&>Q+B)X-+q?c^6S`F z^?$1Pw8yUW!2Z{t=l}oo_WZwl??1fX_bsySWvu?+of40?@A>+~bCx%s{m0AyKb$Mu z{PWo1eLdUf)w|ccJsp4hnPvW?88at+Sp3@EnM3(`q``UNr#724JfhZBGVm^3u*`Pu zd@VV1fQsV$ioS491ub#33m zt6VNR(&d|rHp-h^&0*6EF@C>!#mB3POsQrPrfyCgz3jO%CBdJ=-)r*!Td?KelCI^V zn--nOxl^BTTVgB2zt1ZfoQ^8`x8GINUKn0IcbOmmKFwnZ1sXQ9>+Kj0zj$=y!3I6c zlsLwdOe}|N&aP(vcV+wAHj^#&*N?U=nwy+n&NLRARM$lO=eB!`*$A_;Z5} zXY+-6(WRvk`>W=z=Qg`4RC~(i=3d2a-++hC&BtGL70LTeuU^*rB_#OQX6IkCaxYxz z(Bg7@nbAJw(b;;r!nc;cb1l3T9l93$NLOe%%61~e@hX>Ek!6LN`H`~nNVaS`%F#Gj?c@Bqp-@jX&_%8ggKKyDe$MXIA@7-a1!;rJ@ z&#~}-&(8n-qyIy>CgxcJflAMvS4)(~XD?Oj(pFWT&Kae&?5EIDkr=z3haS84e|&OM zd5V&P*No+y=WXlR*Y9~QT~Pa%MN#GUmd=0)dsABfFl=P6(_Y<}{@d8yrC`0s+e=yJ zgT>W%L^4iVs^V_zEuWP2RiM%QUWM%U_xAjv;vp|L9gLX!X5r`QTf_cGvG6fYFuQzfE>Ev`-kpli-pwNMe;$c{xVpaPDnHxHCdbtg-@dn~ z=d(Vk+puSJ7hALb)K}EvrvX=ZJaR?DKnO@j34UzS*~(w^l^));;Lt zubifq$^Khw_k0`o`I1Y#Lv?p5)o%QwYq-zlTa`tHR+9HDk+v{5!P6I~Pg{7PLhC~M zLh&WH0xZw7uYUP7#Vl-N<94qfR@w6|hVHUZiZDDcEOB%FD1qE*CPTtt$G4)_D*UN0?cKmX!*_ z)08_e&K8yw|6M7`@a*NMxV4`SO*r)2*{X7a>wRP2ijSZ7|Nm89^JMwIi_7nQ?$!VM zRKNb`S@Cu2KR>(nGjdmHSzWbE`)@^;WeSgX$U2=9?hMh;Jo{O3+N{Vd*9RV}W{S)V z+Qh%wOW_$~(A71LVzOzgvJ^c`U2CUGE){t)XRh?xbxdhzRI8KjwoFogGyl!U2M42f z?ArCE_i$65p5D0+2l?wb{O85ox<8#s@pi%tvBoJ?)Aq{Vd*zwNsM(ihTP(M2b?5bV z{*9gDiOemB-qzSLG-%JWsqEN1nfp4&hpzQzA<9Qu7fqNK_dyInc&LuY?I(;4Uc-=yB~ZCYY`ap&&~u19R1zRqc6 z+a8?VdfD~yfs@V&uPz?Aur1=~#)j3o_g3*<%3EE-pd7I}X2lApj*I)gS@iwgn-lrv z+rO~w3~uu8c$Q{5b2aw=c&H{7Qzevr?3@zjnaaOU+da4b5mV^Pr!J=#glsza-Eih! zlkL-d1Se>D^~S1S*lK)9sp__4p5d;j?#@pR0{i2wYoETH?d{Mn<0{_#Sn1W9?+(@P zo4fh{z7KzS@vQCxZyRH$kOc}y3?6*>!jrE4{Kh+_wu`S9RI->jv?_8Hm^i8lPGC}O z>s8DTRA^*eDK+!;fjN^CW<8U+@F)?s7U1x|KX1OgS}Gp@^U&w>dp~^E-}mKGz30a# zC(jy|6#uQyV>t1iv%I37)z+kwg8l#g)rv^$HiL1pPR8xLspwTU3^Un%A?P%dZ{Jdyt&V zqnLG)qt8mAxg4d7w%wK){nCSI6D6eVSk~j zk!&yW=KQT^-aHc~`ZpKyF_#xcXI?B5BCA6g$*q-4B3&weAT`*qIx)eA%Hj9zCgn3UADPb~jTK!LNW zNI+H;7bB~1-KtyfowGMb-P*9|-l7QGh7&mpITd+2G?OIQmsli8xE&WxYnd?N5?>+9 z3Bg$=D(9m!E*|6DI_t*7ok=|>yA++74oF#OymSnn(bCX!X8P`rU%J1)xBGsveBY;2 z?(zTshX4P~|NrRzB~$W5vwq$+zkc?sdM3k+WwxtTW_|v5P9ph&%l%)kmdF49kYE2Q zxct5S?=!numWyv~DVZUE_txAa(V@>KupK%4MdL)tgUX<3vu0E>Y-Vp3YP4wfSSi9- z{FuXe{)Nj4Z_~9}f;bu<9V!pIza_JiH#X|1lYji`t-lf)`WR+}p4;>C7;E|yo5fR3 zCVp;;QF~Hz;PCcu6|dKBpK!Wm5~JlCgXh{c&%f{CU;e!1we8JiE8Z|2NNwiK30(W= zLd_9Yr!Tt31|3FIqPk;jZsjRYOW7J_ToSt2%jL%@>HG(>`g;=ix6FFG;PDeh(_sIF zr&V{~J!kP&LL&XSy2Z{LifU}djLGa*#mXk#S+&C5X-(%`Z6_h$%c zp8hb}!1VpTkH5VfxOxQ45_rU3pDOhXj6Qg6YZwc!-jq-6i*;wOd&d9c&hxm#r}g*0 ziMFl0R`cQQ+^Wq{Yp>?M7Gn@@O4^)yr|Oy5A%_IZw`*&-sw4F7zCF#BE}dnwt28UG zY*W|$zi-kDZ#+NR^i0X>>QViCY2~$b?L7i*bq{VZsm$G<-`nja)^T`UcgBCcV>c!? zss6hDcIt*_+aIt$keU>K`^&3U8wdCA5A?>Y?e>kjWGroOIUSVq04&Td_5?gq;INoZz^+2wQQNvpHK-}y-7nGN7 zse1Wf%gi4MkN@nda4i&%!Gi`{MwH5}7g**-74$g-4WYEJu7Hvfmh z?vZN$|IVK6`gcRV*`A8m%ZpqqfyoIHIC9d~#cO=O-MC}Za?#V4E zd7=>!5ZHAxdG+gy7fw%^aH&C}S&?;i%L_gc;e*H4ZRXhc?VxEzbIR{|Zw?nEge9?g z3QUaAyfW+g;iqfw{tVaG%d7qL@9%H<>W{JSf1Uk(e(wj(M<0v*=f&KUI$mPQlf2V% zSKd1NZ;TIK{hA;&y}I?qr~LmP`v3YS{$VfI*L&Bbl2@jD%tC>e(=xs5$}7LOj!80= zZ}%uyE|xjyWEv!6=xdy`WSxh*a1N()iBq=m=CcWN5BkcU3V)*fzapaWOz-Br_FYM3 zuO~#Gk6q?UGgV*!p{j)`r1NMhrlQ#Orx3fiI z@3&jo6<=NyKL5GeoO=@YTPgAVEQhzmv|N$?`)0$Jw>>d;*rn$=ZOMw-JU6iY&u!-_ z$v;`^@0rfNZ^W^xW4hVRgDY1D%q-iWH)pTY(gx<}OY;^h@+Ln|Q-0mFyR|Jq(M7zi zQ_Oj5K=q;}yxdPJ1z$Ls{{HvIq<8-p(?CxaY4)GV&_%uyFO8mj5Hd5PIwuXjr4 zzRk?s#nr}rGoju-`{ThqYmRhhA90vgB(u`Cz$5hFzunuMrE4297wlUTpz_W0wAr(1 z+yS;H(k~wN2)!P8<3s-Xw^BzObR~C+`26m8{hFDtU46#0ro;Ey^#i z5NX=H+{o>S$*&CwRib>_ib@R<=CU`r3>A-bBuZ?&+0)TEVNr06%tSW*_gT(u!K@dP zm+xE{#^NA6WtCQ%fXnv6Xs?-@Jmwxttk~pvIDg;co#nNEZvH<1_fYk{@4oV)GxN_D zSJv*f-MLZdUQB%t^MMdQ|6>(DC;z{EzV`I`y}xG4*B>u_?5%usqGiyXc{d(z^Xy1$ zNN_vH-jWgBBI5espjx#m|LMr~H3#^QJgbazy?ia=oh~3K>?|5y$Szl#t$O6eLvy2uGi%bs*{Zg#*K4o0u8F$3 z%InzS_WXyB9v$M-Fj;X$t1x>mZ(_lV5QTuw3t5GGXWwo3d|Ox zzTAI7<=-sD2Mtrr*uX>kn12cwMb5la873 z@Tk>7Wgo*$hxb3x?avX|cI|4dmfYeu&HDXeoID>xj+|`2{=m^(_vFQ-NeeHAe!Tip zSLchjtnG|d5o?SlS$>X^@?uiw3_TZ~l-$XoMsFT?uRATc|3A0aOk0hviRsn$&muSOzw`Ly zWc3|;YMLz5&rDvd%h^}qV&Iy+D<%6@4*R~sU(eoUIHz?j&V8a;vCPGV=j1%&mZx@% z0!c1D%uX^^heRzDddqh7KNfSolXT}sgBVluUjAfB7pMRB3>>_b!TM>797DM;350r! zt^K?v==<&o-{u^cg} zbv**u$VRD>(&dV(k?wB!Q1Dq+-7DObyar#q3I&FivFGgKW9AVmw6K> z>}=6>_?lrjmz! zmxO**1uu-6v+hNr=&K{Pj~y3kThBXq>dF80*ETtPZkl?*prPca+@fif2~|SU3|0M% z7w(I%ne=nlv{oID>t@B1pLK;er-ukmT9EQ1!Oc6=v}n86t-Z(l3=Fd7Dq1=Iyj863 zV{hOq>?Qc-JG)I?N$cv>oGlHnSFa3z!}iSYx&d$Blp7bWYRuc=)H*{_Q7^#8u+ery zXNSO~=_QqRN796M>#4RhoNx%e{jXE<@Pu6-W+b<)NbrzeQjm83pzegWjMzmJJwPLJS(u0^5Rt2T87oHQ+*^Qx|{WS8yVOXhoiT*`jFT)h7I-uM5P zg|9E(DdAyf`_k=_8W)2c^VQkO@1Ffyyzc*PM~9^{a`x5l{rL?nnU%1r6vzfPFBB>vu#Ca|Aqc#AL6EMJ(`wY$$CZfpAK_~){HaL z)SS+R-b#}@lyvyff!fbo_3t=kaGA|!y#2OAVsh&G_FL_?X|8j(epk@x%yIBpR`Xti zJ$i>wW$31bCN~$>=>JzNe0T5A>Ck|+^Vxb8#ly;7bm=Dh0x7DY=l4E{eV*zo({z4Fl0tHmw9oMU8m zxz&~-oxd`x@?VSH29t@|)?2()J>qsc{&EPqdr0f=`>RnKXDRMJv^Vs#*3G}yv-3`7 z_tYBX`pIl&{^jA%y7b)LEN=hz%I6;kL~MN*vL@+gc6@aQJHMQwKNG97_JKVgdsrPG zEE8YBkfy=Kp;ndKYVY(qN&DsP@3$luW~ur=3TeNqT=ss(T`>W}#5|5>&YGJs?x99W z9y6XxYN}qpu99PBoxh*Q!uo!~oej$!`ua+A4|_KML z1})C>E>-NiZEN@Def_8J_J99bUFZLQO}+m0$>Q^N-=~)Ee}8^Y+53CN{}b2EHZNWm z&A^}6w{!OE`KK8Sp05_1Bmd{r|8M8(3UAeaJ?wvI&)TSscjq=%v`^aXyFImki{kd` zjn(&WpN%zK^5kXWs}&BX+t#lzjs8|Cy22t~=IwzKmbp`|7QMdN&jv-TNE;fL*e9-iG~l z5+*W2`@SsIe|+(9{DJb?@8yYlN6qZq!h?(Re+i2lg$lIkJ$S_664h+-#ChV=zHrSI zi#!UC{QKp5VeW$sx>e4xkEh*^H(wa@)%hAruI2N*=SF$K3On4Mtd-rwHD#Y^SpUx0 zZI`3wB&%!3N*?R@+#PIF^V%@UN9{(k)h&;;v3d!cZ+w{1Ac zuO{Dg#O&{}Z0*(8mHIi7-^i?y4baZJ$6D^&B60Y__K4DVGPCZ8&#TtiXnOgjP~+=* zyXl+(6;tw8-_3nlnweSYVw!T2dBu?hQ>I2t4oJOUf1S59vx;4sODF8sgq7d^O>kGy zXZ7_xuAnqw*@t{f#?W29p(z)QLslk47Ku4=_!a(q-g)IgO~=*mRh)f_jA_?{x9-Xm zmJrcRgfcWvXD16Q9q+tmDE=$DUu^f0<@U+#8gv)L^IH~H_kI0!CHF>rsf zbHO#{4oOYE1lc#XZY^1-Pjl?O-?&1jL-F%O?xs7{HyLxp>aJd7wRhyDt~FWK3Z?SpQsSui31ygKpi~se=DjX=qKWX;zDRCgI?< zfT=)9K&voCYwC^*0;*n251&l>WIX@(tLbrnzP$hcj(uC^=eO@GpYF}K`+jEb{2g_# zzlNLdjQG3G0)9B#!Svj0vSW(61b_vAc2B{$*Hj>!8t zT)U+9hPFAeJjk(GYV}6<*56OlR_bXa@n(x~_;fW270Df3a-+}s&Q9Bg4{G*K;JqSp*3ZJ> zM%`;nbzOZpnOKiAh;0`OdawG{KYnW%{G^LXa>B75z_Iu}q?mBw= zvyUKu#>#1NE05X>XfNH*ztL=i$9bg}d%xYG^t^Y2oYBmGyOH&(jiiNHY8r;61QKzW(dt{U5LS|M}woRIxVF*~-y}$?ZT|bzhLy zv5iTy^bF4%Z<9V`(4)|I&r<%)gJrk)OCL)YZ~rypg6Ey(>-n6kzAj%OJIf_O?k(fR z9r2+JN*%YE&v*HHG#9V?_T5rI$#9F%ss-xJp4m0Y!KJqsX66gCb0@6~a^#qIJU<|v zhg1Cd_MXkZS3UZ4@?H_^s-2Sm{<;6Nv-|V+e*g1(A9X(2Na`xJtU6f78fDFL!zDLD z^ZoRK`R8&ha@U?vZJzPRURvgUPWhgux}~ofdv0&@y|XQVwe^`k`;2mhoWRwp_m3vL z=+$n!_6ug|9o#l&0*9q}Z^y??7uSaA z+V6M$aEN)DLsHC^5c!^_@c(A|^KD`Q{H#0|;OWb;a2a(T`x`_^&?I(8){2xuRZnAj$Gd$Ms(`Em)D;&5S+#3hGNt*JplJF4wNe*Jo1d%SwzpIh;J z%fCMgo5!!5eWUKv)%7{bFHPQ_R)2T5{+;{1?`!XWep<6O`f26wihs@S&kq-WJ}X#h z%wSXdbb5T{cXf~Bt8K3D_Lp0^@_;|=A-j!i76{mD>L#K^O_^}&&jsGDo; z){3|ZtzhiT#adG5~49)4Ci40pRZb!3RymqAR=CAAe`uqHRI= z_dMVG;{m&U%W3s~o*leuTE?dpEU#CsIU92*bJnzTt~I+{_RO0%&&g%NqW$XHJGMXP zDp`0}%l`iUb(K4t^KUjy(rx#hdtOZU9>?{%^s*V}KQm@Z=p>%q?)i*E_4lsZYjfWm z-FfC>^URJ_!IEN%)=P999z{pQEU3y4?J}I1|M!2w``G%@=*wHyz1}zfu*Cb!b33oy z+r6rLUDk^dmkrL&fgFqGYTWJR2t0H!p-1AeyZwv|AD+7F62kj`I9_RySd_6`Yv!quy*=3l#4J@?t1_lZ3pW%BIreE-~2ZuU?=;p~!4VP$7c`QKX~ zt9W;~^sipif>r+qyvHrQG{zsS75|{8lB@<-6d($z`g(JLP$UChHg{ z$iCjK%@M?XcB0na7pE*{-gdBk75d?b`F*#GmrWE8tPb56mFT%a#rb6qkI{zEt>^YL z=AKYA5s2KB1blmFgSUNXC^Rpgv-cx|)aO^L$>Niyy&5*zRK-FRzu<9?1oi=+F0NA*Ol zGsRuspLKPyKZ!aZ5}@6DRI_o@t1OqT-n-7LZ(lV3;tzJ)tmxM10$a7r4tLw#zA}t> zZ+nPwVAVW{)Je|M^yliWuYY|0&sqEb*Y|(A8vi@~&c5$k=ihg$D*v&+nDNhJ?)Lh} z_kVq_)7sGbebFMBi4hAD7O_XU{oS`<`ucL^`u<{v!Dd zhQd0g!!HBo%6$v^{ZA}yX7)FY4)>`y^9=GW{FPZRbsg4Sxa zR^+s>OJZA@K)MD0j|cM$o~~bLvQ{F4pCxU@{`-?I^8MB=%6c4}FRL_x+1`1gFjk>mEJjJ(W*v<4n{_l^a z@9Qdl$Nvle|J8q9TG=f(Ge!)~kJ2|TF1z`l(0 z=cb=aXD3C6{<(5Ao@;_*xPSKzzW5sf`?UUD^gAYfP`g=n*Vk2%k8VYT9iOrAGvk-n zcHjQyp4{r}6~%td+Bk4)iQnsov#0gU;n(eFy&jwbgr>w5Q@NlmGIr z`(Jn0sUJI=VP+n9zMw>*vGCPP&dd8Y-Uww_ZXM^!&R*?c|G+!`R}uT>6@CleUR_zP zv}<+PbLQywn)2%Q9e2wcCY@BSKDf}c`Gw(O0k%S;@)l=ZxfOx;?e}M~+&Z;zZN#m4 zA%g2x?+6TM&N_KoHFJv*i^{(D$Go?F7j|Wym!c}StwFjrVAH{(Ywx^!79Y5^KGBmq zX#cen2A8#FiKG~a>bzXE=nPNq6jv6*37>Obw|u>op<*L?rBP(s)H{#KKS~YeaV&sp~p<(1)9Rs-TlunKa%JTVSt_saOBv%>qjl;_3YXy ztQdQJ+lzDac1ay#nO5psp^`LVqvVZUf7*K07%t9J&as-p zx1Qg+NiqWMJCdqrmUA{pxlXG8zI*rQ-NK)FtO;2M-u`5-d+=M|{_iJw4?(7b$yVwPa*lHz9AfDc z46>Cm)7av$>G;nW10LpW(VGM$-X0INHZ9y|4aY&tSYM0vUR7l+4t#MX z^88&t=6zsn>pebud%wke{n{2gmP7x4F8?pG?_+QNgWvoAhcEJC5|}7{P@vX6VBO6B z+Sg{B^}p+OxhL_)q9@hA|J-r^r~3Te%WdjwBj=Wcyjhd&Q`vYv@~FRy*cPSmmDOK8 z)f%|8S>NpO%_!l2z30Ds+5MWe+rIB(e`iv-yzGhgm6bOt=6i%@D7EZ);W$}*qo&KI z(zbo<0&m&8SG|6(|6*~K;K51a#sX$eN*m5>mbLOPR+SNb+qHVquW3mKWI`H@U5vag zwwzQdw!cy2#kHgHM&q7eSFU$n?ONIPaD(abMK49`Ds%PN?w@>dSRvE3scH5kOQ$36 zcq6|_l{`JK@k8dxxvI677&F=Wj&sYs7oX!V`uuZK`1<<~N@ke~9N*m++E>_eA&0Xw zG@NNmSE1?khng;#x=ab*&WZ)<{4G^l_4oA_CW$*ti)C&|ew`Srf9Y12L#&MC<)UMG z+mGLUYn;O`xZT`b;uz!Yvy1{}(JLou+%%PCw6$C^`^L1HIq&0szYkd*v1z&J+C>u2 z*}i67o*`Cr^~f#-ri}_#`8w@Yt?SuZ+I~AQcKYEe|E-(^K5q?&Z}-do7Vp~ zk@>myu|gMJ$*on~hFUZ9Btz0WM9<4yu?)<1JS)!N$~oI9L91hrtDod_&4)&@C0w(N zKkZS_744ar{qTgzzUPl_-~V&;Ie+}mKbNQ9|NH#kO?gYEig1QK+6-SFXW#$4XO8}5 z|Fcu;P83Qgw8V(n*v(Ve;@BbTBzJg&I}c+Ew?c~rkH<`dvn^-Kx*srmsWyMjIHR87 zx-qVLdbHS2DXyUFN{n0_T256nD%g}k${Ur;7 zZ079Zx0#vQ*S*Zn3W!|#Sg^_OD(kTaN_?gLT}?sabIx;1@bz(Rn=NSncY7Vz=cg_5 zzkaPhY@)j3z^zit?^o89Oy$3DvOGiXKU-d=;Fhi38ndr@9N*J$d1qF*xOkw^{Ac0} zSByj@{yHvKw3)W$7>j1q0}H+r-iFfgJ5S|{fBt;?OJmXhYU%Lr6ZM6QX70XgJUwZf z-^(#qo2W%sH?kc1;9pz~1?8S6|I)SjYG5+CxK^J!O8P z9ye>A$tbct)-+n^rR@1?;YDsUca2QL=onMSeP3)^%9e#+Tz~#i)spp-cqDGBalHPR z|3Ef!%A9bKt=>mYd=0#=wB)$AUsI~)il@#M?khY$JUc5r$FF}!z4gN%4iy#AfyRxo zZTw8~9B*v+%vn}$=FFKoH_+8sw`7m+UWxq49BJQKIPW%Ct*ukMe5S*9UdPc3C%5kZ zpPSQf_f=`}b4h;3kmk*I^9=i>-;_nmyxVp|-sanH<~_F=*L|sWt7PWLW;^fFHLKV|M_S#|NjrKr_cYR&hYPh`SGW_ znHWCT^rY{6bJ*aX|K!!TCkDRe32^-&H~n+Zc8kZ$-kF>$3yGfhcw_gS8-f{3HFp$_ z_#VHrZN;UpGnKN<6Yu8j&Yb&MBWM>JgOCn``~TFAmO1GbeYRO!Yh`U));u?`J5W)_Qd%*E4I37G1_Oc zHgjc#F&QgPz4BQ%BuoK1?6Rh31+XgCK^iIxvI02)oSOv!}`mXaxPqu#MtR{T%k%~m&e`>*OGR; z%#tYN_;z3S;KrhU^=GTz`*ZBlFa3g8A^oF~&TQ~HB_GbZ!&#TnJI-NW;kSla zSJjS*h_26h>?G(aaAlLiQ=a$CuYwFcU%!&dSRtW)U{}QEQ%geve6Aln5^!*r*2Cb+aFH zJ~7MGxN!LBktx{ss7HHLRbi(M0&$c`tErRJVl6A|m!n0~FA`wsK|IlH^k+n$>5NZVh`koi%6s-xfY zfr2J@N{NJoS^e7{U;o-{<#VB%+K&%yU-52_*r9vX(Uk@oXBM zX1m3V5?Wb%Jnv6BdrPrMR{ph2IpYGiI<^pod#izYN)I*J-D-DioS;Ew|%d&gQi_6Uwqld`%| zc~|sLWjpkhmcIR){jch4(etT$4}4J(X}@(|nXBt!4+FDVWJk#7=jPvB*6s?rWLUzO za_!|LZ@2ARUT-(>d#+qGPa&w#YVLk+LpEQzOmdAhV zbX)Gwb8O*!&X2$R16b)5AAhu~SyNYCL-yus*9hwq zC&Q|vPK0P@90}|8c@ee9Y+d~Fo-4v;zgrf(xZ<6zyVYFkvD@0ihI|$O{)n~DmUZIj zxEOHRWRch6Y3IUnvJ5Y-Yj4{g#@>3|%Tn1Rj4{)T``Oc`Iq6H*obNUY-@R_@Y4ufR zM@5vY#ZGH5cwORT*`Y9pXNGaZg(j~@yO?v@eQ#$fJ3P?I6I+oQ zcd{^c%8K15y7q9@GHl+t@cpFheV3Fa3=UylU2x3--RH(6^pXR|NI38uGMtB74)vo4czh~ zr`9QX-F0;-;o2ALn@m@VvM%*!h&a*bBCGl&WLMChDLJx>i-}a@+q8B>Bpj-{s{S z<|#GxbJX<>GY&0y z&F2uhRWNkdh7Ey?(VHL6+0_+t=anE+^6tBjo;_>$o7nxgjyvFJ-tNmGfngkz?s+q5 zHuWS4-sh4~I)3fxdIzN$e44698<-E6`0j|&b5MLTC)9`M0pYgOU1(`#d|-cPDemT?p_TU5ooZEoD_xSqD_M-$fuUpmbC5+(zRicX z@qbure%aTz-2cvAXFjdw;zq?OQa7xls_&lY^L#HeE%l;jOXa593$H2|hR&KkE5OTW zkAAa9=-cI&ITbV9XJtEnXql38oiDO`>(O{<8(^bxEc5R9%GJ4zOr}9j7@s*_A2?>!xH(cUFSxy^0ESaS zeSfatOqk6N^)0r~W6~|QtUr6fV4gr|{UHbOswU%YzdH_}mHYjd?e<6J;Ai&NxAx8d z^?PwsjGHdYb2EkTGfx%gro5=#q4a;P)9p0DK4+8D39&OD9EobMxL9hos*YdIdj6rv zgNq*qaWM-;%1Y&~GU1V)8A?hFd@(lC8kGjqb^bvG}iUQ{~TGAZb);^k`-RF}(bo1!{<+Ht;uZ)z<2 zyk2Zkm9l2+j1pgJ5;p5Vq{z-ER|IbcZJn9P*L#Rb-DRa1Urb(*Rh?(`Tb!@;GXy1c=oskrI!U*;^m z4(5V=9DV)V|4zvNl>bm&fB*e~>HGhf+U%M8_Ti%*=|v$&k}4VRSyxXmTry2=63ex9 zEgiZCmX;_?x^Zu|=V8B&&2j~&TY^|m+kD--LoC@KwM5u^(_7h<{U5(xn4~vH=<)RJ z8?CaKCK&h{_w|e4xhuQwO_kZ4{McTJuYFQ$H%KH!T73$AoEbhP?>=|*$EzibLE;{~ zwO{TYTfert*e6yvfahHZceBc&k3Bp0yuDkd*<_=g9=EFfyYdXCxVnE*%RftQ4Y9GC z_uk{VNWCQaKtbz;YwVlnN1T?hN;a2-{M zeZuwP-RzkPF>eLR#oqV$J-9sKr0K^EH{VJu3shjM=3jPlQNJwT@9zaWZYFHEPS|`q zxqe5WtMwIMCDTKN3RdS*PFd*ElnlFLjXt!#7s++*~_PfuPEG0j!h^GT_YiF&}sLm^r* z5#5*78gzHA2;F6BT$Z$XZ`rw*#%rfA30+rTp_*PS@}m0Po*AjTd>K#ZoLzOdh|4eV zfJEqzLo4p>{8_TocD}zo$AehL59=5%^v8dE`rh9DPJG=em48>adQDl?E~BCOl9%b3 zWB#cqLx1r(ca>%4IQp_JF-erze!?ZWy(fL^B>Rp|4aV)CjZ;8=C5@8 z@#phv6FV!kc{l8pThJttET8`SfZLH^$7u?sat&8XlNJU~ZR(lq_T4F*GbJ`<<8{6Z zPK&&5o3ArDw#+bKQ6Yu8RLiw%%gow(UKqLpzdZb_yt;Pfmy28bcI2+{7oErOT=oFp&5qt(Vgb6&AEbYO-<2lG^E@WY zNk-<8gkZaEUjF>#?ROK(8Om;38}M=%Hrg!oV0B3@x_yOBZ}z+cF3VLTj+ArX6}-%6 za(k5+YgNWBzwIe%0j7az+F`TKF=_4C&38(Ov2DlOoVGdo1?!qx1Q#8)V7p_x`(WMv z!va@*Tu03Ro?p;9ZTp=`t4@5n{IMtX0g@ec$PF)&oT<+?uxx!L0@!GpdEP7R^|G8~H^p*X=i#?R|MT>ZFPG1Mu>J3g z{)AmiOs%%1ynQ24_9FZH!pjY;=U%rs9QE%lOnB@W=C-eR+x~NWnI{wU6rvi|IBksS zVl_Ru>;0{mYAF+D-LSCt%M{dEe>51eZ0@ylm1Rx%-11st+Z0hAmsKYM1QYdFjrC3&RF&$L^;&~@eO-xI~Q{oPqQV@CDGphv3C^9cbhv#P!idJ5?~x%PE(#XmBe zmw$2Ny7fl4OjdW^TXB2a5x(%vJ15>)IB)A?^@baVHyiu4$j&%2VbM%(J3WgxWjAum zcI>_Ts9^Ka9kPPQ4+g0*`ZKQZx~m+nuxxwbhq-H^@x6Q50egkM++u0^ zdFoyFzMzX&nM-%8+)QzBzm+1zmU>^ic9NqT$K5>lJ9q9SSpU=FDQtf`Pq4i-HDYyE zKv2|`a~d~wPBAWJxM!rN(DFjrLZ_qZP!r=00Rvyotqh-S7Cwn|t;*aOx}Zqq(j-UG z4ri0@Tvx+o9U)GQzrHz&DjIy+^QB?^oQvN-g}L2+pI`CL=5@&Wi{cZn9!yxxE^8TP z5q%SpGr%-*o%F`+uwdner$m%sTh?V8q%2&UuA9WeSUnZ-2hwxQ*R?hm>Ns z;XBi1W)}U&I}Oh^luPz)xh(3vRJ(Fx`_^A8SWoWxb#)8Fp02m6BE(le+MxBTz_~CX zf1&Z#1=Ef$k$k&wY1x{X=)^Ry+USQNiUFygD`!92$FO4CCC}jVf-ANte81BR^d1#du)S{(xDjx*DJ6=LQK0#H z(#1(iGiU8Mv%q5C&sTdzb;G`&UR9u98oSx^a-TtV$<{S%{$JX#tM})^dA7URINyjY z6aB-cC{(svcb%3(VYF+-PHfqf*bFji*$r~wSHC(NY}}HC9He**2^jpSAmFd&(e)L ztSUcVlya$AeSEYnPoY0XdyjsD|KF;~UJ5Ghkgbe_da0 z|GEC}%`KJN7`yuZU3?UFltC(EaiO&R)0UNC0{0T`ygIxrN@rES;De^1hQ!6@YbK{G zlJEVJ`pwMmD*Ky{KRA>QrEPZYVYFO-tD$nAL|^gI`ndAHrrMKd&uvcbpAxpL+OV~1 z;{nl#JF6q^=taJEZHStj^Zwe^1Dk%W&KA{mdXrFck11_WgID7OW-q41BfsTs+$Ch< z_ExoK&SFekGDWb7DW>kv@&D?7PW1oL*!NsJ-tnApjIiXS;DWPrCU`e>u-#g*;zXub zjQXdQT5<9|DPpEheyk^t{ZElK3ygB_Ide<$L$KGwt+GMgn{Me=EcH;|x6)wq$5(F; z-ZXl>HX>(b6N6*d>s@@YYk8#Z1nU?0?Y$*XYQ3cB3e)ncj+^JT&MA29h*4X@I>S$t z|9jK%>Z|5+^z#dC&b`w9{!WWK@rZzQ+5V;O*RIAYEE2OxYCid*`u5ekTgsl={^Z+m zzqq%wjPG@v+-to$*L&MOs4^w82^@SP(8jUSp`#~CLRDCa@qwhG!6U^--`F%S~UgV@+DoCF`isDt2n$;>}KS~ zxrz}7)EHbZU)Ul!J>;?a7Wbtu!vY*~pDva0=ACC`EjO8&^YG;rk&;RYs~kQi$SbV) z5EA&AX-Z4{uNTRC_SPR!*S9%-W~`MI$N`| zVdg{G#tqIO^?kkK_T#_b?;kgb-Ss~H z>gKY?%E~(mO{X!Joe())yUfTt1Mto^Uy;+|$G}?Myx@fYSar-~X11;Cr$3L!_m%C*B;w}rTKRfOJKmX9X z{=ZnwWAndaHa2^j_?f*L6P-k}qZC)1{Hl4_>ec2N#s%!GmCqG|UC&Btbp6qFQt-C@ za&Dnmpu92ji9ac#MSFimxKD38-~QgOHT$mHdp7Ck3(t92-cNN-~H>+U%veNJ`rlio`w|I*gZJ=T3IjskV$HTUP6~fW%C2J39}iKdXgPP z^Cw<>v8tNkS#J1&GpqC$zJ6}GXS(+3*xIIJd!we`Jh4A6P**o&+5eSmTF+feHwv8P zS7>v8(Y1z@11n!J%P{{wY;05iPo_P(y--==c*EImGyT|Z)m?ubaeaG5w$g_09;Mfg zSSf`_@3hXcmzLf|$`A#eAz0NGLdbNvlXLRN+)%UZWWlq}>#I5(4_4Zq_ z_x9WziVyaFzjydy!DUGXt!>QHrUVom)+itL8>P>y!)bnwlB_3z3e;+Bwx;4#b zI(JaiglR`VoaD3AKD$LU?#QeMD~0)V?|JEky{R<0ovF#{l(X7GbPCf!F1E@|uL2S` z`Egl^JFl>o*rR+U=F3c%U%$nRO;vx#)?P@`doG!2`Dn6u{)bmrrE7lN?f>wxUH`+Q zqt9n7SFU?-y~h5~1H-;kQ4)_BRhb*NS5)jsn3tZjJ^JyqGXf9ge$QQcU^DZKD>u1+ zHi9P`7u28m-1_gx|8K%yL6tve#gs{t1ZK>#aF<%ix5j*Bug%R}OM|$UbwA6#Ke2DV zi%|{FiG58O%Wpn5Q98n)mLReCZEg6`?>7EohdobND!Pe^&pX%eahmB?%e%K%1!T;+ zqgp@T34I;vCGWZJpm}zJpQhQnl)rPmt_H?+!p2OeP5PGSB3 zjw$Inr&;IMeshZz5>XI(P-O6#}xxM0{fw?tkhT5h5 zZeH^PbFCF?Sr2nWAB?dq+7jBXEZSkU{PIL4)|V&^Q?nly+Rgv)@3(wHhqO&~UAG0#j@`SRKgfM9YDvC2V@j0c9ELcP zHtWg>J!$E4Hs0*c>z-h0g2 z$f@$`-HNLVFE9mcY1*(L#X0rzF1Od;_e6SsHI?w$y~yc~DSu|NYPgk$`_f!1G&iTJBYrfs&uKD#+U4ci#Q@QuC!J@E!{(aB2 zKO{1%wKBIZcyBEr_?WGH`}Wx2rNYj#-=3^-ook@rGUIZSGsleQFJ-wO#4>KE<2meB z_bdJ1xliW*jwM$8{N+4#br@SG`-L}=R&2S+XRp4_Ra!gA@p6N(SdTS(5$7SM`AU1l z8^q6Cwtcnf_`kINIiVa^gcwhFgdSmPGLDLE{4UsDz)*3`hDq?p0!GJIZ`aKYSbnm; z!P#Zvo?{P<;#of!v~6(LyEJt-@03NcY>LlWl{|IZ+fuGNHU0X2LE|2mmf%u7u~&>8 z$ss|DBqtwki{@iId{EJ){qf7G%bs67xW=B_Z~FBgi|fDiKm7h@-u?dP@B3#wcR%8o zXzBZgt=sFZ(%MB67Hm;Dz<5v4=q0n^be8-+Cb!2oFHdcsRh539k4@r>yRy$hM@O+I zL0+$9YgP)gY_oUW^53jEC42Jhq$Y>{R8EhVJ*P{KOwzNE6|ebtQ!u{fmX&er=Zf_P zGG#4i)5=xf)G#PAo#2`QBK3jH8Y*X>O*^gw;YA$k3 z67CS1zK*rwEf17uD4~~i4p}nZYJ*EfAC>J^I5e;J6PKf z>lR(|WYkzF(kNk{kkZOqc}=HH%`29BYTBPQ1y91o_7}A8pWs*+;ut5Wq#f_LBzgPl z5SKo)IPvT?bKfnQ7+`s`R&?X-o9~M(5;n^geE)N7owW4LaL1M0&pt=it0|ir8OnrD z*>zxdhW&5JH$FWblFgS(UHwjNoZw|)H*dq4@2ifizxhceN&H_~fKc&#sVm1?9hhZT z&Rgom`jkOlCdjM9QTG&&o8~UIi%oat7+h_Xy}dc#Ft=gqgrjc%*PK^++shKdy~ORw zqN67Sn7!7`c+S4Ww0FU#`{^ zdoo3#cdmk*3ez*D=L=frHqJ5It^24ga8l!r2O(t)E1DfdL_z{K7BWUkJin~Xa9~Re z2g9))6U&c3w|^Q7TuRA<_K(dJoh z{o1Boa>u=|TG@x)bvWl$D8jh##>0@(CAX~WOa8i?le83^!|m}^S3$0)BStI8Z`Is} zvLCAE4PLDt$7~o?g@e3SXg(~lOP;58=5$Y`-idC7^n*6@KmMp-DQw`& zpPtq|((9%(a5A_Fi{4Uc3DsP?|8kYWx4k*l^H+ZJJRp^&E~~rtuKdh*&A(sYR%1B# zTf1pqUBATQzKMzw?(1&}iS!)qc$?S#x32m2ZQEmKJMMmCGjz)_lNLGoL2=eI6~-;@ zQC;hj7t{-xhPPx1IfWRm?kZTnOd@7}#PKJuF6xF`XYGA={SMF8?Z-l;A6}bsDCW6d z5|3h%ao)!_KaE>B?%ciCa3WdaSfACpAOqj-n}2@1vUK=$e^%KErAkMKf>%->{RG+@ zwxm4Svp}ppbJj*3;ZKVeos635veG(7!hwh3_0|`AnX8-DonLBi-=!L`E_?N_mK8T9 z$xUA}aj)x?Y0Gc>Z4wm^c$re>!{5QGVLH*!ID+d_kb{jf3$Lu!(go9cKK~Juum2$# zSND(W{?BvUKb|}u|6p>zUGo*ja`WvBT1h28UR|#fU1i|+ymaSLW-_6b(@4 zxwkpe;HJ*>p4qe49$IzdWp#w<4X^Gv{)rswp356eowE+z+;@C;^Z!`Jgr;TOf)_vK z|KDBzVe_ON3L7Ud-k90-_SSXTn_KPUX9r*FJIcF4b)ib?MgQqM9~NjmSux|hlJT=G z2NIb-xU~i--e^9eIj2o_li=r$O?`2x8}#-F?)uPwH&(mpTh)B+{cnnUAH?S>+QFU=Q1OX|ExIlw8-dut)t8q z>)$W;{|)}}<*NOG{y#7FH(l57moQ)av$NLz(X1K1U%Rh9kQaRZdC@J-w1D%08x|c@ zV_dpq>h*liOwDu;p#^!NB`4CS>?-+qf0N3RrAn%EciGt7dHls=h2^7~D4#1cd9N&K zkN8}>+IC~YofQ_7@7$atqW!&L<;u6$ls2o%t@~Z`>ffhnKI)&oNIt8OeQLM${#v|9ck6A5hTq>(tfY*fY1n8CCAsSwCpjzpKc1ao0m#v)O`gBn}JY@XJ#n zYOfvXw|(t=ZKdbArziiexy(|Wa3yE5?aTGaCv${X@oY;w%wGC<%ApgRkKg{yZezFa zP`9}J2g~a|D%ZUJzxTnrwC=-e6Sl8+xclIA{I6Lr7qO_Gui_Voo-uLXe9QD5 z2g1*9|q!+WlV zuZyp|aaH-Z{QuATWA)#c|CicU_=Y1wk$r~1ipk$*@yD+^))5e*qETW#^>S0yJjITJ zgUuO@4+Nb!lY16SGLf3xXqcxf75+HB_JgeK>xwIZ#+xFK+sxtCNDW-Nr?Vj8)z@u@ zQzyyk@45Ho`a=`0xP|K;#s1lS&=i~c3<^Mgb7u>#GI%e6GpYMYt3a&lv za#(e2ir;ir?^7P#M*KHsd{gRv`|jin#_pFqQ&QA5yrLKPJboNKr%!Tv@KF<8i@EO$ zYvvSM>Ft-9CjPg?<*yICx2sEm%eBElIxB= zjO~Zz4yPS>`_}Q|j@^Rof8&n7Y+ex7E^zGJ+7*jx*qWNZ3r-bjUwyQ}czZ|Dhfb5H zXMYzQ-Mb<9oKkgkVC2#lOS(AkZDGF@*q9>Kn=>tR>G#G3vn0=P99(&{pQZf#_Z#o| zZ@m4!W2fbf=k7~BiMlTKR3_RgMksuh?V>9$E3hZ>ELn$^^3tw#yB37|TST7|GqYdGPhN{)cb>xNAP0 zRR8hfu=$TChn3~tpP#_>hQGR6Ece6e|0}J1Uum;eMmgj;YDy(7Ta>O_6ui#u$1=Sa zzMAWMr*?A9{uCJB9NMnrWN}C4%g#3(m!}kbw@LDw9Q!+GOB-uzRTEpM$nn!P+Dg_+ zRq5DVb7n~!4!0apWA1gBRw5D+c{1)p z*N-Wz8}61`U%BqLBjQDW;mNhXv)OmA6F$NBIbq`FD2C9L4ommVO9*@TU{&{pxqHg4 zTdlj2#N?)Zg+2Zpr=h^RcV!>q3hL|oFaPYAlKy1P5f`y`9nSi{>;Jm``BwkaUH8#s z#Z-rR>U;U`?%=whQp4N z-@fB}pS<~If{Zzbq5=!Qe3R=YF^*5K-m1Uj&r)mRPGMzW=CL@v@58>e;*c-)!oxc@-wn@$SmP2P>PoLl-E_wlz7}&hTEQY`3i4j|bt2+iy4QP-5AXvj6qh zhGi0AS|2WMGLBf=VaOwpqFU?Jt^ZuRE$}k;NsXCHMdrx$pLi;GdQ-x@bnO&L)$9aO zSp0_>tvV zLt&5Y-}m3r`nA0H)+|~hvW~k$XwLNI6EDBo>$-PV!OPnVc{+kZzdNc(tx?O}bV7ma z0=IvF>u33z4vDtCZL1U$S8`9YS+B6=l$US`=gzJoGo3p(E59#&`Q_zx#y?lfk3ZYZ z#BlJvaYKIn=h^>X`&%9VzbxUV`6+q(ou(%({^|z$@K_`k&YMzwJeq5zs{6Tyx66|Y zIZ~K*?NZp$<0KiR*P)kjqI*VA^e&qXmoK+G;kp!jyE?>Mu4!q>aDK2Es1LRDOhEz4EH z?SxUXGS5AuIT^=`=FKf_Wi<`uadtSzUH9nxKgl=d?;rmB{QSp*=JgNWy|XR&kf82y zT5v1F^Us2pZ4yr!*C^bvzjJuw;lqcSpA{ebJ6kwzU(JD!AA2%)DLl`*JNb3Bt6;w( zOR-!^b-~B09P)8py3K8+ zxa0Q0`nQV~XrEr+G-FR^T4Ru@(@sGb(UhgZ;!iClTrWAbF)hGIw zLE+lE0nanGEOIXmTjslJX|cu;8Qtq9S3)_wZsf54a8NLF=T2`B=Fs|d^`-cP$&T0F zNc#P%Yd;^iXGyvHv)xP&P9ERB@9Wxp;YT~4d2%Q<+GZ}zTC92ck($frpXv=lC*-cY zx@~$|ft$s+=+q2#*;GSIpCyU*iO&_6u87|ow&W>`IJ*VcFM-{BlMETfKW1GHF3IC| z=3Jqvefo}I*1Yfo0-@aJ8BZ**-5Rkax18Zh-QicSeEwcla?thUSBT~fvHoHDXv(!8 zk!uVeyy1wk_1e}hm2MEqVN)X$knJYX@QOu*$-=FGgX1{6jm^Hma;DV_&i~|4JN9wL zhl2l1_kUeG|G1>ifuraB-+TNYmg?7gx<5Jenn`0nlVl7>A69oHPI zX1lnwIM_}r;f+w_uw2Z$jW7IU%N6FbuEu{qxT+q%H8>sabaCtBkhiQ=)9)XdaeYVn zBDG`1wOk97%=n*AT3a(mcG8uF=D8;q^$GGHXS`?KGn?`Jyt_&D7BA*i-&j2%OW`of z`DuFPTkW^4^jjE^gkv+dAhMZ{Ga7Nq5|Oq}T6iaIyWOp?;VxcvGk&oAtKC zuC6`4)(`d?^VMyge^dJQya}Iseut}vXlht0PVbo{V=`$Q!=$a;rHs>0uMsv=VtKB( z^w8w(Us+6?Zg%=|6}J8nv-tMPSG;o3(;a#}H`WRMy_q1z@byBtp%{DhlPM2wJ}#PP z(Blv%Ho@g=?F=rtdv$&O_O*@t_J26?@9jHy{{Nx-M}Jlvd-1)aFx~Yr!+B;ShVzW3 z%%7J8pN;ZfzOe7jwHJAx1dP%e8#k=`>XMbbrgqUamsPvIu@ax{W%Sn0+TeGqPgbph!TusWJ&NR_0tT8Q#%WKB1y5ev+5Pjt$yJ%@GoNICD_gCFl^=LJQo;TBi*>+#DaoNi}_0}YjME11X)!z4SZ~s_! z`+3unWytp$E&F$pmN2f`p={7_J_{@eY5@Jhaar- z?DrqGkU3zKR1$xzVs+BfIa?z#xoXt98_jI_XPD$K(2ISr(ly#}SL)RRN)wENtG*cj zVp->z>1WXD({YPhm=IpTgz#UNL6M z$;6ZcW%Zt=EYlutxcT3Bz3abIpW7^Izkl>EV{~x&r2prGeZT!r_5GFg=Ym$w>gaVT zoa9uie>0~sYOWgxZ&v;!Gq1dTk?fjUCss!|tU0KC`>dFY`ff%Mx27i#oEXHKL>lGU zZ+{Qd(LA_2FjePL$eDfCY$YI%o#dK)gbTJ7!`>V9{@x;G1Q*zJjzr}iT!Y-{X ztLAo|TT^&IDVu4Qa$|SO%IIGT8sRKQ<Iu(V$~T7ADHle{@(J+ zZ92El?cQhjY)4G;-^lHoH{l1=ego@_p;Ag9$#R1Y)`E6+A%HCet-|HvD6N~>V0?z_2OC%HBGS4ku} zoijd`*d8>eX~k9MW{%s1&DP@I3%1=)uHRSa`n|(JTHlPjXlCJ@bupVCvCd3C;?28y z%fW-zDIa|6KU6$U>YUt# z7R>0oZXw4Vx4)`=`ucr`miO0noVTlOyZ_(a-$1sZ`?p{wL)(tSN9S5wSl@Qqk~EKX zs|>Hwl1F?p?@e5*`nzn38{&IyN^;F(ilk_mr zGXGr@&m8KSHSILZ&aC3l%^M0i1m-Eq1TK@DBC)2WCSZxLgR9}ix!ZkbE;@dSFJN8S zqDQJO?I##4pX6q{9hkJ^+O5l1A8O@(J2O|c;p)mMHNtP+F8MR@8>%6A#I}SMWd~DeM{@%l1w-hxTeyU*h4q{^OT7u^-WC zWw0{em&#^vn{&_B-PQMY{g3ux6ekH@^Ax zV6n{WNgdlen%QsoSjhCLozNC8nkSo+y1eSJ=WVt-_x4}wJmA%Ha&MTLOP>OJ)Yr;C zSvAd5S6tI++Q}DyTan*wY8zzgW@I%dg64x$zT(q`d zvij`wy(gk_8p{@BdVDNcyuK1!ljQg9X%;s3 zcr0m_uB6FJ0iZ>1T0w%h#Dj!ab3tS!^PQ|ILd3Q?O<)@9ZEm zL3!T}lNk~Id=7IO3;Gg$+V+bc=G{88y63Fc5xIkpinL*C0iq_?NE%fq9!@Aq2>H%? z`{lB;pTrjS?TWu=@ojl`bpFS#Z|gI2Pq+E-DptDfetKp5{N-7Hz8k0rKe13*!FlG) ztBeKwn%e}0ZuiMne3|HQ;OW)q+aIL*rgJYjH?K`h(24b;;2Ft{VJWtYEUY4Srm7uy znG<(pM%ZN*U+sy35u6)*O6N2BmYoV`(x_BSkoy+=W$ibUopyFFqko$K#7D;phG*;=fa|0R)8FW3Ctqdi%6SUXe?B3QM2FA->{y3|c$( z)pgI|_WCyYugUj~Z5bPV7d}03_(h%V+=*9qmoeH3OTE}76?A$@`-~48a{sN3tz}|m z{=Mejz56$Ixo>GHG~E!EaDMUxH9zKKhP!%KK%%;`FJ$^ z$D^0w7BbvziRl~n>39@2?-p;~-<~#E`|FFqUCN(Acv@vRGuI?Y?J=GiE1o=uUD5gJ zs>4N0>s>lnJVduYoH;9Q@mf~z2Uiy5MnwJJ)#1MDU2CkgVlC5xT_TgNT%WykK|)@_ z8ir@ZOG?;f*yQb1#r>@UuTH$XY^{L9w2gv_GuKX>67oE8UY~t!=;`zCoc~;Wd#y5> z;XvxGA4lK+KlJCx$@iWM7N5V%6tS~-`dZr?ozVkAUaXK&cp9myKCX!{<9Rc{`)JgYTt-6bm7(qS`ulGzeY z=TmjXH=MGVj$SC`exmcm)N@0aYsaxG{W7u{n@c!nZQpzMh|CF_+Z+?JIFq~>m0F^> zuGl_Qi(1W*nCvPf%B@vc80^I;B%vxkq0d8_)s^XJae<6O;*pP^gg)D>pK|nM)UA`B zu3PeOOfF?!z{s(Ax!Ee^DYq?kE2=L<|L@(WVb|^ZYOaXMiN@uETuf_@MyNJ9yDXKQ zxTrjm$s&irXqkhq=wX4v=l?9<-P?a4?M~A6+lkw)k6Yw9hHSW|c zv!^)Smg))|QJNve+50l3am~_Sa&7^EOLi=A)hlseyRPb^X>~WSRz%n`^7roYZl8ps z^BNaqH5qUTrvEO!Q(w_0!14WET}Ppho%*_Ucl1vfDNgSai2kLrM#FJSMs`ZE*bBBO zE~W0HI+K;!j8~|v5bKCjo-UcMzdqozb;!vX&lhK^uK2P*mDzS<^?{RH7|)75dvsmm zt=5X89FvzuSuI@={n_j52K{ZSjSN#c+?bY2Zk3t%DC42k(iy7jg4&Zac1? zvWCj_QyXfxeQr^dka_uY`g%}jv*zE==RYp?*Eg)+_lGNdI_qUdk4}TUH79&BZ_gEf zrF=q*D`AuGuF_po0z-A&B5&r*2wW)jMkM@rHqqge742P_T%Gs)U-RHNKF4lVy!O!<7L)t^;ge-qtV{&4% zsmz)$mun4H&Epa|>UUWsL2F%{Umf#y$wGz#23MyRi+_`M&(L#`?rdP%!N(TS$!gfc zq4>~>ZBOm@bN;i-)=6Q zB5+vjbK$0ojyx-rcG&q?$lO~H=6KHi`t%#cS09=AZq>-@Kkl$NdRs)?<;5P$d9G>o z#pvBz7Uw2^^l(Lp)(vCPXPttRx4sGX*`~Scv~$=JPoV{3+D0=(f;RU{yhYUWh^j7*60t*-J`1Y6Pj~> z?y>Yar{-v{p|ke)_g=#frsju!y}!M6+p_L|id#d~l_q_CAK@|enkwVO<>J4-K20_i z4q;znk|d#IA>zDdGQ*RjTtZn}8B8ZK1r=XCV&U-W$u0)_A5Si7tli#!o9V%`$L#h$ z4&GOP;347?;+hoDYM$_Tu$VZfwsk4^A24N#FrKmg zKw^W(p^}7b&h2x)ExDj^BS%NT#bmd~`mM&%_x9cwa9VwBcKG4C@7r4rsNVFw;8x9) z+03}#(|J3W(7{#j{+0WBu9uTh&a;m>lE9rcO|Wg@=PNT$zVW#u#P#se+6#eu4MUDh z5DY$I;MVh7cHR2*g+JfP&S(ru-~78GCg(wigy_<99i4$((hJwmatPFt`RXlD#k}x3 zM^#&tPG#?b6<3brUy0tbq-BQIw%ZM#t)-7BD)mOc`7ZzH-O<*ct6c@mI1Oi5Y_7a1 z%ILyuF=N82rOZx?MT41Zj$FzqT-dL%>+FQRPw%&s?V5MEsGWc2u6t{{UR`kDQh$;4 z<2NtUC5xn4>H-pn)0!0xKqGLE4>q&6o#E|C^zhJB5P!WwX1TUNxB=^t4a@?(F-PB= zW8Z$W)t6sHX&uL@4n?IFK`pjxmNM%#|~ZTrQku&i$+Us@e7vf?H?YV+-1NJ2&viCCkq?i4tbZD#Q;8n2Rk` zNfY)tX}3G`ltepkoXvk8{dw_^ZcdMX@bR(#haVS}ZT|i-U2^B(&pH>5rU^=y(z;)? zmS`@MR;at~+N|Ym)|`6xb7$2*`Td`xe10U^UX@;6Jm*R2mhTyy|9(~pUf5#&`hQ$> z^!?~bcRqYHH_W*nwl=QYq+;4Or5#lk(@WLNW*_8cFk&>;6btKGFh%l+@)70jie^Qf ziVF@LY7LostdL{XSLsz%`KOMT&rYn4=KT|>&#-R&`p0?Owd^U=KR$ICV!E!lC*CO&c2`ibe$IyZOEe6vX9D(@1pDV1hdHd*nt7qlmjX7p>l-&}x`&-!Ge^j&oaNhRAY2LNP&!#LeQp#2SWTNO=_O5mlZ`)#5zQw=v zbXJ)D%Dlqj`J^H(ZL{CZ<8{0uMK@#Zec8V|xc@(Mi|O@>yK>(yeNkU4c)(Un+dwI_*v$$?&AN|a>srw>h|LfuMA9weE|IM(?;`aQ+J6!MX?muwzrnx}#Ul~QS zPqK_5>B@gq4_A8UwZ?Awz4r5`kN=B*?cey(>&1nIYEl1w9rK9~ey1P1Q7-D5QqSruc1=P24MBn$ zx96)JN?j4-TJVR@;D2H0-)aWE{O#xMUnw`-UB_@h|L-OF)w}=J&EpG~GLX18HEns@ z&iqKTzT~S@ljQa)ss7OP<$ZXIHIyqP$Ypp)+=vbp316ut9u5^j^GB{ zdux6c-#+^)(z7=1PF@+G+xJHaC$3G(O#*c!rnelq#}xiV>BLT_RJRAV#}eB& ze{T4Dv*T}G|L*Val4L*~o5CIQ)@mPYIb6~jWwhjs+r-rd))60)f`pX%1MdDvnlBrb zGCQn`bLE_5AI9Q!Gx{XAa;#e(?lyNe>*o+gtre=wRt*^jxsD1eqWqZLrB|2gvat%N zbEJyQns~x|%Y>f&7kFeBh4Bb44BD#X>o#SL!-jWkB`gAh%{OB9i4;p*;nM9op|)hP zV$w7omxFG}@5`n#P04gpJnC=vUvXaDN0#~Z|0L$yR(8q%c_3)^(Qe!Ay{(FcM~~nC zX~uV4d0FPR*XvV`7%Z5U)Z`nQv2BsdiaQxAr4Mkdm3XpY&Z)0zwx72A_MdlDA?b<7 z>z^~_oU&{=JEJ&yxes)o$XK-Qc)X!PlKkV4jUAs-mppLKHM#vt=tPRrp-rbu7M%-= zWI1tbx9{0Rfo9R8mvsVeKKis)sW$)i$@(XcEf=?CwbyvE&Tx~iH8>#TxPoI6gG-1d zQ;eh3gw+{4Yrf}I|NBt(dA}~hwBy_Nef{`eZr$g}2M&K{5z6iF-?uP(y_xITbIEd1 z6}PYHy4l5>aaO(4%%7X9*L}9@Ok>02uNPO=v0T+%AlcG&%Gl{v-?=va+$0wZ#*V#4wMxtzPa&m^A_Nu!~+Z1PP?UK58-JQw%kyOpLZEIM) zm#it3yj9T@X{~kT)@R5*!bN@IcOq3 zv0N~y-{Kr&&=I2}oeD7%A2k%-Q98m}yz6T9v(;cO~>dulwb1KX;!!Z@Gcn>#d4hJCB2nT^ZBa zCVsiPhQd3K4*q4|QT|_!qwDQ6zGpiVWH_5%%hjkT?bx&DQ}EQCtQ}Wf3W93hY}&Yv zg+s>o#|g#XYyt{G6CcSfP3Z{PQ}>na_~D*Oxyf4}`3HWPTPmEwkn$o~<7mqM-9L@5 z+AVi$%1$!UW=U)JtSooAdgFba5N~5OM_=iDiB)%OUoPQ$pLLVx>QC84D>fT`?qr#o zzC@sb%SF=Qyr{nZ{YN)9pa1yhr?yS?H>UY^{}k;izi?Eh-P!+}aR!r9&yQp5_HSj) zysdOpm8WmIRAf0~8n`S0W@6;*Ou zaDd}uL*eUL3pTvGZn*Zdvd!Wp*Oqp?dKkeKqFEcG7%DhJWY*W8-QwE|4{T>WaNR}w z>H2@x|KB~m`ZPVXU<2=_>fgSm^Cx{?R%*)r`RsoEClmC7GH35^{h?!QcKxdLC6mQ1 z9WQ?+Oqeipku?(V)Jz>4>$3NbBzb-c9vPbsm-erFCx&M~VD2mwo zcGj8fx5_QYm@^dh9{sC-H9cd8AjVcw~dS z>&K4B!?KHS>qK8q77Q>l&)FaG=4`Brx_!xW<&5W?S_e#G zAD+7zduR7|hVSp~4;*g)UiklD>=MN!t8+8>#2RgUg=c6l`zh+wVIh-V@ZrPUXG_bj zAJ4OYWFfnzV`)xa{JyK1t2-k2~?L^WRddA3imcJsw|hsBt6 z-|SznROE1Wuh-GK-ABJ(74?vex2x?FKR^G`>h=2$rTgzYB<>&o=<4a|8mVRvBX2n~ ze|Yfj_`a>P<}JSVX#UJxyH~lZRRyv#tGAzxxms{)ZGhQ2mW5AUwtP>rOl;p*r}Jyk z_wElbQdll5h+Wt}LF(eAqz(R?wafwBmn$-pt#%vGLH3Uvt+xTy^k?-8sj1>v_Sb z2g-bI9AbMeHx(?&XApd6wADep(f!V>8NN#%Rp_h;GUQQycelQwx?KLj!^8ZA{|~a? zc<0YC+gEtDJ0H!Et6IqLsAGm(_4^veFDEt3cC#F8u`Vw!OG@9& z^Q@9hxS;eW+xh*wj?H0BRhtsiv**NFzEufbedoVk*Saaer*ZA-ga;S5cUA6la${w$ zKVQN+gIT&eUMK7}*YjKRgD>XzaHmdSW0BkS&LL6JTBgbHb>^4s3tZO~a|GHOqPi#k z=X&_+l~BK2ZPRr9_y_IwKN$D@`Xst;eZPPx&*5`h6t)~p+uWS->YU^XRfk)D`LA2_ zD5RE8toY#XJ@@i79!?XRZDo7(!_M^X6uXRTYBqnwyc?a|Dtb(j`RQjR$Lf% zIWypzs^6U0g0)>|pYb@$>{;yC#^Sbtnfpwf@6?5^4p-+GUD_2BFePe^(#d^nZjYFL zeY!b)d!xg4)&rkz<-Kz!-Ezq#Mn-h905uwazdqlEj`Pnl=vdRc_CdNXCU_z6EMXiGG9 z(EN3BYT&Ck3_R6QOT$`3dhV^iwYlEIS3ls>qw}T}6Xr@B4Spwb)q-W$jr|?7!*7Kz zNjo~})gc|%7fth1pQZCPTxiV{iCXwj_tC2`*`V;#lhvzvxBXkwGv+;>RG zNM-qQ``@#AGVK(O3g+L7P2Mj3;qLod>H9ywl@~mJBzG+FK-%u34-1YMMA#hxoj>#H zsqm32f9|j{<@)au&Vg6PfSl}hQ3 zE8U-DwrMGzx6@B6DXrx=s55`l5_v6=(0((qu7t*v{t;^VjCUyiYjrVmzkKZ^Rmw?zDo zx8v?JZ;s|3h`p|S%~yCMAKz}#87sa?rX9AHuD!x9b#9eFe3w|NnEaKkpyzTyC#orz4Hik7tdvG7vx}0m3^(?1;q4jDaYHCww#O<#V&EJ0Z zHq(Rb{{4Tq|6BdPt>oWVhr^MfOp~83*dA$ZUT^mJSdC2I=_hvIO#@ux{I*_P{n5<+ z^)H6--@BhzPGZ_8wZMA!i}tf@@B2g_TQsfOS{VFcW|YAU&)pAqtDZT|eC?H3Jj;VC zhnCjnFOMw@+wP?L#U{`B!?eClS0{_jx0e3(=ia>j$`j7)C)eagyx#VBk;b>qr&7*m zj_Gc=nEyh|Vq#XuQvtsux1*tV7w}xU81jGJRf9iT%(G%*_0;d5?o%<%|FdWhf8zno z9gptT9M|<}@0eKehP$fgU}mA2mO!-a-1X~rRDWa;7k|EEhs9y@{a<-)YJTwYJZ?CB zdV9skPpo|H=O^MA1^p$2$WM0AiZML=8)R?{* z>X&(C_@-CT#CSKVq zd%j;ZU(c}WRW)m~#69Z4ksz{Ov{NV!vyz3U7UtZS!q>(Gu{z z;?K$OijS|nYrZ`RwyF9eDfjn@WLz!lo!SjY%h->w+}XRiRcq&rAca|h&t9GSv~|l| zf4^6+&sOEmwsvK_AF#jso9|Y|rEjaH!@_^xH&w~o&34`RYw+LBc_x3R%gp}X!yF@j zGKI)&wgKbGwYR=oO4si*jRdwXV)AHc^$4> zTt6IqTu;9X|F<&!XE(#Yciy)(IZA@3yeN(_q;a$eMMsbjy!pOMCluZGB#5s01h) zuvwJdW$9hW**FQ zR;S;1yRBoQ0bhAQSJEv0il47o@5St6Emz&vJE<-4wct@nkyX(@v{w0ffnCI&i)|NVmI?n5}yS!F=xjVz2+EZ^#OgX28D)VZu_Hg<8cimQ} z?uidXk{0>CUh9zcBK?7y($VLOI>Z#w~wdmPR)5W{yeXOtD zTz~)Bo_}|Hx82x({mtm@sl_rw_DtN+|u|G(wYgz-7fZON)&s#cllcWUN8J9{GESr0621jG`?@N9=wRqK6 zpLqJf+`3w4#hN!x-RhMexvgKQx!5nN?&j^?v~3Azl*6RMwk9`!y9zoRq=$k&fgMzwf4igqv_AZSmuYXayncTrM0!pd+u31+sr=6tr8WQF6|aO zzd5gPQ2AZG+Qa$K+|Rou%$48Gng96S-rW+%7#~|yn5@~meyiL>?ZtBI1e(tpwwpx# z5KO=SW6cYr+K${;hEZm}$~J#(vAaDZX%o+{!!@m|ANNd3f3ovdMdGZO(;Es{UioIzJVh{+ z>ykjgtAlo@mF5X~dNc-1Vd(U*aR@Q+KDzt*`j7AKn%ez-!#S_!A9KyWFW*1jOpkx` zmHW_LYkuC9YrcQ{xcz<7tn~p!Zfiv!&p7z-R96gN0+-sQ!$wR(*I&=*PStGd^y9v` z?f>_6f=kYynJv31(D--T+s95$0f?Iz4@~$NMp@z!4l`% z`zNMbMn5q(pXVX`^VKen1?Qfo^LaZhYF;@*>44jXIh#vwX5}i`IGww>#qvm>MxLy@ z>%^Q>zXc3=n3;^fr7I_Gn$thyl9A9N)vYD7)EEvJRJbb`TCm0E3(wNsW~rePttg#o zpzgbMYu}Ns?90b*oQ?5nbXXY|-*!9q^EQSbw;osD|NHF!&YL;=y`2B@dGR)~ZxV~z zwna~>=CjGuS5Z5X*UkOP8(HfWcm=i=VAtLAdH-^_^;rv)cbQ%_D4g%l-Z#O@Y4y(q z*(oyo*ZTYd4Aig8Y&2;oIbbN<7U+0z&kw`5hQ5-j;o&o8Kf1AN#~oJtMOV9+?{h4i zC)IBHx;pesLhtO@v-*c8z27HdfA3lA+#9RY4?a)2vR!1-{EAve0i8pdz4vBq*J+N* z3cqUp-8FmmI!0C7DpB1{+YK+RoPUXlpCdCc%zT>7%B@#DC0x~nLpG`Q$Hv?_ymvQ$ zL0K95;RyzLLXRBGq!?-pMP&He_pM+{YcVLB7`M{>yv6!y3lH=Nn5hZ5I!O5hs3lD= zy4Dn>m9=umKD&f@x-ZvVYl%{Gc>CmzUzv;d7Om}T7@qcR+;)Cf<;m{L9JM?`4MCf& zU44=-PEuK|qjYiU?BLyx7yU?*Z|3~E#enJCgqU6Tn6)&77hmJu6sNqjBQb&Jx8V8t zdynldfB)gz*=U>UZ>n)N^{xK)e`U_kt8G2}P|8_qwXW2Ejx9y;}f zn(E7MAKiB|C@lK9{!euM(^XH>le|7LTxyZ%Hg!)`(?_VrwRUXrQ_lqR!Y{La?M?YF9sdG+*L^E24|Hu3%Wz4mEF*x6;A0V}`R{k}dusFrcdqwIObSUv&I)0{4>TRGYi3${0XtJDZ)+I;q=vy4LM z#+!LQntIP(t23>;7x(bj53#KpeeF5wn(l`Ujf=MZUskZCY=yYL%%tw^OY#f2w_S}| ze{lZsOKf5B9kaQQSTT9)Y_ZyGU(%%L7xL!T%4R8^Lfz1s9#w|)DVa`Zg^x{~=(OdD zPioBml@*`EdS`V{{AD+{o@{8T^%kfpL^yzuhRU)?HdowTkXyM>_n-%+VO-( zUW;G~wu+_fsqK_~YJ5>|EY5xU_J5-OHKm)+7roJXePb@m zwi&KRX8c`dxWIj;(SqZ7f?c}>m)v|&ZKQmiWfrqgFN6G9Hc{WJd0EjfKU==+X5J&( zceT^y*TVxkJ*Q84L_K_LxbV#4=kvu|61E*QosfLjlVeT{i<*a~!jIw%>A8zI)j6O1 zdy$$aC6@R!t5MAIXlI*1fLED|@m!6ivn4!24OBMY&Na85Gxu%5^G7_p@3MLI9DXRY z$n1K1N=HEcT46)4v(Hu^3(Dcqblk(8v|RLHnoO?p8Bwig$ND^7YH<{)Kz?9ZK(?|M2AF^olPp zIF}fNaLoRA=9stR#7i^9<(n#leA;jRU{&cbOp-|Glj_yBYsn92z5CK}+UchYz0W*p zRoPn}{J)v2ap~!=b%GBj9qM>mb=1mlM`XKn!19Sd@AaSEdXcG=|Ie@QYXa|?AFi6V zl`Zf3)5%IZ|CW1YUcB{%N$oq!VYk1NqpFXm)W#dSZ@(aE`|(rJp>*e(aWiaBgn( zidLC7t#Ja|*Ez2}n3&Ns=lQ;y+t1eTjhi+poau4X-8ybA(Q-Yr6{Xv%^Fkd<**b66 z-n=Zf*gA2BgL^9yw{@@2 z$+@^_*^0S)j_xg$_F=r3&~1G7T|9r^O%@aXgsy8*>z?)dYdWr0TGp|OXJwB-?q{xx zV%~zRS&lQ;=Sr_T`uszH2v^RfBC&!u-3zd%a2=qn@Fe#Wi#2Csm&9OQW;JNPG z*Kf01_9aY1-u5k{@H$6IFaoU!1v=;JetrrV$AEdLe5%%SYS zUT|iG>X+|kb5wS*ic1P5eJZowIPsA~1B-^>r4tr@*X7PFIT0$5d}zYCg75Dn+YBEa z=6~-TSWs8j_*k+0hUZ$*<2Uy{Ju_kE#7i%Bv049QE7C9eDA+!q<#-{pqv?xPn-6yRYh0tXvh*Iz(0SS0J-?5|g>$Qg`JsCK8oB#oPY;N#*9ln|Gm**q z`JTBCisi2v7p7fdHs0jvFibMe32aW7XT0p^C8t?`zTEcz zb}?<+u0#5_oARZYSr>-H%4i<+|NCuG?z?rIp-Vm%-u+YNJZJkYi4ak?SD)8kzslzC zy((37^VN9_8%!$F7``VtPqf`@=y1}V#e%;@+%-M1K+1=&or|b?HRIhUV z#N{M&x5;Pj+l2<(yE5Fab}9BUu*&~u{r^Yo;C-t-J$Lu5whcZaY`k(2molH={a@$W zCCqsy)cUSuFXlh!+Nd$%(H$Pa4DS40AFbd1_l^i$+YloB`{w74gnLQlb{3zim=(F> zwI8*v4coxf=&K*a5`5IfmXW7JV09e=K{wN0-4*uHEy6 z{g3beUghUF|JWR0`#cJF1Fu=T6!=J3PQHtNZ#X8p-3a+-Da zRF(GXTfE7-;npXw#yE)BoC;wKykgnxxMJl21(T#1mlY;tsc)Deq{b2CrFKNQf9lz_ zs;@R~FR9v;$8Gq4>#cx~<6Dck=Nz{0ilY+u_Y{8e&0U_ z&sx1$cbkOTs@0dGA8cjmZagYzn!fsrCZm@}<`H-K+K%1dw^>+QA1~W|)I#c3**vbS zrFD-C*Z(fMlqJiSx%1sb2aUR-JgHVLwWAWTGmdWCFeNGD-cAvpcFxa<+n#G(J=uNB zaKp6vB{M!-%XhOd2p%zZDwq&5J7393rDS)wedJc(%&m_4-9L+rwq5kysB|)Z`wB}< z2G_Mc4ZK;s9eZ5o#aBJdO!8al*6)3oL5-2AV8^_IIciThe|)-GZ1d}hq21pvhIT(c zzJK`3DtY_v18FjjB8JQOH|%uZ8)5ps-0ZcugrdsrFPdM@?*DyhV+LPTbkm40)ayR4W|3;bG2eyZH&HjJx{mlQDuUiFqKVRLMczRNdd){Z4&-a4c)9&Vc zG>=MuZKkui`n^@tpHiu)8+G@3qPU*fe2=W*VV-gHr*zqah}{KwWmj*d$PwgU_7pXV|b6hCnP82_huzu6!D|6l9d z&c2K3W==d3TBoML%iz{N+e9&p@ijx5Ye4p6Fa8f1um0V5YjD^2UGCMiv)Ntm@3nnj zz#mxXS9>(1KOnT{cJIx^ zzk_Dw9kgJ))^yZ!z7ih8rN+vnO;#b}e>-~^`~U(ZbGFyLD} z|5A{@w6&bBSXkHGnEvC+&nn$?4_v*fnv`;;@=(k@#Q-M-H_=b$?}fhbQ#B5)(w-HS ze!_2g(AwgpQZeZV>N*;arq!wY1*vS?7~~yo{MY%7Y`~f^P-!TuXp{sDxy%5X}3j) zgT{+FBkG(scj**2gvZb$M_1Zf)^y+x6l6y&&Z|LaI6D*d>c0Q}C>Mk5Uz6yACXur*PThXymiV&^=HV}k?G6=PdQtqi z?M1HfXMs5-?ss1u)_oPka&xWGqAueu1rgx~JN{c0FiDl$2;F#G!z|q=CTFxc>}&Mw zbGrp!=~nQcF-+(=FYPRRcdKvx#>b{#w{~oedpO1UvfT{Ui$X_NXkUp=KkCtB=G<$T zB(rTt^>@8(w{_3yvn_EnkmcSHv#`y-7*5xbtf2E!pTV4>^*jy=%(|VQJz% z;q>Xy@wz^xZ|D3IHnT(tUg2u^wmiOj$vKV{aXNb3e-A|{81!pwm6$roH$ADu;dJVa zcT7vtWR@$(?N_m>`=mL~zP?SpU;c6T^7S8nd^9%by^&`oVQ%KV??$cgmhG2iJ0st) zWUUVmS2X9)Gs=;^dr9`uf!G%(`IcoBnz2oLxc=-tfB$EG)$xCK$L_v*`@QIz!&)(H z>a0gsM)0Z6-W|LDN~xi*%L94jV6c^4)XHjlwa-R8Xf%D(I5TDO3`gz<9x0xQ)_Osvr z*Lwd~_Wy73KeBs1^$H{h=(;R&@U4|gH?D6B`+Q`wNI;5+;O-AQn^Y_&98arV_9=bM z^~o0=rR`n6z^fxqHk+$>>!xd&xofBMOfgz4r&Awm*24SVKweUWcU9Ao6+fklJZ`)_ z=O824 z{fRfX?kVlMd1%|&US>RD5`_P<)Ho_x$D2)-$)YNq!ZMV&15|_V)Y4tv_zFU5q+?WuJIkMPAC8*p zd905ulvJzZ-pWOlU#NP)7a6o*N>9|q=+|4rp2RSOl$-S^Fx`vYclheoU3neT-^DIj zx`3x=)#>*NtgG7k4A0-ZB)K{+X|wR1-R1n^<#I{8Z4ajzH+g)Rz5nO_hYy?EJ)8^n z|9|kr{rcApoO054PVsTFEL4r?(1>8v(Y0;}Tj=m1$>~6dg2J0~S{CP4l)5b72r}ZC zDx}2J71EN>%E8{yYUnE*#Ixe);~Uaivv10pGBzq3YM%|cy!tlNgKZ2I_aC2qt^Z^F zfA|0YK7M%T&8t=CwWV@@$Jse=-4cE~Cv47OnCQDAIkuT&&8zd%2r(-m{oF%7RB?o3dO@3A=dt`NA^w zBpG3*{(!CX!#5?&wRyPtoO>5;?bxr_v}5H=;jFEbKboZX zuhpH=w|VP!e)bsody1~iTc+gb-qJdnTk0menRljt!P|9|y^n({V( z`M(_dKW?v=o?rWoH6%Ah=yAsZL4J8VgAY^s6T4*IR8Ba!@X)DSHzRrY)^2Lh{=fbE zx$FMVZ@W$AR+sx8cf=(74{vk@w^ zQb|L#n3y|U3=ip(J5gyA9zh!tPM*a z<^?3T+>tq`;keZ4)5KVxlj;Ot~`8$ZKnQo6fE!Z|pB?ta}?}6rJ3fk`{XR z@5lIGPwV*(^yfpyDGCd}OMf!|fBAnw-KXZ~UYjFWU)fbSe)RQNz%lPnT4vhT4#7`X zCY?X9TJkm*%ceLH@j1^g9eOHoVN>9({jPCctqt3Ltmte|J0_#v@+4{DjD;Kv<_I`) z1QyI$$0H~s`FO)tB}Ek(KKI$P1NSWC*w%VK!F*Xz`1w`&+?txzZIx{+6zyEk?Am&l z?T@hiciR?$4`=89(!4)i;`rk?v)vq5URMa)VD#)I2VcwC9UCt?&lVJCEi{t1)R~xT z{btwt?P=Na=QkI>*YBV4Ec?vQj?7)#ZiE}LR<31zvfO@I#^+yYo<&n_H5)?@UW^ew zs6F>v_ta1dV08Ar=AqOAzCbUBw_icsK%JC?cbidlw=s+Z<(ebk!)SNZh_v0 z?B%Cg8r1$6?^^Q0_w=mhh8XtHu)-Cp%>Uos|D(HSw^f3~`(4Qn0k0D^A|jtNyQcCFXyNuG1;#w)Exzx{egqH{m*IW^<|u8Mv?<`R$EB`xb( zGp_1<-ML5g^({0g*)ohsuHGz zTz=9ceROZN_>SWA?!wIn^R~P9Fq=uw-kfhH{pZa2KQ?u*X7hhM*e?F#!{Xo1VrGcQ z+x>|AqyGP6edGK3|LF>MCI#+I_v8*(&uMpUv!ecJS}h@jB-7>1AMB6>KNZpph?lQcC(Moethu|_t9`sd(|11q+$t`o{7ATq> z7(L_2g*6vNABKnLZ`dDfc%8?JCE?D@UvpSZG~Nz{Tdk zRTA9_t-4&YdyjhG+bb|7sJi3A&6{$wa}PDQf8TJk=SJT4eVw~+bg~|QDcg3I%~k8s zgqRQJv(mRqBo<1zF|f3h~J6*lx|8i}1V3C>9{L3Ft98~q;Y&`2EIeWEJZt~izLITW^ z`VBQR7AHBK5mD|E{&M5_hO$e-<*hop)zJaDZ!SmwPFa<`;pXKF&(2*sGW}7Qukfs| ztW$H8Q^HtW{yb6d|9EwC_L7Z}PbQsrS6*hL=%THcCAfdtp$dhpPy7B(}#{2Uh|9PZ$tg!v3z=!Vp|6TvwIsaeeUTiJn)uz*{!zC_B zehU0}cm7X~`k(Q?r+?u8fAIa!Xr;ej*LIs{YIfzF_tz>`%{KIUtKIy=1ly2al_ij9oEmwH{5=|;bu-jU0GkE&x~cvGdR=Jt!4Vc1q5aK!a4SA z3|=RpxL#~)i0j%10&kD4>k?tVl61{7bi0?+gy%hxU7hp2j(&Y81X^<&muMvyU=+|L zRb|GrS2sJ+K50$)d4qJndyNVjzjf}nPPm)L=IC*7>gSWscRZ2mySnm@@NAK*6Aneq z{gN(tLU#Qthslq2GCvC3RrYs=gmzm7gUp!~Q438OME)wQuf3DJ+*`QJsQOhx|E#q9 zwMEx`wrnfkoZNd@?6P6=;@zPhhUuFpPP>%T^+=g*ey6ja-!9#fllNCicUms@EH$6{ z^>0*pp@!7b2@m#_eYw6tMEss%_7aQ!{k&L5OUz^f-cT5ybI2ok9dPair(hkX8L2vbq-yMCefA8G(;O_=1|BDSA zrrmxxOYPt;e#y|Z1y)`Wx<-|=R&780_WKp9W)}gcWAeX+_ctYO2s~I`|80JY)5iOE z9Uti~dwsp)%MZ?FLLZ+0|6|{M|KHjFf+BrCt{s;aNEcw*Hrv?ec-I7mKH+~)>z`i# zV7>oy{ey?i`4Q8PCU5kgBW3aS#)@^hZP{~=U0NHp?^@E@i=~Qk0!L@3)(GcJHvg@% z>$0jBuU{i~Pi=x*lKDBp{@c5}>-L`uD87?dNVYJ=oiC|MmR;oAw_U-~avl zV~%;ntyyP(v%ccY@;-lg)3aPb#XNJDrb{`h)!UEEIp=n}?dpo0RsTM3y>;E$rb1)p z6werm=L!?A-OFm4Z<8)!wa7$!hRB4F04W72K~9Y*!%Rn+oVb%b85>%4&tE%rKD3~& zjQ#$P7tuH7zcu8!c)j!!z~9R0~A7=E4IfSpC0?U+PW(1MMRm|a#cbWc<| zEF#R;-aI$R`M}4DBeTud2YeE|Y?3^W<#WgxrSN`@uNk>Dowa;?OfJjx%(Pmqzg>B@ z;VhTC`sY(-ZH7^c6rP{VovC~DqS?==;_U_Nj%KioLBaXrX2s5tI6=EW=9SGiz7D+ zR&fgW`^2otHQ)R1b^T_gGeH8)>gkha{JI;L{eek)*4+}#tG(wQB<=YYBQ?vijfGV} z%7iET_an_&<=by3Nt{_~)W^ND_+?m#_-E5Lm$&z79~*l-4|Qk`X4?JcGS}6ZkAIGO z|9Q3kpXHxV`u~N#{pPK3|M6t9`w!{*$NLYT|9eLN(P8%TkLv$t+P8vsXK$DOkpE}) z|6Ob4zcz@JC-ia5nGobMZ@uAJ_CJ^O|1<6Txi(+X|Mc&TIj{cR{P5fUe`?6)DCViw zQa8D>mj|qJ$UL-Tq4bO=*K}9BaEx1Ix2VZ^@|JA%jx+DHr}`Utu{3c-yWiheUAw#Z zo*2XX`kF6i`|HA=d=PJ3yNb(nb+o3jQx12@=|KL~#S@D6Z*4NEn*H^4&&Ss1vDQD9 zZ9TNb$m!I+A1>J+%|g_gHnQKbm!A>9n6Y-5$a&VuX(}r@q6BSz>a1wYnbEj2Ekmx> ztmc44AA{1q?|1t@K5YMPkar?@uS5{D*Gi3$fUcv$#|3)29oVii-uk?1Md*f`Jtr#T z#7YdWEI-k6fSIp7`^;s*rD0DhkL`Y4KI2*T6r<#S|8G>k&p5kj^PbO@-|s!IdAV#= z^!B3g@Y3+rizl>532<;uFm&Ybk($Jwm?9>%zV%>(X@aC~|Hm0Gw!V>U{^)UnLr3TA z1Rf<0oe3OHP8*kMG1Ps8tpy0ni;`WvJ1P9`ht}etbE*I(=OpAs6fiZ3&QD|`c$3)!_qV)xBiVm#?&Q_Yz< zJ8pf-jP7T;a6 zke~NdS(u;<(=}Dis;^&Xg{vPu=g+BlHt~kWUcFPP*{Qk8o!yoB`mgF%rD|~mD5j*z z`uOBlo_l&peu}8m{uQTO{dxrLws_@DDRuJUZP+ECytC*2?ON8rkn?*4Wc6bzxTM+5 z3v<8AWF;4VUg`Ts{{O4_jBg&WnJ$WF&}?|@w8=B0r_r`y*~c3i4GiOba_Ccsm@!%jfMfWZV(RVDq>C z;;UbIrZVoYTjWG1$8cP$JZolt>&|Ssr_o8_!s;qniJ5DZt+EP^Qz$a_fVEt|f^SQ{7=9Xo17aN&2xm}jhKJmb1PPk%$V}%8){Yci~%P6F%1=aP?$&2bT*EW?gYBF#4d&yv*suz4F%&v@U)3Xekx5W0AOh z%Iic|Z&=-_VpoU2U+ov-bxT9+UzU9~;ZVrp{=M*a?~BLF#k>l?op@|4*ZXnW_CI`a z-@exKFH1Y}M9_&fqs*g=o58q6ZQ)G!n4N!A&e_&U_S+T-YG<$hapbuCfnSczS3gRf zyHmxrwm;*L-n+ktZhz=rzrW*bukq3V-SkMI>9+5qS*9*fJQ1RGJjdNns?9B`V{3<$ zfSJM69yL?7Xr+^$>Sm@r$pT6`ovmVR7pmG++n0Tn@MDt-&pT-5Xu#^mwBtl$k_xj~ zcUk^{GtBbO_N_bi@|bDWVg?QSoVUlWo>+1uc;@$Dfz~a*=2`|yrcYZnebWn%quN^> zd;)$+H&2e|ddA?YQgL>@oY*GO2M3lpw%qz#;w$@iPsz5ww$W;Ng*>l3)qj{NEEUr{ z_fRR>6Nx3AS-e96`Nc#fGXk7G_KN9-l}1#5mTdlMOahJDKm%_CMzl}k6h zSia|J%lRDH!}!R?kGL_aPRR96TQ1h>5kra5BiBZ^h{vlnf2(Sm<9J# zS=+-+lgcc8Ho3ic8@JZ9Vc=;w;(x9>M!y?U1EpV5{tO*{J*&QVwN|2|7VmV4@RQ~$aw^9h=* zvEug{v&y_)&NMQdW0lLEetin_%Tp$9ZLOQkg%Y^V*&K@Gp1i`Y=*t^%=7^Q6KTeen zf6>d7@Y4OuzqQBv?*DO~u5VLtAYxnC#(jZPZv-uz-Slm0ik8C0xUjUw6WkWtnVJ=A zGQKQ2*Hg^?Ov;7%#+&f7vI2$^-0q4eGZ@Jk1ih5@y_)PI+N}EYOkn@AsSPJMe7Ttv zS8Nps z7Flwd)lxUF;eyu!en}?|-ki|I>%zX~eA0?*DhrO;l_(gq^wL7_n2o=BL|1CDM;y0( zuxa)3Lr&teCw4Hsu390?Z25$(S&*$+Fo|cy>!{;bS9bhtkyKTFA|Z4lN}#R7ZW{O8 zjSgxLMcryVeR8_a$L-4Axb@`GsK*bEiItTtFF3a-chNJZ1qOV-lE3|}c=7J{d#mqx z>u0ZPe)z?G|L^Xee=nrpoT}R{U^Lms(x^Z2KkFp9O%;$YeCU7J4GEhsV#3vZj@(-sjKIra1z0jJKRek+bEpGoJ| z5#vp22olIne3kvrwJ!GyH~&tB@6V-6T&M5Z*K1Yh@?L4(#GK2$OC?@(zy6e+wP|Bh z`JTV$3x3fV2^lb7H1zHUu!PLfGvbAIaDAgiiH`wiVJ)4L*)tqvwVG)$S8 zqH})l9)0!|cR1#(d8HE2b*n~BWVBWd|oeD7hLIDsqTt!bwXeEu|}YY$6QCAq)5>2!u*3%P;B`oVIt1QeLi} z4#Ty-X4-M)GsVvG-0JM^|MO(x?1Im}%LUKM95cFg;ZRijtsa3}Vuv?2_RD>abl9A5 zW*Osd|JZ{`8@tWUh|Jb5JbF=E;AqRIf9rHEnCRZ%T)#kR^`b3Ynryafo=otT5>uJU zJjp2hfrr~%(UqG8B$Mu5H)eCbIsZ6^qW-Qu-CGsBIW}I5Dd@PtCwX7%apcCnlcrJ^ zJ@y!1(azC1!E!`Gph@$f*Rcs)7g9>Hugp8b>AgU{kU_=sT=CQ(@x@GjRlgWtJuqow ziczi3Qe#`rHdFnm?Z>2J>x}k1vpT^SJx8oZB6X9?lDL9Zg%z(YmTfLBni&zcJ(m6H z$=|R4G0xMiIQ_dkSa0^d3x*Q&04` z-DB?**ed)aMKJN~R%GGS97TS9^Z15Y`Fa^&<75Qt8n! z$>p2Zm2i~WY8-X>zwy1zx0P!W-4+Yh{p`&@w!QYb`GYGLb#=tJb<((N&W6{@x_wo< zlfkuWTcU2k+edQqYJN!B{e56r^Wm@jf#~}0Z+~2HmuK0~_w}pP;=tbK=;e-W7j%T$ z4zH?_t$%*-P0ag6%lX8P?o@cO!0YF4`97JRvkvPVzt7V7pgQ+JYI*O+6+AEN;wLh4vdCoLA6fh8YV%~oRf4J(^tCGRzN7*3FS*l}HXv2Zh2?(Ijnww}Im@7}R{??iH?9WE*zZCJ&Y z^hqIPlXH9fY96JOaIdiPh0B@}CHF5?DG+`y?OPwLq~yISyi2EWLBXSfh6{g!HZ)|q z%n+AgGY!fqWjWRLZR*Fx81UHyFhvnTD4EfP##d)0HIh(FW)#0d3uJo3^4+9|ER(E@ zy!$51JTcVBmCf*^>RTU{0L58ip+|4nY-wzltMoZMQ%iT}ld=J^hS1Fo2H(u<@*w$BVpVPY;%;DoG+;r zhityMsVjQPk!4@24}bOiT6*~5kLUR@3+JZ_H#8Ps%`se_(Wcw#8r$!_XZsAfdmlHa zy?uYWDjaC$|U z-t50dl6t>$9{ovrd%${S8*t;K@Xlxk=Fi3k0W#?4GG{`{{JI zgF7Ej4Va|BWWMgpfe)%KnydEefBvfL**HO|L|ucmw|JWiYk5ZOC4tGQJUQ30Rcx31 zQhr#Y^_489N^L&1q84}^)7Q?mA^ysV^&C8xNq!+9z zt#X<5Z-qsK^1p(_S(h)dUhaLT8>G@(z^0XcFe8AMspih%kF(7L|7Gz#XM1(ZW0sDG zfA;I!>v#EU+P*zerFl&36!(j_jm5uWw_Plil@GYiT=4B{wxYWDT*vtm*Z0n=vTFEK zf5zYg$I62>iH389-&Nl?t9gC#OtwV!#%&urPgdxBJT@(1j%IwYUdE^I51ZdSuKgf; z&HR+!P6dgDGF)LAy^SiDmb&SGdSm^*OG4?L1e;50l1tQ?vdKbGLKjlQ5C1#S>lPIy%k2A_Cu68vGefD; zsVQbroUHP2lYJ!2v!7j6y!0tM_S;H@bs8fx;t`wJ*ggGRVtG0L z**&aRs#1DoW}UeroUk(CT#M7m?!c3+D!=#lIK92SGbo8s`l*BJ5Tt)NTwt>!4@%v&zKU{;%Br|Ih!<|9jti zugnjddFS3W?O`fh_gHJfTdM;rPW@h#?C?tUo8T`=hNioIzbtuASn{axo#TBdlV}uq z^y6gVoi3s4C%^2vsi$FG70)%*XP1xX{p&K`59bPXYxV|oRaX8D*!a(gY1bY8)jk|r zuSF{PwQUW9KOeZBsZvxvSN`Gw6p7IlBZZ2nvjDJ>OH?_b|7 zte`3(;83j;_D$@8)Vg&p6SB3gl(z25D@k=$-Q&4TG)%Yl#ZCRob}^eYJ2Hcdq;~yy zX6JrDB7DQ+NCwGZjdZ^{npnZFE#TZeVfRdF zd%J3`hTg4T({@?gfBjd!?{RkBqx*l3*gx8^sq(yS`OU}2`D{x6ym)qd-d{;=sizK3uomcZ6aCn=*GKlP z@01%C3JrB53%#yclssW;zFE?Cv4VB??qD8v!BX4f88OT@hrWGd+HJji#(8lEk@Z_o zhUxTq|9-e>wXalbjKEf_DQ`6!jAtzWK2=m&&g0m3wP>DXtww82R*7iM_c5Ni2CY}r z@7K5e;<(AzpmM8os?5}_tIm4dI$F}8G}%~cl7(rE9#hhl*!3!}JkuOsU3~at<9REF zogGj2hngO#xu?+5a4}1Q({HlB2k z2-e&c=Hj>ElZ|_y*EeMb(;$@`Ih&5Odr3x;ilS0+SDJd)?fy`#vQCAeELgB{V}QT( zgj1ij*5`&FTD0l=>@V+`!;U|+64VO3xsltsXxZ~E50+k^5GVcARPOT?PL|hNYu2t! zFp@lc!`an<8tc6XqXMt$n5Gv``oqr&1+Q6g%s}bA zXL+w%MpYq0c4?3VZ$}to9&37^+hsT1B(4p81`=Hg{&r^HTe=oKIKemb$ifXALI328 zWLrV!v!8Xq%kTcv2S@rvs2r^Z&UCYM*Pc$3?Eq~!qb z4Iam1iN9Z&&8lQ^kJNp#QC{>|Zrx^e+a*DQMnx0M!|EQZJ-f72%yDX&k8j3l$MmO- zmyT=cUgZ6(>ietKt&fRcQE2I&hcXT7S?|syr;99%eAE{^d((^w*&pwzD^5uLwdlgD z2>l&Cl5k>bs;f(S+~e+0M|tO#japhJ4k61M zc1Z1!>j}s&e=)CInYDqx$e?>^??bKIoHi>zUs!r$TEgsO@rN6moh3efD)UrIGmYAF zWQ)x$|IY5IYd=3I7R;UM@kS`=%G*VsJ-TA#q=k*VQ?dLh7wcHVZ}Tu__!4U6;OcN=Atho22Sd1qDf!SX)lsE3cR6 zH0-!^BJ0xTpxNeL4XoeFw&&lOH$Rt^;rG?&l8KdZ~XiRu5ZkNbZA#fyU(d^vo+q1JQuZ)lzyd+0*mwdSg|>)4rv4LRr6 zJ^1)#=ltUCuXn7Jyti%Q$n0CV(#m>T*RCnXU3x#7zPL0 z!O|;!PAg*Zjs&Kj=@}2sh$RGn+mPzNW@W)O!DZFqjLs|CdJeF7v1JNAa6Xi@i~SMD zIoX`Q6IOoU7|Cwm=L&aKd#)P2V zImXJ0yE`|W7qt+Wz{MYL#kzd%-%E8Ko>`o2Y@a^vWE7YnVyL5BJ=5sKzK!nP%mJa! zy7zQmMHxLw7FyuTA=t)p{&j7zRg#itXV1cFo8&2fmnpKViROPjQGLlaIKM}aefq{r zyi&?j-1cXb^iE{XSYh+C^1N*FktYW@4hQmPZ|;hkce=?dE-6%fsiV{J?=$lgywmmT z>VmlS4I@hskn=sJ#{qdfRqKZ=LG-H>jjw`L*Y7!W0XY zQv%n&IhoA=LnJ|FYQ*h14+FMI{|;hfJaOctclg^?j10}L93IQGtxnmWzue7og_(WB zo5y?er^c*U|9Vqc(~`G>+}cfy$wB_BMZT0qeBC5-W%I>?0o%0@pm=%xZ_ULm;PV;IWUF`gF z*(xE&?i~Kp^J>K$1vRw3?+g7sd&%mj^@~~5MQb{@_Mi5cR+VC}87U9? zProP6J0}qqE&Y05(C*;V8~R*NFE9{hDxJR0h#~38(v2%>^j6>EE97%|?fUXPYnJf} zEzxCci5wy^28%ECtKMQ;P{h2(C(Lm6S;3?W$7A@8_=M}Mx1Gf8{3tK?=U$u8Q(a{l zSF(FJ@97`teBg7aacyi)?!BJxd!93`S^UZ3h(ti>&yC)vnf9#Mc6Hug{lfCj=B9n` z)~Nl9Tyo{mZ?W9lB6ANU8S3vY|0yJCw~fKNb{;Fo)a5dp*cxxy99?$3cf#(ARdsPe zx7t6xL^QoPRk&X-aTX>2r^x7co9F+(lg=xp zH?KG$=5_o`i&yd*t9%uoHAPFZMJjnY?s#9DZrQO)#NlY7!>Rfy-qd1BMzi5r**X+mBx@2=dK}y1%dH9s9oz{PmCJ zYd#6{%RKGf{O#L$`@SC^`5)bC?cVX{#pEBq@_(w?{Xg=v?SyH+?Ux&WK3z5NzqfRi z+>Yq?7N@nfwfX1T7N1_MU;8rr_x$R&=l?!8-}5m1(W_g>+T*{z3a>v`|Hpp+|M1yW z6}RsM_d2*-R9wiaofl$t#_O@R^hKryligN_BDNZIUY1_v708{)Z``w_Y&yrLxEBRC z|NA>E+9Ta^ASA-#`hsoAh2M9ztdZ?FnVf3m)WNCNwKntjB|aaC1yVf+GP#^t(pNFP zJ27{qVbRT{BBnp}`rV4nCkq6dn|2u9mfrkKQB+&S(DUJ>{iP`~dW~BuJf|FR+m*(7 zYx29LN|P+2RaDemkDf|A;(4TLPKe)z%z&`~Y+oP2)2$RpFg3cmV%&9>MpK#f762N{RG*`=*~d3wVonn6L$`oR+L8-ZS<2W@V)`)jc9s*H|KE zHCS{Sw@M!gSoqbr=QwkZyXm!XZ5f*inZpMeF29s{U;F;J!OS&>q%_4Cv?B$kJjhrf z%pBUWI!|4Bi>vXZx$Im2?Q5Dob6OFb6<5->qpd+d+{AA9JPCNSqjT{!Z^_$Jb{Sd} zPBf2trPIIUJf~)dw&KBs+8ZQKe{nnY+9aF%$q5VQ=$)4~mVdmoF?zqj^cAU{Gx?sH zF5zfbf~^JUQ7vuXF~{hi`4N`p6*u`9CPuJEUguStxhd%M(VBnT=emZkX*7yeiddD< z-r^jcJ!4H&Pn+1iDAd5B~K*g z?|i!Ezxeup)9Xurp5$KdnUeQwUU<#-YW3Cah37ZVe;oI3u6}&=#p!#WC^CeLZ+>|< z{@2v_pMpUrzn#4O{?~`wb-&Nn|9KYw>*wUfCzo)g`EWLXFSmIUO)v?E+N0g&< zqh)G*&dI6QIUVKFnH&qJX*q0m`|)-aPrsJSq?L^(+uM$q$4}!vmHzw+XLnbTrP~pK zP*rXAi@~>ddz?)Cyg@rY_`}90o1XirFS{W8{OHpa*YD(hG?LW0Ey){tY3{0}T5gIz zRojm3+_b7;YjlagByord&PB;`XLDYVA}# z4fz$CrHZ;qPra--I~M&l;5)m>G4yJLPSjRKD?y>D6SpbFDYEy!X`L(x*`5`aYW%VSrDzV6)(rT5wVX>i4eVz?}g2Lkb zCtoM%Cf}SgNkm*xV~(bR>okolRYNaB$uCSHv*Qas^d6nuZ(i}_VLyX`M96B1-eW6X z3*Or1c-d=tTG1x8$hpT@bj{ceRPq`*m?kktHlOWPj)>BanW|Y0sccShk2}vPi<@ua zGTAk0l7Q+}-iV(Mlw5jUx17?-QgLWnbK+3w*0Qx%X181r%3e6XB_f9DTIuCEaV-r` zV!wDyJCUut_nr5?R-fNOD+LV2ZLBsf^pR^}p3EA2VI|wk_ku}LZ=xAjblI~?XwRDP zvZU?p-PJpuzuR5#>dM(2kJsHUcy?`ef>xyeR^LN4`y6^=x{ABK)}CaDY=7|FpkqZ0 z>niP*7Z00{9|%3_Iyt$~nBAr8%&c`WyRI-C$T2K`{P0Da(ubK*3|G#{S^dAzZ2!sF z{TUPw6Ucfvu$VZvI2%I#9qMUJrST<|n#O3v3iUj>576_;^rx)i9MsoTAk zi($=WB`x_iD}R^vFkb5t)k=-CRF6>CW6XAme-Isiq+sRYpURsrb@C`xe>FJ%NTb7W zn#PL-inf*S<&zr<{oHr<-jMH|%Hmw|yGXC9LMx`@joyj#J5?0BI#%UM&#@@vng8nw zbJv5=IU#Bhuabq6TjI~0uF|UBoh;Jf`((i*7u8!EojaHwO7^PFSQE8o-MyBN6&*8_ zcz6@ea-8Yuo<2{fY-7%T6{8PvPT4&lXRNsz5iOtm`G8nhm|BO4yRAw=%;5@~BOf0h zFMRezQpUQD$NX*y*VhXPxqF(H>*YNzUH^A|(MzF&2bhkwUC-n_a@gyyOcUKJtt1t zY@gy7v1Y|-KF-bOk2=~0TrCPb?77fliGa}()z=GabVQ9`eaWvk2-&vF$a-T!lw*$Z zk{_pjij>BB8;U=9uH0|mz%0G`$0PB59NX_yu|>CUFZlDrFd$X%5YyQtKDD-d$-@UZ zCKt9oOyFJnJwj($$41x97c>`%brtZb-4+biYK-~2xtm+srC1|L#d%v)qV9J`^iA~>Qzs;S5IgOb$dbDEm^ zQ)T!5v1ZR$b?4IT&|kem&bNOxJnT@}>0kTLck={3+ap58+K=B|SbVThlcDHH=JVib zv1TC=Y_IrE2I;J*)mav>ruEv%6h@V8nu|MbEnqTvedJJ@$-8SDnH)U|@%#Bd#O*3h zcm0{WHmYMw_KCvNk;Z|?wlZ2>ESR6XubRY^e#1RUg1@z6g9Ty z+0B3Su0hKQ>-o!Or5woh|t`iSaP+ADxF$yW6Mldvp53tnmLT^GdIujneTv zq{xwKJ83Jc;m08M-YYNpQleaL3CwmXdBXB#Yxd5==Z^LWC>mezT)ZYUI-zPhzjLts z$(LHbdb*pIMTjrG(dX(jd;aX0j1aC_uQrSC`oku|>(ay7lD4u#z3h7ZU#rL$4z8c} z{b;?hhCy=%~GXv4P>r;cq{XE!@(T8>EAtOJDgP1EIu+( zTaQ=EZ-Gt+Yf?-G!xYC4_xjw}-+$PgZTe=(&ca^1X6}Z$$L+s#=l|%>kFqX)Uz{7t zn&s5oecS)xiCpu<(p=V+w~j5Dn{;d40o_H4JEq20f6lKv`8w|Vuleul7d*`Pv3=Rx z{i>-*l#W?yX~lJxq7c|lskf^v&s-ag0O5ihr`T^n-MH|e8d z=tei&Un}*tEuJA()Zuh>n}LB;k6;qZ1pXG5rLiaaVvn{T<1+1^%AqlLCqsslw7@Nm zN7kfTG*Wh)G&M9JA&(_jp=%+|7wNo&0vMQl;e~Czo{1Qyp_R z)lSlGF`G7Vd1>sky+?MoUAmP1b^8$x;iMeVq9rq#dgNHtMYCfbg&okb)9A81aMN&x zZOshr*#|tP6ep=D%dRry6IuAgzA|R*R*!Ag9h`p4q<+arBq>yGXyg4U@sPtKjj_OG zj)g)lsI`O)I=RG%{Jt8erZc1Bf265f+ zvXp2x;yi7|KJ!9HHsgy+0-hcT-tU?gJq^(H{(t?qvGlY<6&kNX)TC>bLFLPd@=<0v>P(lzCUGfB~;@zLp0;%XHs*kKM7hDf7|)- znCUMbJ%(oo_f_O+&kiy=!?;bT?{~9&y-;*J|AQZ$%@L8g8}`<+HXmi^j$G3xXIu8= z)z;;H6PLQ%U-rMU>_w2Y`Mxio_rD08|K~#c_51&)*MGTscj{6Qp9_*d8 z;f=6PN0w;oQYD+{RjV>9r>C!+)T|x7wyNG-o@efc<02C6J>gr0{qJ~3JijzGT`@j1 z@`p&(#A7Qp&b96k{XAjEamE*Ojn!VuHw9c;aY=Ar%314l?iAIH)18f){e&`CDP~Vx z_}hQ7^}Kf*7wODV(OX<0xZJYR*?ro%-qiIorktPueTveSV%8gz)@G|}JIG&u;4By} znfvufn8s_?$}`O?F7`(BCv`n=m}NAB>vMzkxlG1?DejKKX-3SeRNlwLOy)cm#iHA_ zXS%odkvg{{^;_=LmT@}n(A#C+(y&TOp(Sih%*lqe$DdteEak1(vd{H)RpVln_EVu= zYEu{_qAg`^+-WJk)Ozx>tHSOJK4m*EaP%xo)DdIMl@{F7ljR(F#!elgasRddGfqEm-xvP>MRvixi$>q{g9RNfoa<|zet*y&_jUaSqsVsEDUa4z1WfrM?sUie+_Oa@ z?-zGHy}oBjx!}URev?I}Ontkwa{IjH8Q#Ad@B&?uA3P)AHKGbGjIQ6 z%N=hc(+hu1dmIrfpJ*bLl)t|5JMX&O_@m#-mWEvE$XcMyD3+BKvdr_+cWcE1v%J)` z{I&=v-MlchxmC3}syBX}QjZ$5PFk_fGUFc)juuXi+IU(jI4s5J=*HAu4keS~?(XO7 zKlW;WnW@LLBxJ3h&a-Y!2_AR0eVLA#TeoKc*9u>URHY*Yy8q9{1N*J^u8QJ)UJ#wxKGs^4w2C^>!;yELWE> zVhLpW{>5$2m$vsJH*Qsk9}HLbxzwk~oil;8bfe0Hr&lZju1GHHDS7S4dViaT?ZsdY z-Bne0Vk3Hlrk~!^BjL7@S@W>#+KQDLOLlt)-m8fXvoungHrJ~u_~ZKSVug$dzqZpW z`0dhHD1TE>GIIKEx1#G-*0k!Td}a^p!i&}~KQA0OI+G>X(sxm~r}ULl!L7TqH;KL2#JlJ~Qip)%?ZdmC-@8zh zn0Doo+V3Y3IpH3!1PmGkzZyTYX4B+hSe2-oxZ{<9R4)k0@NL`_q%3%0ORtcSau8R6 z>}Ao*dnKQ37ISe_F7xD8z4Uczkg??yzlzcl7IWGC!uNlzz0a|XRZ7QTgY%!0^7~}- zYaXwE6#Z{{_=7t?KU-8jQrY)UzDD|7?5%_0b$`7N?r0NHHwsjo`R2%!fa|8S-0EyU z2k-gNZO<=0e@9Dix-8q`%UU9e**$x?w@;7gu)8*6+W(xBi|0o&O6EAH@?K8A(7mIt z>hh*JEE%U?o7MNNTkt+zZ^rAcUH^9Mx0gK;)x2pLPh^AFB%xVnz8*bS%G&nh>DodA zu?=cXih;L3-(=cd9o(aye5dAF*c_Wurse+kTW0&sJ$9_ox8=g3T=5y_%067#dU`=F zb2i%p4PS?@C4zSyJdCD_#1wK*=Fu{5*jibYvHPmjmW2ij8#eM-zJ2rb^}1DDQ?p9d z9#3pB{Mnk4uF^hZlbHK;IZcrUp^2`yx0HN*bX3~>h4Eeni9SxX7{F1w{2F#gPhhSm-&p?G{1DTbiFm+yY6&^Q-=;ukx^27Q1q-H zv#;9wgyc9#?#=3H?Dze?Ln8PN3zOl?oamjWcFhYsz%_qiljymU!vaAYcX#HlbZTlX z+_&OqC-?J^<>GSJ(q_h`^{Zdak>c%}csGlu@>NpFo%#ILOJ}*p%NajUc{0DNeV!M4 zWSF?-t1E{TSOvAc76vM_^skajw2(^t{J_z|TY`seMHYMbYpxc~%P)Bpqb3-xSS^(+ zZI~}%$5L@$p+z&OhimUfRpZ9UpIkhg7EQ0OJX=-1q3@&g{(rM8j@tj@v-x&p`N6Lo zD|qI8|MUF8nYGI|?yKWD-gm!6EyguN$f4Ne^YRCKkN#?u+P6_6)Ko8iUyJ+v3ITOL zx#J6+r5Ew3A9{6*tL_8)f6jZKrrERiMA#dzwtvdmpyr-7F}pE9^jLiqo4>B++usUF zm-tNErML@&tx67hs`EBZ;*2(LS}qr^&@J+Pch)bd)~EY--#M7>7`N?KSm@ICF9W(_ zPNlO4Pv5QRSJn7@L0f*~6q$7~ySlP3f8O!;nsveR>E0)AJ5qOg>&vP|SPvz`>~I zpEX@SliJkv-!LU4S|2#HQ!r@LiaRV{I~83P3fpKw5j;uQ2Lmw zwoRNt^V*6^{zjgRUEIOFj>i;_bnN}f^u7Lzql{&djJvGncO#rcYgKzZnBHKPS3e&JF^0NmUE3gc(?B`O@xciNuMH}@?>ti9 zzG`klXY{ihV%wNzo(UFDoDs2m4TrujyUxUj*qK=qSm%7bb<^8N-+1vVHSgr7c}G_L zjy2%nJ;FF)*CD00E7A8)6f39SWSBOIOWZZ(X-F}{xdQQEJN9CM``hfUD|W;wznrD4 z*>X(s=JR4xmkv&KKiPvD<{kJQwu9xGQcH`#h$H@u#En$9YzitD@o^K8HO@ux-kJEncFmc}!2v$=AI_ZNPPOuzVR z`$D+_&hR8*Rn?0EJXVQWDKmQ_=bj4G+~-pmnzAr=TiB$RpWj^lC}j0%dCBiAc9Q_x z4grp(3LYl}miV2#ADI?-Z@29AI(r2!j}Als9~^cnoiF=z6RtjcwX0vd>?}vRYl8UJ z4Bm+w%1gz=x5*#e{C*Gj`O15HEs9Tb%2-xOXg}87V$*Ecvuvi)63d{=k*Vxo7pSk< z;ytTf!uCYiBLM~O=PS%PCm!FqS=uY5a@$2C?^E*2!~XTIPgvVrm~@x-Ubn=qOY2oR zf2d0y%6K#(sC(|)Y>Azrp09NLBxjy_v8C0iYuU{6Vej`m?t9KyalAMCi)0J~&l#=0 z{I#E+ZgF;zI~cwqn?2b>M|H7O^R2|+uR?$PWXgWcK5>y@@s5Y`f1c&vtNV4Pv;Mp7 z|J&O2XW8q78_t)gxi~x!uesP=_q#Ly|GA5^>wlKo@2N{j)^3g1*vC*@SF>*W=ehGO zIQJ;^zb%)gQFPAwho)5iw>yY5G^n4>LyK}o={y8@J$mR>BVrwFl zo^5(7&VA{h;X)?&D`sx5>I`PB5))oyyw^Zn@9zGV+Z>Cf*Q|(Bwy8F9;1T4T zS~5Ycvs%fO!Fi)+ll(jm+r&rR+$Sds9X`R5_Fw7p+G&sW{*`s^y_ zH_=$xi#p|rmTEhjw}08NZEr`S{I0)wY+prK%O9nNY|MP9rJ$z1?_bJprE?d87Aj6V ze@;1Xt@eVM5{p~BUM@Y%BcZKXqwX(r{Oamz25zoOyXb_ARa@4&b2#$7JYp+SsxkBX z-HcgPJl%Yvv)87x{tFSf8shdyTDtwiwEI7uYwmyluN*Tkj$s1#L{7ECrZF>ZTkqcO z=&${9`NsqHcZc`Je{lM9tp0y};fo8pKl<{2x9@o0T;KZs|3mq<)oc))yEP74&RbG7gXqY zqt?kqsj}(!ZlZ!%$#M~UE9(vN;vEe z9rW6KXw$obyaoZ=vh{wg0;}FB&HPn4cVE^YQymT;JD=4Sw{4-N@ndK9+sy9oj|E%% zhiaZkv#Q|VPYNf9<)O>31vN zsm6c2y8qA2x=U3CUDegQwI{wkb-nKK_PsBI<$vE;EC2Tc`@U3*Rs0s|xu>S=-(;9x zVi*^qH{;OFXX`jNTu-eH7Cf5Dqi@o-!$;*a`+_CD%KC5lS)Gyuny$Zy(U$ItQEAZ# zW>Md;NY6lJ|H!;IIp|G z@R?)pkCzt@Z*KAmN{)XyPo7)y{j7JN9<_Yk%KStB|I_e~d)L>n-YV;>O4v9%)OT?9Twe1sd@oO%jn?Hyx30?C{Q8i( z=WBC)-}b$4Wp})1mT%qKP?{|HT}sQRd!F;Y?>2%KRyXyfx96`}=h?uj?7eiw+kN|= zUfg37_99g}V10p)>&*FEE&rHEGWhRb{@yOWOeV!hLwV7uLXl(p=f^cRt75`TeK5@WltMYy3G022xB6HMf(j?j9~tT)+6*_7$(VQkdKpOC5_^ zBGGNIL;mNUGx7;r_8mOHbL#Pgol3`c82x;$(Zy%DLgQAO&@bi*N-KOjSD#}QIDLb8 zah1XYy`{|W-ozZtxusBfK+>_gTW+cL2O)Ne;FnVFM@}#9T%3J-y2lpb;_SOG+N2*y zu4J^>@r`}^z0YqBI@kYH*Uyw**j#9|z(e-&!bor{tH(gKGx) zWd#qtvd#GJnp9ow-}9?`|EK#mpQF5B_r)|3jDYeEMWxv{n$Y@oxn{!ddnLWJ(A5lG9DH!ihOr`tMh{uJGoxzZP8Qu_0B0}(&59u#SA+l z47<-K^~{=Fxtru?|7@j-X_`FuzaM@JtZ5wUo z@hYxVxY%g2P-m$^!~;3g9VJ&>SH2Sv7QOE9D9k!|%4zjtuAsg{S9Pimh|VeM;*p3J z;_W@Vr~c4KVReJ~x(7}wxjB9C?Cfxyt0Z{DQS=H=ALlan24manjLZtx|4N#e&650G z^zf;GzsyGSxd*p1zOQ-y`$LoX{ifyX=CWV3x)v5*@FSwvIKBU|YyErH8#WvGjxSP? z2yID_K2s)L^Thf6;otXv$NjlE|BvCl|NDM#+#bDHj)&1%!vC0paBJ9#Z~AI+i;|vs zFH>fedYJp-b<~?xUhP+|Mu>~|#Mu~lh3z$*dcz=*@sszhnKHL~<*wUV^970Zq?vnF z>YvC~YFXmL7q;9nXhlfcYxSiZY&y>vFP>hN`1gR?yz2LRcf5YL*@|4Mvg2 zcdDODH0YUezIth88lTlcDcptthZaj6!PlEznzwjCpkXGeRXB? zUbo~=MR;haOZT~#t4?JU&Xt)n`D@rQj_?!~;Ws)Cj0epl&ZNyaYa_N<%usL3j!C9| zPZr3BcLy`y{p-z`=<(s~IjJ9NY9U{F#Sa+oWtegHQh)9J{(mp*|8CB&dp^fzr^7HJw|_!k>}{Xrv%l9rIlO<9`RxB+3tGaN zDnt(a$-m0jv#ZPS(vyqxtKYu9|24ndwZVTrK`_!~8c0yarq*asbk8YBl++d-_>d-fnwYx#@D95I)GJT!~JC8+) ze)uRNG9ByyBaqr&Ynr9m~+qyb+?|#28c8#}GoXD+p!tS$RYXQ!DE-1M6^h@d6 zQy$h~dKdStG*41}S2iU^FM6@K;p^5(tdryT9WU~K3B6r;S8;j*i>k<$0-v>PmjX8C zd413HV#(u+do(3MQ}I{Cv319`cyxvsJJ|mB(As~BLF(Fh?YYW_rP^=iH1_uTzIpd9 z$wK0!>!EEu?^TZ<5aE`dU?^N7%ehWJK)EDaPjgLxOOz@<)1=%32|Vu1d!Cm6V~GEj z`d{kJ`Uc-_^?4OM@qeGjcR$Q%n!>gs=FnDc@sB?iKmTy>`~CL&zyIDpJb&L~X9k`= zIlG>N2@M}lab8jG|C!VHGpSKaz$euE#>4{#TYkJ;w8nMz!(D~D1%1pTU!8x&b!BCT zL$!Dn`wfv-b4?uQ2VLPmzCM4ZLz(`*15XXQOhUQ;b`-xgf2Zb_rGitOgj`6 z+!ix>JZiBhdSmcz=X1F`C9g!b@yQ?mbxdkavX0p9f~iLr2~Pc&5u?a*EWyCd{>}1; zvadhSY;*1WZkGBfwI^1{y^D9pW}~Y88o@i?+H|4H?Cv~SZ~s-d{zF>gVl9kwCnzat}jfpkP6zgEwUowdBZ6WK1Rw#@Z0s@jqQK-vWJD&J$$dlFzqdd*z;P!oL;H6I{X_vqJ`Eg{{ z{CT23uk^k;Z5K6{^{EQe_j@;#wAP3oQ|w%}OoVlr&_%iDHWjHI&WHPUc{_CEs-LQF|n(x^3><NeH0swu2@@7y()CvGn}pZU@#dRq{qth}vTyp?43 z#qPUjKOA0Tuq-vr+G=Z^Sn9Kkgo|=ZnpmbeEqZ?aflP(didBglS=G)cJe+=Lu6R<> zv)93%Z;e?ZqV;=MHv0vJgY=7ov>Hvf6b^~0>g zYj!DJl4#ylmJ#97y#M#^{q58DzB&D|HNHkYXwrmf-Qse`s_lLX$o={9_{Zh#`}y;K zAKuTx0Gf?1H9d55b9yVMeCi{?AO@cnX``I31mO#AK?`~UvmY6mu4{V3 zE)Y4Q*cD+>?;9Gr(rW(cFIvZErTaR?mcLwa^W>zh=Enq9c_pOFD0`^4p9@`dwQx~+ z<}Ax^+sXx*4sLhIN!4Xlu}Dw!?G>>(p|$2rh>@V_GL8Ua-Ajj**fJg3@)(ZsEHj!D zH2cw>y;ZM2&-?GK{o4IrJ!Ht@&KdnPK1;;+{qVl`LG=EIukqjd?CVb3Zg#!Zpm^Iv z*U3nNk6nRDD|^F?+{KYsZroU5C}o)=BbAt*@9-w;`#1ag>$mv-9?|<6=?{R+ZLF8bDz#@aKx{?yvPt)IRGdj^WZLN20XOf)tB|Gk<%V!KEJjzwX^q5~fe80w3 z*hu8~ltqquZ`K_?ll817V_Awx>4g=pI`xckyJRLGn3$NslHJarZV|k2RaVU0cMlFN z?e1vY_(4!xn|b;>QdTX++ztJ&rE{dc~xZ(Fzik0x=2mSsP7y}spHzV@Jl z;+jlMuV#m=(wge!;qBkx@xq1mZ_c{A?4Mp<_1`PLcR@p! z?!9Wp-)vvHcw<;a)S#H7)A? zxv^xQ``?@uE53Iwzw*FVpnJ_$vBwuVnjf-VTGF^y`*y((Pw~f#oY^;&{ubMETi0YZ z?}SOFAuri9n3WBAXI$~fV`Nd8x~w;<`oZGU&dX9iel6;l|6g*UzAx)$#S1=Mi`HlM zPo3sur|js`VfasGwu#uTb3HR&F*T%ZmJK|RJjIMXy8U1R&-<1`oxTz&(;nz;`@kr~ z%Eu;?P{MZcVpsKv&HZNH%sbB>`Lt$h`=y4aXPnVyZ;HcjSWn;fwmN;D_^Xdr`{(`m z#g)ro_4nGbjGWI;r`p<|KePXn{r$QZbN7E+7GLAIZiTN^aDm)51(VsiEYB1FO1zeK zHjvcGjd!t+K6Gv`r`(?ZjE~A@)xMF>uf7()=ehIxALFUR{iRiz2&tZ*DbZq`}3tcw8?V%vaUUo`DSr;`MT^=N{gNzc=4_3 zMIN34<-UYc-!np@8~Z!sRq`0ZX8ZL%c-b6rag9`b*S1AsF*g~UnCE$ieBA2L@KtP< zFVC|;!_c)t3M*&c{dy&Bh3L`t=FZ;-UOkByRpDjncU#=L^`nHMf#2Lpmc@a6VcN|> zJ#TM+Psq$-POJ5HT(I^CYszO=-twJ@>_tiE*-X_#Y%V zJXu^`CzX6=#igrBZj6xyTfD+{pFCisx1J@;O}gTFve3M47rQGye~xU)c4Ks%=y)_o zUG%}j1*Qk1Kb~sVR@uD%>K7|B;h-Zs-42BL{MvQn*rJIll6$x>Pi;-gFm09b?G`>C zpe&jb`Sc32LsOb@^GxO~=bn7E5EN1Rp)qUrOueIq>un~K?sXEJy)b~kHYCD->VLa; zYc%`PSc`R(Z@THoIBDmYTK~9lJg@VA9{26?Ev_s5FGW-ZHS{MJ{jfOo^oKFa#~j&& zNt!Q%j<1NGdBrF2TxinsXG}}wZcDsa@v>pfeUXpLK5o5M75u_)>bA&((^t6#Pri{i zli6eWrnCb*4<|(%t}SZ1_u;vy*scj*80NR(tw>^Yql1g z^U_M4bs(e7Q{|V0ogib(s)x=UjBa5ic0#&ZTTV(e>)u`7cVFE8c%Z?`M-umMDQ)^} zx<>R;@+6ZK*?`900|u*F7pyYaq97?hZGseQu7nF)r#j0_EB+M0|BDe4E6_Z(jNMAA2T*5gGAbJbkV zY}n>7NkXOb;ICtBbJ#;B9k?~|L18HO(o?02yZ`0y{aPMhboRPUb3=-}Z+sQ_ z^J)KAr)}$UHZ$lje8~7A#bzeM>rrZhP^iSUFV9b9elHtM|g@~)2`7Hwe z_dh+joF&Dkv`{^`@2^O%m$62|mE8%cHf!X&)Ms6?^5|ebD8}fi^eR_F)97nPJ=>I^ zcE-XjehWX@dvDJdI#_MxF8KE5(c|_%C1q?%BqEg$vsUY~Ehu<)#?$AM>7AO(yfb=i zo4hyvfArVl-w940^J5yPg^u^nJG$-dZ3C$_P0pRn?0Qbqwi#%8^&A&ovNC4(p(v9e zVfkG$3w1JeTfWTJXwupF(J*LBpWD)xo&Jv3nG6a-J|Ewkkr}IEwJPd@sV`wYEK_m`7oTHuURA}_eVN0AmAyT?LXX^ToB7gZ#dQ&v zhGJHs$%m#fhQ}4D9&>h@=Re_v$dQTv9kj%Fs;+3Um_FL}$!~&E#kT&&XEwh|Y_v1f zR|$Q;@}(|h)wk8mEaJ!aUcFbjDv=|2*Sw(8oDCvrk*1!(Q;&QvyTuWDZFiRbS;l^= zz2|p0rp=Wyep%gr&A#P;g6bhZz8(|iuBL^;f*Y4*s%fv&vgCJrG2=~3r~L^-Dc-`L zqQ47%hWa1g_xJaP9XmRfK6ULmCY+&raof_l4O6ChJ5Jh=zC}=tmGg`DBvID}jfgy6 zuaFq&){5R_;Sg&jmj^47LUzU!?|=E%$kX-N=8v`B3pAKd9LzXUZOx@Ilfi3(gwx`M z3#1q;1CzEGI!20VoQ`qXb@4dAU+d+Aa*--aiv-@bb)+sod-cuNaz(Y!V{NWwe;8+R zTw^y7JS=+0i>Fwlnd`|M^P|6h6+GS}JAZC`%%ArBKiB@h=GMMl_J8e*9h=ns{{NSg zYIwDJ^0s4*r`do1{b^nQ>3ID8tgXA|Ub0T*u3R;d%Oix%l`A{@`NO@3i|7B=nR4yX z!Y>kX7LyLQZanu;?A|Bu{C{oR_kA_r8}wz@&!0zw3d&K^^cTmm?$HWR^Aaa|DX1{18-(bJe>S})8_8uXMcOjey>Q@xXZL? zm;BYkcSDbp?P^8<2sn68At|o0( zuKBHXE8_I~ql@IkO!7tbgf3rT;{LS7s*y#q)cedv*Q1UVB@4eytkF2A-LcSY#rpE2 zrWxC#H(Wa;!Ti3$Ey03!@k*BN81Bt~dJ4MJm=-o%%;;%m=YKS9_Pc4dd&4hGVR~bJ z*WG2dj_lU+v5f+AT=(A>Tpf9#|00`>mF2o=Cncr{8qL;N_GNa{lx3$s1sH$P&RQHM zQo6}xbJomT$;$>o{ z4X;2y4y(z(Q%vL(^u1ah6ufxkT=C4*|7h!P{)FG(=AMvpxWysS+x}tR#$EfQR`xqO zm2c^?bPS2-?|jKINzP+t!S9v#z8|z^|DjOBdo5VCZp-z&O_D_-=M5*QY;KH5oP0IR zbuQD4BV9d)P8U2boAq4#FzvuR1IgZkZ(l4MY(IJS?DA9L(eVwQvUIJi&x&a#vzzsj zTngt@82MjURWg`Wna0V_aK?wx(U{e!(_3n7Qu5b78uC5Yr%x-Nb8A!T`LpNuK6{W} z_l9?U?R)vXk861+uxVedTU7Gz_m8SGlb^l0dD;8(-+TY|@Ba5IzUplMo@W~_dh&Z^ zE)`zXG9k^^r-*%NaLKLME!LXT#HL?(Sz3@+D_VZ1(A>jXZk~PYz6X`(?Z35||GA<) zecJSQ@4r9uw|U2=@O{?ayM?dM&i~VA{`dO)iqh@Y`x)BQTtnvGNayx@yFE zfmhen9v!*qz|ho}{88e*RHFP=A**>(oeeq{cf9>vo}8H~ZC8Al_r>|#qXi{$;_|yB z4x4s=e%|-^<@K1Bty_zCJnnWc{2J<-C!D;RHici7wx;~~b zC?wq8Cd&DL0nfpozZk_1P4QIt#mc4}bvL5fLcw=Qr@^rU;eS}B38*EmIDO@S`>&*@ zyVon48#n1cPtkh7e87YCuyor6l`VTuE%R8Ceq>hBrHg?VT)f;%ja`2y2wE~(|f;dK(S)cLb}4JD#}kPV3FR-MsAlu`P3}%My>Dlby8lLPnxRRP)x4wIOj^WDN{$ zCr?menar`>Icdi7C7w-g4{WSN)6Utic~!%^@qm}k&K*vRCcB>XX`gYx?#KaMe(Afq zQL80=9kzCt3zZz5nqhPx(ru#nj3>-HI1ff2>}JJ2_vJGp|PpmmG^-Um^l6G z_iJq|)av0g*flGTA*%G?8;gWP4<_;Uoc9UhGh<73P1~^1uU5qx#f$+1iw#xH>YAz%|Gke3@0L%+e$tE_U3ckhpqQNe*Rzj z=X8F}VSgL_i#KZorx-deK2f}7w(SpwDP^K3Q?#E|onElSVg2-k|L^8n{QDsIXqnf) zhwtsTTrl|cbN`>&`%Bpla5BvBQM;03_CNH0#^!~#4T~oy{ZPOEuSRh^P1iE-4ol@%Z^&O0Es8CXW`c<>$K=)_VNtndTW^#J|56HSE!J zTz=a*(C5RI2SN= z(YfXK`_^1N@adG;o%;LE7RA4KeihsDuscgkKIkVigXLw^T#ltbLKj-pN%bAMdSXi8 z4W}**k&alI^CwEX3&J(t3M2$Zb(>_m+}Su=ur;(UeWqH5?}LDb!z#0mSS+p+;SNxhyvv2W>iX7k+n%wkoaqHQx?gpVs`{XH`J?wLGUL5)7b*ynw#YKtc z2daJL1~$$AoTR?*$Gb6U7)=802M`B%a9n$yH12O3dnIa({j@ zxzy8pJlP^#>Aa;`cT(xqQyy*1zFB|SI}RKvum&@Z?Ar+zT{*eR@kEx=&W+m7QZOH)kKx0tvuF<}z%=r&fo8kwSY;<@U@-W_g1 zCw!QF_$Hs^kbccPWoN6ds)6@vmNpxU9TJu69!z!RU{b$yfx+8CSi|9PNW?x4`_Eff z7*tfYy*ObW;C9&h>>14|No~?>i>GKGtCVb-zeC_$T6Z!3(zoAs&o6#k`da+W-VewVe`J~FmPoucxAlKC0(ykTcm9<(-uFM zybF6C_f@a6EV}MoZz$D!scd)bzv!d&o2?m|#qIvH{{Psx``ypKyYv75xxBDO`~p{K zWrAD7ZIesWXYYOVQP|=~gqOg@S-~sVlsQ-@R9wEX>D7bEHj560x;LA6g!U|qZQ(n) zW45JpAe+f;U6yDk)lA>-%3K?^wOrGjQ(6?%y|3cTf;?t!&Goa2JWkDb-+lQ|!4}4~ z!704QDoh-1zE;d#!V$B`{(iG3$Mf^+lXh(DipyuTGMSjhcG}xJqugkTr|>UM9Y%(qm0{j0=TWI@NnTFK-X-`?M%^QwJ(S8FsK zJU)5%A3H6k7tGv-fy=yiovXeuOTgmjp*vwYJZ&@PXCK(S+JDn!L7TLHIa(YcE(KNx z)O#G{js@S9IdiYL{~F_!$A29zIW$aI#wk+5v+_!R)9D8ruN-mjee+dED%!Vj{0ZsHl+U zi`m1zyG+(iJK7=A=feE_g%eE!MOZ&6ahTf+Y}#V!%x+RBq!MQFTxnMrXJ_C`mv_?= zmitW=c-7)77;);b=3xQ|HKxg&smZd5jv$c99z{zG?WF z((^H+<&xNkeQRzCMoF&t5y^e;aPS1rsH4C6x!nGon3yJ+)VyM$@21SyC5w2?elV~o zTs(3xnyo`PwaK019Q*dVI_39Yx)xqL`+MG(C+Tyo%F`b6@B5~zAGF|D?zP_2ouP~W zU)B7iA;0{s+iIrH13$kB$26?J#+G2knK5m$lKsbP_kYTl|NpT%eskHU7oBI+b53ni zm@AROE1VmpH1Fq`<#|Wf)oMpX-Rt7!JM(y3bofbi&tC^Rlc)dPZvOvKeZ_D2zXxw$ zyLRo`vuDrb%F}OTm6|c+{5jnI@0q*5y#2@P(yxzizO>6{bzmuTRXvJ%3s)vs z1eHHIn3LOj;H%&n!K05t3jTkb#KeYa`<6`f?GOBYr(>nLXkUwFH% z@WBDcKacI}xL!-Ae>m|`*`RI1#zHyk@^?p6IGMPOyLdvn=oU*6UMzx@= z)>BRgT$SA!r)3r{Bfl+i)+90R={F=-x@{L?WneoPUUpWX+jWy>{K3j-|DY+0B+eMS zDqlaS-eJl0#Ju;*YNgeSjyaUAV|mZQ6TI{#zG^A7#FW7D*J=A)nbxmTC{6yoAJ-lD{DaFU4JV%ZhC9a|!M+^3u~;rQ5i z-Z*Nyq}{Q_i`Sd~eE(QeLhyp}eW~~Up{=SPm#Hn$^0~wkdgf)zDU(>p}HzeNvQj@^?BXeSQ3N3lKLZ|Iod)2Q7 zh2AM%s(&}0Va`cR%sr5h-1Fe>m2Z~4XD7Vuysi*-!R_jz;OBR?czzC9?s9FW^cn|8 zcco00(1}g@w&Cxm2U;D7Iv(Sr_Shg!m;Lb5wWp=6x38Dko$%gtyP5P}{`a@43v|z` zTWXdTnSAWZT+(66Q^Ad>RK8B%R&%GGCv`eR+dy zn&r_@{#CmaSFFqv2|br|I(eyFDOcFWnG;?u+S<>dBg- z{o5P%II(C8yjgaqy=t2ww^!2~o6@Q8jlQeiIbU+S3776PG}RD@LXEy)@R|E zE&mO^#qN+7kFVhj3!8TFb@{~{vxj?3=FdBKie))Vi5SEA04v7L9QXI|U)~idnj+*d z(Xiq3(UPELj1|hgGD$OdEwbE7_AFn0{<_b;f-BEL9AmpeYSaWgEN^UbnP&1Jr}2o2 z$JRE_C)KC#B$}L>D6TB>lx1B>V7tQdn&6vL9^dC>+tPPlTt0JI%tnWp775i-77O=+ zj*CkFgfA&F2pF?(D9_o#H#1S3>6Ebg`Ie6w+i#b@vD;hq?aA(W|M#r7|7l+T{p9!k z&r0vhH>^=u^zm51B%we~hNDYV)^eOpJH}uj*(=H*a?~X?()iD5*ZG%c|9km<{+_bD zuMgb+J*&MR?W1O0vP|f*$KMxkIaTpiU;BM;dCez(zL;Ng?5h`D zshirtAph4?f>-?B|9AG0KQG%?UcYZw^yrJ;63?I?4r;!tKbV}-m6s;0J*Ya}j#E2& z`o|B4zdt_mk-hNIk;8W~wshAl-t+n1@Av<#7}Sq#TXJps!HIHw?SK82Z~oW5|NHFx z|GWA3K2MD@6`SI>HR$3#(e9Ooo^N`Vd!;O0CV9`zJaL8SVQ&@D3o6Ub{aYurgXJJM zLzddl^)9nK=e&P(CvHo%twE7Nq(C-HhRRCE#djGdHkt_;J+g3FU&9pLCAJ{XL+PeZ zSESCmQ;b|3aXFEV-V&1^6r11cdiqp%$6M}rr_C1~BZFpcUI1GQz>;%wm+0|+`<}e* zt+LkJlIsdr+HDkZ4Sdbsf8XIH%;apJ9BdGqgx5r{u*fCn;f7lyZ)+) zQPj)KE4t@X6wcH=vMi9%^_~%U^~AM9QL|ca_!M)dG%3y3e(pWRwe#!O(u!|8UOaH! z@!^47%#M2bvUj&S{gyYI^nKcTtzch+*`zBgx3rZDZ(LJ&G=0MFxq>WBE+UKf+J^KT zVpC5DGe|pT=ha}u(jvip?sBKkR1T^4ei>^YJ=gDw-OGAHu`~JW1KU033TiXXoN80k z$dF)hpYcRm!uQ-F9h)ZqSE8JcH0)SbU3_x2q${LC=i>$Tj3DFhi&rU6o+>8Rs3@py zq%!-^?Iz*5tlyRvZ~JoX*P}Z(i<{4EIhQrJ?un*<<*i?r=a;@s%KMwIqo=c0dh$B^ zyo+B`7R^4pZ2pr}rf(ceQyEs>eLwZgo}$xd=kNU^EdMVc|MfZ9`&n-jmfp>N?-Tv` zZ(8*}?zO@Tw@3?QDs?p--^B6OMf7M!g&nKi{!O{x*T1u>xS4)j?(e#Vm;I;QTR({{ zA$h~RGV8r>)Z_ooy8q__yZx7-^jdkf%l9%;W;$-Z*j&o$wBdp$_u4RdPvwLAVy!Qn z;d!^`y_}47otlDtUQFfHr}OJ>-@f;4F~j9-J`!r9WXU16l>T-xfO1kl` zy{Jz6VB?cXTGgyar)WM(3*L!_H8}8nQ4lN^*Z)NPYYhHyl(t) z=l>XGh2X}Q-#aRVjVm72$B9TB3W;`@mHL-8zWT&w9cPY5iPMD(J3ME|xxQpLy5qy4 z+8f*R_4(q9B%-(H9KCZ#rpUUdirey{T4dCI`Fr94RlA}#T)XzV&8l?rC5cOq1(RN> zI4FcYn9&zetCp@V%NSSme(I5*Z1!_gCWn1|9xY%fH22&Zw`G;wo=FK?GVJDj<=AjS zT{Z0d+EeHG8n_v~I9~?q-8W$j4s3g{bmJwjgDX~L_I=;IXy!3xpJJho2`_x=x&w|# zJmRZI%ek*&Di!& zVh%s9`+e9P|MSSQo(Hqe>hv6c9LJHk@$yTVolmFDUia&TyZx^9*I(Bh&am0DYKjZRWg;=QBf?j94`M98b7R$@CJ?ZaI)M<&$s1qdE2q1?);+s*3;J z81%OO%&l5`sooWL^XvsRzD&Kv(9`C8)@7zr)Q!!6D3+8CbF z=oK)DTFX}T*X){kk;LU=tiSb-Oq z-{-n~*%5e9dhxH#`50VF(qX6!wU+NRTQ2sOx{)=`s9g9 z%B!>k8M^%GXAO1AWC73Ztcguo#qDJb5A{a&utG({Iy8-M2PWky?f2#VBn#> zaC2cp%Hb0`ra7_J8D3&I;H2&NL2B}WpM|_zS90aOQG3*J{cyX{JLj*@qNk@WU%%za z!tA++qQtjy%)Y-ridF98VY_|ok3UKrz9?{edw%oQZFZgE*TW6o%SgWDl(6jCr{N}BLsD`$=MFRb<$rk|FUn#_yT5;?VNOm!(h5IaF`mHr z3(aD+t3q71vAim{^IHAmm6s}F=31^D#i%+RHZhvbt`}c=Ue}8Y-Q!2eJC;H%> z82L^`pHH59m-F3I_M9}+jq7Xu`haa;_pWH|i%{IQc#Fxe8%IT*xj5pwzt3I9Ib(L+ zdP&|iSyh|E`Uwlto;EX?oMv%aH`9Hl|En)ve11|dFE!3gSlb*H#i4MnS)m04;{Do_mUexPdy;m!8^6UAU#{?U7G}kVu z|2#VEzpr+m`S*{{?VhfDZxS7L%xK&B?HjZ{hi%>-H)Zipo!s?xmDV+WcIB7Ts~2B< zwe4cTm#&j3pU$w$*<8vk{k2xtx~#lvuixgIIVr9)UoY6obuci=#KC9Q3bhWd4VsATb+ENTCHFuz>mrfAM_F!f z(_y&x_{qm$i~WVO)S092)Ly?^ey8kqdR^W1b=`J;N1`-StM}gfasL|Alx0(w@G<=R zw*LPc_x}&J-~S=}wyu6+NxZUyMv{u7y6DG#rOR_(3AY{SQTcwi!J_xy$5$dk?jNsu zwl@FZP2wvn{gkscDkAD;oU{3yuSySs<<^$TyZGMJ&FYj&n~_;pyS4h-)r8#Om>_(i$!%h|5d1O+sQG9k@?n)U*!p_Rx~Kdg@o=Y{NwHy8IwMj zUC+#4t|qmy$MAwmO>N&HKTWfk?!zt{Qy$u{ga7GLym@R*<` z`{(R$yN1ipa6seX&Fk;OKQML)?~Jok@QvE>`yBg+dG_`Dd#tmO0Z<_akY~bgJTdYxJF+JHxD#1qba7JaG#p}iMPMiqQoOk23#d9wSu7@@! zN?orU{UK5HG;zY!je8DqTTW1xX4YygZVVRMyzm-py8)N9^y;G(Pu$(g&3FCPoo`=t ze{TN&fAW9o+1T~=USoRIXZpO#Hu+rkqJ+aP>RH8H@$;UmDZVZJcB5%laYnj=UGb-b ztJ@zxy!!vk#r~z=Wh*mIA38Pdbye}*dv`u1?Z5lhtoPg%mF-cpTjrFX%3w|wQu-7y z!|AM3$*Y!2oiRpi#uHaHUGb1$Ip^%2ZJ;g6qv<|5X@Y}nY}}ms>yP?!-@hoEexC8b z%&(<;@4UBvsPMx}kTLA2JcC&HB?E~Y)%8!@;n@y9``!3m*-<>IEQ}N)!|C;C3b&o>rKdo}#b@yFu+n^RëM#e#+f2d1`1p5zETWUX;4jU#x{ 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

G{^W=X;Y3)zeg;wYN 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 z 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 HN@xNA@g3%h literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_pc_82.png b/src/qt/assets/systemicons/ibm_pc_82.png new file mode 100644 index 0000000000000000000000000000000000000000..4f398d468088aa499996656e04cdf03f946cf5fc GIT binary patch literal 295676 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ëM#e#+f2d1`1p5zETWUX;4jU#x{ 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

G{^W=X;Y3)zeg;wYN zW_!+Z|NpG^-S;I7AAB`sm_$|YnLqyi=g9pZ7x(}BUiWMIISULo zTbb$nw!bc%yS?vgZvAWjzd!9ipNv|S?i!oAH}CsvF&;j5_2wAY)&C#7|8t{1uHx19 z`@3q=*3Q=}nNrvlp>A<;)m7ICd#&?NT1gg~Wq;0$na%&MhgDSKwqs0but)0JnZ~aV zyUD*XPi*Emdcmhu-mK-@e+|dvwAu9m58H+RUH|uI=87{Wb#~X)Sze#L`ta?%Yf@j2 z-uY%R|97ym=t3>^d7HVNUhmMgb6PK=-`uKpP3Sq-9{xotE0?VATIsL!^w{D~&C|Q~ z)xACSBjNvpC)=#w&0e==P0i1*{PtgR>P!DR^V|J+QFiaG{NHH54@T#U%Zu~uLp^1t z{JHE|xoq224~3BZ*Ecu(o*G~GU)t{X%ky_$)_it%l}Y`6|Nnz$$5wu=yVm`9(K;o? zDJH$b=PCtt`rkh4>`g7+y~dpR?bLXus74%AU8Vh#I()w0T(N7 zuG;9!t(y6=Ya8!|P@$IGi>phupM5U=+ctqK`;d%ij>eCcoRhswuca2PI6LRVK_kgG zUY+s-@P-toO$@=T4N8J$0t1nmWKv!>GFKU=lk}@5q0~s$BtnU zB>3^|7Y`n6%P=q%ado^qrKBo$mu>Hawuq%m0^2t72Ci{%;Sm$BeAONAHgU4r!`;g= zedaBnV_QD$_4RTKJ1fQWyHq^cUuOwi4$FTS86BWb?Nm+JklWsj&xufv0)$?=r+}2N?yo@t*R#J{{!KFjsUMy2;he7ZR=XEsl>joZDa zcjLT+Nqv1PfA2A9CaX<0yw-MhN1j@Q{V@su;M?08JT7XvosbJ;n(NoD^ZL@;uN#gP zm6Ui)b1&H?drIj^mx-%WWQav!k6#;4)#{pe+v6Xcnkswl?l!+^TeG)jem;C#FD$~E z`CU|&tBiZe;u()8bI$+$XS#*OnjQZet1GYX{;v=@?ZS@P=jJd>;7&Hm7CCfWL3@c_ z^or>YKWz5wPI}er8MDM^Vnz9t^Wt{bU*`U~kf1p|HS+R%-g*D~S2Jj+2|jSSw(*|N zm+tw0pY;DVzyDo*|MsB2|CW5(WG0%q&*9!%!I_ic7FBm*>%6t?|tvDk6iJ^`+xkt z!x=@ByjGg8kFBx%?QZ{(zb-7~clp{py^7WHG^os$B0%rtAc>LI&%g9U@&jtlE- zCss;-Iud)kYVOnN-DR7ndbLizt+QrX?%V2^(-QpBIqsa zLpZK>9@>2OWs1ks&g83NyB9tdE|L)Oob)L6N?F6Pl4{NA@s+*V*Vh$4dy_edr$j{X zxMfg7SmHfdckVr3{YC%XBSP3!BPrrP~zjDP<2{SUEg*TbXT z`{ugmy?^`u)1S}ll~SFy3#VPJoELQ6v@|w3w>j^)Kxu6AhlB5RWln3`E_*6iI`Ps= zw-ReZ3)fk#hOJ+vma4AS&ffFmk?XqHTZyTqE8o_&Hsux&s_^`KSf!?J1kMYR${C-zB?atM&@a&7C!~?Ff6|lCL>AdJ9vIJbXCe;GqVO>OCtQ z&NM^@YKSaZq{HpkmfWQj;W~Ant9fB7er%B1e?URgZHQ=_ZtWyz_B2N@^!ZQPb< zB)MHB=-Hh91vU=-o0S*&}4m*|MuIezRem2Q#MFFSMfDoYACwwql%}5tcI%O zmud~kKry-3SzSpiPLon&r(BYelPgNDZrAaTjEqz~Z+&E!bENOab!k>JFU??k?)Az_ z;MiYY*(2^muZt(%lU^>(u|= zGdgekohN*K?4sLmC!|UxJ57k}Nat^uZ}CzUi~WHKl$9|{}=lh7*4(Xr~LoJ@%lI7|G(Y;e{=JqiMJlQ+>1S;I8#jd)X5!R zTePIOSIu9~!Egpu;=PtyacAozB>rT(TpLaM& zZ`qPtu`f(huUYEu&H|acSNwre|VXwh0{EdXr<-Qu%F1&+K{n ze!)s<`IpE1-H%_h4wQe_`|9o7zaO`*zRjLr_j&u9z3;xRw~vX8{PQyZ*R<{R91GTY z397H0@As;2$|^tOt1|rVa}PSbzn^`sw5Fz}y*Te@@cds#lIQ=ql0SFl>}PXdFW)A1 zZod8f=*YNNDtA4^mj>SB)NBz}y5>~Dx{dQr{z9kQSI>l;UpKdvefg1`EsqM{?%kH_ z$YRy?-0OcsY+sb&T*u7otLD!<&R4zsmJdg{@!Pz*vsY^jm*)ys<=;;K`-~?@Ank_N z*<;MxUpU3g4sV=OEc~P=*p6BKq{4xmtn(Qr4?jHUkiH$Rc}nmc*QYJ_*`8)h@$#4? zu~s&465F1Yr7jcQR?qBad}Lu^GsUZEu_H^;{iWXPAJrV*`~3am#q$4j)h;)=%hk^K z+I!XD{WZn4f`=lsyxI4B_~ZSsML+M{!sC;f=T-c9>);jHXDKHacwO~a7*BiSL%E}Z zyQ`~1ma2AE>*(rTJSlwa@db`4N;StUB~Gxu2-!Zp=ytAj$!tL5$+f_;!v8|6%Z5#RJlAhO@a~=IC6~pe8ZV|! zi*T-?M?6+I=Bbox(P8J^bmexdPj=ks}wZ+*@F zVlC-8X|<*>Q>Qj{ogGm`#mqK9(&xhC)>$TKY7ko z4@u@y?#{^`l8Lc*n=Xh%EzNzHnwish$!>#5PFulF=a6IOS3`tzzguzd-%7-l3JWr0SK9a;nmtXo|N8lRAD7IKSzFG&`V^A6Ejyj@1JgD zCt3XTR<_KWw-4X&oPFVWNoJ1wuM14EadHJlHU~_WI;2j#^z*^_Kb`jFb+wg$=PvuC z|L4K{U)=fsmj8bue#CtL*TCZU&H2CHeE)a-{mw0Qzk0HHO4m>SFYP}w+q;{u;%xQ) zpDXYGJM;Ah|8*_>DF(e00!8vVzAVrY@JPRAk{Ed9;J-(<5!bgo+G93rn=R`(w%wZp zoiff#E3M3svKBvi=GOns64yRVcwMl|xpm7Svy*R^UB9>OF`IOP>WZ>s?{A5R-WPee z#h2kW7Z3A|6{?b2oQoVenm6*PGv|bHzVuBNkc$^#-KKf=#gi3wH*T(8eN0w{fA;f# zAIkSUzx3+Z()gb%=l_1H&#lP!|LSXL^_Awnilrjw&Hu!$s&nVQ?-~4UkHFG~v-7&X z$Jc({d3Jrx&znc%|6g#w|7G9zzjwaJ?JP_DyRZHI>phQS^SgijJ(^;(a;l-5y}GQ4?P}>bTi~T|M1fOQ22Sv9a6_nY^uALj*KcvYo+z~{b2HnoRub3aB%I7 z)4K(@U(bE|=Iwv|;(V!`*QL|T|6PlEzhn94^A+!H%cs3taB`z+1YZHGwl z<7;YNQ}Tao&QC8XI5D~3-g{QLgumA#i)1t2oSvxgGt1gJ*uU?8CR+3D^ZeY;pJ!!S zs`~A|v!k@v&A%h5@!~9HtFXX~HDVUo9gkU(vt3d=tmpkJU{p;$b!g*$^E4yP7vGI~ zbZ_3dlTckf`Eq*SM3+f_|1$S%Ect9VQOIKLMc)sKo{14LQA;kLy?N`F6PM(LgBCra z9PrcM;CJ!GtW7e;A8a>maTY0+ zke|Y_^ySx28*~ljx|O;_gO;hu<&U&@7+o%FYgb(^Sx-_%ijAQ z^U6De5C41E@#vcGA`3;YO=7?A{Ysp)_<8fa{cL!b5j6&-}8iQs!0Eeibu@*7D_L^Xi}d zd;hQR|KIR$-@i{^;~=@*HBj=E*MgRVmX340+DQPD?#|_j|0_-#oj!H>@=H)OQ<+xn1*3?!Nfsf%U&j z<$vt&|L3oJFh4bN-_7@>|Bsw$sQ=a{|8x4)dt3KQ@J_CKGIffPde=_*XQ3wc9cM=*2I0o;~_2xWZLv>#jF7mu4Ssj*>lR{&{QRWfPaew(m^Y zw_cum{j;UsEE5mo4 zthjvTYva9}yPuYoFIVdfn`d48Y~AvEzeMvbBBG<~&Ofbw_q*BtYWh+Qm5vzC>74EU zR(ER~ULL%6w7>p~@af&RZ|C2YmEZGpgVg*O>pC0z>Sx>To%)n@JosqpWskRW3J%t2 zKGQAMznLc^`>ioszUbS(6_3i!UEzQvxG)Cp*n&W?Id9 zuO+lXX1U2OwewYHmKk>?9XfYTZ};xqZ{Er-n4*5#N~LhR&Pk7;`>*aiJTG^2OURPj zMI!g}RD)*iQu0mei)oJw$*|>p>aDhDrEd4(P`T~O2syq36LozopjH?M_hSM8O%B{A>MBjGRXwR;*oj!6U;-~QRn z)7~Ak_m|Bvnb5fHMv@Q9_ix(L)WzCw`%fkG?u6xnPAw{plMG8k&##=>!I69FT7vhD z105az6rSJsnEJ?Np|tgW5kB#0H*elcudWuq`{LW)?Fv#>k%xYD8fUzfkoOUYSY%=2 zKgmY%w2|9lXFmRAJ>Rrnd0l?}{0m!G^6_go?%i6x(l%WW$Ke9Q<+r_W?O1=zviDlwu9-oib{jNvn$4`X zm@Tsnn|8gx&LD8tUAu{10UMS4n1qvRA~x*ZdH&cj-?qbccjL~bL`_&`xZH1ja&P9x zOM)EDpXV*xcxCId8B;AJ=hYTQ-(9z4(fxP@-{K`oCecdIFU|UH=Wt<->UrZy7Rg3> zH}2kaHdnnHH+}iMDxoD$_x+AL`gVK#lOLU_TQn_YBqymH{$+J!|MN`?INylz_HjwJ zhV++rX`H%{)+KUrPtorahecm(dZ=uE|5TU4<|L-dZJSsRv4(GOidg?O;!ys*!tdJm zF23f?tM&9`SbX^6M~Uy7;(soU|MRf?|DXN4w(p)$-nA=Ws^}Rm_bX;|pGLafd%1vj zimP*I`^jTFC;au9)Z&=msB>ELRMR4zpBv}@sIK|Ey~eu!;qCuI=j}c+=~sWPonuiv zNqt`BIoZ6N-5-Bg22R`Uw2L)AHfx*t_V4u{WB330_x{JZ_kZTua~h=CHNLy|=i2Ar zPpNXg_l0?JhlD>}*Ke|%QyiiGe1Dpz%kD?v#pydUmX|6j1jVk=F4U{gO%k2+V2e2a z#XPA)|HBtAl6c(0{&KC}o=dHB<=)Nsd(pA<^RbGWXMbAn9+$8DB3%Fb{hz;|wsAl2 zy8V8~@AB3TyUj26My!yU`h4Y2=ja9YozvodgA`My9eFuPz{}>>iRb6+e>`aB_P6`_ zWOm;El838Pr|HbGthI`L!T)K;Y|Z2?SC&mY7kTk)wNrL`kY~XSD`~0cx4u7Js^YXV z#G<6edv|tsPm4uU?H2aB)pKu)Wy}0qGyD2IHr}|c(X!8$o!)SlGq-KuRL?!dDl=zU z|NO|5{6~hdo8wHy#keC=PBf=GSMJGhXxJ=xh&^nVnJI_IBaX+~E!^+&v%S(>kEYxy zczjIl=$b*D9!$jr8m-k%<(JhQJ1Tq<95A4_5AL&<_A8X3cq{$**9LhZyWnRoeIBq z-S5MyULUD7f+3*?i^JzF)!=%x;_%1E*(#Y$c{#W11+6;vX58YA+F_%zG9fj!)#iNV zqmRoiD*vby%1lm`bQ0?6GU9n!xMqUZv)0w-8mnfhaD_f8eR*ONU-|vwnHMwWFPgJ8 z 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 HN@xNA@g3%h literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_pcjr.png b/src/qt/assets/systemicons/ibm_pcjr.png new file mode 100644 index 0000000000000000000000000000000000000000..1f3014bb4fcff0c9b99bf69defee4a80e35b532d GIT binary patch literal 296020 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%0A!XV0~Qk-~eOy__|h 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 z zOWat_X>eoTQaK|F(H;CwhKJ7`}XfRW@~f2Q^|6|42k8o{@122;lKW5#f`gFVe;R3&T_6X*(xG` zQp-X5#U+Mh(cEK>3ArC7Q=}u})_7VbM4zp=b7_ib?DdV)Pt1<^5M;eM$Mjanbhl|0 zk1jU8VRXa|<)wZmnYwUY#Qlo;=t8;1LazpDDaH7d2K~O*m`tr_b$gx)v@ua7ZHQV~UB0cb(nhrLME*{oKIHdi(Iah4D#SAD@-5 zIM?_>`IaT$Apg(%=oxyN-tMof z%7i>VPy7FK|K4Zc|NS)1(Oe-ggMa4h*d-}vm+%&DR(^Ko`C+cEHv1LpKWwW${Ii{_ z{Xt~)Tr*phqa z9J$0o3u}RO%GG5xTj~zHv-tSoae7St_8*x}>t)_Wp8t}?d@J$Vv?t72lO0)a755tR zJ>|JwsdDe!k;3*{*>^t8nclzd#=m=wm*y=lPLwqYx14Z@w|&p!nz%*RB=wDrwEK#W zXSCc&U$XY+t1uBg)w0h=3auAboe#clWK-9$zxA)d!jRyH`rY#kWM|wu>zvQ`9!(RR z89B3b{kpubD~@~gZk*|;a8RLArDel`ggwUF%#%JGlW6{UNV+m%Lf9>d{sV5(iupO~ zQ=0Wp$VDsUWSXqqdBrEZy!5V-va<4{-tT4SD)a31=LrYe8vl3D{d89(B<ZhBx|G*pFGu$k_ z)26+C?33j-$7sslr-8yZ|G#N_R$cu}-T$Vn*%sgCs~2vx-MyYY>$7U|{#J<>v)azq z9e(qoV-lO6-ZY7;MsA7W-{#oGee$kXHGIc={pqyw+sSb+Cz@FW2~O%fbGz?r-h#qX z+bdg^9pjO2F-eP={`2GAY>PV|Kkk+{{I}ro#s1%?49#Y}(JkLRea#^r%~@w(vQ3uR z{Z)6})gvZJTbCKmN|fPDescYP<74|@`u{oln4d3iTP^+Yv374XgVn<4)7*G|`*Z&k zxf8i?;dl_D&0w=EXW|RdAh!&zNOm5v^)ik|t9&g) zJ#H17s!RzybEYSdJ9&HRM!Q8fB|l|Yn5*xp_^JB#rl9{U^*Oa)TEy!=2>so%p=8zt ziJtczjuW>}eENOfqo)Tv_c>cS??1JrT((?Yz2|J>lGg4Eg}?7kw|OaE5Pah(^SOgr zR}*`bItqRywfFH|*D(xKNRyhGc(_N#)Oo+MsX~>~&%1q79$Pi+UfvQ`wOnB7grJ%m zFYm9n3jHVS+AwQTBP{$+v>pr5_SN-xbzfI_^MPnz(J$B5TjqQ}@>;gc^6`l|myRE(=-_!d zX-{uQ#+{YVcg)>bFJqY_5@jUB^ET7@wau-*9V_pAC_7kj<-y$4h}0(nmFcyOH%v25 zZ?G=-ThVt@qbsPx{?S$O1UXY4$)0UCws8eo6IbvBD0!;)eDgRZ(0cWw%>N_8@%JW{ zE|G~&Tje@O_4qFvJ#pF7p@*NoownvdikZ5`j&5a5mn&%w^Uuy)DH?hI!Smvp3vZTA zNILN2RA5Bx8OcLpnId|*GfazX`fgn1d~fG9A>HH3k_iE?I3BZp%HN#jx2652yC3<>mM**e__W)* zO}i)aE$2FXBROPiAe-ff9K#E9Y!qL$+=~Bv?ao4>38Ini0h}|_w-iqa5fBZ$wa}XT zsDt*N;Jf0DM?jg&jurpHa7XJJ7k5nAk z(KKJba@E71#Yg`nxn8qA)~aT=wIbc}iLLKr?OoqJyA8W!rRR02KkW&UwM^IBoqg_p z)Cb4kbKaI6_bEN1^kPoHqQY>e>LRC~2M?rek@=g`T3OPRpPzX$W9p529G@R6&$@iX zZvDxWh;9+Qq$3EC2k9Ua^ET zzHi34MClK{DG_UT#zaq2`M^6T^3>{xK4exCYTXkzuuv>L^Dc^hPmRen{1flv@>=w8F-g*em7jI)27p!0V zRX&2tFm2Yc>r2+XoYcS2ppW@pR+~uniN0$l%iJ=JGTDmsG!`3N6Fe@cDY<`3%VCb4 zla4aXdbEMdCon?ULPU-GmbOlpVyabm@NYg%!I_)brmT}L((I8m*%h>FNr4IXoSKbK zmM_=0_?vSqFEb#!dscRUcSKg)DR9mgvzRGdtZ>x9 zul4LN!^Z-v?3^-hZF_h@pYw6YR`H&N2ciWI1yr($w@qpFX=ZpVae!l6tqDv{oSb;ggF!6RNwyWTM?Am7;h$ZRh4&v{?6iEAdTwTNR?^5xBs3uU1K~`jHN& zjhDDo1(S6RS!(tlaph${o?Cu)Y2+sp`HUl%q|fJE+YooJP|Eb|oq~#a7tAI1W(8PH zKFnBnT&LsAoHUtlIbP0D8s8rGJ>KS~VI3MU$#Pa{k5SP&@i|94Je@S><%PMfeS1cj zU%CHKvC_Pscc<5wy0NXcu#8NY^7xsWk#*k5oDT~hcINJ|eQo&vOR?GhRX=ysw^V;o zeQzf2aqfxpn)mw44R+eTf?!;z3H&k_XX@1)~Zcm?%qEAO&NRLw;KI4MDvXxoW)`)$Wcm2=o`j@s-M55N8+?igtXkl+g zvf-_y-iIgeEVz5(--X9l1dr#7@6j~j)9AdJ>6YE>_V{b?AE7;Ke&);n4H|I_&oAAZ83#RF=<>8pOKxvAPbLssz-bque7(G-&H^r|>N?$A+ zR1{mN8T;|c3NN$XomFCw8jN`_xzAZUBW2>5f{qlfa}i!Ac`Ox{KAK;APE_dUvyaOd zeuzzH*zU8q?D?C+CsuhV9_iWY+k1G9TjsGD_GZ_DE_dwL`fuFvV2*R7v((`hk!A0? zS6VS=FN=8avUu%OCGUe;z4ISczYk|mTXi9OLZ{M`5Y78tnmuj{Pds2bKk3=ero;b# zvi^F>)F*W+^7xOd+MlkT__JlP?dCUicRuI;S(R8TWzpApd%}w&k89h5WR;xKtJdT) zczd=kV!F0{K~zzPMB$YU+fr+V-Y{rh*}m%Xg5bAuE*hI0q{Huu87eM4oYkLwo-t9z zeUJV6GH)Tn@T#QMuN{RW7aF*j)W5H{(Spi zb@u(A{qGB_)<~2ougjJ=&6do)h`FuJcYZ|a@e((Irvl7|?*!HwE^AAl8dR|C@sEkg zGD^~_5|1U1?>m;!zcQ|C-K{9;-3ym1Kl}c}dVl5F{J;8bwfC8sKOZ&ReO>w8iiHM3 zy#msX^%je7t8cmf=kNbt@sIDiDv0}PF{X>Ay+{ywA@ZV|YfbmYeQITWrAzDF)M|<* zbObd?SMS@g>w*5C*7~N}Z!I;l2?1YJ#Ig>m#b4y(U0v7uf5FqI)zeG%n}0gIKlA7L z|Cbx`mGeCpRCH)jqZ({o0&M<+iE%H!du&->dw0=PbUc6~Ya1tBPHpJKd7c z5`H9OcuGX0%%AJuvJ({oj{fNrsyMy|-tYO_9TIVKi_zJg^J=^Dt^QjbeA3JM!I$yF z+uDpTUuz3xlWPt{MXfEoHfhPSF5U3WyRK`cT9ueyyUDKD>oL=Wv8zZvY*F^1u#-<6 zO%`WlNJ|tgTN2XEzSJY~MNicQiHKO?7n3*)Q}?ju^K2Axnpswp8s$BOIdlKvxWfzB zuDEOaJU-#F$z|8`V!z$nD{6~f`wKos2=m2XvWb55&FOioo1H^*7%oOU zjg+Z8mg{TsrFZER7r9U7QtcZS&pm%~(geFjpLhZ+!ncY@IX_-zARWk4>$L5HN!zly z7v&R#;~vhQwPZ!ZUjsWE`K#f&0`7T_=lx_)&v`38<+8Af)uY#fiym02v)+(1x~7+z zZrv7h^;TGPSe>7yWHQ&WEf!NZo=eE_O};h5_9(|^&DnOVCoa;u75TI!xGN~jpS=Td(bwZ{KAn0(GIV8_oB zd#-SA=hZ#8)01&s#IIQ;%eO9DvdZ=4l~qo)E&*niJzNfzDdxr`~6HnWePtFYingZXZZ95q=b>63oJewS| zqn%rioj7-IL(RrT4BJnK&pFbz#ri_sbL%JFwzan}b_=*F-tBP|^5QqxS<|a&vQ&-d znaQI)i+XcQZ)-GX^oCbY^4t0$U+3__1#294Mj5O!38_7D>_hlFS1c}^4YP>HM933Tk}Cn|J_Xm7cySU)paO+TJVm2L)65s z2R*9GTs$NnuTtF*XLt4cT-Si53+7w>xo5a<*TFdzcP<&mpM7!GLF)aEKS}=ctQTE> za#!>2WXru_Ke}Dq5BjxM`6_GdseY39Dc*a{?gx{Xu1{K!c;scj zlr5A47TjO|a?f%JSNj(y#b#vO7JK}vwPLfJK~% zLhqrUwoC0(x9@$rrj~2za?NRX`@fwz&9hi2&b(z~`n|?OlO`|NvY?qY`Q*}o4u#T5 zsp?U4I0BSv86`%rQN-<5h!U!>KQC!*$BeKX|ZXk4%7SvBjI4YKL?3 z4`@z0+afSyr|OipG|d?PY_Xz4McWvz3YL{t8O@%**|W8-c)@F_J2if{)@y1`Fs`^B zBxLedW{T3%9_0;Dr7?0!f6YGL{V>CR(eW9X`uDWOPA4C_+#+Xt`nr3J?X6D}E8A=T zv>02bzdJu8detMpyXuC&^4-32v1JL$beQbuWQgE4^G!S5RQ5}p`Rik`Mu&tmjddH2 zq-gQkIO_=3YsB1J=P^CH>~r?4oy#jmMIKna>W6&LGSg*R)0P+3%Rd$o zS#omcE#BgjJig2Ji@mv)*mwTK&H$Byy}MOS`Sz9vm{?WZIo-JXy79kT^*@aL`W$wa zJM2GF(XZ8YEkdQYFc3+>>8ogkTV>R zrkX(Pg{7*eJEX$Cm|grn@378B>xjOqO@7+%Bn;~MZXTNW`h?--{SnQ1A8nqk*!!&h z*K+TD-yin8jaY88^Zvmaw;onWQN#N|pBln~tncnwe8hEcNvPYVMJYFU%PX>fygA+{ zUVq_mb(cL?@#1Zj|*cUlVGtZry z{-oJ$ug4v^`$jVkea`dz{ibE_?^)kgGcBLEE;DdaX4k?13y--9Vh%kEB~D*t3gXI$ zIr?)KXTH^1!(@-Et^uc$u?I7&`U7Jjnj z&>5MH_ZRL}x}m#MBk0ovZY@i%)q!zYHTgFKQ(V3YtUYGla9U+@;i*Fz9P3}z{e1M% zu+l=|pX#xa03B8BcfV}Y=N`3i_BvE0zA-9rjZ*a4_pxyw?>(AQW|=H**0b%QPvot# zWB&YggJ`wkx(yx1ys)Bed*rQl_ zT$Mcf9%N@NY2k@Fp|WQC6X&-(?yO1N9b3FBMzDOx zns!6(MbN?Ljj!!Rrlmh$)5o+jqNM!HyRWkKukUADPy=Ome|<>dmi zBAxY^y+l>E_q4a<>MSyjkH24dxnzc1*!zrk-zM4{N9>3)TIYVp-L^cVNiOn^u4nS1 zJ%6P--*3FX|5#by&6}LNYZSgp-qzFD-E^_lP;J*`(O-92&9`SiTYtT$Tebf8`#lFr zbgyq`%oXuJpKcRWAn|RAui8_=|JUT^q(y)?Yr?|VO{_1hi(6VZ?~=Dz9xFi%;Pr_RTip!xyQcq^TWod7@!==K_4D_-WiQ+!+pc`ndj8oCO^0)5?B*1EboOir z=ls6Md2jNLimwuXr(USH*!0WU_1C|i#f#lrN?fnaj7gQ#XjEy{5nfdJXpYQ!xo}&* zGn2RP|KuWfjm^z}?mzR4`*U8^*)R7w_x)h%rvz1#V+&j-pPZt3?oWY*PoiUf7(+f+ zL;hwqhn3Qcd6k|n)9};BkDA@C?VeJb;{?_lZQjg!(tTaZ=|6jmy>4$# z?G^Pm&W@DupV|APav|%KnaR#uFUrcEzj@r&u=-tD^d9{!s~8u1MhZK-%ywC=d+jWz zvqDQt(6lvNlFdhUZ9bd4MnTLbX|+MX(X7Q%PRl;_Su_PoF11ctS$|AmxlKoBZhV&G zf+=o`()Ra1NUz!1H{()Lv2%()-$Xz24vQ(eFQ$C3n)sb7Rb*AfyS7_PZ-3V{FP~qO z*XKFO!zbajKeLE1U|r0kl`YUettrbS%<_;#f|zI8f=r%#eQUdW zdatw+ZYiKx)r=Gp_-49Pvj=s5SI6Zv&4cEh2rq6$^ zjt+SpaGZDUr#I{0PuTb2&l}w>H;W_kPOzSNYWjYjouhhV;qm3aW?hS(*1IU$;@c~S ziH!j|iWz=iyKLB;d{hielG&Bs+~=y%IKJb4){j3grIclFHtvgf5UQ}b#QPg;Ex;SL zCuO}itDa0u%Cm~A`=*)raOPasKbsN@?-tEE&-rv(^k=Sv8*O4YS*x^NoOHTlQ`bd} zJ*RR?Rld%2-*)tl)~3K2MjI})-Cp0a=W;`G#hnYeMyJ#HQd=LM)@|0jQ&;Ql?LOVa zGW(N-(Z3z;e>(mJyjZ$m3DdDAj_+zVt3}TJ%sQ$&bBfZnl~xyL7fHQ)?pt;1<^9_X ztCuaDH}UJ7*)9#=&GyHrvwi=i@pEVBGm92;)&sMd9z@45WYosG`dwWc)LPfHRm^LZ zc*!{vU+0dAmiJu}j!9gMdK?vhnUOJfzancG>-1S=nLc?;rbi3Hx^6o&DVqLJ_fwiZ z>t<}T^D)mKrR#sK|J9&5Z@0+1kn@)p9=EURIX`owwn(POdcGaW{*|vZ!>hks3eIDC zA3y&?{GVNq*9gb8O139D2lu^nclGJ2T`zG-CSCMztlP@ADJ{Ddi^>X*>^?8L|Fb_& zXX9auq@{`Kv+8)u9-dscyuY*TTH)tk+uHVQ;hy)ssYviL%QwRXZ{{54Ynzj?0bb5@qslW=UKn~GZxoc(Ih=N+ zoNqnv#q?7V8qxkX_pdrEdD5|0?FRF;U7jWD1fAQ*6#O-pryvx=$ z-3)ZoD{nlyFZrrWGv}A^SyN;l-#t-N>-A0WZpo9a>y@_sm8*SJ`FCgX&%3g}3XeXP zYcu_|LoH*OjZxc~PhY0g?N40$?Z(!uVJ&xySXj%j452`aU&<*FU}gH+B7uQ`6=(^fcY@ zxs`9&tH!uUG)iQe6(>ieTJ${U6&~4ZSI=1A^&=#=sc7Y;Uc=b&F)Tays8jMG3;*XbsXZyt?g?L= z1Kbm~MMZlotV$QZ!^tXV6c2u_KvqUnfGb^yh^|Kc{?K0N=&BgJ3hzS>xR(g zL$bOC`bstzOBVe+$N%7u^ZCaqFIVhpst!a>m(c6Q?o}sR?mtEBNoG3Hrt^410q#mAb z_c{IDxd{F0XRD3dPMe;I-s4iHwrRWUtNP+U-~XSNJk=wS8@RCV>(+T!IhzN8utLKi2!ox-zHQ+44PnWfxeF}$IZdOX~692Pw*eErk^-|Xps-v7UG zQTJ8r3oHMqY?tW1b2`qu4wv@*JMHj>N4@OmG;I-eo^9##rdMoDHh%Y`+kVdH@Ba$f zUvj4e!($4J2d9CtP-4WYu`7RBhM$kv$?6X_9PP5_3(B#8k!dN(fd{1~&DNhxSaQ{xIJN6ibR^CmHS>8s7pm7RGs zsNh&a>Dy1P3pQ>$_Tt{{$}I=$oF$iaTxjRr6gl}#Pm<}m)J>r+w;6?QTu6GybZYf0 z_2`O2VTN~D_LNF&U2!*FOeMNVEF{|1LD*-?wf7!^YmBEs25Yoh(7ZMyBX z{f2U#%Ga)b_53O&eoV%|%I|#sk(Aner?e!Q zGxWa)9N_1k<6t6KT-NY*Pv72NS5NOV)_Yby@^RcT!{4(%bcz2p+m3aTd=_4UTh^8D z-gxz6lYt&p-FB`Sfy4*1*S8mdELvNo#N1FDBQd(!S)?f(ucL>&~rP zx~yQ@DanT4CYlSyCVY2otJ7dnTkcSN=;Y1ocj}nV&Qvq84tjO6f~i%=EseA9w&l|P zo{OKKH0!#%>rP>IX`b;r@WYqlH2d10)wgF$J4ZNj8!a-^=%WKKJ{_w^^|_7fbg>C{AgZ64IR;9QxEZyJPmm#HR(P`;=29 zr_K71binTAjt%NO4@GxxTBgyR^Xp~#j5{_fAKu)ox_IvAs_&xTlG^ue+7a!W$+P%? z;`;*`eq z`{p>6`flNj6|qWN;^Gz_ux_#bL|@H0uh{Nac=0S~nYl`@XUC#W|0rfJ@U6X^!E2a);KJFc zkaZ;os`<*k?mpJVb!}Bu%G!ex1^2?%HC&6huB7TG#pr8Z{6r|=sP7luuL2@V)Lx%0 z*`A=bzjB_@u3j^V(Es=Uu3I}-R@ncU$+EQ@<{p+)E?%?Q!}{<&iBCBS=UMJ*RNYMa zV|li)eMi$xQK`F=LJn3rdrWrND8j|1*>$b#%g2UuTrR< zmEi0K-+6aK8T@AM-Y8}eBr7y`Zm<_qV8&Zc-&q#VQ@QeH`O228dsUY$KS9G#wWmzkCan?i+M%uMmij!9NPhQH{Qir;qLu&GoxSQmU&$+amcWagqsONex~w$) zt5;O_XUgty`=e5(xQZZ55`Mukz2urDe z<(fezTF!p0d>0}!Hm0a|WE_$(SeB^M$=kYyOSRX-D`n%9D<9AQdwSsCXW7r&=Pfo< z-jzFXGvAf@dD~JiiQP3f>VCTC-7DdU*I5xWH}NYuEWM(VbnffU^QMvkn$CWlQ;t=h zKhe=~p~AnjwVK(pW8o*wWp^6Ql@6G*9@rksD$sNBa-wbJ8}HUP8jIya*5*Ebxjl1L z$IL4mIbXjq;nInCuVLA!b-!TSN=8Q?<@;QmL0dnadv-88dO5>ayEB*Pu9&jOzfGBDFxQheJK@koIK5YlS7d51WX!ChU23 z`Da&s>E35QUnU=V*zmdd$=3tVG8V+gZMbRCc1+1F@j^#yu29c+e%*;F{YI;9&3gY^ zHFR0u*XPGxdnsO9FqMJbB|M;O;h`B>j4J{%wi(rZ&gcDea_jTItp9xFp9P-TH?!`A z=ArF+ey>*kJuaj4^@Cp4s_7>6TF2LlwoWhioZkBLv+=usAG(ePd&hGItN{w1XGsKEE{qtdqwD^>})zseI&l}lQm9l1PUMppBdJ{`&6S6Vu* z&Ba|wub(^jxNmv%`cjk86T6~FlV{$}zZN7|d&_bC3R=8dEL3gMvN9Pt*IWAESGawC zk$HHRp#az8tFyjI*5vMcbXolQpY!u&Dr#>OMfC+-xvzZm#Pa!KVxPJ9N$FMA|CBIU zl6vf&$j?>jHLn|Xemddw;EvHTLGx`>LONaxdOi78dH87d(aH9|yZ;=!|98^;Kkl=x zX#bkdIaSxp;+S)j>*1?s#jaXB^Y*Qpx%1yi+38Fqzk0!&uqy0fgqWrJ58LBHeUF=$@BK5K4l!E5wnk`BD_bq$RK5JX5 zgnQa%Nlmw!%RW*KCO4C!=4{oNx;$@lS$+^#t^F0-%|RN`tE~2OXo==zTP*QNezos@ zhHv+}-H$yPEMnawk~=&*L?&snh$bxNT$WyE@Z^|KpUkH$h56+sJLevCN#bSw z^W|siH#n?!&~2F>ZvS*orB4Ox%o7`K7Jb^|{DtlQmMM-uR=o_cc2yF-b>yNO2e-$u z#oy$Ll=7KQWvPg5S|Qcp+~%%pez zw959J)s<@-&(7N9!;|Hpee~m0_k8Iumlnv0n`J8GNq5Y97s653eBXKUIgQko$VW@x zWOk*OS*y#drhR6PDqj*9`0LQqq$57r3evjiE0tgI?&O`qxa&^`*K*la{LwPyn#Gf= zZk?Nu^U(U)l)~-m#~N>b?5VS7-+R=gb$#6XpC2wpzcK4vf74)k%O-W3_>^sK$=hc= zTp3U%8!7VePv1;alf!e|`};i#&!3%t_k(u*#o)f`HP`O^eP?<)-F<^p=Cszj**ktm zF0s+FsV-{jKJ@%=+q0?8RTg{93vy)E>Gy0>ddsx=vBMjq?!S_cmrwj#-4vB`(ed%N zd3kSk*vMyo)qQ)jeTDzD8~jl|_YQ4K-+lk^XW^J@C9GD#ca^)Q8CXv^ESGEgJo)(4 z^unZE$332P;$5Em=fA~miBA@bJI(vLq@3G(bwKUmq&la4 zd^h@AmCIXXm|R6IMBc=F{;3~Ze92b*Z@m3Mo4PYUUiCfx*Yn)o`uXaov)-+3=}->z z*!8N@>aI|mV6sU6Ilm6YMBm>AA4_(zO;nVOUFG|A-$zCR$+n6EmEOmE^%z^r`wC?W zeN|nhST)&BEKM_=;-vA@m+`|gh96<}F8(*}RzK)7EEOu4zl2q^cxI98_wBvQnf@+K zOYRnMK5}E#nytqYdlg$7wk>-XP`uL2q48-^V~U63f@QJMPm8=o|N9oswp5kMHJtq2 z{)tbLRIi^}vy#)B?LTg3&0lP&^15UG+rUK{^6?Ae_AQV&`)zah5%;zqD-@m@-^&Vr zVRZPp3zxaX>X$uECOMxPs-v2_`3`ezdbHvElxr7%3ft}8y{u4nlKYmd8~>b^M6z6a z9lm9y>bBx_#ual9T7OD9n5Z`6oycs__Pc%GBZGntm53EKUb^zq!%E}IE@k_@Y9=;c z=FGmdVf)My51s2yo5PkY7yS9o@OV5=&4-f4OfiK+4~;&*`KUR6t~*=dlEeiwtL=6L zZzwQPb!>dL_;`=Azy8GLeUI1fJbX@phdpPyp#GDeGS*q|_T4j#uG*I^E)lh4tBd3X z_x@EK8v-|MnN!qSG|PnNN91t}t1o|KYLs%=L(Yi=2P_NvTjDooI@=a!%Z|hIZdbUM zKa1Sv{-)h_b=i`FF45EccJqRrR0J#iOCu&rdZ+B?U$XI_j%<|mn@;uRO}=7*vo^?7 zZu}>;ROZ&+k8op4m4DBtN3l*FJL;M&AKP7rvBQ2!sfc$N}r>q zWZs?djY*vAc4p7Zj@JzGrYZ6P*A}g1f32~essC@!ho1)?_S+q=sW|mEeErAs)>bng z`%9VKt~;fCA;($aWmLfG*ats$pO-im-m-6fQ*>>UciW$i5<*w>M^^8?GI|FrW?GVkEE$+G$t zdTcuHUOCOz#h0v#wqzKd`t$$IUeEPwBWKc&BOJiaruvGZ!P|>QuFl9-oED9cAX2#B}V8td@K{W;c6I!dgkz_3caS-`hUv zG40y+Rax@Gdj1)F(usj0{2QM{y=Fgq<@@5st=D*B`@c6Hn#HelfS>gM|8DjLTkW?-y{rZAT%CxZt%O&X)bVo$G^y zVia_zq0gEMbYVH)=aEdIXmn= z{8`Ots=eW?;NR5KYxFgysJ>=XHT`SO_;oe!{C|`E3qo>!wR~s4vM%t(n*?!>=;NO^ zr+ZA@`8C>QQi^^@>(d?btKHu#8M17fdfcOX&XqUcZCf)0o!RDRY>~UYPP4h|#0pQ( zjZ0PATh4TOJPR~b+|ef^bNpBk>yF#^1i5-=W@)I!yw8t_o15&fwX5iCVeP42z9nV> z=e2HaIVd{q*=wn<9t-12?i_LOJpAD*-`5vY6s#}IswUl_ z7x+0sWuIN*669VoPw=SNMBWoj*VT)XC!SJTtM;)P%2XFF%vsb#yc9YCVDa$DQW3-TTcQORBdu zKmPT0`;=VQS*cyCT)NuI->EKLH{(uNNAkf1RW5QKVG3EzFL>@g?TTRxW)7d(nRnye z{mE*ae|J3mQNR9XP1cNkD}Ma=sQdqoyq>|yVCm*_O$$s{Ufl7*!cO0fqt8}theKe< zjG%?u?INAGw74_{jg6z2o>o}S2mn%9A!}>YruV_B&pVXsxq=COqg!!LubC6-5 z+fyBg35VO%-^~&-_B@ZBPF8MlKI-AOc$Ur5j<9ErPiyUOg|^pQKWX_jugP5Y z*>Cp#1CBqYb68G%FaB6@srGZmhios5(yWy8q86QbGE+6z`bO#}-|ib;t8OXH*ZTKS zzS{0Td(-a3)-r(}%QNp)BE7cUQ*J%P-oBM}<#i5A*AB@bj#XMhP7Dhmn8T_C$+UmB{H<2Z=w922v5Hd!}^Prm+d~{wI&NEOmjuPl?Qz$qgn7hPOvnO!NlZ(^kHhLH;d$vDHsP19bXgx7Y=lI3x zCr%%>l5RX{6u~xGa~t#jv-RJ3{~!Kukz7`1^6yPx($>3*W^Do0XHpU_9eBFW{hg}1 z{=5f&qV?{@1WXk^v&Ye2r2MtmMA4}$E&lzP(H$;+X4a%Fc`uU>I?Yp*%}Li*i}f|l zR7ju0!I5d;RQ#ppRBQah-?m{1sG@tE!D-!vV|`!T*Gje>*id}Mw>hkB z_C4jEL)M;wQBAKapFDi^H2YGz>d}6qpYhIms?MSx&(@V};b=V3-rZes9C^yk^jlvJ(@~Wj~sXCQ0`Zeb(tU3)$H-X`mBT3Oqt^!n;$q!J!ofo zz#hx+V$D{^PK#x?pYa$b_Nbl=oHjLh(HgHqijuw@jvXHp6;%}{IQ4Fu(L5o*?m?aV z*EJib&2S4@bMEQkg?-#lir(<4Xs%egYybPp%Nwj%1UL;hJ@#apDD-ebghsI1WyR!W zJ1&2D|1LpEqx$qdnH#n@6U|wlJx^b8TJ~4S#CX$~_1|qgI|F2ldlN;9Itz16O__eHPBsGiU_?b*+^wkkwyPe==P@mTUeW6Q$3CRffs_;ua-j=Q$l!i9A^AN+cp zf8$>ooBMM*f+f~O=8B0Dv^ucFBZ9GUI>|@y1;r$)4{JAxq(hb zj79G@3O8Pz<(T5~LB#clce9*K>(wo>=3>0798y@F1WtQs9?j@qr1ng1uBejMC&za) zUvO-7NpqF0FC;OWm{Ql?Rd6AP-zNGoSOE)QQ^uOyk;Z?__zz*dkzZAhv zBL&TXNQFswIAPiL68yKp+{GbcqG&E-5dzxLQ4 zjS0?4&fRHScDIUj91^%TZ_U9Drt(=gYASnc<_JulBw!k8wQGiEuVUrNUr)Qf<~7d| z`=J$>AyC(lcqHp}=FxX$M?i=IDKjZC4^wsrhJ9zQTvNv5PmKGd&u~A)YEzj(_!!F)6r&xlEq|I7_`d?M5 zYX0eo9OA)kv9b&${Ja8zvNxmk@2_X^Lq1|ojF@dDEE%y zdhn0QC{E$nHyfTh9{Hk$=|-7ylXO^uj-^B8kcyh1;19W9F-jx^0- z*&NdIx$@wQtqSkVk9aITb7SfWNkzxk)2^tAc}=QuaVZaw5c+NnTMOXcKmVqJo9dnu zLb^&~{bv?OyT}PKrAow#J87PnwMSl~ML~97di8UIvs22qPb|A((A)2^f9sto?<4e? z((el1-FEz%a+d`!-}d)~nv>Tmn#>HH&F8~;vf%m!4aP*@M6V?CfG4a=e7q)3(Ajot zGQXbaWaA%PYk79~6d4>&C}xyABp?vAXpQuKWjzP!4Nk!kzI-#E*l^EWuv2m7f%rd9 zXO)!u%&3}TCb9h39?sbl>>QI7UH`A9TXYJ_{J9e4SNeW#bUE4$w%q(*>X4y4NnRkFg#QWmp z#WI!hp30M++>Jfmq1w-}@W!2nb7IdE3Oe6zcwBqyv;M!ODKB)?C)>N}DHq;r;Cx)} z{zp34_1(pXO8u|b>2$M)w?Ei-Sd%ZWp>W&(zccI9jr=Ifa^_djEUhPcm*~PP; zFUdN4?{1*Y-Had1Sh;a5koEz1Xs5Xgt zukM2&@5OH!S?78LEof1F${6g##e7Oc*+TW}jF>*oNv^CyNfJlrD`_ublYF1=FQw^q zOHh}wNJZt;L?@F;|65eP1)LF{>2XZ3I3enKOzP3pmY0i_^Y-suV%t{vyQy=FMWye~ z856dubTYI$xb@Gyvg38*vm*;WYpl90*{b+yt@I3Ed#S^5L5}Ce5-ltC>(;I}3|d^| zq~Ot-$0?755kiGtu#wcP4^=k!->7d?Obc+S@=rc^@w;^UNVw_7g-$&p5y0NP{LgFM|9@gxN;y96YqMZz;Bz^D z*ly(#n;wP7&2E`nIGT$41Vz3o^8IjT{BXGL)7}qH<+go(z+kcEw{hi}U41VV8IFWMXs}Q(lQ<3(wPi6U&g}WJc)NEjqdsA=cmc&-P zfvvCDx-sN2ukj6+ibV&-Z$$g%DE$pw@+WFS*GK!D>a%x$iY`16v*&(rsj!#d!(GSk z?ny5y;kotcdHq&Z_Wl`~K_wz_lSPl%T>8|tMd2%7iPMRmSm#-m7bLgMG{~7SxkX@N zR^mw`!KDg2YzwCg)-KckRL-iTUCMcRx<`{&V^N6YUh^r5A(mEK{AP5N^9^Bgev306LkgaJS1JADAyKDpN z`+a+ttm9Jq+%suf;^P#dQMAJ_?rDX zE1q%1W-bvs()-}u|ES>qhodk3oU-__=IPwSt(D#DO+K%9>8!GY!)ozlm$S>3#0Ukq zZ)DR}YHi7FsoMC^{ulqkT=rK>Q~!Q-DBSE&|3q`iVIJ1}U#6+ank9=?uvSKI`dgY( zWp!{~y352D`a-YR4jrF4w}|Hz@6s(V;u6-TMsGi%XBaFRYWi?n>_T(VSKqbe{<5Dx zaanimdx47^ZB};Xs(qa(b5Nvdm&OMzr8zEf{5LWku5`XylJd98{o?tX&-iMWM9z_$ zc)8`@*M{o7i~oHTY|f87qrPU{wii(odR5{oQbc&lqu*QzE8g_e^uAv+A6=d-|9HFY>-*~+!(Qw?cAd|@e2VqK z$;+19KDgQMpu#O- z@a~6d(6pA$CBHo%*v#GN-S_3$wAquJ9wzNd-qAl?JBBG?kY`J6n z&r;^oONXDFhBhT^K{gRHms*&7ma=VH@s8ulgNX3rZYht-0alAk-)i}081 zVm@rcIpvbY`xBPE+ay(2u2Ees*j6k*du6Zd&A=^-*IK<`b(=JwLo!yZ}ol%)TRHJuaQy4l?w}fUCnPQvL7tjt+2;n z#caNty@f|U?^CcheiJEtKUVpfD35NMS^Dp%vPA+qVZ}_0A1hsN^G-R>vXA@4iUqB2 zwsi=(Oq{5+Ia{gl{e{g!fyP!GYZOZ7P3_O%d1bVyi%C-C*NUc-J-Z|)f4TPFYFkq8 zUu)5QJv-DctGHh0yD@j^4&58Gw$C`P(|l{Q$oz@_wy2+p`ZD=Q*}K3;f=e3S3%&GE zPVahrTy*tWIm5Lp&pn%S%zBBZ$gxS^bbrtH^|*Rt(soZlj}@#-I-6f;u4>x%{Y0!= z$V45txWg9%T|N5dR=0DRMoybESHdfJqO1GD>{Y1;O#A+^ovG=ZCK>E`N=2}=e}(Gb zG6$=pj~~tPa`w`l#r4(GeVSk>$E`i-wvokqYP@y?haByx-I02}ZSvFPGpXLu_aAL2 zFmZm?k^OzgxrI`_Q@YGj=S8!7IrU+qL&yTxC4Q6A-x>07 z*7zF+u34q~>&~U6wsGGj7SEK)u6gycyz!?^;QM8ZAMIJ!p=mTX<&CG~{L;OI)Jeew7{n^*w*)RpDF7jlO)I?&;AX%+~6j zy^5~=MollDPFXl%$05Tr%!#IQo6I7D^d$D3`q6oCZfa5Pjh~4*&+R!+9J;v2aLzH| zAjylC8^m;Xf35!YeB!_K{uSl3naf@5I(l5iI1I~f1f7Zqmf`#O`*h8o>rTb;`5zYq z+6gG^Eq|QaA;_b)#BD{-r8JghPX!ZHkDFb)QP|NqL+Qzvh0GuRA5ym8!}|ZeC_^%L zgk0Y(=Ax-QkunCGq_Vx8J}kcK+jqA~g865hJwy8k3IA!FYu`7gzN`KBctt|bZ5xH6 zsV+;H4dWWlR&IH_q{aWEqL{>iIGNVB+w+Tf+mEos_BJKo%(J}V^VjdF+@m;0%glK}_soLH z7uTDVMJt5Qthjmky^N2lo5&6B&Rri~I0oN2@aM;jllzYB3WaY~HVdt|mfXdmsEcYndJ|`lQsli|=zo^w*MFhaB6=>y!6B z`1}4{MrrqamLlFr*C$#*e4?zZ#i4?1M|a6f%sF&Leab~69jk5WeY5vG`n%+)nCaTv zi=IuZF-zY1dZvN%8WsD$Ka5wsoK$i>*viAqsJ5z0{o#7s$%~D*th9`>OZ@g?%02!! zy$*THZ>(DuG%N3B(5y*C8+=|H_vn1gcJF9>v{=*8;#8)up!b{V-n-%*t*)l5(Q5@a zORY0He%aq3)j6K+*Ob7u?zUTR-2Z-JMQ1GU_Tyjb9z6Rd`pQ?~c-P~_;xBF_T;tr? zHzi-^@?XPWiyZ!a>eKRG)@`|ThN5xDR`;q2w;d9tOCpt|d4)X<`nd7BiAkm`WIc$EEM3&o_K(BQGZBiZ_q56 z%Ni}Bk5_2A*^BXfvi`lY!Xk%OP62QHO+TN~AD z#dImccDYMWveR7Mx6ZNU{Y>8sA1+Bavaw(O`;3*c$N3J{GTr{J)bgI$V@kstnM)Z* zju$_9DipsT6tJjCHpEzQ>EX(_l zemD=eJ4f{dAw!LpkQI8tA;D8}Im)GDlmna=zY^Lgd%^C&re(KXeI~6qI%h}ui42ad zYL5)ngKM-V-aN3oA>ta#+s-h7f;ac$A1`&Q@HFdM6jM~b+3}{38FO7hhuY+C)qA{5 zmN~h3&ywDBqGYvfgySbRTZuEdhxoIf$32TM%`2P)@>O=vT)e(oPW<_rZQ&U! zKWMklH9xY@*^ldny4d-1H`nLijEPa~=jtjtw(eF!RO>#mEyoOJ%0FITy++hW`(%RF z62l$3Z`NNIF}|?tkPpwcmMz(uVx~N*KdTzvN_~wHKEw5r=a-k^ijJH&8I$)&1f;Th z1x9%Osd4<1t8znbUgVT>KIf*r`8G|5y-HLvC25t`mDOD#T3za@S?U6@%XZ8(jA6^G zuW=6b`o{A{@4d#P#O*s11I6FG&zn%^RJ(~~yZU?K@b`KdY3fJj>%P#>e|dy$=Jh8} zg_emn9*BB#(7I$+z)a<~MDP8#0_S9Pas8U>v_tT`?5UQoV)v~hzV2{((9i0mAvM!8 z)YZas#dbc;<00N92hNLBh6%;xf5*XHj z^}1K{qt*J)W&HmudGKw=zN7B_tJFEBPl)c!6J2V+Vr%92q^e(>$*k|yOTj5K59W66 zl28A-lyPzAUdJ_6OLQ-OZu_uWHtpKOe|L>TsyQz^mw9+4Z{uK(ew!E{oF(#t)3S)c z<=?uu_3Ifu+8fvx9{aX0NSVp%NZ@gmsVct$4K)5mskz!QoN0639>VoCk>$fe<`0K! zrwBw!ewKYd$8e3>(&h|Qqx&CN1KMBN)%rhB77!^qBK|wtJ;M5kLcmF-?+d~ND|ffa z>vyIq)vYR6dHAQ;=f%dGF0CkCQZZNaUTVqu3*mjM&#$Yj{S$uYT%7VVskK^D^aQU> zSgRz~S#mRZQR=Uc##6R*yl(ha)c$SS!E0OW7A#SlDYftIieF8izV|&kWEkF6a#QJ^ z^^s7A^+ILp3DygqOLZre%ek-cFkSdb^=*N(kzA5nsgR`NqXQgWSxu&>n;*H zbIOv#`2y?0(k1GG!9F|wt~QU^yX&Btx5DH@4*PEkto#0>*FCCLLgtWn)=h=4KW={e zeOH3tCiBI5YnEA4vkjLn?Pk2s$B|swg3(v8K*Q?}l@yY5E0t*3(?)83e5HOb#A6u-}tFkZb{_HL>B z$3IgpxbLcM_ilQ^QYkJFx477Isya`!zlM<~=eOI9cGhz|-#nf7P}#Gm(TuI^ZC_1{ zQcc>9+?%}BHTM^KpU&Hw_PpxX+j)~e7YFejd3)f?pN`GX&qvx>CI0^;6*WP>+-FtS z<;THAGc)t=8NVqzGE*Vjaf0MBNm(ue-p6wyVdHY{PkIWujK$q^!g-EQN)-DTdgS_pF1eemUH2=Fcqv_zl1`hk z&?#oi5`D9l9m+PEiAfWu>mHlp5j{ySuVAY3vOoD53@rjGN*DVRQ;yyE_^GI4&z}F0 zl?4Jl6VD|tO6HpQ;IE^$0;6N)jy*jECbci-)UgMCR$S0qdBJ5RXo6X`;lI6&A#2M8 z{+7LSJ~!X+KN7f7*2$*jfQQo=evLCT9vyD-u98vCSUfSR?^a`-#Ok~w8Gm>2-?9*4 zv+RFlugUsr!-Ar7{Hy+RB)2R43j8wN;>dNbO#(YaCeBsQXFIa;;55~jzTE+=IkJz$ z&v%Af|1sp*_w=Rz{KsXDv-9;=ICbi(-^lIfRNhxH!&~gE&^;f|bBb&nzNT(hzA^3c z_&>8nQSpZ2zFn+JXV1q?XjZ7%%XU@y8QcHa+9AOcr?DEUui7m6urT5Gzow&?g?}k3 zeG__Vd#lkZ%qQpIw{=T@{bdUD+H+%K-7JG`3pfn!e7kaX&cibQk9(ZN+Wy{^YIij? z-MQvt#h>4{QBsRmdWNdZXsDSz)ArwtcX|H5p0bro85*CxnBycc(=YSa?dVtPY&SX0 z%(Z9zSxGi@xF{{6%oDS7SatgLF6&8sEqE?wl; zz3Hgz|1e^6eR=nMwL@zU*u@Fe9)EjQSBW$2tn#0JZ>#;uUpFNO$|=k1cjntVU;kWp zJNW;JfISgH=8bRPnx-z!Ok4iKNpRiulCyn}`NYmk(er!un;ek2!H~v^yOfq6IPdc|$?r_5=#fL$frbh z-E+t!)#TjI!m^yVHy8toVmzL{sP0o-l;R-S=+yghR^^$f_U5k!OPyE83p_f}-mjT7 z<lAVW4xGg zY1iT(Uo`Kowhm#BE1R)bwN&=7yJ@Xx;7!Hqvm0(I=r2e+l=t3XbTnMu2U!A>5z4O$Sir5R%AIxQ6 z#-9JOytrup;<_T2@4Nd>er|JWn#Ou4a@`|c^{-P>ix0)_a{j@&NX#bk%ne=UPm5At zS6`X=z(szu@5HZHb+1i%;p%zIE$`nKp-7*ZfB#DE=E%BMxOtb$eDfRX!e#$>|JA0L zWj@HyKDFBRSE$k!*;U(C9OpcF;M-H)yC?fT{gg};eHnW^z{+L+!qLor@wv1h~J& zukTotT4v*Zwe4S-?}}whCQHdOU6k9nFEjA3Y308u8QV;>F3DLI#ZQ_xEjQ1wUuAFf z#PeEh<+_{tL>4YHVEnJ_edFzi*?os(Hr8!zo0(R%?a9+uykCnNYwcPyk3I_*U!wK- z>nEmAu@HM}w>rg(n^gASUf|Eu*kO_HVLs^v>(~Dq7uTDp{n9P_(*Zy>GkBk3zLFey&UH_xqEdZ3|iKZkBp#na!O~$FHoJz@(|YM1s@w zJB`N7x_|Fo=jDf?3{6J#p`MRo{B2I;p~?_a#Q4^)#19B(>pKTa1@^GpypgM z?bRX$>)!qQ)aJ5WkP>XHmH0nRBVc#K9El@(ioTAUB)94;2<}+eemDA*a%&b#-sQ{R zS$DA(Zf){ko?zrA*3!+WtF>bK2Hu?SwsCJfS9@I4(G+W{+p1KyppW;a<)xU1*QJwo zrWaPZymzeG?HcZ#b^aXBStlxV`rP*Ur)~Zg~5?P+0pbnRdAuZR0CnbOTEbL;r!NNAF^zOoWkwp_D z=jna8eZtQDTz$RQzsd#X(bHabT;opBoZ#vr-l=r%h54+^#T!j$lz9isKfc{_mTP~9 z&pf}*=EUE>bzgmEOF3C$x9~noo1ReGq^CD~?pf!(*ZWzr&&4i3FjV17=ew;g=a}aI zUwnRI+Jo-<`=tX97k6v3rFkE|{r|1*=lx#|r8g(edieMD_8WhK=g|A2z!4 zt7bl*Q0tP`oT++7=U;@-;~V?VSS_44KfqMKAeR67JQLB5T}tM154TNV$;zB?YQg^x z%0D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

=i517!~&0gqZ(5)3WPQloIpX(}Fq1 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֩ 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�QMAzV>j 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 be|EW(wPHU%=>KG3U|{fc^>bP0l+XkKlz%iz literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_ps2_m80.png b/src/qt/assets/systemicons/ibm_ps2_m80.png new file mode 100644 index 0000000000000000000000000000000000000000..9df02adffc37ad3ab68e9eab35a115ae1ace0887 GIT binary patch literal 265107 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%0AAne=Dl$%D2hd%0J6azz};%-Xljr$_7DtE=2S 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

70;?w&P`=^0i(MH2PHL6o)u>DV*KGVPjV0 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�+5GzJLG>%L!qnnfW_L^t)|j5Nx#RZlcUx=A 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

+Uz-zpYiJsw(4_o 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%0Dj9d9|o@>(0`z6VLpuovIf#`}woX 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 To-SixU|{fc^>bP0l+XkKXaAHc literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_psvp_p60.png b/src/qt/assets/systemicons/ibm_psvp_p60.png new file mode 100644 index 0000000000000000000000000000000000000000..af5a95675ffcf1ae77ea8df69c011b61c7e5bf9d GIT binary patch literal 217113 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�+5GzJLG>%L!qnnfW_L^t)|j5Nx#RZlcUx=A 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

+Uz-zpYiJsw(4_o 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%0Dj9d9|o@>(0`z6VLpuovIf#`}woX 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 To-SixU|{fc^>bP0l+XkKXaAHc literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_xt_82.png b/src/qt/assets/systemicons/ibm_xt_82.png new file mode 100644 index 0000000000000000000000000000000000000000..4f398d468088aa499996656e04cdf03f946cf5fc GIT binary patch literal 295676 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ëM#e#+f2d1`1p5zETWUX;4jU#x{ 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

G{^W=X;Y3)zeg;wYN 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 z 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 HN@xNA@g3%h literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/ibm_xt_86.png b/src/qt/assets/systemicons/ibm_xt_86.png new file mode 100644 index 0000000000000000000000000000000000000000..4f398d468088aa499996656e04cdf03f946cf5fc GIT binary patch literal 295676 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ëM#e#+f2d1`1p5zETWUX;4jU#x{ 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

G{^W=X;Y3)zeg;wYN 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 z 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 HN@xNA@g3%h literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/olivetti_m19.png b/src/qt/assets/systemicons/olivetti_m19.png new file mode 100644 index 0000000000000000000000000000000000000000..766e335f72d22b07e92f6b6a03e858a340554a1f GIT binary patch literal 262763 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

&@HydAa3NMb`UAd(@WSQAl@Q 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⁣1bF^yJsbrADy{k*CC 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�uJcHEeV>zVEjyaR+)P6-ms>| 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 ZmZ4vAI&eEn9RH^_{jS&_iwkT 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%0DG1gO$DL%cf#?37muzH49)Y)f~Wq+*} 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/olivetti_m24.png b/src/qt/assets/systemicons/olivetti_m24.png new file mode 100644 index 0000000000000000000000000000000000000000..e48356c32d8dee63dcf41854c7bb447e50da3465 GIT binary patch literal 209215 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelaj;->wRYC<#g|S12gTPs_|n zRVb+}NL5I!$V_8ksJOLtPUbWj%f6QXpG9g}-kmPovCrIm#^dwpCH+%^R71=C&rk94 zI;nhUt_nl5BuCrL|9|6;|9LF`zrbu)R+5(K_Bp!$kBZHH|7Yo~=lcu)Kk5B`{(Swv zy}#b>`dM|bSo4FijlRkMx}4&<`+t9ltCxRd_x}H`i@(LM|BU|i@z9O;UqAl+b>{ts zSL@BI=F8mqoU;2K{~mL$e>>kj`uyH>{`{R+KjmgUpX>PI{nB5L%g?O2cjn~npsw?4 zj|df?x_$c%cX7Yo@tRH7t$jA_e0EsckMn!JnM}U(C+j;KfBm$3Q2S~9|7Z7f*QM~v zf2ujby1KvZhmZP;?cA}~e@^cFEg!B`e@sBmII)QB%#}ZXPFlTR^?y%?{mj4H|JN?d z|2OsL|F>V{%L|@~rx))p-nM@K-$&Vhi)~-H+50Qk|1H_S``sn|>xZu=|Jg41_0QLo z|G6$_zTH0b=ZVtuHC5-rIt;qyjNQ(>Ut$-$v;J|fOAOEV7pzS^*{aV|9*3Oe!_e1=C9dnC8md; zFyM*wtN*0O^XT01{!6hB&aaREAN+(}XU03DaJ3t6EAk8{{eBpIFvgkv-i#kV9a^gb1Hy_m&_LZ)=vD~;w-scOm@Qx{elBUc{IFecOwaRS1=DU5@ z)&Iw^bs4&FS&H~vb~+wrxNHWmV%W!p^PIXgm(KB8wQ}h^=dd?VV>TJ=o$g?=Y*Oc$ zsHm5wS0aMXZoLu}{dU<;u>*gubleV$&ffd^!nwKD^WSYPPW&P0CX@Lj&`mb?OXu%1 z7MIU#K4W$JP1;XUu@hT9X{}zj?N^y}_^ra_bIWg*ZokXFuIx~!x@^<`E0_KLZ@RU0 z)z7re`=j2yU;8X>b)rFWu2|*e<5@9!Pm8(LEj%|#ihaJA_)&@b!G$=p%~y}UNVQa+ zJ@H6K*AvOqNrlrUAKj2}=iKtg`*OY?E~?)+Tk+lh?PZ_sqtBfv`7b`r*ywJ)&iC-$ ze~)E(+azl7_Cv(V8XG$)+!_A{_Hy-oYdE4$Y zgJ65)*0nctRb#fXfCEyI=m}$@JBqJtdM>qdd}vN<_1q8O zUR58D(t`ruE3)C5!7t4dW-=<4CkjU@Zd}uFAY!HOhZF00^70MDHy6tG2pAZK+evu) z?VxG=6dK`p~6dTrYc>yO)*PuP7s<~q|x?#_nvL*YOFOg!8; zqxER^vwJLDhFioY>}+V)W7sP<{W_E0R9idwO zuSB!2maIJGueN$-=F%ttVD_ZAYO=&vuA*R{#t)GWXf&fp4ijRzCu7D}i?T;mDdymu_ zSSy&fSl;ewStxpUjVbfNdux>1zA-y91s|4+c9-w*t$M-Yy-icpo$-pH!4r;IbLTuf zpJuQ3<-E*`*jxF0Uw-vh%B+|;SumS(v8P3Wb`Rli+7!4T<)z}T;bf} zdN4+)TEW&w`u!sIBPtRG9uh~zZu3#_Fax3ZOX8t+dXyecHl|N1%u@tuQ z;JjA5W3O>fTZRfh^M%5sziBF>F1rqNMshkz=+-s!Nf@a)G1yC9@RoV`+(l;ROGb@L z%qKFX?y;_$Gez&>!J`lC6JAfBUyxafn>o~0?zcH$78AL1@oBW)oudwi0=$oMnrhGa+#K5R(mP2(c(IW8kLg0% zRYv(uxp|fXEg|=smuj`xD*vu>RlKooiQTq8{Prx7G0Io6ZMl!9?fY#Zv8&#OO*s0x zmQ?PsP3$((+ne*vIIp&ee7zni>5=bU#lI~y@J&NXLw{>l^~n$H?f!=*E3Uqzy;1U~ zs0GVex3c?FoR@v!>t?%=wEk*g=YoSvR%D7#Ii)&@Ev0Ny$9XU2D$cLo6Vxkw4~BgZ z7qQ&fI7R2fiptI_4Qn^uDVxvv=cA$A0+Y*$7CJhMj1*+g?%3{-&;5Eza%Zr{^FwS& zJ9~s98@#P7WLN%J#G>f@;XvxIT^zw5&G*P><+{r)Q02Mu33r5SWw9fxX@TE?ovml20^cY`U({TC z;ETicZyG(U{|>#kozR&1>0zvfZ3L&@g6)+?Lgj}GJ&XeCrbet^f8gw^ZS!(+xeAm z;@BrU*M>63Y--5+aHY`TdfAD>sS{pZRm@hLviRy(l@~H~#_u{^3&O(uZuVBsPy3dx zXPbX9OmITMQ+{vdtCN;rmZ)y|oaFSPK^|{4j9->* zMTEni@@oEUiRFi;Xy3Fq&skN@8c;E9?&e0hbq~a2?(46#Q<)%bt#Z&$d5Ym>34>}G z*@FC4N4)RnG##^bQQm!ZuDQ)L6TXu-HD)onCb}9&@GgHZ{9iSjp=td_$C=Y_O*WJ* zw*Sw6algu=IM*dkasd^AukXENn*DC-@!9hpRG;}OJ%2*k`kQa86xF4d9Ga8zC7r8s z-JXO5zdu?EkIK7+{+BM8`I#tl2h6=iIVG{5uyPF8Gjmg^%T8 zT4e_N{Dl)#84Rn}b262PIEA_VV6r{8Xu^m4HJ?75S@CW0skcX@Y#AzoU6jg6DMtI+nJ0y6Hn0{c#Ow}AIuL!K@%n1@l?D$rFXw&SG*h7L zYFLfg%4I?C*ti2rl@vXe9Xq9RPrAK9?-<|d!>1zbT3Iyr^vz&flXIXX_}JfxU4g2> zmn%zrdY81ierpQ1IemB13pIv2{@cP|o-^7Vle}R5@{+$V4?KLMH8Cwa=qp<>YeIVxA%^M~6~_q6Hdd9k;c zZtd_)jnWh~n=C(ZLSkfNL(qb29eebAz3()xIU~3J>NJI8ZJT>0hVH&s!zc4i#oH*X z|3m(vj))PH}pi@T%e)tMgCM!5raC%mtv2VPhC7yfdC zjtA@eiO1YZOPa5jga(-&TNm~6%Cct-Te#kOC#HJ7I+N3sx8&_)*Qx>qr-?FbJJ+Z* zu86(p;C944Ag-S0%E#kcN5y{||5d-*uJm)Z!_&C_YxR$%Eq)3Br7<(9$(y^y*3EA!&TQoi_XSiCI4tz^lpUm^ztRallD_m;8=nbNVx zSaGFkZejU@jT4`A3iL4SHRD!2qS2wbU{BZX4>L5(s!yCau*<75_RXBkM^nC?n^OJ$ z#uCAX`)ZTYzbs;|(KcwmlC?F(fb+KEve3QmzHcg7c%MwOu3+`Z_&F&(NIqubae0p2 zTKs3a<~WyhhaHtrs9&e}v4O)#pO2x@JvI7@sug=)-vn_{hj@>giT*zOe0a|Dncnl2 z44QrWNoVhZ&ckkZpOHR0PyTnUS6*|zyv}r4b;XwRh-F2k`kKzSUdKL8;Mio9 z_U8Jv+|)TOdv^M@r!Yw^zFXeT6WgAkk)IXbkdkq*?D{u__dPe47n-_@emW?(eS*_w z#s`n@`#m|l<9;~LzrF?KD{t-QKj3WkNaB2(%ai$qEawY$1cWI>d|JPH?MH>29uFrQ=TUZVE9?D7Od z$A`PitCn}JyQ`8Y@}h29%xrG1owfp>Mu#`>+J|()cBy_C~FxhUD#rl z#Ouj=-|C!CF5fdLJ%@8F%uEK`m=_=XxH{&WG4C2%2cCe;BVP^~pDMfKuGaJ|rlqz0 zK?CmwKI5voem;w`J$%z9DK|JwFrUJ*&~Js%;md~lYS{6X^*Gf0i@p%6=Db@tmq^Y8WCueVb38){zY|Eao>QIUAd@oL6bC4B6!w zc-d9dW2^VVCgpQ1B?mU;z1<>eb8#}G`)d_dv0AsE#(Xn(X&I=@P7*%YJI8g0;Ud3# z?VAsAPM`8|rGexeF{y}%cZ->GfRlV6;AQbjS zs;#Vg=f|CXTi!Bmm0Y6~BqG)Mh=N~mVrHt!R^b#yMD z*~h`g;ko**z|(fdP7R%cnC-iL*Y*@Jvfq!=`@hYGKS6fJly5>ao$gNfx-iU`nVH4p zM7Jr2pzE|PfeqL6&o#daT0Y^Yf7Z2skwKSywjYt6TmN!v;N55CnlmI`*7vQEcbcnO zVknfYtbA6>vfz=f;Hq`YwuH)UI3jQCy((=r>w4J(YMC;Q(*onwHzwVZRte`%UsZND zCd!-Rx`Y4Q^M@8poUoMf%3^j?V;=5_p6rv?TU?!OHaocc*gBz`2D;5E#ji|wZp`0l zw3p@h)5x2Xo!pX+?GRd{ugz0^ah}S&X7z>N{x-dCt$PrdmZy;9vq-yt)U&Zue*1UJyM%hngCoy5 zUp-WM>&sR2E~i6$>cSMEcO~~;Ps%-?_JgG|>PMF~&SPy5al{Qc_JxvDJv(_)`h zW(Ui1h-C#nJbP@nCx6#V#<}coRyTNa|76l%e6ZHz-ozj8bQaxe`*zFV-l4TK4n;3M z6!h@g&5P@~Zu^Bj)iX?PuaZ(!n-wp3FQaz)PTrPUqY9Oyfm^fNIsH~V4JoqlEctqQ zQP5A`iBh^xoHwy7;#I%;$aBf$ooio4+3ji1oS-89aHE-FSg5!~#^SSk)f@TqJh|`R zjWg9+zB@jdyZiRm_2~w?Uj5(mYN;4U@Z0X@D6J>f55&xmY4iUS<_pYTxnO^C<{wvf zk2g#CZtrnUyK4~C{AT`ceYN1OLk78etnA*GkFA+}BKT#4L2uujhGPfPyT9CuNEKUg zlE**o^O?8H_62@huHB?j7nVP-Vg9OJELQQy+CvaNh&-3$6na#7(rKd&(;gU$zMtK?=2gh4WBQ?o z+jiU!3co&0*=FvIB%MA0C5@9E2DKvW=4U9V1we`yF zZ3m+{L&dH%KT!FavgGHcU%wR`%YVl%jo+%}#(#WbPq6wLDVB-eF7@-ibzL_|v=or} zv&_pQL!2q>hkvKHz$s&Cn_X{2CT6xvE)lSM8t{3q+${s8Qz{wS&MT`9Ifl$p3R-4# zBv5Sf(w5>^by`_p4=Bykxx{GFQqaBKzFuP{cSinap)36hKhAXi;eK`BX4Z|(+lzD> z8@L!J+{)Wh-Iny_1^Xn)Z<-#r(?Tnn!4R;7rvgM++`@TXOoQ^; zS_HN@rmW)1P}0a=m1KH#@hPV>$Gz_Te$*b-x+LjJ%;hTq5=}*}7u{l=&ZWLp*T2Bl zyZzRzS2nxeXuDks&Jnw>aQ^qxJyxuHoY)VZa5?$mN#Lgo1`)}Rn(i(#yXd*bpet^7 z@{Z;+hpQfF2c%rtK7U?x^m>lMtVvCicdVEstJ1VH-#;ieNQGx>VeJa{3pW|JsJ-KS zvzS*gqtIZ|I^D|)v<|Qylnv`q6c1K(Z+dJp0NA90T#~gI? z_AB;g2pnTwQV`$b`OSa-Y;ms7ZaPwCk0*v5WILI$cB}0>$y=g(xz#$Pg)Z>!wO|bW zlF7)uI~uYT>Q{R!R+{P);2swc43t+>dizR12wOvOS) zxRU=;PlLoN#$TPz0!qq9SA@O$VDm$8Z_@D%cNRTc-!t2>Xy(puf?FRhV^#L;V`+Vm z`{>v5S#qIrEjt^|i}qiz(_6{#w@f9B@AR?gi7mIHnr<_*WJO56a+`keRq(64V|g{c zSGauwe~aWRHBMfd9(r`;$|AQf=1!`bSwDn3_+5_eRB>MEVb6QUVzX9riz;L5GXck# zTU|lM>erkW#x_noHurc~^`h{%=`T9Z=01COQfb1znR*dd7-y=^eAg&YDt>5km4J-M zlMZiZ6AqSY=_MbJ@fJ0OuDJbpx#MD!)p{&(SA-7P1)3R{g|gc0Ja=%5dUv1C#YomA zqU%Ci7YfMlIF-;~YI;~A;)n$!mxXkurLhHfbhHK+E~Bt24DdS8vwRF$?jV;WNS4lv#Ou%!bh3#Dt*f z{5tEC<(nogWV`F@_hhHF|IVVMlM^^Ma2}}6)MvE{VsorXSf05=s#)t;wp+V7$Http z3Z3p)g-d_U9y%NC@w#B4$5gK5zfoh+9oB&0bn`uZwb*;U2hPVQGLHo z!?AnYs=vY=jtzUBKey>sIG`l6+;5xDRt~Yy><2b#szz2`rjC{qtW<2jW`>(yJGAX^ zR^adbw{&&eGbXOn3D9d_>CvE)GN~(jy8+))Kh8goG;PmKC`l1hE0fj`xM7vr;Cr>! zDKDgXNxAa{1*Vw2Weaw%4t(YDm&;}8t}QN+S1*fQO_r2kQZYOp)L3ia^>ofcF14F_ zVkUtO`^7H`UH3V5IU(sxWNV1+Y!UwKz;1~+?;}a2`!7^yKZ)G-VuE@R3e;9I z5r~~Gk41eho;o4h28@swEL`>;gHTy%cNQ(BkEaBca&3;j5Si9@!&bd-5uvhj`(7Z;m*i0=wHQB=()UtNBE`6z$eSa(4Vr?U}$C}Yap1TEH4DDWa zn7k`0G2$qY$$BDG;eCX0tLmyfyMJr(R*HpgXTQ}ouC&xSWGs{xh+}K`BH%51>$SB*cS*?2?KW$&G;bbU^0c(hiRD?# z^TspMWh?XUww9&FE=UWG3SGouE#UdBp~yf(O9Vm=QevDYMk{^F)Hl%RFx9OEiB6wBRtM!D00>Wc=z9bHM{AI z?%dS^+(+vRFRqzaoFb`t`cM{o75Cf4Ms<2F-eJc5zn(Lgx^OkG={@LlVfVRDLj0kr zGBROj4^Fz(I(rtIZUpzwt8D_VEW#mHER(`{4daWepS)2yamYo+q41-U9fM`kfdWmF z7iI!k6<4mkv}E@wFUfSfxWaiyO0Hzr$%E6LEA3+RTZcZed8sqr4e|TnC~Ldm z&}RL>kQI;TDakFEls?DXlwV=9=A7m}ei6l`+iG^5niZvV)%u8gn~hcHzC+uly;^3V z?a>ih-jn}y9(&kw-G?vSCvQ4bxO`?_$Mv?`CW`(mS}gdScT|1oqk~0x!>e9EIp_-C7w~5Ky5gai zBp+KtR;{<9#=QIac6)!H+U}H`)H`2nN>Q<-_Qbz|7gt1Q)CJ96pb^U;Q@W~OXK|CQ z$E1MyOB`=V@4O@uTHV+(d+Ap9^~IHbC7VOG+}B(+z$9COD_p zX}|0~!}7lI;mX}zJ6D*e3rVLGKPb(SF@%a9hy^y@YV(~kb z*K>}ZyuQcXL-}2P=o>~pr3bAcC2_tRFF(1})pA{B$)mVgU1hsDss!_&?A^uX`lO{Z zQg~jK{HztKrZzGUtM6T15#Q;Np16mZe@~VBHa`{TH*Ug?s_Pdpu=gC`o7>sT(PUZF zS|7e%`KRao^9Q9mJsG+ZPsxaypI>5Gi&j+#?SPWvOWf_@)-++qCn$b#uxcYF}~ z=yYPmuE^z428)*|e>!{n%FM_8eOd?q8J=>fUbVLDWygYD%RlvMe0jZ%n>TV(U^MTS zu=E~>cMCqBGm?z-`ow4#v&yXPp~RDAk{mTxo?fg}D?H~_l$pTwhhu--s)NUFZ{JsP zK(ukG(W7g(L%G|YDfwRvzLnO)as2kKC9jlik`6KzZ$0^>v|sOZq~x&xO_j{wYlYsp zaC9r1G_203KHu!6nCX91e~#5k|NI||=SIOvG;MUM@jm)1#YEvD*IkLX% z$Z2e=+$wS-FGQ&IxZ~vyw{l8t7^}lo>R$EM`%XRcfQ|VhEAz#N+@)UWi&~eQKf5O- zLQ2h3Zj)TovA~7@lk-bkPKkaIW%R9m`ecsJyF_EY)jXS)~E*@RiZhJCME?JJFOpd-Z=h)qfA~P@r7@^Z`Z8u+A7g27X8!i zPEh`0ziHNnGlvWhM080Rx#{hXzpv!wEysSSbk^;~o30+=QjTBs)nQF^*h*ocfcItU zf?PA^_?4`R=)V3^pt#5T&rQoM(L3X{norFW^L+pA8;4r)Duxoi5vNHopqlzy^gdoU!3Wg>Uzf^{g+>R z;tEH%_&t;Kp8K6$Yj99MC}rxSP~Eh|Nz3Nx%$*vT=XF=I}nZHG^bIVP6+REA8AnhAED@lG@&YGmsYm8eDRZICqr}KX0O>=x9zE?8qeQEUa z($kV31l~U0yd*36pCL;NQ{0c~f>|rC_!xdUE6TdY>1#ZT4U5$FX1UEP{9lJ$>yuNt z%U?Qq<;h%|`@Rc!76<=7eLrZ!%CFl*_T5+iv}aXrdQL#-|L3hXm+jo=>t`*m&6}TK zm=)UM%`EriAK#K)%X^r%yuJPKyU**ql9abIS8NWvKY!EC3GXz%Oj)u%^u~#k>EcY! zw)g)!^xpJq7>li>%jK175!F}2C;X|IZyguPTk~_4pLLu0f~)geb*=PyoX`ErlM-<$ zU!k1Wx8OqOAGI%gvQK_pY}Q)BFLLw4lv=(S>?#hk=1uMwY^qp(c+m}JP6M_wsT|2=)+JJY``-u7w3745*g*%_WWIs$Z=xndQ8qXXjq6 zG^_Nb@7J%kn)ttfac)X&Rb20^hco^?Kds|2^_LNI{nX`Zn}7d%m12ATAn&B#0bjqo zt3JBm*#C@Pzn~opHiZNTGp}N{6-%@&;M9NP|4WR`bo2Y@&xd9*#@|VGev;R7X8D`X zbywLZd^IUo2ynA)*j<*sp?CX@q&J3Jytf@qT(vE{Y2QJ%)W(DFzYB*juers@>ttp2 z@o&hHH-Bu!Ug{<-y7yOVu4G7cjjMFBa_#ha=iYRLejW(jK6MmV#rsXay?Sj zMlAG!fJngEJ0}BNPli|5zDm0C-C$wgEI$|bt#zv}8`<4YTl_iHV#ZJT?ClOdJa=r0 z85kH_Go76SJe{3k%X}FaD(2KqwDmX~Akyj|yfi3E=9c3TMd#8@0U<{MS4FUJFI{_K zRr5*j{|h=5Jqrs(Vz~MK>4eF~%qcA`5M?^)O2@eSzZc%KZU6p` zxg~7w%CvZ<0MpYamQ6}pxI>98POybvuw~+e87r3;b5~YeyKeh6=hdMa_rmUxp+OzzJCF13QuwHRJ$3qhi*OmSinJ>y(w}!MK9aPw z{i$49sI%%kr9RD7ZaG8{>_;GsA$=mBTE<= z7#8IXksPAt^OIGtXA({qFrr3YjUk zO5vuy2EGN(sTr9bRYj@6RemAKRoTgwDN6QsTs9R}6}bhusU?XD6}dTi#a0!zN?>!X z@`|lM!um=IU?nBlwn`Dc0SeCfMX3rVdM0`Xx~>(OWkyPNTnaWtDQQ+gE^bgGic->S zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6}q(sYX}^GXscbn}XpK}JB#a7isr zF3Kz@$;{7F0GXMXlwVq6tE9xGpr8OXydt;2*B5SlUNJNjlJj%*D-sLz4fPE4b942P zbrhGlmX+YwQ5;fPkg6Y)TAW{6l$`2XmYP?hjBG?oGF*Q_X;BW?J1NQfsX3{+sd**E z`i6RjC|0_A`Ub#tfPx@BGq(V&t0K1mMP*558X~Yzd;^jJdk5Je6}bg)b5T^o{0>$O z4kIg<{Nz%Q^E_Q_l|c4erQ|1PrdWZQ$%e)zNlBLGy2(k#Cb}j`7G}ChMoG!KW)_JS zCdo#rNhXG=NJe?)6_+IDC8vUns>m(S%gju%GB-9hH#aah&^0tMw9qw4PBPTBv`jSC zH8xI6N=~&*HB2)yMKZ#_C^J1XFEIz%RUo5MGE=N96HSbhjLa=`jm^yrbWO|+l5~?& zEKGHiEYgxpjZ9OL(k#-zMx`WMx#bt-CYIPLW#%TPr|K8vrGq6v0dD0O;AyL5q-TH- z3CKw-Ny{(FwN(nw%uC5HFGfg(Wag#@mn4G1)6mS=*wE0_(#XWZ%)r#r45272wWv5V zKM!Q8p@E)}30MXcF;@OXnW=dtiJ+8ft7HfkugER1axO|uEXgkl$?g_trC+VmJ}zJrKW%_Qh-S% zXC&sOr>58{L6a0rJQGWFS)`g8B&S&#>KdC_8tIxO8XD+Yni-_&nkSj1B^n!>CZ!lc z!WeFPaei7!d16tjV|r>{iLH`*W^Mu4Hwqfiz|=%_O?gHtD5MOG40R0+bPWtcj0~*| zEv!sTl=LCqv(X3TX_#+q^fAH%q5!E7u;WsIhy}U0*>TzEgG(Y%sRS_)R4ULCL*s## zRwyWpT0&Czjt19gaFG-OBq<(EU8BK8QV5WwcrLwVD~+K-*f&i!w_}Qu7p&Dis_-y)A`+jQo=P;*9(Pdj(THqkTS` zg%}tV7(87ZLn>~)+3VY{;yq2atZ$}!O4`-m@2=b4l{v%Sc#ubxF^W%Ntw)2%jz>|_ zp4^W04Zk?Agn8?3y%@&C!n0+`7OAF7Jf=-M9!zLB;8y>=#D9O?*IiosmG1P3eJeeC z$M%r1_UqEr?YEuxo$BfNQebYrz53nG@AJ5GlBI9oIA*qOV{a~2=KTW)bGf!%?63d3 z{@#(%FXgNvep0fT_&Tr2rZ*|v{;54x5gvNZo~xmmsH z-z-U|2Nr!j%l)5Zd&R%4S+`rH^8M-iGhe6we-q5W$jI{2g-eO?+D;YMqw_6!n)iJF zaPMFx|8rSStLHLviwo{u=9OFGV#PS6nBk=>*AiuiBbr}Wm@dCOa=F3yb;|@d8UAu7 z2}UMGmR13Qz90_AN`?z(zv}XRZ+|vR)9kdL5Pv&!|Kk@f7U~s(J@R7r-?4NsI9eFZ zTli{C;EDB|4J;gr8UkM5-M?A<{Oo$5vGm*J_osh9+9=7vc5aW-+#LQuX+96`oF)vrk~q+ zzxv~&qxTEX)v_e8A6ULV{&~QyBkvgZu>IgV5YCXtAj807#METDq&jcAGNaq?`b)8Kwnk6-X?470T{Xk+l6THbOg}Au zavkvJ{KN2|-?4`C!Mp=M^#A{~53hFn81Kp9D8a^Vq$l`%#p>15f4z9j|MhqMdwY)C zc{@R=t*!U^`uN?4AAUG^_3G94e1|{CTR#8CabP=V%>*;4@+4W+>&+L7h59beSIXF< zsnUNV&oX11`~mCdGB3}*KfY(C+VR)(4rF)jSNWlOz}#nc{iiCo31>Gh{9I?j_+wX~ zzLYX!2uDD~QwLXe1FMBMEiA*5O&D%ie!BGYA!|psN$_`-e1rd!F;|L&$r=FqC<$-oXIh)Q|JDz*h z4i7B)^jZWCeJqfE$8Wy>&%N(?_CJrA^Zj|y-0OIQ;ec74@Ui&6@%0Dy|9t8H{rKUB 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 Rtpzy#mR~R4uJZG*uUB{6wKBi{Hs;Eb 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πE$G_k<7dyl<}ZIUvfV*dDRaKeEk4<=Lg;leKz( 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

    )P-8Gw){B*$rtiiI#e4F?dFyC_7NwB&(>^R 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%0Dy|9t8H{rKUB zn^&J+ZGVUN@O+I2?>T>oHBJ|4OSz#N%6W9|Y3)eiX}P@0EdgitiR_Hd+-~pd6If?FI`VVcp647p0s{&hB~&kDF1h@c4$C8{Gc6LTUM<4sBh-C*7j6f*1gLeCsun;jC&(-Tv9CP z?E9+{_dea4c%gPt{QH?Te_Z(G89jO!V^1@jG35Jp#g+G@#{7-1S>{@M|NH*&cclrV z%KMV}hjcqXCM?^@+U*wB)c@z^)6bi&?Th_>?%T3`$*%tl4{XYpEH2*Df8BqAgv`eB zBM)R>+CG#K_7LQdTjbiclC@G(WmBp_@CNVoTerCFt9-&3puu2rG~1<5;l1NM=L0V| zc1V0yV^Rs26wb0Tz;v%QQ?-CKSGB;B2|c;7_s!}KWJ-8+rrC=fmh}H2!I*hCX$h;^ zgsgb&`{@h~vY)G#eq$R_)uFFWykoTkf-zmKf@lj zLXAYOZL6oHBxy1!Nt7fjII>WspqoxED9n{(3vHoiD#mTD2PDxy=+~fRvR{4R} zS=rY(UY>ij$h5P)@?0!?fQZxP=;tby{s$`K-%mY#;9vtQQ^}o)1uE|s$@?=%E!n^> zv&2C|NJCHfSLW3TIxX9GwoTchw#Bm{x50Ul6G!;Px&DT)c+?)t%P`()?r1yBIqAuq z!xEGBrtG_Si0kbFkG0ClQ$^%9991Mjr*L z-b+n1e}C2|e}?emn-%HZTkOtV`k?wuT4>Dz+s0{M1C~^8+-??k;KU4(Fb6Mosac;B z%KK(9vd*Zq*Zf>-`iCLQWX?_R<;{ziGr!PyzN7fw+qvZn$|s5z%$;Qa z)iLGFCspw!Sq(}8P7R;=f-Y3p$a%!QXRCiGTmMpKf2qx#T6-D(_?Gbao_CMWn~5br z!f$$f&BJ%^->>(mJIBGWPw~al1>Q}+xA?`Fy{No>QZAEYq2ZmQ4bOdjUfIn3{QKyw zO?#g>#m(?Im=q?w^GR{2LBQjU>Gl<}%np+;T|55H^R&4|L!FcHWe3GsmErkn;d3VM zRR7GkYSyLwb(2I6dK5mLt30Q8-o}6H4Ori@USYAY67>%2uVi{^YEtPW*vYzpSz^*_ zzjrQHo{PK%%Q!h0EjdlwPEXyR^r!7$W2W83t3MM>Z$FAMG2g3S%64si?%B_Q>r$_X zd9+n+&NV$Occ?GOVUu|=HN^?YSYWyd7iOG?$}3V+5X=jE#x+|GMX`L z=zVTo_x0D;0vkDdl@Ge^b=?Ql6<@SAeM>O=x2~eQkUum@&UAC4(9F5H-*?Si@%uLa zyx8M4H!g1BTRi9fk(-$eH*USXXqbL`Cx2FcTd%*D-9}Hy?)N zf4=!pz^~@A`@MfVj|f_8N+hiENy$s&R_A)3>u0k5a@Abcf;DW5tt|ham3{tl(Us1R z?;RfB*|NsM`TUbt%U6lqTykfd$;Kz;PpY3YvTD|>5ZK50%G&W^`LV}8ENGt@9-%uimXT6a5V#zKZhiTu3#!iO16 zbp$3K`nl!U{0&=PSN<-1r+aL*-S0ZP2P(lowk>~antbnC-4dUQBNGoMFS?pHsy5n$1^?cR1Uc(6w@j%Ym4Xg%d76O5%t~EZS)L zS5N!f2A3aO8%ubUeqlY<5h+zgxavJr+wZI9XjHw?t*ud;!-t-bU|az9=ZP zn1nMreONimk@43y<$nPe`ui3C=)QZGe^`ItAFuX;C+Bh%!0FWQvAX@w&T_}_dGCy$ z-$`e%o3f?5dT;W%++{Z(Xc=Uj6`q^j8#0;y!G>#|5#ImpIkeXpnAKb;`@iA*wL_I> zwAJP@Y5uzP^V+JQ_j zS_+vNr5SDD!|cir;)?n!o2OIQo|i})`%W?lY%CGQQFq8jhi zofgw|bH<>Ihz;(6AML1NoaCP#aUWgM+OcXoYYNBUOgUGsPTdgG(YYJL2Y z)yCQ{j-TfT|M{`(PjByXugSe_I#UBm*$@7?D)F30&RZ;@w|#S)*tI*|JaU{z-h6p< z`guKb(!(f^{oK#K8#pp5yXQ{&7*P~;tMb(R?e7{NY58pOa@v)$x~NKrdxh4#NcV*+ zjI7cfD;j1x9#dr~*Zd%@_~QLNdA{{5dl%i0m+wFRJ5eHU<5OmE_4WV9)BFFL?Ef9) zzvJ*4UtM2S&&wG7Vy#M-3b)E1@`ty~o z3ob}ih%oC(oqTwvb+wTuPe)?8wRXs+9dzHFw*E88^hAWyOMrQ{;2<+ zbH=j&D`m7Lw(nec!S}|ij|rPix1~lkU3-3TRq6z_tO&J6|5(ZUN_sDySSR0O3;iZo zvaU8xg)Ng^ljWt6hkW0o=ZEk8KliZU&zFDi-WAoCe$~F)|L9)6&H*-tZ6EFW<7+;8 z|9i6BelOSYkH!AqcefvYczgHVcggPMuI=2N)}A3=n@+vTR^7cnk4KQF3oNf({5?#rnxEy9=JI-PUAtb7o{8?uUjA?sHs9{H`@+90TZ6SJatnly z$xS^ZcAi;0y~oS@Z@B95oC;U(pXyuxO!&+war^pIqumv9jc(%V-OLi1DQgY3xGa6U zGJv5$J1xHLnt0B-{l@#JM@IHeYtkujU}j4DDk^p`)#!uk`iW|L5?;S8+@-=?%6l^9 z|J0qcenwu%{JUz)j;u@TV)>_C+-xdeTGyx|5;ChGiT$N&UweK}(fwune?BvKW4C9| zt{<1)e`k!A02eI#-6bCG`|~I~TwGjy{yVnsy#{^q7h_}ImhW!dD5}}KX+gw%iKWk8 zS6C=%h`hQ`-G7k3;NHQhzF9507p%6fT~&F1Qz}Q0P`|ltxaGzJ8^dC1=WdTGoi{~h z=}v)TJQf=TpZ=?zwP*g^>#5H+WicwR;julkpK~r7!?Rc4me*%DI2y$EuX&hx+o&KY zmci}+tW3VC=a#Xl-?~?sAOB-!YW-x-^j|it9-Ir*CN7xreBLeTOJ4t{6^n;FVc@FG zTe?X2!c!%2llxOPmeihFz2i^L?fA3n-<-TOr-ncbY9pu>GfV zFV)ocQv3Uun)ls>GWJ$->-X!v{LbDlfA3yQP2s~hnI#i$Ipl*|Rqv1e|G57@cisDH z`%mll?W+8Fkp1v-@!t=HnZ(;ap5w36ITjkmX{UXpaao8?J44yY!yRruiqkqO-3%V= zX;v2uX=GAAzT%p8%f=MN`CleE9WddFOuKsvU5z@Tt`HyHi<=HviS* zILMydlbI9uu5E_#b7{7v_94Mp+q5QUCmoS4U|a2yo&ANk_S~!2q0I5gzkTOdZsVNj zwZ?I0j1Zq^zWYT+KCgN2C9ZZAU900@JZIUV70R-)Xvy{1fX6M@<%90n9WfPiQ(!sv z&h-O_N>i~!zkAQZdES4*W7pPP-Lm4kRDb-t?Bd_)lY(yO_7%;~{;Yj4MO4g2>Y3_l zG4Hb{aF0? z;NM5Tw$^{XxPAZU?YH@MGdASzIsQ1k{`2-fpQf)byMFz6{~Y=KhJBBh3&kyhS&A6MW!(qUHo9pZ(mXI-0N1Irn2|bq+B^i5pk~cyNQq6)tR5o z(O#NyR?Lgxi~1hb%PS(3z3Qi2@oqR3`FiEffIOoVnZ-FbveNdSTr}VFN!_0nvh|HK zUp3vdXuA1hwnGhD$vOl1L!WkPxip^=sZaFyeu>eJ<1q)%aR&1z%eELjnCLszqwem` zY1ht8yRLRXRLRO+!s*IN{*|i5*XD3A^|?Q^Xj4hoZkh0efhQs<>*MX0pG)O-X>k~p z)Xe@oVTV@ajTb=`UQ=f+&t1R7f}i_<)7e)k?r#}#f9CSvnli7EqvCP#%$t1|8Jbrt zv5-F{u%}#tE#J#>_nwXj`8|sti|+lstoa|ug}WaMq#6F)hlk$3f`anz?cNt^g_!K@ z<-WeO=#y^|&|`SR$QO9IcGkuzy*dBH8Ti_r7YiCZzdQLzp8bL9>wD*!Z{4@;_m-Jc zSe|pdmz>P~^5Nd*&vJbq%a^JcrYR*Y{F<=aQu~O|CZCx>!I=)1<9C?v(Ye3-QRF(G zOK}q`mOW}RRDU+{n9B__qn#lezH(&Vy0D1R_VpxVUDcSq&T5MvC#gI5?^t-Q-}F~) zxzqLwQ!m67Eqr%X%O}ckRnCOtA(K`KcpX+)$t38`?tb9l!IKOOHy`-LitpUc=;EQ+ z#HDE#W@JD8O^b|CbV7;8qoV!(*JC#eE>m2hv*xMaIzjG5#Xrtg_a{osN)O?Z6%H}7 zQ9sIg*xv5KKS>~?&7-7$FqA5 zNX17mD)uO_KHqb5#h)j|QS0SDGaR@wU7Vqy%T(d~o;1dWb5j3JXFl&c@}TB)UPEqK z{i6-0eWpx#Lcem1<-$BRGA%rC;k!rgJd>q!1r^#}GN>QmmNVa%Ba#T?2>z){BQXWb@?l z$hLf%#p^kTonhy$hGTK(#cxl%d?RPI!j$Z1Ic#6K7z*6f=PC8|uG-uAU)rpRQ%7K3 zvgNCI3AggO7QX-H+*x;X*|zCS42nyXY-YP3oEgyZ_Hg#gDL$9YeG4s_gVMBQL#)^q zCD#N+IvG84TzK-Iel4HXVI2iC>1|hgzQtX95}J~K$4AWi!*Qh}`A^qbC<|_gGc=U` zCct#8Fel`X7Q+Na{Va(c5eot%_g2g~%<~|ey{<{RzrDNrGq|qAZ)w|Rv|z2+3hC|9E2S#VWpHJ^7QO$e;^~fsYRu=VCR&<2s9kyJgz3+(_wU_U zGu6v%irr0*FV}p2F&y8fvc7nIdP9TZuawCe9h0V9V_LcMr&ioM7VUyrJIn*!jOKP{ zOwy9QrFO=0)sm>%N!DVQ!vv;GvNz5Acj?QWkZYO^dhJhbB*G?}+zx*kqE*kwAmBIA zGC0SMhe6`_%)TCzMEPT_62}&cKVf}0*M8rPvg^DIIgf4SRXnZqPxe2S@NT?#>4#R3 zp4DllGlq=C$8y(Yo)lt;*#4Pu@j{F0_dUyu9EAG|)}_2+EIJsYnem~4&Es{1z+@lu zjjPqF&O|xR-|M%H_5W3c*00xNN-%s249 z&RF+t)51-OHkE0!MZa>o2-qb$EbU^y{cywDI}=31H)MNG6+G3nbF;Q);EUXocC!x~ zZf$>dX4lJ8AJgj3Ev+uoz51tN7Iy$|WvXw&s_Ij>G>^|{yF6oyY}syGhF9<2-DAD` zJGcBU!vV8<-)GxZRJ{MZPfGsh%o}yiC-o#tIUidjt-DqIsoW;^RoIamPFG6elX-6c z+Vx5`h|j?EL2l&3ny+=!7~_=LV|o*B|46;X(Y8A9s1(BkjtjfRrrbPYKbd2O@Y7SJ z7dOafFf+YoaG1L_NhT#F*~!RhY3_!#(dP?OOeNOn+Mb?edho)llZ$gr{%qzuWODql zs#IOj*7>tFG(Wpuy|C4M-`XG!MTHqLU6bS|^DHaAe5z|_Y1Z?&SxgHLm8}S4n3C4U ze?mSo%DM90^7DnWH@u#7&8cP?Z=+-B{LsTbn%^C{tnzlh1{F{9`h%QW1yy8TuzBz( ziu}5(_Tg*M{=ElhZR4KzeUfT|-95|H_VcG0I6ln#aQMQUZmB@wX`2pzb#~2p_GTIP z;`K_=4rw;gI}fe1VO_1jaJ=Bn_75?|6AtNow3rvFVJ@A0Tg5}IdcO8-L6)VLcCTXz zURe{Yxa33gYyrh{FZk2VlvpHtuFNdC{o%ls#n1N~+?lt{a$9`w>`Cpj#T8C-s!D3^ z@cB7gXWs<7=`4RX7|+|uC2;yG=e9`=+-*C<_NaVZvdZd;q4G*Chh@?W->y%%KPzte zX}RAfdla6RYnPv!oUIQOm7KD+PIvj{7mX;1W%f4uBk zxYClrLHGUZO*>Xj+P95MiLC~AMDdzmWW8Twl11=Vi|*ASpWT3cTSu9&+M_+HN7htAjGrL zRZqw{pDce_C z7|%{VliD`LQpCXT%7+{|*CZB^tr|;iKI^}FK>Xx`SC4LI&&c@t+2+AEg=)?P&+CmD zG8jd@`5aG*Z+JR;*`?fwp=37H+&UL(OB`rT1cTtv_qpgBcDT+sADjSj@=c`&+`icutyH zsKE*Yeyz6ESC8cjD=mM0v261e&yM1aKj&3u+LoNtu$lHX4=i2cf|GY@Q zs(*H+?q=rPTi3Vz-IZp0V%^8+-JSYj+-J7koM~!ecxTR@uk(`A?r-zIeErSuS;liN z-88!Ud{&YBqXyuk#|(c>V#K)_S`o zTbRU>?H<=1i%1jQyYu|ii~qKNR|%KW3DBM!{&(7W#&ee}O+QYGmE)iFe3_QUIp%~( zK{-6N3>CbE+>GEc2~!4xxZ3+KlKW=W|N8i$cUOL$k?Fe^Joe}FCcS;XYya#{;q$^r z{$>YHT-er`@ta}sr#nui_e&qu&ODm`0GM@vp#I~-so%nV3W|Q37Th`HL>+DURY0QqPUbpsp{>yi_q{<%WtGtG- z1$a4UXMt=?UH;;_6_Sq+OSUy}pJ^3cZ}_}>+u4GguoSHazHjU9{>at;`7ZcqAE#sP zG2xKsdp9P1jh}jH??107#u&3o$>JPe>*K}Gul)ZbVdHgXt>Min6Jzvm8!?_;d&W}y zTmqZ#(g{6jPTD7yM5-m{-SwZ>92!3FUGak@Yc@1Ba78WM78vF^WzG57L933h=&1Zhzm*${6~iZLVYL#C@|5s@zRY>t!gE zJfkaVJg0$alA!#n>}R=u(!TD>3Y~sCxn#Xl$I4=K0LzG+z$a*3=J2 zUay~5!SceS^vCN-Dd&?Ln_Zay zGPg`kMZV$e?^o7Q2WOf|uGP1Hz4zPB7K`E&#h02QCbLZ2`=gR;`_4yo=e$16nk^x? z^cmBUnxbgyyZnYWvBnE#R>p2VwrIJePs|??(RDK|=T_}mHoGV`e_4FPt`pq8MQPIC z&wsYlXTCA*%TswL*7jIEuj=?;*;f|tO53(z(bre6(@XE!=|~%5S}ea~og)Zn z{rO(@dmE{Zjb?Keue&L{Y;UEtZpWu|;kni4;;;FnAFWywuzq5&Zo`}ei<29+-)XeC zt<%lssdMrF^Mehy((Gh4Ha_wSez-2mFu<{4;_JvF;;I*Xf?Z_}HVe*C-kHh-&jNLI!Lp!>mXBk!ZwvSveX#ubPw|iV@5<{uS&Tt6*k0x3Y8#{1>Z~>5xft@i{GiU-O|Oq=WhOpgWb(-}{@49E^Jw;z z*+ za}6h@zRva9{)w@vaPGXOP2q=iY>v)t=D7ZJOQGkhx<@PYr}mfLVt4D`KW%-agF$l1 z>|OTPrqw#kF6nHS`X9B*YPyG}t()2QSpVMD+$K8(e8Uy5=(X8?480}O?Yp*qcK0Q< z>vPx0oeY(YU9seY>|_u3uaDlAZc$yNCs})TO=A11+JxU42UM$7>8el4s^0od`lXvvV^YiQrfzt?!A|kL z4fBFF)(R#DRcrtL-TJxAvRm){=49UeMe=g>*`rg9X9wZVY!Wmm3DyT!9|-P$|fZeA4)KPCEEzV8`J@1grm zuNM5>Znxbf-f7nDGWAvuMh?XmhfQ0=?}5suk8ymGv-*9fm7Se&eb=imp@lalya>~+ z_`l4peqASj^x|ll#DgjaE}qzSYS*r37Ow*NFD!}T^bbB4Bh1yh!HGR#@9+N#n|2!} zc^^1u;u>}B*xVam?8+B#-M?10e|gW}T{mjq`p=JMpKtVQbqQ+`U&EC(KZARY-ubO& zFI{l=oACm}#m^#zZ(DIMoElPQSju_w z;Xnq5UF$TIL>!)*F@V;X?79Bz{t-V<_STIm?U9f7e~ZZ8yEE>{v1Qua!PkA}crV<% zHPGnRt6A3$UH-OodxDEBLq_PMbHRVIBbqKuTWia@tYT61J^AT#kF4IxVWL}GTofOF z{NA54>^0w%*FVl(Qm8%qz&ewXTa1O9^wL%G`kHWTiS6b#&qL;~ZU3E{%JV1d z#Ztr6hgZL5a0{(2tG``m(e}+E@toJDHJr20Ze4Y5szYtN!*i3J)A>TRX;L+xkLT-Fl%l ztUOa5zIwJ|!=qW}C1l%f35EMJGt0gD>%aS&ukE)up7e=a@6(FraR%IO$v9?VA9E~B z^Yx#%HvhkMXjV=+y{h`}-*xl$rA4Xu-{-!}w4<_j&Xq6GS^L-Ac_z8#s!Z&9w&16c zHs5D{&kVd9JlT$+?Cg`z-5>w&o29a~a+yp+BG19YmU#@|+QHx5lqQ%6BQ$a&o}Zh(w|%{&);?DLnA3G@JX0 zXu1n5-9HYHn~h-&DzTUcPw4hUv_4SM8+I8-30CQh8?ydG3zm%-#~cQC{V3 z?d)&zL4Wtn&7EFt#*o0aC971<%OT6`{$U|W;hPIzR-di0ROn(jK7X!L!A#a0$JiL; zZ2x`I|9|Q3y?c)yJ#wo5wY+}U)X6qWCCiRUduqwm#xqRf@Q>o$;4*Xb)cm(KvA3UX z`){p%(^A?-o?cBKrJNf#?t_{#3t8_uRswpD!Y zA3b@8**f~Nb_IKNt6v=XVsiUdz1|&%wR@IsWpLOKb)t7?ZpzBWTk8+WHRonOV*9e` z$p7Y@{C#s`^wS-qe^*ZBdU2bn{EXXrF|APD27xA(Tpo~LZ2OKY$L+7{ovt7M=+&!N zfot`*7gi;gsO*s!IMgA)@Sd&Wy`rnxf*-TAGas0KKXK7fF-_?GH|rJyx20R2=*sZ1 zzuD9NozHP$$3hd=R27+Qo_$k-RWAq}>S$n4jb%Qbapv|hvu&&k)V6G8erTmIN%-)m z*R{c-x7GKygcXIV7N5TUEy9~^PBGi{IabX6_io4Bzc05un<1G)aF>y@F!POiyWde? z)|D3fl`qKt%qqiaRrbgz%GE&dbJX`*w_kT+zMReb6jjP{E9&blhgI*5BHqV}#kyTR zr0)B^)#7~R+({GXz1Pn5@|-_Yv3=J%Pw{^LgO%*hv)XD|PL%F_TgKdXT=4i|#t9GR zuhzbN)7};SGJq>$d0jg!lbF zRWslE`qkbUvIh)1Lpc|mk?!BNRV()GPd#7TRjTLf`&bq3NHPT6?8}l7mUcQb)xqU2}gYu+E-ata{{2!ZVHzp>0uS|GXU%`dB*@{L}kG+vnG=XAQR8 zxF!Gp>jUrN1a>FRP&sF{kaK@y&!jtc=Vq()B<671xD^=iSjWW0DYY~_{@5YFbj(np zCwb4cNpD^|>=3@iJEKHp%Wq~&;adhLmlS4dYk2(rTX#FnoZ-WckH_o(9RKy%{(o`J z*Q?<*pP%*q{@7p7!|*u%&(ZjV)9e*YpXVo)E-lfp-KWU%ck0&mLBWZxY#z4ie77>6TA_ z>c_e>+a23DWuM-@d`FhU|MrC(GB&Z|;MI8ZPtTY?=<13EJPkhYt!4TZ1ZP?@952+l zEA#ko@dT!_-HhVm(|6o>Z}_H6qKuiT-@+r{)LYG*V?HP6m$GNHbJ)f4pA*_xhiQ{Pibx@3wxvcX_d&BFjXcAGdy8`~R#@;L$OKWQDH6 z#n;T2T0TsT6knuf;mZH?+qZ_K%vk%tiE%TOX5COF3oK zC+!z-N!fq4y0NfBIB)%?u0B2;x7CaFsy9sdr}koo1mkTr)4)vvB1#e;?z!(WegB^~ z`@k`8uDKaLFSkDk>R5DP-{*Pz|K7ZqSYZ7m%vbnX<2CNBZ62n}VjA3SKFZe4*)KMG zMw;hI{xZ39yZbzXp7UPY;AF5snaNQ6u-2M+kF}P0mfo8_Ly-CTtmLTVw`XkHKXw?% zW!Kv-+L{0J*YrctZ)f$Vc6r?vHnp{$eaWg%(JtGw>v9<5jUx?*9||bW|IQ(F?Bk4= z-zM!h?o%$?&8TnxgJFK%Cr-Qne~N3q-AtD#vu5G6l6&-(%~W@D^n+{L8Q3(;GnG^4 zFO~|NV4M21+BC<>L7JiB&5tja{Xc%5|6k^uW##*swr#$#uUV$Yep4RmYSo zV^0Qemi?Ub{3egoF~bKHHggtksuEHzo=4+>z&#=y#Xt+j#o^>FN3(e%F8a{o}Fy zKjE5xH`5EwDYsPLk$=y4Bz@I~YV|__!DjiDpO}ALn4#eL@A356i?=a09Pj;G*Y9ul zlSRJf!@-KmO3O)8mKg9H-nL?%0Z&4z-POQ{ZQtvEeLQ0%q2YOLw9`mn|pRC%Rc)&nqy?mHRy43acv$cYmrsePP_U@d{Uf6N6Kb?_5#-?rCFUHtC z^YQUAopebn2Pwx8jR=Tw6ou%(LDsv~;CcEYIE5 z6JLJi6sdZjy{$$t`_hx&GS>6wc0ZHTY;>6^b~@71P{iMQ+nlnqm7a>Gi$d1^?~kd9 zJRQVfYxst(;lRU!{>K_D{5&N)_U}KwI{q)0{jZ1pg{5Dab|)TKKEI~v??0yR+qW0i zTJra5aW#dlSYanVqh(i?x<~1PduLpD)B`_0u-R92I1#j-tm4d$UAqpM@B7&M;n7j< zx(^50rP>^$nH~sBJ-Wl=!RVS4lEK>GRAIop;mKK1W|5#zQ{DFbyc+)F=lQxW`M)pN zckJGK@aR$2V;>t5<&%H43z$C;NZRN0Zo;vk^YGn6sGu^(38D#`AJMwHD25X7-5Ji(6L7&%5`GUwNbPU%m^$ ze|9oX65A6b{C@q(UbV^hWcuBtS3Y2y%xO1WH2?g1)lRL=LN5zU_P*i1P_*u)X`(il z-@2Qkz0-B<3N3Rc&un92DB9QYcQe&{zl8y-*@QfQ@gZ} z%s2R%=k&`J-(zw1`=fpJdttCha{cFqDbfv6-TH#3t_UCa8G9?kdDTq6)V7svR*z2` zsJ*gq;SrhHz;OFjo4_9Vu5>X*j};$|F!oJ+XP2c@$?IF0uxZ}a58Fj~YRxKd&T-8M zd3iLC_wSaZMPcS9v&%adAF0^drx?n(!ASk(og}%VTNDM;lM@H zNn2MR=CTUaI~g{&kMCS~gV?bK!z0x*_WlnFyWY?+b3;p7p?@@IK#||1?enuf7oTUm zsbVkD5GCX`HR;`{nN=HAr^-Kg5uDe>#c(739i#i6y1!EU|2!4{(0q9N{=d0@=Dx3C z|J}{Kr|vJC{f~qEA3h!BuK9A&{l@$662}FTIW~We5EZlx?9_?;AH@9P)#iEgH#@jp zdCgdGhXK^2wBGam*Sqrl-p^x}O(`iZZuaGQk?FRWMIyxL>fFbVmxTIP6tvC?Ghv!8 zF3!MqC+_}(UuR9*5)Yi7F8|=@)$XWYPdJ{pZ4ullVZDHPqRoe#KQ9$4dZukUbBz0D zH@9Z-tO>`qeC*dew*C>5F(bES!>5&NE=aO&d$afHS-Yx8)Qocr^l6H+fu9>owcHNPLCn-?S9l|39-@ z9Tb-QFEUoN3g5!8pq;V7!hhe{RnNb~D@@}ydOpEmljZTp5kfDFBsOmSQoHH@md44M zyNoASob>$e<=nSiz+qqd8J>oT2IL=h-b)S8!y;DzSBO`wryoKi(}a|KMN6 zfz{#bKXmKwJ8-pIyXM!;^c(SUkKVnLi{JN)tGxVs#m`5qP92==%AMiah?~7vH(}!p;JV3c3RQRvSKJc%QBN)k1Ev zBgb4vl|vjA6>n;EmaqE7Bzhr5S!_yA{U^2TM+#l$GR0q=dYH0rb=|o6c%A^mthavb z&V}M-j+3?6s(Z6m8L=!+G0By2U1s01u)W%>L5yL;>w@P+uWzZGn8MHyWRVp1gmdj8 z1@FW2A{r;y&rUG>qcVGg>$1hMt7IgPYfLJ(kSUNk9^rT>A?ulRMoh9zd^x=!9&lJgNvrMAW!VXRN%5s9-_OZZQC!>|9{-o?@P_t2#>W~5j&F+55&UDz z91yqqF8gKKf(3d)+c&mXNH$D&tnz$bUfzC@QDXaDP{%;(vBjn1LJaH*74P|{PoF;f zV||yv0gFkAD$3{IdTcM&`z7`Gqr}VOPQPs*+O|6EZ@wR|bmUp$j|Yd(7gT;VY`U%d zL1_1C@f$bu_NqLIx#C}LIPY9atfWNf|5I*9Z-p(GAfxwH%U{~8c1c+6j8y#@PQ0o= zxlAQD?o&UWCi{X>ee3P*hHXU`mBT*X&1Rmp=F2&~Yje6cHG!}C4QB|h9sNuH#sWe{q=9N0cr<&O9`?d*Rd{ao5k9 zs?S?Hb>G>m48EdmjG2DRQUX_|ZuLFpzkVyzK~4{q^R`P?HTNBx*;Xtxp-Iy^XJ$`D z5Z|E*hnyV)SHEO3ly9qZ;NWZCeV|?6{^;A;)pug=J1ZBKOB_sO*L+~da;KkBafz3R z+XSoJ4Rf9O&r}?p;vBZ~{>isu5-gVr-9H?)=$kLo_xO1Dx%j4Y`Jge4emVWPJqOJ9 z|Mab|ueaY*`8n;&y?*_;Jr%FcY3-lO;J`THg^D|?{PuPi-Q~VLhd(S4I%7H6{t`c5 zp>)xQ!+bK|1j;yWEWK6Lr0nBjU8?Qjq@s8A|MB>?nKyFYAKlQ|L{1PbV0xi)^39yUJm~yozf(3JN9PH-Av#(0_SnX~SCS z3v3Mc9vx|GoL~QMXZ7D-U*G-ub&Ju$i>v-ydi}BbPyYW-vN7FLV|gIED3YtMNaxu) z;SZHnPYlz|ie#=hcN}O~c0`xC;a7Q%*@IN+Yg*S~Sd+;+Uq+4$|4p;vG?F>C!Op`k633uiB$e^q1$LhaNDJr zc6-GYDVvU@FW4aNd1?EVBP!RlJd=JWG90_IS*i48v6|wyKW}Ge-b#sE-Pw3{y+(q- zPUX4t-&*hK#uIYH#$-Z)^xz4$LXcy)W$3Eo&mHvV2GL#n0vYI--xZ1!m3IEcRml zA;USWu3;yihUFRymS8azQyW$ zKi*Tz`m?zHOMgjuxjEC0>YtyU z+BP(QxBJsv|AF5u>t*h?XW}9Un_Koz{8B&Z-TkCvkJoeTpE|wrOt_}DF@r*tmX4D3 zITntJYdicMkDggR?`P$^zx;F0WPTF+-LihpcZn$(;3*<5EVJtB2d;IWdx41O(21AB?^MC*D|Nnhksfzva z{vY}OJ~KDWXZ&&V|A+hk{p%r=sJS0=a#yNYCCVns&OKXh zWS;Xb{PXOaPxilS+47*a?CZp}JR8-HFFc!V=-K)<`gzqqyPCbvRgT^&+{oH7hp|Wf zI-h0yw3)lIj(Kqh-cU&V3FnMFq)#a&z1tS!X2TH!*CxJ&5U*UTrHmne5Iv8l8^ ze7Yfb3urp4SYnl<+vFRY^%8$L&R1T|FYlUK5fHp@n)$x0J8P6~#$?{U^5UGN*}C~X z?76>UY=nz1#$K>KzW!?9#xv4YMorhuEI)JlZGBU4vSsgNEk2tZp{WPvo?V^3vTX)C zgV)TJ!Al*?Zm~zU?L3zwF69|lwE38zR7RTZtImnFQcfA)p0Co{@n;^_mm4pw7nseT zq~K#)CgrFz-N-GOyTEsn`}Aw2mvu{?RU1!iz2WtBWuHpHjc-?Z8FC)~>?wa^7o2fw z<%^=3muB>YX577%!?OR{(<|4UO8>u)N4mBSJd9-5{vwMpv3XamaXQ8 z%s@XyQlDd)m^xRP&HQuA!`{acCI8kg?@(JeTbg^} zrd^YttlL@lJR)+Mjqi%r!Z)Svxfokja?f8nlc#;zH`y7N9xrR29~f^e`DjK(+up{C zqWg6V`)g(&yf<%_hBRCL-r9A$_2-l>-M!5HZdHck#gwA7XWr`T3*YY1sW{zze2!G4 z?+xMSGH#ls!6wJeboVa2_5AR*rfF3tUmuV6E|2w_q`Y(Su|3D;4$D}Wps_PX`Fk9q7)@1S=OO{MnSLc6wuD&|+vHzFYLPH9(lxNI&5c2h0 z)YnDE6Pu2oIpQg?`OoJ+H65ReT2=2CE?ZyI*|Z`{epAhJfvCC%ie*1$uJsI^<}zcZ z&e|h|IZP}9R(BiPnbhXQDo;M*e{zcXJU!33dpDak`Y-(1GKt}p7W0KKP7{)TYR*@? zvY8=6X35+JSrcNH zyZxT>6oswVL$l8vmi)b@lXrb+p^@3D{_pLgI>&cSJGyRiiktqu#SyFruU_zJ;mubx{yuV||&3(e(n-U9?>&`qEjn7xgpHt5_xjLXRJom%n zoJ+H^?lb;ndlKQh`LB3J+T7XczVVYk9zAP2qq|*Sm1$nrQ~g5s)7KY${bpYMI(D)8 z(tEs%7&%r|GQF8H(dpmb(_CFqUv1X!)4%wmpCOMm#(Ni^qRgD)=s)$K#Wifo98%to zh4yss`n9e&*5hg2PP?7qHrYRJr|zu~TEDb?A7;oje7?TvTicaxft<)xex2yYvO)z4 zxhKxrzWU=In1bZ0|im<|NcN->A!w&9CHhVe0q&$ecP~h z^PZ%`&zXfT*YPgS-7Gz;W{cbDdumG(Z~eSr7IbOW>pUs#y~`(WzEzOL$nwEt^@SJr zi`fc%SF6jdX1p-}rlvrFoIu8W1{PDr~pSmodnPnSch6SG{q?g*Q)o+aYyzkOBlST`=5j9KgM6ZD>uwD)r;jju*ESrSGuN4F{@{B)Y1ma z_y2RhFlZ^*de2rM6qoZ5IYlu1&hMc|QD%?Z=B3;r|8sN7Zd z`Y)q!xBs!lx)XtS!E^O;J%WcA8)o^H@E2?dS7(&!U&b-@$-8HozYAQ%ABQWQn=NPM z)#>-Xd{Lp#0w3N+FP`bG`=)2gpPBMHUTWh4Bc;AIx0tTv&)IWI>eQZNZ*^U-tYW$L zUYB#xv+t)C`5f^~{{LcK!{43fV@^A31*H}-Y&x5ISS&Scfz&U9zFhr&1(ueOs9#&Y zFHH((b!6vk->@~e*6eU@@P}x-70eQO4F&x(a_(flp5Z&)Ry4c5{#EU(ZEyB%(Kk1K z*i$aQ_54f?AFcZN4F@JmIom!mU)~??_47t3566q=v!0b#{d>J?+JqI++;hy$maEM_ z)blXDda+Udr+~f9r9V|&_J(jJT=)`Lar$b6gwhSM%Zf#=Y%-n;SNwZAY2GE{2ZGOw z=B?CtF0LZOn#r?xn^r?F%H{riJf!hAI$aMc;>}VHkI7(F`W*N-!2K;aMReY_Ti+wx>wWB#R=~Vv;F8|=eYmw zt{UCg=aGJ8d)Ga?eeKT5Wv^Rf_O0-GaBi8UiG9YV-DVq8|IYgKKR1r?_C21Z>l?G0 zocAob^=0LgSMBfS-Pmu;*s$zF(C6IwT*7y+e7er&Ge?+nj`uucMW%1DV$$}V&#qlI zu$}r*vpjOny=yk&bFze4wq>(RopvfyRVnECsQBEFN6)O=4hMf|)Njvb`54V*CdxVs*1g-iL`Upwz2t|aj@KzW<`zGj zbat=#0e7ED;kIYwA^7*USjTA0$`9FKxaecW}($=iav3b_|^1=4s_nt4GaZWz{+}>mhzogz* zC&if*CCm4=_IrL^+2H+Lc$&t9Fa5J))USTqpk#II;gpG{%LQjRI4pYa%)z-i>9YBEfY}iusD`(%}}&y-i_S` z0;-1HKDVCE`Ovo2vJw557E@7pbF{_M0#Yp(mYdZYL`Lz@#ppXaR?zoT=%IU&mK z=I71dH!#X?Q%(|g47$9)u0>*}LJ_zg2}zCzU0g-Yk-AIysl|c_c3**X3-ht=py*F<4o|pV(WO z+myTKeDZ3hA8XkegjyVurraz1xASY-X2J3~HzTq>ObK;7@TX^eD`y24$C2ZAC&zDI z{`)mE)8+Zgb*q+t{%ElB-sB7EMRE?ol?r~Vq;j(E%6KnSeVkv=-lHMtdqP3&Lu$X> zKN;2f#SSGLUN;u(TR!Lcl8{UD{{P%sns;|)@LLfV&hr{ETYGyMZ!kFA(L0gsDOBfv zUVrVD$Y0xx7`WRuum6?hbb8s|H^LJ2^M33&?$>$m(Y`%<=e%LQcA$DgrvJK~{w;Gl z)5EQH*&h3ux<*vSqx}2U3qreCJ``)lu~(V$CZDakwD~-@cW*rl%eFZSOh4!_s0RP@ zw2S&C;}g74)Zv#1$BF}cGju#AnSBQ5+2s?B?!Q%YwlfuXP|n?TfWhRquDWmBttZOU z*xW8>I8I-(<qTqR zv;sMX4!8SF#%=rJZ*H4;bxxy;W_L*VA9%e@r;!t^A2SoU53H&SzNvva`VMs*DDsj z^O?brrMhr+mQx;+=moPkNt&{$S;aPy>WgO1UlOq3id=MD2T4KG?W&hcye7Mc5zUM4c=$rgr?a!elQ{IK_JCNLP`uf-D z`+Ge@HeWweURl27)k%xoKjLrR9{L;2y8LRUM~dZxFZmpbNB^cCN;u#=J7v9}fbCy9 z&MsSq25E-t4DT3P&i=^fIbb&L^t0@wCfD`$FFJppRo7=*(N!0_-S~Np=m$-O7WM7f zdW@~^RcGHAt+*YPcTP}fx$ha~Bu#J6p8kE)*uQM5FVE)oTybp8Hc?IXZJGgxW7f~% zI=k}6tGjXOv-e*pua4PV_d9&kt);0_0oH%c>a5k+5b9bzr+Dcu_n^b)_Lr`HyuPk8mZy}CZ-l;v|V-^9J=)z}?AKeu1G_xMbi2KD|`8^Ru~Jt7@y zH)HcRd$wz^nL%`JchZ<#~7Z=v?X?&ukgrS;S=#xO#S!rn05v@PP}xc(x>Xn&d+P>;{D&}o=bYT z`KulepIGm|-O=*>dpf4<{okV^c~87z->>Ua*C$U_zI?ZZ-DbJ^@eYr#_m$QD-{q`Q zelhFG!*2b3H(vY)bpvin{ClyFC$-yta>Lhv#q;-0p7T;>@5C*Wdz76d9^OyVT(|On z{PvxDnI&7ww}{$_uWhir7WaPgrjJTiv$Yvw7l`aQqjkphkmcpY4c*@9ry4^4GTsiz zP&>R};yke{FN5~E9$Lxe$SA{d$9WfP#p^lJ_wVev$#B3}GFs?C{$ByciV1R^$5Vv& z)Yx#mF#r3fDnR3D{o}$T5=u|+b1!+}@?^i-kG1CiRQ&5~RXzu5TYVA@b>3&3*}C2A z-+MpSfX!_y`NLm`_}^bUSKZ!x-mYJMF6m|`{d}$8sHr4cJ#YkuTk#!G<*8V_8w6fgUIciY-LP+~sJ;n>&m+~?!E zU$So+?^UdS9mn9n;d)WWd*-FcsSaCXTW`+(mld1acUMy_p*Q{T%y}&7I{CSFx7!PM zzsa#xEy^yHg#Pb6JqPq=-}V%x-X6ZVTnM1A@bzIJKFqs2>b!18zhF5`q&!{jr6!dH0Cg`A4R$SlC- zUar}0yMWt6oQchm|54oe)jO{))1366_*(rh%W$@k#r;P&=|>&iEP4Ld#)Jlb1?wf3 zW4UJTmVNj#nW4Dt-`WEQf~8ZR2HER9V>r`!@r?ZHw1fMjeH0eYujev3Bb~YXTsosx zjzo^^8V!EOb+aBgnKv&Jj=#QgePw#ayW`H*%;(k=3feH7V!sylA6zr&Gi+#nytH`_ zi~1pBF$Mb*8FT$LR?TZyv3UO=*3VjDPq}M(Yxe8CyZ61``)2*$nfnhuvU;yAEO5Pn zbMlPqVU@G;CpLcyJ96N5-1gYn-j4rLYoa%J=vC&b)}-#u_bJxB^yilTO{qq%bJONu zy(+#+BXmM{XL95_vw7!l{FrtBlOn5ntD@wyHvu+UAG3NDCw=@ex7_vL_JDTbpNZ$9 z|Gt}gQ~y)ruMB<@v1jpL)h}Cb?Elx${`cL(WB+51Yf3y#lK*^DJOAGAN5!93F57uh zeWN97SX20A&RJ(O=PXy9C#5ni?9uGM_az!~ZRR_AwK% zFH6tuefs$9zeyJ_NUgO#o9#4b-{Q^p&B7ObuDAMqT3G(fX4a}_5-T>Y3a(G(+-f=b zjOC-l6|am|&G4Boc1)1Nt9Q?*&rf(H5+(}hv2xF;5BvRo`EQnR+uzcV*jT(#zD*%< zO4A(aAa`SSdmfI*g;Qldyn0un_V%ZRoME5xp9c=CckbUm^iy_@vOq==Ly&cFN$r*1 zS&;_M6E-iCk75=0f5zABWYz((p4oxL%F(O!=P@d4zT2~8pWDt(sf7l|S~lD0|E#|K z)%0om%HzVCbM&rNbZgtbkl$8&UV6`y&GSMgX-^J2blhQnhxz7XVJCjCTXD<3ctM+` zM(P3s)rBi|iI%?0R*K8HAbe_x5MP5et7IClYIMnQ(P?T2d0(eqVjyM60+rKf9l8rRz~-jV0~u>0&1a6V1jv17fA z^EFQWkH^10dl2JRxZCo2RLaesv{nwg7izW-PTMbk>N#KS@EqJ#%H6Wzlz#lqB>AIB zzCs^&^|d^(Vti$JG3BhF1CxMLA(m^RJ)*k)?D?s?DqJ0JJ2bI?8e_f?pTeDM->oAsA= zU0)Y(D*5U1KKAEHFZ|1=RknI7a-}|IPO{vpw#z*Q+ebnvM7pmW6+I6Ap=<%Vg}+(o=3d z+4#dbqX+jNZ79C_^fgPk_QRa5cjnzIuJ^J%5SNhtZ{M7__~NH|{?&U`r`KKFuv&Zl z>zPy4<5Y@YA8VK_F{}IR4ms|1*iJr+#lF|}TByeBw{!~0dw=JW45pPyXCHf_T( zHYPK+1nKjq|F36t(zxlh_xd-1_x0Df%|&*7-P7d6?sn-|(3Eo)n@hvbZz{L>!Elgi1e8|m)^XO_y<`hEYh zC;i=06`>Zn1uVHsmMUbZzx~3zWbMDH3tCw^?H!~YFSM!b5ab9DP-U9VQlfA8{oc!$ z^WJ@4;hwgmHtL7+9a|+M<;|PUt(;Sq9WsB_nl&dXcGaeRyP3Xy`}P~}%UeIC*kx5S z`3HTmfA@Of%7*TX^*@$eS>|EWnpV7-jbWB;C7Xiysz~D_e+1{LT~j(b<3QZGQ@kll zS5DvgcS7^@Q_W98k2|LPQQdumNjsi#2gtMtpw$=SJTk0)Cuhranid-s|LAVk*iv?Hu~5R(6bt#k_Pnu%|7Fg(Y=6qI`r{*AUc;#Kvm<}o zEmbqrzHi{jvv8|&Q%16`%9ekfKD!kxJiqoU$$Ja_3vxfe5+m%iK|Rxh?WUrcYJ>Ks zV~iOL3o2GDZa8Q8FwC};KQhSi&?$WZ2}4GP87k7!w$6WUALS~Ho%B?r{g;jZhfg{? zoeL}0zF#J>lfhs3@8?C)t6#q^Hm%p&8g29PUh4c!7NYrcHXQG24BThVQ}yU_3UdT?uQ3#WFCrbGCn>fS8n3hpDuM}mB;6I&bIho zWAnB0OHTbq!Tnl2KQ7JOy6>(3+(VY(O$;*+JaK>j`{4IqElsQ!0HZ*cRi$hfWu>t$2eW&SHRUAgmH=(c^=PKKE)PXDO$HL6|4#BBO`Zrn!w)X)mE z3{92R$m=hzH?BxsdUVbf%j0_Ne)INx7BSk)eSBxxtS1|vKe$l5@mPqc!sNr>&ucOU z-e0OL=rLQzTJ4{$;??&diH4ujdIatN{a{(X|Awl7g)LhW`=B1>J+)%G{ri=h82V3cy7KkUpYouk z41AoNA3GOcIPH2kX5x+?J(>+u|Gu4W(OLtM(zIaY2)*a|L*M6k1T7AxuLvrOSBMYx477G%fdAuqzdJq9r8V1`+m9W zKKAVI#o_M{lvVtzw65?~yMHxuqES%)(ycX0X-N-Hv0m>Hx?>^GZ0NRo-Qlv$x!kX( zMrbqsdBJ$#%%ejluYM==|DAJrZnk1q-$7RfflIU8d{*T*E&dX)P)jXUbgrXgyT)zy zrCH2#veTosemIqU?&+E5>sh2z_C5$#P-wOZI@s!+VzX>*yUouT%h|WBi8}Gzz{+gV z#*+~Tllk`BxmZfNtYuo_vTUy4GQYN*8+V@A3I-QsGc>mNNzXi!YVrS`pZ#*qDFqB6 zJqx!^yZv^V?iyYOlijm;9Jm}KS?}4bVl#XG5 zc%DIJZL3vq!J>PIFO~M4pLaxa%FQQT;`;I1TDLMbq+L%~^~%%5$m&*2%v)v~)_hmh&Ua-H zV5^?Oe{bf&{~KTHxH%j;RL<0~_1n*^B9m-}1vk$)scLXm20m+En)YiU$NvjoHeAg7 zooIh<=at8E_Qy{(5IPjwxB2F!eMjmJMlelS(_*+dDNK9z)9&!UyCz| zEz_L;VMevr<1oX(^VasC+?Q#bxEaaPZe-hS&wNy*v*PaQoJ$-Ar=$4OWj|kDX)X84 zMd4H=!`7LS4}zvGo3`%wtZbDPX{tv~PdOdGStd)xXd7SJm3ciD5%WJAEC2uaGie5U zg6B6D>tr8c=3PqJDhJpYR!uW#`s&pDRrv6<&cwx=W#@RWt=ed-@Afj)n2Eb@(!^}o zS^%MhHPuGJDc-Yk-8~xG<4$jH70$Y!J?DK4`vJo!$xlb^_s)#m;y%au*6iOCIM(%* zipyB#U;eQ(i1En6nI}r~pI7pIE>uYH^;)!RlCk)Q8FM~q#xl4rOn-Oh%F|r|(jMo7 z&3^i?OnhS&KAoX2CY|{}(+j63_k(vbUMP=E59<^*&6aFPJI~0V;SlVS{W$BJg;0Xz z$6mob#e8AAra1X@FV@O1S}y1mca2*x^-zDDGt-eXznAfS{5Y{bHfY9Kk>X!YZ>3ot z{r;z|eq^f3fy+wIzecuhefi&l!$YmUT2lP)7Bl;aAD+Cq#Wms24d(vye!qm3dcK_7 zcfH`Azs1kOfC#&37BT7E3El|`H&<^8&eET-?{)R+Rr6D7LN`xi%qV+l;PI@TdG6)k z@!suS5&;W_Lz3MEHONFR%UtHEOX8Rj?33)y+}2DwBKR>_l3oWlb`(PyxR5u zrwGGYfv$B$cb;4Pzk2+b>0jQcJ%^$Wa(;MV+R#H#;X4?E2wxM1QjG)Q6@s zXWmk%dbBg@cfqya69x60pLsntZu6?z)z&X`nqBBujY`e@{cRsjEB^5w-s)wmX~OV# zvyAdTjw7zKqBA8M(!wA8Jj!68^WtdT*ND{}+qRszD!8MVD_bXLKjYE=+H()ydt1nS z=v!>W2@y4&s?0ex$7HUHgr3UEtC%Yp5i?`yn>SJK;^V_!O!Rykkv2EsEboc*UG85D zta%d?V-)%;&&4eK!0^1WhDSkz-E!g_j`LG}zU};GGIvLkt$@&T-FK_m^q$J9Y<^R5 za)Q%chxzu(Pu=u2z31)_>G>lnDZ8&i@2tb2Mmd$}##M*kB|e{TDAB=WrO_j??K;gy=N9c1+M7z2;X90q=da)oaqk_tDhpMPtX{^IaG8{BZyXHj4}ARwYF zFiB`Hm53z^!xJOH0K}*z~v#3A93?h(W9B?h)3lX+O5dT2>@^RZ|M{gzGAJKHG1V9|6ZPnscvVZqI< zH{_b4lT+M3G)}Q|N%Plwt{VDl9yfPxj;l`e{N@=xr%X3Rh`bK8oaFj-tGd9Eo)o)1EG#rnj3<>{`>0(U6mDPjJ@`0R(ZF;t`qNPvM(?? z>DGDTOS=E>efTYnHo&J`V{7OJN!5P`gZ>BJ3VW6X5M-4 zvq4YMXuY)W%;F%wr%E!fz9n3n=oFx^WgBAyDBy*eBpB{=Cx~yV_LmUuYrSu>L?wQP zO82kVCbou)TaGQib(q_-ehr(j|I|tGtDoF>Bgs7B=Ifcube0+(IOcIJY__fU&)@zv zX~(vml@!udYAk3`DJ&`6{CY#%RVk($%thWw>IV!m@6-vM3H&$v)qn3K1DBQm|4$Lr z)_?owygb`yk&7>4zT96Dt>3g|p2ny6I=vYp*0qn$b(}P^iRv)gIAN;I+wL{>^CoWQ z@;H3sSx^+)f}3A=)K6q@c<*tqdq%bLBN6`_$0uL*A0np zRyrKJzBzMk6X&NHC)Gc^NZE5)=GhdPZxIEB>kiM;WnVC@G4Ezm@%isd&!5}!yK#o{ zdslYdg~^QyLbDz+|`{Y?El92zdy3V<;EJuhO}@d297YM4IQxm0@mc%nC)>qRFS80gNS*t?Fullc{g0)d4GPkN zA1a;rpQr>atEp4?8hTmSbxGB_9UM~E)J#*H_N@)kvrOY;X)s*NQs8^-LDXj3&VH4A z)d_6`WqI^v~Pk%Tm4Ons3bE zdFi!3W^ljpO*fumKYik>FU2YU=A0S4+`Px4sI1TC@?gnNrsMAv{}+B~YH3hj`6`B) z0hANu7z{3SEj4uF{d=gzvbgF;(HkY#)$uc8#5}yEW*mDZ$iPq>w6`*E&HFi@=QA@* ze|0|o^$mSn^?z52P2M}qUom@;lzMH&n@NC#N&SIc)f9wMg?@MU$!SHnW!!ACGpt;9yTE+#K|-;Ggm5d534t)SJ^8 zmA!oboNaOP(s8qVDop$2KNqu4`=WNOPimiv#NI2VmAA5^wlNt=&p0x{bn`Vev3>IF zGS69_*)Sfg?Eki;@;YM$!-t7SsvEX5l*!xG1b|z5S9LDRo)lk_=h~wgazJ0xUpm!0 z^kGQiA%XdK7Cy_ZIDW0>+z~aGujT1$ii?*vS_*uSIR0VfDTevZ5g8?G3gu5}i_W#z z-cs6;YnS9Kw^uQYJMwJK`-|6~HpR+ZKHQ<)KJ%2BpwDWp9Cit1gD@ct2}h>Y&iiiI znhX5lcp$4F-(zTX*$Tq5ieva(vlEd<`Aqe2E)%Y|qLZI?u{fw7=+WYQxpv z)}QUx1<2U&Fv-bQ=%-E8D~i>t()~QE-shpRX40e+n;5Qs_VPJkD(PDNRER<0%HLFm zCyWPVJNUn-Hav{~dwPFH_AAjyZN@)0d<_KlsQ+Y0aK9ATeB#`zuXUjv;Vb?y&byk^ z<9W#8bMSe)y_e%B|Etfbd=fl`(Jr1dA*F|%jfHQbBLCGtlRr;N6}8s<^ZrzI$Bfop z{k!zUMT?|d>yOE%O$>Y3ld?XT{nBZsYNrPlio!xG%(agxOyA!3Bt4fu{`Y;x8;v`Z z3;2`rdoKQew*Pm2G}{7DahAf|5IyO;LQIdsD)#?Q5zbv17t$Hr809OQ&ew1W6nL`# zS{@_h;ng?!*S|Br`HC2Rcz*l3@%q!3>z~$Wx-_wDTjexYf4!u(f#4dgy>9zwFvwjK zU|i}HVaXxTx08*J;X6ajWX64V+2LzuPAX7|mC-9&mG;B(^o;im9DC0mx^i4+4 z|3->?rP^oF&xX%7akbX3Zxo-d$L6SU@Y?_Tpw9NW->apPZ!*3J4Rx5`wcMch_nre? zuU>lb>^=GD_T(PM9>x`16AY&C$XroyIJD^bZuSYBi&P>eSijZjoVfa~?~%|fcjc#3 z4*f`P54v!5p&X-_rSrcn`)$>`H!g|zp?Pw8yIp?llJhsuIM&@e_UY0e9`17n4?lm_ zEqukY{Cd6Ukv%J3Cr@+y_@sSKb&megl+q73&4PLvMay5Qu8{cECbhHW*S7*P7*EE@;I zf$h30tpY^da+IuHZ3VsVDM@6WGt<4P^mxCfRFV{r#p4%|Cd;p96_*MaZ(Dn`{(08T zpoxF^sySv#dRK5=o;#;}QTEeLb=6*G)1RqN_nAtHwEQwQzOZ@Cxr#HIdbM@u7%y;b znRcqQMMaluW^=uyz?Gi~Tl?{*$C|Y)L(5 zLcscq+S{5hGlqm~sHG`y(JBz#%{^)H`f~wQo4E`)7BJlWUVECsgyF)QSML}fu^mvW znQ2wD-@`}w@_gmz{hG!KPnB#04X3WD%WRNbUYS)A?SH~r{J|Ny4O5zQ?Zcw&Z$3=Y zWPjl0E-wB+=iaA@Z}Tm7#ebZv@BTsD)kgWrB*SRMtIDAn!;w{nN7uTQL!eYkI`sDJuSxPHnYvTH2=CMUwRsX!6+3(ksS)ZkZZe&_G%==*C z^|6%afJyZ~zx`D{muz=TIe5}LZlbmE+klC#40Tp5v%kv5o{8aPiM{^lB&aqGUADw9 z#rz((Ptn4dg&bSXF{YkLmdyUHH1nIlaSx}ijF!_0464mG{r_GwsufTCCv)3I+&40d zvs$a~MyB5$%RkxWzfR9pvkXw%w4>f9$Kzz9WT@%p`1T$LnFFqIKh`PoG$<&smBe1p zI|a6l!6DRRmVw9$nN{0@4!+&-_|%-bKmIBu3=$QO7RCoI3wnC|X}rJS3`;$;;+*K$ zcAG8#r!8-KHtEMK#-MY-{KXe_{_8CLQge!HLh|)nvau=W)Xm!>;1zIqM@gdo$Wc%A_fFH(cTVUt!=o z?fd3eu5;_ZNLI?{@h=h=yln)osjV0sSYI4FnUNY*boTnI?@C4eyew)0(~q5)J#pg{ zv4cGh>RmgF9M(>^d%oxSoF8}2x8M6e<>LR9&#PZbnfwke`1P~4;nB^R?3*HQDy;ao zG2vgV$VKi3ISr4)`iH{vdkp{osQ>N$HZ6x?!A(;}2BGST&hwkYx`Jf`nwTUt4fGjL zsJvRgKYindvyBa=OAcK2W|^oWg4NK9*Fi=l&Fw6Px5&Hmm%f zh0xU#U5{<^O>5Tu`>G{l|9^@7yEp!}Wp9Nh>aR?GmLU1qV8MZRr#ZJiw*8%Ay7z|g z4aOTz7rHw#Qz0#Fh5%WHI*}9Z0@V&C9q%&VZIPc}_07~P^pGX*+FKKu6Bevm*f&$R ztdLRooZG+P<95>pE%F7_bbuJ#kv1ZoLzaF`BR|F zySY~By{&?eMV3ssU2N4pP0W<>0bBd;-|Tx{Su?QBeVf>G)WBj--POYq%)VB7LQ@!$ zJ%rmuwHF=ojFp|c>?gnb`_IjF%N&&0nVvqcDVjMu)zxO==7R?>`>8xxv*^K%MV4-> z`mdQr6!N(o(Po-gV{goO{dhxz^K+~G*Uo-DqRbk$x9#WXF6TSOv1aQ(8!g)jW{*`I z{@d)_vexNeMdFF8iUsF|LbV&JCvAWAg|XrHx7qe4$8t`C2ksaoy&0?<-yG@xb;rJS zvzM>e&U^k7x2-ApWB7@6+3Jvak`^*I=WB6napACW5!mxgI_P@z!C{lRY~|1pX0^Z%s(&tzuMWxnvHOUI+CsKJ3zL;mH% zXKA~ZJKD~?(fRRa+f&xi03Wr(ctyi2uAUcZ9j&VASn7^&sc3o8iWBpz%gG$4twETm3(4NyaUbIG~hd z!?2-jmy4&_ndJpZKc{T^D){%;{No()q5Rv}Xlvt$r4?lb2_X*xUHiKZPn1 z*P57ldnGO~UGO2m`)y-L`(l2D7-_aEpc*iLZujE-F+Z-m?|P*EV{PT4>mF~9Jv?MN z^PB{C@|lBXs*OG}`%>O=W~( ze-!JmrA=a#Sol48-ovNnY5%!4+|0Sv3hsSJmQ=a%96Wxu-d?1!f4=A#CzW0=1>|6j57 z8RhFKM{U2X={tU8+O3VRosKAkUp{l2lmG5@^)!Z{vh}G9>&{EDFIdW;&=?!8!>6uS zv-;S}w*N=(A1zyYQPg$jgIPb%pZU2tggb7h$N8%tyvzRYxfQQ@x-02TmLyx^L(@vL znaxuC9;UMw-n0_<8uR^fF~hO!y%ThzZPrab=$F;`byY*IL;$FC$#3m`r(eCQ@NufjGpH;GNcjnfA&D!>7dC?+c{r>Ma7wpw8 z&hgKVVSM2CrA_>vb;4cU@GjQEe{rhkD)g@13E84#aP3xEaO_Oe6W^50Q{OI8;rt*Q zuVZ;|!p;wVx~^V<0axnTMCS^YxFtMD7nIH@dKbBQLA|b)(9&yatgl_y1^l&icy#Li z@tniz8@`>sVi|lgsfPLby1SFV#~zxx=3T`9jeb^VI+so{$kF-`oKnemw5aOOq<#5U zKB-1H_@6Y{SkrX>eZQem+T|Ig7v~h$Zgx*!_%Lk_o5mZ4x2(sclBK}oDW*5iz5Nix zaanSIh6Hm~#FHgmThdd16}xL6?fJBkP0pK}Pl-#A+1%#A(`Cm`zh#r{%uRPLS-;>% zX5&iFi|Selj}$~K1;QsA$Cb2woZB95ndYI@th(|-eZ9i0>4Dosr~X>FW@ey*a?c6z z+;h5*HeI^w!^zv-$@^?hZ|jD@u=)>GBAc(wEZDT_Vb6{$AJ5AjbP(Dh%sE%#_|;!o z^Ss|E>=ZEJU#e$Zwx8*y&e@OE6JG4%n|)U77)Qy1`hJc%LQcG|ZhdZXczDKk)tuV8 zLx#~mJRA0MRdHBztzC8M{l7=|PptocFF)Ek0Tj^(J$O4`DHL~QIo(g;(O<5u;Vlrb z=9s33x&!MG?q3~N5sX#Iml6tRrs!^FJfvu)e)a!eah7j$T;-xa@NX?C{Q2QkLtvlf z#>^}G&93Sltz6yUAX*w{a>i=m?cPr>Z}6ydT(+^gq<1yAzm6QOd{mQi_xGty z$Ca-int5&Sd99bfPaf2q|K;3#tN+hW{(3$!TcO=3_Icvoqp#)ng)}%as0VsZd9@^z z0W@S|x{P5*_)~@pl7|CgV`k0!)^W^GGWZFL)7?vb-1!rkB&KUOP3}0NE_+SiB8HQx zPxHC1<%7d3b1Xk!DhSoSf3@7D;c(^2VVI`bP(t7M<< zf8hR{nvz$-@>S(Zb&JAPp84N8qEde5XU(Urrq>I545k`fI}~BR)hG0`lK= zt_c&0IkXn#ib0xAJ%-JKKRF)sGu&g|!Ms6zLv5FAf!ad+vYn(jt!*#w1>F zd-)bagXuYmVr`}S)eH*d3~VZyv69OFPbw)Z|9?Nleg3_N)gOi4f0@H)_o=b{jnuz%`0I}8^MNOU2)giz++t36R$~_9<%FspsY}?bfbA6=L!{3@25tO4pnpQ z&yxvQwD9bSeuK~zR_9+Y=X@Iyw50X;(3X_ zwlybzTI4*{3&!DGm3RLAeQELEklDa4dA@?;gXJAeeJqJA*KTcF0GhJgWyBzsqY1->H@DtA?VjE?h4*B*QiUN;UhwJ5);r81Nl^-vav+iIJe$-;mqRO~Qi+7IPT>EcZo&DA(xx;Veyz9jiW>i=96!AXUv%&9fd3=|K?)S&?%!OxMCa1idbHRLV`<&oF zHjDhaBbS*xlY7*UFXOD0I*<|ad`UIS&xTx|=z22mPF$(| znj7x@<}OMvZscswb<71drDtxv#=~r`63$*4{$$l>7W0lUkWWhXDoX@?-_r}^#D0Z&h0I)w)i}0t=M#Z z@~-s08(!Oyeb|(5S2UlUpL?iIuQcN4l6|FjEnZ|B8}S{~YFsvHp2_K| zYi=3Kd%Nb<9Qw$!#Ad{Wh8>-sb1!p1|SkJS%qQ);VYU@2uIntGQa?Bi{pe2L2`T zpAJs_dC<^QpPSFR`1+TXr*_PchapP&;Qp< zOFcAW;m18J4noHyBtE8^>aVo@_^e&-V6l;|-WpzOrtK{6LQ5OA7=eq-Q+aWB1eQ#a z@p#85$zU;wxgqiDroa^&rt&N{oU1>%)YIv8!2R!aiNWT27BVZNG8NC%9o4!WVBJ=1 z%$Pm*)^at5IBpJ)%}@EYxaZkjeo$a?I@A16&tt3O*0!!+>T717`S(6LapqKJ53!|2 zg8GM))fgI1aC@9ouM~MYG3D#{3m^-2wzN^SYF+F&-W-3G7n`i7T+@6Zcf**P$ z-Y0M-)XeAiNMh07aBac+-3$y{A}**}{{Q)+qfyW{(fPc_ueDEE=3Hhi`0;$XCS#1& zUwfskpOdQ3)yOMMQlE4BlCOIDy*1oSo)-_E_Xs}M%viTg=)kT#UMHTQGQ4$_wRk;?Q#%bFvYCtf+pE$p&IH2LRZhP^dkcA7C%2}CnUS8&`1 z&9_`nF`s+)OW3}ug2VbpzS%c_*xIzW=~w~Jt5YKR@6?tiJnnz_#OnR~_{$TlmwdGS z=XL1lytE%_i+-?jym0Sze8|r3*iTJ`c@wqfAGI)ptpzwZnc=*ldfb6&CnNT2-ssLxTq{tKxTm;A zLCF0;bhm>abfWbCxpK5_WI4#=ya(6;LGkq68Ej7 z1Jn1M-=m_x@EoIKu5sgs6+A~?Ra&w!9Ws_MOJ@ASvfb~lxYD<$xApITdvLPYakeSL zg*Th;F>I^e`Epl0$4_m+KO#-xTyLj5tq?T&zb}Vh>M!qeV}_F}TW-YLFkIL%hm~o5 zZ_xg(CmnzH1pc_sYNHgXWTJO1d1q`>)`J(%KL0%%rz>lg($kgl#;8NMUG-an?v*X7 z%*>6eV-GfaTOHoWXQw{1x@yKw2buM!UJ5gM%&eDx`XuMGvN6NXJQu|e-J8nJHb37~ zb3W!tb;P;~-GXRyaYg1$A`_Uz=gB(=|Cn0x*KLA=TT|46{MAd@>>RK1PMAM6`8%(7 zMh3$dmF=&7ta^QR_3XFZyiu|XK#N*ZuiXl-z5oA|#Aj~hXWSfd6K*h=@DwLK7kaWY zIQD5G*RpN=c^p-~4B3;~YIe3=xy$-Eykv{(>`JeXvu-Z+P_e2^t8B4p(hp^GpLlbs zR`blmf(FGc{_adMQZgk%hxc*KDL!;#$*XAV{X4(c9+D`yxp31NFVXe#VH0C+JzKM1 z{9MCbZ`l|IlZTa_tp;oY4D&0@-8P+?5q?XD&*9VZ7fIsBr!y!-AJ`*cD9zBu9BP#r z2_Cy)Wq9#s+v{EWu1|Pb^#3sT>UQ|*Zmjd^c)FsQ=jHhu$3*5%+qi9pfW`E>>ObRgKg%= z_NY`kKV?f{Z#!jW`SNYNl*?u_J2tJPNroG?Iln4Dc0=`t3SY>)bE=!gVi&eN-l4+m z5VrL1e5X@CBiP-3{$9>*=gr*K6>_;qE{ln&uRmd)W!Ow@+n5h^NoO)rTh}jOeGu|6 z>1$W^w;Kfq+f5UTh!UT!7ON; z>7Sx(CX+K?t_5-J%oBdB`0vJi|GP_rB zqa){r{**sEPMqla@_$xc30D_K9JA#)326ogJ!RunzP4ZJu*bx`8$@Dd zZ~if!WLC5*>y8lbTOox6zk5Iabkr==Gn&je|H!Vd*?aDMn7{S8mG~~*^)H3k9SmfJ z4c0HQU}x&OFWMw3uFsTme!j?4i%b6JLazFJ)qirHDIme@*y5ef(|8$7X5V9oRgb+N zDR27Zmz7LvsJ!E!)6gXK~|MW7r<9;aQ?FM_YNezsi}#J4K#ue#iKn!}LkR zWS)k^Id|vv>g`z6vf`o1=>uHf4H}jmnknWvNoVt?BgbRiw!QXfFlA48>nC@vF17C$ zXWz`qmyRkYlAk}{afU}>`k}m*J!!}1{VwB@V%V@vSlQ9jCqQTNk*BYAC(o7@nBuE= z?7)n5uUx0=yju5r7e8~WbN7!KyHd@J?S9tM>F21ikv*Ggh9|vBa zp0gt<;f(rGo9^SMLf7leUHw#0q;%R-O;-L1r+B2S(jW0O{IIEfV8`_0$)EFk#LwMu z{=a0B?#TE86DIemaj@`Hruz#IXzeCbYz#=b-gy_g>@;0tF?~&a8wIum5`R{PLtXk_{rS= zv9!K|$o<*BZ>-T|5SrZGR*qtJWiP54Vm72#!-KJK1%`Jz>m=O~vP`);&* zUeN=q7fYVicT^V5dLON>sPoWDgEQj4xsXf!oLvhRtW zGYKr}jDGahX3oo;_Sv(g%@{5)IBeG5yzl+RQdw6PE~Bj0*~ym{Ebn3v3=n5yXuY^h z?Tq!(;)9J6@zNa(4J|MyKP3yaHv4>{xw(1X=9ltEX2_nLyUNN?Oif4TjAvYb2$PB8 zUw+0lEg5P#$2k(t&bajT;u6nW&otl4mT-mScwElD+gWt{jiHC$eVxyNr6O~!E|^X{QLBFE{w$;L=^NV<8$`LY z_n!G@z_WqT;(INBvhD)CFMnrW;Wmt`Z+vSdA;^>W;dsXRP=`5x)-aSYyko3n*w}tx zt0;IKDl5ac+WkK@l(q-(tXg8&(s3|#D#PLho#JNUp(~0PWOwFbUojp>qe3d?P{`6&Lyz3{sXTOUV0uvcxoQT*&P z%kwDr?@A4Z+Y0u1$23g#Vo*OPe4;*{VZuyflWJbIzNZBrc8D>|S>#k7@xEz!^BwNv z`&MyDH&~b~yYsTqt?b^eb{waLNnq+SF{+4%{#2^y3(~amqAD^Q!3eM=JSuw=gq4yW~gB( zaQ}2oVzayVf6(TMT{)X?+H}l#ANn&eLC$H$f=8$Oo&`Lq*Ww76KJlMRg3E_TPrd)V zSswrR`u;zv|2{or3}N4X-+4EqlhexwA&N;(XCobjcQAh_J$K|@ziC0nrHAol*QKO* zOXjded9;vyr@qB9PG?_0!U+T|1Jhtn< zW5K}_yDzw?ExDpFNpwYJ&*yrPC#%?g`GoB>)~>44zjn{@3F8xHR;ME6$V1;I2tByPdUlqMTD-zm4kudPnSKvrL$D(ixbm1URFkfNgroa z9WAZ>!oR@SY@%J|k&ovJdDVXNpFf%~=emt$`eQS<2}OHY3RsSwQDL6e+Hm5fO~a?n z*Iscyv0>W#V)IHrMvhh^{(};++2&(4cixuoFFyBo-D|V|(>ngN9N=D+cgd@=@r(U~ zlin(ZJ8WHSlYhRwZT{n`eqG<+e{%P0K3CU#KP&&?-(lHbXL)z!H9LwLH1V1-bpCzE zn0Mp1m}@fQ#)N`j^SBdgZbkOSe|eQ5CD^b*LRaPF!K_CjDhvY8+0F~y;$vo5ZrAL1 zaq+qOb!Usb_*mwAKH{FOyJl-^aM`)3LL0M9Ih1~Gy0h}p{T+AjEEJ3R&B39PE$-r} zH1}{ywk5;yV9BrBZGP-?E;_I}nt|DS8u!d8#}yflrfqiJely8j;QROQJNE89{O+OL zHH|s%7=_~Nev0Ma-`6@rZr63g;AEBF`+ee%?#LYN`7FF+GU_1*(SZ< z{kwO0@Ann@{of`2du_*`SrhbU>c8tR__fpWs=@Q~lYf1yW_SAV?6m&J@Bi=C^WWcJ z-yi?ym-&yo_y6eD{dmY6xAzy*VS@#?OJ3~e{r21T--om25@o*~`ivxG7D_w_sg)LC z?9J0DWPa3fg@ZvLijz^e(ZTC~`sAwu#tdqyTuK5He%KmjsRo={=q^!xD%|p6Gjo|y z=`o$6(5odeJiFKzA9`qb{N?xR3yObJiac-1G<2vWMe5vNQY^@toy5kp@825Dulzox z3~sg!L3Nd{R`s84m@>0iWwUNWvTpsWKhI_BG&PR?{OeJ?Zs!5E74N%B)f84R%e}LI zbhq95&b_+_-^wpI_weCAzGcFHo^7vhyZ`UmdC;lsOy%FLYihn5a{iat7$AB6b?dQU zLzjQm4BuJadA_sG-kJ#>Yd-a+TmRmh`}Kc*G%NpOI8pBOIWU2ZiEjaO!po(0t3~o` zv%dVe{QeNr%}8#;rr&!Hzu*5`?)LQc8*bit@cz&3dinVOkGB8V{r=wL!^fj@%%d$* zCvc1L?6$pE|A*nZ&CCls8OzJJ7aX3jXv5vS{(jJ=wC@FehC37mmYKZZVQ7{%c=LVb zVupi-tE6jQnYdhB$s6?NzLn7Kzjj+9N*8m*cKz~A`n&l# zPIulbUOn?e`KyHPi`^={yP{Cv_1r((~O~mY5qr>%#7k%5e5OlK!&~p z4j&v3*6zQ%0ang^_}2Q4tybZTd+5IHCgn_@9g>zWYCELspzSIX>}IsdY|}ju@Skw&;kU=u zJii%ZuOF0XZokW1_v4|goSd9P=$pF@zuVazMAbBS-<4V4xqm-Ve$LKG65pzMe#^2P zIefTz{c@?-ouLcA=Iy`#`0nmuBPYZr8VRGf@QI>+q zg0ENos-0-J{E%yAL=OW~V2CEODA(7u$&u~Mtp+Db9y{~56z2)uJlz=iso3cBDKGuN zfIIS!Ut3KQab@7sygaFL#+F{e;#n*XucjTIqr6aRs>;ltpS*lL-D=sMG1fE3$`dTElt?G_h5eA@AMzv|2Nk+{BD>1_u*~%jWXN3dwB{51UM!e9`EP9jv)s4cB2$mu(S$)n*0w%vzDrhv352j=^c5K zapzI9_d1uK?<0gH=kyh*6|dR4WK*MO&7qj+h1Vhz?(LfOwtTK-!MTGgn3iutU)OgwGA20g*;CoL?)8OIF>`bCiod^1bJG9Xrr0bz-yL2V zlykp)$IhJxyT$c4+|9dKYNjN(r}8hCe*B)6x7G(FJgz(Ew736l;NSi|faBhtze4qY z&Fi^;I{O7*RC#c8!pn(XA0PEhiWB))$q{eOP%aS9v}0%G#X0q$+15{LFRHh0t7dr8 z_+-K{rsJ#?ia{2#Sx;_%$@D7iYX2=eC-~0&-!E*f{;Yd_;d^Y?JJpG&|1_noU9kDy z!aH~FJb3nyEs3Y?uiUYyoTfV4(1-8d2a6q)kgx3C+IixdLdw!5f_;eJQ8(EWXUy zKk<7`LcCiUxh*zX1f_5+jZ_%HN*RdGxu6|?C|!>Wqu%TmN7}s^qRxb&9}<=`ES_1 zNjP)-%C#rTde)H#R5yIgO~3G6mZSY_TJzbo$wz|LY>d;pI%7i6*TDG>7xJre%%de< z2XBsBaN>#$D5-k?nxA` z-**GjEzUL;eE9#z{r~#sB7RTodhhW^@PNCZO+$s`^W|stFQ}_AG;L0iF;iLmY>(Dq z83p$EW#5!EnA_K+NnM)5D8gX4s7$kqxyCozbx z$?^)G{_D5Vrr%3bcFkUMcf&rppQVPHLVdSqyRCHy=$h@hUp+u@2k*6KHLXvD8nn90 z4r*3#^!1-f(?4@Je4(G;fi7MVZ%xluNw?malTNHz-8n6}oc*E0iw6#Uxs!S7PxJ6d z8ooGGd1kZb)*>b54FZ=NSMA%w{8dJ*E$+{RiCV@s5ASgt@OGZon&-gonE%)CJzM)< zg9<)|2E{*byu~K9tXJ_lJSC^2J!Q>A=X3R1*1GNT>6bb?xLR&(*$Q5o)W!6m$FSV* z=U$F~94FZApK=?rM@=|%?m8n!Ajj43;w<`U3LC;|yzce%b%@-*)@Jeg&g)sf|J8py zS1)ntg51>!+pbL%P`@mTf)oAPtsYoxfvgTDVO{+r@- zTbe)2X-eMF<&&&mpB5E*bx5(2Ur?V##F%BD>uLQPg6N!p zCD8hxmF_x8VOw^_Qn#i3T}44&e9r}+UfM9HQhol}<>&44d+r=hbnq(QktV{>5O8eU zv6)70HuGFE)|?8rtY;MZ7w5Lmm4$CodWwrvdB0$ zOQ+}H2I&WnZoEu7=EC6W6(IY9?aQ&x2^{lpUUFgjdcMhYUWml`HV850*lTY98+ZmAIzITO%dEee(aH*>!(nMM9%CGELmdOuu*V{fklB96ppm(CS z%9ey@H~TH>Ec2J1VRR7t8>}{q=lCfG_P_h<>yG?jl$yR)96W8jd}H|fxJSR=-)k3I zAfy|GvpJ@X^;BaZlFQ%XkK~UBFm2v+AB>@O)dQ?v1CGy(miP`gYc3m%z(7pBPpR zn^1kZ^_;TWm6oavd|?R&m#=%=oPI%W)spjK7SDGYUdy-Ul-4v_pz*XeV732=lA@=| z40{<~c$E1ZHkt*RtCC`DXiQ*!FtuY3Tft(l!&S%LDbKCQqqsKY4Udv8*xGpTPKwIMK%A!>ozaBe3HU0Wu zUEQc`!g9W5llcuAY5Yd-+}QLUl^nkKuqxG7IB1{U(K9(G_`0_3w)rLdv-4+0il)eq zB<_b2g{M;-{Cr;=7UJk&)Rc77(7&tgbMD-Y%>O@Ae#tRr`_4SK{@1n7yGqY3ow47a z*JsDGI;|&LrUZO2+>)26W6dm(_2b^n>`7D4wY&fPcx#e_FJty%HHTgNOcfk+MZCW5 znc*EHea_9?uB*BvKL4;GViu;&xSq;l$PceJaUcjfHloOtn0w-|1uSBfPUzgxw1J&uhPk`<^`Cq;aY>Am`kqK;hO>74Z@>Spvww5H zr0lb4=XRz&BJ%|&>~#G%XV-rIB{lVbf{qAomyGUO2kQ!04U4*21Ybio-U(K5en%p1rToR!=2`6oG4evpscljGwGgIyLQv z>^T;;0)Y^j`34#vXNaGxEz0?5HOZadd(#`%)hgv}H!kr{VLd2)a@K#ua? zF0BWZAL=ZM_Hrl4{X4PKF;JCiemiS^KO*_e*|g1- z-bbgedZ&6d=ZFXY0(VozZxfDnl|5k z=EF=*E)R#ur)<+>qOTbqkUU#IXYbQTO!kdy*|^=0h5w$v^Tn6xb#_&cIgGe6-n>5l zPW)HdxhxMS8Na!6s_OhbvhGXot&}>Yvd`CSwOp#^|A4fI9F`TA4!1WS^0%AqJ|RS~ zP$`$qftlg#x^o_tQ))a+Z**6-}2_LFo?%oH2(KD#wy`$c4Wvp z@g6&;$+1O!i>stg&0m@lb6l^%(EEVOnV{XiNiR*s{u%Fe)AXn-dIpUmr>w zTYlU3SoN0!#*?2dJ#+-N7NCgNMn5ntonce4`zkF@Q#U=Mqz&NYzOnZE_WP#}A3oe` z_-yUgXUh-Y`^$1b+hNxnhmx!<1sX}`t0$=!UyA%27qL&jy4Ud0q|=Wk7v|)3Jo;4Y zpQ>wl$lJqo>38q$-yGHC0|tsHDkk57viCZ&okka}V)uBbda@x#lx zzcyC4KiwL?x&P*b1zU0@qdk`2wv+j(pT&9RO8Bvr)oRSSYB7&z#{K?N>Sg#`sa^Q! zhh;26OLOXVFZ~r_Q}^|j$bLUtb)S31-HCU8?^Ij{*>#lr?cZJgPyheE-oK@}Sl>E( zzu3g}p+ChAcqjY3pSgE>?Yiz&%TAc+Of-~Qbmjf&ed~i)ihEld_xgyQ(ODpq{KwFE z{;Xd{(@bmC8k19|vlmuwnftxd+w}BO4hHx7+Ax80o`0>?PjG%X)4p^4-XqGkQzlU_&jrxq47b&BP&Xx{u6_};@vcd@sPo=Rva zyWytyzt=%G?Uj{Rcjwpr|Gn=0_Vv5>{k|3T+jONqW3jSQwBVN~RqHqG({|{q(f72? z^_t-%>BRkP<(K{j^#@ag!r4x!cH8wQb-%3mTGo*haQ=(wmE_#j99u+g+3L#9J1?lQ zM7C?&ZqeJ7Oq;In;%Qhj&n?#YOLw2>#5Jb-_w0P`;K0N`hf%V4vxLRAn7&&AYy1j! z>VIUDFgA(0Ba`f@vHtt!UEC=ue9NYUG~BMNRKG8FE%yD)*Txg>OuWOm!#JsI)hb6GM6Vvw!~{9=r8#^|`YBFMj`9&Jf4&g5`zB4R7oJS7RAgbHz!9Rt&yJ%pSb)AOmcR{$^bc7C94Ih3DVdvm*3=OR46;HM_34vb!u57VxOI zW{~&XC!YOoDm%Lsc;c~mQ~v)C)juDX-APpb?wXNbpAQN_lgd~l9a=>&zh6Pf{sM~O0anr(Xl8*S*mf(rYT-LMz_D8 zToba@u6PRrlgIxg8QFhvF7LLR&kkb(ZwGCe!Ue!Ke9)IBZ7WhyTHOP%&fp0myF zMz`%9BRMu!0pE$K3xf=vx-DB^G~eXK{nrP5*UH(Pi{^NsUUTn7tb|8yq{;04$8yp& zJ`4W78E5)jZH{qW)xK%^I)Q%_7sn*@j!s zznSx7x20fFPs-H_f8TfWN);HAnUtJn*&e87*sfH>esJIIFOWsQQE&eK=Kpl|{r;DX zpKr~0=bik6wL#ix`|N$UZ>@VRFIVQcASZ6#c0XRZNup<;uLv$JTiAK3GU&I!#3F-S zwT-71td={zJ85J2{vgBEzZY&6+q~p~xiwoNtM#6LcS2tG-sP?2IBw+S9cS-9^~Xie znQpNG8`V=3*?j9IRVN$%%0IdMFt<^ejr+uzSts}xNY*=?y55y6x%kzio|760%3J>( z5ZoZP_{mn!){~*hbA=q29qxZ+)4o4+rd74!RI6k@sic;;eKmQnGxO+EA7SasKbJVYd|t%z)Fn#L^xBH3 zgK}$`KsjW!p{*;G${IW7FHr9 z^^PugV4hy5_T>N11yxhoCR{nLzp+K}==9OdOLc8N*^|6UV5Q~6`2QvR zOsbZrGneSK8tXSit~seJ{x0$6zCi15CZD$NlDN6;^XsQ`w`d!CtoS0;@#>sbe{&?e z9qE;QFxe0ThJbpMa~YQdjE zP4ScdOf`I_Zf~gY%4nVv%j#8*X+{X6Kf7`xx^%4%ol2% zQ?>sL-_(R}mM#|?B2sOqUD9+}C#}KA5+J!OguBO|JEH5g$JSNrnqRt{U;{Tdc)x|$ ze+~ck?b|ojhWXr2wuk%+IJU!wM%=rR4OrA_ja9}ep2l=xnyZ$uFAHiIpsk;GEytX%D0~b4p7?~h-J*Em z>)(NCc5{ub)h2)9`uw|4lT*F!%NA2Hk=9c)WP^^U*jZ*|?B=`edmlW;`|VEel0TR0 zKl%Uu{rmU!+U-Amub1v`J#}5_+tt_M>+|;g`?dV`-MrPkv{(IYmY2#NH|E+ES9X@@l5;T&a$v#~Yt1nH6=g zSa>gU{#vbh;8NDtX3@7(#7qB0s#tPHtgctKh$!cI&3 z?eOds?~#c!nV!}LH+8*<*c{0?`DEP;`AQvEHig4eBcrpgy%#to{BJ z`FhtoVJrW3i|ap4xBn}dmlyZoZ~ONj5ARmL`DXp5o$>cyxpS5l&($0h^cks zO=e_JdR=)XCtanlGyQ-!8$N4$+zEs_ibJ_dAfdlQgv~&{=Gd1XPdt-++Tg*?_uV5@855{{r15f3tfMv z!`0hwhdwzVvDE!hLWZ%iP>9!QgSLq*9Fwm;GF6(=&4!%-ZRTQ z)*idIeMkPkQr&1let}1i{)K#ux#*^F=GR;QPlenH3!Zeux-3+@%ymfh>hHc~zam}l zikn!rNj%$9!=LBBYNF^?aoN*O69RJ!wTzayCZ&rgcP%h$dYrRM<@AY~DGcWv6IDMQ z*(t+5Ddt0sTubUEHJkDl{l_a;31qpZ+%EstEv~<9|Euk@?YAp!x|p0zWFYF)ekNu{a%mdE&U%{FW%%k7O`i?&Vy&qidCB@Y`>ql{dS^6o6;ro zV+|^GKOVBbDcc?LxqoI;qQs&7d`o_rR7ljUe|5P>>eu<&DN7wL1#+`CK3MTmdPeY* z*_ZxJI?pjl>6fH2>*Gh!Y>&?Dy22r7EF|CWdUmIsW7zex)@ofWhgcWKSU%jVz4vQX zy2fjlSw+YH?{Ks}e^_npVk7nSXI4Em)Mxj(%`!9d$MI@|O@gdkVlfk}ybs^>)?j&d zxBi5TBmbRnpY!u4u3>pL-`h}W_S>@N>+9p|KmPi|2pBi9P=aH8c(UTF|VxTto)KcVSC8Y zUHduv_WfHGc46|OySr42RJ_)4|G#c^)I(@MAr5nZL1{P{UgeY~-`n?lmUQ(B8USGvsi?=fuc zRB^m;T`i=!`P>|PC;Pgbis`v2JzZJJG7OEj}})_6=*HE=V!FtMBAW5@0f z@m}Z6R!CoV>pQ}6K}i1LgtUgs7yK#}859_N)^S)^>DAv!u1@C-bNlBpcSeNRtXcnm zpA?wwdChrMM#Z|lmn4|8eZ#KJnkQT@{VUMg>P_(bJqap@pD9#vC|KMVHxho$xwc+; z=Qf+IN=(_jRxtZa``_{WD}H&_K9d2oSo{2yfA9aljz1;;??W#832DL4TMfTyJH&A=RlhlL z%L0$C6w7Ugdna!9Q@R_tL0xat<@=Rx`=|F_o$$!q^KHmplY#^%@0e*qoLbj>Oa(bq zi~cyLi+Hja?VmqMd<)mTz18jS_x&O%V*7pfyIwD!=f6Oz?sx#7 z#A%spZt3qG8#oerTDOXA+q^-tp~LTB*}w05-(HZMea^9@=~|RTc9+;jOZQpVH(xev z|9s?@plEz>x|#IFw#z!&n?NC55Z5oSC=zjAeS?E`evF2f7Y$E%?1qL*?d0DfhFW<-S%d!g?R@av>gzApt3dI zeRk=QnfvEiKl=AS{r%mll#`o2Z^&P}SJ`;=t2@8$T{d>^esW-$uGglMhOCZF3^&zW zCVXmUJY2VlasQ9+KVt0`_C_4rDd%AEvoLu z_O0bEX{qMzPagQVJpN)ib?Vfqk{grPZ{7EG?fcJ~j0TG*xriiQ6S*Q1bxUY-LbkRi z(*d66wrkjve8Y;Gg#N$%8z9iVZBkzH*5=(FMcY~4vNzRxvMA2gXK0jJ-XJD8$>W(x za=OS|elE!n(~mAa?#>haR~)ogUn}G^Q{g4=B$lX_#fwhOHQ{tvc`Q&>;@IPk!*%lE z>5dC{_BJc+-J-_W()&F@e7&XMgE_~qUggW*`_*jS`t=WFo-Wf+xvDfy(_5I&U>-XQcXM2&WR3&}DSmQmz zj#rk|N~{+?Prg{JmO)g_)xnrg0RL}$ITcR!zHzqI0py*YdRZ>z#7>zyvlG%ge? zTRuaL_41~fp?l4wR-AKJSgV|{?#~ptv~$;Q{cKWReV*InnVWazIvZ_EFDHgYF?B6l zuFlZleC07q_U4?GZ)bg*WNNo5<*ZFxl&;zq$@MvLvsW!yx1h^PRQGR-QGnBCg|6Q6 z8*j@#+?&plu=!@f2flm8Ww(8^7(Hy>FL`Nu{QJ8Z2ld!~?ARArq20GKc*dNd-Hlue zCtNZOHxg>+jGQQ9Tuld%?=Cglz&CvJy z+-^07*B_M&?%ch5>7#*_=pCNJAC6f5m+-n>b$-6ObLPr>w-;1s30ib=WqkEse__?K z2lH#ulQkF|1Xxb~t@ZP8sG9p_@8KyYTh>bXHpbWJ+m zybkr>r?~r{1|CrD*!6#>&!#uOZnxS&^z*%oAL0+pvTeb8A>K`?GM0rmVKBStWyuZ)W;+B|)$u`A2Q{@vq zcQPk__kHi)D|p%Gi&kyO%(MKI(6J3ehSY*4qh+o`yR6_Md_6B(eKlm z%53jX645T6tu%?NGdkqB7Nf|LW*?)&UyDVKtX*JtD}pgap*L+7^Q;o%ob1M)|A~F_c}5?l z8En}~xF@h@IDFNx4gG(f>3`7IZ6QCWujg*mI{Qccgsl+6W{vyRA${dtmdZS*XDb5irbDE zFN_T4%B@%zxU?a;;IUIk$vO2yO3N4IF-3E+-0{{HesJePg!T7MhxuRT^8Q=N|CZG>JgG&v8MxJ_xgWp+}CX_D(Yzl9c(H$S}G z*AXRk=cD7Rzf(@u7kX{oCiaHK%SH3j))cdIb!HPi-#1#%jCY!Du)vU0A^75SK{w$$ z+Ug3n%RaAcx?-gu`f;A6hG5gH=Tm=9m;IQ}93k8Q4ylvQp)c?MIhMbxa8BMH>3dC= zqF4QrSiq|{ZPLpp8J$v#VtAM3PRM)qZR@6W$qm~Vw_a*}pSeruMdl8*7)brY!&AVUjJq*^FQM z*&grbccl`aiuD)wXf6qKEGSf5lf0sB;(X`gtl9}4#k`Ut2b&aBKc33gN^#Q3T>0s7 zRAI)(KH(EQVhbkNIbN7ivAI|vRNXP}&#`)kydTl=|4-%Dyk5TV4}aX+-5+K#tT}%F z!pFbwYg_)-y>C7teEgS~$oY_$Z5+2l>TRYtEScnJ@cRDo&Mzt_g8x4`zJSSfMSr&1 z57rE&JxAy5FS)v9ibK44mEp<8yHi)F-b+(^Wxrq zNJ2sNo1LgEgYGf?DNO}op{EzuFaLF~c7fjGqIF#2p{t*~x)wI$Ue3Jf51v}E9$04T zcsJYSm-t5SJ)Ju*US65UzZG*L!)Gp^(6oQ<8iVtv-!>LbQ3<^;Nxs@7q0s5* z3y&iSdJTDxsL z5>0B@(Q|&<#e*((0t($3+fN9G9!i>$w&B6PX(kQ9x58G}g?v=BzMS!Y?g^GYhNb|e zi$=zK7q--!$@R-K|ERwfTLCKJ@?ZQo$iMHr_mA zr97+`PjXXOVQ}E>jd_CaHTTwgf6IP;ZF)}a^rro-6P-J_()}3K#Gik;dGua}TIST5 z@3vhElD6PV?47m#^z&t6Vr|ZfvqhUFlPdbI#?^Id+<9dEC{mXBG$%8M=vEIWC)Jq> zOqNaM>kgf`o3nTB#_cB>=XRc7;kf8-_~zC>D|hCKimZOZeWa^s>&b3AuCEJa3Ytsz&X$NK}p}#Nh#IJ8$G$+=uLVUA+onvQ2NH}@2{5m8UNUmbMC0G!D`MU z-&MGJf*Uf{OnCc5V&$>p7oxUKN^RB;*`4L`zql!cqb)O7rL5r1L!0T}-^m=@tiQpw zkul8TQ-XWuw%bb;&bBUnx5A%6Yo(4l-%{QKci3vTg&hym+@Lyb>I0|Dd-Hf-&$ib5 z<>PR9n^nky3&$3{o-;2*e#@$=J1lp~ZY_5Brgb6Vt7O0}CqoJL#XoMm{xbW>d7tSm zoq|o>bt2oYUf3?qqiK9P;P?`kU7XWj^+Z1VDJ*|jJ#d8p)3L&q@9R91az3oTYxH&! z^V^)ZlXJLL)O}y?ikQsM{mk2ub5&&M!|o;4jy}?>?!>R;4Z33Mn4o)$gJ**Bit7sI ze1GOS?e|ft|Mvag>iA#RU+3)sHDa#Uym{ZZWB1`9PaBJ23iA)o&*lAs@GT>w|=U_PN zQ+}&q-Kqrk9S2b3%c`-jmdtfj zdgOR{>-XE`p&y?z{QZ~zcmDt5+e5!f+kfxgZ?tyzCs4^6fBECp_5Td}j~B9kkaqc^ z=aAoZN;zXm@bTU$euuaCx?jw>tF=OB=gzBhZ}G8oyEeK3FDxy$U5=e9F0 zT*bJ{!fcvc`8o5V4Rd@Vy2|$b+`GZHYR31BePNq)KGaR=kGf;0o^K*=9mDduGwpw0 zYeG3(sf1+%FQiq4>Ydf%ezyAW5@ePu0(^ zy1&=|@phlsTKq1z;hyRtzjB>! zbd@Hf#axafXXCF-I>jNR*1_U)nS*m--YmySPEzVG?wg4DC@;D7XWP}ar9v)T-=>)U zwd|9e^zz_!mIJC~bzVH5BEkb}S93O(uT$c@BK17P;@XNmr5Z;koj8B#^R#_=$FID2 zbN=i8?3b?}h19p1-0*jslaYEsPMS08TOx#rwDRlcl=Zk5o2Q2?HZ>iRStp)Ir{XfN_{y_8pNBjS8|9^e; z{GY%7|Jd;ETsG4Nx%#8WKU!RRSa5@{?)RDM|8j!&SbngriVn?T;3@sGkN4JIX6b~M z%rk27-}jhtW(YTJ<6kMeCGY=@-crfH2rsr>E^49wBAF9rEpvKs+Uk|(-(?d`m!6Y3 z-Y1$CW^38^x1vb($L7yN<$mZtfLhdT%fD;5_R+ zvk$^)AEm{P*-v+v(OIOl#c21J2frgGh2-sDw`upyJ?i~^dX>g5PnOH7pW!?ZG~fQR z?dLmnwXw52&9kHUH=aM=&Eddtr9$mW{rS|TrGYix>ASdtQdaF;kjdTp|76%{o{P%W zizmP3iDY}1Gk5C^*Qf7RXdRHb9i`$Ix_#ohLlO=9nGgM6^Z3Vph98Sd%i}<`ing6y z<-evGf2V$ams|E{9>+a~f~8%K3*{8z=LDsdm$z|qE>~w=(fl#s;rPNNpP;Ofb9 zOWi`9PIov3 z!T;c$uwOe5`5)4sqgcOfk&PK+hjMuiPh$~N!j*(qd2?*JSJ=LE$ zj$7Z(Oo}_0Boq+$zU0$||G)2iPdJ#@n{Bq)lgnW3F)gnhA1t(f`fC-QS78i#_G<0t z1=AAZT~>10&f}hbbdgEc72V(GuVibSap}qUx3inCZHb|sTOj+DImN-gXHK`cJ=|FG z+&1<1mD4ik^d|4T_tgH3Q0p4AlbN+%9dgn;|4z-@!7IG7_zP>%yKt6Yv-khc{{Lz5 z{=fY7AK72??FCg8;U$0Wz5iGJ>s$H0=N&&+Hr)@sP~EVP@qycdW~a)X{GQyi84^0( z%^J+5?<|^m;ZEr~wz@pG&yPfk=P6_awgvSvss$QYPe1naLyW9@M0wMx6fI*-PLA18 z9t#_sKiZwEt+9@pzPj?g%!#d>4tyWp)V%#Zo2B7qW6Yn!XL$e2pUhCi8OR_t)%o`E z^UrtQocD5%{^6hk+g_mv7Khym_qMV5sWV(Xey>D$8uKq^Ddx@lXY;i5c1@C;e|r7F zQd=?qlP+wkf*RKu&R8l~I}1$-Yw>XEFuMG0vjHxP289cEYS`vcAhF^VQul5bGy}#XZ~5Q_{o=H|E_nJz&Ww?!~f6E&zG*KiSzEk+7`(OL<;UrhjMm{xO1z~NR({x6yz!Cw$%8R7 z`=!FSsWBeVe5`oXb)U_0mYNk;8&`82VER+HDeAqTf<(JbiA~q#t9G_0(jA1>FRa|^ z(_}e)sapRP*0mLTUz?tPy-@PEH>bn9kL*f5LD8H`I3+!%)~DTf|G465>5VSVt#cZe zzLNJX&wVIokTuzIqJzHU-X%{stm8Ud+fOgLv|~cg*EZjy7Y#pWomhHDLs@s?rUwfa zCH`XNy}bY5|GLNV|EwBr|NkMs<`x4eob10mF0lCU&>)WY@CPx6_l_@p%W9UcI?}D%Sw-166EO-Z|YGN@sJoyWX}uHvQlvY&o`mACQL`jn=)pStayB>8|8b~hQY$Dz5dEn&vjN*mtQTFq%-Kzd( z!{C@C?szH0&m-#Cx!p(h3kJ<>J6QdE?r$NH_&ryEdF9!M3jBc=-Ph z{x5gm|2yw~j+y!F#LrVYQ^`VKFM(D1VQ!*yzkGott9$CIL<`j{7wEA7y^%=`D zcvO^*2Cgk$w06Eq-2{zOlOI&;3Dl>4eSTeW9m|0oHzipX)TB*$zHs%w-!rSU-F>(( zhD&$s?W=rf{DCoDG3^UGxb$cCb7uRS8T0Ax`*p%xi+M)I7=(D}y-S=E( zTwc?lZ@j6xzidIa_0w+*OG{rp&@vKZabe`hRhs;MxshAey7YAm{u(6gzI}+_dFQ>9 zXP>H^mDQR>G|rsYQO&>N@g@9TN9$+N+-Lo258s%o-1_R;t6MN}@3JM|X1=>9u;@IK zrC!)E0i{-pH1Rz~E0@ntIAkx$U;baZLHzYPaOv)BweRoR_ZLijrO&^+nYX*Pxno|7 zz`B{0rvubG6Q9promK0(D%@#m+}g6uJWoZ|c$>zCKAd5^M2dNj$L^ixVw*#lbvHL} zXjse99bCZSdPJSYGID0hCDGtJ8gsv&EKp6j!dWNr;o0o`gTEQ|EZ}(hNeE(-;ooO6n?z@dGYt9_!h&JCD(W(}Ble@Ft`)!+9%ITN` zCl&;Lomr{t)%d$xXn|~nc@@Kyl&ZHspR>egDw%e1F!k`{ZIaV_ZnY$(d9zZgsYTJb z#PYp|zn(QU+nu}d{n-`0vrHK#w;X@q-@74bqoAJI-YY7`3x3_ox)yU-|Dh@$mwB9^ zZ;*S0L$Z~k){#tZ0Y?Q6rvx^OlXBfGNom`^{!5?oVt;wvXY1|ve}2Bdzw$qK;@zFs zSrTmPIF1`sh%YNR+*020B9_gT`C{9Q4hLrKn0dzH8VW26U3`=jj!dy*OMH>@Y+mbR z8-oQwk-rM%Lsslk^LP^Z(u1R@p`}A|USP=Ug+F(lJ??eFPG5<^gY$5U081T5L7fIy z@wv)7_wGJ^dU|^5WPT-u=Y|C}^UqcD)HQr(e$$ccTye^SVYdluz}I^#6PvRQTNbjI zFXn!=^ws(K<}E+Ji?4cWV_N9>VgHt2$C-}!Y*Bexy~@d)(fRyhR{l<=+GGAEheM>I zV;5b^R&v;H5Rof*$%oI3VvrR=R?_1x|!bN<@;Vm{|b6P_$N)5R>9=*H*j zbfjx-vGA0$mhn66OCHu_HCL57F)fSt_bw1BeamE>c4M-jQ0KHyYjX1%4TJ@GH<~_W zIai-}Bk%vsyQ{^wGwj>;?hdG~s0R)4Y487cJNo?(-}8Sg-7ESz{bhFYRw{8$oO{G4 zb@2tBzv<>?o;n#{{=Jmcobcl1VwS0^{+SoLxNcV8bzVs`tXB80;>vrkPET5;UbUFJ zFE?^>jEX~(LPr8uQ=yDu&Nd0N=r`-W@3<#l@b?Gju_wpMWRA~Z+0gCgw&LB_Y1a?T zS@`!$d(14y{{1_)ao4n-xxB{S@HnTlgm3khfYqvPf~z#|dzReq$%vi8^o6ti?&Y(; zU#w&_{b|uI7c(y>;>rUXp~7e16FoOC>JPaYth8PK0&7W=N=g&&&q<$VtX7>8b=33H zlL;>-+2-3MJF+AS^;~Yz^bz3gT~pxJY&M&>Eipr2<5HFdYxgitx0F3GhtH^c$#T|f zVNQ%*KD!-sZx?Snuwu)94OON&bJ;h#XyvLKeTwSzEG*)DvO~NeN~dq;2}8l^XNjMe zN&m4=TNWP;88?+b^l`2I&uyRkg@AF)j&Y8&G z#j7x-~$jJm|Eiw^VJ z8dm&2+_ymS;)GvuTu`(_uBPrv5EleQh_(i8VY9_^abbedvLu{OqiwC^5uKsECV_B zp5vUCO_Hqoj;^baIi8ihhAT(pTyP=7oYSYGHY#P7{L$^)H1&RL)4yESe>YdX-}i~l z&*OcNxPfQyn+qWdDXq~m@Vea5KSe-JzN#@Mn?-Ff_N(|EXRTxB5XQ?x6RSlech;8k{ zZ!zia_D>T0VIh* z@6ragLWlGnzgm~e*S}uvQd0l*P4Q~81E8Un<+gTzJ~+=i_HttJyS=^gb%zZ1>ucpR z?DGCzzltqL)g|(k$=4|pryg1Kzk1uBi!K_cK4=!-Gq~xnw!uPAx5dmNd|pF`gY#=~ z2IaTABfge@_aTdGujPgZE_tqV z?B;vIRp-gEtljKXvRC?SVR6HM{xxe&4zq|ozpJtOa%4W&;^;=5?>wzO8qd6TM(MTL z$8vkQ82ASJumy$AX0D0d-WGfylv`PinXj(k?hP$5!G=3pC#%61HLXWa8^7ybrN^d#Jid^SIH#)wAEY0|Efo~)XJP^-KAT7ksQ&X zl}-ozyIS-cKd>`|oqhnCQ1LIWd0%~h`TP3!znMF2%AVZ&d~WY^8GCNW^^A7~FEen2 z-mdC>T+1*eJJr`mRPO2&m4c~rPcGTNL-H8I#QlAj8D=^^kXk5cYV}WO%NeO}#mA}D-*={dg@w?p6r=4MPd!fSwRpCKIZ$;$F;fEbo=~om zz6X1?V;YWa>|gcHVLpRS?K7Ls3EE}nIPJuKutt_ieUwW-u5M~J?Shnce(YYuHFC{U zHlCc*x#BTXY`|e-#eg@~Imxn%t}FbxBXZ1MebIX6immTnfV2Fg8Ou0-|GoD%qxi5- zzQG4Jm-ULg<+nnNQePGwyqfZpo z1m3(<`gUv2DVy~FT!%x>&9?I@ny_3_<%-rOHDQMn($z-Mg=Z>CbSu7n(X{*DdVcxm z>I18%umA98vj2yV>hmAGd&jpv?(V^zFY->En;Q4tASbEmfo;sZriKHm<_B_?1sy*Z zpb)i$veu~?nGCtB_Wr4Uuf<{F4 zZU>8AIU`5Q^V+jqr_}6wB%MVmXUjAAY0(N$+*GI?^SW|o84)D@>v7kMtxnD$)3MfJd%A8JY#GJQLC z??1fycJv$m>O1%DJ$!n4`p5IDqu+f09%y$Xf5T0l8#&u0%;cKOCD{0H@qEaf5)jE< zxzW5|@q(w&g1NW;dv9f(cKWMY$@%8}u8J>?td?Z;w3R(z-<|vMroYo$js<@!we#ox z{wr|M!quZ*rhnq=z(2|o&EIdt=5M_HcEin_M=R8KO}tQZchl_!S<@Z1o)A+NS)jzG z@!nQF!Imi@+E8roi2ys{@@!T1YOhY$y{mq{Zab1+{Vy#zVcDc5b3(Fwa-F89#eUk- z5TqU-b4xVjO*|ivH+h=Q^qDO#@=@$v)!xXr zx}lyKreBsG5Wm%@^E`5Qj;{`rLD#1EG^1?ER-fm6oU`AGUGLBPAhuuhXmd#6?^mLB zl^;3nDnBxvpI_fIT|fTOyKj8I|H`#Lwte?)y8=_$ZQXV2*KfF+XV|Mer@Z%NSC*GR zhoX?wCNbTVtS+Y8Cb!;g7TkaD++JhptWdVA63zz`_;r;Me!se+@o6sKm0OX13%PBI z`=f;abk1rB4Yu>kUa%{2O6IpIS6r1=g|zMGXlh9kwdr&3xxBH)?LB*r8FSfg?K?5? zkDvXL3g0a|r?{0rVPSFHgt>iwEw>cIau4*j8kT$R5WB|^ylu(0>;-B^bUi0LpRC0D zBrn=cFgKxieW)Lc)cH<3Muv=UyEmuq5R%;ZYEs^kPTt3iS>Jm#vW_a;6DZ)FXl~fL z|LOL_zqQuesnu=y#j=L;K$T5N&5yb7FTQ=dw)lwonJ;RB_n5x$GOg=8aal)t{lP=8 zzCWKGH0fdI+F9Oi^LZML7CD%CtWNzi>0^MuG;@07g*}SLrnN|{|0>gxbbn5FO@Uy( z;^NBnDK}1?V>veCM8QP6fn<5 z#)9=n62DJizT*~AhE2U(mzGVvqLS;dYhB1*fgU-hnPwXg+OzJgI4i1n#Ov4&k@KFbS$|wq z4ZYU4d;OXlt(Pr$Ug`3~<&!z(R6lO$I<)Yk>xwQ>yl!H}E5IxFs8T$9ywwefs}v#v1@ z(}i2>uibmS=g>61y$o764bHmloP#|6vFxBqytSiYg-(V8D=!6#ZKCd%FB+$cJ60&`KpVYcSe zUhO>37$=>WuKRt_+!H7E-nkXl`KQIgtgNde;^7O8!aHgn#->(JCSJS{x@qfqomCDq zPNkoH*IjF^^6eROh)7?9fLqUF!SeEr>Gpkr_ZP;@ev~1(-@c-M^=j>yx9c|C&D(G@ zuW;+`Ls!4*ZA-Q}oZqJ5n>%UttT#uBPpwj)#m^?_xO(UO#PX8R;%dJ@x$NUk-tud= zJbROSr`yE##Y%?k>uYE1HjN7BJFtrP*6x0*Ag^hc*9F+8aW<58ZrIcDV`GQMRp*Z! zTJwXa{`YYDp?tIcQ|vw4y|Lv#Kn)k;;}17HFO*q7^QWxEKbaZ#)DDRref`Q|>aD9O zpKk4%nAs-T{nG2sff)1k@t-Rt5)HgAvy?jLxc}Nxu_ZW#b8Bg$A)`@e^Ua+;u~GNB zGh~-8US_pPI(XG5<0QtFF2|ZQW*kxKwGm@_IEgvR%V)+4mYJDC9vxHT6+0^VpJ@v; zyu6s~F@qtr=EJ|=H{`#qOcK6x_wK`^-Qt0BKU5rf`&RbdyLSck<^8{RN8dTM+UWXR z)gIA{5otHxZMf?uaa+X@wZHg2kha2YroV@+`*U>V0fHIuIAF(Nw>rTMK&vHOm#8b8xXxTSbyf4s~47g zpIVvSY8d&O`85B^u8^7Qlk(r+`!@4Tt-qAc<>Y1GJor6>ZhOV8eA*wddU3$fZXT}- z9%ieXlbEkci`Kfk))jF*w7*>NU9sVQG%QL!7L;5zv6X6jnEU>xY?2LYiL_|4rgD9u zabs(3@QkV3E`?rMaIWL;SD$Ix2FeSAH?5W~|Nq{sV_9Xz*2xUV{rlZH0yn()_D-z*uiWpya>pMVO3L_J$nfph zyZi9lx4PfjnVXm<``oy{|HwbP(5sG%WO7%v?ft&vR&1lJIj3WC`fR%u_BJ5wF|bB;%+LrPZFrP}>>1P-q1n7lfuvEGwaM4t7FXvJJj+XiSUgzJ()jd}h*jN4c#owzs8NLkH7Td?w{F$@w zuXw#-i-6qyJ287t_RU*)s<)|Z%Bufn$^Pcc(&pN4d0Moc`>3I^-xKBBE0-@^6FADY z)lsFxL-O5#F;4*HT z>iztQ-t-^*O%phLf7&d0c;bu(yFX5W!p_i7e;9_BSVlZ}WQ7}5F`gq3KV+VIK zo~zvBoj>jJ^yh0sMcWTEu8+I>=<4e58}fWJrW9DnZQQ^Ac-{Wve-rzE@3y{k|Ni3& zn`K-x7di^2=(u?<3T)lD%_wMrrt7jXLaVZG2Xtrt|!WA5o55-?LFP08SI!y5PUJNNDtacl~`ntt#1_Rf#TRCX}FoaS)* zOrP@Y{pYKFR(*5uoEE<8T|C#nzL*l87MD%_O6OB&2YHFD-nqM@Pgj;RHC821Q`FN? zO6#J<$+onwHk&`DbVPb6h{W=Qer~%iv|+-N_EwHVZrg5j2pud^)Y!&hvXeW=$htpz zZS&Iw>I<0qI9J82=-x2fMpqW<^w|Jj>Tk#?=vu~uB-Ng)Jy{E1w@0aOx%8~%Yx;V5-6Ex?de~Zk z?NUnOilNC`7X+fE40p7IEc8?LEPUhe>QYFGi7eMagL{+XYFmyOE8DQTKH><-mc5yD zJmCF?ySxEAGf#9Ga$K|gdg^T725T3sO$)ak%Y76W)^;UJtg(@wsPSDkmJ&lk}R@m_FUtMB6sys7=w^=RLPxre&Ng_z#n=Dl_5PKuL~KF33WRi73_B!!B&uHCPn`)%X@ zu85_#?-}dw*}3RxUi!08mgd!~iY;&4c3D`fvu<+5 zyjLRaPoAgBpS-h<(VU6FP|@qT#&63Mqs*C==^9Ord6POrJUN!Am>zw@HgV^A)y{`1 zme-dBBJ61is*b}kbHDuMg`XhBAc?%=XvAi*uyG1bJsbQ70-E6RF?E?S8LJ^@d&jQ zik$8_pW&16s)z4aKlpy=%OB_G^WR>dTkp$ojrqWF`Pw54Wrq#+Y`mRwKXKV|haGAO z&T}igc^BN(h}pMsW>DzlXaBCQ*qhn9J=Tb!lW~flz+bsjF;SOhtUZuBHU1d)Ma~T~ z{%ZzbW!|vl(3Q()7&k@jzRY?0p&8?e=Lu}h9Dju)40*Rq)UgmdvL3GFi7Y=KrDE#E^gdaC4%)tgdQJhR|xQMo_+ z>~xNXbaU>U)*~~u{@%-31#xr2vY{aRauKAh^Q zx8o1n-LUH1T#t?i*2RK9Pjb4egs4tdVr{AZtmw&d#L9R*rxO39^Ci<|Ze4KB5Skrn zZxMe`7O&#*`5x4u?3e!_cf4@dX(7RIl8qB`UKj@ew<%BK`(D(|=@mq&H(%Lmr( zZp{n)8qO^I_H(zbx!v+AxqtcvRr7gP%#*peSXjB@`MbkzZ!a&%n<Y>t}~ zkA%&e%J4Mfxs^2g%=zoX4$E!+o_^gS<&yG5&C0y&HQtw5{?4hGs&Y-O@ruwN#sse5 zpt_vne%gh7r*3V%CGL`=bx%yOn`NsNQ}x5UH)jeRWbs;6C9#*OC^BW)D}R+Mx5D!$ zZxKDmJ3Gc{+nugtXdid{bIR(s`z zaG}J_3T{gRR;XVv`&cvI;R$on-^vyL9FF(bcej~?2Yr8hwB`G4yDU>`&-eZ*UwAn` zb<8w7b7YECPRiD6qHF(|U)nLXF@5%`2qB#{bN*e>S@Fv0LTr_ve8S9_S3jT19{&0} zB6@A$dV>h&#JaC5+WqFTZal|Rw&ksDi1?9nyDB8F#rnydn75yA^@?D&5XJ9&UTT{w z(|La^^;$p2-`H{4mY7Vv{pXEO`hRLzSH;R2ms&$Q%K^28 zzD<*^*M|R0|KeiBJpbmdt6JV?&WLZ@(ewORvtE~p^nPdlkE`|6gkRhdo32y)eE)Q> zg!Avuuc|yIHgihL0x2O$kxa(K4yBMgDptO?bxy0Ke_VNJMQ-3OpLe09EJE%I?iaE{ zD`zX%Gf%Z|mHy`t%6vA}>3Xs+L!C|EbNTu+_kL@q)lHsxU-Y6mLyYhVD=Gg*0o<*adw!0&&OePLQ*dt}IRX-`x_N>gwvm-FNLu@9lp-<34|vIm6z>X$K37UcGBNwI<1( zd-*e2wO{*>%nlckP@Ph^&gax=+e5dsb0+%dcFAA12yko1^Of87+ooHyys59km*UB$bFRtXe-4}MwO~?DeqFF0S z8~6QtvphER)~g%lDS=TgMRI+AGxzQ5uv*Dk(DreDh}!wy_G#NDJbM)?H7Rmyn;1)| zkI~WZ5{20!_it^9>N0bk<$k@$cIy^ZFNN!NGi~J)J8zXtn)Pq{&yE=FPiLlu8<$0` zPPaPzBL8~1U&|Wx`QNV34Di`@>t=ma#opG7)n1F7+^#!x{V|*swxITYnUUIW|1U3m z{a#%v;c?#B+0km(|XTbe7{i1XwoM)NwqGkJ?6^yvp&nc&*(TNSJtN4PQ1A6 z+`+!t&qTxmI({exb3EN8D7h&n>Cf|Pq2F9HN~<~b&VD}5$t)t7qVnBY`iJM%kgKK@ zbG;aRnw(>%F5)oGelyEpTNQ_DrFOnzmycnnFV~H&$wF)2v~X-XSDUr!ix$Tcl>ng# z*#^6rCpa5(H%?KRAH}3$y3FykSA+4R1s8X`xNbSsEK!fS#JR^^L8|kE-Gcv$9d%+m zcC&tXD8+Y;<-zf10inM(+y4x%ude>x(_#1FUVU8XeWjyQzn>Fq32|2n4mEkE%693A z%493lFsPdekquItYQSBXSu8a>ZV zIsfE%Sp7LJ)rc3@4y`-M6wbo$#B?&AG1Abl+HIeko=4!fim2O~OhhLN{($3Rp5U8DthpnDox9ShrGD)y+_S z?eny0yxSOqJa3!kRw#VSZanjH?zG)23Z2?csD9~mIF&2yxjSKfZc(e+!zZ_1Wd;}+ z_04>-pr$#+&}x0JN(HM#xn~JuZC{;j&EjQ(2mf@<3E8(Ge9^;P-e0P0{{%CCJe$R^ zhVwxG)sMaFYvj`dx#Y4gRtJ2Ow!ACowc<8mjjDb+}RZHiWuveNBonNhN}OC!5Vl+PsRR99P+ zr={&kaB{v-GPikSqu<#HmyY`#a`QZ~g7*^3>WOP+=A;D(%oaSeoH0RXj-l}JlYbYV z5n^9*!#I86NgeMqd<@xoCI?+U+&gOM_{_x3GD%AH;CoAhtk83pt8_KO*OaWfe(~!$ zQQZ%I&n5oM@U_1tveKG=Nv~R4S#}&xexuLqrTg8Eu3yCY<+E9%+2d)3hEG)@W8MCq z`oeVnR-7)A19$q`ui7WpyIU3tHy2n`gx>7*>1U`DKVtv7;&Xq<{QJVT(OVfoDfO|1 z3?JWt$IJca*S*Wy{(H~&f3l&qOIAsT%FZx7b;!K7^3{VMSJJ~8YPSS_t?M{uyfZ$E z$#zy{g{l30<7G2|23Yc+qFORYlI@u@3%&dv33T5;{jO}A@ox0g<1 zeaZB@?qRm5?l*(TM*h92>t+dfgqUz=8LSX3=U_bk_{PCgCwUD|zEL{)#!vCwSLK!b z$37p(m2S+L&DyQo{v&U4@qC|`e~YtUN3C;w_5WMwQcmZx83x?^^R4=S+NL-zZ9nDg zb<8%<)R3Kb?Pb9gSv{3&H(Z>p&JgV3yiq5iZ<$NgD$^v9w|euKCd^n6Fuhdp?9AVP zmpD{4&RH~jdCB7iwvC%+K6*L%>Cd0fimzIP?tGz@I_Jr)WrMw zPQ$s9=4aIsv$k$L!uep~rq&0Vj`j+N>{-6-UL{{Y`9*JGFJCs(hg*mL$NxTTe=F|o zx_edc@0QzFeEIRQ`u5vzlACug>v`_%pfb1EBRny+e2Zp-O!H0GO(F4(ZVhmfX_Ux$ggCIA7Kxl@RP0(3SiUg$ z@#$TR2HEW#d;bJo&#~`5Gha5A?f)zs`6ti($_)&I2Zv@Be%~@_6_4 z@aysxkG}JL|9$+iNzuIfXZ50YhI_L;?*6`M%DopRzQ!DP`rdDO7-7SZwF?Pjw6RJgbpYiH*Im&k={!M?dvg7T3 z?q`ek&d{=KOP(GevWhW;_f0SRv3ntlkG?I7p8K{*WK!DKmEjQ+k8R6caQ9x^`RQA| z*R61>jX(V0!HT%kD>m!5ChA{xO>aDL?YE|YOR)a-o>!slo`!p?FV6Ym@i$;e_l2(p z2FnbbTsPi+d!Td0w*C8$-+e16(nh*7kk$Y$k-fB)LP`!@ed*VZ+2 zd-fIho(W2|*T1=SXZ)Ov5yv=F_Z{+&uqu}=oF=_}?`0K-FDhyD^ zzioB1=KQx*`c>Xg$A6%UWew+n*O7ns|2fz`FLYhx(_V4;+COTB_F+f;T+9?(eD7#K zJD2hGUjF7E6C|#Fb~wSkAw~K|_rl(rQ?{&sv-P`8|Ln|(byqJR40y@%Y{A-V3|$92 zUTfUQsd6h6N9t%l4AN3^S;ZpXjJ2rDCYDK)Xs zeb2>P6OHE<3s1YkFFoae#MK{@_DF0$+{2MEJ0n9WI7?}jWAwqrGaLk6R`gFS<#OnK z6f+_0-E{%M?r*l*%Q{aTIljdGj$fg!Um_DL(-G%BE??agUdG0wYh-f;rWVdpP~38L zYvkn=5sssM71J`gwLBfan5_8xcdv2U|5D!>UsbeR8JsR}dRTci#;147>>C-Y|KDLt zUj3|`?-YZ8fYz@~OXg$-7{5Jc^H|m7vT0=L#8p3o8m5%Zp44PIvmmhJvf`W&W>V<5+h2V6+r_h!)0^eZ_PBMKGFHU$TgklJZq#?)q@}#?@jqQwTct<5 z4s~1yi>ENI`FzIGyZzuZg;YOF;|1v-s#g|SEtHt-k@4>MB+>Sl+w}}**Zln-v!v`F zUruWEyPX@k1YfkA6Wc2KUNcSkXkmWbfza0yzAV~#X34e}zn)<9o))z1i+$aS_fdTe zckLBQ{l0F_E{>fxZw2pqKXCy`t;S`-c1Ew$_WkshJ-OxE#%+gs*6nqZj(tumR+TJ%U?CUebg)y$ufb(@N^d07q=)a7p7^;G6nvh%`fTUAH0QY+ zCq{AJS6bS;>hAhj?^Tg5F(8C+nt#rp_T7{9>7rt{uB4tK%FJ8 zZE9T&S7aVeQBi8GJ@n?6z}B}bs<<-P&YFa8im7LwU(d#RQ_OSYiSY78mos9F_j%m% zjEPz#b8elhi}RB!y9^f3xZA3_<%ux{c{K`xo!NO%r)Z8XFN$pFCiS4U3;wxCQ(vwMG?ZqTthPcBl4vtnk9~bVi z>$`kAV2^9x`h`ziT132VKDIu$h~9ei7AY-9NOFT>7$sY#dk zH5nVEcHC0poAZG!PCzm$Y>)QV^R379O^ypsyRVcv%kVn;{NEpnmA;+-vF7;&76I!+ zFJoeyE7|sHMrv~g2w(IKo^)kvLGd|eCDSvNMvF_Q?9hl*-sdW~<#4ppr73dBvv&j- zo_@($u2p8c%F$?=n}z<0Ln~buZ+U*>hN2_QL=dA6}A08tvV+@ zGg~OnyKFJHV7&MPgWp!uu223cGog(;VYx+Bxzp?)9Vx2E>;48-zmIBl#j+Unr85w-K5XYDHglt;pu><=l48bx$SwJrt$ilHStmR8oL@_ z1_w;J!*)riV&$LR5?&>HUkhKq6StqWNn_%(kadcyjy-WoP}CJPO|mn)uuZqY`+WIh zJ&r9_e7t+s$!>7-RbCib>20*z`{Pb?wN2|MuM6Ii=_mTlQ+c`HykCq(9CIr=OB>TYYfdVW*t4hmyPs4zr!nn^g8zPDq$J=~}PGPLrkwj64mKRtX5M zU)x~HSW(;e_+f*8+#Zhh!-*^}4&0M(-fhh^!Ej*!+C= zU50ArnV&r!R_`$XE;!?T{OPL>QfIU(9>u&}TlP5m+ULv{aaoft_q&T;oE&V^`ZGIt zRh}N#I_@L8CyT1+I)9q~R6#Yn_QTEi%iBCpsLyBg`of#rQEYi5`dek*+5Pqp9$X+tZ!xnH}r z{qmC?CO<8{%ANoFXU%zk**^{%+ytCo}(@3*V=7*+SNA_T9DR zhZz@4oT;uPchgebMdskech98!=i9D3IIriY?|rTfBHxcbs89N~f2Pce+u7<4_w(4! zYE0t%H$U<5Y*y&7SYHRi^(wdH3Vi`eCIZQJ9tvIF1dC8xNy zta@E-w$U$N;e^f)@nTh@+FpZD^^?Y&2X4NPEDczg<)hhUAZPgQeSwXSplHXmN6a4O z4C^?ybQk)()GrSPtq=OcAvb@|50`c3;mX4DjwV_QB+9IZg zn*=hxyMOiZJf+_Bf98S}vfTUct9*J~^ia1dlW750218oU598TqR44ujT6DLSlVR4h z(?LQ_eF>F%Rvy1++6O<_KC$OEOTtC>uxR=6OPilt_%lZQW$Rolu~b&5^jl(1xo+W^ zkoPZl#xw=+h8fS3o<-iix0x|=^(w`QQu%E^r)oWJiehc>n3S_w z@l|AOeRtK=Cr1kO5^ggrQP`T>kmcz+>-bA6-3e?SC*K|rX5m|WRN$v^)1^=9o%Z=l zcC0R1aPE4If02l>k=GuDh-u3w$V_P2%Fv{qAjKcpuh??tf3e`N<6;N+R@tSttab)9 zRO60Yu)gS1S>gBC#Mj5~p~PjAhfm*XzxnQNQ~Ql&71K<$!!BOtuh+2u3Sd%5*9wgK zcTH%fhj>qb-du(qCK2bg60W^eQiE7dTf26eI@dj$)r# z^^)i7$)G&Zs~gX1B+q3Eex(*+ICs``sk3eGrle2QJeoO4>Eg=O84n6Bsa(Iq^&>zr z=GoFHb-63^-n(s|-#w?~C(o=s##@vkS~O&PReppRPu#idu_cRx@I|B9I;{c=7zJ9M znH9Pi#|r59l%zaSQm;C4U=Fv?clkptITKV9TYQ2qe-jYwIB@tQ-v!?s#x*tvOc^V9 z`O|`wt|@3q96rJ$m?YE3Ui0On`i|Xu4{x~nU~&Jv$49&S7t3t$WLQzS()l{qf~N;K ztpq(*IN!RgrlreL!PU29Q)K)F>-`-`>*sdz=t|tnxXoVsz%+De*mC|qzq}XJy4TF) zW4Oo~9UNoCw^MToK1=R#w7P!1wb^Y2bMo^=>;?4K(J8s=;*b{tQ#Y^Pd z@8&%n%sf_L5t2d&4EbmSmzIB~ElU2W^``6wnS{_#RPuKgh@_ykdoXx}O%KOXP z?zF0e>z~`M3JkIb*Kr=26!NV{!Z4e2!IjX9w@&PoQWme?xl@VZR;g~%y%l>+9N05n z^k~d_o06`FJsFJ`LfQy{7tUvJ?mb~VHAs+zW?9OD~7+bKd?$gCoN{UrDA7$@=}D~{9WQ& zM#@+BXnK|${}vFl`rK}fm2YI$l|}QMTe@=63F8xwJC3G1SKr99y~gsu)Y|UX56gAs z{tqe`*w_Ty4?m2{%YQHE^6(FXIZr`eL(rNjeC@VJn5F2Up6~zTFqOJf^IoA-%E|#Hr0O6jhn@=ME2<+ z{`=amxBl-_oK^2})Kl$|tFXG)F}oCvo**HHz=I~OMsjXPSvq=+q{U75?kri`x@#rd z`N?c%YA>D(I@rd4OcPRgC{n*#>-b8R0Ws%hhGn7wfkg-tc_x{pt7Y*EyyaBJ67?|CQcS?f0?3VE)t< zpSVw*&z$`x!>c7BciH97i_M+BtU8f=bh_NnJI}J>&b*g9E_nU=^&b!Ze*e&_U(@h5 zjoG4$Z$c`6U~|E=lJILP3BC+*w;%sJ9bWN#t*5#3g~Wh{;JYVz%A9$O-XsScXb|Z8 z@yz_cO#KJ;{r&H2zTf_!x9#|z=VD#iIdyAK@b|2mclhvhRi;#_cAMA6Smnw!|2=A{=LKALx0rrd z&w1c=waokP6JI=*c%u}fuXI$`Pw?x;P>$UXxn9|P+wNZT*#95T{;#+H^WCeiIA5Sw zxpcCb?X9{WGJuUZ%O&D$t`Nl$Ru&h%qSOv`hb7(V~&Tr~Mf^NU%A zJGwemoNL#btcu;-{$1{{!GUV|&c(N+vOHJ%&Enpp#+c3Yp-N7X#lYI)8Ov-zmqt&K zU;&oUH{aQNt_!a-lRL+okmM75;4}Yx(2_KXn5Mgrvi%a@Ot}}dz;x;RoMP+g3@Ntx zA>lS^Mk$I$T`46@PTPyma!b!&ne$d>ON`Fl-wyuH*<1Z0!n9SAGbSruSbEB*x5G>O zQ&n5#+UZ|U~k zLC@;}kNU#PlMOz7*&OD-b=kT7(LB<7H(hN_kTF^5rK_NNCsA`n)IFZ)lP%Az&is#U zmyO(tnr zdbD53KmT%5Ip6HW18JKZA7_ZDczSko9Gla&VDsKRUWeRne0{_uJ=MfT!Ozoy?^%i4 z{$pW|8LLlSyRm$hRI2Sy*40~u8J}!2V?00Sy45x7px28s7GxV9TiF^pWx4LAomUph zrQa4&Py3PcG;ikh?(=WE{!La{uV(Ay>@sH|gVp6%_H!8wj%*Q~b>H!;SKNZyE9=&` znno?-6T9Cj8)&?bfmP~yo9X>$5w}!@?z%72+jwS@NJQC5o2fh{mKSe|9g<$(ILh%p~c<|Qjzz)RW!Rf689~)P}F4%USTD9&eGz!0}D&9#`01j zlVgikvIe*qUOTW~jbZ(LN0$i-8*fc#2wiuTQP{)Mu{ASTr1iVp?Xzt6eom2i^4>Mc z-}Hlln+)qD6Os3a9xZ2QdS26hX~D_BJ=6Rr%2c=|zE_Ft5&Qpd%kz(uUd=M;lMB3T zreG}R?iqO1mHn96C8?F$uYJ_3+s4{?`-{ZEZ`b`jO_vu>@tL2IC~{FrcH+Xj?3<6e z9pd@kAo@(Rw#klj#%#M(_3f{C3Lfned>DM>zuAS1*S{T%Q#@~ZIY<`A&&)%wbVj;7+4u1 zR{u9;ta#h^diL>;YEw0qg)Y`}oEoie)7$3I{QXAGwh!kXTJ$NTRTOb3&d!Tq3TnN6 z^;4GSw+SyDC&gaByv6fC4u3~X%hE~5?97FGXFV`%c3s)L=KPz5zWYC)2@d``?`Zmo zjQNubkG`6{gL2j0FLlQX zO{!gXFI#i)!t$M6Wnc97AMaArxMBIGEIMa*inPpyW51VHy+n3ATJat^Jf-k~$g)5`S=}F6TJbls^t#u7q zF;ncs`H4nu)1`#3@a=!SrZ`}$RLQk(v*asx9b06uS26gXy!pN6x2EdFi7k33ytYir zE);_mw zzH`*{hi!?mtFt9~zklX*SiQ^K-#^PmQ2Ni>S$F@Rzc<^=vn=*{Quh4fcV|~Fd$(@k z^J5NO3a$)uRJ>JOcn=F+5E0t=&n$_0nT&sXl+eQeE{J>Tc-{rm9F!#lIhS8uv-)gjzCpC#aGXynXt zo9efFug7Vxw|cVcYqIM7Tl=|%Rar0I+;{B@gUa+tx=k;ZoN|$6EGYZKVWF_JYwnxL zH{V5{&19$%&EpI_`?l!Q?}EdB!&bZu)$)5>`+m;rgRX4nJSS@NF&Y`^UTuAB9yO=a#o9)l8k{b+&dr*Pc`RPo9kJ)vGssYCWxrdqL*M^Nk%L zP2L*!of9*cHkn~dxx$g#{k}UaLN}r+SvJ$+cnD)_<;}TEb5@Hk zZe3BWXA*MeQ^LA{*{2*b!;X~Zvq@F|^LYB!ab3dEQ!6zb8bc0b@s%xk_sa7iN9G29 zSL+1~{SG(2t`OkOUc5AF^{Fd;JNC3bd(Za#q-TQC4xXGR$DZjNdh+{E7z<}ZuAq(3 zMBg$SmMODcyCfMZ)V6nsD9x?By16-s&nkGv=e^PT(-P-8zhc-SvNnwSZJG3=Bl=3N zS8e2dSGTDMT}fMByfx%zJgY)^>gp-!D`yx?w^`wF^}b8fe%_Bvt&58tm)aX>uAWgR z_TEyIX~r|t%JeA)*WN9=)2sV?)_%P+8<@f`8|+BRDn6W<{(NOz#Cox|PbquD4mu`R z?$O%(I-2p)jN?B)+ve^M4{Z)-G}z=Ir_dXuey@IAQ04kvbL1Wx)^@Rdk(lS~=&HJr zA$g}u@!DS@tL_%|3I~6my&_cZ)Z!H%c#cI09IUe{+&5)j=51l8+`d1_B0Agw6Ka@O zK3@~7@^D8^FH2-$)Ra}m$?IwtWbAR7-~U82_+I$K87o>;ExCR&KFpldm13eHe4{8% z!AG07jPKD6_P=kcG=v+sd~*x(TG0D(vd0-e!CnQcLO-DiJSY`nm!9n(QBTR6=)I*IWKIo%U@xyK#u}644`D*w!(pUOHmwxptMAyTT=2trp(5D;&fZ zX=R1lUl&RcUKQGva))#G!n=;9o0$dq-fUODUgNc1*D>_sv3{+pJm%k;@*$l?hZw)N z8ZA9*bHmH@>vX1B9=R)y^xx+UzS#Xec{i8TzW;f1W!a5NopLQ=0~czwB<~7R5f*3+ z;|e_Xq5NEUzzj?27t0UD%rO3xTIjWU`8`GtMGwQx4D%Qp(xn)lOj_cYaNVnV>6$Zp z)ZR~>x=15btYpSTugMqXuX>$mzkm8~aPF;s%YRem|7Q!UII+Rb=!W6fYCFkI!NLqR zcRrV0_;{7kU*qi@W`?QU2|In>eLFCb|BbO!(B`E}KmGPhp3V`%v3kDqS%FACu{j#6 zcw>H9dwkd~`nN&HL@Y{}@qKgZoi*umrpG^f_j9LCPvs{sUe84HInIJyN>!oSj;j_g z3%dG^=d@gqw&&9X=j^$$&wVm4E>|%K6zMSzPn~vi^#XROs|5^mWWF|AFf(j^n|bTc zoiz?CFB!OK#-91KIb||~>&s2|yuaT0Uo_2JgMCp*Irp8U?!ZMSJ?EQDNm^@q6C; zKgP!SetfG1Ls&vIeY#g1i`Bft%k;kQncUQ-K8bQ_8;%2{P`vSWgolIo7t;X6SWt} zO*wSk%WUT)<`$+2vKyNBZ9Z_+^3&b6RY`FghG%tDIaUbVe|?YnhWd~G+p(wZtoR;& zY`?Cl{{32i`-)xsp`FjGrY8M&Kg+y&)L8vzp5{Lw1I&h_S>u z=EelWlfN?#{S0Y%|8k;Lhomga|7G$)&egsdP72GJ4;;F@@8pwJ2a}r`9#?*G|MQPm z?z`y3nR~?NvbO9w6q?o&+@u+p>{VI1GWx#NW2f+aac5UWd}Uh{ayc~hRs8Dntf|S< zE1xdha(tct%8ZuI+|cv;ckK`Uofu$R$g$pa#rcP#*0IU0sy5f|%$(H0wDhUM@ADO0 zOb(sTB`R(;iG14UrJ2DrV~V)G@iBk14wDteP9g`nIzFGD?fd^c!vSM{hHcxoJESZq zHC6t;mXY=3Ery>F3r=y^9+e1HJmxIAX#$IreTbwZmwRLC{?G>v5B@JXd`d9&|JGMW zFUS6~zf)px9@_B3Wf@QnzS(Yn&3Da;7JUr1a zk7M16lz){o=c;M`u{~C+6*M_Fk7M0Z)=gI!cvz=4*2JryPHDH3oyYvZIPck>s|W5~ zQJ?MeVQSN}jb}dW?J}xMYmND3>bcN;!s@Ijc8N(owHM#F3pHx6@-j)b#;xzx=vuJV zZJBd~pdr_BotpRcVZY`xHl){NZ;je;&GGf7J92y<1y?35Oi9xa{lOBjV9V75AJk_~ zU}a0)^YQAEHj!fvPXCPaPIUDBs{Fc4DfsBumDjmAH*NZB{C}lN%xfkicY&DxUw^qm z#jRF-=Waf7P>%0wgZwt;ImHR;7p%BKIKKbCW3$6+re#>qvQG;l{G_f`GKH+VtSJ@z za888l>|@@$0%n|X_gEb>djo%8(ieS!xu?pbielSpd>5?RlK!+PEue#S<>?x|1)t}h z`}OHxpwKzhW?rplaYttfWtmhk6-`|0U1=}6_wO2}1AU1~{&8Ue2FDI`etmrU&4SW5 zp$xt28XSYT3XG(`%w}wezs#M&6SJ^GwC6s{!G_qK1=Aee7m9qC#N=pi*K8{>M^4$} z?fR1PFA52#aw@!`~Yo#&xHArnty5 zSiQFU79?<6F)lS>^wD^K{<)bTkjF|a3Wb*n{R)AN-@ZVOC4>MgDO zCLdz4s#(T$W+RuZ=lx9!ZmJyMVX&DTz5H_H=~FpJW%8$q1{|AZ>ULOSt}fr4neQ?z zo^z$G)evEl?iZJ85?P(WzTy{i*Q<(458v+Ux4PjMA2s5SN%R~=70 z&nvsjqew#_)Sg}OwT=GIXY09}!!sREAGLM8qHr=iaGDyVieRaQlj!R^QBqusd2>0+p#M{MXL(Xmnk8TXr#PYuCNKTg5zQ zDM+e%Oj^Rg-+C(EKul!S|5k`=oX=D2|_r>rg^lK}UxP5w)!08XaqZCr1C0^}72&g*j0{|{{|r{k zuQm(Z8x)du_u&yoKBiSI*8k%t^#sV4hw`ewE>J&TTpDsz$ed?Gxq%Gd#ATVG%eJST2)^-}ZE8cn>qRU0Or}(DDbKmEPfC^Z{N#HfYHo)Q zsx*e2sdRdsGV>AR>gY#)tC)V2r*7CRaD!o2@U%o@8SY6U6ON?cXg$HtUc)}=P@iX} z|0-b%m6HrcOftJ4<$F$izhB$*t|-s+%P3J#7iD82LXQO{`SM`>IuP?9EuzAbSx$NHYWjjmefApSs^x690RXhI%9jlo6 zWAidDACG>`c;}gFcA;OGnVJ~2*6J?eVqEBHlP<);(ZApF^|u3YN0h>~bhIj26OtmN z!whyL@yC8ptZ89uTo9u1;i;%walz#668zHxrax{}H@8A|%bq9-tKHkV zr+Rks^HPRQK`SnC-I}o|J;GzwsYK-yZz`>3E%^Jgp(`_rzlh_^XO+Ii>qKURvvkQB zFh&JWI2*L`UHFlen|6k7x;DFnS4C$Y>*M-`h7+dTT>ky?x|58nkEI{+XY@(`8}Ui< z&;5`}*2V+=a(_Mx+`F(my-c#;6N3sn$JK1r);$G(=RC>w7Hv79_-=hsu40I`vdiPN zMs&k63ypIBtD?{nlAnvX!kB?sQMwpAa@fAfq~6d!G2GfD5Zu&2#%5wen5$)7hfT^A>R(NVI6ZtidSs z#A7vs{PfQ=(*J$^%eVDscdcH@_oXM69JZ^xH~qWg9rwi-{2R0!cdXkPpD%l5Y3=N0 zdreD`54m>JQ%jq*mN;KADxI48VbzIWuBWbthcX#AxIC>WP%IJ2;MQ;rEn0e_@%oK; zy^}}(pIV}*{l8i%VVhni@7fZ}XYO2D#i>SWPRlRrX*sm!F>8qluy}A!s9byH)QMfj z|9|w`M`f2jFRS}qUVnYLK<89oJbF?h32<7kgm3 z;{1)%zt^smiDVT`ys%_rpo9Ir@bdeMr5aW^wAXGZIq)k#^ zv%+E|v>SXxT9i0$DdI+YeYc+3F{$qZ(?vvP@R+d zIq1dL#VRjE|JKas;8^V=zU0>N={*t=FG@P(MbDgf{^<41=Wop4+uvV)ZM<&w-1`St z1B;47s9$ml&pw;NkMEX7YCErt>D_TeIVd-hC0kHXgx5U z{p&tm{&8k!ae4gTOVhU>*z|gicO;9}iFf(;_j%TT-n;*5{V)B0^ToK!Z?7#g@9GI! z(q>=%xc9F8|8wPS=k34G`Fluw|Bvio!5NGV$(v`0sr)lqvAQO1Th5M&D|DKI13NFX zF2A!?ekI*UDG}8D<10eR^QKYzoSwZ{kMkG!er}zEe}h1|0i8?`}y|; zSsx5(sTQ$f6X6jJV9YDJ{mAA=xW``C*UYTl`)t%7AMy?#z>$y3W<=KUGaZzi(ty^;LWI@Z3Wjm^WPy6@p`#$m5y7xup zCSHEq9$m{k^OZ~uR`eBbPUlk5M_{~OiNAjx3CC%*Eo(4{Wd zBR5q9bGL+_3zB-&mhk*R5chPeEy>J_&MXqXS7%(#&>XanNvmf=rg+!N0>3{KeHvFA z{&>!ypkvPVdN#wVM3e3eEBEbLp5GT3d}ndV$=p@>&a?h=;nQYyO9^Y9R_d8zRx5xdJq!EM3N}aGqFS#>PYu|R)m5Lf%nJTt?R*i-X z$7-*sto;ivy;^jrc|jBNCgxS!^|WLdG8>{x&nm6ZVs~cBd~nM)MC<2Np#$uiLC=z> z{#&~_jM04&IHk(7LCbXi)VDQW*Vh3b2sZJOrFr(f}M6g;@8 zx%8jDr)z@1oaB60pSs?phYUM3EEo-245UgQPpiD}`rE(f#n1KsR5Sf;-T(jKeQDOE z|32{lQ?RZ6rqiLqD!9|c^!4|5rT1!IzdahgJ%9bWb#r%KcwM6R_0hMJ9+FB2mCN3B z-Ib25+p)dw?ZT=ZA3vMl^NIg^Yx=xO0Rv`+;|ZtbqEG8=OZe^a?MPbj)) zYZ&jDuK6OkD!u(ClcNwzc?d_aDDS3K4(3Y~%{-GiDt>KWzBK*+M=f^w*|p(mKSJLA zpU|`XtIFe@wyX>rB?4_f#F#fu`+FeJHd|Jmt1Thr|L5x=ih?GS{~Y?eB3#ia@ys+G0$>GvQ@UmX@kSFeeCJ{@J=D z|6TrnvzPDRoY?;FMgOz7A8)!fm1LuH Rtpzy#mR~R4uJZG*uUB{6wKBi{Hs;Eb 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πE$G_k<7dyl<}ZIUvfV*dDRaKeEk4<=Lg;leKz( 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

    q2cJU%{7!(~cCo^EHJsRfO38v=pzHctV)d{Jz}% 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_redhat_x2.png b/src/qt/assets/systemicons/os_redhat_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..a756e8aacd339ba1cb6feb3f1d3540b1d4aec9ca GIT binary patch literal 5231 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 qxZZf5ecO+VH_aOFGuHjCXEbU;L2bvEg{&*@^r1 zz3-iG^8L5%{rg3A-+OobympCsKC&-gdR- zl{$Norrt``j836RJMYPTSbpI9B!Lyz59Bj&1!;O6wPBd#ot3$(+3IDgci}S*wo(ph z&W~;Eak8&USA;H%Vtz2GsNvd$+baTgRocD~aMIscYrxJgW!IwU!Kk(C3d;qCFQ!^k z%-8szaChu+X%T2rXcTDJ^+iS@aLp?J;Hdvb99f1RB{m8uwy&#Y^^#SR>td(h+U8C6*+%>GJAMne za)z)(IhV{+4B(QsDfo~nv(}*7!(&-cWX#MLQXcIWeI`!6DdzVi>imKhu}@9hi%i$7 z@t+uf$+7S%m&E<)SL*Kj3$)x2FkqUKFFK>tsAkQ7v3n+FM^2xPyk_^u)a!M=%A9#F zm2&@16#ls=_{zC@#rwOyx##t=c5gF?h&kkM^~-WnzHZ(q2|Q~eKT&Yf4>pyYC@ zjp0$vqy-TLwY#>=VL#3MruzSG$@(YKEn6i+N`1s3 z5VXnu{<-B>8Q$;t-z>84!}~2U_qYRR-09)!eQRPNH1XVqH>KMz{=B{Y!bkr3i@sl! z|8z9$vN&ftxjTQ8rWt3C0ft8vJS z2N&I@K4O3O{8zhuZvdlF-{H2vm}Zd)MGAA(=IU>F*7$wXlXJH-e?PeYNp^d?y7jM# zK?z4{9ThJ;56y_&uGRV9jn{@>it)#?zr9S!wNo838$Opd7$`AZ>R|Y@V{gB-UvB!# z>-$cAs;*P-bU)vEV2YB71=A(X6=$6iXPtY^9`XN!{iJ>G^COIQ&Cb_}?H0Jy^+Eg5 z{@d#>6`fuC;QGOAhr{gl28sfb>^FXF-x?jaKtN!@Ru%;&x$NkJPvifp?ai++)%q~e zk=Z8MGxg1Lj}uD{oNkC-eBA1GVh4JP&qY6{!eT@HZo;yEnKWm5HgTfnK z4mu6jX06qY<+0h?xpe#833nu{c1qqqqS7F8!9#M1V#WmhsXM+Mey>pRUR`qb$p#P^{`KH|ZwG3(BdxiD3Fqj#7Dc%fzky7+I?2w0|tWVPA1wKhZ zTm}mtcynA*^Jfv+eJkSgzU?2T_19UxQ}GwM^{kkwLyhxNlcTb&~9rkJY;pPqv1Ixx`PrF1`y;ECqc(dwxA-CCfDU4#S z470genu2eNr9Edk@l-+gpr8WdO2**n%Eg!W<-2?kQupyYlrwj0e!cSbuUiY=zmRL; zx)^1udUR!p*!LqHk`*pur{2{Vi;YRlCiArhPwFSGDU^{iaS8O0VChzGIC{iHacCvX-UFL2uJtcKna~@uU7?T}t*H<(_9=4Ga%5 zww*b%?(m0d=~=mbN<6hp|9P4k6uxvSwOZe1n5N&wu*^`%XBl^4(<(VDuew}wi(~(s zm<>NZd$Y#io2Z(PkYZ47y33CPdsF29Dc+r3ckbDzBD3vr$2^uD*yqH4xq6#`Pk3QZ zLE?kQ*R_94m1=w)Y#Y1S>SfUEPZ=T13_D(>c1tj2T$#gdq`T&3eaE`j`plk83pchb ze#Xbk>or5|n4yyEl3P(bzr}vP@cGwm&3~`MZ&bXIlaw~Xb+pf%2WAV{Ra$0bc zl_9N6J?FX@tH6&3VJ~C$waoti^RG<(AIn?Y-X%S_IhR4^_d&fmO$jxx4b%91j8?0h ze`a+f{9R)GHW~j_Edp!-F@IKWco4Df%$aYs87nWicsK@gNQj$QJ0_lBo|t@k*>ffD z$uV`=^3(6v3SWG=*eCDiu?ykbjJ`b0o#P??qp*x_`n0T@{4iwMi6hJAe%W8O_AKKZV?i@(#}_VVJ&x#c z*!C{3dF9v~eB0m1(BhzQtDfBJs9t?pnVA!&869JK#KH5^wY_6rARE#G$e z|F5qKh5=?G0oPcc7d5en{D^a~{V+pj_QNBa56kcd)hsO5Jv`IN=hDPJRl9Ogp`1I+ zhsxH7E3+#kRG$ut+nTQZ?nLIMmJ>5<(r(VW>vNBxmrI0qf8*=wIW`98ejL=CccT3B zUDfG=r$mbSb_jDPbVT27R?WY@h&y5RL62>%lV>U&m%DprmH9g3LJI7 z#LbObd+y=EKs7b#nw6yu&p*pxy%0e9D%%SoLk(n_L!ScJuF2p#yR~EeYkWqwwXB$Z{!O6BL$gGehivzsT? z9_f29to_=(VTng4yl(dFQ@FK)fDZS2Db#mR4$ zoN%5SE@YYc=G^Snz9kI%=P|6eG-QcdSks@7)>g2st0-1!yIXRK&cDdq|B8#EdQZKp z4f&qu&dRv_^3RB#zeoM}<{b2~V((CM^fBs+{cv@isgCW|=7q=0Ha$CMsxYOLX~DCc z_t$35oAdO*xx#IoLi6+G9jrCy+%R1^qh`{JSvvn;a~^mRyg+HmwUnjK+vcd(&y z?@V9%_1XU2l1#=PSEku$=%8q}bi(3i52IcnO)8N3!h|1OuTd*hkq?q8^K z{nWc@>vpOiER0?=RVheN_5Rbf!p=D_3L`3m^{qZw?s+QG?#67l@k!RJm2WIhL_ZRD zYxsSwN!~#qX||xXlaY1)WP2`^1%}Cb2P}V|INcb-=yf+>U(ZeD$2|7?Ixo)8IVL?< zLCEOep(7i8H0`$XT1T3Nx&6>hpZ0Aj>oLA_9}AI2o-|jod zFYDTVelj;C%W>uI3)-v#A*(GKo!U;Fc_iXemXJ6%A%@XR$E9Yg--M)v94obY_>L!u zaIyZ%k8=B;ea&&5Yzmu}u#5G+Zn}fUD=vs5Z%17P{8{6^21keYPp-s9xip>cem6s=+u#4+qNGs zh__*^`}b8>=e6FY{e`@;ci*P89Jn~6UA$~t-!-v>=!nEPZ|#=S78drLOJ=!f2A_vIh7?EFjhdpo6n&z@_Zwdn+3z)POJgWzJGA9J719O z{X?efclTYprnEqKyH<9kFyGk?p@(b41ej*4pQ(P_cVVq@VZyAvH;s~CD)ns;mSJu< zDz5N!$%UZc$&=2P#UHkv+|F@s$HUa`G5*!=+#0 zAM9f0&~CV&khZ2z`e4F7X777)d3w_rHogktE~z;X(Bbi6@wYmz$%>yYI_CX4{Pp8U z)2U)|BXSm`8Q>!R-c;%4i{yZ#LoWrH+uHzZ%38wlY;Qfy5}3O z?Z3ek!Lgc2$X9vl)6?GT9_h1{U%D5)X!&|xr`{5l7B`mM+<6Vf9Sj^DhbDL(Jub|* zcxKbh%ESZSS`DHHEf^D2;-6W+4WCf?hheGxj=pIzTq{{xj&Z8-oYQ48<7w$&U2)CX z?Na3yRsIi`tQSPGa9SPR_Nl1quh!1@?~@NpUz;F2p~z=D`;CugCfo;_#G*8P&+;W}k>lSc)csL-{ceX$i$dzHnBa%ACe7P>i+M_y z(yP296=w4%^d0oxxJTrJRUJ1A zYzqx*=vwg5-A8nDgTsva_@=L%pPzrOVX5H1a47%SDu($ic3OV literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_turbolinux_x2.png b/src/qt/assets/systemicons/os_turbolinux_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4d5ee4ab1da548ef10bc993675fb29c73610b832 GIT binary patch literal 4018 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 HDWM4fw|!y> literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_ubuntu_x2.png b/src/qt/assets/systemicons/os_ubuntu_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6302b37bda4b3fbb172ec7a9a5ef77ec2b1651 GIT binary patch literal 4050 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 O1B0ilpUXO@geCw={g{XV literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win2k3_x2.png b/src/qt/assets/systemicons/os_win2k3_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..45bec005d0a055df1008ae1ee2234ac3691fa655 GIT binary patch literal 6250 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win2k8_x2.png b/src/qt/assets/systemicons/os_win2k8_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..d97a2789dde0c952b99eda9eb870f0756bd424c5 GIT binary patch literal 6322 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win2k_x2.png b/src/qt/assets/systemicons/os_win2k_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..a773288edf5492935053784ed3ca44ccd6bc8205 GIT binary patch literal 5948 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 FCIH4(=1c$p literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win31_x2.png b/src/qt/assets/systemicons/os_win31_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ca2005d6acff00e65079e3cdf1e58f190d26876 GIT binary patch literal 6116 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 Dz{%z! literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win81_x2.png b/src/qt/assets/systemicons/os_win81_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..07131ed6c6bdade2c5a6d03c6f19407e19356385 GIT binary patch literal 6134 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEDeJ6=w+ta$vmlcR$nF}?TSwmYFa z?lY;gTvy+6Bj1EKuJ%9AdYwNL{;Y~mmRJ@N{7R!M?R@&n$BPA5>|g$L9n*%6-e@7mmgchB4JDQ$i@cmwOhrj33sp<2pZ?WvTH~I9>lia<3 zims~2ZTx?sIxS_fZ_Q9zt7#>v3}pIHQOG)Sk}4jrHMLk;+GQ( zr|@`oTbcCi?m8!}+Vab-^W#%vYlb7U88{!hv0dBK{r*z>pGB+Y#P5wiW&Z4G;qfbL zG&oWX!{?r;GvpJPmhf=a<}cgI|5tQ(MrdVTNz-&+@g&reLtLluBf|`a zUD>OToDh{hV*Nwf>|@MTpSY;VQ-`C4OHXKo3JSmo^; zqL9MD8p$Z}d+PGY?NzcfeQ$Sg$FljBJGAI~3+y``U9mIEin~7k)ZOCGJ2Jh@Ud&>C zu&XKHWPQyGA=A)w%`CeYZ}zQw+7e}^WQlI9(UrdTPv+k)#u&!v2vCB5VIw1ZQor^coWa2>GD zesg#Ko~@tXEuZ@F?arMN%jC9JdpN$hvqh9=&5TK*MunQ9&s08s+J1af{k;S+ojG1# z_wlQ87+<=^dL&8uNc*0`Dz^9QG#`4Kb!0BxsPJQPb&J=(8z;3xqd-|GZ zQ5omHWBoY-Pxqu-KkBor^wB*Xc6{-xJ*Px%8!p^En11w@R`vJoi5X(M-c96N;jR04 zUnH|1C3F}02`S{oe@b#85FbY<0^OwEcuDLBNNBYd^_r7WcS=@i4%Mv0O zTbK?mnB{s&aKE)>^HW)c9CshRvtiSMU&*y>vU`4hd(o2zl3lax3)$s+C#dt*uMf0I zVD6~7_iftlMKKp7n_jUxJ$2V%IK8!#tt3-qyWhEI%O?5UyB%|4^?Tn#7W=QVZDe<5 z2~^NCTv2BDws&@9MHZVjmzu%*YfN7GCxYAq%oVH{FFg33t@ZTX?3P8lNcnJ@41;SJt|Vc z$3Je}Ss9V_T{iLvQ-DCo-|r^uEJ^}pvI;G;cNR=C->|fi@5oU}n~dl`=Uy^bl%_JS zHj`0aoTy!Ui$5vi;W>q@d&}KnAEy?#fzMEuOT z$MdI&Z%X_e_{%hR`S+{N5>BrlaY(y7Zr8Dk%xji7KW8UvkKE*!4FP%!mL5HS+h+$I6{}rre`D@gk ze#-MX-JZ8=_k5GSlaGr|oc8OxWs`98*B<5&&Le&;v9qiio@G@H zUiV_BhEy`htj~LPbm{Sx7A14uTzk9Zcc1s7L(^1sT2d2l?vk4BTzib?QundK%X6GQ zaaVsl6D)nw_FwR$52t_IrOC7#|L+suAAjzLqGU@8(}V3v)eTJ-m;OthweHfd-|5y2 za*?kXIJ6m7aWb{NduQ|DqAbHbJ%tkAxsR*0^*+B|dfcM?(-Ph!?aY6t@*GlbE1bIc zi|=T0qP1mjcFLz+Yulc1F7f?ibiRH)4`YjU`QLMs7cdEJ{vGD?$!oUUoVRgpN~f%{ zG75y5c(|M9t7bQbw@+wlT;8pGjQ91~)Bmknd#l+#-+o#tV_)sn?`@aAM#{(cu4hq>fak&PK!II)9-P-3*>=6VQkPs~ z$SGMXX}HS1&O5h7fUBX3-Qi}OmGZK0)l3Vdyj;8(FPKEHu;R~7*r8|8uz^pJ*GG2G zv}mbaO$iAt~o@Q~e_qp#n9JyCd z!nrtc7TflFAr3d6IIf8>@Ax{K%QMH;&F?m!kW%jgMMegd_SYIYHPg2}JF8;He?(EYjyrUJG7E8?HNKN4WuEERs?-jY~GQy0rP-H#Tp^%`Zy4c7)$!^NE+$ z+&7uyu#0e0*=Bjcv))B7_LMZQd(EH{b(SY1#`gl-#;tim+1LA*=XfbzK9wuJR8`^1 zvXv|S*Uoh+dCxGVb=S_7D<68SbqjZuVV5{%I%C$aY1$jI-fI5Z^2X)FYJdaOv5ZkNtaxIIni*qwj_Pb6EHeD$8lAW*`_ zbb*(H)xmV4#Ontt>l{iL1^W6ea8#-zm3h#o}*gBD>awxy)|yKd+Gcz{Bpx zO`dP_r4AQ+yMI1;&;RB1ee>fQlP@XGT6bE~Nmy}H)b@+pQ^lW4AOG;^+)0sM%>^ZH zg0<`^3pkgsWQlH65NYsmF`XQ7`wNfLw6?5Cn|MlM7%p!=ua=o- z6#V*LEPi&zhTzEt^cqfp;G$z$59-9A0M#${A1 ze>u9TL!qTl&5`5R559}5|1RK7ve53EI%%GHOJ{JmhRoE*4GaQ#{z8Vf3)&YiP8axO z{cTIYrxyYnzaC^)Kaug1CHVK9X7@uD`>Ki+mmLofp1agR5hbB`+Sz$~%iBrGDL=F_^7K-IQ#GwOwck=`3ot2Dn6=RRKndf5 zz6p7g-gCC7PA*?Mry;9}@4>Ea-8pMstoU2|>Y%g#0^3}k__=fYz3xqno_0}U!pt+1 z>#ZBv^Yqge@+KX=_V`QYUFZ1+5=#V`d{3lhMv6%;^tvSFck!A{gY0wl&Be)vkMngF zRUA?%>F-nx*naTQ{PoUXSRUMx5v-1?dBzYezvr{z*4xu3-`ym5xkS%)Yvh ztG@4{^sZHH0mF)UPn_ILOXUST+s2;br4ASSua`j%99b-Z1Ct}$>e80lGN^e6Zmgd z&y@I3<=y6|+eNoriBV$VYT&c#<1x+mFgUxGQEa{4xn2E!lde>C`23HvxfXg{aGj2J zlDEK>$tOLo7&zKK=zh)PST5~+`KjBv{3y4i+kvlK*3I%`Dt%M)JKd(NLSpl?DZx>8 zx?Bnh{%Wia84GqQl*l^0wVU?$`solkTertc*%;b-B#xcgxp~L;^v@C7>LlLh%Q!oI zUT)S=Td`J*eSypho#?j?lU_HZFJX>ZDfQT&WuYd+m3Kco9-kHy%FJg=_%R`-tGnpq zEVhFIEza(%Eh0-98#byw-uZoE{sYg`1yYIEe;#4o^S=4(o0zSWw7-5m!e;a5hWSjh zY__-m47APXCGD*JRI%Pd;n5mxhD*G0`7&w^?^M61@G_hzuy1%Ze@n&tHur3`Wu;wKJhV7^@aqeP<=;Y+b}5uR^eAp+&=K!>>S2-nUFbqV2LHZa-8P>N z?D0Fv-mJJg`hD`#U$I-Z{S5f)^!VoTXUqYWKMdYB8vHZpbK3Cp>;Gvd|3A3>ePiv< z&00Sr1bJFBI9)Qho6a)U-^g6mmRS&8skr{n3$b_gFZ@i;zKi`QCoPt%c;i{|atqOp zj8CsDS6#M^IT@sVcB(t$j_2QAGF;p>yXg7jKVKKyKYLhTH*M4H{jK-qLz?}jO}^54 zd3nb7_7ANSv$ls;f6`#6|9@f6i^C^F=g+^<5O8DBP5lf`rPSsHe~kqMmv^6=H)}nE z$d*0cFCHXK+rOo&*!^4r(=rC2|FnwX*H_Qr`i%iIUKN+B zsHqv`#Tb_I`o^rtU69S;{eZiLv*p0`g$f*}yXLK5SkNLKUq64(CH4;9<@qtClk+(p zvM+=kU`;$NKS@D^;jqC=aT|xcyRY9=m5WAC%T<2Fov`Rx6>pNa(~3z2r<}g_1>9hG zky5<=`r$2?0=I1cePjQBjkwD_@2n0S-F2EFCFS`EVFiJ0qD9xX96ZWk^I`4$N#RBI z{(m3w?&|Ic@Z9dj5p+sW@wnhB&RJ@+mQI$)T(~0Du$0|z^Q#)$rJKD^Xvr`{J%7fb z70CVI^ZFBqB4^iroN-|N{Xe$$wVx92B%Jj2|8(QB{>H-FjAnX2ISUKr?mVcruM=(f z()hE*ptHoG!(y9k&F||Uw{N}Sd@io4tK;dLEuu{MEIz!Ccs{r&__427Tq?8RHJe+z zkMQLSC%E1yE`P>brWbqi-S_enxdt&&Z47(8Js(&#bZm}WwI}1U|3QT#`Qq!7?>`LQ zq1eCXdHoNLcC&phY4>?z>i)c0y3}armoqwSQ~$9hKAgB){!M^HhyUUi2bW9y>XkSA z6d(8RFat{ruVeLrIO{Kwnm^`l-I@GVo8994#Wuca&uZLFEUm@2=`7027hQe+TCmaX zDRw&}Id}t%nP%;73c7la%czFkIyhe_jyUx4htiXK;xQa)Hy9J8 zib5Hdq+EJ1$)TLVLttf?Z0Fki!ou^BW+B%NK0Y(LwE5S{x&^-&u2%O?cxUf(!suhC zOOa9a=F4&|S6Di9I-eY2v1Hi!V8`oiD`&Kw`}6+aq{XZ6r~UZrFC?ON@cc4I@15(G z3pj=8hI!bYuuzC$SSP}uTK;^ZpTMj?Z?z6N{7R0^PN6+nlR9%s*w=Cy6zxR`zsCwUp zs+DZEwG4s_UDNql_pr0?2+tC9+Z(WxOH*JYgVkzI6 zD^}X%?@r{>tgZIGJ@;OwaGKdbrQ}bmgUYoT01hPhag`&gfWk&LF63`9za9$FlVr3nVypc4`ZTDTp+@ zQ+%-N-~_!5If>eS+!LQiAD_y-{N|<~M$TTxCR(p);8tIC;`{rfm-aCDXiK(ot+1$M zYiN3??D5ikLhkB&ski4T2Qn~7W@<8Q36np@duuhH$I=)J#|6(=4*v4`7x3eJXu#L` z{Et1)Pxm75n%9-rXn*YrnRKOSV)1RgqNMi;lbEI+>DK;qu$kjZ z?7k*03Cj|L+Nz~R1>fZo`v2_vy)AP^L-18`h96gr`-`rx4OaaSD*xuu!}_Xe*P63` zCM#VD(N1+$`ZD+L_fMi;jt+Y{i_SjWwWYRvp8N${@1DPD zn{Q>i^!Wtk;%`6JCoK84^ndt2=DUyI{;B%=>rDjvmp5!GcCi}jFJ}40zh-I3>H0K( zBTs+Mef>SVnvU=Lr+Q~WLcp|;oCC(^^(URIKKris<=2WG$0jW2YIvHhD8!>svi|mq zrHc;B)(f#rn0Be4s#&c>d}8ws+l3PA_jjeoMY#C>72Ws!g>A|bRblCX>X%&q{~W%5 z!t;WMhw6*$hll5~&x|xwCT-f93@+8vB=Su{W?R1uH zEmHi2(k8|SQ&U9kd{*5V1WO{rKKL|<|UTt10<9lxQMAttDHg1uLVm|Oj zQkX$yhP}EC^YMvBj|0E#nBwPOw$gk3MwWGNmt1fNp4{Qiazc1_hKbS6HT()UA1`0H zvGHkk`2|yz%=A_QI~& zQ|GUAi(GrEpfJ~gQig@!;+ePGFDY(Za>6z1OXrWOv&&Lq)b{>f_JF^I^YurGmzFGB zT%4k8827lev>yqq?_B=F%&BaVl8lr0Nf+bCIhBmOf}FRw8bu%Sx8*I6lrz}Fk*K6} zo!{a7`lfgLUn=vMTuySRFwb2(_028YxoiF;ojRqy@VNSAxoaDotR4yoT-tqq06E6054OdX@)tEcg6L+o3`sBU*k?;H4KWDAYYrcM# zmvifF#y@Hwgg*4w92BfReC0xk_dYw-h&s0RYZoKxySlb+{UU8PZ_PyE6n1{5h=yfx z)j$61elq`pbkMo=N{^qMX4wBiqJ=?>;Xc!(pZ^8d9@u=~@_%OW-3#Zh3v0JyU|?YI MboFyt=akR{0F(EnJpcdz literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win8_x2.png b/src/qt/assets/systemicons/os_win8_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..ff94c2dd1176a919d4ea05f3299f511c16364295 GIT binary patch literal 6158 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 Y_YNC48u%0$7#J8lUHx3vIVCg!0NhSWXaE2J literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win95_x2.png b/src/qt/assets/systemicons/os_win95_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..efd62799e7bf62b77da704b48550627f2d45c4e2 GIT binary patch literal 6296 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 R`3wvU44$rjF6*2UngA|LE8GA8 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_win_other_x2.png b/src/qt/assets/systemicons/os_win_other_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..fac95889fef6e6c13865f0dd2f3b0b79eab94649 GIT binary patch literal 5454 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 LtDnm{r-UW|Mo;OG literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_winme_x2.png b/src/qt/assets/systemicons/os_winme_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..1c268c84bcb29adbb24f73040f1b99bb8ecea58f GIT binary patch literal 5959 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_winnt4_x2.png b/src/qt/assets/systemicons/os_winnt4_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..c3352abcd66e1ca76113ed2911e83b976b76cc41 GIT binary patch literal 6045 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 KIJ^GysYHX?aST@+U*WyetYCO_zz8W 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_winvista_x2.png b/src/qt/assets/systemicons/os_winvista_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..7b633b79f29361af3d8ad02ef554251c9de2ee1a GIT binary patch literal 6013 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 AnE(I) literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_winxp_x2.png b/src/qt/assets/systemicons/os_winxp_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..b97e6b51d6dc100dead5a947f6b369d2146c6b3d GIT binary patch literal 6340 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 N44$rjF6*2UngEKu*c1Q& literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_xandros_x2.png b/src/qt/assets/systemicons/os_xandros_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..23de5ca91727d727cc8636176d59ec4a03904697 GIT binary patch literal 3209 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 AwEzGB literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/pb_bora_pro.png b/src/qt/assets/systemicons/pb_bora_pro.png new file mode 100644 index 0000000000000000000000000000000000000000..6aaaf9d262a89918320563c5731e7d64bfb1f5e9 GIT binary patch literal 172596 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лZU6H-rvCU=Q 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/pb_pb410.png b/src/qt/assets/systemicons/pb_pb410.png new file mode 100644 index 0000000000000000000000000000000000000000..c78c0496b639e4f468cb157072722bcadf7c1418 GIT binary patch literal 209719 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 z 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 RM3Q5g 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/pb_pb640.png b/src/qt/assets/systemicons/pb_pb640.png new file mode 100644 index 0000000000000000000000000000000000000000..d0be550f1f1ba2a87be86b9620b316c873e4e848 GIT binary patch literal 177292 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

    I&0HeKQbZOlIG=vsTuN9hD~La$&+)Sk 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

    )P-8Gw){B*$rtiiI#e4F?dFyC_7NwB&(>^R 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 ZnxxnNZFe{CV_;xl@O1TaS?83{1OTR%@P_~Z literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_debian_x2.png b/src/qt/assets/systemicons/os_debian_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..a6644c33dcdbef1a76cee5eb48f221a04dd4ed51 GIT binary patch literal 5228 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_dos_x2.png b/src/qt/assets/systemicons/os_dos_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..b6df56ef54177932838b17374a6683001ffc6574 GIT binary patch literal 3718 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 N;OXk;vd$@?2>_It*_!|W literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_fedora_x2.png b/src/qt/assets/systemicons/os_fedora_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..120d247a8ee2cfa298968d87f966355edebd789e GIT binary patch literal 3449 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_freebsd_x2.png b/src/qt/assets/systemicons/os_freebsd_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6f88d416986a1a4aec26f952ba04aa2ae0a80f GIT binary patch literal 3969 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_gentoo_x2.png b/src/qt/assets/systemicons/os_gentoo_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..f27afa5fc289c6887707b2bdc8feb8d29a453944 GIT binary patch literal 3845 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_jrockitve_x2.png b/src/qt/assets/systemicons/os_jrockitve_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4283cad5edecdd84807114174a73a86ef1afe86f GIT binary patch literal 3703 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 B{f7Vm literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_l4_x2.png b/src/qt/assets/systemicons/os_l4_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..9fbbaa183f4ac699dd9da4ee584fcfe55c8fe533 GIT binary patch literal 4348 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_linux22_x2.png b/src/qt/assets/systemicons/os_linux22_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..0de56653ae41aeb7943c3ca5b0a6bfe7001d9d4c GIT binary patch literal 5219 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_linux24_x2.png b/src/qt/assets/systemicons/os_linux24_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..b3df83b7f2fa9cac71f541ce5fcdd7b2d7b5937e GIT binary patch literal 5161 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 bUC;chaQWovl0vQw3=9mOu6{1-oD!M< literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_linux26_x2.png b/src/qt/assets/systemicons/os_linux26_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..8fdf52df7a2705c569158275f91e865fffa352cb GIT binary patch literal 5274 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_linux_x2.png b/src/qt/assets/systemicons/os_linux_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c2eeebe5c10971a95b5215ca9d5b5c1e65964e GIT binary patch literal 4364 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 a)=LlH$y_ze$zfn%VDNPHb6Mw<&;$V5j!U5c literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_macosx_x2.png b/src/qt/assets/systemicons/os_macosx_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..38eb2e5a7115fe58a71a19a99f87862ecfb39b09 GIT binary patch literal 3783 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 X55uVKUym{{Ffe$!`njxgN@xNAf-e#N literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_mandriva_x2.png b/src/qt/assets/systemicons/os_mandriva_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..a09e9c1708bbfeb337d8872e1f3ca7d9dc63bb34 GIT binary patch literal 3858 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 E054=X1^@s6 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_netbsd_x2.png b/src/qt/assets/systemicons/os_netbsd_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..9fa38a7a693b238b7f1d9fe1e135d789bfd80bb6 GIT binary patch literal 4123 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE^?Ky- z`t0|$=XSogKJQ~RGc#^-<(8FaO`L?aZw2*)bVWr6YzSm!>{<}z@PSn@+3{dU$D)R- zVqQzUayx`(FY(OCS*4aa$usBdnUs0uao^9?&M*F!Z5y*YJ2&jc?Zb&aZJs9@i!(| zdAqxF<=^dwrLW~Qei_7UjoGH-{B2e$^SShbB;ieV8E<(MlC)+vbXG3g?#s02E{}oF zsY$!d^dj_%ytkcu6I;IN>v6k--}>vP+&d@vBEDto<_$l!_Wa>}vEDJV=}Lgc^undg zml`fEs5Q~tz$B4ie)6{J?W=MBPMpf*`!0U--$ePXi{2;S-YdU!^HTPgl`rNuT=ze8 zD^-F=@$AA00b1QGE4B7ybO$Zidc0xfMTZyDPHq*ebFc60UpptM-oM~(?e~qZ#p^on zt+Vvdcl<9i$MUV$9VwUn`I-qCp1Q3i8u~j*nwl$^SFK~0Pz*OX)@bv!T&(|!! z{W-||=FgM!0QQIV__?6faunYL-)i4U2b)Tab;?TI>x0; zS(>sVYQj3t84XXeWMl5#-=DJkmn5H$>YJZ$?{gmdTq=>%;Ipt`M^L%jj%vv%tP6L~ zR=D9J#_+I(>!D$S(t(idQ$fKZmX(<&xqf+DHg{W2pJsah?YY7=yJgFqKZSMK8ANP5 zBwqRdnUcAT&55t`f7@8szY2EgY^dR7o4p`t!c+(UiPjfW`8M^bYDj+DB+#JRRa2JS z-(-9CltNg^z8QJ+m&0(ncd6JD*l;oF1@Xxkg?EJUru)M z&fFbAoZAjfzp*QIn(X{PBG&c4E}xP6=Q#aj4XfF&1;*ZdtCW}{Ly}}yZJ4q^SL4F8 zfOCB}79~0P9LNw@km{%D{YgpvtWlW%+Rgu}<|h|59bcCJ%>&VBZ{{6wG z-yylrZg2nNy^-oxMUPxX1aICjda&8JmQ6kWum|S_rFk>cJ}r~(R8yO=>#x9N`ww=~ z-wkVD2z+!oKefoNrCWb@-&&T8?t@Bm3$&KFH%_y=ET(hFLMi-JqlJL_1PuYHRHaWr zlcuda`-5wGT+|au_%;sno@?u_GskWBoco0iFi_ntz)OEcu0v&pkacbx!o} z?1%q1IW>7Y@;&&pJ!WxG>;+i^&W!Glu~H9>m)3;yHRQ?q?tNjl@#v39%bgc;1%+WA%zm)_o@R4NFrt3B76M_I|^{9VpG9`1>HkzK`Y?JQqkiU)pHc=y&}7YsX7p zuiLucX?>?MW8Ko{O0x3G3T&^8)*VPvIF{t_;J|w2Kw%c`?iK5W4cKxgt=c(J>*S-; z=@$RraPBj!wDr%~KTpAiFS7iRZYYa@of+?qkPC(rGQ34ak4Wu0wbpv+Qtr+zQ_eLk zX;{I&Xi@UZC?Wrxk2k$_Huf)L>ew4GzvH6X4=s@ey@@kYdDtYM%T>-3KmX_d%}};{V;4n?9s%bC;f= z<Q=R4!zOixJgY5zd zO^+S7uq~Zykt@U0G5eA1x|f_=t}V$tc@VSFO&+ zdEf7p{a^1B$G{+afI-Wp{`_P4Vu|g?gs-|^zHrc4xu=Hbdkzm<%iaf_o|`9~T^ic= z@2IoQjk}MJ9zRm(l(O=u^17IcSXIs|O1vDhE{|G;j99rkoJ2(HR%dj7Ivadl!(ig+ zxRHmCRuik9;S#bNb+A{w3oT;qEs}i=`ugIM& z8N5nH^H)&$tkZKnr{&n#8y-IW*?iK4d0_$<#00Nd6)`b6Ry^qq(2`h`tZre%B7AQL zuhy%QA1}Oj26UbFw>@sJ)A*9JuIRJO?{43`ZAt0;Z_+`N1T%sD+@xe~lX^X`~wGMuz`w@)2UL0F| zJ9^A5LL6!pX3d!O?9%1)A2<4)Su1aG;?6^UqwfcI&)EN3&t-`NzvI`1F{SUNpKhAX zAYadEHeKQT0-f4N30m(AP0i0wJN&ueyzPh6_I&$)W*96;WqRxNK~$i}Kv(!y+KY-7 z&O=S+j83913@X9Ke@=w&XNk@$QkyDy!cONO{|Vmvkw+%usN6zM=A7YVZ|xA6~ac zJ*|y>NfL3ZPcQ27tBKpi6`*y7b>)S78L~VM3~4=_yY8_m`vja#TOq~fDsZhg*WpL! ztsH$ZCswWhLQ9J#e3embw)y%knoN-nul4a~n@a7r&^$)^Fv`6}u(3 zZFguba8a6}VB^Mo$#tpDF{RkZ(?X}_O!#_9S@%?+RQVTYgot`zPhgWUtsG| zliv;fS~1n%ZLJo(+R9nMe8;I;w)#(?Fc1Lu=}b%JcGu3AYb z9GfL@LD6c9d#gmt^(1CBpTg!JR#hLasLiM<2>PKL(6-*;pu>ej>s#X=8!pJ&P%*iQ z@zH-V|7e?qOm1d}w{iBB-Os4ob?C9UTl=wg6%8ZCMpuhN46Ki`WDBeguiSi>*-4p4 zVh^Y8p~nIJ2`R=soY#As11nV63NHv~-fBwj-lnlX?CW2Z85&u^u~$xY`X0+;R6I62 z!RG6}{-zIZ#$OCSeOGScw3zcv!H(%nN2FtM&NP*CPyB47k0f1iTHNC@O?9cxgiS7* ztal#7x25SdNq&B&P~&ppoLdTK_982*JG*LSH)$|2`D+CGBuBq;Q@R!3FhQeertt}O zo~|ihukubizkXvy*4*y(Yd3wk#O0s2f9<-42Y+TX2R=@D!LsGI!<`d#k1KL!J#XK@ zD`BtwVd~_FLz{!8o2N`#wCIFJyYn^w*p$adgk~=f-!X^VuQc7_?#zcynIc;yJFS)?ds=V%Z zpo=DNW#EM6tkUb}r~cd@_w$|!1>N`yA zXMA;I6@%2C(9KN|{q}O((^(hJj9PLnCDPOCL`2mq)^q<)U#>BJ`{~S=(wJNOwhKLB zTWt1=U-4|u?$Q|!rd16FkGD4zG|48Xv8JUM%h+ohTuC;Z(zZtD1lP%@`TI|`uD3b2 zdG#ds^!tZTP2+TVvdQ)pcfi(VhEm@bMl!y2v$)l=adXrEdSjoOpTd*HCvBOsMmGAv zoBOtBCbpW&&AWU0&^1XV{cFeCeuT~JpC{DL#nEzqhr3d^fp&)J;csgW%(&$-r731A z&*n+3?em{}Q9l1+f@odJ?}OLG7jPLqyP=5xGzXBx1{<;%!}{V?=z$-XAHIlmbYNbWwZ-sVeCdo1@AdPZ zytzK_+5MSMC%%2Zv_p9M&l~Brf5aD0NSO-bSGsaMH5-7zt;Lf2K=Rg>FjwMQKsA>I{{1CId8Ma_vh@KTYUGW*NYj)qXp_kc?IP9Ih&5n5@;4<>vi#J z4p})n#=U84>B(bVDPLnw?KF90zpU)jpKY@xj>x(^R=HlW$Fwy*mf1^X!QBaJW-d+* zY#bU(4UQ!kWURe=#np3)p~qrP5gy~jM#uQe@u719ZR2L%IF!Bj?womZdDky{_~O+j z+h-2NS9v2W_I3uSip*NM&OzfXFUN0(?8644rJvQ$@>KTiO_y|-D1A^;BM9*boQl#rj}zid_Ynn=BKK81;| zRia!3jtB?~whGS{e{)3n$X20yW)IfqS-kPybI9Ryaco43cE;X{BfX7>Pc*Vz52?7_ zpwZ{paPg2NgED7Rqd|hh1p)us-tL|n+r7`&MDF@+k3J=&)XXT6+9Z(3`PR|dfZ3_- ze%T`C6wVLVIX-54UUJN~{l_7(WSei{>tzqN8`nqu|NfJ`A)Y<$p6mbGe~u6S{bv<= X9+#)@`BRO7fq}u()z4*}Q$iB}1aGm! literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_netware_x2.png b/src/qt/assets/systemicons/os_netware_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bcc965218472a24e61b9407ad3320ddca34d283 GIT binary patch literal 4623 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 DmX`7> literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_os2ecs_x2.png b/src/qt/assets/systemicons/os_os2ecs_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..261f9f56c9d5eb304b42d667b812c39994d689ac GIT binary patch literal 4796 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 Ofx*+&&t;ucLK6UbGem3v literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_os2warp45_x2.png b/src/qt/assets/systemicons/os_os2warp45_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a4df0c2361cdc211f85284ce1890f1a7076b85 GIT binary patch literal 4476 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_os2warp4_x2.png b/src/qt/assets/systemicons/os_os2warp4_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..0a81c875961d620b8d6448ee1b68d1d9de9dd9da GIT binary patch literal 4129 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 literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_other_x2.png b/src/qt/assets/systemicons/os_other_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..9602353c0d9bf0b0dca6e817825fa22b4b5e7f50 GIT binary patch literal 4271 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 Z|0iPmPR?M@R0akH22WQ%mvv4FO#n`k1%3bk literal 0 HcmV?d00001 diff --git a/src/qt/assets/systemicons/os_qnx_x2.png b/src/qt/assets/systemicons/os_qnx_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..b124cfa6e0e9d92a753d6dfa435c432c18bf3f90 GIT binary patch literal 6414 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

#&t9+PgihyF6h>8*vGsnWzqY$ zZxapUAN+U{^x(ST?Yb+8&tKKYZ@v}$#|rokEKqiGIBDWG{P%i(ABlmkg7)_&nVdKKH~PFNJ`% z11g;-n_1_rJ9<51TCOk03>JfOWzU8nHAOkK6s3TkNo$T*_z1|kP3tU=G0wOd+n@6< zTzY$x%@dPlpHdyexgzz2<4(8CSm*T5x6wKH9!ICiR*NUTf*k)g+Z=o>x+q2S1H*!o zIfao7&lnB<%y&4&mAUcAL$}CE;rCx#nFFrbdNr$7&r(lYDl+Xf>$A_Sd3Se3+B4g+ z@YFT%%k7I-{4wurg_FaFl}hYy=InI5Ui#s1+LLn^wjEY$$WqPeaXXiseBir%;s@u# zH_hAL)Okq0_-*>_TiM3lyQBB&Zn?PO*oLgu081Xvc}wf|I`Z9l!ROq6Y>TMij8fw{ zbLYm&LMp1vowM@xRegByZ}Ym>dcVFtO=Qby5!q-X*OA5aQoVCgXleOgURLo-m%kmf zl?!W~6881`A1 z5ybJ$KBnbugG(A~( zOY4mZB85&-`(-mdJF&76HR&}cb>3TtxZ*CT=VIlZ*+>?)PcuYZ;+BO~)c zX1?*7(t>jvxg0ijr~0k=qOkMmNS8x-)!AwB70(7nh!>_iEHJ+7eZnIp<4}rj$|QJ~{8`NAborA56Dxf0MA? zGi9gK%Gqa^wY~S@|9$Arxk#B0DTZrGj;+bvu-Q0SGsLn+RnC-SOIB&4mF<>_gVLvY z8;ZpO4w&!z*KV<=jM@Hs@qUK)%5{I#>tz1_xn3{J{=53d-J1v5(|WinUkD;wBu0egR4JQygc6)&bh~^BYIEkE0cD^3(I$i95Z=$#{HbzJ*^i@3r}<{ z|EQ~0bI?fb=zP_x#mDv;$ZA#khpxBFaP?Ser29nj<~CbD1`X|$j@qqETeg}?ZLe9o z>VSr8{J!~4Y()=3c{G)kY^vVC@jz6+{e&yc^NMf*<2vOQhUm9QD)B$S|5pOIdrS+mOL^d9s3Ibl=xh$p*r%=wVU;u|n2 zDkS)si(5s(4)$cOH|GVanH(i=R#vPPw&98a;y5hHS zesX%bc>LeJ_m7^u=xtN|Nh0_5qhr0&SCc9@CjMl*yyDgr$6F4ZJG1uga=E=NBc}O@ z@{UEtg5D=KL~as(_L!-W*uuS{w4%MLF6ka{a^sq?Kz#aCQ* z>!j@QnR?kF;dI)954=}ca)U~Jr?|#tiL76h#BoPsMaP4jEA2w9acNJOIh()?l~7l)@vr-N`0kg&Nz1(Hq|(>%~md5 zlrXd0_*~G6`tZfMx-~Mds;3A{ob2A!BEkObih^=>)3uhHYYzWq|6cI@UhJLS)%?G! zt8d)Bd-UEvx%T+X0}`z=MnP&3cNc8b6^U$MI-&AJVu9(wYQE!9vFk4EVq1NcAz9|= z6i&kx$0Ez?%C_yX3SGZ$HQR&WlDF^P?fdiQx!vzi+v`8a=S?|hn4U3DNyJIQuFyR? z=KKWrl~c~-@^D}N=9RGOX1Zp=k0W=!UVjijF^2bVfTv$1mw3HxEdRYv-+Qk`>tOf-#>hKxIN;XPGLnw$I+xl1v#cA9o;i$+!Oh>Cy2}Uw$cwq-^+)xTDN6x+_ghw z$&v{VZ#?Y1e3wU=BWl?p8=*T%91UVmT$f#6yW{co@E4`wdyh6ASgqAu7zrj<+myaFghdzp*S3F=!gS58c-Q=(4PN1vOGBk1gP0Wy zcP!ocBZF;fB+_ zKkfz#WoNEB%f6rOO54;9hB+pN#{R!c(~od=1#LAn_Koq;d5IBHFxrGwKzPE zT2rXovytPWjLV&dFg-7|FSY&4G9NUvYqq{%5Au4w?rqxrf8UN@FYbz0Sz7=4Rmxs) zmS*Ki*#GgI_4^u|*=Nt2{mq)Mu~TEh;?2|SUkD%jA0p?At*^5#`LGxaj-qTMPz40t=>8`d0fT{8SQ5%ug5Z-73MhO*d87p4?XpOs=SL?%vl_^VMJXUus}ki#~)IV&F4;Js{VvG(GQunM7M1%Ed;rSmauCI@~u z*{Le@w_JPD?Q7=ze^-$`*ZtPsQaydW3#GEJzw|m@-ZpiG_?~uowt_kO=8|?i22mG` zRy&w1kY_8&ZU5QiylzhMjoY`6&b8iN`2Jt)ot?$pyRCQMxP9O8`dNX=#|=7er^vjw zU4OSlz)O`QGo+}8#lLsXR1=Gu`D<8%&P1%gzN73dTatxim#JrvdG2Ldd0E*C`#Za> zLckgH@@BS*k1rnE|NL<7uJ!Tv|4+)_5A<3(MU+*3iqn+L#>6tM>@2O%8SBh8&yZO0 zVojW3s^s3^j3Gwxnk_E#r_>#HE&RY7w%T-$`~+j^-y#uHHS(wK7D`?{)yX{j;ugMi zah;dlpS~sqUOuWa^CMT7oN}&|&NQDlx9;9`-Z9mXM=thy(#Flrd-vKpWSjl^$jIV! zqQR8ymZhD;(I^Xlt~K&DX|e3CEcf#-Y>Ty>P`Pc=UE`qMx4xFi5>BPL$@`WtWgcDV z;L7^J%TRx^iAd*Dz56R${zzTkCvdsw+@#aSS}Hwe(Ua^ry63BHI=oR%oVhva!jTDe zAD2A0c8T_zXxaa5cW_et**=du0vZBNJVK^D*8_TVmRxai>3pr;Zbb3P;Z9m0Kw)c1+zM@G2>3Dx1iCwTH(fW}ch6f?>-uj;w6nHN_S- zH^jg1;oZ+BG->U5hn@{>3B7HX7@oG+vGLqXzP2?&NBYi=I^OMh_m6DNzP@q){{Fd7 z`S|$xH*Vg{{Q3(^<>TL0U&M1*eOPjNO0r)|t-E9Ptm=c6u6h}ZOdI3suUxCIN*yza zI8!bV+`w;}WUt_s@Yq&QFH9-lCHJ1Q$CEjxug|7h^Eg+Ru8ITqSzcJ}Df@eKcK-gq zk7n2ZVbAuiS~&HhCZB@q9J#PZ5#BpR|CY^kF@AbWWJ<=Tmx=asf1T>9&+=b=^l$&N z?B*^OmzFw*uDUCQ*H3PlaPdmYf8B#NUWw`Do#OiE7!q@*KN35o&$fqq z^>dbAmD_2eF1)|~<9Ysrn{OouUAM0MeUv@^pXA~urN;Z0!__}Fse}mKJ(6hPyQtJ~ zVo}%@HQ#HF2RKTD#iqE0hVPm5*=EwWE=`74U*>bMJ5+UEEY!dDB6jte7s?Zaijt(G z7mH3YGnmy`IHA_MF`TulYwpGZ&mbor$1v76p$ThS1EXfCD(^09ozZ30R4l#5?9rX$ za|G+=u6QkUFV1zRJfo$WhKq^r`Z6a8i={!#wfB?vzS|g6Qt`OAdPnJNHM{>m%L@y3 zwBKBFFv+YryG6$<%46!8{T-T4n#@bRoDXqHO=9s;QhwsD`mSrGQqak2K8`LOQ69ww z_j4|6kzE&We&haa_fvsqcHHnS-W!)_HeY#ZkA&()1Jx%zcS>cQIDWl(6B0jn1!S~s z*Q~UkOXvUJIsfnJ{hv^{Aj7$$~zgGeb)c{x!Gir`lppsjgEzRylb?0^zbXk{minzTYiY&n9Z5K{>VSI zlRe9GrC*%lzIeN{#Y;+VpZ%d&1yd^lzjvjl&S=bEr^B^>|C>3Ow(l6Sunca2o#bbe3W~>npgv$V6&+;&Yyd<-L>t z*32;R`qQ&SB#Vu;v3GUaX1<(k*@>4L<`}KnY+-TZ@LcQi59h4sA3WU7U-0$=L+o`& z>89_^CIKwY4jnmnUvIy}>E687aO1@LN3#Anvw5bp9yYjge$IC}t;JOtAx)2tq<9E^ zu79(x(U5KPO`a(2Gta!kmNGp4ET_CR*W0pLPw(9NB@N&R%iR6${{H`4W}iKm{KEN7 zwaDtrK^ck@R~@ZcCYFCTxG!kct(9zrg3{f-_lo`-A4}L9mzbX3&abSrCD+*MfG^*Y zpeOB#%o=gxEcObeyi=}rsQONrK6gXZ!=Rw=X|e2UE6rttQ-U5Cd}wx-y7$@S>||?C z4gTee&)#CaG~t5D8x;!{evX+N-rQck-|c?OM2qK3BLlm>AGAKL`lqT_VvhoA^5G}! z{8=}oDqbvoDNxGL;aes$Wd=tg)6)Ln+OJ_9EA6JEro$i=@z|#9#)ZV!DcduqvmByMf z%-{6-*xA|s_P^gfkE?sCy}$N8L+oV}t)mVhJ?SkRQ;S=|miYx8b=6rKk?dcb^nF92 z)Uv7r)0!eKo#3*z{1H%o^67%K-$A`~myLN|GJEe*voD|NX7EwA;F{9!mZM30OF1n! zt=lK?vTN(!MS`1pFRQh4*tta{zq-ElTHlAv!uzXT_MCj>wDGaDLQM0Vht3VfZ4ZlF zGiI@Uo~wFo`tzWSodVCNXt|t=?^hG9TX*Qs9J_Uu19Vi%jfW%=xoe!Ju^?DE5vmc7t<7V!#j$u0-A5$ykUA^!<{nW`@A{XSKqzM z`~BnNe{%l9X57RM!c-b*i*$#GjHxa)G~(Q1DCik5@P2DZQU9k)5l zxb}72Zk>a{T9?-JJWb+T%2AilR(nR!&_(lB@~WFN+)TV~cKzG?>YA$9c9%8b#Uhpw z-H+!kE4-Da-=Oi6U2=ABlDS<`s9<_XkgXIB}8JC+(Gal0UcFRC`R+ zy|nJr=jWYQjP`B%zMS*Q`nbZJkfWcW+P^(#%Hw4 zVe(XG%^yoUb&k%TD6`EyZFdr<(y62BNj3JT{-&kv{v&%(HK^}u&hbv3Vzc?zMccQE z9eeTXj#$&2Yb?18sXXuB3#$t^Dg6%Ov8}nW;B5q3)%$z0dp@7D-ckKs?%TKN0gv9E z?`H^YcXX4j5|Er&wrR>#=?j`Y@f;?Ldy9H@`h8VosVLkobKQQUSFv}`$1Agyo#WPf zFs@w@w#Be!{?qEdIdd=GXUzPy#;{-E2*-01@1WqOpjkbJBEcor*4FI$aeMyMocqb` z^2IuQ`Kzm?R~c%&);0f?zF+t8OY{8dPd^Ty|DXT=^>n@(4nCJ9MlWN^-@Z9uzGR`_ ztJ`n>_Dp(dch}tbW&V_vQ~$@Wzn(FRZK8#zf95Tvg@qno{IAU=4!JD|ZQ96X=#tTR zczbG2a#8GUt1aseK0T^A|;#<7c?LPmTy?hK_f9_`T+`2jIL;S|0YhRpt5*prCb1GWJ zCuowH#Y4V;!k>biGRN*uRgmGBIAQW9mp><~6SF5Ozn{eZKC!nkSL(}QuNxnvZgpMz zBYdW9*?ETg$tPN4H#R9KUOD9A^y$JZHMt))FPFtk`opodl;Oswo0jZC68CPfdFjkc z{u1gtL3sHK$+a%u#BP2wS1sf7VYFnASYBAMq5byu{KxO^-mWP4FSqW##gTviS=tcng{Oj&-Vy&*DU-DgX3Ux_%Ts!B?To!hi>nqhC*y3MDb zKKh^?|MS%MeV@;z|6e^_KmMOz&qw*VxVUxlb~Q6P>`pFx^lBHVFKI7+J*#%tn_E9; z*Z*Drf2+E`{l9|m=5>$fYqIJ*J#g`|Q^><(N7npz@;N0L&=q<7wr0`Jw%bz{2qp8p zR|{^rRF?E^vD=TrNlfNE&Qt#{JaIj)lGi7Vspt{Y?QODUW#t7WHEgc84L2@5sll>h zrPIPETp=8?w;jz|UmNJ|(R6tzrLrw>s%Y~ysa+<_SNX)5IJ@WnUgD{-?ZDCM{Yzy0 zIODtGZob^VXr+Fm-PgT5K2MVM+8N{~uMaJI&uXjS<57O&+VAC4HpH!;nCy1j%;L^{ z_M&4qe{xRS9LZ~>WH?ik*L8}mIm5=3zMvbSa}&Hz^trsbniL%{&b&z-Lk6s;t5y#=P_6o z)f;8~bJ+Rg^P&%ro_hbid;f3j-J_@Me>{!<`SjWKe>d&xA3r?Ye!u?txw-G>%$5B= zzy8PB_4Qxxmha0}SR@|4{4FT!{;8~1_T9|6@PD{@{{6ZCkNE$4^7Qlb^LC%V-v7V1 zeaR=giA61Ig1HuLG`rw+df{B{loRY-E8Blbs4ZSNrPB4cKgYq(T#lP#wHp_(i19h4 zXt`GIja&S_`pAJL%gWd;?pl7bQN{Y@j0HUYPN$FVkt^^LoDjf$`Nox=M8jh@tj;!8 z+&Wq4VjbkgVacE{GcVr!MyJumNn&^RDQr8)ZgF_mr)8NeY|qwvPSQEyc;@Laot(}}Hv}j3o-QNh4;@)Y#scVfg6?!y-6SgX>VA(f8+5f?{55E^x@+S4P3C_Ni zcdgOLfG0cUQO4aVMjC;=oR^jeIIlR@5q#{IhNjO{W&vl1pfxwkd!IE(SH`_64w1@9SgrYBUDMJQ z1v5dfl{XAO7td0W);z+?rWl)NCe7m<@cemp_3LN7PkW`e$J+mBK7IPM`TlQP*Uw8i zB0uNsF8B9)zu#jAjhH_*uYd4+e}&oXv+KiHz^<Pm8vFU48ZReZ#76UvF=JKWqQj z@_(oQKRbHz|Bkv}AKB;kYsv@+iEMP`QgxDNk9fVn)tf)%TVo(gQ=RIxu+GRX$DW;s z7Q47Da8p>Nv-7PaC+Dr6_9zLqmV?QgZ(jK@Yl=`&M?lmg@9r7_hLc$bB%0?w6$;Z7 z(c7_&&9M0MB2UGx<9ja2gr2buVP$QOxPCJ^%qD2vnGD?(Oux@}ugzB!T4q?O-`e5Z zG2^Ti&uqCU!L+kH7nz@k2)PPWSouEEabKpg*DywUlZf@nr0v&~j&kS=ubH+Ybuss5 zn`^aO_#=CAGIClR6ude(9MXJkR>oZB>MhGixM0DZyGDiIC|`&7FKlc4DeSf|S4Qk^PxqXbw;Q(AE^<&{ResenrK&>y zqM6tdBO%o%GB>6gFn1a8@qPdJ;9spx&1+wq9rg0p*T=hG-=d&9d4ts2s;zGhOjKd; z{-l?a`gFB!e~U<@>?3EzP16DvGzc&ko#C+DkXpi#JS$Dl?A#rLLKgEQ*DS)->K;dw zt=Q7EvG3%z(tLSWQAUlk@%p}N>WY>6D%AXP?|8iy+3J0&v)FDz;uJ@|7J(TBk()(1 zzRq{lnH#g-T*B!{*4|^Uih3m)CM@VNIuTiVO7ptuTczhUw#xUqHTP5(6%~DYadENy zuUGHu-+r9_@8kKp&)o4p4zcI&`}xe=WA*yjxd*_hB)#TrT07?ft>5tnQhHY?iDuX1d-s zGdQ;Bef6~XWjz9HOOEU=R$?=5OPulML*?=}bB+oymprsTab@Myd(WIam=CdRXY75= zlJs6>)68&HpK08S`E66J1)rxyQ*qX02{G^r9v$0Re zD)fS=qt=8(j-vf0JzFzmj(?2Gc5h1Htev#}=vm=y9t*tsIYOs=<-cvVd2*u9&Rg2y zd0h*5zy4(vaDMXS6bDNtgA<3u5p~6uhVIj*VXH;cStdAnIrJ3qIW$fQd!*}l%t|&n zBl%EF=HAy*<+bJI-{p+-^v_-Y|4;wlBmI3ZcD-91|9fiu-*dO~_y7Gkz3$!oKac1C z_$VKKeO;_~uJ!Bneow%YfW|wD&iy>Mw%XlauKve<`+qN*cZ0?~c3fYtKYL2^t6gEo zPwXu4nmLPO1+VpN--RcFI9E5zsBK(-x|Z`g|bc$PF}Ar zx$$k9e&;T>mL(j$EPpJXZ+N%Y=M1NzT0}OB*)u1nfY#4P*43^&@O}k*iekXk8+TUz zS^q9|d-=C6F2mEG82wn1P1B|=j`Tm@pSWdZOVhENvs6~}PU|#uJm}DP<7s%9zG|g@ z%YkWITsk^8KU18%Ldog6RUX3;yO|vqBAB&b&rnj2UT^Mj&!bAtvw4Bm^5&;$sr zZJzhw*jZ@{iyMzSp50YlCo5O9gYRSQxr7k)qan@BJw^t-sY_CSZP|N>Q}Se`pyAJ` z2yXe-`0^=B+;ZOD^1eL%DC?vn^D0svWk)Q&xMSU?q-{B~SbbNmn=RZl@7Ar?+-mbx z4|wWKQH+_Zn6vGZ%7mm`E$*yksur0NY)@u9-0Ob-`-g+cADSoFvIid0$VlE;UeIv5 zTlCkx;%3FyI&l*<8W#LIm>v`vvt*N>rTK|Ww}9Q$mrpnN&RqEV<-dIek36}!1ryD(4dHP+? zw-)doeyA{Q;Y6Q{Zk?}V8{hZ3zP4D>$s5nKC2U9ChW@>OYk6w>&!!pQ^WM-_&#`yI zDdC_m5x?bD&$;kjI^y&_-N>AoTf-d0f)^f9bI~j+)Vy>?W%9BxsS|IOzwdFq{pt7J zZN947S&J`P%-hy}PaY@IKawx%{bkk;$4|OYOt<#|>QEDlIy@ z0~^n*=E$DQVwcion4%ykGEprx_)OmA-#f#$SVx~*zkG@u&*6ffUv7TBdhz2)PQlv$ z+wax?kKX@LfB&D~@ArH@w|VyU{Jrij{_FgngNugXT^$(=AME#h-&+6o=iJxwsuINS`IbeIbO= zP>M0MS;2DJ+O0b*tPkINCwJ?ZVjJV(12SDNyB23koq5jPB2Z9O$Ci6{#*gp-5znsd znC9l@TAk_M5|w`s8zgLwJKX&_x-mDHOJU{`&n@>=kFF~`J3}qPqp#7DbNyPwDU&2p z)r9q)ald)@Hpy;&@#G~>Yh7hH(>py=6?rbLF?c*Lf3=&R@~Y&u$BK3ycy~{TU(V)0 zbpGB}^LrHytpb*-cP~6ON#Ml&(^AplHonQLZ^!mz7QMeTO*&O`-qcF{|1w98XoeZZ zSFSr8_EERKFHnv(dFM|}fqlh(YSsUYJ>MmBFxt8Cy;j^KcG3E4*$pq3IWBho6Pqjo zYo_csR&!zFNlZAoge@aC98MaR*5#p>i5!1uf#}io*l&1{Jq)mnO%on zc}d9^=KWuz_kXR)PyfGoecjjZ_It|T|GT_*@80>-H@^gx22;6Z z|G6vw@8#+44{uH;Kbav=)D)KXxE_}vkP8AegHu);fAhC4g<~xlW z+3wb~eXU}3Wpi^%-*uBG_jb}X6ANqmqbE;t&a?Z)G5c$kie}Swh0LG`i&BFSO_k_p zUhQfbo_#uBFGV>wTQYlz@Bhj3TqkX_|9$6KG-r(U{)48x~GkSr}lr;#q*Zer(P=ARJZj-pYZ=5GYi^M%fq_%<;n;#9=o+m z&Py}#>UV>*Xu-u(lIAzfQTgI={ZVY)v`_Q=E%pA~ul@V0^=N$8uaISui%pCT6_z!e zP1BWQsho7=r3KUN(n}jml#-`RaejPbqp>=V^BSWA-QB!35sEDT{$!?3Tre>-Gsc3s zxnsekH6M-$Zc@r%sPWTc+;*9VBje&#TYxI>%t$UTtBs zr?tBL-G_5^_42!`ci)KAyST;I*W9O5^5yHVU2mIOU9xng8F*{Yr<`1*?DNJlv0{o_ z*PGArYgYahNWCktir>+(FQQE)Y^0KnBH*@}W zcOU)Z?#v-y^Lh6DKU-g4U%&p_w{QO@bUeCxvi2%NOzeOD^>aR3yL@rCe6D}wMgE-m z@wXN)R{s9y=jCrlKR@4I|4+Q`;oTR%n~(R)S+6x=oEhZE(3QR}g=xb_?$EX6fy`4L zP29XnGs)y)ZFt(=H;WW^7wPS&S;2Goz=YIgRWE#HFLIc8Zh4%x_`s>n>s*y|C%M?2 z5b{u~|9C;)>JOJb_sw;G_Dy)TY~#^jR)+8=owfzMYfcuNJ6PTSGpEhqOH$C`G*^`m zTPIyT^75o+&sNad_q5FiZ~nA&N?H{2F~8n-f9xlgqGJlyami;_{GR8xzcWEryybWK zyTT9M8v~X+Jj~GKbXjVN1Vh)J+eddS=W9OlT8njY6vTxqKGrBz2`Tf(M7nat#h*-=`5k0KpW!tzdQge}K=yKPf78Ta6&W<}bri2Dg z`4OGR;jDY(YKHr=Uq*()4A)Hx);ZrkTX|@@!UC!I7{LV---IVmOnn{~sy|sNLP+ZM zU!nhOe3k)=XA1Y8ubgHYp4qeKyT?st4+*yZ?r!fj*I#$VwLF-pRCqa&XN#J~-Gqxe ztrIeix;MNxWoS9_{&?2jV;?_i#>wqHQgydjW?QMjwS!XZ+0q%g6O|aFIKy3yPq{B% z@7(F8^=B?m(wFvt`}93xe*aqg-}d#_v~6+gXJ5X&`Q7RL|5oq* z|DgWg%$xpy_x`W@{vt&>lV zqPIfYH1)Pd@ov^x+m7CJ(RFpA&zNhz%vl4F(7j7>*EpFeOrS@Co*78%C7Z}(y zGuF+J@@zKt_}6I2rkEmeTv5kR>~%8pT3=pID|`FnX`2(zmj$Z0$WK@;Bd`;{* zSY&zp>}>PGx3?JY{e5%W!p7#vxpRC{uMK|mw!C2J>k8{Czc00TcCuVCqn45K>qSOu z#Xm_gEIFtw#&p{tr24K*aqYEblTBuaF4fJbpXGSLMCMBJ99ikh7k?D(IX+|3{{UkV z53Tv8%Vsf56|`H<^8T@Q+07Mt{eO7+Ynne*O%0M@i(fonlJQo;=E#NbfB%vyVq23t zq4-dZq4VXEt3E4oqfLC91%7@`>|u7ek#o($HvaL+$?88|TvV?4ef$2gj~@*=q(1*- zI{j2`*H4+#Px+pGR^6p{m^IYa-pfJw(hQ-Q6DDNFw14bQy``hEzs&ywS5|~n#y=k4 zd(IL9`zxbVL;ub2>yYxu^~#)Be9yZxFD53&X2*^lJGNY_yMOZJ$&)!|)^R#w@^;nV z-ZURg`scp+=AY?duY*fN|E!m4sGqL(U9y3dVQTP#>H708PFDBVJhtWg!*=;UORv64 zs^1!A{yaVX*N-Ph{`{T)Z+@En*Wmj1AD(uLv+MWAor~L3kvQMJKJWZ_KPiXVbuXe* zEOdVqeF!{0V~ydem%k6j#jP{B{)=TXuSllaUf(?@D$Q-mzRfUTKE)WlY?@MMRI;g9 zkjJ_`9+NjYg^ITbT*$9F^29M?f|B%ViA`T$FBf_3=*xA&FwrhQvA2nzIpo@<7!{QO zUwdu#5|R4GM<4yS*uLHTzWSEch0~79mR!_apUib%D*1?EuETY!C5`*riuqQbW=wk| z@9!d^vTetkmdf*|)fa3GTXsaSF=G~+=Y+Oxxsu!Rq|WS;jB30Y-1VY*+Mmk(j^`vl zm$l8AslhQp;_QM~XD1qOF}!j2_VKT;+i%>zefZ!*yS#gQ8ed;upSW=j_s_FQd*ht5 zRjt3v&EoK4+-=RRxX5)T+s+CJ35KMYkP~w+-T7ha|FKo&lyJeJ4ez#d6rOk-Vi$XL zitD5>u3J`}-&57>l;zm2-Q+qbevd&psPJ^!t`^a$SD8hpxKEI~v}##M-pz>TdsMeS z7TK?{aqpV8jzX)sZCVGrC%zB;xm%ItOq%SPZ0-I9HoMPRWj<<%-0pDM22^ zY!ALX5pj2SulV;zRnGR8#QAtT_x+q3t}U8fT2Q7JDSqJNOUY}^=_xvz0wz6q$DMdR z4^LVfPoF-$fBya-Kg4fs+dJdzF5$Il z+I9EYjgG~pipH2S)aP;kWjYXT+4}9#Bd7f}KQGOhGiS^HNAWd3W#9j9PhXyX_vX!+ zww9J*%a<>I_vcT}_b*>k-v4-d@zJA4SJqsg{_4*kpRa$936xAPdNt+JvW73`tYniH zMc&R(TFVg7BgoaVW;2_^>a$U6uRC0h*b??_zUGG05{yzUKB~4pWk09HD>`g6Dd3v; z$t3x~-t{RKzDfpj7Vxlsy7xtzr#XH7mlKmzZ8bS~6rV{Qojq~m=FO*ne<^9|&|vRc zIeGbaTaH;zGrX=Y3gG&XU0vrh>Fud`#)fCIS;YFAGJMJpnXYl)H!p~5^G_!6=g;>f zr#6VQIPHIxeNkUq^xAV~uVv-gGiPj%(AyC6E<~(4apCkw!of$59*rzzG)YT(yNW4@ z`UZE;oS^4AhdNiR0?*>;Fb zI&ke;mfADV7ec9JvyzV}aqugKcqYtza$4jKyZ%Fu2~Lsk4rl1JsAMr*tGTv7DO*f>cai;;np+HRvTy*NILE45pA<&mp$KXY}%Y#`)?1w#eR#U<$ZFG-@K7=cXzk2 zvpe=#{CwfgC}ox~?}*12cCqf7Ss*2I_-}9ag%Vx!V&CS-?Jn2LGH!|aUjBGqIcML> zuLW$A!{hy*-I(_-RBkrIISU6>Yro#jUd|?8?`!aNK8|!cqUPDTE<|Gqb8&YTtL=jW|jy!i1u`M-zf?<}mUDtmvl`}yg|kArwth{#kdr7?>Qg1 z=*Y)aEpwC>aLhiaz1B49y29~}?#;#t7ZdZg-1t}2;Vq!gpnL1juZQ7GXPx$ng+}ou zEd~u>M!goW*?n@VJ@-RKmy>4So2S3*?B-8$GFv}+P0^zrmv|C3MkLtH_g>&N=||$l zTJM7=yN=IV^xkjc*@iCVm_{pa#g%7r=ex*BOb}d{vj0?TUduf0&oP?42Y+Y1+O&Ij z_t~nWy=RYgC(G`i*WKM+WpHjf_nlqE((Uc-8XDQL%o7ehsQucZ@AH0H=8;vF4$`a2 z_TTYvG3jLvJQV$YPow$$8t(kPh4Sp|?JstT^=3b~v%`FSslb~D;$4RPf?F;D>`;@ zR-Fo+JZH+}mbYIXx2%-Bo4Ho>x!t|{=^Lt?WaNL?acvVgHP7y|ap26KPoJM!X?Na` zt1?d_VXb6p`90+$9Sh%I{4FQ>=8i?I=a$@HOUVOEPWrIiK6gZRl5?kB)fb6=dHZ9R z)z24HRkdBd9K0qxJFsEFEWOgVOkSPy?)L^A-S+y%l$DtVudOnYFPQM%lCroRazp+? z=w+)&Z0#ee?}nmgb5v+3g7 z{J5!?SF=61A7&WNP~>y(>tCtWr+H=N_aAYWub;C2b@Bb;VClc|-)r|rtPgwl<;|Hn zGVB=+tza7N`yWo!@jZYWI}M zo|-GBFo{gO#x=8J%C)Gcb3(cp4O29hZra$D#L#OH`?DbR>72=Pm#{AsSio^^>kD(~ zZ)Ve<7$wipjZ1NkqqL1oc*y`8GWpJt`+L2h_6G=zjC$ z`%$E^dA5|fswHRRgcmjBsjOAk$(+D|O2zp9#Z9B$Z_ z`{Bbw=QnTP8n!RYzWDv`j81{d|95w=-K}9$R&%;0DWNO2Z|21*Yi8Q++irdQ>ud9Z zii!s7^8CmD{{G%k_gA2|_=ILhBagYq6!)8w{_7-{EaRQ9^3sl=J-ydT?sOl&kMd@Ba(&x-JgwO7p0KNv z&6XyIz`Nn%a-R2^R)zk3ugc1=DwFl=jbGWfH%%`#zWjY_%2J7qaceJrpRHTpI7#{9 zmbn(PQX7lYcB*w&HGDRyP&NI+Y<9RoT;A^B=H>byF1pJ6#g8 ztAA|n_cRHcWEvIrXGqf6a%t_CFUNUf#cda{irN z-_|!q? nm&Ne!zQ`|WhYaIQQES6qy}Z2q)!+R8AEn*h^-tb>_WQj4xn13#z00f0 zR_W{M?YjSWT5$VU*jj*7|F_nclx(T5sWGv)w%(kco}RUJS4pBo+Cl!!51LO}ax3?S zoSMk6$xU;u$Lc9Yo{oW=^uq=B7(ah$s?@Teqk}ieM|rniet)&+%H=Rd z%|q;dd9x?oUbD?(X2RCgyTu>g$XTc?@l!t15~i(o?BtWTd)d)t&-_m?HR_&?d z;_sa2N+pWcOfo%PQpWdN^IY{c10QX(4LqJkIVT0St>Dv87BhD|s@bT>_K-`(@<#x~4n=j_6)ZTv>ixwt&nkY;EjRokonvPE?6ai*o1*+0t{49OZuYD!755h#vYkuG z30v-QP+83^=GKInPmxjZIB{H?G z-xu$Rdva!z_4yCA_rG6l(LDLOwC{RU?(NQfai2^4xlWk`RL%Lc_xqmR_B#*!{K=($ ze0jykPpWdYe>n8xWD@tjOx)6#y`w??P5k=oHJ3Ono-es@K0&%Y&n~%Qe`!Y4wO`Xi zIW^t#GonzvdS5wRm&oX;$ z+Tn0ZL*kUn3A3eFG@jhNdGTpcZJv1Hj=IGgf4EuS{&{pxyS-YGdic|?s~B(W3gWWg z5x4#}sJHy)rt$aN`~OC_A2z7@_T$OZdq00x?v7gf<>t-E>awzHxz}bteR=ccqc?BX zy!_qErx@gQ^2fgXJ@U6CCO?&$xAn}fDDAaVq{W{Ys(X1VE?>f>-j*16%4NZv&67@Q zPOk{Kxi+xzp!bB1Sppw24#mkWe`d7u^piPD9Zzr_Te55Q=T2sKJw3gJrU%dMeziPb zWwNXie^Zc<`z(RQ&;4o_Ee?MqFeBLM_O>}i={czzKHoD8e-v<%;l=gWuS&umyt}kR zrBQXU$bY5N(K=#l#Mu>>L?pftQ0__l;+$#5n4}cdwr!Q)7O$5VW!K)BKf_|KfxqIZ z9*xPqis^<&v?pyo^814drxw@D*{dd~t}{=T(3@z+X>HxzS=bw~IjVKveFhQ33jXBu z9o5g(-rd>Rd%osb?wdDf4C8eS;?F#2Ny%J$Q^|Ol#Ep4#r?9*VDCN*;;!Qmp*1<3C z7q5OVoHN^{#p1`?GnJYL?tKq+HLP9F;brnIX3Ltb7ureQseQ#@ZpaqBI?VRTiDqh>VB?YSXI^a_;K}fQ5tvaJ(ywlY{sm6TsZW-G-#p`3gCwRYi6-t=o zX(VQDzWe!{_ch$AarMWRIHqiA`h59DO#I%RH}byEx3B*8XSsdVKllIhI{uk2z49u! z^KXX~gVH9&mj6lHZ`a!KIM){!CztJ>Tle=@>F%33a{r&k|9dLGHf%Nf?6b@6=50S) zx8Gj+_{XGAhm~3ube=fz=#$KfNiK**D3dr%1wg^6`HgRy#$d zO^T~qdo5~-z;g$=>Uo}W5necdQ>qKUt!`fEO7LU`7rauREDV+wutp6|0tI*_xUG0 zX{IsXxvW1={QoJ}d_4O6$7TD!!8X<3c)E`^sh==ld~p5zhaWX_iziQ6zW>e-$?Wt= zX`*>0H{>gnrg_?RObnX9)5J7ixU(iuIrQ6(pL6NXqsmbGIlU%`O^VR;(N(G*K7|ePi$Q1wBNkg{nXQhJf`tA+#WiuAF zi;LCO?KN~+Vxj2jAboDrhFb@>vPFITcgN~qZRV<{w=_~W+elk` z>k(_sKGdxU5bs@<`SHOgPPyptvNxP9r`xCJT)%A;sc$X#tyaHpQf;N}%V&=Uzl(|d%_S;_%&sLY$RnFWcQucrKw$uJATjZUYH{5^!fAjudtM~uX zkKb4GbN;%p)z2@ReBFK5Po9t6*+uQxh8fE~+8n##8F=00$(C!^ta5t{qZatHI(Q$v z5S2Yue$%#GLpipybB$M2tq9?9JSyUN>x`O)d*R%bUSCh;rR~%-_-v;e(3x~J(D8av z#Cg5s3!zr?XD(On%e{JmWy`fgTD=198)wh8e{R5Y;|-7ATh=vCGiNILD!<8P(*LJb zTX2=(O5E#nRy^!{YYan`Q+l4Y7|&IF9#C_}SW#PkPU+`Ke?Kd4G(A~V+1B07{pNUd z&?^O=j~UdW*>W@+D!ryE&JmR-Ab!`1IAS+)A_8C%C_N~m&{C>%ME+2VWo zfQj3M4wk0$v$k8FY^au4d*Q3>wA0>m=Ffk4adCUaw>Oe?pB{tToG*5*tN7plm?OjN z)XQCA-##hXp5C_Z*rHsq2^fjE3D3xyUdemzE1CH&>53CMl$xZ)7fZl6Ra1x|z{4Zz3fCi+ z8J8J1*XFrRXnNjupt}FB#U10QOS8UzJr^l)*7fdAwy@&G8Ec$B#I0E@QsX1R-oJad zXxx6WP4{k>N36dt)N+;S+JT#5cR%eBNM5_Osb|Bih3~EB%(XpGwDSSeiyJnlLbWH^ z%$0uICsn=g+Af>_Io@ZkAG-N%-jlvbZ=Os@OS22u^2cUpu;<@1?-!be*~n)6TVTR3 z-j?Rtul0i0oI&%`uQM6F`yOY%dSm&^wSDu`pgBsi>(;L~c*E{9P3`2RF`=3fq} z28qX)Av^eI_&`Qs~%OFlA1=R$RgdPPi~COG?Kdln0CH~8oqK1q3=x?tT6 zf7v$@ZThjBC)~YpH>5Lm)pI7D%t}?6;~(a|E0Cz*3cQ>1+0*8tTBLJB1^c-5?l8ctHaB((Pl+OvbH2nA~Ny@$FvWlCl z+(CB{XS>Cx|4x#g^rpAJ>&mQ-2hI*1g1={*n%(9Nd(Hdq-u(wxXPa02{-(Q#pMx{v zi|w4;4L0>1>oOxxMT#zJ>M4=^{n?y%*S4p%^_LfB>MCTog;hWKo}%_u&i~cTciYW+ znO^N*-#dAR&P?{+Hmiezh^SC}7GlCH2y0hvuuKMZavhCaLqw*ko<< zX1?6(i*jQP&pmQG`}kei(ZC~yMVlSg=v>^iNoDE85(dHNZbuBJ$_QnbW;PiyUYF=y z_nhsP)b#b;X?2}NUYV{3j8*8ESPI>>*qt~li!~0`4pix z<4=I-{_j~rCpT$Jh;;b9{Fxn{&8?XJ?OZ@AJNFgdMk_Cm$JZ5ux1Ly3v3+IYR7U0d ze=LOx&8j&BZ|iQp{(GPB{`xaZbY{wJ`N8@@|J90#CkpJ_zijBUUD~oP`$4Tvn-)vk zpUr7Do+a5FaeS{!Pl5Wd%eU445EM_ToPzqJ5 zN)PuG5oOoby);p3!G=$+OtWU&x0Nkk5c22O;^%A!+B*`ZHr{@F>d5?Bb+3e=Z%3|w zHa*)Ksm(2zPkRiWzAo!RKKSRt#4)f`>E-^c7(|}Pa_p+ zQ_1WNHrA8B@|sJ(xp3n^M)$T{RzpKq*<@*5&mN}tr%jC?`EgizicI-#GGBSZ-o3hx zUY>P9ff@$hH)Kq?J~cX-Yzyd^GeuJJDOW;AY;@SKj9Kqzi>Ng;95Z_{U3S`Erqizd z`^sO;l3SwGcDSKXV&i9a0oR_x4IT?!N{s!FZYl}g%KK@p?%c6?tL>W9|DW#6{rvo4 zTVw6%=jUfWIXEvjYPC(l&cwA7ZDr0LQ)W>7ap&V~Cie5+cJK1Zi##-4H+i$#{UVe+ zvBQkVw0;ya98mLkV=bT1({}NVqWq`(d|4sYY2eJ076^(B`e?4Q%Hx^-;7Hd*1bNmWQF5>eQxojxX6fz zbVpCoD=9Lze22xt!^3|(Y?uG==y&*z-MbH`ZGOBp?)Wngugn|ETvx9Z(2stYBw?nO zWnGeceq~>6|F*}Eru^>>+NIDjGe79f#K{p-+D+Tsnr5ux;qr89sVFL1tSi&mqTJ_G z=oM1TaBa_}i|*$&>$QUaN{60P68-tc@R&nqju$d04%ops@3pm4@m~ zJ`qE|>N~mHCH@|Ga%##15%vPfv*#VTe0E(?$hah9B4*pP!gEeUQFQi0v0BN79TSb+ zuiYrtv7G9-IG1;s;TfT8FAVz@8*X##h)`K^o-g^w^zG%dpEKB*GSt6NIgoySUap>= z-m*fO&Fdm$`PirKE=>4VcmBiy&6#;>FE%RQjXAJV=F9S3=?%Jx#x*N@8~GSly*g|> zk)5g2IlE;B*O9c=Gop+2|8MiN(*A8>{F&7w;lLcV>C#Oa!iw*=_Fw*Kv{2LkmZqQx z58rR*o-&L55vQ(SXe|xCaa}cl?P#8vx$n*PhQt>Udmd~}TU%IGm3)1(;NcDKJU(9B zNox+bF8lPjdwtYSyEeD;SH}PUa8gyyzN!UM*-qC9%$j}4;)piDUY1YMQ5=_+!M>-x@x><^UbvY9ze`LF2JTsHHd+5%ssoSlR&)8^MMRV0{&NzKs zUQ(y_z`bp8&!5aKjI$MBc&%f+_3869)~DHwrpno*>owdk3jgyVICZV`k_X2H40@RN zym+7dx;bC`!ZJNQUagtkvbnmwcZbF;H_^&aZ3Fp*cs&|Gy8s^jjkE#3@E0_Wf(_c_#et zp22ZVLnE7e%KkUvFK&sg%UsYo)$DP_feMKT!AV6~YR6fl&&u<6aa=U6;cs0cy5L5N zmRi_XlXDK)e(RoS)~mgEcFgR5{WRy4)dsAcPZYqy<~d8D(1Ddnqy@8n0WtKK_v z^_Ttr>+D!<|C9NTqB+C#>C<0-{`~o@0na_l>3hDnEj;6yx9xHJ(l;*td>#!G|JmeT zZ`sao_^?vT%=P}7BQDAp=NL@e&(nHDD{Jjd*7XiAw@qMu&Ac^_Md<9OH3Bm%mi44{ z&b0U$=(Qli_hO_i1Lw0wE#3oXv>&i+zT5XUMPE-(g?&LlgKN_Kz7USDSEh4Ucuh8V zpMFGnkyqs8{+Y`<&sKW`eF~X-Xxgd6^Cz?2K316Ewb+nH@YpAl2Wy&~rnopLh6TBJ z7){M+7Gd*w%$Op3?!0)#r!Sm#)!#(U+y54vXH(hpbkp&qjRI!dw6ASi^5e7L<9&PX zuQQa{p}gKln|-y^&Anm5l7f$p{H~BsyYcHpu3m+UV(ql==7L)+9#z^WN~mibX7jxn zd44PJw4^6XrX)#5-j*}%OP1jNRBXR$+Pk;2{I9C^^b}s~d+>6q!C~ge;C?Q>XEJP^ z!rvBd(cb!|VEgTJM{FOOPMC1`e^`@Ws8e3{=M2B*>c|;~ z7ZvrR&O8-5DoO zcjz!r5l=s}#_vULwA!zjAKjN0I_cPbNsqkfvSfl1r+xe0z-2EcUOKUQ!jpqRj!c?C zE}qucXNpYz8Ion+#P;Cs?(+Y?KR-YJ|MlwCs~t5<_2w!amALwFgZp*Uqse<65)b`b zw|s$4v*lSy^;JFon|jmK7@zf&YSt~`4M|Cw-u6g3I8#Msg^aV+&qICZT*I=hoolad zSt?q7qx9b1NhjNdmOt0z6c4OizeYrw-YbJ-+u|NX;Ky-yzr{eR^DkM-Y= z{{Is3H6K~!>}oo;l^!oUp4BFI^TCrFvn&J`zW?o1XPnkn9-MM0MXw;{&NGo65>AHG zer+}ftwS(_*#U$u7O+KHK(&v!7d@L0P% z@WjlDaC3&%$q&*`CcHg5-#eo0pK{`>=f_I--%i|qJ6VSP?y0sQK8tap}#+hxRA*|DC2@t^LGjZRx~_b1ynh^=CD%_`LPBqNk~&S@ze@^Zu25 zSh28ns`|HGjMiMYET{btdbCj{;>@n5f;^tom#MkC?<~r;Dv8y$5nG5o zGK+baF7W*1IKi`_uuo)?skGuW7yq@-wmQvwGMB|N)hV;L=Sp^O)!!(o;H83>RC<@L z(G1ez>-N3el``vp{r1SkZ)J9UlbO;WAT-BO$*bM}@_+XW3^6e=Ir8>(HQp}HkGSUd z7+Oi6ZV|X>a@;(s=j95<6S7sdPp@$_Oqv~|`Obq|OM!R0AzR1}Rw0GS8QWG)WuL@y z?36%4hn$N~i+5;L%J^z5ha~Zp{pXUS;tJ z(Vqt{Eps^VCzeG~`|RZo!3dl8Yc(0|guW%R+q1Q8ZoOhA{5kEK4cC{sEf1!hoM&@! zlTFdN_!re?EiZp>yCZL~YfZo>KDGLJXWOm|s;!p&wDp{Hf@Ot&YN32o?b1^sFEtqb zJt|cX?G%XqIq&3}8vDYiq#nWDcljze=kiqFirzhAs-nwBL!JaHTW!sD2ta^IqE`HzpL)|1o zM=aw=LVKk}-_yR{$CwRa4=xLys1>dm%18; zr7Ody{@j_W@qb6)Y*7m_sho>%rP|l6_L0PhX$^*o+lZyeikvYmT;9RIF3Dx^*e9 zZq)ZRzH3#3jSJVQ`9GD7*_o+b@h3xkm5BelpO4R;*%CIjkxQhr-pYT^OqnC?c{=Rw ziy}JWZb|eRpXE=Dy|DIaGtbRF`)S9Ngn1&R*IzV|RXZ;vlY8UClFS<-s*Z(=C;v!z zW|7#uBq-BrM`P#F91TJ1jgm?~9;D}Pia4Q`q;{VM)^ zQT%uN|2zE;f4{Ha5Sc6BeBfwvaZJpdhaVrizYyonSlS)lbn(b0>*NhDtdD%MOVyap z!n^TN{Di)s=WU4%^6C>0pAD{?lJsJ+esFbKUa)7J=bU1FBP~u_OQr5q3#<2YHs4NM z6tU$}qtI$b7q2MuWivVbI}L(n{A52G&GcyL|MR9yAv371fxRUGSOiQ^Q3!lRs z2Cb5e45E*o1$k7x5wZNu|K;tX4{8n#^O?+c%WnH^yY05@z5Dkbym}>d{d)M0*!&4e z4%e+Datq4J&SeDf?K=6gv3JMItv=VXf2&q$ez|F(Y5&=aBg;$XwUNr)*{OLYQ#ES* zdbUnsI&w1LMp0``cq*@_@XTkMnZ-^uByZ>s`slaAebajOXXj(r-_lS|eD%jhW8z`S zX^(fZt=*iVBP>2O?RBob?~OIr7rjd0-OrRDl2CPgL!H@EFF`Nkt|O-oXdDdGD7?1D z=Y-x=w>J}Y*FP0WnL2T&n@PO>BITLsVdkw86}-!yPgT`6yK#52(8)@}ji;CM1pl^8 z59K-BqQCD4)9=4*?GGE)z29)(x5LH6H#lp~?<)*7JiG@ctNTBitnR-p_B!uj1C^yB zQ%`tV&e_8skmYoHn@qvv!+IfF!lot+xh_m*>zTd$YznikU0i4P`;>S1oU{21XLo*; zWLvXk`>B-ps)hu?8m`y6-M78>6@5LO#c%$}TA3$JE*@P1M;Y~Ajif#wxm%p0Aj7w|4h`nJ}Ltx>6GTfntL!A^@sm4v30 zT@dQ*KCxw^LB$e}56KgzGQKzc`{XoVf#1g9)c#vH#1vh0#JT^R-2W#tbHl7{j$Mvj zmZC4Cu3Jam+~M?Mi;(h~DM_=FRZliAK0bj>vqtcq{|90JAAw9WljaC`9Tw_pQk?Ak zdF#3A+@%cZYv0UD_pkBGy!?I3T^GTHPTZetPp9}Z&;Iy)R`Wy)WhZIo#Wy(vvwKB^ zPU~?RR|cFFz9ypPCe+c{F+pkVLaubhV;uTvu9rFWF?JK8WEy=VMUd8@}^j z>da_81J2opTdrocet(}|P+s1C`*!r5d+RpH^W6!VsJHv8JO4a~=)9&mTVMQ=J7?l^ zz6pDM88bBHETO; zEr3cobKlx7)^F#pn<}&4xzNt#xZ)gNcjW) zvNE>o5qTv&teH)VS`sY|_zQpA&71V>;F6iqA+z(JrfImwcg%L;pOkW@C+oxagT30H z73XAI8XpMZY~G{(;B(-@A6y@HP8T@3*FZHvhW+FI2Ml^jor>3^+7w$48#p%3p7Fqa z%i5!PnhDCM$BS87e(Sub@_HnzB`suq(c$&6j>-vcJ;5`po|o+OvgVClX4#=% z)Arc7%8-w_X2yeLheZ`aZN`gjEsYt=_NhB1++$?;Qrmy}wEK%+a%QhDXz#wJljx|3_wT`3#3=|5YP(q+>BSK-Fz`|2j8Bt-T(iA`QEM6f3xnY=&q!ndBjl+$-|!lo?$#q)Cd1evA%*P@FX zL)BmRM+Pot&E0s5$tu(>`q8oFmjX}87QcBhW9s_!rX_}FC$gBYE}jzPu~c(GlS@&U zi~7Ne>MqE^>7KAFjc|6dh+)f zPEOlx+5@GwuQr|2Rq^wY?!Nk;O#1tO^Bp!gWXe0G^u;Z{bCN!XJGK=Dcqkn-^C)y# ze0TZZ|Hm&dXe@2p|9kiT-(P?J{CPKP>nxRME3L{)#);}(%~7?%(u=txmvhYIaNRt+ z{N9t5EX^s((o0R(JhJ(fq`kU7HSlwPNRC;k=<%%F;JtkDk3x2?oN=A4qot*QMgCcf z+1jU!>jn6|O7w#p__fOpU3Qb2njzqLiO0akj)y&Gd(@lY$aCUCjGcS07;osGVbRFX z86{jJF>%H8W$I#+lH- zn^zF;^MGZGtQ4EB9Vxu~=;X#1Vi{3wUn*5g52Woqnz!Bg8;2(Aehs!2o8HeoFOg8j zF*m$TYTfIlAI>{^L`g3ZIeoJtMSd+qYsfrFubqK>NlTVYoOHadUf@0(yS%z0uhA^a zys|%UCKoiRZA%REN|a&FyPo~$@czH$KbF`3sm?Jk|1tmn^8XWsxtPthPj6OL?vE34 zcFlTmXVDVlG#9&O4PnW#I>vrF=|adqXanx)g9 zIURkN!sc0ae^-*j?M1&+zwMcpl=a0%u&G0F=L%KH^|LabKD+WjI&8I8iSsgz#l0T0 zjrU3%?J|C)k=BrNB5=#z)HU<>voGChP?cTolol?Y-<%V%h|}y0U#TWr#raDP&t>$^ zP4^JWIpku+91;5Jx=#Re^yRAfHF2+FvvM5NB?Xl3}p>rjwU5H|9oX++CcRBU+g4eI#$L&vfb2 zg);Uhs+MsztyTYjnJIL}cLl}vWm>b$%{^C55Lq1aT7YTu&d%KC+7Cuo{bw}kyBt+W zvpp6OvG&5Z(@9FHK6>B6JeKZx$*7J-4e^aUhI>1S){Bkk7-7CQmfChZo8Uot9+ln&r&_S zvc660{Bhe~GbQ5YzWbfc?kBU5%jV1KN7Dn$vo_b+iYthSa2tL!R;f=kP1qe-d*J)j z*3E2OInP9v3En;%an0bVq@z`kdI8UaGtmNN?utrjn^sS%pZrsOro$@jrx$A8-Vr=G z{jve``ZA589g_;&y9K4D6b*3z5I)$`_UF___O`R8Y2fP!L2s(dxC zi1`*9TjR;Mn>OuasGixirHy-oUE+&nQykdltXVGdz_O;@Bvfoo&)ah zQO1C?q3_X-fUU6*uHU&QOAk8pO!`;+J3i{B2zUsJY6TITgbtZ%H#Cq#=9~Z zj>Wps9j6|qPZcz}Yq;@bWcNdZ1-Vgn8?L;0?Y~K`Q!_z^-RE+}`UiC#3a$xP6s@Oi zR5>v{r_sh&wb1YJ$@%Xl-YYt@;b4q|5W}PiOL$7neVezvzQDC-&doQ+Rwysq6SO&0 zZ*GL+{7rk)%blw?z1y+>+X(?(_Qe~TmRfjTl3Din?;E*@Z{O}6=1-owTR>~N1MB0o z_T4)5b9j4JB;`3*Xo}swD`#%Lz2f&b*?W7d+h@;~e)FCA+izQ82gZ!#i~8p-%#EG$ z$VgZ=+GL&M_6U);wKG56y%S()?<8fkmV0L5Hm_;V`;8n;rYXp|?R_^pUG!?Vi^P1V zpQctbCT_P8c*40ik4>S-Vb%N4S%S7Feut^FNVZ)+l$sIU_(k^cPtAkvoQ5tx9yZiI zSY}$m@1-nt{eUT7ZNA`Qn{3asf0#|(f1hLY-aN6dG^al|B(*bA;A1#nEXwQ2Id(ObRq-X^olZ0&~|uCKrM=<4h36`!AR-QQo+ zTONLW$L`2vE=MD2DVrTNZ8OwNeEXk1lBq3kd%sx2Qd))E zrJWA`nxJs5!XQ=EA!-)OEc3@+HJlzz4qcNY%{~Q4HHx%l9(ntUk6%8v$f12xtMbH| zr#-)Qcxjfzc7Ltnyq>fpkiKT4MV5`-{;KewrS$re1|f{|L$EMU!QX?J1xURRi@f2g!O)i(TS>E>L*!N z{Lg)RZu?ysCMzJ(oL`*ZW?NwN{@Z%a4=B zGlK#q?Y_(Q{@&ihx3|Cl@aQP_n=vn#ge1d$RVpf4J`d`6pc=zwvfIhvLCm)2;`n zB+hBRBxT3KbGT*O)(fW|e)=Rhul8H=otXWOU0jMPjsomIBrcewzmQqKa?MtuXHzHZ zWtKhp^W`!Be#QW=+VAG|pUwAgzILzo@e9Thjc>oDqS8foJAKnR->4FK{+3r_TDxAX zj!*v{MvL<4lg}@yNaxL+Ywi#=tJy0)`rFo$J(E|LetK#kvNFC$P-|sU^Qp_)>en(O zJwLE4*=cw|Wr=O9kIg6M({AcBC0(XIoAI!AwMfEDmt_kD_a3j>?6yB5VdI;l$M2mn z@|d~gbMrM1HHJ{u5c#9*>@7>W1Nqc-+ZJE1m5QAmbf|3e(YpO>*MxE2^Z$Nd`sa@j zKAUan+l2Pd;topIac)~`(7ijB_2BgvjPg5HEPEUxwK7U7tL3hZ|Ch>C$EnFNS^{=~ zI<9k5%PozpHaN9NygFmB;k(>pi-W%{1vKQpU9*}q|EodMIg8r|B9s|Jq%_Zc($1U3 z#MjPT_S-fuKkvg~{`-%Qc8f=>eb;66_{|@gYf(DWpTBW=A#-b4b6(F1gCz%Uvz>k_ zM3>)l;*(z#Ym>YhF6{rL>z?@JDKYMi~qxvAvUsml9jJl-`QvOKtV>#4uTKAFf> zZac84xHr==Nh!)U$;yM)N&2+YWhlXc~B$ zxUQJ-K-1CF#FSI&fJTf%&k?>hFXfh&!cReGMDyO?d$>COpH%$6SJQtyyZwH{%{K)f zA1KCLR{F&uZ#pN_z>l$=Sv#*Mb+XzwZDoz@g|W@sVmGX@bh9}AJy0n@X3-LZGNn?# zO>#4fEg7Dr)cpE5(S(8F!_VjQ^QWDDTDSRT#oE$M*D{n={QQtAF;_l~Is4~B3z=h+ zrX90Ni2ic+0+;4{nbf%tnsptF-+aJe#RDxye%-QpDmY%-6Z-U6)=biVAd+d3V6?Z;8 zyf;&7&fK}8vD*x{Sr{Ihabd@{8vT3KckbOw+IzF;%iFBx*Q>MlRDNb#{Z%)}Cuoc8 zucwwh+a{G<-?Zo;XV3l8jM-xAvQ^p2)Lw7R4Zru_C|64N;@YF#)p@%%F{f?4J$;(z z7wJ_JTvyNgP5o5q^ka4`zkN!5jmgRIjOMUyCP9_;d2`#u=6QN8{9!re{PM=s;~YWP zx4gI|c1*+PGRI=kJ@YrjzTf%c_<<}XmB2!QHEF+}FPo{_DYM|PkCe;lk7hP411N^ zGLIBUB=#Kp`IA*oPhVwbz&-H{on5T!ZPy+(==0D#wApNDg_Xo%X4cQsBbw)G1bTJa zDKf}MGJp8-@$ucu%l*IS-`n%?&feKhe2*-ALccBYvf1&OrNW}8A?op)nv>>9tmaY; z%z8(3PDnLJ@QLf`M9ujnQRnNSRm8LAO-a8_o9N+(uKUE(_ip5x`0(?oQ=t=?Y!-+z znlYug6t8)>yfZa&>b2R?Jtpq0r|(I-Ii6l9tr}!9d7;loH4mX_$t;`rJth|X{l|9x zZm^xpq(hsM8&ns|Uz5;anikvt(qNG(pO8nGTHl_{sVoX%MY}_|-V}OtHJP&gU3A={ z_roL!@uO|u|NL?MSX#bq_T9@Or}Rvmw;8_wSpq^MPGmUu>T{SL2@g{{mSH zrf3~={5ngaW#yYqQ<;_(9(q`y(Q@?g!-hnOuEWaerdC^W`IS>FbaWX7lbz&)x68nf24nqskIz^J=bj$nVd7Ak)sh z)wg+F{FxV?mk&g8U*9l!-o`UZ>zAM1lc(%ypR#GL?)PfVTU}je%f6jhE)${u`{kXG z`HL8r3)}9${_%hDr}K`$~eZiFXS1R{)(*_Gg zzINNN)x7S}+N`cQag$|DdJ{j*4%%wu@#S-ChI&i9?}Z~iQ;(IlPM^fPXUi!^t8FJ@ z)4zC5e?7C_#ZjPGIAZ;bKPCq?-P$%)iV03wU?A)E=G&ZEH@3?Dddl2#^6{%@V*7tT zv#$BO`~JhPtG7q2zkcIA+nsgWS~vWB@UY*Ya@tkC=HqqyojY0*B@DV!wmot_6v=#B zB18KLmu`#Q>WjKjenM;7W~z9unX^=3UGu9OdwLTCMWQl z`*d2L|JV%%joF?~M^hGS8GY>+U@E&U8Dg{{ng^bhTfG%=}Mtx`!0)YxGPssx36KdZuV@=gAw!6HnA4o|DL0{C+6N} zhSYN|PflE)Sjn(3f|*&~YJ2gl$ZO5|VtclqFQ`8kaN-}2m*%&m6*C?#<+Rb{`}%tQ z+K&F^e{3Sp)-=WZ`261f$@F+{spr?_H{O0^FaaT_F zn`;?8nxC$Q9jZ@K=y}YtcBaVIsI?y+9rdpH{)u(p|9{ncDr;GlX1EWqYe_{pM0W-^+(WS&aC~1-+9?W!zUA@ml-;NxgLK`=VEkCHc?m zVs3nvt&!hmKlh#G)}Zj7n$j=#K26E+OQ@F<3hJ4m7N1c3T4&nbofAZ*P4uG6)p-s# zynQz9{__K67i^BJ|9G%;;?1Z^*zKQPtzcs$o=I9z8 z&E9FNW^q|%tzi82_{8^D7JW}=J+*jR_@(vy5t~Vz!96d2v+g>|oU`5f&#%+}8{%uf zithXK$$L-LU$$Fj8NXS#Yz#0k*yXr?&w<1b68y|&x21E;cHd;0ZK2)rzFEd?T6jN8 zdUV8VmdLpVzRGhRf7Xt+eEyz4z+;hKm=|YY$+w#i?y7V&EZB03sq9Zkmi;0&2hFeb z|KFtB|2981Ls!ssk%yOIrLOZ9NjKG5zV;$I3w|ivUw17)JiVapaQLS6){?qse%?IL zdU@lfO%89Owrag8_i8XwkGt*}%Ff7nC1Uxi(4#@z=X{cwl)ugB;<(uIC{02s`ij(A z#@XK=C{6a(QTI;LGLdhv)H5;H6{=n%=`>F%`ro85g-;uDoj zBG^4?j@qstcW%_YaG#rO@L#I?Wl-M+Tis7T8RnhrVtj0oG-1WZ?Cay?$txPuOg!t76CR1Y}K6NGP^rGf%zQ zqxJr3=)<*Vv^o}Bq?YD{#+YZ`y!Wf4M6=O!Nm8e~o$9W_#s^I^?{8PS?9;OE^@VS| zV!qllzi4FdoubtCm#|Kj)B#4}mP(5<{r=)q5==a?^+jX-io!WXq zRCBgac4DoL@>-3vok5zLT#h`9I>fEH`q-2QsaL1;wtFdrD_Pu5ye0d9dHsTIyKVE{ zM@;+P9beNK|M!WY8QoU`F>&O!#W3d3bf-lR4QtXg2c z=uYdZnIRpKQD(cl12sPc=Dm2Mc<#gUwzF&Qo!Bt_)G=FzN&KG=iYqa2r~cevdQ0JE zhlrBTCJ!|y*TRg`mv&mbS6G>}==p_7H5)cda-9{@2$W5cDBODQKveU(><2y0T{*&M zjyO&WF!kkr&m41EYzt%8Ls#ADdo5-xyw`u%1S1@{ugWaPYJO< z-P`pvKq^_+`OpzYkC-(TMtgVeJh;0&e8=A1hqJaG+P(e#hkt*obGAndsFuX`A5H4q z{Fz&YX-)3KU46lyRF2<^=-zzh)bzi#m$z(YIdAq^B*0s?pTd0va0xnX)xQg1DvJo8)@zK_4Mw(b(%8q&S2&_c$o=J#9gnE3mT z?p_t$_x~Sz&F{PA6`#N9CS5SdZC&+av3>|W|t0soJmc&NKDNmk%_{}a2w*ZBy7oELa zGzD23zPWtiJMeXR(C>++4F2-*RusPT^IsVDK#2d^!(v%GL5qxWv!ai6T` z8w#d9{J}FfTRE>WrX~0kd%tDZTAjZ7B|AA!WH1PsoRw*a@tGpl)EBnlR>-FHDvSz$ z9F`tgrWB>Ns!-x$$MpIOlYJQG#LrXMw#`mK>6D1~p`_``A>o;Ilb?T3ICXIz!$Iej zZ1+B2znQn)K(tSp?V!pL)g5z?!tao~h4BF``GK_l}`av595pl?jREx;cL} zQtbN+zoeGOXTSTbIIlP7*S_@}S$6_V*I933fA&3mk6hBBw{K}kTe zvr~dr1@)eJX0~bKbi9j*K(*xO+JUDR_46+wnS5r2O=n9K$g2<>zYd zOD=v8b67ro>l$Akk(ZBBW`vr1oy~5T`QYSFnN$mhIqhvaqM=?w8q1T@>~$Pk6x7mv zl)f^UoI8KMu<)aRxw&@D&!_sJg&Gf^f>sCcTkr@U>(sq8bz8=7?;iq&KEiyLI|^qM zNU(kL>y)$m5&3r#!}8q1{Uv?Ur!u9wla^;nw^(qVyy4_x_;kHx>u*)Wk`FuvS35U35F%YnWYz^)=mkUzlp(a8{30Fe`@}Jd3pKo)vKWm4*5|V zpR@))nqe3#ykp7S=do2?FJ|*yt~=BfW^gNUV?+mAyvgRE4?h#UmwtJ|zO(P_Qi+K| z*{?r;S-&7*$`Qfl@BbKX^v9GPjhP{$p;>rs(uq4uyn@1d1oJL7Em^s7-9(K?9HNZ^ zJR(ACf~*SSfne7Jb*6at=PyV-aKrc8J35>%`fRw(*(S47}Y%SnHU zcEQQ=0ySDE7~B_rd+~eU8jUr%T03I+wALmZIdY7>|B3RUCxyG?9)4YY{l~M}`5$Mm zuW!Da*T3!MjrVsdtU8KE9KmBIdw%n?cpew)Lq$~XX7xUs1pQZSGp|%pC%GHg^ zKO@o}x=($V`Ej91b;_Js;*O5l;X5LZXKw$Q9Gn`xx@&7$kEfCPCNBqZrIfPVC&wJb zxAfe7o06->yQ#EB-fS9YckTIyrpGiU>H(Iz*j z@WSKkimP}ZIjBrKVx*}r{a(T_IO(&-&SxQ!VcNQE3C15y0w0*hhD|=gvbIMd;Em(M z<$+(I+Bt~p zSXswGrKbJM9|#}2+vq#brOv8n@}0|*<}ywGo%xJcvC$;)1M{5X8BPz*IOa0)%KSO9 z+VkvL&M!GDmiDq`K6B`Od?M~&*WKQEYRkx)cWuC1}7uD_XzfsOd)n@MJ`oQ^5O)<N zYJDO6^TOgI{0YmhW@SIwa5+Frr0l)VvPqeh}sDvP4l^=r5`jW zZN0a^kXLV-w@=-nL*HZ$TKByWm;LtGaY_Bk3HrT;mjpJ>-Sk~}QpT;#`VABJYUp^K zTI9v4`1+Bsf7i|P4Vw(P&kB@&X{ACRvG41tIk2-rZyEqF|JWP*uBw8hGzg-+s z^yLI!L1p~yZ+ud_o?PPIrf6LrHc#W`?O-p7<(zdg8*k?nmRGm0eyzQywz@TZecgex zcXiiu-eUdb+Q0d8`<`0{Qf}9n*Chtev=lkM>0MmHpFfk!|DN^K+x_qP4 zqE^4PmEEcJ`+22&bo!O$M}&)Xf1X~w;bXaWvD%)K%b|6JMDm2IZI9Y^PqGQ>hbDwXtnJG11ba=N3;>G_wRfYo7B$AX*IE&Qare>R^{xTnAbJ_=`Giy zx}UTbJFZg5xE3`*&mos*PU;6uju*)}40Yc&&;R@A=jZ3wqh8u(x-1Q0a-1A6Ihplq zT99BO-?@{#PJHDzbIfFRX7TvPA8TNmD$sjq$6C27QnOaup7bo)UHm`M>soo;iZofP z(ATUX21RH6!aWq_q?fSx>6P!YR63jLTT}LfE76IA;b=(LLeU`ED?AUimL{GIyDx5E za*%z^wd^ms?b`}xsPSi;dSq_=R&wIkKLMp4#U)D;kM6deeR0W?)(|uI*I61WM=L*R zZu&UsQqF3t=K>qH*Wdeo{Kd@o1}binEdrtU-)FAUsq6D+Iu#w`RZF; zzTb_@KW$^3cfArIlxg{)(pHzShvbPTETdNx7TcD$sB>!h!acVS~KSu@G#4FO;hoFbxjhycmGT&s5O|{@H z{z1~!W`+!>weGaNxtV;XaDx%uD2li$oi_N;O3wS`l<41+FznJ?AQzmf4r_x>N;f4^RjUw?a@?6=>wb5iSX z@*g-;U0!e!hy_2jDp3lFKd0|u;|qMh!UO)@E$7YL^n z`6XR;`*Y`3dd%jeC-5w{cV-+g?lU*EaD z?sN2?Z|3`tmmPjLgXL_tD#P7JLWXK@z6%EhF);D9GsX#7{LFc1oFU<^ahTOadAj16 zGk+r{YQ8r9wB_cR^N|nxm$WEFYM6J}6`k;zs^q}^(%%89#voN%hZ zNs0H|VP0jM94k?0r|N69t2W6eGZz#VI!>QHef8(hpZ`8A=YfttSPy{Sn%HZ+=ql(N1Mmr=Op5q@xdh{LFmfe`lq- z7W>w1Qd*pu-e-b+Ogs*rH#_X%{%ygzn~UZz3O~rzX zep4!$FTcrB^LcmX2>(6t&lBfZ2Rz6-Dv(#Uskmv1$fUVjH*C}0@2{!k;udr)@qmHP zjlAtU_U$`%T73P7+4t*O%k$S2)YUcCZEOf)tKC0^(^WLwcBx7B8rQt*y5a@bI49RP z`jwnN_F_`W^)lbo4aS?FdkYHXR>V%|t9^8t{ZWDc^{`c+TGy-n{>`TC?z(qg)zSOE z=5-4BKNOuaFGx|s>CCE}Yxm0+P0NVdacx2F9E)hRo_0p_)!!xD`K*n&_UIW^UOliP zQt`~vpONOX7N$Rw|KO6h{p@?e#cNt)xVsJ* z_y!z1WID~*=vbhTVdLMr{)Yw!t<t5fuz#Skz?pYDFGQ|FrkF*;aEXsg#M-b_ zt{1=eZJ3)aU*)SZVU?Dww&z9dy!1miRA*+TubgG^Z0g;zS+=JAveLvWxvJYq>GRH>pr=fuH0Rtzo>A}^7p^wa_=wB z-TCAEq%G5)R`ovJAa~Y|@#nqO#_u&>E@oTnp%A(&z2Ew|&5UZDU;LAqp5$CzB@vW* zWmR0TrsuWh3Xcgbhpya{dd1w~xQN5|=e(@w_CnQ;6?d!R!HW8$X|hZ%Q&l@-76 zpgVfmMV9MQnM{idShLz~XZn(*@nwhsmcuejTX*=9-d$;Jl{reBzt?FH0|DSi?udCq|zrW3` zurLWI)Aa3fZF;D~=hE|=^YUG`;DjcviCWg>OL-Sh(QKIV=Cr7??m0^h-ETL7?yP;3 zUOOrDW&4FCJptEz9eQ_My`EjhxK`;zYW@7B2cqsM)y|pAR2fj{8Z@(agGbxeo*AN+ z32O7Z7P)8tUU{mnhqoc9tM1?D`TyTtTHGGq8a_r-Q zQ|t}pQyOR9;u73_H%#qkKu&S?=Oueqn;cuTe~x-)dgSMITitjTv275WlIEfk*mQ~Q z_Fb{<=G#G|K6O7HvfsIL=TY9)wAFF;Cr`N_yd~y8FOGp}Zglp8S=)TRoj%Hxdp&Vy zj8k^+(In1v*;&^dqoa4IY&MHgQ%Rij{K<|Ir+tfLGIWHt?|BvQ%g&~H*YEYleD72b z%~fJKvFXoFN8MJ1i5Z)`Pfm4?(pl!*baCn#?|t>@yiw^F^~ECe#9v6&@pmX4GI_M& zwgOj>aFaXNz8OrJzD7sc{uL*8-85i!ee`TW#oVdA>w7+^^eph~Ek1N*ebE0U4~>o` z&3pb;@aNjHh8{zY&$iXCHv9B)b}Me^xh561@5qz|TMu6SYUt`J(bn1vu8)IxvuRKd_+Wfi{Xxn4>J$^$*Fj{*S$ly?QlotoRkd-UsRVr z&0MQ`r|IHJ0oy5I899fu`5!u@D8XvQG;Bm)tnX-~s?O`XuEC2a}qfV|g=V5;L?%k=DJ7sHUY?qjD zW0%pJ6RoO>p;cdIJ}KK3{ie@*I^OHvoJqZG`JB(r-6f61 zc(uo(FYK=t&hu_qu&$j+WkG%X-fdU1Or+K_wYWK7y*ojJbI}YRzLP1NJkru!+*;g! zyeYS8_WiqI`^}BTwh{FTe}!C9c;3~u7oXYocJHMTo7DQI+=T3qQr*m@`(Iv8LuQyypniW)9|@*|2Eg{w-2!QuX~;F_JHAb-tAYi zuY^uE|M_K~>iz13G6u#7j&L6rbFTc#|Nn&E-`jgs{@)K?J$?Ox@_KGfjpO$ucxSd$ zmL6u*ZMeqfYkNNK|IeCvE2}so=d{!?%=n_t*m?4~`MC*|B`V9LcRcz3cJ&6=i?hVf zOwbp<=c)KZ-KFB`Gk;kXAD05n4Xf@jaFm|?{QAU`Ln_lA+wd$FWpPgm-*qU*?a!_heKJ6;ugoAuDJF!4`LnO>+IUs{GIU}KhFZCSpO4`QqKv` z?C5hZOyx5cmoWC8(KFNLZ=`hy%ZrrP_w5zGX?Hh&v735y@?%r)qKrVzDSY>WSuDln z@7?_KIk;&_d99v;P?c5e>y>Bodm0&1r+3(>9bL@v;dc~+P4%}m*4Eb5`b%@xZVht^ zX|&zCQK9W*lZg2}8~*ee!c+2lGPXzG`M~-3%SmAq-?^f1GPk+alz(E-j=NJFlPVCP z#d=}~zgAZ8?7}?{k3Dyq%W(dY`mB?uE&3RzTw~Dg_1@?^>uN8fO_SfkdFl6?Y%Zqo z7VXiTFjsHM%oP)Maw{%rSS2!Lv2^X$UGA4dGQ><}=5r+r^yn`WTT}exs;HNfPV)6gzg7{JDL#MWX0hF|v;WsuS9fpE zzyIj#>+Kfx<$ZV8wN7E$e3L0O^x>B$nk?s=SFd7oafuD&l3U6vb!9W#>7zoWq3NY{ z-)?a`E|7iavE=(4Bd$X&Yo@O$(bV-%$ca`@=+e5dVP$q;-ZLi`h0lI+LcHJq|84(w zXU3tYfgB-QRjQLe%oD%rF(aGNL*!bp=EWIYp}7}AcxSZ`i3e%k~oEA!+)-1p@$=GVs^*AjqBO|szt&T-|_0<>5b&{TVk6lmW zQiSHq#y#Bp@BW8u_$6Q@d!@2F_PSAULrDI)(kCo0R|?-K<%_TVs%rQDs`!sb)8iMs zm+kZKKWVFEG9_@rEWhK;i)Xw(D7f>2am}fyP5%Vd6`m|Px+S#z!2?Aje-#&l+@O@X zllbQyncAW9f%U|qIbU5)9J##7Lg)FfNNZEhH%|8s1bd}svf5Z%H-DFVeKjp<_ti9! zhBk?WTz>P2jLT0-uSoFje%z6?kI#+KBw@?31a_I1k3Ve?W3HXiFRL zxtpua`nbnr!=^B?&8Ma~PWCfhnm%n4yOUl_kKp8W4GIhD``FGcS5|x=nK#KJTI=Y! zV+?a2XPf@ao~x$OZfLNtZL3_G#DWm^Y}vMji#=OI6r}G?FcoGv$R{dN!*L_0Y{hJ@ z<>~G#UR!;)QBc{k?t+Q2#M+gqYecWz_T47!xlrNiimK_Ry6@aHGh!V#F6g-Ryv@18 z=UcqGfY&nCcd4nla0Y zxisyw5=vTJx-t0dt#9UVX^89wE#6Qrjkum9%hCoAr41erJ z(>W&!yq2q-*;5} zm)pMm`;HxZj>*^kH`UW$SMcwhY>P?2tp^W&uyBh%OmewBaqq>*YlnEmDsPD^ulbx( zJ5}V=(jyZ7b6pSa+2@g{P?789+T*7bCI9)Cqou@`?5^*k64!TZO6@;%c1!))CDZC( z2`rg^yELURcb1g@Je#MIwubh<@=n+v=M(et4q4X3!Fc#W|HLC5mFwo~96vd0?$N0e z`RqbN7v9d1Jj|!p&?4@jzqE>lu{NHYL5}&3oSa~MgQAp> ztE1EG9`}|hX-m2`zTcNqy3Ezr;(J4>yz=~jr7j<)ai+@6Q&c}}a6sbdtL)R<%Uxo_ zKg`SbsL)6iXmY>(uAo}Gpr)i_Rn`NUNT#I|W}JU+VQF_TX=lqMuB$aHH&>jAQaBi_ zq@}eqAtY49L-X8~#aUS;vHe&7^6Kf`d;IkD^@{KBWb@YLCsW1S^q&q%Q{m&;B1`f1V0^X9ellr%5e zCoG@rq|~MvN`Qv3*bDLbvl!k70<$JI*gtE_EcWx})#E?qu4Gcj~|L=llQfREnIJ^Lx#T<&&S6ZEr3; zkW|_6^AE>$bMqg6KI?zjegCiWx^?RcDl3~8F28c-_Ume!-!GES%nH8Y@jdc(V7c~D zm+03Scb=YDrE#@_pSh8>M&js~9HyFK?Y|ve|cxkB_gQrl#j+PTSY2Ui18WPf`Msc^)1XU90HCamCkm zms(T%(pv(e)UW z>hpP)FHe8_`h6Vx``QUXuWJ^5kg1c>nUwbG@pq4IcgxMZJ>Pv-{Xd)5+`zF^blx0W z$JhxsE^*p!Ex$ZJ^PJoKd5=6iV^-}se(pd<_>$S@n45Oq$~&PMDc8X9A39J88Feff~cw$$v!F0p%wPj+@Q=$g1J2(`DEb@f|p zd-rMWnlEoO#g*IE7Kr-IvpINCQ1$oBE~m;>r&4YRRlfcC^x$#`IG0C=?OZ= zGD4<0PEp!E>2%o7_GgPH@7!}>iFXi}-*Mh3rz3k6lsgW6V)rVYb3~YXiC{X@jh07W ztZu$YUZi=#wV87+o6IohU9xEMhS$|=^44AaYHe{nm|<$r1TP0J ze!&bsJ*T4X4_h;JMKl(87#+N1*}tOWPsCNV{Clb|I?|43Io)AS(OZ*Q{J2`Dsv&t} zZNY~+pIo2yo1dt*IGpJW$xt6y6aGmnIqnB#LLJ^lO-^Xop{|9CTf{=?V#|2UFG zwya`Q>@1aM;ApNYYuII(z_`*qzxvI#+-omXen;Jkuywj-tTO3g#oLxeo0T267j%g% zU*x~ERHfkhfqsrum$r<~1KB)ou6vIxnV_ZUlG*aKSzSwG{x9KgyK zs3%c-H95r4w$tF_1+8syj835*J6~}z#kI{jAiDDupUv&iNxIE8>wT1#PbuY}FvDYG zzI_FMy2+gKn&L@r3*K|A5?=H)%=~QUOI1x4hVA9rGV=2sUP&fRDVUcw=kre?c6N6g zJW!O3>>6YXYC{<_X6a?5nTDajt^bhdwDJ?!c9VX^A^4JN%wL0wsVKKkAl zkI!UKcTRLqx)tN6uYK#QV8e&WuNBK%y0#VkGM^Ost@4Z})9O#kQ;c%deVNvqIGwuR z!Obk^uMzOjWU*ko;jBb+p=*2}u08tpj>-9UYS)s6$IqEG9{pCR+SU~5|9)|pN7P>d zrp~<{{K?t6(W-qV{`tFfLB z_`KHRKuY4}I};A^G6N4d|xZ0^?i!h2`x<;4k+26ECb z-)HtHKJhr_eWv%x0S?0+&xLEG6(mLClOIg0?3@4WqtlXe{#E%~LspcuO4x|8dz*Zg zWMO%=>)6$+qPx}|HsFcS6X$5;DrM~4l~+(z#pZI!??$4-?rh7$M<)6mch}Hcr_`S0 z>6p@eGslnR_!*~%AJ)7mR-C(Qj?;zZ(n&meRoYYU9g}#PEOFuc4hDl`d#b-(+{~?+ z%6%aC>v`$qk|){y)5ISf+TJB-s(IOAimvIzL{rX4$q4@k&BxRB9(#I}H7mKGsH|<( zIz`csTTET})-u?*@SKTQ*s6K#K%#lct%W}|I>n|=@OkSkzVF%kM4$CnEcvE-&Favw zJnM5Q$&s^uVTNoQ=L(hdF6RT)<*pu&|`}W=-R&tWTO}_@=1V)z|lzzrXkJ)h{;l>)Uti z-Rrpf^~T8e8(vqRN#mVjW?@y?WW0FcYObhNZ&qLTTDVTjgm>!)VQc%FpT8Af7Zz4{ zx^gO4jUq$t7k0l7o|!5OmYj6GlCl5GO}D8{!7U3~y$_`FHTCapG2;wdegB zw)}9vR(0X4(&mOOEUd0<_f)D3V?Q;z2H)|z&h@#n`ROBu(6y0QJU=YicQ@f`sYF}f zT>Uf4`vrprJV}Ddt?aA5Kwocb)KMj_KpHUbBE*XLK*Dahfh8 zr5h05X03dt?LpIV!&5h_=O5bndBwrw49{hm+#bp7weOlN&1rG@yG!dD>E=~=3>kZV zz2lABSJnGnJbXt*eW&^J_XR)y8NK$K5@J#LNk$;+%+w8xwc8I~;J2``XfiaGSiGR8 zZJkJYa|VmWLX~BUjLP#)P1~KamwmR-)B_QW9}`(Pw{!oy^Rv2`an@G#$Q{xTn@-2J zn-nSD&P=ju`BQVw&p)xJ@$JjnyxU?-g1*7ZKRV8)b>F@nUGwFlv5c(j!q-+Ip}m(c z8^0;DUK5rb6BFauG~sr$tbojkOX4dGCI?OkYc&7&LQ_>lG3i=}$+2$1dxCF+y<9Ej zTi;G+$f)V&IPzd|_^li6;s?I(VGwZI^Xvb=`TxIfom6BSk-c=v)&=c8Z~q29?PmYH zQG$C@q@eU0;UJ5`U&<11IoE_~&(UVpXkC7O-a!qaW2rADsFdV<*~bwi`TU;}>!J-C zG+(nYJn9s`+gLI~!0DrnuE;}ehLST}4+Hlb9I_I!Q9Em%+*2So;bQ9T_z!YgXSv@t zL`g^7J}^V-n8}4I=BqE8wuHBEdiJgZO&z#~np)V}v`v!QzP)_L*=GjJj-Nftdv9ND zcXv1Up1QwM-@kv)xGm<@EBTcnVV2bSz7^R5tPh=DFKd)Fi(dd+3t%MG{Zr=jQKM|m zw9wu(v-8tzrn+PC!e!c{r zx$n$Z^RCO&7kqf~??cW5OGM`$+EeWDg>hHrF^OD7i-^@cA3Yx(@9C1A%rW)i1ULVk zzi#=YeS7l%nrrtxMc0V_J3Sry-WNMgKhY4pT0eJ#-K80)E!*F2bG^?m^6{>Y!jwjN zo4UV8JPI+YJfqIooyDt=GR;Dw{TE zmqts&N@<;^f$s#;Ty#G$%#Q9;y2P_j#`4{6^GWIUbE{6@nQ-R#f8m9;D>-JJe=a@yLYs!`n})j!4&OTBPj1A z;MC&MP+L>u&&|M4@$u2oRWr|S+r5o<7stDw6BM%S7v}so^c9eK{`q2YpKW(~-n#Y1 zoF7hZ?hi13>=~}ft65?vI)$^oDmIYgN^6J>-CvA%H>qz086}TgzkcS_3Pm~_U>#9nRV1&v?tKQvd$^%okS(yUWZs=?f8wy z>&)gGPO5C&weG@)``K#~f2gdqTvRGw7Ho7zoi$nUj0#WQ9FDm`;SUye=zs9!k~r)q zx9Z*Z_1ix^pMLbkkLR4RYu&^hKAMWm_i}9%x>6K>#rP2W=M{@HvqHR_J@O{=+ve%r zPuhL=&`(CM4HW@y2P{`SVd1!vdEw130S58I$@iKbbhR@TyPcjJ*mjKLn8Q*NN7t1z zQh#vIU3J{%`;P4w*z%w=@KcS(C z5^NrthCIxxRvjwZc_g7)XS(;LCmOvEZ13%>Y?e^wPUgJ0`(}>9(gQayt6SJuIrRwE zUOyZn`pDqHpFeZ9@HH>(NRW5i+tod1g=LwHTUIjXsz-WL6%9Wo8M<$BUGnAR7rP1B z%j-789hXR4+w0`u6h%wfUNksc z-U_k3K2vf+p5Rhu!S6=POpMGAIG@UL*~VpT8Jp>O&2>Gql1w4XmWQovwmTFTtkXPo z{g#|_@ZvnFExFzM-m9w{S&4>zxcBhwPs>%O95i@yO_r?s@Z=`nULhS|Bi8=Q_PCQz{Z}k4K3je|-#?PDr zFLb)5ypB5a`AUh_Y$MfUmyIH?2E;@^{%NQA=j9V^1y`BH!NPZW1x>eKd%eqPsi{w@ zhUo^gf;@-oUtetdej|$eb+yIoA1@~yiuZOay1(C2*ZI#K^7SY;=Cs-E;V_VNGCX$PuZ1l8-O+qJKI{ZmC}T`z%}eYU?#&(J`@ckGIGF6RZDoSiZ2ly!~j7=OMe=hRN!@Oe$8{iL$ooUdN>q zc7E+ybMv8s?8(Qno-^ei-0#QiQPt<|$qD%i zA_-#I)pzd1J(qs*=1ot&hTk7;7T=~T7Bfqp*3O9F_guMJLCAd0;`Bzr)1GB}nBE=Y z4te5J%9XINWpBrc;wLXNmHldtXm(C`(R}jK3(I-o*6gvN2F;GK<}=Pdi_m*H<;phM zTiaT{r?|eUEVG||_Tie=H6|PHu_&}2%CSp-Z*ca_^wZ2&N?8?IU#&X0X68bpS-EkM z_ZxSuJN~9bY>#K1yy6{p|36RD=DnHz^Rt*?{k_SL96I<9l@#5M?tAt3MTGn*z`GsXlC;C-FpxJE%lzm_P(fW z0{@cei&;Jkg?!fXBsQGR{V}m^`m4D|&igwVX5GC$Vb`g1y&^BU6%({3NB(}gRW9k3 z-_ApA;+qbXZF$tWkwL?n;g9LP>MgtZYTecU?V7n!HT1#N*Villev{qz`<>~%{rf>n z;L4&Gz3^PBa8<^Co}Om-;lk|)G{2lXXxX1vz#y~6--=Hv{m6p|Wu*lceNmFEr|dm*`cAJley=w zV}3P@>-9S63*Tk0z1HR9=l>Zew<)0Fh1H#V_Z5#dyv=Lh_j>b$jqj_O7I3yMlrQRY zi|komxU9JE@E)0#2@x61k1q>bm?vz%IpIV^!{W)AI#mS)2VTx^u{)=1_DZzC5 zOEE7wb*TB!uOFo!kLh*4Yb`#!q|_}pWA5!q$*)6$CwOekuzsH4#PEtuF~Y)K>y1jB zOdDVB?a#ki#R^%^h_PP~&As>e=bUF7KUbcs@IPd;w)EJftfikUly4r|WY*+AFI6eh ztI|hlMbX0Agr7RMKL&lUcs~Ei)HhrIA57Z!<$IA5*PV1vkB&RS3ZZuI-$``)9?TOw zd+PhLMc>ox<}Y05ljfMST{`EwZrNMDd$$GeG&4*U_l_)CpRrHhA~eWJ$xF$^tIX<$ zgaQ+%z|u!AqVqONCwJ^v&coFG>YH+B=Ev#DjsZRAfbHxDNm zT7b@!ENA|;@A%7?!ZI>4kDtAh+yCRJ_>ZUS>szPauj#(J%yo*Cmw|+7Pa8@ZkuMm0Cl0okqQE`#<>-lkLOl&ux?)`X%%93 z%6IP(o$0ZClTrizRsOV_DBM|Ox+UnvZn?t-51u?>S-yO^KvUYc>({Tpu(Ar(Ub^9K zUSVBb-`jPE`|ExZ>FDCU7lxkMx49i zxe><-8;_+)AmjY!+a0}lQBdqGk09gw`|}?^-Ci$q*VlDoGEb@8=O3-C>tiy5?o?>K zGVGNU<9`s<-~T?9k%0lUt8V4%s`B#k=hIH7F4&^y&nIDcFJY#+?lSY(T^*V#?VI;J zzHzFH<3pq0qR^!$FCG8C?REK%UAq!m%a7c=DQwl5={uV-`pXohIk{ZdFGL+S%JueW z<~T2TZ;RoA1$&=1F+a`>)ne8Es4jWWi$lXy+fP~U*b$p+0a_^m0-@igXe&I*a9?uv z-m`{2lRSlsQ;%Nib#?K2x9at*JwIw5t$)SkChf3-^Mh)CB#Zw6VX1G<2ThfFT|%EN z@?LuEM3idx&bmzvh2F6$Udo@I2X!s}Hu-|u`|?kpKYw3*ZAruDC8s$gBejf$6KeJ; zil?L$EB{_-DCHZvaGq(#tFAXaO;(}TzD3-;7hcdh zK6m;I>&Tb;yjR3Nx2@c7>uO;Ax|2~*neFw4sP!M`|3B^j@%H_HV)1_;=PM>~JkF7- zSa?&(yR$fm@f<5p^U@zL>KbHqOm^!`xwK(k&Q_);YLatWi_dHk7jhCS{{0}4b+7t| z6s9u610EAYzfMrO;^X3XTrpfMUYz!Llyd)a$^Yx6zS-Uz^+LTCOILX$8y(f( zWN}&IQS_OtQ;R$-RWo%X^`-}SCGL$&-hA`Hix(W9f6B14v+vls^Z4Dnwt9Mc8f`n? z|Fl}lWX7qn^;!edn+Ff!U^rl(Z*|}|=kskByS6%Dp&&7Av zhke-Qo@!DWk>v7$ueQLzE%`-Q{=KU%kBo!_d&dC!%Vyq@fwG=VA5B_hB0tLD^}gsj>9^TdRE zHgB7FPffs)Q8GL{ykUXB+{>4ZTND=dBpwV6+BQx7svwWEuKrOa9mA@pmFAra`nf?r znKPN6_-bnIxEzr<>3Ce7jN#*!Hf55gBth#N<-7_~vR=kWYb1qfXcD`bHPBkFNsZcv|xvM`D>F?DFXkSXPV^Ppm#&+Mhee4ncrgEK3#6&D}4 zz#owx-Vk76Y0J7}um7qaUGJH_tvKaAYp#6Y8G7QNqhOPB-kRhcfiI&vQvQ3-{%Pl3 zzh8QSmB-Wh>|#gQ2@y*d}ZzsQ^N_v)#XdkjD7{MNsI@PebA-QB{{(lz#~ z#2W@xR8-Hf9?EC%kV+6y4o14?kj~_o?E-o(a%%SMPI<@A~Qyabc8e63pqxM9$NF19z zjZuarqg(mM(t!Nw`_;PVe1ATrah-_Ye4FN{8)TQhcoIHuT9To)pS?1d&)QUp+viTm z6|Ab8`+Y*ul53q#J9R}ICmdmCDO}8(cSc|an}~1llVy(%YhEq*?=rv6tyANi^qP># z6Mc-nJ$pXM=WR^FlJ`q5RX1HySC`xJ_PhUw-^z`jO5dGNRo{GF!^l|CEj;3eNXwIL zR>|?LJu@$aOEL#bYAiIEZ8}5$h0Btiru(DTZ`gVNW12<5uGI|_h-r&rtmQRC#_DOvZm=YCwZg#E&n058si(^h?%Ikjm^(P6K|h?4z19WmK&T@LKJ zoA*-WH0uI>!MqK77`5J%*>1b7Th3zgs)}u;)E>+F?)(4VY1jPzx_!sKy@$VEm0h#+ zd*uePbLIs!GuId4kum0GiF(XCrzinE>k2O0b z+ZeCiI;o*5`18cQmjzWdO*eC<{m;E$dLgv+@nhwjZP7fj{b$pdpKEZ2WS>3tM{&KQ ze*C^UF|TvIH-G)IbGh*TNnFj!;%;}Z+&n9gawaLZfn{I%@^nx!6&f0`e!I+$()PDy zvu}S_{b+Ec<7tl@!!_Q=iVG^@qPVY=2FIN4tIB2Ns&%|Y97Y>4 zhA%&M@Bh8~|KFqC;{QK=-~Yds`vCLBBRv_l5>i|1KWRr#smzN!r!%qQ_KAlB3I|sJL(j?*vZ=j{wbd zPydCjO_!LAn%;E!_U>BPViPNQCfoVnt8ItRKGofIm+$X|z=ubtEIR+r38PGnVh_zzS^-lycCNov-mDwJzod!( zO`YWZQ?+E|_2@+xbJI~)UD@+L&&mv=NB(=}vk@lZK5<(Ni=&Y~$Nm8VIly0G*tJkwqN z{@&xw=k1(B8VqOUrV5>_oUzMo8K*&yy<6uACRcH{XsM?LJ@0yp!rnI>7l;YF*WYM< z;>lj4Yi5Z>!Pnosc);MLxhC(uK=P5a&55_~2`;&~W6!>0Z{NzkT6XN>OHDq0{>`f2 z>$aX!|NW)d?TdMDblT>dDz6ppD@QF%($3oy9~SDIIb+wM8oT2!Uur)4Y*}_&_TBq; z8zb`*B7J6Z#V_UIRIXeSSa>Pkx@1Mr#7IGz)6v|?DzB%Ba9jUP$?ZORBj0X*@`FX1 z@{BL4c%xRkiyug4bm-sz_xAp&`~O_kf4_8!GsnSpfu@c(n}sh6Z7f;0 z{`y~ibw_TR(3x1-|LbgyPG8qpwB*ABQ~#?U61by<9vz9vXh?5b^+U?iafh2?fN168 z%qxm5Ck!{QT-Dk1VL`{FgB6`8?YYjl_&nKcByYDc`-7vwsehUE`-?Z9f9)U1GtqzQ z&HnS;lONu!2$epQ&1If7YgX|i=BCmYzxiT!AG-Zj>SF)Nq9Cu3S$dnXOUDye|FNijS7B8<;i(CCxr1mwijXl*j#<+M!gPN42#aGjB}utKTNw z(WJ?`Wa64;$&G95UfbLJpP#dV>B_YGxmAa(-bdB^ed}HG@u>KZZ&$rb=C-br+GKK$ z@4=qq2evPN>zSIb+sU{$Uyzm4Rnhc-nUSWd&)T3O7rvlNv$_I=mhsInH*R9Be86sB z(RcfI^q&vy_Q#%H73EBAb@|fpb;@$Vozm`_QyYY)?3unxrO&xmB&2NWkCb$u7f(Al z)fe2!2o4O`_RsT!<@rXR*I%W!$rn@P2whe)7UL6ELv7-OWo$=d@qxipAR~#WzqZJ zO4_QuvTg^Y?wT{s^V5oaG23No(4}v(0-M|1vs+iK+PuRwJO9uP$%S(muEjoK&^scq zM^xbNW3k^63=9l$dny{u^Y4`edA**~&obZRp(1N?{E;_bzjof$4`!Nue)a+Ow+XH~ z**Y~_SAKoo#u&&H6n5iX*^hTuy$`i!&CSjKBJ*U)(s|qrCr{kpQ>o6kL*YoyyNH&W zT?)lUqKrS^2X`$9;|wzwvwnJV&y42xE8AUqnku7JSKhm8lVSTG>kIap8P5H-1UcDGKMB zdm2*0oW0s61o=Pv7^HnAly~8cq!k_f6W){@3#n9I(7Nl)Y>!tpr{~U|P3A`;}-s6@8O?6E#vlAHm_bSy~le0k=Nn*8{^hr zj6TljFy-_ECzlQ`C#@ETx4G|MPPtVoa^W(sEkoziBu+(M$;7G0&Rn@;RGz%fsmH`D zkn19Q%ZrOwjBnjgFvu5Mk)w_$PgC;o~y|HFl4@;(r3Ck<5#1~e3 z?CZOGpDU^NUO1A`F2WjWbo6;2ifavumnsNxEO&aWlG) z!{A@riin%jdy+oO>z72eh^nwOEq`LjwUr^JU~-9W)j=U6w~hxJZ{B;n`?~(ZEl1}6 zy*WSl>S~^(otdg`2Kb&NXJmf=-vt%15l2en&unGgT(?k8#*P%L28f zmYeKtMQxN?6+I^=i9h@yFm0aujm-?lI5HF!m!t(nrm%aQ(XA6y&RV=ctMyoj&Hnj| zS88(z8uI9t?G}CaK8h#y^u;}mf6sl{(Az|3vkcVay+ZtuwXTEZCUvgNPd;m#9B87#7I z?se!0wf@pDDZp@1ZuOS84eOL+-aWi%xMfr+k9}2Vt8DH z1H;_6imffVvNb$BCplB@ereLF>Z@cq=)9zQdUAhiPeECO&$WcLiE~>+xJvIn`0;~d z`SNrN3yULp+d*fG=;`ZkwmwkJuNg8?`cV1q1%B7}MXQP5IOyn+utE3W^c~F#J*V`P ze>8Ya)`;@<%}DUS+xQ^&9M6P_d}ex9GBUD{o_!Nr6;xp8;PE#0!`ut6o|*6edG-It z9iXB65Z|!gc%A9b+uPe`pYG;f?QvLNl;e(KZ^-(0)DTu9#jofzR`>mUmeJ2i0Z#RBdBrN-~^kqp9-^pU{ zm>$`NOG!TrW=Zh7GrzolbVkVsol^%zzH2HsJuaBW5+-!zm0o?B&M~2#YfhYBdBWq4 zf8GM>Zq1hRl5BE6lzWwOk zFWX;v-0#^HI&9b$I{7(q`WNm9ayrFO!FA!H(BzLCJAR&=F5tM-Lc(3M%h@dS?C0vU zu1yd4_(hq8S1kz&FnA-wShIjvHQ=iIikNo?el*_xdeJ#_$|sMRLQJKh&f1?6^KbE; zi;58Y82Mbl=E4>3kgH7j_vSse|I=Q7K;P~^Yux<(%`2s@oRzsH5%D^4u4`(RLrBN0 zbsIHQa+A(2e6PFrpM=2&wfWrkYXxsu%_y>%BE-`$>8M7Z)21Nr=+|6c!RBYJW}B)l zNn4*Ndw22YpF*{_7q8+K>sIcwU$=0}k*w18vuUkw)0)4g^2_5uUI$R zJu4n(cFk8xOY?lV=H8oLRK&mBtU@S2?R8>k=!&gwx8H7Bd(GNEOSMmbSySt~n@hU< zl@75OcAs-TvT?Gw1!G{QRqyOoPFJs3SXdmmcu|ny!Lw&<_v?NOHC_FGZs#68&82E* zy7@C(zg@RI`Er4s#hGWtCceFA(++>OJu>iEGP5g36VS^0wT6A=bLm# z+S+U}5}dMCM8J^ag!S_`%3MD-GMo^9^kMe>Kfmhd%$xV`tbC&*honGl%M;yn|CfB{ zPS#!cr6;n-a!ONXR#CoAK;2vB_g4Df&RNF9#~#+$^r7a&=%jDLy-Lpwp?o$;)k`omj@TIH4a59P?)1I&fY& zK+wSG?9VAGUio!gmpVU8DzsE`a+#Xj&nOeC#UN%D5ER!K?AKZN=I)8};U{PO$$Fnrr@6n0fo0-Gx}^S?^$&&^_JN z-x`h7gnldSHGi@t=;ov8?h=Yd<;gMKJ!#upzh2<(J;eTm@kW|ibqS~k`uOqBQkNAJ-^kT_I&?Rv$6d^55uj6 z^X;nHma6m%Wt^MO&3U9KV?MX|)bysJM`{yXclfg1KXPQ%^ZP2*vgccBJwDf*WM%)E zUuxx=;;ndozHzYQ2esZc_x$aH4P;e0zb+Bd^qOd{&$Q9OMJpShk*c zHkKy&h`oNSO%oObwt4lj^uJ&-yxrP1$zdt4SU2n3H`=#iwlciCZqAW+VB6x}$$P%f zW2xG6Q($R-DYIgM&bl*?EKfd`T5H-Elyr+vf@x`INhCtZ=cVx&nGuJ=%yF(XneW0=yi3;-lGOQB22{BI$EVq4QMz}|cAMK` zb0n58+csUd&@v+$KW3*tsd_bL7 zKzy&~YeD6r7w0d0U*Xd#t{?Z{HdUsp$r< z^4E}}?Mqv_Iz654TUhzL?q1>>m3<`P;o8UN5)wN6b*7o{uRSSeG5hQfsZW+Kr|e(} zIhfTqQSR3~kA*EelC+$Ax{v-TY_HW}IClKx%a;XZWo7HPzH8=hG~3KRw`s5M>%(i; zZes8d6M1v?#O3|o=9Rx{KmFt4P-_sJ{O8vzE~lP-KaVCEGJfsJJ-6|Yo_Xy@#`o27 z$s07ZO0|;aocr*Y{TR2hSFsBBv}q>{Z4IAIb34O&D#KOBopWXOf+=n;S<{bs-u|EX zoo%Oc;5pfq&mVGz9j+^B`d{FC+0ubcB6i_S^BLi6o74K1Ej)5ifGNg4Vf((LdApmx zGq3VGbThHXKUH7~kDybxjzKrWqRk3(RVOOA&e_BrWU?t~qj=gsngJGr09fNsy zS{DSKFo+P_?6v3)C!?Sc@8n&cK|Pf$Q?C@Xb=!o_^%|aPGL>UgS68q2 z__0_;kGq`4US-pA^GC@Fs&HKBcHOnQP zw=X_CnaKJlf?*1OWqnD>mtC2&e!s2yY?yiXQFCvdQjPX8X0MH=ZRYtd*JdT&=?N8_ zy<7g>L@TDB&snXWR^QvTX8dW8Nsh z-FM#pC1cTbr%My=7QXiN;?#Jw%AHZ6^`wuJmzTBT@1@0y5+#FeYI##{a9(u^zUI&+ z?Du5nfwc}N&#RVaM%ZLbal4u!ky}u(p=DxI+CeXeg4LIJW%JgD7hGe~S>(haaOm(h zF(;uI5ABI-3y=5+L>entR)urq*|u*~m}IkB+{>uKJy2zx(v@`rT!Ct`O^Zrw(ljol z$G&ijNEW)$KG$P%X4;$uS`*`)XRW@}({iZg*E;v(UB4bE&*A^jw=ZnA<+ZN&f`OdvkT9i)*xQ3r4MB1hv;s&wN8@p^vhWV7iKZ775U75 z>9bhS*`cXs2Mq0INQimf)q5(jYw?mJHDQbA=^9B*xA|ML z>0ZvRlgDPueYPxR7TYZ8;~K@qC9&zo+p-UO&zv4S`N8n{r%k$nf?Le}druDCsG44Q zfAUwA3q7-0Rte4Hz8P4XfBbi}iiNm5&yV0Q=a`!==`t&=T6XGW^VF4wvoF53u(3;e zF!|uCe{$>N_8v=+eUtF>bKrzsk6yRuH06IGNS#d)Q;d{Mb$=H~o*R*>%2WqJz*IvkbU z1X~39Wg3n%B@`*``pUUolu&In&(7nAjko`|KXT=~?ta^Y z@s?~F&dr}VtwPVfyw4!fCinjS-o<>4Q&J8Knku&Ro(kG0F{!=YOMG?*gR$g=a->vA%}{%{^yLwWG?A{!Tmnf}kp)4C8aY!E-(+|=o;PRl z+EQGWFx}~an3d-G$x8Kxi(?pa1;=W~>SzB~dkA%-*TR!#B$B%|- zn_1J&%KS}W^oX!d*dR9htkmhFO!D=A1m{Q>)bDrd5RAS3w8?{mQ=aj4mBW<@b}2!L zv6&~_(%*ts#g*+oYQS?N_qqVbj=g)&%35a~uKxGO?aum?@UC(>y7@Rq0-kb!xXa~=^o;`Qh9lrWaYWK7?%ey}FPBGiF@zM;3tkwsO z2ZN-Nq!fiRvUCD2+0LKj;2yM6-)&ZMxnFTk#U-7kj}%%OR;~KfaYW+q#+xpVt=~C5 zm@Mm3`8NCfv!8Vfwz_=!(Y!_KY|gQ${*W~R>>XB~4J+jW5A?Ghxc7LnzuiqezG-j2 zKAp;K$kMn%&9iXj+HKPxeN!|zS7*3EU*yk)8wraR^|Qv?yYzkeBJqoH`uqEv-^*5f zyXc-Fb@*g~(ROcEYtD-2{{jvgTQMkcZQwP!ukgRoA@BM7{rCQMT*^5-IrzSP?yuyO zA|Xqs3!J)J|FAGvM})0E-4np8Sg>x-tTP)0m9|XF&|+RJy5-`GtGr^|p9=NUi!H7% zmbWUo&AV+k@2+*q@wWB0q7E&BOPz~a#I{(v&tKN&@PT=X$NJExV(UDdY*jgPSDP%k zw#0h^Q`Ch{`<2(Gs+?bR$%^~ulqV&JSu(t)9g}!a`D|8@25a{+qiLa?dn&YCr|s`( zc)+0OIcNLLoP@PU6WHg>t7~a)W>#RjU-z49|IbhRAKlK6d-&`b-|Mqtx35mSeL%?R zoPm9egJPs==Zzbsy0^*>WbJMIEOJb_<-o^}hVyJJ9q*obSbHRGd+O=M2`y_JCro5o zozW265wFa{eI`iT`qu>R%}*8yG~IYF;E=lNPOR}Uhvp;M_1|7DkC2mjRJZlmy4;O- z-xbuBcFX_!aQ@?B`F|XrU3))&F1M)vEq0FAQm-*_DFCTrJxg>kty5}oibKTN7 zlXk?HV_w|(s?y#>iBB0SA3t$69I?0m?93qkLPWo7%dttE3qkcqwvdT}Tg|JKtEgLgjVz zi?6}#FF=!%BK_+A^S=1cx4XOV&oAlOYynFxo;w@=s}1|}@7Rv_Gxh(!wac%|lJB{! z*Ze%NIc&qa<4=!To;t2& zi{_8Y0G6X1g29WDT2`I0SbT0x73aibQkKgb%wqGaJtQ(rx7GEUt;qiM{&6#F+G$n+ zrfs)*f93T~e;>Db!AZfTzLP{Ws`x#$?1JhlQmmpM*|sWdauB=N} z>zq<9wbT6Cs$#N6Xx7g6O}X`x#Ph!%aFetY)IV$Dos+|HrT4?N=Pa(8taFqnO0WDX zo1bFac5qQ{^tB$Hi)Wr^+?Lz_^HKSa_x8Un>puR}zqr-*Ra)P!tQDzzoQu;q3=c%I zFXh>C<;5>%2+7#@lNJbq;q0+$yhy{CGBdePKaGivX*i|NIB; z_P+%E`p$p&_BQ&@GxPXIZ*LdN$eb&zsAv#~S@!s-$CpzqlRO`pCq4UKFfH!9!Hqem zrr-Mdvr4?7TT#4kvVpwfX1hkeEgKvDpE&tzqS^W_mCNg$qb6`gg@?Qd6Onog=eQWC#56^IP z+{~=U(DqVlI-eTj2OX=Bu1zK`A~P$U=Gxs8+0rH=bnMDaMTbNmMh-pkCtq$}_&lX% zZsdHI?OeWJHJEC27{1A!&H4E3=jZ3!gHD+ROmb)1Z+qjzzbl;ooMnFgy+2*|S-x_C>D)uT zVjTC9_wGCRyL|n{?^9$2!{ooC6F>n`~s7nQ|!1Rp$lKtn_8Ua;76&$BPf zqdxz!+xnq&n`x$^qJ@}w?ibHJVwWGOGswH0tLl*Zz6h*?V#~ZVIS(8% ze(BORd6M8NIf-8k?^)KZ%lmLt-2Pzw&y)3s*4zEpoLBQF`AnL-g@w(Lz^yL#ts|rb zSrr@E-#=XA&SGHEp1AjGiukGAoVL>Vy7Ku&%3FWVU0!DT_ven6PZiYm@yq7d{k}E*lieDhqd%e# zOV>@F|M&v`jhwI>Ic65Nwg=x=urN)urnN>IQ92@(!`aLKbXAVh0!( z+^j9&)rQm^Ht$-Ok<7>UwygPU7PGv~oY$W3?Rgv) z=v1q+Ea?hp(ysHoEAT$Zf>)QzD4E~&Ra;tb^OVa^c3=5vP|6!D_}Qk{ZAu8s4Nddv ziCj!GA1_JfDd=NfT=BTPF|%6dk#OOx*$&(G9nh`ITKsOuS~-bl1vM2-S(eAs_8y#V z{=DMvFWq(P^FO>TU;p9NQ|~)>?>WDgx)wF3_Rsl(ijq^`%v%q#x~ycht5nykJD;1Z zDe9zRH2cxb;;c$`w)YY5HF`8F-g(Sj@Ve~A)>^*xhO;hzI?x#G^=>K0rA2vbQx7TR zHnqFA|9CjRzDxek1NI+ZF8hCM7S}JRs9;#i(-SDrDE9ShRdfFS>dyKf{r?#hRr2!k zKK%R3nwS6XqV*rc z=gOmVRnn1j+PW)VEjjtob#?p)jpZw|^}1sJSts+%T6QqW(mnQi$Hi2sg!`p8)`acY zzx(L?|3BP+O#lCA{^RxkUakLd{@){g18a)|7atlbF5G&s{@+ReV;l5WO3XW4u9vOb z#9z}}6sT}wllG0i>7PtCJ-FHC#Hae{#u4`U*38L*0WFhK-RI`KefGjIMQi>^8NV;Ge28GM$tk}b z|M%19-9KyYy)C<~(Bi}Rsz^v+^Z(Mwi_#G*wbcK=bJqRL&-qgA(E*nIotNJ~oU_zy z^MW0h7QQa{`HyLt(T01EZ*ERkW)1LQaXV|5VLIK_@z-B=E}10`i`TSDq)!)CtN-|K z%C649zw^`ntTbS3`r2{outaa##sft=pGc}{PVY5*@muct_3IY(pSjNQuE^4o>Y284 zt;admUn@k~Z~YKh$hv&_$CI};7&EmvG!t&m`|&SQ;N-4~r3-zhy7L5Bou9r^`Cw=L zokQkPhi6z>i<~+?)$EPk_D`8=FF$EoRq)Hpx=dkN%_(?bhKl7e7v|l0?RWFoT{;&p zR<^19#Bwca&iwcX|NrIx7mTm{YQ3lKZ<|M*K*7DmoB57~SXln$h&4~xyq9&Rv=W>A zgT?K#GBpY@dHJ?euKc;>`^-SYb;Cjl=3nbn#TyxBEmJ(Yn?Y-_1jmyNw{sPzCZ_H@ zvp=og_VYJal`mV&*p8jKSSrgmtyo4@_AzMbL4W<9?ln{pe4&yX`mAj3lEzx