2014-12-31 22:53:55 +00:00
|
|
|
/*
|
|
|
|
AppleWin : An Apple //e emulator for Windows
|
|
|
|
|
|
|
|
Copyright (C) 2010-2011, William S Simms
|
2016-07-26 18:14:06 +00:00
|
|
|
Copyright (C) 2016, Tom Charlesworth
|
2014-12-31 22:53:55 +00:00
|
|
|
|
|
|
|
AppleWin is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
AppleWin is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with AppleWin; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "StdAfx.h"
|
2020-11-11 21:15:27 +00:00
|
|
|
#include "NTSC_CharSet.h"
|
2020-11-29 17:30:06 +00:00
|
|
|
#include "Interface.h"
|
2020-11-26 21:50:06 +00:00
|
|
|
#include "Core.h"
|
2020-04-02 19:17:32 +00:00
|
|
|
#include "../resource/resource.h"
|
2016-07-26 18:14:06 +00:00
|
|
|
|
2014-12-31 22:53:55 +00:00
|
|
|
|
2018-11-17 16:29:17 +00:00
|
|
|
unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
|
2019-01-10 21:38:21 +00:00
|
|
|
static unsigned char csbits_2e_pal[2][256][8]; // PAL Original or Enhanced //e (2764 8K video ROM - low 4K) via rocker switch under keyboard
|
2016-04-12 22:21:05 +00:00
|
|
|
unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
|
|
|
|
unsigned char csbits_a2[1][256][8]; // ][ and ][+
|
2020-04-02 19:17:32 +00:00
|
|
|
unsigned char csbits_a2j[2][256][8]; // ][J-Plus
|
2016-04-12 22:21:05 +00:00
|
|
|
unsigned char csbits_pravets82[1][256][8]; // Pravets 82
|
|
|
|
unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
|
|
|
|
unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
|
2020-07-06 19:24:16 +00:00
|
|
|
unsigned char csbits_base64a[2][256][8]; // Base 64A
|
|
|
|
|
2014-12-31 22:53:55 +00:00
|
|
|
|
2016-07-26 18:14:06 +00:00
|
|
|
//
|
2016-04-08 21:44:07 +00:00
|
|
|
|
|
|
|
static const UINT bitmapWidth = 256;
|
|
|
|
static const UINT bitmapWidthBytes = bitmapWidth/8;
|
|
|
|
static const UINT bitmapHeight = 768;
|
|
|
|
|
|
|
|
static const UINT charWidth = 16;
|
|
|
|
static const UINT charWidthBytes = 16/8;
|
|
|
|
static const UINT charHeight = 16;
|
|
|
|
|
2016-07-26 18:14:06 +00:00
|
|
|
static void get_csbits_xy(csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap)
|
2016-04-08 21:44:07 +00:00
|
|
|
{
|
|
|
|
_ASSERT(ch < 256);
|
|
|
|
_ASSERT((cx < bitmapWidth/charWidth) && (cy < bitmapHeight/charHeight));
|
|
|
|
|
|
|
|
pBitmap += cy*charHeight*bitmapWidthBytes + cx*charWidthBytes;
|
|
|
|
|
|
|
|
for (UINT y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
BYTE n = 0;
|
|
|
|
for (int x=0; x<14; x+=2)
|
|
|
|
{
|
|
|
|
UINT xp = x/8;
|
|
|
|
BYTE d = pBitmap[xp];
|
|
|
|
UINT b = 7 - x%8;
|
|
|
|
if (d & (1<<b)) n |= 0x80;
|
|
|
|
n >>= 1;
|
|
|
|
}
|
|
|
|
|
2016-04-12 22:21:05 +00:00
|
|
|
csbits[0][ch][y] = n;
|
2016-04-08 21:44:07 +00:00
|
|
|
pBitmap += bitmapWidthBytes*2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 18:14:06 +00:00
|
|
|
static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0)
|
2016-04-08 21:44:07 +00:00
|
|
|
{
|
|
|
|
const UINT bufferSize = bitmapWidthBytes*bitmapHeight;
|
|
|
|
BYTE* pBuffer = new BYTE [bufferSize];
|
|
|
|
|
2021-01-19 20:37:43 +00:00
|
|
|
GetFrame().GetBitmap(resourceName, bufferSize, pBuffer);
|
2016-04-08 21:44:07 +00:00
|
|
|
|
2016-04-12 22:21:05 +00:00
|
|
|
for (UINT cy=cy0, ch=0; cy<cy0+16; cy++)
|
2016-04-08 21:44:07 +00:00
|
|
|
{
|
|
|
|
for (UINT cx=0; cx<16; cx++)
|
|
|
|
{
|
2016-04-12 22:21:05 +00:00
|
|
|
get_csbits_xy(csbits, ch++, cx, cy, pBuffer);
|
2016-04-08 21:44:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] pBuffer;
|
2016-04-12 22:21:05 +00:00
|
|
|
}
|
|
|
|
|
2018-11-17 16:29:17 +00:00
|
|
|
//-------------------------------------
|
|
|
|
|
|
|
|
// ROM address (RA):
|
|
|
|
// -----------------
|
|
|
|
// . RA10,..,RA3;SEGC,SEGB,SEGA => [2^8][2^3] => 256 chars of 8 lines (total = 2KiB)
|
|
|
|
// . VID7,..,VID0 is the 8-bit video character (eg. from TEXT/$400 memory)
|
|
|
|
//
|
|
|
|
// UTAIIe:8-13, Table 8.2:
|
|
|
|
//
|
|
|
|
// ALTCHRSET | RA10 | RA9
|
|
|
|
//------------------------------------------
|
|
|
|
// 0 | VID7 + VID6.FLASH | VID6.VID7
|
|
|
|
// 1 | VID7 | VID6
|
|
|
|
//
|
|
|
|
// FLASH toggles every 16 VBLs, so alternates between selecting NORMAL control/special and INVERSE control/special
|
|
|
|
//
|
|
|
|
|
2020-04-02 19:17:32 +00:00
|
|
|
static void userVideoRom4K(csbits_t csbits, const BYTE* pVideoRom)
|
2018-11-17 16:29:17 +00:00
|
|
|
{
|
|
|
|
int RA = 0; // rom address
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
// regular char set
|
|
|
|
|
|
|
|
for (; i<64; i++, RA+=8) // [00..3F] INVERSE / [40..7F] FLASH
|
|
|
|
{
|
|
|
|
for (int y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
|
|
|
|
csbits[0][i+64][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-14 (Table 8.3) we use FLASH=0, so RA=00ccccccsss
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RA = (1<<10 | 0<<9); // UTAIIe:8-14 (Table 8.3)
|
|
|
|
|
|
|
|
for (i=128; i<256; i++, RA+=8) // [80..BF] NORMAL
|
|
|
|
{
|
|
|
|
for (int y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RA = (1<<10 | 1<<9); // UTAIIe:8-14 (Table 8.3)
|
|
|
|
|
|
|
|
for (i=192; i<256; i++, RA+=8) // [C0..FF] NORMAL
|
|
|
|
{
|
|
|
|
for (int y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
csbits[0][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// alt char set
|
|
|
|
|
|
|
|
RA = 0;
|
|
|
|
|
|
|
|
for (i=0; i<256; i++, RA+=8) // [00..7F] INVERSE / [80..FF] NORMAL
|
|
|
|
{
|
|
|
|
for (int y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
csbits[1][i][y] = pVideoRom[RA+y] ^ 0xff; // UTAIIe:8-11 "dot patterns in the video ROM are inverted..."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-02 19:17:32 +00:00
|
|
|
static void userVideoRomForIIe(void)
|
2018-11-17 16:29:17 +00:00
|
|
|
{
|
|
|
|
const BYTE* pVideoRom;
|
2020-12-28 16:25:29 +00:00
|
|
|
UINT size = GetVideo().GetVideoRom(pVideoRom); // 2K or 4K or 8K
|
|
|
|
if (size < Video::kVideoRomSize4K)
|
2018-11-17 16:29:17 +00:00
|
|
|
return;
|
|
|
|
|
2020-12-28 16:25:29 +00:00
|
|
|
if (size == Video::kVideoRomSize4K)
|
2018-11-17 16:29:17 +00:00
|
|
|
{
|
|
|
|
userVideoRom4K(&csbits_enhanced2e[0], pVideoRom);
|
2019-01-10 21:38:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
userVideoRom4K(&csbits_2e_pal[0], pVideoRom);
|
|
|
|
userVideoRom4K(&csbits_enhanced2e[0], &pVideoRom[4*1024]);
|
2018-11-17 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-10 21:38:21 +00:00
|
|
|
// NB. Same *custom* US video ROM for Original & Enhanced //e
|
|
|
|
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
|
2018-11-17 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
2020-07-06 19:52:31 +00:00
|
|
|
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const eApple2Type type = A2TYPE_APPLE2, const int AN2=0);
|
2020-04-02 19:17:32 +00:00
|
|
|
|
2020-07-06 19:24:16 +00:00
|
|
|
static void userVideoRom2K(csbits_t csbits, const BYTE* pVideoRom, const eApple2Type type /*= A2TYPE_APPLE2*/, const int AN2/*=0*/)
|
2018-11-19 22:15:04 +00:00
|
|
|
{
|
2020-04-02 19:17:32 +00:00
|
|
|
for (int i=0; i<256; i++)
|
2018-11-19 22:15:04 +00:00
|
|
|
{
|
2020-04-02 19:17:32 +00:00
|
|
|
int RA = i*8; // rom address
|
|
|
|
|
2020-07-06 19:24:16 +00:00
|
|
|
if (type == A2TYPE_APPLE2JPLUS)
|
2020-04-02 19:17:32 +00:00
|
|
|
{
|
|
|
|
// AN2=0: $00-3F, $00-3F; $80-BF, $80-BF => KKAA (Repeat Katakana)
|
|
|
|
// AN2=1: $40-7F, $40-7F; $C0-FF, $C0-FF => AAAA (Repeat ASCII)
|
|
|
|
RA &= ~(1<<(6+3));
|
|
|
|
RA |= (AN2<<(6+3)); // AN2 controls A9 (UTAII 8-12, Fig 8.7)
|
|
|
|
}
|
|
|
|
|
2018-11-19 22:15:04 +00:00
|
|
|
for (int y=0; y<8; y++)
|
|
|
|
{
|
|
|
|
BYTE n = pVideoRom[RA+y];
|
|
|
|
|
|
|
|
// UTAII:8-30 "Bit 7 of your EPROM fonts will control flashing in the lower 1024 bytes of the EPROM"
|
|
|
|
// UTAII:8-31 "If you leave O7 (EPROM Output7) reset in these patterns, the resulting characters will be inversions..."
|
2020-04-02 19:17:32 +00:00
|
|
|
// Apple II J-Plus: simplest logic is just invert if reading low 1K of video ROM
|
2020-07-06 19:24:16 +00:00
|
|
|
// Base64A: Bit 0 instead of bit 7
|
2020-04-02 19:17:32 +00:00
|
|
|
if (RA < 1024)
|
|
|
|
{
|
2020-07-06 19:24:16 +00:00
|
|
|
if (type == A2TYPE_BASE64A)
|
|
|
|
{
|
|
|
|
if (!(n & 0x01))
|
|
|
|
n = n ^ 0xfe;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(n & 0x80) || (type == A2TYPE_APPLE2JPLUS))
|
|
|
|
n = n ^ 0x7f;
|
|
|
|
}
|
2020-04-02 19:17:32 +00:00
|
|
|
}
|
2018-11-19 22:15:04 +00:00
|
|
|
|
2018-11-21 21:21:54 +00:00
|
|
|
BYTE d = 0;
|
2020-07-06 19:24:16 +00:00
|
|
|
if (type == A2TYPE_BASE64A)
|
|
|
|
{
|
|
|
|
// On the Base 64A bits are ordered 1345672.
|
|
|
|
d = (n >> 2) | ((n & 2) >> 1) | ((n & 4) << 4);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// UTAII:8-30 "TEXT ROM pattern is ... reversed"
|
|
|
|
for (BYTE j = 0; j < 7; j++, n >>= 1) // Just bits [0..6]
|
|
|
|
d = (d << 1) | (n & 1);
|
|
|
|
}
|
2018-11-21 21:21:54 +00:00
|
|
|
|
2018-11-19 22:15:04 +00:00
|
|
|
csbits[0][i][y] = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-02 19:17:32 +00:00
|
|
|
static void userVideoRomForIIPlus(void)
|
2018-11-19 22:15:04 +00:00
|
|
|
{
|
|
|
|
const BYTE* pVideoRom;
|
2020-12-28 16:25:29 +00:00
|
|
|
UINT size = GetVideo().GetVideoRom(pVideoRom); // 2K or 4K or 8K
|
|
|
|
if (size != Video::kVideoRomSize2K)
|
2018-11-19 22:15:04 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
userVideoRom2K(&csbits_a2[0], pVideoRom);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
|
2024-06-02 11:47:22 +00:00
|
|
|
static void VideoRomForIIandIIPlus(void)
|
|
|
|
{
|
|
|
|
BYTE* pVideoRom = GetFrame().GetResource(IDR_APPLE2_VIDEO_ROM, "ROM", Video::kVideoRomSize2K);
|
|
|
|
if (pVideoRom == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
userVideoRom2K(&csbits_a2[0], pVideoRom);
|
|
|
|
}
|
|
|
|
|
2020-04-02 19:17:32 +00:00
|
|
|
static void VideoRomForIIJPlus(void)
|
|
|
|
{
|
2021-01-19 20:37:43 +00:00
|
|
|
BYTE* pVideoRom = GetFrame().GetResource(IDR_APPLE2_JPLUS_VIDEO_ROM, "ROM", Video::kVideoRomSize2K);
|
2020-04-02 19:17:32 +00:00
|
|
|
if (pVideoRom == NULL)
|
|
|
|
return;
|
|
|
|
|
2020-07-06 19:24:16 +00:00
|
|
|
userVideoRom2K(&csbits_a2j[0], pVideoRom, A2TYPE_APPLE2JPLUS, 0);
|
|
|
|
userVideoRom2K(&csbits_a2j[1], pVideoRom, A2TYPE_APPLE2JPLUS, 1);
|
2020-04-02 19:17:32 +00:00
|
|
|
}
|
|
|
|
|
2020-07-06 19:24:16 +00:00
|
|
|
static void VideoRomForBase64A(void)
|
|
|
|
{
|
2021-01-19 20:37:43 +00:00
|
|
|
BYTE* pVideoRom = GetFrame().GetResource(IDR_BASE64A_VIDEO_ROM, "ROM", Video::kVideoRomSize4K);
|
2020-07-06 19:24:16 +00:00
|
|
|
if (pVideoRom == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
userVideoRom2K(&csbits_base64a[0], pVideoRom, A2TYPE_BASE64A, 0);
|
2020-12-28 16:25:29 +00:00
|
|
|
userVideoRom2K(&csbits_base64a[1], pVideoRom + Video::kVideoRomSize2K, A2TYPE_BASE64A, 0);
|
2020-07-06 19:24:16 +00:00
|
|
|
}
|
|
|
|
|
2024-06-02 11:47:22 +00:00
|
|
|
static void VideoRomForIIeEnhanced(void)
|
|
|
|
{
|
|
|
|
BYTE* pVideoRom = GetFrame().GetResource(IDR_APPLE2E_ENHANCED_VIDEO_ROM, "ROM", Video::kVideoRomSize4K);
|
|
|
|
if (pVideoRom == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
userVideoRom4K(&csbits_enhanced2e[0], pVideoRom);
|
|
|
|
}
|
2020-07-06 19:24:16 +00:00
|
|
|
|
2020-04-02 19:17:32 +00:00
|
|
|
//-------------------------------------
|
|
|
|
|
2016-07-26 18:14:06 +00:00
|
|
|
void make_csbits(void)
|
2016-04-12 22:21:05 +00:00
|
|
|
{
|
|
|
|
get_csbits(&csbits_pravets82[0], TEXT("CHARSET82"), 0); // Pravets 82
|
|
|
|
get_csbits(&csbits_pravets8M[0], TEXT("CHARSET8M"), 0); // Pravets 8M
|
|
|
|
get_csbits(&csbits_pravets8C[0], TEXT("CHARSET8C"), 0); // Pravets 8A / 8C: Alt char set off
|
|
|
|
get_csbits(&csbits_pravets8C[1], TEXT("CHARSET8C"), 16); // Pravets 8A / 8C: Alt char set on
|
|
|
|
|
2024-06-02 11:47:22 +00:00
|
|
|
VideoRomForIIandIIPlus(); // GH#1308
|
|
|
|
VideoRomForIIeEnhanced(); // GH#1308
|
|
|
|
|
2016-04-12 22:21:05 +00:00
|
|
|
// Original //e is just Enhanced //e with the 32 mousetext chars [0x40..0x5F] replaced by the non-alt charset chars [0x40..0x5F]
|
|
|
|
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
|
|
|
|
memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8);
|
2018-11-17 16:29:17 +00:00
|
|
|
|
2020-04-02 22:39:18 +00:00
|
|
|
VideoRomForIIJPlus(); // GH#773
|
2020-07-06 19:24:16 +00:00
|
|
|
VideoRomForBase64A(); // GH#806
|
2020-04-02 19:17:32 +00:00
|
|
|
|
2019-01-10 21:38:21 +00:00
|
|
|
// Try to use any user-provided video ROM for Original/Enhanced //e
|
2018-11-19 22:15:04 +00:00
|
|
|
userVideoRomForIIe();
|
|
|
|
|
|
|
|
// Try to use any user-provided video ROM for II/II+
|
|
|
|
userVideoRomForIIPlus();
|
2018-11-17 16:29:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-10 21:38:21 +00:00
|
|
|
csbits_t Get2e_csbits(void)
|
2018-11-17 16:29:17 +00:00
|
|
|
{
|
2019-01-10 21:38:21 +00:00
|
|
|
const csbits_t videoRom4K = (GetApple2Type() == A2TYPE_APPLE2E) ? csbits_2e : csbits_enhanced2e;
|
|
|
|
|
2020-12-28 16:25:29 +00:00
|
|
|
if (GetVideo().IsVideoRom4K()) // 4K means US-only, so no secondary PAL video ROM
|
2019-01-10 21:38:21 +00:00
|
|
|
return videoRom4K;
|
2018-11-17 16:29:17 +00:00
|
|
|
|
2020-12-28 16:25:29 +00:00
|
|
|
return GetVideo().GetVideoRomRockerSwitch() == false ? videoRom4K : csbits_2e_pal; // NB. Same PAL video ROM for Original & Enhanced //e
|
2016-04-08 21:44:07 +00:00
|
|
|
}
|