mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1490 lines
41 KiB
1490 lines
41 KiB
#include "insignia.h"
|
|
#include "host_def.h"
|
|
|
|
#if !defined(NTVDM) || (defined(NTVDM) && !defined(X86GFX) )
|
|
|
|
/*
|
|
* SoftPC Revision 3.0
|
|
*
|
|
* Title : IBM Colour/Graphics Adapter simulator
|
|
*
|
|
* Description : Simulates the IBM CGA.
|
|
*
|
|
* Author : Rod MacGregor / Henry Nash
|
|
*
|
|
* Notes : The earlier versions of this module could run on an ADM 3E,
|
|
* a dumb ANSI standard terminal, in debug mode or in a Sun
|
|
* Window. In the interests of sanity and as the versions other
|
|
* than the Sun were not fully developed, they were removed. if
|
|
* interested in the workings of these implementations they are
|
|
* available in the SCCS file before version 2.36.
|
|
*
|
|
* The supported functions are:
|
|
*
|
|
* cga_init Initialise the subsystem
|
|
* cga_term Terminate the subsystem
|
|
* cga_inb I/P a byte from the MC6845 chip
|
|
* cga_outb O/P a byte to the MC6845 chip
|
|
*
|
|
* In the new EGA world, we use screen start instead of screen base.
|
|
* This is also a WORD address if the adapter is in text mode.
|
|
* (Thats how the EGA works!)
|
|
* So we don't have to double it now. Ho Hum.
|
|
*
|
|
* Mods: (r2.71): In the real 6845 chip, the pointer which addresses the
|
|
* base of the screen is a WORD ptr. We've just discovered
|
|
* this; all usage of the variable 'screen_base' assumes
|
|
* that it is a BYTE ptr. Hence in cga_outb() we now
|
|
* double the value in screen_base when it is set.
|
|
*
|
|
* (r3.2) : (SCR 258). cur_offset now declared as static.
|
|
*
|
|
* (r3.3) : (SCR 257). Set timer_video_enabled when the bit in
|
|
* the M6845 mode register which controls the video
|
|
* display is changed. Also neatened the indentation
|
|
* for outb().
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* static char SccsID[]="@(#)cga.c 1.36 05/05/95 Copyright Insignia Solutions Ltd.";
|
|
*/
|
|
|
|
#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_CGA.seg"
|
|
#endif
|
|
|
|
/*
|
|
* O/S include files.
|
|
*/
|
|
#include <stdio.h>
|
|
#include TypesH
|
|
#include StringH
|
|
#include FCntlH
|
|
|
|
/*
|
|
* SoftPC include files
|
|
*/
|
|
#include "xt.h"
|
|
#include "timeval.h"
|
|
#include "timer.h"
|
|
#include CpuH
|
|
#include "ios.h"
|
|
#include "gmi.h"
|
|
#include "gfx_upd.h"
|
|
#include "gvi.h"
|
|
#include "sas.h"
|
|
#include "cga.h"
|
|
#include "error.h"
|
|
#include "config.h"
|
|
#include "host.h"
|
|
#include "trace.h"
|
|
#include "debug.h"
|
|
#include "cpu_vid.h"
|
|
#ifdef EGG
|
|
#include "egacpu.h"
|
|
#endif /* EGG */
|
|
#include "video.h"
|
|
#include "ckmalloc.h"
|
|
|
|
#ifdef REAL_VGA
|
|
#include "avm361.h"
|
|
#else
|
|
#include "host_gfx.h"
|
|
#endif
|
|
|
|
|
|
/*
|
|
*============================================================================
|
|
* Local Defines, Macros & Declarations
|
|
*============================================================================
|
|
*/
|
|
|
|
#define CURSOR_NON_DISPLAY_BIT (1 << 5)
|
|
/* Bit in Cursor Start Register which
|
|
makes the cursor invisible */
|
|
#define CURSOR_USED_BITS 0x1f
|
|
/* Mask to clear out unused bits */
|
|
|
|
static int current_mode = -1; /* Value of Mode Select at last call */
|
|
|
|
/*
|
|
* MC6845 Registers
|
|
*/
|
|
|
|
#ifdef HUNTER
|
|
half_word MC6845[MC6845_REGS]; /* The current values of the MC6845 registers */
|
|
half_word mode_reg; /* The value of the mode control register */
|
|
#endif
|
|
|
|
static half_word index_reg = 00 ; /* Index register */
|
|
|
|
/*
|
|
* 6845 Register variables
|
|
*/
|
|
static half_word R0_horizontal_total;
|
|
static half_word R1_horizontal_displayed = 80;
|
|
static half_word R2_horizontal_sync_pos;
|
|
static half_word R3_horizontal_sync_width;
|
|
static half_word R4_vertical_total;
|
|
static half_word R5_vertical_total_adjust;
|
|
static half_word R6_vertical_displayed = 25;
|
|
static half_word R7_vertical_sync;
|
|
static half_word R9_max_scan_line_addr = 7;
|
|
static half_word R8_interlace;
|
|
static half_word Ra_cursor_start = 0;
|
|
static half_word Rb_cursor_end = 0;
|
|
static half_word Re_cursor_loc_high = 0;
|
|
static half_word Rf_cursor_loc_low = 0;
|
|
|
|
/*
|
|
* global variables peculiar to the cga
|
|
*/
|
|
|
|
CGA_GLOBS CGA_GLOBALS;
|
|
|
|
GLOBAL VOID (*bios_ch2_byte_wrt_fn)();
|
|
GLOBAL VOID (*bios_ch2_word_wrt_fn)();
|
|
|
|
GLOBAL IU8 *cga_screen_buf = 0;
|
|
|
|
/*
|
|
* Globals used in various functions to synchronise the display
|
|
*/
|
|
|
|
int cursor_over_screen = FALSE; /* When set to TRUE the cursor is over the */
|
|
/* screen areas and the cursor should flash */
|
|
|
|
/*
|
|
* Static forward declarations.
|
|
*/
|
|
|
|
static void set_cga_palette IPT2(int, screen_mode, int, res);
|
|
static void update_cursor_shape IPT0();
|
|
|
|
|
|
#ifdef A3CPU
|
|
IMPORT WRT_POINTERS Glue_writes;
|
|
#else
|
|
IMPORT MEM_HANDLERS Glue_writes;
|
|
#endif /* A3CPU */
|
|
IMPORT WRT_POINTERS simple_writes;
|
|
IMPORT READ_POINTERS Glue_reads;
|
|
IMPORT READ_POINTERS read_glue_ptrs;
|
|
IMPORT READ_POINTERS simple_reads;
|
|
|
|
#ifdef A2CPU
|
|
LOCAL ULONG dummy_read IFN1(ULONG, offset)
|
|
{
|
|
UNUSED(offset);
|
|
return 0;
|
|
}
|
|
|
|
LOCAL void dummy_str_read IFN3(UTINY *, dest, ULONG, offset, ULONG, count)
|
|
{
|
|
UNUSED(dest);
|
|
UNUSED(offset);
|
|
UNUSED(count);
|
|
}
|
|
|
|
LOCAL READ_POINTERS dummy_reads =
|
|
{
|
|
dummy_read,
|
|
dummy_read
|
|
#ifndef NO_STRING_OPERATIONS
|
|
,
|
|
dummy_str_read
|
|
#endif /* NO_STRING_OPERATIONS */
|
|
};
|
|
#endif /* A2CPU */
|
|
|
|
/*
|
|
*==========================================================================
|
|
* Global Functions
|
|
*==========================================================================
|
|
*/
|
|
|
|
/*
|
|
********** Functions that operate on the I/O Address Space ********************
|
|
*/
|
|
|
|
/*
|
|
* Global variables
|
|
*/
|
|
|
|
half_word bg_col_mask = 0x70;
|
|
reg regen_start; /* Regen start address */
|
|
|
|
void cga_inb IFN2(io_addr, address, half_word *, value)
|
|
{
|
|
|
|
static int cga_state = 0; /* current cga status state */
|
|
static long state_count = 1; /* position in that state */
|
|
static int sub_state = 0; /* sub state for cga state 2 */
|
|
static unsigned long gmfudge = 17; /* Random number seed for pseudo-random
|
|
bitstream generator to give the state
|
|
lengths below that 'genuine' hardware
|
|
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 };
|
|
|
|
/*
|
|
* Read from MC6845 Register
|
|
*/
|
|
|
|
if ( address == 0x3DA ) {
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
state_count --; /* attempt relative 'timings' */
|
|
switch (cga_state) {
|
|
|
|
case 0:
|
|
if (state_count == 0) { /* change to next state ? */
|
|
h = gmfudge << 1;
|
|
gmfudge = (h&0x80000000L) ^ (gmfudge & 0x80000000L)? h|1 : h;
|
|
state_count = s_lengths[1] + (gmfudge & 3);
|
|
cga_state = 1;
|
|
}
|
|
*value = 0xf1;
|
|
break;
|
|
|
|
case 1:
|
|
if (state_count == 0) { /* change to next state ? */
|
|
h = gmfudge << 1;
|
|
gmfudge = (h&0x80000000L) ^ (gmfudge & 0x80000000L)? h|1 : h;
|
|
state_count = s_lengths[2] + (gmfudge & 3);
|
|
cga_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;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (state_count == 0) { /* change to next state ? */
|
|
h = gmfudge << 1;
|
|
gmfudge = (h&0x80000000L) ^ (gmfudge & 0x80000000L)? h|1 : h;
|
|
state_count = s_lengths[3] + (gmfudge & 3);
|
|
cga_state = 3;
|
|
}
|
|
*value = 0xf1;
|
|
break;
|
|
|
|
case 3:
|
|
if (state_count == 0) { /* wrap back to first state */
|
|
h = gmfudge << 1;
|
|
gmfudge = (h&0x80000000L) ^ (gmfudge & 0x80000000L)? h|1 : h;
|
|
state_count = s_lengths[0] + (gmfudge & 3);
|
|
cga_state = 0;
|
|
}
|
|
*value = 0xf9;
|
|
break;
|
|
}
|
|
}
|
|
else if ( (address & 0xFFF9) == 0x3D1)
|
|
{
|
|
|
|
/*
|
|
* Internal data register, the only supported internal
|
|
* registers are E and F the cursor address registers.
|
|
*/
|
|
|
|
switch (index_reg) {
|
|
|
|
case 0xE:
|
|
*value = (get_cur_y() * get_chars_per_line() + get_cur_x() ) >> 8;
|
|
break;
|
|
case 0xF:
|
|
*value = (get_cur_y() * get_chars_per_line() + get_cur_x()) & 0xff;
|
|
break;
|
|
case 0x10: case 0x11:
|
|
*value = 0;
|
|
break;
|
|
default:
|
|
note_trace1(CGA_VERBOSE,
|
|
"Read from unsupported MC6845 internal reg %x",
|
|
index_reg);
|
|
}
|
|
}
|
|
else
|
|
/*
|
|
* Read from a write only register
|
|
*/
|
|
|
|
*value = 0x00;
|
|
}
|
|
|
|
|
|
void cga_outb IFN2(io_addr, address, half_word, value)
|
|
{
|
|
|
|
/*
|
|
* Output to a 6845 register
|
|
*/
|
|
|
|
word cur_offset; /* The cursor position registers */
|
|
static half_word last_mode = -1;
|
|
static half_word last_screen_length = 25;
|
|
static half_word video_mode;
|
|
/*
|
|
* Variable used to see if text character height has changed, so that
|
|
* unnecessary calls to host_change_mode can be avoided.
|
|
*/
|
|
static half_word last_max_scan_line = 7;
|
|
|
|
/*
|
|
* Masks for testing the input byte. The MODE_MASK hides the (unsupported)
|
|
* blink bit and the video enable bit to ascertain whether any mode specific
|
|
* variables need to be changed. The BLINK_MASK hides the blink bit for storing
|
|
* the current_mode between changes.
|
|
*/
|
|
|
|
#define RESET 0x00
|
|
#define ALPHA_80x25 0x01
|
|
#define GRAPH 0x02
|
|
#define BW_ENABLE 0x04
|
|
#define GRAPH_640x200 0x10
|
|
#define MODE_MASK 0x17
|
|
#define BLINK_MASK 0x1F
|
|
#define COLOR_MASK 0x3F
|
|
|
|
note_trace2(CGA_VERBOSE, "cga_outb: port %x value %x", address, value);
|
|
|
|
switch (address) {
|
|
case 0x3D0:
|
|
case 0x3D2:
|
|
case 0x3D4:
|
|
case 0x3D6:
|
|
|
|
/*
|
|
* Index Register
|
|
*/
|
|
index_reg = value;
|
|
break;
|
|
|
|
case 0x3D1:
|
|
case 0x3D3:
|
|
case 0x3D5:
|
|
case 0x3D7:
|
|
#ifdef HUNTER
|
|
MC6845[index_reg] = value;
|
|
#endif
|
|
|
|
/*
|
|
* This is the data register, the function to be performed depends on the
|
|
* value in the index register
|
|
*
|
|
* The various registers affect the position and size of the screen and the
|
|
* image on it. The screen can be logically divided into two halves: the
|
|
* displayed text and the rest which is the border. The border colour can
|
|
* be changed by programming the 3D9 register.
|
|
* NB. Currently SoftPC does not obey positioning & display sizing
|
|
* information - the display remains constant.
|
|
* The first 8 registers (R0-R7) affect the size & position of the display;
|
|
* their effects are as follows:
|
|
* R0 - R3 control the horizontal display aspects & R4 - R7 the vertical.
|
|
*
|
|
* The diagram below attempts to show how each is related to the screen
|
|
* size & shape.
|
|
*
|
|
* (Shaded Area - border)
|
|
* ________________________________________________________ <-------------
|
|
* |......................................................| | | R5 |
|
|
* |..|-----------------------------------------------|...| | <---- |
|
|
* |..| |...| | | |
|
|
* |..|c> |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| R R R
|
|
* |..| |...| 4 6 7
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..| |...| | | |
|
|
* |..|_______________________________________________|...| | <-------
|
|
* |......................................................| |
|
|
* -------------------------------------------------------- <------------
|
|
* ^ ^
|
|
* |-----------------------R0-----------------------------|
|
|
* | ^ |
|
|
* |R3| |
|
|
* | | ^ |
|
|
* | |--------------------R1--------------------------|
|
|
* | |
|
|
* |-----------------------R2--------------------------|
|
|
*
|
|
* The reason for having 4 registers to handle the full range of values
|
|
* is because they are actually used to control the horizontal & vertical
|
|
* traces on the screen hence:
|
|
* R0 - total time of scan
|
|
* R1 - active display - scan on
|
|
* R2 - time sync for scan off/on/off
|
|
* R3 - time to scan on
|
|
*
|
|
* R1
|
|
* -------------------------------------------------
|
|
* | |
|
|
* | |
|
|
* R3 | |
|
|
* ---- ---
|
|
* <---------------------R2-------------------------->
|
|
* <---------------------R0----------------------------->
|
|
*
|
|
* The veritcal registers organise an analagous trace. The two traces are
|
|
* synchronised by Register 8.
|
|
*
|
|
* This is why altering these values on the PC will move the display or
|
|
* more likely cause garbaging of the image!
|
|
*/
|
|
|
|
switch ( index_reg ) {
|
|
case 0x00:
|
|
/*
|
|
* total horizontal display (inc border)
|
|
*/
|
|
R0_horizontal_total = value;
|
|
break;
|
|
|
|
case 0x01:
|
|
/*
|
|
* Specify the number of characters per row
|
|
*/
|
|
if (value > 80) {
|
|
always_trace1("cga_outb: trying to set width %d", value);
|
|
value = 80;
|
|
}
|
|
R1_horizontal_displayed = value;
|
|
set_horiz_total(value);
|
|
break;
|
|
|
|
case 0x02:
|
|
/*
|
|
* Right hand edge of displayed text
|
|
* affect left_border(?), right_border(?)
|
|
*/
|
|
R2_horizontal_sync_pos = value;
|
|
break;
|
|
|
|
case 0x03:
|
|
/*
|
|
* Left hand edge of displayed text
|
|
* affect left_border, right_border
|
|
*/
|
|
R3_horizontal_sync_width = value;
|
|
break;
|
|
|
|
case 0x04:
|
|
/*
|
|
* total vertical display (inc border)
|
|
*/
|
|
R4_vertical_total = value;
|
|
break;
|
|
|
|
case 0x05:
|
|
/*
|
|
* Top edge of displayed text
|
|
* affect top_border, bottom_border
|
|
*/
|
|
R5_vertical_total_adjust = value;
|
|
break;
|
|
|
|
case 0x06:
|
|
/*
|
|
* If the screen length is 0, this effectively means
|
|
* don't display anything.
|
|
*/
|
|
if(value == 0)
|
|
{
|
|
host_clear_screen();
|
|
set_display_disabled(TRUE);
|
|
last_screen_length = 0;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Specify the screen length - in our
|
|
* implementation used only in text mode.
|
|
* affect top_border, bottom_border
|
|
*/
|
|
R6_vertical_displayed = value;
|
|
set_screen_length( R1_horizontal_displayed * R6_vertical_displayed * 2 );
|
|
}
|
|
/*
|
|
* check if we are resetting the screen to
|
|
* display again
|
|
*/
|
|
if((value != 0) && (last_screen_length == 0))
|
|
{
|
|
set_display_disabled(FALSE);
|
|
host_flush_screen();
|
|
last_screen_length = value;
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
case 0x07:
|
|
/*
|
|
* bottom of displayed text
|
|
* affect top_border(?), bottom_border(?)
|
|
*/
|
|
R7_vertical_sync = value;
|
|
break;
|
|
|
|
case 0x08:
|
|
/*
|
|
* interlace of traces - hold constant
|
|
*/
|
|
R8_interlace = 2;
|
|
break;
|
|
|
|
case 0x09:
|
|
/*
|
|
* Specify the character height - in our
|
|
* implementation used only in text mode.
|
|
* The actual number of pixels is one
|
|
* more than this value.
|
|
*/
|
|
R9_max_scan_line_addr = value;
|
|
set_char_height_recal(R9_max_scan_line_addr + 1);
|
|
set_screen_height_recal( R6_vertical_displayed*(R9_max_scan_line_addr+1) - 1);
|
|
flag_mode_change_required();
|
|
screen_refresh_required();
|
|
break;
|
|
|
|
/*
|
|
* A defines the cursor start scan line
|
|
* B defines the cursor stop scan line
|
|
*/
|
|
case 0x0A:
|
|
/* bypass redundant updates */
|
|
if (Ra_cursor_start != value)
|
|
{
|
|
Ra_cursor_start = value;
|
|
#ifdef REAL_VGA
|
|
CRTC_REG(0xa, value);
|
|
#endif
|
|
update_cursor_shape();
|
|
}
|
|
break;
|
|
case 0x0B:
|
|
/* bypass redundant updates */
|
|
if (Rb_cursor_end != (value & CURSOR_USED_BITS))
|
|
{
|
|
Rb_cursor_end = (value & CURSOR_USED_BITS);
|
|
#ifdef REAL_VGA
|
|
CRTC_REG(0xb, value);
|
|
#endif
|
|
update_cursor_shape();
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* C & D define the start of the regen buffer
|
|
*/
|
|
case 0x0C:
|
|
/*
|
|
* High byte
|
|
*/
|
|
if (value != regen_start.byte.high)
|
|
{
|
|
regen_start.byte.high = value;
|
|
host_screen_address_changed(regen_start.byte.high,
|
|
regen_start.byte.low);
|
|
set_screen_start(regen_start.X % (short)(CGA_REGEN_LENGTH/2) );
|
|
screen_refresh_required();
|
|
}
|
|
#ifdef REAL_VGA
|
|
CRTC_REG(0xc, value);
|
|
#endif
|
|
break;
|
|
|
|
case 0x0D:
|
|
/*
|
|
* low byte
|
|
*/
|
|
if (value != regen_start.byte.low)
|
|
{
|
|
regen_start.byte.low = value;
|
|
host_screen_address_changed(regen_start.byte.high,
|
|
regen_start.byte.low);
|
|
set_screen_start(regen_start.X % (short)(CGA_REGEN_LENGTH/2));
|
|
screen_refresh_required();
|
|
}
|
|
#ifdef REAL_VGA
|
|
CRTC_REG(0xd, value);
|
|
#endif
|
|
break;
|
|
|
|
/*
|
|
* E and F define the cursor coordinates in characters
|
|
*/
|
|
case 0x0E:
|
|
/*
|
|
* High byte
|
|
*/
|
|
if (Re_cursor_loc_high != value)
|
|
{
|
|
Re_cursor_loc_high = value;
|
|
|
|
if(get_cga_mode() == TEXT)
|
|
host_cga_cursor_has_moved(get_cur_x(), get_cur_y());
|
|
cur_offset = (value << 8) | Rf_cursor_loc_low;
|
|
cur_offset -= get_screen_start();
|
|
set_cur_y( cur_offset / get_chars_per_line() );
|
|
set_cur_x( cur_offset % get_chars_per_line() );
|
|
|
|
}
|
|
break;
|
|
|
|
case 0x0F:
|
|
/*
|
|
* low byte
|
|
*/
|
|
if (Rf_cursor_loc_low != value)
|
|
{
|
|
Rf_cursor_loc_low = value;
|
|
|
|
if(get_cga_mode() == TEXT)
|
|
host_cga_cursor_has_moved(get_cur_x(), get_cur_y());
|
|
cur_offset = (Re_cursor_loc_high << 8) | value;
|
|
cur_offset -= get_screen_start();
|
|
set_cur_y( cur_offset / get_chars_per_line());
|
|
set_cur_x( cur_offset % get_chars_per_line());
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
note_trace2(CGA_VERBOSE, "Unsupported 6845 reg %x=%x(write)",
|
|
index_reg, value);
|
|
}
|
|
break;
|
|
|
|
case 0x3D8:
|
|
/*
|
|
* Mode control register. The first
|
|
* six bits are encoded as follows:
|
|
*
|
|
* BIT Function Status
|
|
* --- -------- ------
|
|
* 0 A/N 80x25 mode Supported
|
|
* 1 Graphics Select Supported
|
|
* 2 B/W Select Supported
|
|
* 3 Enable Video Supported
|
|
* 4 640x200 B/W mode Supported
|
|
* 5 Change B/G intensity to blink Not Supported
|
|
* 6,7 Unused
|
|
*/
|
|
|
|
#ifdef HUNTER
|
|
mode_reg = value;
|
|
#endif
|
|
timer_video_enabled = (boolean) (value & VIDEO_ENABLE);
|
|
|
|
if (value != current_mode) {
|
|
|
|
if (value == RESET)
|
|
set_display_disabled(TRUE); /* Chip reset - do nothing */
|
|
else {
|
|
/*
|
|
* Take note whether color or B/W
|
|
*/
|
|
|
|
set_cga_color_select( !(value & BW_ENABLE) );
|
|
|
|
/*
|
|
* Set up for graphics or text
|
|
*/
|
|
if (value & GRAPH) {
|
|
set_chars_per_line(R1_horizontal_displayed<<1);
|
|
set_cursor_visible(FALSE);
|
|
set_cga_mode(GRAPHICS);
|
|
host_set_border_colour(0);
|
|
set_word_addressing(FALSE); /* bytes per line = chars per line */
|
|
set_cga_resolution( (value & GRAPH_640x200 ? HIGH : MEDIUM) );
|
|
if (get_cga_resolution() == HIGH) {
|
|
video_mode = 6;
|
|
set_pix_width(1);
|
|
}
|
|
else {
|
|
video_mode = (get_cga_color_select() ? 4 : 5);
|
|
set_pix_width(2);
|
|
}
|
|
if (video_mode != last_mode)
|
|
{
|
|
host_change_mode();
|
|
set_cga_palette(get_cga_mode(),get_cga_resolution());
|
|
}
|
|
}
|
|
else { /* Text, presumably */
|
|
set_chars_per_line(R1_horizontal_displayed);
|
|
set_cga_mode(TEXT);
|
|
set_cursor_visible(TRUE);
|
|
set_word_addressing_recal(TRUE); /* so that bytes per line is twice chars per line */
|
|
|
|
if (value & 0x20)
|
|
/* blinking - not supported */
|
|
bg_col_mask = 0x70;
|
|
else
|
|
/* using blink bit to provide 16 background colours */
|
|
bg_col_mask = 0xf0;
|
|
|
|
if (value & ALPHA_80x25)
|
|
{
|
|
video_mode = (get_cga_color_select() ? 3 : 2);
|
|
set_pix_width(1);
|
|
set_pix_char_width(8);
|
|
}
|
|
else
|
|
{
|
|
video_mode = (get_cga_color_select() ? 1 : 0);
|
|
set_pix_width(2);
|
|
set_pix_char_width(16);
|
|
}
|
|
|
|
|
|
/*
|
|
* Avoid mode changes with disabled screen.
|
|
*
|
|
* Text mode changes are also needed if the character height changes. The
|
|
* character height is set here rather than when that register is set. This
|
|
* avoids unnecessary mode changes, as the character height is set before we
|
|
* know if a graphics or text mode is to be entered.
|
|
*/
|
|
if ( (value & VIDEO_ENABLE) && ((video_mode != last_mode) ||
|
|
(last_max_scan_line != R9_max_scan_line_addr)))
|
|
{
|
|
last_max_scan_line = R9_max_scan_line_addr;
|
|
host_change_mode(); /* redo fonts etc */
|
|
set_cga_palette(get_cga_mode(),get_cga_resolution());
|
|
}
|
|
}
|
|
set_bytes_per_line(R1_horizontal_displayed<<1);
|
|
set_offset_per_line(get_bytes_per_line());
|
|
|
|
if (video_mode != last_mode) {
|
|
if (value & VIDEO_ENABLE) {
|
|
set_display_disabled(FALSE);
|
|
screen_refresh_required();
|
|
last_mode = video_mode; /* Do this here so when screen display is re-enabled we do 'pending' mode change */
|
|
}
|
|
else
|
|
set_display_disabled(TRUE);
|
|
}
|
|
else if ((value & VIDEO_ENABLE)
|
|
!= (current_mode & VIDEO_ENABLE)) {
|
|
if (value & VIDEO_ENABLE) {
|
|
set_display_disabled(FALSE);
|
|
host_flush_screen();
|
|
}
|
|
else
|
|
set_display_disabled(TRUE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
current_mode = value;
|
|
break;
|
|
|
|
case 0x3D9:
|
|
/*
|
|
* The Color Select Register. Just save this into a
|
|
* variable so the machine-specific graphics s/w can
|
|
* see it, then call a host specific routine to act on it.
|
|
*/
|
|
|
|
if ((value & COLOR_MASK) != get_cga_colormask() ) {
|
|
set_cga_colormask(value & COLOR_MASK);
|
|
set_cga_palette(get_cga_mode(),get_cga_resolution());
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Write to an unsupported 6845 internal register
|
|
*/
|
|
|
|
note_trace2(CGA_VERBOSE, "Write to unsupported 6845 reg %x=%x",
|
|
address,value);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Set up the host palette & border for the current CGA screen mode and resolution
|
|
*/
|
|
|
|
static void set_cga_palette IFN2(int, screen_mode, int, res)
|
|
{
|
|
/*
|
|
* palette for color text - 16 colors for FG and BG
|
|
* These tables are also used to set some graphic mode palette entries
|
|
* since they represent a 'standard' set of colors.
|
|
*/
|
|
|
|
static PC_palette cga_text_palette[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Black */
|
|
0x22, 0x22, 0xBB, /* Blue */
|
|
0x00, 0xAA, 0x00, /* Green */
|
|
0x00, 0xAA, 0xAA, /* Cyan */
|
|
0xAA, 0x00, 0x00, /* Red */
|
|
0xAA, 0x00, 0xAA, /* Magenta */
|
|
0xAA, 0x88, 0x00, /* Brown */
|
|
0xCC, 0xCC, 0xCC, /* White */
|
|
0x55, 0x55, 0x55, /* Grey */
|
|
0x22, 0x22, 0xEE, /* Light Blue */
|
|
0x00, 0xEE, 0x00, /* Light Green */
|
|
0x00, 0xEE, 0xEE, /* Light Cyan */
|
|
0xEE, 0x00, 0x00, /* Light Red */
|
|
0xEE, 0x00, 0xEE, /* Light Magenta*/
|
|
0xEE, 0xEE, 0x00, /* Yellow */
|
|
0xFF, 0xFF, 0xFF /* Bright White */
|
|
};
|
|
|
|
|
|
/*
|
|
* NOTE: The medium resolution graphics colors below have their first
|
|
* and second indices reversed, due to a "feature" in the supplied
|
|
* graphics system library routines. We are trying to persuade IBM
|
|
* to change the spec of the CGA accordingly.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Medium resolution graphics, color set 1 (Green, Red, Brown)
|
|
*/
|
|
|
|
static PC_palette cga_graph_m1l[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xAA, 0x00, /* Green */
|
|
0xAA, 0x00, 0x00, /* Red */
|
|
0xAA, 0x88, 0x00 /* Brown */
|
|
};
|
|
|
|
/*
|
|
* As above but with high intensity bit on
|
|
*/
|
|
|
|
static PC_palette cga_graph_m1h[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xEE, 0x00, /* Green (alt Red) */
|
|
0xEE, 0x00, 0x00, /* Red (alt Green) */
|
|
0xEE, 0xEE, 0x00 /* Yellow */
|
|
};
|
|
|
|
/*
|
|
* Medium resolution graphics, color set 2 (Cyan, Magenta, White)
|
|
*/
|
|
|
|
static PC_palette cga_graph_m2l[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xAA, 0xAA, /* Magenta (alt Cyan) */
|
|
0xAA, 0x00, 0xAA, /* Cyan (alt Magenta) */
|
|
0xCC, 0xCC, 0xCC /* White */
|
|
};
|
|
|
|
|
|
/*
|
|
* As above but with high intensity bit on
|
|
*/
|
|
|
|
static PC_palette cga_graph_m2h[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xEE, 0xEE, /* Magenta (alt Cyan) */
|
|
0xEE, 0x00, 0xEE, /* Cyan (alt Magenta) */
|
|
0xFF, 0xFF, 0xFF /* White */
|
|
};
|
|
|
|
/*
|
|
* Medium resolution graphics, color set 3 (Cyan, Red, White)
|
|
* This is what you get when the "Black & White" bit is on!!!
|
|
*/
|
|
|
|
static PC_palette cga_graph_m3l[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xAA, 0xAA, /* Cyan (alt Red) */
|
|
0xAA, 0x00, 0x00, /* Red (alt Cyan) */
|
|
0xCC, 0xCC, 0xCC /* White */
|
|
};
|
|
|
|
/*
|
|
* As above but with high intensity on
|
|
*/
|
|
|
|
static PC_palette cga_graph_m3h[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Set dynamically */
|
|
0x00, 0xEE, 0xEE, /* Cyan (alt Red) */
|
|
0xEE, 0x00, 0x00, /* Red (alt Cyan) */
|
|
0xFF, 0xFF, 0xFF /* White */
|
|
};
|
|
|
|
|
|
/*
|
|
* High resolution graphics
|
|
*/
|
|
|
|
static PC_palette cga_graph_high[] =
|
|
{
|
|
0x00, 0x00, 0x00, /* Black */
|
|
0x00, 0x00, 0x00 /* Set dynamically */
|
|
};
|
|
|
|
|
|
/*
|
|
* Local variables
|
|
*/
|
|
|
|
PC_palette *cga_graph_med;
|
|
int ind;
|
|
|
|
/*
|
|
* If the mode is TEXT use cga_text_palette
|
|
*/
|
|
|
|
if (screen_mode == TEXT)
|
|
{
|
|
host_set_palette(cga_text_palette, 16);
|
|
host_set_border_colour(get_cga_colormask() &0xf);
|
|
}
|
|
|
|
else /* Mode must be GRAPHICS */
|
|
if (res == MEDIUM)
|
|
{
|
|
/*
|
|
* Select the appropriate slot array, then fill in the background.
|
|
*
|
|
* Note: 1) On a CGA driving an IBM Color Monitor, the intensity
|
|
* of these three colors (but NOT the background color)
|
|
* is affected by bit 4 of the Color Register.
|
|
*
|
|
* 2) The documentation says that bit 5 of the Color
|
|
* register selects one of two color sets. On a CGA
|
|
* driving an IBM Color Monitor, this is true UNLESS
|
|
* the B/W Enable bit in the Mode Set register is on,
|
|
* in which case you get a third set unaffected by
|
|
* bit 5 of the Color Register.
|
|
*/
|
|
|
|
if (!get_cga_color_select() ) /* Set 3 */
|
|
if (get_cga_colormask() & 0x10) /* High */
|
|
cga_graph_med = cga_graph_m3h;
|
|
else /* Low */
|
|
cga_graph_med = cga_graph_m3l;
|
|
else
|
|
if (get_cga_colormask() & 0x20) /* Set 2 */
|
|
if (get_cga_colormask() & 0x10) /* High */
|
|
cga_graph_med = cga_graph_m2h;
|
|
else /* Low */
|
|
cga_graph_med = cga_graph_m2l;
|
|
else /* Set 1 */
|
|
if (get_cga_colormask() & 0x10) /* High */
|
|
cga_graph_med = cga_graph_m1h;
|
|
else /* Low */
|
|
cga_graph_med = cga_graph_m1l;
|
|
|
|
/*
|
|
* Load the background color from the TEXT palette
|
|
*/
|
|
|
|
ind = get_cga_colormask() & 15; /* Lower 4 bits select color */
|
|
cga_graph_med->red = cga_text_palette[ind].red;
|
|
cga_graph_med->green = cga_text_palette[ind].green;
|
|
cga_graph_med->blue = cga_text_palette[ind].blue;
|
|
|
|
/*
|
|
* Load it
|
|
*/
|
|
host_set_palette(cga_graph_med,4);
|
|
|
|
}
|
|
else /* Must be high resolution graphics */
|
|
{
|
|
/*
|
|
* The background is BLACK, and the foreground is selected
|
|
* from the lower 4 bits of the Color Register
|
|
*/
|
|
|
|
ind = (get_cga_colormask() & 15);
|
|
cga_graph_high[1].red = cga_text_palette[ind].red;
|
|
cga_graph_high[1].green = cga_text_palette[ind].green;
|
|
cga_graph_high[1].blue = cga_text_palette[ind].blue;
|
|
|
|
host_set_palette(cga_graph_high,2);
|
|
}
|
|
}
|
|
|
|
static void update_cursor_shape IFN0()
|
|
{
|
|
/*
|
|
* This function actions a change to the cursor shape
|
|
* when either the cursor start or cursor end registers
|
|
* are updated with DIFFERENT values.
|
|
*/
|
|
half_word temp_start;
|
|
|
|
|
|
set_cursor_height1(0);
|
|
set_cursor_start1(0);
|
|
|
|
if ( (Ra_cursor_start & CURSOR_NON_DISPLAY_BIT)
|
|
|| ( Ra_cursor_start > CGA_CURS_START)) {
|
|
/*
|
|
* Either of these conditions causes the
|
|
* cursor to disappear on the real PC
|
|
*/
|
|
set_cursor_height(0);
|
|
set_cursor_visible(FALSE);
|
|
}
|
|
else {
|
|
temp_start = Ra_cursor_start & CURSOR_USED_BITS;
|
|
set_cursor_visible(TRUE);
|
|
if (Rb_cursor_end > CGA_CURS_START) { /* block */
|
|
set_cursor_height(CGA_CURS_START);
|
|
set_cursor_start(0);
|
|
}
|
|
else if (temp_start <= Rb_cursor_end) { /* 'normal' */
|
|
set_cursor_start(temp_start);
|
|
set_cursor_height(Rb_cursor_end - temp_start + 1);
|
|
}
|
|
else { /* wrap */
|
|
set_cursor_start(0);
|
|
set_cursor_height(Rb_cursor_end);
|
|
set_cursor_start1(temp_start);
|
|
set_cursor_height1(get_char_height() - temp_start);
|
|
}
|
|
}
|
|
base_cursor_shape_changed();
|
|
|
|
|
|
host_cursor_size_changed(Ra_cursor_start, Rb_cursor_end);
|
|
|
|
}
|
|
|
|
#if !defined(EGG) && !defined(A3CPU) && !defined(A2CPU) && !defined(C_VID) && !defined(A_VID)
|
|
|
|
/*
|
|
The following functions are MEM_HANDLER functions for the CGA-only
|
|
build with no C_VID (no a common build). They are unused for most
|
|
variants of SoftPC.
|
|
*/
|
|
|
|
#define INTEL_SRC 0
|
|
#define HOST_SRC 1
|
|
|
|
/*
|
|
======================== cga_only_simple_handler =========================
|
|
PURPOSE: This function provides a stub for the unused MEM_HANDLER
|
|
functions. This function probably shouldn't be called hence
|
|
the trace statement.
|
|
INPUT: None.
|
|
OUTPUT: None.
|
|
==========================================================================
|
|
*/
|
|
LOCAL void cga_only_simple_handler IFN0()
|
|
{
|
|
always_trace0("cga_only_simple_handler called");
|
|
setVideodirty_total(getVideodirty_total() + 1);
|
|
}
|
|
|
|
/*
|
|
=========================== cga_only_b_write =============================
|
|
PURPOSE: Byte write function. Puts the value at the given address
|
|
and increments dirty_flag.
|
|
INPUT: Address (in terms of M) and value to put there.
|
|
OUTPUT: None.
|
|
==========================================================================
|
|
*/
|
|
LOCAL void cga_only_b_write IFN2(UTINY *, addr, ULONG, val)
|
|
{
|
|
host_addr ptr;
|
|
ULONG offs;
|
|
|
|
offs = (ULONG) (addr - gvi_pc_low_regen);
|
|
ptr = get_screen_ptr(offs);
|
|
*ptr = val & 0xff;
|
|
setVideodirty_total(getVideodirty_total() + 1);
|
|
}
|
|
|
|
/*
|
|
=========================== cga_only_w_write =============================
|
|
PURPOSE: Word write function. Puts the value at the given address
|
|
and increments dirty_flag.
|
|
INPUT: Address (in terms of M) and value to put there.
|
|
OUTPUT: None.
|
|
==========================================================================
|
|
*/
|
|
LOCAL void cga_only_w_write IFN2(UTINY *, addr, ULONG, val)
|
|
{
|
|
host_addr ptr;
|
|
ULONG offs;
|
|
|
|
offs = (ULONG) (addr - gvi_pc_low_regen);
|
|
ptr = get_screen_ptr(offs);
|
|
*ptr++ = val & 0xff;
|
|
*ptr = (val >> 8) & 0xff;
|
|
setVideodirty_total(getVideodirty_total() + 2);
|
|
}
|
|
|
|
/*
|
|
=========================== cga_only_b_fill ==============================
|
|
PURPOSE: Byte fill function. Fills the given address range with the
|
|
value and increments dirty_flag.
|
|
INPUT: Address range (in terms of M) and value to put there.
|
|
OUTPUT: None.
|
|
==========================================================================
|
|
*/
|
|
LOCAL void cga_only_b_fill IFN3(UTINY *, laddr, UTINY *, haddr, ULONG, val )
|
|
{
|
|
host_addr ptr;
|
|
IS32 len;
|
|
ULONG offs;
|
|
|
|
offs = (ULONG) (laddr - gvi_pc_low_regen);
|
|
ptr = get_screen_ptr(offs);
|
|
for (len = (haddr - laddr); len > 0; len--)
|
|
*ptr++ = val;
|
|
}
|
|
|
|
/*
|
|
=========================== cga_only_w_fill ==============================
|
|
PURPOSE: Word fill function. Fills the given address range with the
|
|
value and increments dirty_flag.
|
|
INPUT: Address range (in terms of M) and value to put there.
|
|
OUTPUT: None.
|
|
==========================================================================
|
|
*/
|
|
LOCAL void cga_only_w_fill IFN3(UTINY *, laddr, UTINY *, haddr, ULONG, val )
|
|
{
|
|
host_addr ptr;
|
|
IS32 len;
|
|
IU8 lo;
|
|
IU8 hi;
|
|
ULONG offs;
|
|
|
|
lo = val & 0xff;
|
|
hi = (val >> 8) & 0xff;
|
|
offs = (ULONG) (laddr - gvi_pc_low_regen);
|
|
ptr = get_screen_ptr(offs);
|
|
for (len = (haddr - laddr) >> 1; len > 0; len--)
|
|
{
|
|
*ptr++ = lo;
|
|
*ptr++ = hi;
|
|
}
|
|
}
|
|
|
|
LOCAL void cga_only_b_move IFN4(UTINY *, laddr, UTINY *, haddr, UTINY *, src,
|
|
UTINY, src_type)
|
|
{
|
|
host_addr src_ptr;
|
|
host_addr dst_ptr;
|
|
IS32 len;
|
|
ULONG offs;
|
|
BOOL move_bwds = getDF();
|
|
|
|
offs = (ULONG) (laddr - gvi_pc_low_regen);
|
|
dst_ptr = get_screen_ptr(offs);
|
|
len = haddr - laddr;
|
|
if ((src_type == HOST_SRC) || (src < (UTINY *)gvi_pc_low_regen) ||
|
|
((UTINY *)gvi_pc_high_regen < src))
|
|
{
|
|
/* Ram source */
|
|
if (src_type == INTEL_SRC)
|
|
src_ptr = get_byte_addr(src);
|
|
else
|
|
src_ptr = src;
|
|
|
|
/* Ram to video move - video is always forwards, ram
|
|
** depends on BACK_M.
|
|
*/
|
|
if (move_bwds)
|
|
{
|
|
dst_ptr += len;
|
|
#ifdef BACK_M
|
|
src_ptr -= len;
|
|
for ( ; len > 0; len--)
|
|
*(--dst_ptr) = *(++src_ptr);
|
|
#else
|
|
src_ptr += len;
|
|
for ( ; len > 0; len--)
|
|
*(--dst_ptr) = *(--src_ptr);
|
|
#endif /* BACK_M */
|
|
}
|
|
else
|
|
{
|
|
#ifdef BACK_M
|
|
for ( ; len > 0; len--)
|
|
*dst_ptr++ = *src_ptr--;
|
|
#else
|
|
memcpy(dst_ptr, src_ptr, len);
|
|
#endif /* BACK_M */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Video source */
|
|
offs = (ULONG) (src - gvi_pc_low_regen);
|
|
src_ptr = get_screen_ptr(offs);
|
|
|
|
/* Video to video move - both sets of memory are always
|
|
** forwards.
|
|
*/
|
|
if (move_bwds)
|
|
{
|
|
dst_ptr += len;
|
|
src_ptr += len;
|
|
for ( ; len > 0; len--)
|
|
*(--dst_ptr) = *(--src_ptr);
|
|
}
|
|
else
|
|
memcpy(dst_ptr, src_ptr, len);
|
|
}
|
|
}
|
|
|
|
LOCAL MEM_HANDLERS cga_only_handlers =
|
|
{
|
|
cga_only_b_write,
|
|
cga_only_w_write,
|
|
cga_only_b_fill,
|
|
cga_only_w_fill,
|
|
cga_only_b_move,
|
|
cga_only_simple_handler /* word move - not used? */
|
|
};
|
|
|
|
#endif /* not EGG or A3CPU or A2CPU or C_VID or A_VID */
|
|
|
|
#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_INIT.seg"
|
|
#endif
|
|
|
|
void cga_init()
|
|
{
|
|
IMPORT void Glue_set_vid_rd_ptrs IPT1(READ_POINTERS *, handler );
|
|
IMPORT void Glue_set_vid_wrt_ptrs IPT1(WRT_POINTERS *, handler );
|
|
|
|
io_addr i;
|
|
|
|
#ifdef HUNTER
|
|
for (i = 0; i < MC6845_REGS; i++)
|
|
MC6845[i] = 0;
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Set up the IO chip select logic for this adaptor
|
|
*/
|
|
|
|
io_define_inb(CGA_ADAPTOR, cga_inb);
|
|
io_define_outb(CGA_ADAPTOR, cga_outb);
|
|
|
|
for(i = CGA_PORT_START; i <= CGA_PORT_END; i++)
|
|
io_connect_port(i, CGA_ADAPTOR, IO_READ_WRITE);
|
|
|
|
/*
|
|
* Initialise the adapter, assume Alpha numeric 80x25 as start up state
|
|
* with active page of zero & default cursor
|
|
*/
|
|
|
|
gvi_pc_low_regen = CGA_REGEN_START;
|
|
gvi_pc_high_regen = CGA_REGEN_END;
|
|
set_cursor_start(8-CGA_CURS_HEIGHT);
|
|
set_cursor_height(CGA_CURS_HEIGHT);
|
|
set_cga_color_select(FALSE); /* B/W at switch-on */
|
|
set_cga_colormask(0); /* Will be set by BIOS */
|
|
|
|
#ifndef GISP_CPU
|
|
/* GISP CPU physically cannot perform read and/or write checks */
|
|
|
|
#ifdef JOKER
|
|
|
|
/* gmi_define_mem(SAS_VIDEO, &Glue_writes); */
|
|
Glue_set_vid_wrt_ptrs(&simple_writes);
|
|
Glue_set_vid_rd_ptrs(&simple_reads);
|
|
|
|
#else /* not JOKER */
|
|
|
|
|
|
#ifdef A3CPU
|
|
#ifdef C_VID
|
|
Cpu_set_vid_wrt_ptrs( &Glue_writes );
|
|
Cpu_set_vid_rd_ptrs( &Glue_reads );
|
|
Glue_set_vid_wrt_ptrs( &simple_writes );
|
|
Glue_set_vid_rd_ptrs( &simple_reads );
|
|
#else
|
|
Cpu_set_vid_wrt_ptrs( &simple_writes );
|
|
Cpu_set_vid_rd_ptrs( &simple_reads );
|
|
#endif /* C_VID */
|
|
#else /* not A3CPU */
|
|
#ifdef A2CPU
|
|
gmi_define_mem(SAS_VIDEO, &vid_handlers);
|
|
read_pointers = dummy_reads;
|
|
#else
|
|
#if !defined(EGG) && !defined(C_VID) && !defined(A_VID)
|
|
gmi_define_mem(SAS_VIDEO, &cga_only_handlers);
|
|
#else
|
|
gmi_define_mem(SAS_VIDEO, &Glue_writes);
|
|
read_pointers = Glue_reads;
|
|
Glue_set_vid_wrt_ptrs( &simple_writes );
|
|
Glue_set_vid_rd_ptrs( &simple_reads );
|
|
#endif /* not EGG or C_VID or A_VID */
|
|
#endif /* A2CPU */
|
|
#endif /* A3CPU */
|
|
|
|
#endif /* JOKER */
|
|
#endif /* GISP_CPU */
|
|
|
|
#ifdef CPU_40_STYLE
|
|
setVideochain(3);
|
|
SetWritePointers();
|
|
SetReadPointers(3);
|
|
#endif /* CPU_40_STYLE */
|
|
|
|
sas_connect_memory(gvi_pc_low_regen,gvi_pc_high_regen,(half_word)SAS_VIDEO);
|
|
|
|
current_mode = -1; /* Only used by outb */
|
|
|
|
set_char_height(8);
|
|
set_pc_pix_height(1);
|
|
set_host_pix_height(2);
|
|
set_word_addressing(TRUE);
|
|
set_screen_height(199);
|
|
set_screen_limit(0x4000);
|
|
set_horiz_total(80); /* calculate screen params from this val, and prev 2 */
|
|
set_pix_width(1);
|
|
set_pix_char_width(8);
|
|
|
|
set_cga_mode(TEXT);
|
|
set_cursor_height(CGA_CURS_HEIGHT);
|
|
set_cursor_start(8-CGA_CURS_HEIGHT);
|
|
set_screen_start(0);
|
|
|
|
check_malloc(cga_screen_buf, CGA_REGEN_LENGTH, IU8);
|
|
set_screen_ptr(cga_screen_buf);
|
|
setVideoscreen_ptr(get_screen_ptr(0));
|
|
|
|
sas_fillsw(CGA_REGEN_START, (7 << 8)| ' ', CGA_REGEN_LENGTH >> 1);
|
|
/* Fill with blanks */
|
|
|
|
bios_ch2_byte_wrt_fn = simple_bios_byte_wrt;
|
|
bios_ch2_word_wrt_fn = simple_bios_word_wrt;
|
|
}
|
|
|
|
void cga_term IFN0()
|
|
{
|
|
io_addr i;
|
|
|
|
/*
|
|
* Disconnect the IO chip select logic for this adapter
|
|
*/
|
|
|
|
for(i = CGA_PORT_START; i <= CGA_PORT_END; i++)
|
|
io_disconnect_port(i, CGA_ADAPTOR);
|
|
/*
|
|
* Disconnect RAM from the adaptor
|
|
*/
|
|
sas_disconnect_memory(gvi_pc_low_regen,gvi_pc_high_regen);
|
|
|
|
if (cga_screen_buf != 0)
|
|
{
|
|
host_free(cga_screen_buf);
|
|
cga_screen_buf = 0;
|
|
}
|
|
}
|
|
|
|
|
|
#if !defined(EGG) && !defined(C_VID) && !defined(A_VID)
|
|
|
|
GLOBAL CGA_ONLY_GLOBS *VGLOBS = NULL;
|
|
LOCAL CGA_ONLY_GLOBS CgaOnlyGlobs;
|
|
/*(
|
|
============================ setup_vga_globals =============================
|
|
PURPOSE: This function is provided for CGA-only builds to set up a
|
|
dummy VGLOBS structure which avoids the need to ifdef all
|
|
references to VGLOBS->dirty_flag and VGLOBS->screen_ptr.
|
|
INPUT: None.
|
|
OUTPUT: None.
|
|
============================================================================
|
|
)*/
|
|
GLOBAL void setup_vga_globals IFN0()
|
|
{
|
|
#ifndef CPU_40_STYLE /* Evid interface */
|
|
VGLOBS = &CgaOnlyGlobs;
|
|
#endif
|
|
}
|
|
#endif /* not EGG or C_VID or A_VID */
|
|
#endif /* !NTVDM | (NTVDM & !X86GFX) */
|