summaryrefslogtreecommitdiffstats
path: root/private/mvdm/softpc.new/base/video/ega_prts.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/softpc.new/base/video/ega_prts.c')
-rw-r--r--private/mvdm/softpc.new/base/video/ega_prts.c3459
1 files changed, 3459 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/base/video/ega_prts.c b/private/mvdm/softpc.new/base/video/ega_prts.c
new file mode 100644
index 000000000..b30fc8b5e
--- /dev/null
+++ b/private/mvdm/softpc.new/base/video/ega_prts.c
@@ -0,0 +1,3459 @@
+#include "insignia.h"
+#include "host_def.h"
+/* INSIGNIA (SUB)MODULE SPECIFICATION
+ -----------------------------
+
+
+ THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE
+ CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST
+ NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS
+ AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS LTD.
+
+DOCUMENT : name and number
+
+RELATED DOCS : include all relevant references
+
+DESIGNER :
+
+REVISION HISTORY :
+First version : 13 July 1988, J.Roper
+
+SUBMODULE NAME : ega
+
+SOURCE FILE NAME : ega_ports.c
+
+PURPOSE : emulation of EGA registers (ports).
+ Calls lower levels of the EGA emulation to do the real work.
+
+static char SccsID[]="@(#)ega_ports.c 1.54 07/18/94 Copyright Insignia Solutions Ltd.";
+
+
+[1.INTERMODULE INTERFACE SPECIFICATION]
+
+[1.0 INCLUDE FILE NEEDED TO ACCESS THIS INTERFACE FROM OTHER SUBMODULES]
+
+ INCLUDE FILE : ega_ports.gi
+
+[1.1 INTERMODULE EXPORTS]
+
+ PROCEDURES() :
+ void ega_init()
+ void ega_term()
+ int ega_get_line_compare() (* hunter only *)
+ int ega_get_max_scan_lines() (* hunter only *)
+
+-------------------------------------------------------------------------
+[1.2 DATATYPES FOR [1.1] (if not basic C types)]
+-------------------------------------------------------------------------
+[1.3 INTERMODULE IMPORTS]
+ (not o/s objects or standard libs)
+
+ PROCEDURES() :
+ io_define_inb
+ io_define_outb
+ io_connect_port
+ io_disconnect_port
+
+ DATA : give name, and source module name
+
+-------------------------------------------------------------------------
+
+[1.4 DESCRIPTION OF INTERMODULE INTERFACE]
+
+[1.4.1 IMPORTED OBJECTS]
+
+DATA OBJECTS : specify in following procedure descriptions
+ how these are accessed (read/modified)
+
+FILES ACCESSED : NONE
+
+DEVICES ACCESSED : NONE
+
+SIGNALS CAUGHT : NONE
+
+SIGNALS ISSUED : NONE
+
+
+[1.4.2 EXPORTED OBJECTS]
+=========================================================================
+PROCEDURE : ega_init
+
+PURPOSE : initialize EGA.
+
+PARAMETERS : none
+
+GLOBALS : none
+
+DESCRIPTION : establish ega ports.
+ initialize ega code to sensible state.
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_term
+
+PURPOSE : terminate EGA.
+
+PARAMETERS : none
+
+GLOBALS : none
+
+DESCRIPTION : remove ega ports.
+ free up allocated memory etc.
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_seq_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the sequencer chip's ports, and pass
+ appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_crtc_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the sequencer chip's ports, and pass
+ appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_crtc_inb((io_addr) port, (half_word) *value)
+
+PURPOSE : deal with an attempt to read a byte from one of the crtc's register ports,
+ and gets info from appropriate ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : pointer to memory byte where value read from port should go.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_gc_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the graphics controller chip's ports,
+ and pass appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_ac_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the attribute controller chip's ports, and pass
+ appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_misc_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the miscellaneous register's port, and pass
+ appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_feat_outb((io_addr) port, (half_word) value)
+
+PURPOSE : deal with bytes written to the Feature Control register's port, and pass
+ appropriate info to ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : the byte written to the port.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_ipstat0_inb((io_addr) port, (half_word) *value)
+
+PURPOSE : deal with an attempt to read a byte from the input status register 0 port,
+ and gets info from appropriate ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : pointer to memory byte where value read from port should go.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : ega_ipstat1_inb((io_addr) port, (half_word) *value)
+
+PURPOSE : deal with an attempt to read a byte from the input status register 1 port,
+ and gets info from appropriate ega sub-modules.
+
+PARAMETERS
+ port : port address written to.
+ value : pointer to memory byte where value read from port should go.
+
+GLOBALS : none
+
+DESCRIPTION :
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+PROCEDURE : int ega_get_line_compare()
+
+PURPOSE : Hunter only - returns the line compare value
+ from the crtc registers structure
+
+PARAMETERS : none
+
+GLOBALS : none
+
+DESCRIPTION : Obtains the line compare value from bit 4 of the
+ overflow register (0x7) and the line compare
+ register (0x18).
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+=========================================================================
+
+PROCEDURE : int ega_get_max_scan_lines()
+
+PURPOSE : Hunter only - returns the maximum scan lines value
+ from the crtc registers structure
+
+PARAMETERS : none
+
+GLOBALS : none
+
+DESCRIPTION : Obtains the max scan lines value from the max scan
+ lines register (0x9).
+
+ERROR INDICATIONS : none.
+
+ERROR RECOVERY : none.
+=========================================================================
+
+
+/*=======================================================================
+[3.INTERMODULE INTERFACE DECLARATIONS]
+=========================================================================
+
+[3.1 INTERMODULE IMPORTS] */
+
+/* [3.1.1 #INCLUDES] */
+
+
+#ifndef REAL_VGA /* ega port handling moved to host for REAL_VGA */
+#ifdef EGG
+
+#include "xt.h"
+#include CpuH
+#include "debug.h"
+#include "timer.h"
+#include "sas.h"
+#include "gmi.h"
+#include "gvi.h"
+#include "ios.h"
+#include "ica.h"
+#include "gfx_upd.h"
+#include "egacpu.h"
+#include "egagraph.h"
+#include "egaread.h"
+#include "egamode.h"
+#include "error.h"
+#include "config.h"
+
+#include "host_gfx.h"
+#include "egaports.h"
+
+#ifdef GORE
+#include "gore.h"
+#endif /* GORE */
+
+#include "ga_mark.h"
+#include "ga_defs.h"
+
+/* [3.2 INTERMODULE EXPORTS] */
+
+
+/* [3.1.2 DECLARATIONS] */
+
+IMPORT void ega_mode_init IPT0();
+IMPORT int get_ega_switch_setting IPT0();
+IMPORT void v7_get_banks IPT2(UTINY *, rd_bank, UTINY *, wrt_bank );
+#ifndef cursor_changed
+IMPORT void cursor_changed IPT2(int, x, int, y);
+#endif /* cursor_changed */
+IMPORT void update_shift_count IPT0();
+
+/*
+5.MODULE INTERNALS : (not visible externally, global internally)]
+
+[5.1 LOCAL DECLARATIONS] */
+
+LOCAL void vote_ega_mode IPT0();
+LOCAL void ega_seq_outb_index IPT2(io_addr, port, half_word, value);
+LOCAL void ega_crtc_outb IPT2(io_addr, port, half_word, value);
+LOCAL void ega_crtc_inb IPT2(io_addr, port, half_word *, value);
+LOCAL void ega_ac_outb IPT2(io_addr, port, half_word, value);
+LOCAL void ega_misc_outb IPT2(io_addr, port, half_word, value);
+LOCAL void ega_feat_outb IPT2(io_addr, port, half_word, value);
+LOCAL void ega_ipstat0_inb IPT2(io_addr, port, half_word *, value);
+LOCAL void ega_ipstat1_inb IPT2(io_addr, port, half_word *, value);
+
+/* [5.1.1 #DEFINES] */
+#ifdef SEGMENTATION
+/*
+ * The following #include specifies the code segment into which this
+ * module will by placed by the MPW C compiler on the Mac II running
+ * MultiFinder.
+ */
+#include "SOFTPC_EGA.seg"
+#endif
+
+GLOBAL VOID ega_gc_outw IPT2(io_addr, port, word, outval);
+
+/*
+ * EGA_PLANE_DISP_SIZE is already declared in egaports.h. However if V7VGA is
+ * defined using this definition will cause problems. See BCN 1486 for details.
+ */
+#define EGA_PLANE_SZ 0x10000
+
+/* [5.1.2 TYPEDEF, STRUCTURE, ENUM DECLARATIONS] */
+#ifdef BIT_ORDER1
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned hardware_reset : 1, /* NO */
+ word_or_byte_mode : 1, /* YES */
+ address_wrap : 1, /* NO */
+ output_control : 1, /* YES - screen goes black */
+ count_by_two : 1, /* NO */
+ horizontal_retrace_select : 1, /* NO */
+ select_row_scan_counter : 1, /* NO */
+ compatibility_mode_support : 1; /* YES - CGA graphics banks */
+ } as_bfld;
+} MODE_CONTROL;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ line_compare_bit_8 : 1, /* YES */
+ start_vertical_blank_bit_8 : 1, /* NO */
+ vertical_retrace_start_bit_8 : 1, /* NO */
+ vertical_display_enab_end_bit_8 : 1, /* YES */
+ vertical_total_bit_8 : 1; /* NO */
+ } as_bfld;
+} CRTC_OVERFLOW;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ maximum_scan_line : 5; /* YES */
+ } as_bfld;
+} MAX_SCAN_LINE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ cursor_start : 5; /* YES */
+ } as_bfld;
+} CURSOR_START;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 1,
+ cursor_skew_control : 2, /* NO */
+ cursor_end : 5; /* YES */
+ } as_bfld;
+} CURSOR_END;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 6,
+ synchronous_reset : 1, /* Ditto (could implement as enable_ram)*/
+ asynchronous_reset : 1; /* NO - damages video and font RAM */
+ } as_bfld;
+} SEQ_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ dot_clock : 1, /* YES - distinguishes 40 or 80 chars */
+ shift_load : 1, /* NO */
+ bandwidth : 1, /* NO */
+ eight_or_nine_dot_clocks : 1; /* NO - only for mono display */
+ } as_bfld;
+} CLOCKING_MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ all_planes : 4; /* YES */
+ } as_bfld;
+} MAP_MASK;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ character_map_select_b : 2, /* YES */
+ character_map_select_a : 2; /* YES */
+ } as_bfld;
+ struct {
+ unsigned not_used : 4,
+ map_selects : 4; /* YES */
+ } character;
+} CHAR_MAP_SELECT;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned
+ not_used : 5, /* If above 2 not both 1, bank 0 set 2 */
+ not_odd_or_even : 1, /* YES (check consistency) */
+ extended_memory : 1, /* NO - assume full 256K on board */
+ alpha_mode : 1; /* YES (check consistency) */
+ } as_bfld;
+} MEMORY_MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ set_or_reset : 4; /* YES - write mode 0 only */
+ } as_bfld;
+} SET_OR_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ enable_set_or_reset : 4; /* YES - write mode 0 only */
+ } as_bfld;
+} ENABLE_SET_OR_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ color_compare : 4; /* YES - read mode 1 only */
+ } as_bfld;
+} COLOR_COMPARE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ function_select : 2, /* YES - write mode 0 only */
+ rotate_count : 3; /* YES - write mode 0 only */
+ } as_bfld;
+} DATA_ROTATE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 5,
+ map_select : 3; /* YES */
+ } as_bfld;
+} READ_MAP_SELECT;
+
+typedef union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 2,
+ shift_register_mode : 1, /* YES - CGA colour graphics */
+ odd_or_even : 1, /* YES (check for consistency) */
+ read_mode : 1, /* YES */
+ test_condition : 1, /* NO */
+ write_mode : 2; /* YES */
+ } as_bfld;
+} MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ memory_map : 2, /* YES - location of EGA in M */
+ odd_or_even : 1, /* YES (check consistency) */
+ graphics_mode : 1; /* YES */
+ } as_bfld;
+} MISC_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ color_dont_care : 4; /* YES - read mode 1 only */
+ } as_bfld;
+} COLOR_DONT_CARE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned
+ not_used : 4,
+ background_intensity_or_blink : 1, /* NO - never blink */
+ enable_line_graphics_char_codes : 1, /* NO mono display only */
+ display_type : 1, /* NO - always colour display */
+ graphics_mode : 1; /* YES - with Sequencer Mode reg */
+ } as_bfld;
+} AC_MODE_CONTROL;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned vertical_retrace_polarity : 1, /* YES - switch between 200/350 lines */
+ horizontal_retrace_polarity : 1, /* NO - probably destroys display! */
+ page_bit_odd_even : 1, /* NO - selects 32k page in odd/even? */
+ disable_internal_video_drivers : 1, /* NO - like switching PC off */
+ clock_select : 2, /* YES - only for switch address */
+ enable_ram : 1, /* YES - writes to display mem ignored */
+ io_address_select : 1; /* NO - only used for mono screens */
+ } as_bfld;
+} MISC_OUTPUT_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ reserved : 2, /* YES - ignore */
+ feature_control : 2; /* NO - device not supported */
+ } as_bfld;
+} FEAT_CONT_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned crt_interrupt : 1, /* YES - sequence if not timing */
+ reserved : 2, /* YES - all bits 1 */
+ switch_sense : 1, /* YES - switch selected by clock sel. */
+ not_used : 4; /* YES - all bits 1 */
+ } as_bfld;
+} INPUT_STAT_REG0;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 2,
+ video_status_mux : 2, /* NO */
+ color_plane_enable : 4; /* YES NB. affects attrs in text mode */
+ } as_bfld;
+} COLOR_PLANE_ENABLE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 1, /* YES - set to 1 */
+ diagnostic_0 : 1, /* NO - set to 0 */
+ diagnostic_1 : 1, /* NO - set to 0 */
+ vertical_retrace : 1, /* YES - sequence only */
+ light_pen_switch : 1, /* YES - set to 0 */
+ light_pen_strobe : 1, /* YES - set to 1 */
+ display_enable : 1; /* YES - sequence only */
+ } as_bfld;
+} INPUT_STAT_REG1;
+#endif
+#ifdef BIT_ORDER2
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned compatibility_mode_support : 1, /* YES - CGA graphics banks */
+ select_row_scan_counter : 1, /* NO */
+ horizontal_retrace_select : 1, /* NO */
+ count_by_two : 1, /* NO */
+ output_control : 1, /* YES - screen goes black */
+ address_wrap : 1, /* NO */
+ word_or_byte_mode : 1, /* YES */
+ hardware_reset : 1; /* NO */
+ } as_bfld;
+} MODE_CONTROL;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned vertical_total_bit_8 : 1, /* NO */
+ vertical_display_enab_end_bit_8 : 1, /* YES */
+ vertical_retrace_start_bit_8 : 1, /* NO */
+ start_vertical_blank_bit_8 : 1, /* NO */
+ line_compare_bit_8 : 1, /* YES */
+ not_used : 3;
+ } as_bfld;
+} CRTC_OVERFLOW;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned maximum_scan_line : 5, /* YES */
+ not_used : 3;
+ } as_bfld;
+} MAX_SCAN_LINE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned cursor_start : 5, /* YES */
+ not_used : 3;
+ } as_bfld;
+} CURSOR_START;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned cursor_end : 5, /* YES */
+ cursor_skew_control : 2, /* NO */
+ not_used : 1;
+ } as_bfld;
+} CURSOR_END;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned asynchronous_reset : 1, /* NO - damages video and font RAM */
+ synchronous_reset : 1, /* Ditto (could implement as enable_ram)*/
+ not_used : 6;
+ } as_bfld;
+} SEQ_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned eight_or_nine_dot_clocks : 1, /* NO - only for mono display */
+ bandwidth : 1, /* NO */
+ shift_load : 1, /* NO */
+ dot_clock : 1, /* YES - distinguishes 40 or 80 chars */
+ not_used : 4;
+ } as_bfld;
+} CLOCKING_MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned all_planes : 4, /* YES */
+ not_used : 4;
+ } as_bfld;
+} MAP_MASK;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned character_map_select_a : 2, /* YES */
+ character_map_select_b : 2, /* YES */
+ not_used : 4;
+ } as_bfld;
+ struct {
+ unsigned map_selects : 4, /* YES */
+ not_used : 4;
+ } character;
+} CHAR_MAP_SELECT;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned alpha_mode : 1, /* YES (check consistency) */
+ extended_memory : 1, /* NO - assume full 256K on board */
+ not_odd_or_even : 1, /* YES (check consistency) */
+ not_used : 5; /* If above 2 not both 1, bank 0 set 2 */
+ } as_bfld;
+} MEMORY_MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned set_or_reset : 4, /* YES - write mode 0 only */
+ not_used : 4;
+ } as_bfld;
+} SET_OR_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned enable_set_or_reset : 4, /* YES - write mode 0 only */
+ not_used : 4;
+ } as_bfld;
+} ENABLE_SET_OR_RESET;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned color_compare : 4, /* YES - read mode 1 only */
+ not_used : 4;
+ } as_bfld;
+} COLOR_COMPARE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned rotate_count : 3, /* YES - write mode 0 only */
+ function_select : 2, /* YES - write mode 0 only */
+ not_used : 3;
+ } as_bfld;
+} DATA_ROTATE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned map_select : 3, /* YES - read mode 0 only */
+ not_used : 5;
+ } as_bfld;
+} READ_MAP_SELECT;
+
+typedef union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned write_mode : 2, /* YES */
+ test_condition : 1, /* NO */
+ read_mode : 1, /* YES */
+ odd_or_even : 1, /* YES (check for consistency) */
+ shift_register_mode : 1, /* YES - CGA colour graphics */
+ not_used : 2;
+ } as_bfld;
+} MODE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned graphics_mode : 1, /* YES */
+ odd_or_even : 1, /* YES (check consistency) */
+ memory_map : 2, /* YES - location of EGA in M */
+ not_used : 4;
+ } as_bfld;
+} MISC_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned color_dont_care : 4, /* YES - read mode 1 only */
+ not_used : 4;
+ } as_bfld;
+} COLOR_DONT_CARE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned graphics_mode : 1, /* YES - with Sequencer Mode reg */
+ display_type : 1, /* NO - always colour display */
+ enable_line_graphics_char_codes : 1, /* NO mono display only */
+ background_intensity_or_blink : 1, /* NO - never blink */
+ not_used : 4;
+ } as_bfld;
+} AC_MODE_CONTROL;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned io_address_select : 1, /* NO - only used for mono screens */
+ enable_ram : 1, /* YES - writes to display mem ignored */
+ clock_select : 2, /* YES - only for switch address */
+ disable_internal_video_drivers : 1, /* NO - like switching PC off */
+ page_bit_odd_even : 1, /* NO - selects 32k page in odd/even? */
+ horizontal_retrace_polarity : 1, /* NO - probably destroys display! */
+ vertical_retrace_polarity : 1; /* YES - switch between 200/350 lines */
+ } as_bfld;
+} MISC_OUTPUT_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned feature_control : 2, /* NO - device not supported */
+ reserved : 2, /* YES - ignore */
+ not_used : 4;
+ } as_bfld;
+} FEAT_CONT_REG;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4, /* YES - all bits 1 */
+ switch_sense : 1, /* YES - switch selected by clock sel. */
+ reserved : 2, /* YES - all bits 1 */
+ crt_interrupt : 1; /* YES - sequence if not timing */
+ } as_bfld;
+} INPUT_STAT_REG0;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned color_plane_enable : 4, /* YES NB. affects attrs in text mode */
+ video_status_mux : 2, /* NO */
+ not_used : 2;
+ } as_bfld;
+} COLOR_PLANE_ENABLE;
+
+typedef union
+{
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned display_enable : 1, /* YES - sequence only */
+ light_pen_strobe : 1, /* YES - set to 1 */
+ light_pen_switch : 1, /* YES - set to 0 */
+ vertical_retrace : 1, /* YES - sequence only */
+ diagnostic_1 : 1, /* NO - set to 0 */
+ diagnostic_0 : 1, /* NO - set to 0 */
+ not_used : 1; /* YES - set to 1 */
+ } as_bfld;
+} INPUT_STAT_REG1;
+#endif
+
+
+
+/* [5.1.3 PROCEDURE() DECLARATIONS] */
+
+
+/* -----------------------------------------------------------------------
+[5.2 LOCAL DEFINITIONS]
+
+ [5.2.1 INTERNAL DATA DEFINITIONS */
+
+/*
+
+/* EGA REGISTERS */
+/* Comments after bitfields indicate whether change of value affects emulated screen display or memory interface */
+
+/* Registers not contained in an LSI device */
+
+static MISC_OUTPUT_REG miscellaneous_output_register;
+
+static FEAT_CONT_REG feature_control_register;
+
+static INPUT_STAT_REG0 input_status_register_zero;
+
+static INPUT_STAT_REG1 input_status_register_one;
+
+/* The Sequencer Registers */
+#ifdef BIT_ORDER1
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 5,
+ index : 3;
+ } as_bfld;
+ } address;
+
+ SEQ_RESET reset;
+ CLOCKING_MODE clocking_mode;
+ MAP_MASK map_mask;
+ CHAR_MAP_SELECT character_map_select;
+ MEMORY_MODE memory_mode;
+} sequencer;
+
+
+/* The CRT Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ index : 5;
+ } as_bfld;
+ } address;
+
+ byte horizontal_total; /* NO - screen trash if wrong value */
+ byte horizontal_display_end; /* YES - defines line length!! */
+ byte start_horizontal_blanking; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 1,
+ display_enable_skew_control : 2, /* NO */
+ end_blanking : 5; /* NO */
+ } as_bfld;
+ } end_horizontal_blanking;
+
+ byte start_horizontal_retrace; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 1,
+ horizontal_retrace_delay : 2, /* NO */
+ end_horizontal_retrace : 5; /* NO */
+ } as_bfld;
+ } end_horizontal_retrace;
+
+ byte vertical_total; /* NO */
+ CRTC_OVERFLOW crtc_overflow;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ preset_row_scan : 5; /* NO */
+ } as_bfld;
+ } preset_row_scan;
+
+ MAX_SCAN_LINE maximum_scan_line;
+ CURSOR_START cursor_start;
+ CURSOR_END cursor_end;
+ byte start_address_high; /* YES */
+ byte start_address_low; /* YES */
+ byte cursor_location_high; /* YES */
+ byte cursor_location_low; /* YES */
+ byte vertical_retrace_start; /* NO */
+ byte light_pen_high; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned
+ not_used : 2,
+ enable_vertical_interrupt : 1, /* YES - ditto */
+ clear_vertical_interrupt : 1, /* YES - needs investigation */
+ vertical_retrace_end : 4; /* NO */
+ } as_bfld;
+ } vertical_retrace_end;
+
+ byte light_pen_low; /* NO */
+ byte vertical_display_enable_end; /* YES - defines screen height */
+ byte offset; /* YES (maybe!) ??????? */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ underline_location : 5; /* NO (mono display only) */
+ } as_bfld;
+ } underline_location;
+
+ byte start_vertical_blanking; /* NO */
+ byte end_vertical_blanking; /* NO */
+ MODE_CONTROL mode_control;
+ byte line_compare; /* YES */
+
+} crt_controller;
+
+
+/* The Graphics Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ index : 4;
+ } as_bfld;
+ } address;
+
+ SET_OR_RESET set_or_reset;
+ ENABLE_SET_OR_RESET enable_set_or_reset;
+ COLOR_COMPARE color_compare;
+ DATA_ROTATE data_rotate;
+ READ_MAP_SELECT read_map_select;
+ MODE mode;
+ MISC_REG miscellaneous;
+ COLOR_DONT_CARE color_dont_care;
+ byte bit_mask_register; /* YES - write modes 0 & 2 */
+ byte graphics_1_position; /* NO */
+ byte graphics_2_position; /* NO */
+} graphics_controller;
+
+
+/* The Attribute Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 3,
+ index : 5;
+ } as_bfld;
+ } address;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned
+ not_used : 2, /* YES */
+ secondary_red : 1, /* YES */
+ secondary_green : 1, /* YES */
+ secondary_blue : 1, /* YES */
+ red : 1, /* YES */
+ green : 1, /* YES */
+ blue : 1; /* YES */
+ } as_bfld;
+ } palette[EGA_PALETTE_SIZE];
+
+ AC_MODE_CONTROL mode_control;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 2,
+ secondary_red_border : 1, /* YES */
+ secondary_green_border : 1, /* YES */
+ secondary_blue_border : 1, /* YES */
+ red_border : 1, /* YES */
+ green_border : 1, /* YES */
+ blue_border : 1; /* YES - real thing isn't good at this */
+ } as_bfld;
+ } overscan_color;
+
+ COLOR_PLANE_ENABLE color_plane_enable;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned not_used : 4,
+ horizontal_pel_panning : 4; /* NO */
+ } as_bfld;
+ } horizontal_pel_panning;
+} attribute_controller;
+#endif
+
+#ifdef BIT_ORDER2
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned index : 3,
+ not_used : 5;
+ } as_bfld;
+ } address;
+
+ SEQ_RESET reset;
+ CLOCKING_MODE clocking_mode;
+ MAP_MASK map_mask;
+ CHAR_MAP_SELECT character_map_select;
+ MEMORY_MODE memory_mode;
+} sequencer;
+
+
+/* The CRT Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned index : 5,
+ not_used : 3;
+ } as_bfld;
+ } address;
+
+ byte horizontal_total; /* NO - screen trash if wrong value */
+ byte horizontal_display_end; /* YES - defines line length!! */
+ byte start_horizontal_blanking; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned end_blanking : 5, /* NO */
+ display_enable_skew_control : 2, /* NO */
+ not_used : 1;
+ } as_bfld;
+ } end_horizontal_blanking;
+
+ byte start_horizontal_retrace; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned end_horizontal_retrace : 5, /* NO */
+ horizontal_retrace_delay : 2, /* NO */
+ not_used : 1;
+ } as_bfld;
+ } end_horizontal_retrace;
+
+ byte vertical_total; /* NO */
+ CRTC_OVERFLOW crtc_overflow;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned preset_row_scan : 5, /* NO */
+ not_used : 3;
+ } as_bfld;
+ } preset_row_scan;
+
+ MAX_SCAN_LINE maximum_scan_line;
+ CURSOR_START cursor_start;
+ CURSOR_END cursor_end;
+ byte start_address_high; /* YES */
+ byte start_address_low; /* YES */
+ byte cursor_location_high; /* YES */
+ byte cursor_location_low; /* YES */
+ byte vertical_retrace_start; /* NO */
+ byte light_pen_high; /* NO */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned vertical_retrace_end : 4, /* NO */
+ clear_vertical_interrupt : 1, /* YES - needs investigation */
+ enable_vertical_interrupt : 1, /* YES - ditto */
+ not_used : 2;
+ } as_bfld;
+ } vertical_retrace_end;
+
+ byte light_pen_low; /* NO */
+ byte vertical_display_enable_end; /* YES - defines screen height */
+ byte offset; /* YES (maybe!) ??????? */
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned underline_location : 5, /* NO (mono display only) */
+ not_used : 3;
+ } as_bfld;
+ } underline_location;
+
+ byte start_vertical_blanking; /* NO */
+ byte end_vertical_blanking; /* NO */
+ MODE_CONTROL mode_control;
+ byte line_compare; /* YES */
+
+} crt_controller;
+
+
+/* The Graphics Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned index : 4,
+ not_used : 4;
+ } as_bfld;
+ } address;
+
+ SET_OR_RESET set_or_reset;
+ ENABLE_SET_OR_RESET enable_set_or_reset;
+ COLOR_COMPARE color_compare;
+ DATA_ROTATE data_rotate;
+ READ_MAP_SELECT read_map_select;
+ MODE mode;
+ MISC_REG miscellaneous;
+ COLOR_DONT_CARE color_dont_care;
+ byte bit_mask_register; /* YES - write modes 0 & 2 */
+ byte graphics_1_position; /* NO */
+ byte graphics_2_position; /* NO */
+} graphics_controller;
+
+
+/* The Attribute Controller Registers */
+
+static struct
+{
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned index : 5,
+ not_used : 3;
+ } as_bfld;
+ } address;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned blue : 1, /* YES */
+ green : 1, /* YES */
+ red : 1, /* YES */
+ secondary_blue : 1, /* YES */
+ secondary_green : 1, /* YES */
+ secondary_red : 1, /* YES */
+ not_used : 2; /* YES */
+ } as_bfld;
+ } palette[EGA_PALETTE_SIZE];
+
+ AC_MODE_CONTROL mode_control;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned blue_border : 1, /* YES - real thing isn't good at this */
+ green_border : 1, /* YES */
+ red_border : 1, /* YES */
+ secondary_blue_border : 1, /* YES */
+ secondary_green_border : 1, /* YES */
+ secondary_red_border : 1, /* YES */
+ not_used : 2;
+ } as_bfld;
+ } overscan_color;
+
+ COLOR_PLANE_ENABLE color_plane_enable;
+
+ union
+ {
+ struct {
+ unsigned abyte : 8;
+ } as;
+ struct {
+ unsigned horizontal_pel_panning : 4, /* NO */
+ not_used : 4;
+ } as_bfld;
+ } horizontal_pel_panning;
+} attribute_controller;
+#endif
+
+static boolean ac_index_state = NO;
+extern half_word bg_col_mask; /* Used to work out the background colour */
+
+IMPORT VOID _ega_gc_outb_index IPT2(io_addr,port,half_word,value);
+IMPORT VOID _ega_gc_outb_mask IPT2(io_addr,port,half_word,value);
+IMPORT VOID _ega_gc_outb_mask_ff IPT2(io_addr,port,half_word,value);
+
+/* Declarations for new multi-routine graphics controller */
+void ega_gc_set_reset IPT2(io_addr, port, half_word, value);
+void ega_gc_enable_set IPT2(io_addr, port, half_word, value);
+void ega_gc_compare IPT2(io_addr, port, half_word, value);
+void ega_gc_rotate IPT2(io_addr, port, half_word, value);
+void ega_gc_read_map IPT2(io_addr, port, half_word, value);
+void ega_gc_mode IPT2(io_addr, port, half_word, value);
+void ega_gc_misc IPT2(io_addr, port, half_word, value);
+void ega_gc_dont_care IPT2(io_addr, port, half_word, value);
+LOCAL void ega_gc_mask IPT2(io_addr, port, half_word, value);
+void ega_gc_mask_ff IPT2(io_addr, port, half_word, value);
+LOCAL void ega_index_invalid IPT2(io_addr, port, half_word, value);
+
+void (*ega_gc_regs[]) IPT2(io_addr, port, half_word, value) = {
+ ega_gc_set_reset,
+ ega_gc_enable_set,
+ ega_gc_compare,
+ ega_gc_rotate,
+ ega_gc_read_map,
+ ega_gc_mode,
+ ega_gc_misc,
+ ega_gc_dont_care,
+ ega_gc_mask,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+};
+
+#ifndef A2CPU
+void (*ega_gc_regs_cpu[]) IPT2(io_addr,port,half_word,value) = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+#endif /* A2CPU */
+
+/* Declarations for new seqencer code */
+void ega_seq_reset IPT2(io_addr, port, half_word, value);
+void ega_seq_clock IPT2(io_addr, port, half_word, value);
+void ega_seq_map_mask IPT2(io_addr, port, half_word, value);
+void ega_seq_char_map IPT2(io_addr, port, half_word, value);
+void ega_seq_mem_mode IPT2(io_addr, port, half_word, value);
+
+void (*ega_seq_regs[]) IPT2(io_addr, port, half_word, value) =
+{
+ ega_seq_reset,
+ ega_seq_clock,
+ ega_seq_map_mask,
+ ega_seq_char_map,
+ ega_seq_mem_mode,
+ ega_index_invalid,
+ ega_index_invalid,
+ ega_index_invalid,
+};
+
+
+/* [5.2.2 INTERNAL PROCEDURE DEFINITIONS] */
+
+/*
+==========================================================================
+FUNCTION : set_index_state()
+PURPOSE : Set the attribute controller to use the next value
+ written to its port as the index value.
+EXTERNAL OBJECTS:
+RETURN VALUE : None
+INPUT PARAMS : None
+RETURN PARAMS : None
+==========================================================================
+*/
+
+void set_index_state IFN0()
+{
+ /*
+ * Seems strange, but in_index_state changes the state & returns the result
+ * so we set state to NO, so that next call of in_index_state will return YES
+ */
+ ac_index_state = NO;
+}
+
+/*
+==========================================================================
+FUNCTION : in_index_state()
+PURPOSE : To determine if the value written to the attribute
+ controller is destined for the index register, or
+ another register specified by the current index
+ value.
+EXTERNAL OBJECTS:
+RETURN VALUE : Boolean
+INPUT PARAMS : None
+RETURN PARAMS : None
+==========================================================================
+*/
+
+boolean in_index_state IFN0()
+{
+ ac_index_state = ! ac_index_state;
+ return(ac_index_state);
+}
+
+/*
+==========================================================================
+FUNCTION : do_new_cursor()
+PURPOSE : deals with the shape of the cursor according to
+ char_height, cursor_start and cursor_end. See Tech
+ Memo 88.6.1 for details.
+EXTERNAL OBJECTS: EGA_GRAPH.cursor_start,EGA_GRAPH.cursor_height,EGA_cursor_start1,
+ EGA_GRAPH.cursor_height1,host_cursor_has_changed().
+RETURN VALUE : None
+INPUT PARAMS : None
+RETURN PARAMS : None
+==========================================================================
+*/
+
+LOCAL void do_new_cursor IFN0()
+{
+
+ note_entrance0("do_new_cursor()");
+
+#ifdef VGG
+ if ( video_adapter == VGA ) {
+ note_entrance0("VGA cursor");
+ set_cursor_start(crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_height(crt_controller.cursor_end.as_bfld.cursor_end - crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_start1(0); /* cursor never splits */
+ set_cursor_height1(0);
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ } else {
+#endif
+ if (crt_controller.cursor_start.as_bfld.cursor_start >= get_char_height() ) {
+ note_entrance0("No cursor");
+ set_cursor_visible(FALSE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start | 0x20,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+ else if (crt_controller.cursor_end.as_bfld.cursor_end == 0) {
+ note_entrance0("cursor from start to bum");
+ set_cursor_start1(0);
+ set_cursor_height1(0);
+ set_cursor_start(crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_height(get_char_height() - get_cursor_start());
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+ else if (crt_controller.cursor_end.as_bfld.cursor_end < crt_controller.cursor_start.as_bfld.cursor_start) {
+ note_entrance0("2 cursors");
+ set_cursor_start1(0);
+ set_cursor_height1(crt_controller.cursor_end.as_bfld.cursor_end);
+ set_cursor_start(crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_height(get_char_height() - get_cursor_start());
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+ else if (crt_controller.cursor_end.as_bfld.cursor_end == crt_controller.cursor_start.as_bfld.cursor_start) {
+ note_entrance0("One line cursor");
+ set_cursor_start(crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_height(1);
+ set_cursor_start1(0);
+ set_cursor_height1(0);
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+ else if (crt_controller.cursor_end.as_bfld.cursor_end - 1 >= get_char_height()) {
+ note_entrance0("block cursor");
+ set_cursor_start(0);
+ set_cursor_height(get_char_height());
+ set_cursor_start1(0);
+ set_cursor_height1(0);
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+ else {
+ assert2(((crt_controller.cursor_end.as_bfld.cursor_end - 1) >= crt_controller.cursor_start.as_bfld.cursor_start),
+ "cursor values do not match default set Start %d, End %d",
+ crt_controller.cursor_end.as_bfld.cursor_end,
+ crt_controller.cursor_start.as_bfld.cursor_start);
+ note_entrance0("normal cursor");
+ set_cursor_start(crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_height(crt_controller.cursor_end.as_bfld.cursor_end - crt_controller.cursor_start.as_bfld.cursor_start);
+ set_cursor_start1(0);
+ set_cursor_height1(0);
+ set_cursor_visible(TRUE);
+ host_cursor_size_changed(crt_controller.cursor_start.as_bfld.cursor_start,
+ crt_controller.cursor_end.as_bfld.cursor_end);
+ }
+#ifdef VGG
+ }
+#endif
+
+ if(( get_cur_y() < 0 ) ||
+ ((( get_cur_y() + 1 ) * get_char_height()) > get_screen_height() ))
+ {
+ set_cursor_visible( FALSE );
+ }
+
+ base_cursor_shape_changed();
+}
+
+/*
+==========================================================================
+FUNCTION : do_chain_majority_decision()
+PURPOSE : deals with any contention regarding whether the
+ ega registers indicate that the addressing of the
+ planes is in chained mode or not. If the result
+ of the election is a new addressing mode, then
+ the video routines, read mode and paint modules
+ are informed of the change.
+EXTERNAL OBJECTS: uses local ega register data to count votes.
+RETURN VALUE : None
+INPUT PARAMS : None
+RETURN PARAMS : None
+==========================================================================
+*/
+
+
+LOCAL void do_chain_majority_decision IFN0()
+{
+ static int current_votes=0;
+ int new_votes;
+
+ new_votes = sequencer.memory_mode.as_bfld.not_odd_or_even ? 0 : 1 ; /* 0 - chained */
+ new_votes += graphics_controller.mode.as_bfld.odd_or_even ; /* 1 - chained */
+ new_votes += graphics_controller.miscellaneous.as_bfld.odd_or_even ; /* 1 - chained */
+
+ if( new_votes == 1 && current_votes > 1 )
+ {
+ /*
+ * Transition from chained to unchained
+ */
+
+ EGA_CPU.chain = UNCHAINED;
+ setVideochain(EGA_CPU.chain);
+ ega_read_routines_update();
+ ega_write_routines_update(CHAINED);
+ set_memory_chained(NO);
+ flag_mode_change_required();
+ }
+ else
+ if( new_votes > 1 && current_votes == 1 )
+ {
+ /*
+ * Transition from unchained to chained
+ */
+
+ EGA_CPU.chain = CHAIN2;
+ setVideochain(EGA_CPU.chain);
+ ega_read_routines_update();
+ ega_write_routines_update(CHAINED);
+ set_memory_chained(YES);
+ flag_mode_change_required();
+ }
+
+ current_votes = new_votes;
+}
+
+
+/*
+7.INTERMODULE INTERFACE IMPLEMENTATION :
+
+/*
+[7.1 INTERMODULE DATA DEFINITIONS] */
+
+/*
+ * This structure should contain all the global definitions used by EGA
+ */
+
+struct EGA_GLOBALS EGA_GRAPH;
+struct EGA_CPU_GLOBALS EGA_CPU;
+
+byte *EGA_planes;
+
+int ega_int_enable;
+
+GLOBAL UTINY *ega_gc_outb_index_addr;
+
+
+/*
+[7.2 INTERMODULE PROCEDURE DEFINITIONS] */
+
+GLOBAL void
+set_banking IFN2(UTINY, rd_bank, UTINY, wrt_bank)
+{
+ ULONG roffs, woffs;
+#ifdef PIG
+ IMPORT ULONG pig_vid_bank;
+#endif
+
+#ifdef V7VGA
+ if( get_seq_chain4_mode() && get_chain4_mode() )
+ {
+ roffs = (ULONG)rd_bank << 16;
+ woffs = (ULONG)wrt_bank << 16;
+ }
+ else
+ {
+ roffs = (ULONG)rd_bank << 18;
+ woffs = (ULONG)wrt_bank << 18;
+ }
+#else
+ UNUSED(rd_bank);
+ UNUSED(wrt_bank);
+ roffs = 0;
+ woffs = 0;
+#endif
+
+#ifdef PIG
+ pig_vid_bank = woffs;
+#endif
+ setVideorplane(EGA_planes + roffs);
+ setVideowplane(EGA_planes + woffs);
+
+#ifdef VGG
+ if( get_256_colour_mode() )
+ setVideov7_bank_vid_copy_off(woffs >> 2);
+ else
+#endif /* VGG */
+ setVideov7_bank_vid_copy_off(woffs >> 4);
+
+#ifdef GORE
+ gd.max_vis_addr = get_screen_length() - 1 + woffs;
+#endif /* GORE */
+}
+
+GLOBAL void
+update_banking IFN0()
+{
+ UTINY rd_bank, wrt_bank;
+
+#ifdef V7VGA
+ v7_get_banks( &rd_bank, &wrt_bank );
+#else
+ rd_bank = wrt_bank = 0;
+#endif
+
+ set_banking( rd_bank, wrt_bank );
+}
+
+VOID
+init_vga_globals IFN0()
+{
+ setVideov7_bank_vid_copy_off(0);
+ setVideosr_lookup(sr_lookup);
+ setVideovideo_copy(&video_copy[0]);
+ setVideoscratch(sas_scratch_address(0x10000));
+ setVideoscreen_ptr(EGA_planes);
+ setVideorotate(0);
+#if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX))
+#ifndef CPU_40_STYLE /* EVID */
+ setVideomark_byte(_simple_mark_sml);
+ setVideomark_word(_simple_mark_sml);
+ setVideomark_string(_simple_mark_lge);
+#else
+ SetMarkPointers(0);
+#endif /* CPU_40_STYLE - EVID */
+#endif
+
+
+ update_banking();
+}
+
+void ega_init IFN0()
+{
+ note_entrance0("ega_init");
+ /*
+ * Define sequencer's ports
+ */
+
+ io_define_outb(EGA_SEQ_ADAP_INDEX,ega_seq_outb_index);
+ io_define_outb(EGA_SEQ_ADAP_DATA,ega_seq_reset);
+ io_connect_port(EGA_SEQ_INDEX,EGA_SEQ_ADAP_INDEX,IO_WRITE);
+ io_connect_port(EGA_SEQ_DATA,EGA_SEQ_ADAP_DATA,IO_WRITE);
+
+ /*
+ * Define CRTC's ports
+ */
+
+ io_define_outb(EGA_CRTC_ADAPTOR,ega_crtc_outb);
+ io_define_inb(EGA_CRTC_ADAPTOR,ega_crtc_inb);
+ io_connect_port(EGA_CRTC_INDEX,EGA_CRTC_ADAPTOR,IO_WRITE);
+ io_connect_port(EGA_CRTC_DATA,EGA_CRTC_ADAPTOR,IO_READ_WRITE);
+
+ /*
+ * Define Graphics Controller's ports
+ */
+
+ ega_gc_outb_index_addr = (UTINY *) &graphics_controller.address;
+
+ /*io_define_outb(EGA_GC_ADAP_INDEX,ega_gc_outb_index);*/
+ io_define_out_routines(EGA_GC_ADAP_INDEX, ega_gc_outb_index, ega_gc_outw, NULL, NULL);
+
+#ifndef CPU_40_STYLE /* TEMPORARY */
+ Cpu_define_outb(EGA_GC_ADAP_INDEX,_ega_gc_outb_index);
+#endif
+
+ io_define_outb(EGA_GC_ADAP_DATA,ega_gc_set_reset);
+ Cpu_define_outb(EGA_GC_ADAP_DATA,NULL);
+#ifndef A2CPU
+ ega_gc_regs_cpu[8] = NULL;
+#endif
+
+ io_connect_port(EGA_GC_INDEX,EGA_GC_ADAP_INDEX,IO_WRITE);
+ io_connect_port(EGA_GC_DATA,EGA_GC_ADAP_DATA,IO_WRITE);
+
+ /*
+ * Define Attribute controller's ports
+ */
+
+ io_define_outb(EGA_AC_ADAPTOR,ega_ac_outb);
+ io_connect_port(EGA_AC_INDEX_DATA,EGA_AC_ADAPTOR,IO_WRITE);
+ io_connect_port(EGA_AC_SECRET,EGA_AC_ADAPTOR,IO_WRITE);
+
+ /*
+ * Define Miscellaneous register's port
+ */
+
+ io_define_outb(EGA_MISC_ADAPTOR,ega_misc_outb);
+ io_connect_port(EGA_MISC_REG,EGA_MISC_ADAPTOR,IO_WRITE);
+
+ /*
+ * Define Feature controller's port
+ */
+
+ io_define_outb(EGA_FEAT_ADAPTOR,ega_feat_outb);
+ io_connect_port(EGA_FEAT_REG,EGA_FEAT_ADAPTOR,IO_WRITE);
+
+ /*
+ * Define Input Status Register 0 port
+ */
+
+ io_define_inb(EGA_IPSTAT0_ADAPTOR,ega_ipstat0_inb);
+ io_connect_port(EGA_IPSTAT0_REG,EGA_IPSTAT0_ADAPTOR,IO_READ);
+
+ /*
+ * Define Input Status Register 1 port
+ */
+
+ io_define_inb(EGA_IPSTAT1_ADAPTOR,ega_ipstat1_inb);
+ io_connect_port(EGA_IPSTAT1_REG,EGA_IPSTAT1_ADAPTOR,IO_READ);
+
+ /*
+ * Initialise internals of EGA
+ * +++++++++++++++++++++++++++
+ */
+
+ /* hardware reset sets Misc reg to 0, so.. */
+ /* Perhaps this should be in 'ega_reset()'? */
+
+ miscellaneous_output_register.as.abyte = 0;
+
+ set_pc_pix_height(1); /* set by bit 7 of the misc reg */
+ set_host_pix_height(1);
+
+ /* Initialize address map */
+
+ graphics_controller.miscellaneous.as.abyte = 0;
+ graphics_controller.read_map_select.as_bfld.map_select = 0;
+
+ /* Looking for bright white */
+
+ graphics_controller.color_compare.as_bfld.color_compare = 0xf;
+
+ /* All planes significant */
+
+ graphics_controller.color_dont_care.as_bfld.color_dont_care = 0xf;
+
+ /* Initialise crtc screen height fields and set screen height to be consistent */
+
+ crt_controller.vertical_display_enable_end = 0;
+ crt_controller.crtc_overflow.as_bfld.vertical_display_enab_end_bit_8 = 0;
+
+ set_screen_height(0);
+
+ init_vga_globals();
+
+ EGA_CPU.fun_or_protection = 1; /* assume complicated until we know it's easy */
+
+ setVideobit_prot_mask(0xffffffff);
+
+ ega_write_init();
+ ega_read_init();
+ ega_mode_init(); /* sets a flag in ega_mode.c to allow optimisation of mode changes without falling over */
+
+ /*
+ * Some parts of input status register always return 1, so set fields accordingly
+ */
+ input_status_register_zero.as.abyte = 0x7f ;
+
+ /*
+ * set up some variables to get us going
+ * (They may have to be changed in the fullness of time)
+ */
+
+ gvi_pc_low_regen = CGA_REGEN_START;
+ gvi_pc_high_regen = CGA_REGEN_END;
+
+ choose_display_mode = choose_ega_display_mode;
+
+ set_pix_width(1);
+ set_pix_char_width(8);
+ set_display_disabled(FALSE);
+
+ set_char_height(8);
+ set_screen_limit(0x8000);
+ set_screen_start(0);
+ set_word_addressing(YES);
+ set_actual_offset_per_line(80);
+ set_offset_per_line(160); /* chained */
+ set_horiz_total(80); /* calc screen params from this and prev 3 */
+ set_screen_split(511); /* make sure there is no split screen to start with ! */
+
+ set_prim_font_index(0);
+ set_sec_font_index(0);
+
+ set_regen_ptr(0,EGA_planes);
+
+ /* prevent copyright message mysteriously disappearing */
+ timer_video_enabled = TRUE;
+
+}
+
+void ega_term IFN0()
+{
+
+int index;
+
+ note_entrance0("ega_term");
+
+ /*
+ * Disconnect sequencer's ports
+ */
+
+ io_disconnect_port(EGA_SEQ_INDEX,EGA_SEQ_ADAP_INDEX);
+ io_disconnect_port(EGA_SEQ_DATA,EGA_SEQ_ADAP_DATA);
+
+ /*
+ * Disconnect CRTC's ports
+ */
+
+ io_disconnect_port(EGA_CRTC_INDEX,EGA_CRTC_ADAPTOR);
+ io_disconnect_port(EGA_CRTC_DATA,EGA_CRTC_ADAPTOR);
+
+ /*
+ * Disconnect Graphics Controller's ports
+ */
+
+ io_disconnect_port(EGA_GC_INDEX,EGA_GC_ADAP_INDEX);
+ io_disconnect_port(EGA_GC_DATA,EGA_GC_ADAP_DATA);
+
+ /*
+ * Disconnect Attribute controller's ports
+ */
+
+ io_disconnect_port(EGA_AC_INDEX_DATA,EGA_AC_ADAPTOR);
+ io_disconnect_port(EGA_AC_SECRET,EGA_AC_ADAPTOR);
+
+ /*
+ * Disconnect Miscellaneous register's port
+ */
+
+ io_disconnect_port(EGA_MISC_REG,EGA_MISC_ADAPTOR);
+
+ /*
+ * Disconnect Feature controller's port
+ */
+
+ io_disconnect_port(EGA_FEAT_REG,EGA_FEAT_ADAPTOR);
+
+ /*
+ * Disconnect Input Status Register 0 port
+ */
+
+ io_disconnect_port(EGA_IPSTAT0_REG,EGA_IPSTAT0_ADAPTOR);
+
+ /*
+ * Disconnect Input Status Register 1 port
+ */
+
+ io_disconnect_port(EGA_IPSTAT1_REG,EGA_IPSTAT1_ADAPTOR);
+
+ /*
+ * Free internals of EGA
+ */
+
+ /* free the font files */
+ for (index = 0; index < 4; index++)
+ host_free_font(index);
+
+ /* Disable CPU read processing */
+ ega_read_term();
+ ega_write_term();
+}
+
+LOCAL void ega_seq_outb_index IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_outb_index(%x,%x)", port, value);
+ assert1(value<5,"Bad seq index %d",value);
+ NON_PROD(sequencer.address.as.abyte = value);
+ io_redefine_outb(EGA_SEQ_ADAP_DATA,ega_seq_regs[value & 7]);
+}
+
+void ega_seq_reset IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_reset(%x,%x)", port, value);
+ /* change reset register */
+ note_entrance0("reset register");
+ sequencer.reset.as.abyte = value ;
+ if (sequencer.reset.as_bfld.asynchronous_reset==0)
+ set_bit_display_disabled(ASYNC_RESET);
+ else
+ clear_bit_display_disabled(ASYNC_RESET);
+ if (sequencer.reset.as_bfld.synchronous_reset==0)
+ set_bit_display_disabled(SYNC_RESET);
+ else
+ clear_bit_display_disabled(SYNC_RESET);
+}
+
+void ega_seq_clock IFN2(io_addr, port, half_word, value)
+{
+register int dot_clock;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_clock(%x,%x)", port, value);
+ /* clock mode register */
+ dot_clock = sequencer.clocking_mode.as_bfld.dot_clock;
+ sequencer.clocking_mode.as.abyte = value;
+ if (sequencer.clocking_mode.as_bfld.dot_clock != dot_clock) {
+ /*
+ ** Switch to/from double width pixels
+ */
+ if (sequencer.clocking_mode.as_bfld.dot_clock==1) {
+ set_pix_width(2);
+ set_double_pix_wid(YES);
+ set_pix_char_width(16);
+ } else {
+ set_pix_width(1);
+ set_double_pix_wid(NO);
+ set_pix_char_width(8);
+ }
+ flag_mode_change_required();
+ }
+}
+
+void ega_seq_map_mask IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_map_mask(%x,%x)", port, value);
+
+ /* map mask register */
+
+ /*
+ * Different display plane(s) have been enabled. Update the video
+ * routines to deal with this
+ */
+
+ setVideoplane_enable(value & 0xf);
+ setVideoplane_enable_mask(sr_lookup[value & 0xf]);
+ write_state.pe = ((value & 0xf) == 0xf) ? 1 : 0;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+
+ ega_write_routines_update(PLANES_ENABLED);
+}
+
+void ega_seq_char_map IFN2(io_addr, port, half_word, value)
+{
+register int map_selects;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_char_map(%x,%x)", port, value);
+ /* char map select reg */
+ map_selects = sequencer.character_map_select.character.map_selects;
+ sequencer.character_map_select.as.abyte = value;
+ if (sequencer.character_map_select.character.map_selects != map_selects)
+ {
+ /*
+ ** character mapping attributes have changed.
+ **
+ ** If fonts selected are different bit 3 of attribute byte in alpha mode
+ ** selects which of the two fonts to use (giving 512 chars).
+ */
+
+ EGA_GRAPH.attrib_font_select = (sequencer.character_map_select.as_bfld.character_map_select_a !=
+ sequencer.character_map_select.as_bfld.character_map_select_b );
+ set_prim_font_index(sequencer.character_map_select.as_bfld.character_map_select_a);
+ set_sec_font_index(sequencer.character_map_select.as_bfld.character_map_select_b);
+
+ host_select_fonts(get_prim_font_index(), get_sec_font_index());
+ flag_mode_change_required();
+ }
+}
+
+void ega_seq_mem_mode IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_seq_mem_mode(%x,%x)", port, value);
+
+ /* mem mode register */
+
+ sequencer.memory_mode.as.abyte = value ;
+
+ /*
+ ** Decide alpha/graphics mode by voting
+ */
+ vote_ega_mode();
+
+ /*
+ * See if this causes a by-election for plane addressing
+ */
+
+ do_chain_majority_decision();
+
+ assert1(sequencer.memory_mode.as_bfld.extended_memory == 1,"Someone is trying to set extended memory to 0 (reg=%x)",value);
+}
+
+LOCAL void ega_crtc_outb IFN2(io_addr, port, half_word, value)
+{
+ SHORT offset;
+ struct { /* avoid alignment problems with casts */
+ unsigned value : 8;
+ } new;
+ static int old_underline_start;
+
+
+ note_entrance2("ega_crtc_outb(%x,%x)", port, value);
+ new.value = value;
+ switch (port) {
+ case 0x3d4:
+ note_entrance1("New crtc index %d",value);
+ crt_controller.address.as.abyte = value;
+ break;
+ case 0x3d5:
+ note_entrance1( "Index %d", crt_controller.address.as_bfld.index );
+ switch (crt_controller.address.as_bfld.index) {
+ case 0:
+ note_entrance0("horiz total");
+ NON_PROD(crt_controller.horizontal_total = value);
+ break;
+ case 1:
+ note_entrance0("horiz display end");
+ crt_controller.horizontal_display_end = value+1;
+ set_horiz_total(crt_controller.horizontal_display_end);
+ break;
+ case 2:
+ note_entrance0("start horiz blank");
+ NON_PROD(crt_controller.start_horizontal_blanking = value);
+ break;
+ case 3:
+ note_entrance0("end horiz blank");
+ NON_PROD(crt_controller.end_horizontal_blanking.as.abyte = value);
+ break;
+ case 4:
+ note_entrance0("start horiz retrace");
+ NON_PROD(crt_controller.start_horizontal_retrace = value);
+ break;
+ case 5:
+ note_entrance0("end horiz retrace");
+ NON_PROD(crt_controller.end_horizontal_retrace.as.abyte = value);
+ break;
+ case 6:
+ note_entrance0("vert tot");
+ NON_PROD(crt_controller.vertical_total = value);
+ break;
+ case 7:
+ note_entrance0("overflow");
+ if (crt_controller.crtc_overflow.as_bfld.vertical_display_enab_end_bit_8 !=
+ ((CRTC_OVERFLOW*)&new)->as_bfld.vertical_display_enab_end_bit_8)
+ {
+ /*
+ * Screen height changed
+ */
+
+#ifdef VGG
+ /*
+ * if VGG is set then the screen height
+ * definition is extended from 9 bits to
+ * 10. Thus the 9th bit is now a 'med'
+ * bit and not a 'hi' bit.
+ */
+ set_screen_height_med_recal(
+ ((CRTC_OVERFLOW*)&new)->as_bfld.vertical_display_enab_end_bit_8 );
+#else
+ set_screen_height_hi_recal(
+ ((CRTC_OVERFLOW*)&new)->as_bfld.vertical_display_enab_end_bit_8 );
+#endif
+ flag_mode_change_required();
+ }
+ if (crt_controller.crtc_overflow.as_bfld.line_compare_bit_8 !=
+ ((CRTC_OVERFLOW*)&new)->as_bfld.line_compare_bit_8)
+ {
+ /*
+ * split screen height changed
+ */
+
+ EGA_GRAPH.screen_split.as_bfld.top_bit =
+ ((CRTC_OVERFLOW*)&new)->as_bfld.line_compare_bit_8;
+
+ if( !get_split_screen_used() )
+ flag_mode_change_required();
+
+ screen_refresh_required();
+ }
+ crt_controller.crtc_overflow.as.abyte = value;
+ break;
+ case 8:
+ note_entrance0("preset row scan");
+ NON_PROD(crt_controller.preset_row_scan.as.abyte = value);
+ break;
+ case 9:
+ note_entrance0("max scan line");
+ if (crt_controller.maximum_scan_line.as_bfld.maximum_scan_line !=
+ ((MAX_SCAN_LINE*)&new)->as_bfld.maximum_scan_line)
+ {
+ set_char_height_recal(
+ (((MAX_SCAN_LINE*)&new)->as_bfld.maximum_scan_line)+1);
+ do_new_cursor();
+ }
+ crt_controller.maximum_scan_line.as.abyte = value;
+ break;
+ case 10:
+ note_entrance0("cursor start");
+ if (crt_controller.cursor_start.as_bfld.cursor_start !=
+ ((CURSOR_START*)&new)->as_bfld.cursor_start)
+ {
+ crt_controller.cursor_start.as.abyte = value;
+ do_new_cursor();
+ }
+ break;
+ case 11:
+ note_entrance0("cursor end");
+ if (crt_controller.cursor_end.as_bfld.cursor_end !=
+ ((CURSOR_END*)&new)->as_bfld.cursor_end)
+ {
+ crt_controller.cursor_end.as.abyte = value;
+ assert0(crt_controller.cursor_end.as_bfld.cursor_skew_control == 0,
+ "Someone is trying to use cursor skew");
+ do_new_cursor();
+ }
+ break;
+ case 12:
+ note_entrance0("start address high");
+ if (crt_controller.start_address_high != value)
+ {
+ set_screen_start((value << 8) + crt_controller.start_address_low);
+ host_screen_address_changed(crt_controller.start_address_high,
+ crt_controller.start_address_low);
+ /* check if it wraps now */
+ if ( get_memory_chained() ) {
+ if( (get_screen_start()<<1) + get_screen_length() > 2*EGA_PLANE_SZ )
+ choose_ega_display_mode();
+ }
+ else {
+ if( get_screen_start() + get_screen_length() > EGA_PLANE_SZ )
+ choose_ega_display_mode();
+ }
+ screen_refresh_required();
+ }
+ crt_controller.start_address_high = value;
+ break;
+ case 13:
+ note_entrance0("start address low");
+ if (crt_controller.start_address_low != value)
+ {
+ set_screen_start((crt_controller.start_address_high << 8) + value);
+ host_screen_address_changed(crt_controller.start_address_high,
+ crt_controller.start_address_low);
+ /* check if it wraps now */
+ if ( get_memory_chained() ) {
+ if( (get_screen_start()<<1) + get_screen_length() > 2*EGA_PLANE_SZ )
+ choose_ega_display_mode();
+ }
+ else {
+ if( get_screen_start() + get_screen_length() > EGA_PLANE_SZ )
+ choose_ega_display_mode();
+ }
+ screen_refresh_required();
+ }
+ crt_controller.start_address_low = value;
+ break;
+ case 14:
+ note_entrance0("cursor loc high");
+ if (crt_controller.cursor_location_high != value)
+ {
+ crt_controller.cursor_location_high = value;
+
+ offset = (value<<8) | crt_controller.cursor_location_low;
+ offset -= get_screen_start();
+
+ set_cur_x(offset % crt_controller.horizontal_display_end);
+ set_cur_y(offset / crt_controller.horizontal_display_end);
+
+ do_new_cursor();
+
+ if(!get_mode_change_required() && is_it_text())
+ cursor_changed( get_cur_x(), get_cur_y());
+ }
+ break;
+ case 15:
+ note_entrance0("cursor loc lo");
+ if (crt_controller.cursor_location_low != value)
+ {
+ crt_controller.cursor_location_low = value;
+
+ offset = value | (crt_controller.cursor_location_high<<8);
+ offset -= get_screen_start();
+
+ set_cur_x(offset % crt_controller.horizontal_display_end);
+ set_cur_y(offset / crt_controller.horizontal_display_end);
+
+ do_new_cursor();
+
+ if(!get_mode_change_required() && is_it_text())
+ cursor_changed( get_cur_x(), get_cur_y());
+ }
+ break;
+ case 16:
+ note_entrance0("vert retrace start");
+ NON_PROD(crt_controller.vertical_retrace_start = value);
+ break;
+ case 17:
+ note_entrance0("vert retrace end");
+ crt_controller.vertical_retrace_end.as.abyte = value;
+ if ((value & 32) == 32)
+ ega_int_enable = 0;
+ else
+ ega_int_enable = 1;
+ if ((value & 16) != 16)
+ {
+ ica_clear_int(AT_EGA_VTRACE_ADAPTER,AT_EGA_VTRACE_INT);
+ /*
+ * clear status latch
+ */
+ input_status_register_zero.as_bfld.crt_interrupt = 0; /* = !VS */
+ }
+ /* ??? */
+ break;
+ case 18:
+ note_entrance0("vert disp enable end");
+ if (crt_controller.vertical_display_enable_end != value)
+ {
+ crt_controller.vertical_display_enable_end = value;
+ set_screen_height_lo_recal(value);
+ }
+ break;
+ case 19:
+ note_entrance0("offset");
+ if (crt_controller.offset != value)
+ {
+ crt_controller.offset = value;
+ set_actual_offset_per_line(value<<1); /* actual offset into plane in bytes */
+ flag_mode_change_required();
+ }
+ break;
+ case 20:
+ note_entrance0("underline loc");
+ crt_controller.underline_location.as.abyte = value;
+ if( value != old_underline_start )
+ {
+ old_underline_start = value;
+ set_underline_start(
+ crt_controller.underline_location.as_bfld.underline_location);
+ screen_refresh_required();
+ }
+ break;
+ case 21:
+ note_entrance0("start vert blank");
+ NON_PROD(crt_controller.start_vertical_blanking = value);
+ break;
+ case 22:
+ note_entrance0("end vert blank");
+ NON_PROD(crt_controller.end_vertical_blanking = value);
+ break;
+ case 23:
+ note_entrance0("mode control");
+ if (crt_controller.mode_control.as_bfld.compatibility_mode_support !=
+ ((MODE_CONTROL*)&new)->as_bfld.compatibility_mode_support)
+ {
+ if ( (((MODE_CONTROL*)&new)->as_bfld.compatibility_mode_support) == 0)
+ set_cga_mem_bank(YES);
+ else set_cga_mem_bank(NO);
+ flag_mode_change_required();
+ }
+ if (crt_controller.mode_control.as_bfld.word_or_byte_mode !=
+ ((MODE_CONTROL*)&new)->as_bfld.word_or_byte_mode)
+ {
+ set_word_addressing_recal(
+ (((MODE_CONTROL*)&new)->as_bfld.word_or_byte_mode) == 0 );
+ }
+ crt_controller.mode_control.as.abyte = value;
+ assert0(crt_controller.mode_control.as_bfld.select_row_scan_counter == 1,"Row scan 0");
+ assert0(crt_controller.mode_control.as_bfld.horizontal_retrace_select == 0,
+ "retrace select 1");
+ assert0(crt_controller.mode_control.as_bfld.output_control == 0,"output control set");
+ assert0(crt_controller.mode_control.as_bfld.hardware_reset == 1,"hardware reset cleared");
+ break;
+ case 24:
+ note_entrance0("line compare reg");
+ if (crt_controller.line_compare != value)
+ {
+ crt_controller.line_compare = value;
+ EGA_GRAPH.screen_split.as_bfld.low_byte = value;
+
+ if( !get_split_screen_used() )
+ flag_mode_change_required();
+
+ screen_refresh_required();
+
+ }
+ break;
+ default:
+ assert1(NO,"Bad crtc index %d",crt_controller.address.as_bfld.index);
+ break;
+ }
+ break;
+ default:
+ assert1(NO,"Bad port passed %x", port );
+ break;
+ }
+}
+
+LOCAL void ega_crtc_inb IFN2(io_addr, port, half_word *, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance3("ega_crtc_inb(%x,%x) index %d", port, value, crt_controller.address.as_bfld.index);
+ switch(crt_controller.address.as_bfld.index) {
+ case 10:
+ *value = crt_controller.cursor_start.as.abyte ;
+ note_entrance1("cursor start %d",*value);
+ break;
+ case 11:
+ *value = crt_controller.cursor_end.as.abyte ;
+ note_entrance1("cursor end %d",*value);
+ break;
+ case 12:
+ *value = crt_controller.start_address_high ;
+ note_entrance1("start address high %x",*value);
+ break;
+ case 13:
+ *value = crt_controller.start_address_low ;
+ note_entrance1("start address low %x",*value);
+ break;
+ case 14:
+ *value = crt_controller.cursor_location_high ;
+ note_entrance1("cursor location high %x",*value);
+ break;
+ case 15:
+ *value = crt_controller.cursor_location_low ;
+ note_entrance1("cursor location low %x",*value);
+ break;
+ case 16:
+ *value = 0; /* light pen high */
+ note_entrance1("light pen high %x",*value);
+ break;
+ case 17:
+ *value = 0; /* light pen low */
+ note_entrance1("light pen low %x",*value);
+ break;
+ default:
+ assert1(crt_controller.address.as_bfld.index>24,"inb from bad crtc index %d",crt_controller.address.as_bfld.index);
+ *value = IO_EMPTY_PORT_BYTE_VALUE;
+ break;
+ }
+}
+
+
+void ega_gc_outb_index IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_outb_index(%x,%x)", port, value);
+ NON_PROD(graphics_controller.address.as.abyte = value);
+ assert1(value<9,"Bad gc index %d",value);
+
+ io_redefine_outb(EGA_GC_ADAP_DATA,ega_gc_regs[value & 15]);
+ Cpu_define_outb(EGA_GC_ADAP_DATA,ega_gc_regs_cpu[value & 15]);
+}
+
+
+/**/
+
+
+/*( ega_gc_outw
+** Most PC programs do an "OUT DX, AX" which sets up the GC index
+** register with the AL and the GC data register with AH.
+** Avoid going through generic_outw() by doing it all here!
+)*/
+GLOBAL VOID ega_gc_outw IFN2(io_addr, port, word, outval)
+{
+ reg temp;
+ INT value;
+
+ temp.X = outval;
+ value = temp.byte.low;
+
+ NON_PROD(graphics_controller.address.as.abyte = value);
+
+ assert1(value<9,"Bad gc index %#x", value);
+
+ value &= 15;
+
+ io_redefine_outb(EGA_GC_ADAP_DATA,ega_gc_regs[value]);
+ Cpu_define_outb(EGA_GC_ADAP_DATA,ega_gc_regs_cpu[value]);
+
+ (*(ega_gc_regs[value]))(port+1, temp.byte.high);
+}
+
+
+/**/
+
+
+void ega_gc_set_reset IFN2(io_addr, port, half_word, value)
+{
+register int set_reset;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_set_reset(%x,%x)", port, value);
+
+ set_reset = graphics_controller.set_or_reset.as_bfld.set_or_reset;
+ graphics_controller.set_or_reset.as.abyte = value;
+
+ if (graphics_controller.set_or_reset.as_bfld.set_or_reset != set_reset)
+ {
+ EGA_CPU.set_reset = graphics_controller.set_or_reset.as_bfld.set_or_reset;
+ ega_write_routines_update(SET_RESET);
+ }
+}
+
+void ega_gc_enable_set IFN2(io_addr, port, half_word, value)
+{
+register int en_set_reset;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_enable_set(%x,%x)", port, value);
+
+ en_set_reset = graphics_controller.enable_set_or_reset.as_bfld.enable_set_or_reset;
+ graphics_controller.enable_set_or_reset.as.abyte = value;
+
+ if (graphics_controller.enable_set_or_reset.as_bfld.enable_set_or_reset != en_set_reset)
+ {
+ EGA_CPU.sr_enable = graphics_controller.enable_set_or_reset.as_bfld.enable_set_or_reset;
+ write_state.sr = graphics_controller.enable_set_or_reset.as_bfld.enable_set_or_reset==0?0:1;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+ ega_write_routines_update(ENABLE_SET_RESET);
+ }
+}
+
+void ega_gc_compare IFN2(io_addr, port, half_word, value)
+{
+register int colour_compare;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_compare(%x,%x)", port, value);
+ colour_compare = graphics_controller.color_compare.as_bfld.color_compare;
+ graphics_controller.color_compare.as.abyte = value;
+ if (graphics_controller.color_compare.as_bfld.color_compare != colour_compare)
+ {
+ read_state.colour_compare = graphics_controller.color_compare.as_bfld.color_compare;
+ if (read_state.mode == 1) ega_read_routines_update();
+ }
+}
+
+void ega_gc_rotate IFN2(io_addr, port, half_word, value)
+{
+ struct {
+ unsigned value : 8;
+ } new;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_rotate(%x,%x)", port, value);
+ note_entrance0("data rotate");
+ new.value = value;
+ if (graphics_controller.data_rotate.as_bfld.rotate_count != ((DATA_ROTATE*)&new)->as_bfld.rotate_count )
+ {
+ setVideorotate(((DATA_ROTATE*)&new)->as_bfld.rotate_count);
+ ega_write_routines_update(ROTATION);
+ }
+
+ if (graphics_controller.data_rotate.as_bfld.function_select != ((DATA_ROTATE*)&new)->as_bfld.function_select)
+ {
+ write_state.func = ((DATA_ROTATE*)&new)->as_bfld.function_select;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+ ega_write_routines_update(FUNCTION);
+ }
+ EGA_CPU.fun_or_protection = (value != 0) || write_state.bp;
+ graphics_controller.data_rotate.as.abyte = value;
+}
+
+void ega_gc_read_map IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_read_map(%x,%x)", port, value);
+
+ setVideoread_mapped_plane(value & 3);
+
+ update_shift_count();
+}
+
+void ega_gc_mode IFN2(io_addr, port, half_word, value)
+{
+MODE new_mode;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_set_reset(%x,%x)", port, value);
+ new_mode.as.abyte = value;
+ if (graphics_controller.mode.as_bfld.write_mode != new_mode.as_bfld.write_mode)
+ {
+ /*
+ * write mode change
+ */
+
+ EGA_CPU.write_mode = new_mode.as_bfld.write_mode;
+ setVideowrmode(EGA_CPU.write_mode);
+ ega_write_routines_update(WRITE_MODE);
+ }
+
+ if (graphics_controller.mode.as_bfld.read_mode != new_mode.as_bfld.read_mode)
+ {
+ /*
+ * read mode change
+ */
+ read_state.mode = new_mode.as_bfld.read_mode;
+ ega_read_routines_update();
+ }
+
+ if (graphics_controller.mode.as_bfld.shift_register_mode != new_mode.as_bfld.shift_register_mode)
+ {
+ /*
+ * going to/from one cga graphics mode to another
+ */
+ set_graph_shift_reg(new_mode.as_bfld.shift_register_mode);
+ flag_mode_change_required();
+ }
+
+ graphics_controller.mode.as.abyte = new_mode.as.abyte;
+
+ /*
+ * Check for any change to chained mode rule by having an election
+ * (Note: EGA registers must be updated before calling election)
+ */
+
+ do_chain_majority_decision();
+
+ assert0(graphics_controller.mode.as_bfld.test_condition == 0,"Test conditon set");
+}
+
+void ega_gc_misc IFN2(io_addr, port, half_word, value)
+{
+register int memory_map;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_misc(%x,%x)", port, value);
+ memory_map = graphics_controller.miscellaneous.as_bfld.memory_map;
+ graphics_controller.miscellaneous.as.abyte = value;
+ if (graphics_controller.miscellaneous.as_bfld.memory_map != memory_map)
+ {
+ /*
+ * Where EGA appears in PC memory space changed.
+ */
+ if (miscellaneous_output_register.as_bfld.enable_ram)
+ sas_disconnect_memory(gvi_pc_low_regen,gvi_pc_high_regen);
+
+ switch (graphics_controller.miscellaneous.as_bfld.memory_map)
+ {
+ case 0:
+ gvi_pc_low_regen = 0xA0000;
+ gvi_pc_high_regen = 0xBFFFF;
+ break;
+ case 1:
+ gvi_pc_low_regen = 0xA0000;
+ gvi_pc_high_regen = 0xAFFFF;
+ break;
+ case 2:
+ gvi_pc_low_regen = 0xB0000;
+ gvi_pc_high_regen = 0xB7FFF;
+ break;
+ case 3:
+ gvi_pc_low_regen = 0xB8000;
+ gvi_pc_high_regen = 0xBFFFF;
+ break;
+ }
+
+ if (miscellaneous_output_register.as_bfld.enable_ram)
+ sas_connect_memory(gvi_pc_low_regen,gvi_pc_high_regen,(half_word)SAS_VIDEO);
+
+ /*
+ * Tell cpu associated modules that regen area has moved
+ */
+
+ ega_read_routines_update();
+ ega_write_routines_update(RAM_MOVED);
+ }
+
+ /*
+ ** Vote on alpha/graphics mode.
+ */
+ vote_ega_mode();
+
+ /*
+ * Check for any change to chained mode rule by having an election
+ * (Note: EGA registers must be updated before calling election)
+ */
+
+ do_chain_majority_decision();
+}
+
+void ega_gc_dont_care IFN2(io_addr, port, half_word, value)
+{
+register int colour_dont_care;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_dont_care(%x,%x)", port, value);
+ colour_dont_care = graphics_controller.color_dont_care.as_bfld.color_dont_care;
+ graphics_controller.color_dont_care.as.abyte = value;
+ if (graphics_controller.color_dont_care.as_bfld.color_dont_care != colour_dont_care)
+ {
+ read_state.colour_dont_care = graphics_controller.color_dont_care.as_bfld.color_dont_care;
+ if (read_state.mode == 1) ega_read_routines_update();
+ }
+}
+
+/*
+ * The EGA mask register is written to more times than all other ports added together!
+ * To help make this register fast, we have two different routines to handle it:
+ * ega_gc_mask for when the register's current value is not 0xFF, ie. masking is active
+ * ega_gc_mask_ff for when the mask register = 0xFF, so masking is disabled.
+ */
+
+/*(
+** ega_mask_register_changed
+** This gets called whenever the mask register gets changed, and
+** updates the internals appropriately. Since the mask registers
+** are hit more than any other registers, this should do the job!
+**
+** Rather than calling the monster ega_write_routines_update() (in "ega_write.c"),
+** we do as little as we possibly can here!
+** In particular, all we do is set the video write pointer handlers
+** to the appropriate one and update the internal EGA_CPU state...
+**
+** We DON'T do anything about altering the marking funcs, etc.
+**
+** See also "vga_mask_register_changed" in "vga_ports.c"
+**
+** NB: GLOBAL for JOKER.
+**
+)*/
+#include "cpu_vid.h"
+
+GLOBAL VOID ega_mask_register_changed IFN1(BOOL, gotBitProtection)
+{
+ ULONG state;
+ SAVED IU8 masks[] = {0x1f, 0x01, 0x0f, 0x0f};
+ IMPORT WRT_POINTERS *mode_chain_handler_table[];
+#ifdef V7VGA
+ IMPORT UTINY Last_v7_fg_bg, fg_bg_control;
+#endif
+
+ write_state.bp = gotBitProtection;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+ EGA_CPU.fun_or_protection = (gotBitProtection || (graphics_controller.data_rotate.as.abyte != 0));
+
+ /* Check that we're not trying to handle any pathological cases here...
+ ** This means we chicken out for Chain2 and V7VGA dithering.
+ */
+
+ if ((EGA_CPU.chain == CHAIN2)
+#ifdef V7VGA
+ || ( Last_v7_fg_bg != fg_bg_control)
+#endif /* V7VGA */
+ )
+ {
+ ega_write_routines_update(BIT_PROT);
+
+ return;
+ }
+
+ /* the "mode_0" union variant has the largest "lookup" field (5 bits.) */
+
+ state = EGA_CPU.ega_state.mode_0.lookup & masks[EGA_CPU.write_mode];
+
+#ifdef A3CPU
+#ifdef C_VID
+ Glue_set_vid_wrt_ptrs(&mode_chain_handler_table[EGA_CPU.saved_mode_chain][state]);
+#else
+ Cpu_set_vid_wrt_ptrs(&mode_chain_handler_table[EGA_CPU.saved_mode_chain][state]);
+#endif /* C_VID */
+#else
+#if !(defined(NTVDM) && defined(MONITOR))
+ Glue_set_vid_wrt_ptrs(&mode_chain_handler_table[EGA_CPU.saved_mode_chain][state]);
+#endif /* !(NTVDM && MONITOR) */
+#endif /* A3CPU */
+
+ EGA_CPU.saved_state = state;
+}
+
+
+/**/
+
+
+/* ega_gc_mask is the one that is usually called */
+
+LOCAL void ega_gc_mask IFN2(io_addr, port, half_word, value)
+{
+ register unsigned int mask;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_mask(%x,%x)", port, value);
+
+ /*
+ * Update video routine according to new bit protection
+ */
+
+ mask = value | (((USHORT)value) << 8);
+ mask |= (mask << 16); /* replicate the mask into 4 bytes */
+ setVideobit_prot_mask(mask);
+ setVideodata_xor_mask(~(EGA_CPU.calc_data_xor & mask));
+ setVideolatch_xor_mask(EGA_CPU.calc_latch_xor & mask);
+ if( value == 0xff )
+ {
+#ifndef USE_OLD_MASK_CODE
+ ega_mask_register_changed(/*bit protection :=*/0);
+#else
+ write_state.bp = 0;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+ EGA_CPU.fun_or_protection = (graphics_controller.data_rotate.as.abyte != 0);
+ ega_write_routines_update(BIT_PROT);
+#endif /* USE_OLD_MASK_CODE */
+
+ /* Alter the function table used by ega_gc_index */
+ ega_gc_regs[8] = ega_gc_mask_ff;
+
+#ifndef CPU_40_STYLE /* TEMPORARY */
+#ifndef A2CPU
+ /* Alter the function table used by assembler ega_gc_index */
+ ega_gc_regs_cpu[8] = _ega_gc_outb_mask_ff;
+#endif
+#endif
+
+ io_redefine_outb(EGA_GC_ADAP_DATA,ega_gc_mask_ff);
+
+#ifndef CPU_40_STYLE /* TEMPORARY */
+ Cpu_define_outb(EGA_GC_ADAP_DATA,_ega_gc_outb_mask_ff);
+#endif
+ }
+}
+
+/* This version isn't called so often */
+void ega_gc_mask_ff IFN2(io_addr, port, half_word, value)
+{
+ register unsigned int mask;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_gc_mask(%x,%x)", port, value);
+
+ /*
+ * Update video routine according to new bit protection
+ */
+
+ if(value != 0xff)
+ {
+ mask = value | (((USHORT)value) << 8);
+ mask |= (mask << 16); /* replicate the mask into 4 bytes */
+ setVideobit_prot_mask(mask);
+ setVideodata_xor_mask(~(EGA_CPU.calc_data_xor & mask));
+ setVideolatch_xor_mask(EGA_CPU.calc_latch_xor & mask);
+#ifndef USE_OLD_MASK_CODE
+ ega_mask_register_changed(/*bit protection :=*/1);
+#else
+ write_state.bp = 1;
+ setVideowrstate(EGA_CPU.ega_state.mode_0.lookup);
+ EGA_CPU.fun_or_protection = TRUE;
+ ega_write_routines_update(BIT_PROT);
+#endif /* USE_OLD_MASK_CODE*/
+
+ /* Alter the function table used by ega_gc_index */
+ ega_gc_regs[8] = ega_gc_mask;
+
+#ifndef CPU_40_STYLE /* TEMPORARY */
+#ifndef A2CPU
+ /* Alter the function table used by assembler ega_gc_index */
+ ega_gc_regs_cpu[8] = _ega_gc_outb_mask;
+#endif
+#endif
+
+ io_redefine_outb(EGA_GC_ADAP_DATA,ega_gc_mask);
+
+#ifndef CPU_40_STYLE /* TEMPORARY */
+ Cpu_define_outb(EGA_GC_ADAP_DATA,_ega_gc_outb_mask);
+#endif
+ }
+}
+
+LOCAL void ega_index_invalid IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+ UNUSED(value);
+#endif
+ note_entrance2("ega_index_invalid(%x,%x)", port, value);
+ assert1(NO,"Invalid index %d",graphics_controller.address.as_bfld.index);
+}
+
+LOCAL void ega_ac_outb IFN2(io_addr, port, half_word, value)
+{
+ struct {
+ unsigned value : 8;
+ } new;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_ac_outb(%x,%x)", port, value);
+ assert1( port == EGA_AC_INDEX_DATA || port == EGA_AC_SECRET, "Bad port %x", port);
+ new.value = value;
+ if ( in_index_state() ) {
+ note_entrance1("Setting index to %d", value);
+ attribute_controller.address.as.abyte = value;
+ } else {
+ switch (attribute_controller.address.as_bfld.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:
+ case 14:
+ case 15:
+/*
+ * A real EGA monitor behaves in a strange way:
+ * When it is in 200 scan line mode (vertical_retrace_polarity = 0)
+ * it emulates a CGA monitor - not just in screen resolution, but also
+ * in the way it inteprets the colour signals:
+ * Instead of having 6 colour signals: RGBrgb,
+ * it has 4, RGBI. The Intensity signal is on the same input pin as the secondary green signal.
+ */
+ note_entrance1("Change palette %d",attribute_controller.address.as_bfld.index);
+ attribute_controller.palette[attribute_controller.address.as_bfld.index].as.abyte = value;
+ if(miscellaneous_output_register.as_bfld.vertical_retrace_polarity)
+ {
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].red =
+ get_palette_color(red,secondary_red);
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].green =
+ get_palette_color(green,secondary_green);
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].blue =
+ get_palette_color(blue,secondary_blue);
+ }
+ else
+ {
+ /* Interpret secondary_green as intensity */
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].red =
+ get_palette_color(red,secondary_green);
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].green =
+ get_palette_color(green,secondary_green);
+ EGA_GRAPH.palette[attribute_controller.address.as_bfld.index].blue =
+ get_palette_color(blue,secondary_green);
+ }
+ host_set_palette(EGA_GRAPH.palette,EGA_PALETTE_SIZE);
+ break;
+ case 16:
+ note_entrance0("mode control reg");
+ if (attribute_controller.mode_control.as_bfld.background_intensity_or_blink !=
+ ((AC_MODE_CONTROL*)&new)->as_bfld.background_intensity_or_blink)
+ {
+ set_intensity( ((AC_MODE_CONTROL*)&new)->as_bfld.background_intensity_or_blink );
+ }
+
+ attribute_controller.mode_control.as.abyte = value;
+
+ if (attribute_controller.mode_control.as_bfld.background_intensity_or_blink)
+ /* blinking - not supported */
+ bg_col_mask = 0x70;
+ else
+ /* using blink bit to provide 16 background colours */
+ bg_col_mask = 0xf0;
+
+ /*
+ ** Vote on alpha/graphics mode
+ */
+ vote_ega_mode();
+ assert0(attribute_controller.mode_control.as_bfld.display_type == 0, "Mono display selected");
+ assert0(attribute_controller.mode_control.as_bfld.enable_line_graphics_char_codes == 0,
+ "line graphics enabled");
+ break;
+ case 17:
+ note_entrance0("set border");
+ attribute_controller.overscan_color.as.abyte = value;
+ EGA_GRAPH.border[RED] = get_border_color(red_border,secondary_red_border);
+ EGA_GRAPH.border[GREEN] = get_border_color(green_border,secondary_green_border);
+ EGA_GRAPH.border[BLUE] = get_border_color(blue_border,secondary_blue_border);
+ host_set_border_colour(value);
+ break;
+ case 18:
+ note_entrance1("color plane enable %x",value);
+ if ( attribute_controller.color_plane_enable.as_bfld.color_plane_enable !=
+ ((COLOR_PLANE_ENABLE*)&new)->as_bfld.color_plane_enable ) {
+ set_plane_mask(((COLOR_PLANE_ENABLE*)&new)->as_bfld.color_plane_enable);
+ host_change_plane_mask(get_plane_mask()); /* Update Host palette */
+ }
+ attribute_controller.color_plane_enable.as.abyte = value;
+ break;
+ case 19:
+ note_entrance0("horiz pel panning");
+ NON_PROD(attribute_controller.horizontal_pel_panning.as.abyte = value);
+ break;
+ default:
+ assert1(NO,"Bad ac index %d", attribute_controller.address.as_bfld.index);
+ break;
+ }
+ }
+}
+
+LOCAL void ega_misc_outb IFN2(io_addr, port, half_word, value)
+{
+MISC_OUTPUT_REG new;
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance2("ega_misc_outb(%x,%x)", port, value);
+ assert1(port==EGA_MISC_REG,"Bad port %x",port);
+ new.as.abyte = value;
+ if (miscellaneous_output_register.as_bfld.enable_ram != new.as_bfld.enable_ram)
+ {
+ /*
+ * writes to plane memory en/disabled
+ */
+
+ note_entrance0("Ram enabled");
+ if(new.as_bfld.enable_ram)
+ sas_connect_memory(gvi_pc_low_regen,gvi_pc_high_regen,(half_word)SAS_VIDEO);
+ else
+ sas_disconnect_memory(gvi_pc_low_regen,gvi_pc_high_regen);
+
+ EGA_CPU.ram_enabled = new.as_bfld.enable_ram;
+ ega_read_routines_update();
+ ega_write_routines_update(RAM_ENABLED);
+ }
+
+ if (miscellaneous_output_register.as_bfld.vertical_retrace_polarity !=
+ new.as_bfld.vertical_retrace_polarity)
+ {
+ /*
+ * Going to/from CGA monitor compatibility mode
+ * if this bit is set, it means that the pixels are 'stretched' vertically.
+ */
+
+ set_pc_pix_height( new.as_bfld.vertical_retrace_polarity ? 1 : 2);
+ flag_mode_change_required();
+ }
+
+ miscellaneous_output_register.as.abyte = new.as.abyte;
+
+ set_bit_display_disabled(miscellaneous_output_register.as_bfld.disable_internal_video_drivers ? VIDEO_DRIVERS_DISABLED : 0);
+
+ /*
+ * register value used by ipsr0 to find out the index into the switches
+ * so that correct switch setting can be returned.
+ */
+}
+
+LOCAL void ega_feat_outb IFN2(io_addr, port, half_word, value)
+{
+#ifdef PROD
+ UNUSED(port);
+ UNUSED(value);
+#endif
+ note_entrance2("ega_feat_outb(%x,%x)", port, value);
+ NON_PROD(feature_control_register.as.abyte = value);
+}
+
+LOCAL void ega_ipstat0_inb IFN2(io_addr, port, half_word *, value)
+{
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance1("ega_ipstat0_inb(%x)", port);
+ input_status_register_zero.as_bfld.switch_sense =
+
+ /* The following function call used to pass the argument
+ ** miscellaneous_output_register.as_bfld.clock_select
+ ** but the function expects no argument so it was removed.
+ */
+ get_ega_switch_setting();
+ *value = input_status_register_zero.as.abyte;
+ note_entrance1("returning %x",*value);
+}
+
+LOCAL void ega_ipstat1_inb IFN2(io_addr, port, half_word *, value)
+{
+
+ /*
+ * The whole of this routine has been nicked from the cga without modification
+ * The s_lengths array should probably be altered for the ega timings, and somewhere
+ * an interrupt should be fired off.
+ */
+
+ static int ega_state = 0; /* current ega status state */
+ static int state_count = 1; /* position in that state */
+ static int sub_state = 0; /* sub state for ega state 2 */
+
+ static unsigned long gmfudge = 17; /* Random number seed for pseudo-random
+ bitstream generator to give the state lengths below that 'genuine' feel to
+ progs that require it! */
+ register unsigned long h;
+
+ /*
+ * relative 'lengths' of each state. State 2 is *3 as it has 3 sub states
+ */
+
+ static int s_lengths[] = { 8, 18, 8, 6 };
+
+ /*
+ * Status register, simulated adapter has
+ *
+ * bit setting
+ * --- -------
+ * Display enable 1/0 Toggling each inb
+ * Light Pen 0
+ * Light Pen 0
+ * Vertical Sync 1/0 Toggling each inb
+ * 4-7 Unused 0,0,0,0
+ *
+ * The upper nibble of the byte is always set.
+ * Some programs synchronise with the display by waiting for the
+ * next vertical retrace.
+ *
+ * We attempt to follow the following waveform
+ *
+ * -- ----------
+ * VS |_____________________________________________________| |____
+ *
+ *
+ * ------------- - - ------------------
+ * DE |__||__||__ ... about 180 _|
+ *
+ *State|--- 0 ----|-------------- 1 -----------------|-- 3 --|-- 4 --|
+ *
+ * We do this with a 4 state machine. Each state has a count associated
+ * with it to represent the relative time spent in each state. When this
+ * count is exhausted the machine moves into the next state. One Inb
+ * equals 1 count. The states are as follows:
+ * 0: VS low, DE high.
+ * 1: VS low, DE toggles. This works via an internal state.
+ * 3: VS low, DE high.
+ * 4: VS high,DE high.
+ *
+ */
+
+#ifdef PROD
+ UNUSED(port);
+#endif
+ note_entrance1("ega_ipstat1_inb(%x)", port);
+ note_entrance2("ega_ipstat1_inb(%x,%x)", port, value);
+
+ set_index_state(); /* Initialize the Attribute register flip-flop (EGA tech ref, p 56) */
+
+ state_count --; /* attempt relative 'timings' */
+ switch (ega_state) {
+
+ case 0:
+ if (state_count == 0) { /* change to next state ? */
+ h = gmfudge << 1;
+ gmfudge = (h&0x80000000) ^ (gmfudge & 0x80000000)? h|1 : h;
+ state_count = s_lengths[1] + (gmfudge & 3);
+ ega_state = 1;
+ }
+ input_status_register_zero.as_bfld.crt_interrupt = 1; /* = !VS */
+ *value = 0xf1;
+ break;
+
+ case 1:
+ if (state_count == 0) { /* change to next state ? */
+ h = gmfudge << 1;
+ gmfudge = (h&0x80000000) ^ (gmfudge & 0x80000000)? h|1 : h;
+ state_count = s_lengths[2] + (gmfudge & 3);
+ ega_state = 2;
+ sub_state = 2;
+ }
+ switch (sub_state) { /* cycle through 0,0,1 sequence */
+ case 0: /* to represent DE toggling */
+ *value = 0xf0;
+ sub_state = 1;
+ break;
+ case 1:
+ *value = 0xf0;
+ sub_state = 2;
+ break;
+ case 2:
+ *value = 0xf1;
+ sub_state = 0;
+ break;
+ }
+ input_status_register_zero.as_bfld.crt_interrupt = 1; /* = !VS */
+ break;
+
+ case 2:
+ if (state_count == 0) { /* change to next state ? */
+ h = gmfudge << 1;
+ gmfudge = (h&0x80000000) ^ (gmfudge & 0x80000000)? h|1 : h;
+ state_count = s_lengths[3] + (gmfudge & 3);
+ ega_state = 3;
+ }
+ *value = 0xf1;
+ input_status_register_zero.as_bfld.crt_interrupt = 1; /* = !VS */
+ break;
+
+ case 3:
+ if (state_count == 0) { /* wrap back to first state */
+ h = gmfudge << 1;
+ gmfudge = (h&0x80000000) ^ (gmfudge & 0x80000000)? h|1 : h;
+ state_count = s_lengths[0] + (gmfudge & 3);
+ ega_state = 0;
+ }
+ input_status_register_zero.as_bfld.crt_interrupt = 0; /* = !VS */
+ *value = 0xf9;
+ break;
+ }
+ note_entrance1("returning %x",*value);
+}
+
+LOCAL void vote_ega_mode IFN0()
+{
+ static int old_votes = 3;
+ int votes;
+
+ votes = sequencer.memory_mode.as_bfld.alpha_mode ? 0 : 1;
+ votes += graphics_controller.miscellaneous.as_bfld.graphics_mode;
+ votes += attribute_controller.mode_control.as_bfld.graphics_mode;
+ assert1( votes == 3 || votes == 0, "Headline: Mode government returned with small majority %d", votes);
+ if ((old_votes < 2) && (votes >= 2))
+ {
+ /* change to graphics mode */
+ set_text_mode(NO);
+ flag_mode_change_required();
+ }
+ else if ((old_votes >= 2) && (votes < 2))
+ {
+ /* change to text mode */
+ set_text_mode(YES);
+ flag_mode_change_required();
+ }
+ old_votes = votes;
+}
+
+#ifdef HUNTER
+
+/* Get line compare value */
+
+int ega_get_line_compare IFN0()
+
+ {
+ int return_value;
+
+ return_value = crt_controller.line_compare;
+ if (crt_controller.crtc_overflow.as_bfld.line_compare_bit_8 != 0)
+ return_value += 0x100;
+ return (return_value);
+ } /* ega_get_line_compare */
+
+/* Get maximum scan lines value */
+
+int ega_get_max_scan_lines IFN0()
+
+ {
+ return (crt_controller.maximum_scan_line.as_bfld.maximum_scan_line);
+ } /* ega_get_max_scan_lines */
+
+/* Set line compare value */
+
+void ega_set_line_compare IFN1(int, lcomp_val)
+ {
+ CRTC_OVERFLOW new_overflow;
+
+ new_overflow.as.abyte = crt_controller.crtc_overflow.as.abyte;
+ if (lcomp_val >= 0x100)
+ new_overflow.as_bfld.line_compare_bit_8 = 1;
+ else
+ new_overflow.as_bfld.line_compare_bit_8 = 0;
+
+ outb(EGA_CRTC_INDEX, 7);
+ outb(EGA_CRTC_DATA, new_overflow.as.abyte);
+ outb(EGA_CRTC_INDEX, 24);
+ outb(EGA_CRTC_DATA, lcomp_val & 0xff);
+ }
+
+#endif /* HUNTER */
+#endif /* EGG */
+#endif /* REAL_VGA */