#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 */