2024-03-20 07:41:14 +01:00
/*
* mops . c
*
* This file is part of Emu48
*
* Copyright ( C ) 1995 Sebastien Carlier
*
*/
# include "pch.h"
# include "Emu48.h"
# include "ops.h"
# include "opcodes.h"
# include "io.h"
# include "i28f160.h" // flash support
// #define DEBUG_SERIAL // switch for SERIAL debug purpose
// #define DEBUG_IO // switch for I/O debug purpose
// #define DEBUG_FLASH // switch for FLASH MEMORY debug purpose
// defines for reading an open data bus
# define READEVEN 0x0D
# define READODD 0x0E
// on mapping boundary adjusted base addresses
# define P0MAPBASE ((BYTE)(Chipset.P0Base & ~Chipset.P0Size))
# define P1MAPBASE ((BYTE)(Chipset.P1Base & ~Chipset.P1Size))
# define P2MAPBASE ((BYTE)(Chipset.P2Base & ~Chipset.P2Size))
# define BSMAPBASE ((BYTE)(Chipset.BSBase & ~Chipset.BSSize))
BOOL bFlashRomArray = TRUE ; // flag ROM mode
BYTE disp = 0 ; // flag for update display area
static LPBYTE pbyRomView [ 2 ] = { NULL , NULL } ; // HP49G ROM views
static __inline UINT MIN ( UINT a , UINT b )
{
return ( a < b ) ? a : b ;
}
static __inline UINT MAX ( UINT a , UINT b )
{
return ( a > b ) ? a : b ;
}
// generate UCK signal
static __inline BYTE UckBit ( BYTE byBaudIndex )
{
// table content = baudrate * 16
const DWORD dwBaudrates [ ] = { 19200 , 30720 , 38400 , 61440 , 76800 , 122880 , 153600 , 245760 } ;
LARGE_INTEGER lLC ;
_ASSERT ( byBaudIndex < ARRAYSIZEOF ( dwBaudrates ) ) ;
if ( ( Chipset . IORam [ IOC ] & SON ) = = 0 ) // UART off
return UCK ; // UCK bit always set
QueryPerformanceCounter ( & lLC ) ; // get counter value
// calculate UCK frequency
return ( ( ( BYTE ) ( ( ( lLC . QuadPart - lAppStart . QuadPart ) * dwBaudrates [ byBaudIndex ] )
/ lFreq . QuadPart ) & 0x1 ) < < 3 ) ;
}
// calculate nibble based linear flash address
DWORD FlashROMAddr ( DWORD d )
{
DWORD dwLinAddr ;
// 6 bit of latch (was A6-A1 of address bus)
dwLinAddr = ( Chipset . Bank_FF > > 1 ) & 0x3f ;
// decode A21-A18
dwLinAddr = ( ( d & 0x40000 ) ? ( dwLinAddr & 0xf ) : ( dwLinAddr > > 4 ) ) < < 18 ;
// decode A21-A18, A17-A0
dwLinAddr | = d & 0x3FFFF ;
return dwLinAddr ;
}
// update display
static __inline VOID UpdateDisplay ( DWORD d , UINT s )
{
BYTE p [ 16 ] ;
DWORD u ;
UINT c ;
// address in display main area?
if ( ( d < Chipset . end1 ) & & ( d + s > Chipset . start12 ) )
{
// write to display main area
u = d ; // copy destination ptr
c = MIN ( s , Chipset . end1 - d ) ; // number of nibbles to copy
if ( d < Chipset . start12 ) // first address is out of display area
{
u = Chipset . start12 ; // set destination ptr to start of display area
c - = Chipset . start12 - d ; // - number of bytes that aren't in display area
}
_ASSERT ( c < = ARRAYSIZEOF ( p ) ) ;
Npeek ( p , u , c ) ; // get source data
WriteToMainDisplay ( p , u , c ) ;
}
// address in display menu area?
if ( ( d < Chipset . end2 ) & & ( d + s > Chipset . start2 ) )
{
// write to display menu area
u = d ; // copy destination ptr
c = MIN ( s , Chipset . end2 - d ) ; // number of nibbles to copy
if ( d < Chipset . start2 ) // first address is out of display area
{
u = Chipset . start2 ; // set destination ptr to start of display area
c - = Chipset . start2 - d ; // - number of bytes that are not in display area
}
_ASSERT ( c < = ARRAYSIZEOF ( p ) ) ;
Npeek ( p , u , c ) ; // get source data
WriteToMenuDisplay ( p , u , c ) ;
}
return ;
}
// port mapping
LPBYTE RMap [ 256 ] = { NULL , } ;
LPBYTE WMap [ 256 ] = { NULL , } ;
static VOID MapP0 ( BYTE a , BYTE b )
{
UINT i ;
DWORD p , m ;
a = ( BYTE ) MAX ( a , P0MAPBASE ) ; // adjust base to mapping boundary
b = ( BYTE ) MIN ( b , Chipset . P0End ) ;
m = ( Chipset . Port0Size * 2048 ) - 1 ;
p = ( a < < 12 ) & m ; // offset to begin of P0 in nibbles
for ( i = a ; i < = b ; i + + )
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P0Base ) & ~ Chipset . P0Size ) = = 0 )
{
2024-03-20 07:46:28 +01:00
RMap [ i ] = Port0 + p ;
WMap [ i ] = Port0 + p ;
2024-03-20 07:41:14 +01:00
}
p = ( p + 0x1000 ) & m ;
}
return ;
}
static VOID MapBS ( BYTE a , BYTE b )
{
UINT i ;
a = ( BYTE ) MAX ( a , BSMAPBASE ) ; // adjust base to mapping boundary
b = ( BYTE ) MIN ( b , Chipset . BSEnd ) ;
for ( i = a ; i < = b ; i + + )
{
// mapping area may have holes
if ( ( ( i ^ Chipset . BSBase ) & ~ Chipset . BSSize ) = = 0 )
{
RMap [ i ] = NULL ; // no read cycle, open data bus
WMap [ i ] = NULL ;
}
}
return ;
}
static VOID MapP1 ( BYTE a , BYTE b )
{
UINT i ;
DWORD p , m ;
// clear mapping area if port1 is configured but not plugged
a = ( BYTE ) MAX ( a , P1MAPBASE ) ; // lowest address for use is P1Base
b = ( BYTE ) MIN ( b , Chipset . P1End ) ; // highest address for use is P1End
// port1 not plugged
2024-03-20 07:46:28 +01:00
if ( Port1 = = NULL | | ! ( Chipset . cards_status & PORT1_PRESENT ) )
2024-03-20 07:41:14 +01:00
{
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
if ( ( ( i ^ Chipset . P1Base ) & ~ Chipset . P1Size ) = = 0 )
{
RMap [ i ] = NULL ;
WMap [ i ] = NULL ;
}
}
return ;
}
m = ( Chipset . Port1Size * 2048 ) - 1 ; // real size of module, address mask for mirroring
p = ( a < < 12 ) & m ; // offset to begin of P1 in nibbles
if ( Chipset . cards_status & PORT1_WRITE ) // port1 write enabled
{
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P1Base ) & ~ Chipset . P1Size ) = = 0 )
{
2024-03-20 07:46:28 +01:00
RMap [ i ] = Port1 + p ; // save page address for read
WMap [ i ] = Port1 + p ; // save page address for write
2024-03-20 07:41:14 +01:00
}
p = ( p + 0x1000 ) & m ; // next page, mirror page if real size smaller allocated size
}
}
else // port1 read only
{
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P1Base ) & ~ Chipset . P1Size ) = = 0 )
{
2024-03-20 07:46:28 +01:00
RMap [ i ] = Port1 + p ; // save page address for read
2024-03-20 07:41:14 +01:00
WMap [ i ] = NULL ; // no writing
}
p = ( p + 0x1000 ) & m ; // next page, mirror page if real size smaller allocated size
}
}
return ;
}
static VOID MapP2 ( BYTE a , BYTE b )
{
UINT i ;
DWORD p , m ;
LPBYTE pbyTemp ;
// clear mapping area if port2 is configured but not plugged
a = ( BYTE ) MAX ( a , P2MAPBASE ) ; // adjust base to mapping boundary
b = ( BYTE ) MIN ( b , Chipset . P2End ) ;
if ( Chipset . Port2Size ) // internal port2
{
m = ( Chipset . Port2Size * 2048 ) - 1 ;
p = ( a < < 12 ) & m ; // offset to begin of P0 in nibbles
for ( i = a ; i < = b ; i + + )
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 )
{
2024-03-20 07:46:28 +01:00
RMap [ i ] = Port2 + p ;
WMap [ i ] = Port2 + p ;
2024-03-20 07:41:14 +01:00
}
p = ( p + 0x1000 ) & m ;
}
return ;
}
// HP48SX / HP48GX
// only fill mapping table when CE2.2 is set
for ( i = a ; i < = b ; i + + ) // fill mapping area with not configured
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 )
{
RMap [ i ] = NULL ;
WMap [ i ] = NULL ;
}
}
// port2 not plugged
if ( pbyPort2 = = NULL | | ! ( Chipset . cards_status & PORT2_PRESENT ) )
return ;
pbyTemp = pbyPort2 ;
if ( cCurrentRomType ! = ' S ' ) // bank switching only with GX
{
// Chipset.Port2_Bank is the saved port2 FF content
pbyTemp + = ( ( ( Chipset . Bank_FF > > 1 ) - 1 ) & dwPort2Mask ) < < 18 ;
}
// max. size per bank is 128KB
m = ( dwPort2Size > 128 ) ? 128 : dwPort2Size ;
m = ( m * 2048 ) - 1 ; // real size of module, address mask for mirroring
p = ( a < < 12 ) & m ; // offset to begin of P2 in nibbles
// SX: CE2.2 = CE2
// GX: CE2.2 = BEN & /DA19 & /NCE3
if ( cCurrentRomType = = ' S ' | | ( ( Chipset . IORam [ 0x29 ] & DA19 ) = = 0 & & ( Chipset . Bank_FF & 0x40 ) ) )
{
if ( bPort2Writeable )
{
for ( i = a ; i < = b ; i + + )
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 )
{
RMap [ i ] = pbyTemp + p ;
WMap [ i ] = pbyTemp + p ;
}
p = ( p + 0x1000 ) & m ;
}
}
else
{
for ( i = a ; i < = b ; i + + )
{
// mapping area may have holes
if ( ( ( i ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 )
{
RMap [ i ] = pbyTemp + p ;
}
p = ( p + 0x1000 ) & m ;
}
}
}
return ;
}
static VOID MapROM ( BYTE a , BYTE b )
{
UINT i ;
DWORD p , m ;
2024-03-20 07:46:28 +01:00
// HP39(+)/40G, HP49G/g+ HP48gII // CdB for HP: add apples memory
2024-03-20 07:41:14 +01:00
if ( cCurrentRomType = = ' E ' | | cCurrentRomType = = ' X ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' Q ' )
{
if ( bFlashRomArray ) // view flash ROM data
{
_ASSERT ( pbyRomView [ 0 ] ) ; // check ROM bank set
_ASSERT ( pbyRomView [ 1 ] ) ;
m = ( 128 * 1024 * 2 ) - 1 ; // mapped in 128KB pages
p = ( a < < 12 ) & m ; // offset to the begin of ROM in nibbles
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
RMap [ i ] = pbyRomView [ ( i & 0x40 ) ! = 0 ] + p ;
WMap [ i ] = NULL ; // no writing
p = ( p + 0x1000 ) & m ;
}
}
else // view flash ROM register
{
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
RMap [ i ] = NULL ; // view flash register
WMap [ i ] = NULL ; // no writing
}
}
return ;
}
// HP38G / HP48SX / HP48GX
m = dwRomSize - 1 ; // ROM address mask for mirroring
// when 512KB ROM and DA19=0 (ROM disabled)
if ( ( m & 0x80000 ) ! = 0 & & ( Chipset . IORam [ 0x29 ] & DA19 ) = = 0 )
m > > = 1 ; // mirror ROM at #80000 (AR18=0)
p = ( a * 0x1000 ) & m ; // data offset in nibbles
for ( i = a ; i < = b ; i + + ) // scan each 2KB page
{
RMap [ i ] = pbyRom + p ; // save page address for read
WMap [ i ] = NULL ; // no writing
p = ( p + 0x1000 ) & m ; // next page, mirror page if real size smaller allocated size
}
return ;
}
VOID Map ( BYTE a , BYTE b ) // maps 2KB pages with priority
{
// On HP39/40G and HP49G Chipset.cards_status must be 0xF
_ASSERT ( ( cCurrentRomType ! = ' E ' & & cCurrentRomType ! = ' X ' & & cCurrentRomType ! = ' P ' & & cCurrentRomType ! = ' 2 ' & & cCurrentRomType ! = ' Q ' ) | | ! Chipset . P1Cfig | | Chipset . cards_status = = 0xF ) ; // CdB for HP: add apples
// priority order is HDW, RAM, CE2, CE1, NCE3, ROM
MapROM ( a , b ) ; // ROM, lowest priority, always mapped
if ( cCurrentRomType = = ' S ' ) // HP48SX
{
if ( Chipset . BSCfig ) MapBS ( a , b ) ; // NCE3, not used in S(X)
if ( Chipset . P1Cfig ) MapP1 ( a , b ) ; // CE1, port1 (lower priority than CE2)
if ( Chipset . P2Cfig ) MapP2 ( a , b ) ; // CE2, port2 (higher priority than CE1)
}
else // HP48GX / HP49G
{
if ( Chipset . P2Cfig ) // NCE3, port2
{
// LED bit set on a HP49
if ( ( cCurrentRomType = = ' X ' | | cCurrentRomType = = ' Q ' ) & & ( Chipset . IORam [ LCR ] & LED ) ) // CdB for HP: add apples
MapROM ( a , b ) ; // NCE3, ROM
else
MapP2 ( a , b ) ; // NCE3, port2
}
if ( Chipset . BSCfig ) MapBS ( a , b ) ; // CE1, bank select (lower priority than CE2)
if ( Chipset . P1Cfig ) MapP1 ( a , b ) ; // CE2, port1 (higher priority than CE1)
}
if ( Chipset . P0Cfig ) MapP0 ( a , b ) ; // RAM, highest priority (execpt HDW)
2024-03-20 07:46:28 +01:00
// CdB for HP: add apples header
// @todo cg, bug if display header area is mapped to addr 0
2024-03-20 07:41:14 +01:00
if ( Chipset . d0address ! = 0 )
{
2024-03-20 07:46:28 +01:00
RMap [ Chipset . d0address ] = & ( Chipset . d0memory [ 0 ] ) ; RMap [ Chipset . d0address + 1 ] = & ( Chipset . d0memory [ 2048 * 2 ] ) ;
WMap [ Chipset . d0address ] = & ( Chipset . d0memory [ 0 ] ) ; WMap [ Chipset . d0address + 1 ] = & ( Chipset . d0memory [ 2048 * 2 ] ) ;
2024-03-20 07:41:14 +01:00
}
return ;
}
VOID RomSwitch ( DWORD adr )
{
// only HP39/40G, HP49G
if ( cCurrentRomType = = ' E ' | | cCurrentRomType = = ' X ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' Q ' ) // CdB for HP: add apples
{
Chipset . Bank_FF = adr ; // save address line
adr = ( adr > > 1 ) & 0x3f ; // 6 bit of latch (was A6-A1 of address bus)
// lower 4 bit (16 banks) for 2nd ROM view
pbyRomView [ 1 ] = pbyRom + ( ( ( adr & 0xf ) * 128 * 1024 * 2 ) & ( dwRomSize - 1 ) ) ;
// higher 2 bit (4 banks) for 1st ROM view
pbyRomView [ 0 ] = pbyRom + ( ( ( adr > > 4 ) * 128 * 1024 * 2 ) & ( dwRomSize - 1 ) ) ;
}
Map ( 0x00 , 0xFF ) ; // update memory mapping
return ;
}
////////////////////////////////////////////////////////////////////////////////
//
// Bus Commands
//
////////////////////////////////////////////////////////////////////////////////
VOID Config ( ) // configure modules in fixed order
{
DWORD d = Npack ( Chipset . C , 5 ) ; // decode size or address
BYTE b = ( BYTE ) ( d > > 12 ) ; // number of 2KB pages or page address
BYTE s = ( BYTE ) ( b ^ 0xFF ) ; // size in pages-1, offset to last page
// config order is HDW, RAM, CE1, CE2, NCE3
if ( ! Chipset . IOCfig ) // address of HDW, first module, ROM always configured
{
Chipset . IOCfig = TRUE ;
Chipset . IOBase = d & 0xFFFC0 ; // save HDW base on a 64 nib boundary
Map ( b , b ) ;
return ;
}
if ( ! Chipset . P0Cfg2 ) // RAM size, port0
{
Chipset . P0Cfg2 = TRUE ;
Chipset . P0Size = s ; // offset to last used page
return ;
}
if ( ! Chipset . P0Cfig ) // RAM address, port0
{
Chipset . P0Cfig = TRUE ;
Chipset . P0Base = b ; // save first page address
b & = ~ Chipset . P0Size ; // adjust base to mapping boundary
Chipset . P0End = b + Chipset . P0Size ; // save last page address
Map ( b , Chipset . P0End ) ; // refresh mapping
return ;
}
if ( cCurrentRomType = = ' S ' ) // HP48SX
{
if ( ! Chipset . P1Cfg2 ) // CE1 size, port1
{
Chipset . P1Cfg2 = TRUE ;
Chipset . P1Size = s ;
return ;
}
if ( ! Chipset . P1Cfig ) // CE1 address, port1
{
Chipset . P1Cfig = TRUE ;
Chipset . P1Base = b ;
b & = ~ Chipset . P1Size ; // adjust base to mapping boundary
Chipset . P1End = b + Chipset . P1Size ;
Map ( b , Chipset . P1End ) ; // refresh mapping
return ;
}
if ( ! Chipset . P2Cfg2 ) // CE2 size, port2
{
Chipset . P2Cfg2 = TRUE ;
Chipset . P2Size = s ;
return ;
}
if ( ! Chipset . P2Cfig ) // CE2 address, port2
{
Chipset . P2Cfig = TRUE ;
Chipset . P2Base = b ;
b & = ~ Chipset . P2Size ; // adjust base to mapping boundary
Chipset . P2End = b + Chipset . P2Size ;
Map ( b , Chipset . P2End ) ; // refresh mapping
return ;
}
if ( ! Chipset . BSCfg2 ) // NCE3 size, not used in S(X)
{
Chipset . BSCfg2 = TRUE ;
Chipset . BSSize = s ;
return ;
}
if ( ! Chipset . BSCfig ) // NCE3 address, not used in S(X)
{
Chipset . BSCfig = TRUE ;
Chipset . BSBase = b ;
b & = ~ Chipset . BSSize ; // adjust base to mapping boundary
Chipset . BSEnd = b + Chipset . BSSize ;
Map ( b , Chipset . BSEnd ) ; // refresh mapping
return ;
}
}
else // HP48GX / HP49G
{
if ( ! Chipset . BSCfg2 ) // CE1 size, bank select
{
Chipset . BSCfg2 = TRUE ;
Chipset . BSSize = s ;
return ;
}
if ( ! Chipset . BSCfig ) // CE1 address, bank select
{
Chipset . BSCfig = TRUE ;
Chipset . BSBase = b ;
b & = ~ Chipset . BSSize ; // adjust base to mapping boundary
Chipset . BSEnd = b + Chipset . BSSize ;
Map ( b , Chipset . BSEnd ) ; // refresh mapping
return ;
}
if ( ! Chipset . P1Cfg2 ) // CE2 size, port1
{
Chipset . P1Cfg2 = TRUE ;
Chipset . P1Size = s ;
return ;
}
if ( ! Chipset . P1Cfig ) // CE2 address, port1
{
Chipset . P1Cfig = TRUE ;
Chipset . P1Base = b ;
b & = ~ Chipset . P1Size ; // adjust base to mapping boundary
Chipset . P1End = b + Chipset . P1Size ;
Map ( b , Chipset . P1End ) ; // refresh mapping
return ;
}
if ( ! Chipset . P2Cfg2 ) // NCE3 size, port2
{
Chipset . P2Cfg2 = TRUE ;
Chipset . P2Size = s ;
return ;
}
if ( ! Chipset . P2Cfig ) // NCE3 address, port2
{
Chipset . P2Cfig = TRUE ;
Chipset . P2Base = b ;
b & = ~ Chipset . P2Size ; // adjust base to mapping boundary
Chipset . P2End = b + Chipset . P2Size ;
Map ( b , Chipset . P2End ) ; // refresh mapping
return ;
}
}
return ;
}
VOID Uncnfg ( )
{
DWORD d = Npack ( Chipset . C , 5 ) ; // decode address
BYTE b = ( BYTE ) ( d > > 12 ) ; // page address
// unconfig order is HDW, RAM, CE2, CE1, NCE3
if ( ( Chipset . IOCfig ) & & ( ( d & 0xFFFC0 ) = = Chipset . IOBase ) )
{ Chipset . IOCfig = FALSE ; Map ( b , b ) ; return ; }
if ( ( Chipset . P0Cfig ) & & ( ( b & ~ Chipset . P0Size ) = = P0MAPBASE ) )
{ Chipset . P0Cfig = FALSE ; Chipset . P0Cfg2 = FALSE ; Map ( P0MAPBASE , Chipset . P0End ) ; return ; }
if ( cCurrentRomType = = ' S ' ) // HP48SX
{
if ( ( Chipset . P2Cfig ) & & ( ( b & ~ Chipset . P2Size ) = = P2MAPBASE ) )
{ Chipset . P2Cfig = FALSE ; Chipset . P2Cfg2 = FALSE ; Map ( P2MAPBASE , Chipset . P2End ) ; return ; }
if ( ( Chipset . P1Cfig ) & & ( ( b & ~ Chipset . P1Size ) = = P1MAPBASE ) )
{ Chipset . P1Cfig = FALSE ; Chipset . P1Cfg2 = FALSE ; Map ( P1MAPBASE , Chipset . P1End ) ; return ; }
if ( ( Chipset . BSCfig ) & & ( ( b & ~ Chipset . BSSize ) = = BSMAPBASE ) )
{ Chipset . BSCfig = FALSE ; Chipset . BSCfg2 = FALSE ; Map ( BSMAPBASE , Chipset . BSEnd ) ; return ; }
}
else // HP48GX / HP49G
{
if ( ( Chipset . P1Cfig ) & & ( ( b & ~ Chipset . P1Size ) = = P1MAPBASE ) )
{ Chipset . P1Cfig = FALSE ; Chipset . P1Cfg2 = FALSE ; Map ( P1MAPBASE , Chipset . P1End ) ; return ; }
if ( ( Chipset . BSCfig ) & & ( ( b & ~ Chipset . BSSize ) = = BSMAPBASE ) )
{ Chipset . BSCfig = FALSE ; Chipset . BSCfg2 = FALSE ; Map ( BSMAPBASE , Chipset . BSEnd ) ; return ; }
if ( ( Chipset . P2Cfig ) & & ( ( b & ~ Chipset . P2Size ) = = P2MAPBASE ) )
{ Chipset . P2Cfig = FALSE ; Chipset . P2Cfg2 = FALSE ; Map ( P2MAPBASE , Chipset . P2End ) ; return ; }
}
return ;
}
VOID Reset ( )
{
Chipset . IOCfig = FALSE ; Chipset . IOBase = 0x100000 ;
Chipset . P0Cfig = FALSE ; Chipset . P0Cfg2 = FALSE ; Chipset . P0Base = 0 ; Chipset . P0Size = 0 ; Chipset . P0End = 0 ;
Chipset . BSCfig = FALSE ; Chipset . BSCfg2 = FALSE ; Chipset . BSBase = 0 ; Chipset . BSSize = 0 ; Chipset . BSEnd = 0 ;
Chipset . P1Cfig = FALSE ; Chipset . P1Cfg2 = FALSE ; Chipset . P1Base = 0 ; Chipset . P1Size = 0 ; Chipset . P1End = 0 ;
Chipset . P2Cfig = FALSE ; Chipset . P2Cfg2 = FALSE ; Chipset . P2Base = 0 ; Chipset . P2Size = 0 ; Chipset . P2End = 0 ;
Map ( 0x00 , 0xFF ) ; // refresh mapping
return ;
}
VOID C_Eq_Id ( )
{
// config order is HDW, RAM, CE1, CE2, NCE3
if ( ! Chipset . IOCfig ) { Nunpack ( Chipset . C , ( Chipset . IOBase ) ^ 0x00019 , 5 ) ; return ; }
if ( ! Chipset . P0Cfg2 ) { Nunpack ( Chipset . C , ( Chipset . P0Size * 0x1000 ) ^ 0xFF003 , 5 ) ; return ; }
if ( ! Chipset . P0Cfig ) { Nunpack ( Chipset . C , ( Chipset . P0Base * 0x1000 ) ^ 0x000F4 , 5 ) ; return ; }
if ( cCurrentRomType = = ' S ' ) // HP48SX
{
if ( ! Chipset . P1Cfg2 ) { Nunpack ( Chipset . C , ( Chipset . P1Size * 0x1000 ) ^ 0xFF005 , 5 ) ; return ; }
if ( ! Chipset . P1Cfig ) { Nunpack ( Chipset . C , ( Chipset . P1Base * 0x1000 ) ^ 0x000F6 , 5 ) ; return ; }
if ( ! Chipset . P2Cfg2 ) { Nunpack ( Chipset . C , ( Chipset . P2Size * 0x1000 ) ^ 0xFF007 , 5 ) ; return ; }
if ( ! Chipset . P2Cfig ) { Nunpack ( Chipset . C , ( Chipset . P2Base * 0x1000 ) ^ 0x000F8 , 5 ) ; return ; }
if ( ! Chipset . BSCfg2 ) { Nunpack ( Chipset . C , ( Chipset . BSSize * 0x1000 ) ^ 0xFF001 , 5 ) ; return ; }
if ( ! Chipset . BSCfig ) { Nunpack ( Chipset . C , ( Chipset . BSBase * 0x1000 ) ^ 0x000F2 , 5 ) ; return ; }
}
else // HP48GX / HP49G
{
if ( ! Chipset . BSCfg2 ) { Nunpack ( Chipset . C , ( Chipset . BSSize * 0x1000 ) ^ 0xFF005 , 5 ) ; return ; }
if ( ! Chipset . BSCfig ) { Nunpack ( Chipset . C , ( Chipset . BSBase * 0x1000 ) ^ 0x000F6 , 5 ) ; return ; }
if ( ! Chipset . P1Cfg2 ) { Nunpack ( Chipset . C , ( Chipset . P1Size * 0x1000 ) ^ 0xFF007 , 5 ) ; return ; }
if ( ! Chipset . P1Cfig ) { Nunpack ( Chipset . C , ( Chipset . P1Base * 0x1000 ) ^ 0x000F8 , 5 ) ; return ; }
if ( ! Chipset . P2Cfg2 ) { Nunpack ( Chipset . C , ( Chipset . P2Size * 0x1000 ) ^ 0xFF001 , 5 ) ; return ; }
if ( ! Chipset . P2Cfig ) { Nunpack ( Chipset . C , ( Chipset . P2Base * 0x1000 ) ^ 0x000F2 , 5 ) ; return ; }
}
memset ( Chipset . C , 0 , 5 ) ;
return ;
}
enum MMUMAP MapData ( DWORD d ) // check MMU area
{
BYTE u = ( BYTE ) ( d > > 12 ) ;
if ( Chipset . IOCfig & & ( ( d & 0xFFFC0 ) = = Chipset . IOBase ) ) return M_IO ;
if ( Chipset . P0Cfig & & ( ( ( u ^ Chipset . P0Base ) & ~ Chipset . P0Size ) = = 0 ) ) return M_RAM ;
if ( cCurrentRomType = = ' S ' )
{
if ( Chipset . P2Cfig & & ( ( ( u ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 ) ) return M_P2 ;
if ( Chipset . P1Cfig & & ( ( ( u ^ Chipset . P1Base ) & ~ Chipset . P1Size ) = = 0 ) ) return M_P1 ;
if ( Chipset . BSCfig & & ( ( ( u ^ Chipset . BSBase ) & ~ Chipset . BSSize ) = = 0 ) ) return M_BS ;
}
else
{
if ( Chipset . P1Cfig & & ( ( ( u ^ Chipset . P1Base ) & ~ Chipset . P1Size ) = = 0 ) ) return M_P1 ;
if ( Chipset . BSCfig & & ( ( ( u ^ Chipset . BSBase ) & ~ Chipset . BSSize ) = = 0 ) ) return M_BS ;
if ( Chipset . P2Cfig & & ( ( ( u ^ Chipset . P2Base ) & ~ Chipset . P2Size ) = = 0 ) ) return M_P2 ;
}
return M_ROM ;
}
VOID CpuReset ( VOID ) // register setting after Cpu Reset
{
StopTimers ( ) ; // stop timer, do here because function change Chipset.t2
Chipset . pc = 0 ;
Chipset . rstkp = 0 ;
ZeroMemory ( Chipset . rstk , sizeof ( Chipset . rstk ) ) ;
Chipset . HST = 0 ;
Chipset . SoftInt = FALSE ;
Chipset . Shutdn = TRUE ;
Chipset . inte = TRUE ; // enable interrupts
Chipset . intk = TRUE ; // INTON
Chipset . intd = FALSE ; // no keyboard interrupts pending
Chipset . crc = 0 ;
Chipset . Bank_FF = 0 ; // state of bank switcher FF
Chipset . FlashRomState = 0 ; // WSM state of flash memory
ZeroMemory ( Chipset . IORam , sizeof ( Chipset . IORam ) ) ;
Chipset . IORam [ LPE ] = RST ; // set ReSeT bit at hardware reset
Reset ( ) ; // reset MMU
Chipset . t1 = 0 ; // reset timer values
Chipset . t2 = 0 ;
Chipset . loffset = 0 ; // right margin
Chipset . boffset = 0 ; // left margin
Chipset . lcounter = 0 ; // number of main display lines
Chipset . contrast = 0 ; // contrast dark
UpdateContrast ( Chipset . contrast ) ; // update contrast
// display update when changing to run state
CommSetBaud ( ) ; // new baudrate
CheckSerial ( ) ; // close serial port
RomSwitch ( Chipset . Bank_FF ) ; // force new memory mapping
return ;
}
VOID Npeek ( BYTE * a , DWORD d , UINT s )
{
enum MMUMAP eMap ;
DWORD u , v ;
UINT c ;
BYTE * p ;
do
{
eMap = MapData ( d ) ; // get active memory controller
if ( M_IO = = eMap ) // I/O access
{
v = d & 0x3F ;
do
{
if ( v = = LPE )
{
// don't read LPE content with the function ReadIO()
c = 1 ;
memcpy ( a , Chipset . IORam + v , c ) ;
break ;
}
if ( v > = RBR_LSB & & v < = RBR_MSB )
{
// don't read RBR content with the function ReadIO()
c = MIN ( s , RBR_MSB - v + 1 ) ;
memcpy ( a , Chipset . IORam + v , c ) ;
break ;
}
// all others registers
do
{
if ( v < LPE )
{
c = MIN ( s , LPE - v ) ;
break ;
}
if ( v < RBR_LSB & & ( v + s ) > RBR_LSB )
{
c = MIN ( s , RBR_LSB - v ) ;
break ;
}
c = MIN ( s , 0x40 - v ) ;
}
while ( 0 ) ;
ReadIO ( a , v , c , FALSE ) ;
}
while ( 0 ) ;
}
else
{
u = d > > 12 ;
v = d & 0xFFF ;
c = MIN ( s , 0x1000 - v ) ;
// Flash memory Read access
if ( ( cCurrentRomType = = ' X ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' Q ' ) & & ( Chipset . IORam [ LCR ] & LED ) & & M_P2 = = eMap ) // CdB for HP: add apples
{
FlashRead ( a , FlashROMAddr ( d ) , c ) ;
}
else
{
if ( ( p = RMap [ u ] ) ! = NULL ) // module mapped
{
memcpy ( a , p + v , c ) ;
}
else // open data bus
{
for ( u = 0 ; u < c ; + + u ) // fill all nibbles
{
if ( ( v + u ) & 1 ) // odd address
a [ u ] = READODD ;
else // even address
a [ u ] = READEVEN ;
}
}
}
}
2024-03-20 07:46:28 +01:00
a + = c ;
d = ( d + c ) & 0xFFFFF ;
} while ( s - = c ) ;
2024-03-20 07:41:14 +01:00
return ;
}
VOID Nread ( BYTE * a , DWORD d , UINT s )
{
enum MMUMAP eMap ;
DWORD u , v ;
UINT c ;
BYTE * p ;
do
{
eMap = MapData ( d ) ; // get active memory controller
if ( M_IO = = eMap ) // I/O access
{
v = d & 0x3F ;
c = MIN ( s , 0x40 - v ) ;
ReadIO ( a , v , c , TRUE ) ;
// reading MSB of timer2 update the CRC register
2024-03-20 07:46:29 +01:00
if ( v + c = = 0x40 ) // timer2 MSB touched
{
// update the CRC register
Chipset . crc = UpCRC ( Chipset . crc , a [ c - 1 ] ) ;
}
2024-03-20 07:41:14 +01:00
}
else
{
u = d > > 12 ;
v = d & 0xFFF ;
c = MIN ( s , 0x1000 - v ) ;
// bank switcher access
if ( cCurrentRomType ! = ' S ' & & M_BS = = eMap )
{
if ( cCurrentRomType = = ' G ' ) // HP48GX
{
Chipset . Bank_FF = v + c ; // save FF value
Map ( Chipset . P2Base , Chipset . P2End ) ;
}
if ( cCurrentRomType = = ' E ' | | cCurrentRomType = = ' X ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' Q ' ) // HP39/40G, HP49G // CdB for HP: add apples
{
RomSwitch ( v + c ) ;
}
}
// Flash memory Read access
if ( ( cCurrentRomType = = ' X ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' Q ' ) & & ( Chipset . IORam [ LCR ] & LED ) & & M_P2 = = eMap ) // CdB for HP: add apples
{
DWORD dwLinAddr = FlashROMAddr ( d ) ;
FlashRead ( a , dwLinAddr , c ) ;
# if defined DEBUG_FLASH
{
TCHAR buffer [ 256 ] ;
DWORD j ;
int i ;
i = wsprintf ( buffer , _T ( " %.5lx: Flash Read : %.5x (%.6x),%u = " ) , Chipset . pc , d , dwLinAddr , c ) ;
for ( j = 0 ; j < c ; + + j , + + i )
{
buffer [ i ] = a [ j ] ;
if ( buffer [ i ] > 9 ) buffer [ i ] + = _T ( ' a ' ) - _T ( ' 9 ' ) - 1 ;
buffer [ i ] + = _T ( ' 0 ' ) ;
}
buffer [ i + + ] = _T ( ' \n ' ) ;
buffer [ i ] = 0 ;
OutputDebugString ( buffer ) ;
}
# endif
}
else
{
if ( ( p = RMap [ u ] ) ! = NULL ) // module mapped
{
memcpy ( a , p + v , c ) ;
}
// simulate open data bus
else // open data bus
{
for ( u = 0 ; u < c ; + + u ) // fill all nibbles
{
if ( ( v + u ) & 1 ) // odd address
a [ u ] = READODD ;
else // even address
a [ u ] = READEVEN ;
}
}
}
for ( u = 0 ; u < c ; u + + ) // update CRC
2024-03-20 07:46:29 +01:00
Chipset . crc = UpCRC ( Chipset . crc , a [ u ] ) ;
2024-03-20 07:41:14 +01:00
}
2024-03-20 07:46:28 +01:00
a + = c ;
d = ( d + c ) & 0xFFFFF ;
} while ( s - = c ) ;
2024-03-20 07:41:14 +01:00
return ;
}
VOID Nwrite ( BYTE * a , DWORD d , UINT s )
{
enum MMUMAP eMap ;
DWORD u , v ;
UINT c ;
BYTE * p ;
do
{
eMap = MapData ( d ) ; // get active memory controller
if ( M_IO = = eMap ) // I/O access
{
v = d & 0x3F ;
c = MIN ( s , 0x40 - v ) ;
WriteIO ( a , v , c ) ;
}
else
{
u = d > > 12 ;
v = d & 0xFFF ;
c = MIN ( s , 0x1000 - v ) ;
// bank switcher access
if ( cCurrentRomType ! = ' S ' & & M_BS = = eMap )
{
BOOL bWrite = FALSE ;
// write enabled
if ( Chipset . cards_status & PORT2_WRITE )
{
Chipset . Bank_FF = v + c - 1 ; // save FF value
bWrite = TRUE ; // bank switched
}
else // write disabled, so latch last read cycle
{
if ( ( v & 1 ) ! = 0 ) // low address odd
{
Chipset . Bank_FF = v ; // save FF value
bWrite = TRUE ; // bank switched
}
if ( ( ( v + c ) & 1 ) ! = 0 ) // high address odd
{
Chipset . Bank_FF = v + c - 1 ; // save FF value
bWrite = TRUE ; // bank switched
}
}
if ( bWrite ) // write cycle?
{
// HP48GX
if ( cCurrentRomType = = ' G ' ) Map ( Chipset . P2Base , Chipset . P2End ) ;
// HP39/40G, HP49G
if ( cCurrentRomType = = ' E ' | | cCurrentRomType = = ' X ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' Q ' ) RomSwitch ( Chipset . Bank_FF ) ; // CdB for HP: add apples
}
}
// Flash memory Write access
if ( ( cCurrentRomType = = ' X ' | | cCurrentRomType = = ' 2 ' | | cCurrentRomType = = ' P ' | | cCurrentRomType = = ' Q ' ) & & ( Chipset . IORam [ LCR ] & LED ) & & M_P2 = = eMap ) // CdB for HP: add apples
{
DWORD dwLinAddr = FlashROMAddr ( d ) ;
FlashWrite ( a , dwLinAddr , c ) ;
# if defined DEBUG_FLASH
{
TCHAR buffer [ 256 ] ;
DWORD j ;
int i ;
i = wsprintf ( buffer , _T ( " %.5lx: Flash Write: %.5x (%.6x),%u = " ) , Chipset . pc , d , dwLinAddr , c ) ;
for ( j = 0 ; j < c ; + + j , + + i )
{
buffer [ i ] = a [ j ] ;
if ( buffer [ i ] > 9 ) buffer [ i ] + = _T ( ' a ' ) - _T ( ' 9 ' ) - 1 ;
buffer [ i ] + = _T ( ' 0 ' ) ;
}
buffer [ i + + ] = _T ( ' \n ' ) ;
buffer [ i ] = 0 ;
OutputDebugString ( buffer ) ;
}
# endif
}
else
{
if ( ( p = WMap [ u ] ) ! = NULL ) memcpy ( p + v , a , c ) ;
}
}
2024-03-20 07:46:28 +01:00
if ( ! bGrayscale ) UpdateDisplay ( d , c ) ; // update display
2024-03-20 07:41:14 +01:00
a + = c ;
d = ( d + c ) & 0xFFFFF ;
} while ( s - = c ) ;
return ;
}
DWORD Read5 ( DWORD d )
{
BYTE p [ 5 ] ;
Npeek ( p , d , 5 ) ;
return Npack ( p , 5 ) ;
}
BYTE Read2 ( DWORD d )
{
BYTE p [ 2 ] ;
Npeek ( p , d , 2 ) ;
return ( BYTE ) ( p [ 0 ] | ( p [ 1 ] < < 4 ) ) ;
}
VOID Write5 ( DWORD d , DWORD n )
{
BYTE p [ 5 ] ;
Nunpack ( p , n , 5 ) ;
Nwrite ( p , d , 5 ) ;
return ;
}
VOID Write2 ( DWORD d , BYTE n )
{
BYTE p [ 2 ] ;
Nunpack ( p , n , 2 ) ;
Nwrite ( p , d , 2 ) ;
return ;
}
VOID IOBit ( DWORD d , BYTE b , BOOL s ) // set/clear bit in I/O section
{
EnterCriticalSection ( & csIOLock ) ;
{
if ( s )
Chipset . IORam [ d ] | = b ; // set bit
else
Chipset . IORam [ d ] & = ~ b ; // clear bit
}
LeaveCriticalSection ( & csIOLock ) ;
}
2024-03-20 07:46:28 +01:00
static DWORD ReadT2Acc ( VOID )
{
static DWORD dwCyc = 0 ; // CPU cycle counter at last timer2 read access
DWORD dwCycDif ;
// CPU cycles since last call
dwCycDif = ( DWORD ) ( Chipset . cycles & 0xFFFFFFFF ) - dwCyc ;
dwCyc = ( DWORD ) ( Chipset . cycles & 0xFFFFFFFF ) ;
// maybe CPU speed measurement, slow down the next 10 CPU opcodes
if ( dwCycDif < 150 )
{
2024-03-20 07:46:29 +01:00
InitAdjustSpeed ( ) ; // init variables if necessary
2024-03-20 07:46:28 +01:00
EnterCriticalSection ( & csSlowLock ) ;
{
nOpcSlow = 10 ; // slow down next 10 opcodes
}
LeaveCriticalSection ( & csSlowLock ) ;
}
return ReadT2 ( ) ;
}
2024-03-20 07:46:28 +01:00
2024-03-20 07:41:14 +01:00
VOID ReadIO ( BYTE * a , DWORD d , DWORD s , BOOL bUpdate )
{
2024-03-20 07:46:28 +01:00
BOOL bNINT , bNINT2 ;
BOOL bLBI , bVLBI ;
2024-03-20 07:41:14 +01:00
BYTE c = 0xFF ; // LINECOUNT not initialized
BOOL rbr_acc = FALSE ; // flag to receive data
# if defined DEBUG_IO
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: IO read : %02x,%u \n " ) , Chipset . pc , d , s ) ;
OutputDebugString ( buffer ) ;
}
# endif
do
{
switch ( d )
{
case 0x00 : * a = ( Chipset . IORam [ d ] & DON ) | Chipset . boffset ; break ;
case 0x01 : * a = Chipset . contrast & 0xF ; break ;
case 0x02 : * a = Chipset . contrast > > 4 ; break ;
case 0x03 : * a = 0 ;
case 0x04 : * a = ( Chipset . crc ) & 0xF ; break ;
case 0x05 : * a = ( Chipset . crc > > 4 ) & 0xF ; break ;
case 0x06 : * a = ( Chipset . crc > > 8 ) & 0xF ; break ;
case 0x07 : * a = ( Chipset . crc > > 12 ) & 0xF ; break ;
2024-03-20 07:46:28 +01:00
case 0x08 : // LPD
// LB2 and LB1 not emulated, must be 0
_ASSERT ( ( Chipset . IORam [ LPD ] & ( LB2 | LB1 ) ) = = 0 ) ;
GetBatteryState ( & bLBI , & bVLBI ) ; // get battery state
// check if battery states enabled
bLBI = bLBI & & ( ( Chipset . IORam [ LPE ] & ELBI ) ! = 0 ) ;
bVLBI = bVLBI & & ( ( Chipset . IORam [ LPE ] & EVLBI ) ! = 0 ) ;
// set IO bits
IOBit ( LPD , LB0 , bLBI ) ;
IOBit ( LPD , VLBI , bVLBI ) ;
IOBit ( SRQ1 , VSRQ , bVLBI ) ;
* a = Chipset . IORam [ d ] ;
break ;
2024-03-20 07:41:14 +01:00
case 0x09 : // LPE
* a = Chipset . IORam [ d ] ;
if ( bUpdate )
{
Chipset . IORam [ d ] & = ~ RST ; // clear RST bit after reading
}
break ;
case 0x0A : * a = 0 ; break ;
// case 0x0B: *a = Chipset.IORam[d]; break;
// case 0x0C: *a = Chipset.IORam[d]; break;
case 0x0D : // BAUD
2024-03-20 07:46:28 +01:00
if ( isModelApple ( cCurrentRomType ) )
2024-03-20 07:41:14 +01:00
{
2024-03-20 07:46:28 +01:00
* a = Chipset . IORam [ d ] ;
# if defined DEBUG_SERIAL // return BAUD value
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: BAUD Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
} // Clarke / Yorke chip
else
{
* a = Chipset . IORam [ d ] & 0x7 ;
2024-03-20 07:46:28 +01:00
# if defined DEBUG_SERIAL // return BAUD value
if ( bUpdate )
2024-03-20 07:46:28 +01:00
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: BAUD Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
* a | = UckBit ( * a ) ; // add UCK bit to BAUD rate register
2024-03-20 07:41:14 +01:00
}
break ;
case 0x0E :
// SMP is !NINT and SWINT is always 0
// clear SMP and SWINT bit
Chipset . IORam [ d ] & = ( ECDT | RCDT ) ;
// SMP is !NINT
if ( ( Chipset . IORam [ SRQ2 ] & NINT ) = = 0 )
Chipset . IORam [ d ] | = SMP ;
* a = Chipset . IORam [ d ] ;
break ;
case 0x0F :
// card detection disabled
if ( ( Chipset . IORam [ CARDCTL ] & ECDT ) = = 0 )
{
* a = 0 ; // no cards
}
else
{
2024-03-20 07:46:28 +01:00
// on a HP30/40G and HP49G Chipset.cards_status bust always be 0xF
_ASSERT ( ( cCurrentRomType ! = ' E ' & & cCurrentRomType ! = ' X ' & & cCurrentRomType ! = ' 2 ' & & cCurrentRomType ! = ' P ' & & cCurrentRomType ! = ' Q ' ) | | Chipset . cards_status = = 0xF ) ; // CdB for HP: add apples
2024-03-20 07:41:14 +01:00
* a = Chipset . cards_status ;
}
break ;
case 0x10 : // IO CONTROL
* a = Chipset . IORam [ d ] ; // return IO CONTROL value
# if defined DEBUG_SERIAL
2024-03-20 07:46:28 +01:00
if ( bUpdate )
2024-03-20 07:41:14 +01:00
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: IOC Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
case 0x11 : // RCS
* a = Chipset . IORam [ d ] | RX ; // return RCS value
# if defined DEBUG_SERIAL
2024-03-20 07:46:28 +01:00
if ( bUpdate )
2024-03-20 07:41:14 +01:00
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: RCS Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
case 0x12 : // TCS
* a = Chipset . IORam [ d ] ; // return TCS value
2024-03-20 07:46:29 +01:00
if ( ( * a & TBF ) ) // Transmit buffer full
{
// the G-series XModem implementation has a timeout loop counter
// waiting for transmit buffer empty, so on fast hosts with
// CPU running with max. speed we may get a timeout overflow
// -> to avoid this slow down CPU speed on transmit buffer full
InitAdjustSpeed ( ) ; // init variables if necessary
EnterCriticalSection ( & csSlowLock ) ;
{
nOpcSlow = 10 ; // slow down next 10 opcodes
}
LeaveCriticalSection ( & csSlowLock ) ;
}
2024-03-20 07:41:14 +01:00
# if defined DEBUG_SERIAL
2024-03-20 07:46:28 +01:00
if ( bUpdate )
2024-03-20 07:41:14 +01:00
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: TCS Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
case 0x13 : // CRER
* a = 0 ;
break ;
case 0x14 : // RBR LSB
case 0x15 : // RBR MSB
if ( bUpdate )
{
* a = Chipset . IORam [ d ] ; // return RBR value
2024-03-20 07:46:29 +01:00
if ( d = = 0x15 ) // reading RBR MSB
{
Chipset . IORam [ RCS ] & = ~ RBF ; // clear Receive Buffer Full flag
}
2024-03-20 07:41:14 +01:00
UpdateUSRQ ( ) ; // update USRQ
rbr_acc = TRUE ; // search for new RBR value
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: RBR %s Read: %x \n " ) , Chipset . pc , ( d = = 0x14 ) ? " LSB " : " MSB " , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
}
else
{
* a = Chipset . IORam [ d ] ; // return RBR value
UpdateUSRQ ( ) ; // update USRQ
}
break ;
// case 0x16: *a = Chipset.IORam[d]; break; // TBR LSB
// case 0x17: *a = Chipset.IORam[d]; break; // TBR MSB
case 0x19 : // SREQ? MSB
UpdateKdnBit ( ) ; // update KDN bit
bNINT2 = Chipset . IORam [ SRQ1 ] = = 0 & & ( Chipset . IORam [ SRQ2 ] & LSRQ ) = = 0 ;
bNINT = ( Chipset . IORam [ SRQ2 ] & NINT ) ! = 0 ;
// card detection off and timer running
if ( ( Chipset . IORam [ CARDCTL ] & ECDT ) = = 0 & & ( Chipset . IORam [ TIMER2_CTRL ] & RUN ) ! = 0 )
{
// state of CDT2
bNINT2 = bNINT2 & & ( Chipset . cards_status & ( P2W | P2C ) ) ! = P2C ;
// state of CDT1
bNINT = bNINT & & ( Chipset . cards_status & ( P1W | P1C ) ) ! = P1C ;
}
IOBit ( SRQ2 , NINT2 , bNINT2 ) ;
IOBit ( SRQ2 , NINT , bNINT ) ;
// no break!
case 0x18 : // SREQ? LSB
* a = Chipset . IORam [ d ] ; // return SREQ value
# if defined DEBUG_SERIAL
2024-03-20 07:46:28 +01:00
if ( bUpdate )
2024-03-20 07:41:14 +01:00
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: SEQ %s Read: %x \n " ) , Chipset . pc , ( d = = 0x18 ) ? " LSB " : " MSB " , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
case 0x1A : // IR CONTROL
if ( cCurrentRomType = = ' E ' ) // HP39/40G
{
Chipset . IORam [ d ] = ( nCurrentClass ! = 40 )
2024-03-20 07:46:28 +01:00
? ( Chipset . IORam [ d ] & ~ IRI ) // HP39G
2024-03-20 07:41:14 +01:00
: ( Chipset . IORam [ d ] | IRI ) ; // HP40G
}
* a = Chipset . IORam [ d ] ; // return IR CONTROL value
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: IRC Read: %x \n " ) , Chipset . pc , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
case 0x1B : * a = 0 ; break ;
2024-03-20 07:46:28 +01:00
case 0x1C : // LED CONTROL
// put LBF and LBZ always to zero to indicate a free REDEYE buffer and formatter
* a = ( Chipset . IORam [ d ] & ( LED | ELBE ) ) ;
break ;
case 0x1D : // LED BUFFER
* a = ( Chipset . IORam [ d ] & LBO ) ;
break ;
2024-03-20 07:41:14 +01:00
// case 0x1E: *a = Chipset.IORam[d]; break;
// case 0x1F: *a = Chipset.IORam[d]; break;
case 0x20 : * a = 3 ; break ;
case 0x21 : * a = 3 ; break ;
case 0x22 : * a = 3 ; break ;
case 0x23 : * a = 3 ; break ;
case 0x24 : * a = 3 ; break ;
case 0x25 : * a = 3 ; break ;
case 0x26 : * a = 3 ; break ;
case 0x27 : * a = 3 ; break ;
case 0x28 : // LINECOUNT LSB
case 0x29 : // LINECOUNT MSB + DA19 M32
if ( Chipset . IORam [ 0x00 ] & DON ) // display on
{
if ( c = = 0xFF ) // no actual line information
{
c = GetLineCounter ( ) ; // get LCD update line
// save line information in IO registers
Chipset . IORam [ 0x28 ] = c & 0xF ;
Chipset . IORam [ 0x29 ] = ( Chipset . IORam [ 0x29 ] & ( DA19 | M32 ) ) | ( c > > 4 ) ;
}
}
* a = Chipset . IORam [ d ] ;
if ( d = = 0x29 ) // address 0x29 is mirrored to 0x2A-0x2D
{
Chipset . IORam [ 0x2A ] = * a ;
Chipset . IORam [ 0x2B ] = * a ;
Chipset . IORam [ 0x2C ] = * a ;
Chipset . IORam [ 0x2D ] = * a ;
}
break ;
// case 0x2A: *a = 0; break;
// case 0x2B: *a = 0; break;
// case 0x2C: *a = 0; break;
// case 0x2D: *a = 0; break;
case 0x2E :
ReadT1 ( ) ; // dummy read for update timer1 control register
* a = Chipset . IORam [ d ] ;
break ;
case 0x2F :
ReadT2 ( ) ; // dummy read for update timer2 control register
* a = Chipset . IORam [ d ] ;
break ;
case 0x30 : * a = 3 ; break ;
case 0x31 : * a = 3 ; break ;
case 0x32 : * a = 3 ; break ;
case 0x33 : * a = 3 ; break ;
case 0x34 : * a = 3 ; break ;
case 0x35 : * a = 0 ; break ;
case 0x36 : * a = 0 ; break ;
case 0x37 : * a = ReadT1 ( ) ; break ;
2024-03-20 07:46:28 +01:00
case 0x38 : Nunpack ( a , ReadT2Acc ( ) , s ) ; return ;
case 0x39 : Nunpack ( a , ReadT2Acc ( ) > > 4 , s ) ; return ;
case 0x3A : Nunpack ( a , ReadT2Acc ( ) > > 8 , s ) ; return ;
case 0x3B : Nunpack ( a , ReadT2Acc ( ) > > 12 , s ) ; return ;
case 0x3C : Nunpack ( a , ReadT2Acc ( ) > > 16 , s ) ; return ;
case 0x3D : Nunpack ( a , ReadT2Acc ( ) > > 20 , s ) ; return ;
case 0x3E : Nunpack ( a , ReadT2Acc ( ) > > 24 , s ) ; return ;
case 0x3F : Nunpack ( a , ReadT2Acc ( ) > > 28 , s ) ; return ;
2024-03-20 07:41:14 +01:00
default : * a = Chipset . IORam [ d ] ;
}
d + + ; a + + ;
} while ( - - s ) ;
if ( rbr_acc ) CommReceive ( ) ; // look for new character
return ;
}
VOID WriteIO ( BYTE * a , DWORD d , DWORD s )
{
DWORD b ;
BYTE c ;
BOOL tbr_acc = FALSE ; // flag to transmit data
BOOL bDISPADDR = FALSE ; // flag addr 0x120-0x124 changed
BOOL bLINEOFFS = FALSE ; // flag addr 0x125-0x127 changed
BOOL bMENUADDR = FALSE ; // flag addr 0x130-0x134 changed
2024-03-20 07:46:28 +01:00
DWORD dwAnnunciator = 0 ; // no annunciator write
2024-03-20 07:41:14 +01:00
# if defined DEBUG_IO
{
TCHAR buffer [ 256 ] ;
DWORD j ;
int i ;
i = wsprintf ( buffer , _T ( " %.5lx: IO write: %02x,%u = " ) , Chipset . pc , d , s ) ;
for ( j = 0 ; j < s ; + + j , + + i )
{
buffer [ i ] = a [ j ] ;
if ( buffer [ i ] > 9 ) buffer [ i ] + = _T ( ' a ' ) - _T ( ' 9 ' ) - 1 ;
buffer [ i ] + = _T ( ' 0 ' ) ;
}
buffer [ i + + ] = _T ( ' \n ' ) ;
buffer [ i ] = 0 ;
OutputDebugString ( buffer ) ;
}
# endif
do
{
c = * a ;
switch ( d )
{
// 00100 = NS:DISPIO
// 00100 @ Display bit offset and DON [DON OFF2 OFF1 OFF0]
// 00100 @ 3 nibs for display offset (scrolling), DON=Display ON
case 0x00 :
if ( ( c ^ Chipset . IORam [ d ] ) & DON ) // DON bit changed
{
disp | = ( DISP_POINTER | DISP_MAIN | DISP_MENUE ) ;
// adjust VBL counter start/stop values
if ( ( c & DON ) ! = 0 ) // set display on
{
Chipset . IORam [ d ] | = DON ; // for StartDisplay();
UpdateContrast ( Chipset . contrast ) ;
StartDisplay ( ( BYTE ) Chipset . lcounter ) ; // start display update
}
else // display is off
{
Chipset . IORam [ d ] & = ~ DON ;
UpdateContrast ( Chipset . contrast ) ;
StopDisplay ( ) ; // stop display update
}
}
// OFF bits changed
if ( ( c ^ Chipset . IORam [ d ] ) & ( OFF2 | OFF1 | OFF0 ) )
{
Chipset . boffset = c & ( OFF2 | OFF1 | OFF0 ) ;
disp | = ( DISP_POINTER | DISP_MAIN ) ;
}
Chipset . IORam [ d ] = c ;
break ;
// 00101 = NS:CONTRLSB
// 00101 @ Contrast Control [CON3 CON2 CON1 CON0]
// 00101 @ Higher value = darker screen
case 0x01 :
if ( c ! = Chipset . IORam [ d ] )
{
Chipset . IORam [ d ] = c ;
Chipset . contrast = ( Chipset . contrast & 0x10 ) | c ;
UpdateContrast ( Chipset . contrast ) ;
disp | = ( DISP_MAIN | DISP_MENUE ) ;
}
break ;
// 00102 = NS:DISPTEST
// 00102 @ Display test [VDIG LID TRIM CON4] [LRT LRTD LRTC BIN]
// 00102 @ Normally zeros
case 0x02 :
if ( c ! = Chipset . IORam [ d ] )
{
Chipset . IORam [ d ] = c ;
Chipset . contrast = ( Chipset . contrast & 0x0f ) | ( ( c & 1 ) < < 4 ) ;
UpdateContrast ( Chipset . contrast ) ;
disp | = ( DISP_MAIN | DISP_MENUE ) ;
}
break ;
case 0x03 : Chipset . IORam [ d ] = c ; break ;
// 00104 = HP:CRC
// 00104 @ 16 bit hardware CRC (104-107) (X^16+X^12+X^5+1)
// 00104 @ crc = ( crc >> 4 ) ^ ( ( ( crc ^ nib ) & 0x000F ) * 0x1081 );
case 0x04 : Chipset . crc = ( Chipset . crc & 0xfff0 ) | ( c * 0x0001 ) ; break ;
case 0x05 : Chipset . crc = ( Chipset . crc & 0xff0f ) | ( c * 0x0010 ) ; break ;
case 0x06 : Chipset . crc = ( Chipset . crc & 0xf0ff ) | ( c * 0x0100 ) ; break ;
case 0x07 : Chipset . crc = ( Chipset . crc & 0x0fff ) | ( c * 0x1000 ) ; break ;
// 00108 = NS:POWERSTATUS
// 00108 @ Low power registers (108-109)
// 00108 @ [LB2 LB1 LB0 VLBI] (read only)
// 00108 @ LowBat(2) LowBat(1) LowBat(S) VeryLowBat
case 0x08 : break ; // read-only
// 00109 = NS:POWERCTRL
// 00109 @ [ELBI EVLBI GRST RST] (read/write)
case 0x09 :
Chipset . IORam [ d ] = c ;
if ( c & RST )
{
CpuReset ( ) ; // emulate NRES signal
2024-03-20 07:46:28 +01:00
disp | = ( DISP_POINTER | DISP_MAIN | DISP_MENUE ) ;
dwAnnunciator = 0x3F ; // update all annunciators
2024-03-20 07:41:14 +01:00
bInterrupt = TRUE ; // SHUTDN
}
break ;
// 0010A = NS:MODE
// 0010A @ Mode Register (read-only)
case 0x0A : break ; // read-only
// 0010B = HP:ANNCTRL
// 0010B @ Annunciator control [LA4 LA3 LA2 LA1] = [ alarm alpha -> <- ]
case 0x0B :
case 0x0C :
2024-03-20 07:46:28 +01:00
// annunciator changed
dwAnnunciator | = ( ( Chipset . IORam [ d ] ^ c ) < < ( ( d - 0x0B ) * 4 ) ) & 0x3F ;
Chipset . IORam [ d ] = c ;
2024-03-20 07:41:14 +01:00
break ;
// 0010D = NS:BAUD
// 0010D @ Serial baud rate [UCK BD2 BD1 BD0] (bit 3 is read-only)
// 0010D @ 3 bits = {1200 1920 2400 3840 4800 7680 9600 15360}
case 0x0D :
2024-03-20 07:46:28 +01:00
if ( isModelApple ( cCurrentRomType ) )
{
Chipset . IORam [ d ] = c ;
}
else // Clarke / Yorke chip
{
2024-03-20 07:46:28 +01:00
Chipset . IORam [ d ] = ( Chipset . IORam [ d ] & 8 ) | ( c & 7 ) ; // bit 3 is read-only
2024-03-20 07:46:28 +01:00
}
2024-03-20 07:41:14 +01:00
CommSetBaud ( ) ; // set baudrate
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: BAUD write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
// 0010E = NS:CARDCTL
// 0010E @ [ECDT RCDT SMP SWINT] (read/write)
// 0010E @ Enable Card Det., Run Card Det., Set Module Pulled, Software interrupt
case 0x0E :
if ( c & SWINT ) // SWINT bit set
{
c & = ( ECDT | RCDT | SMP ) ; // clear SWINT bit
Chipset . SoftInt = TRUE ;
bInterrupt = TRUE ;
}
if ( ( c & SMP ) = = 0 ) // SMP bit cleared
{
BOOL bNINT = TRUE ; // ack NINT interrupt -> NINT high
// card detect disabled and CDT1 low -> retrigger
if ( ( c & ECDT ) = = 0 & & ( Chipset . IORam [ TIMER2_CTRL ] & RUN ) ! = 0 )
bNINT = ( Chipset . cards_status & ( P1W | P1C ) ) ! = P1C ;
IOBit ( SRQ2 , NINT , bNINT ) ;
}
// falling edge of Enable Card Detect bit and timer running
if ( ( ( c ^ Chipset . IORam [ d ] ) & ECDT ) ! = 0 & & ( c & ECDT ) = = 0
& & ( Chipset . IORam [ TIMER2_CTRL ] & RUN ) ! = 0 )
{
BOOL bNINT = ( Chipset . IORam [ SRQ2 ] & NINT ) ! = 0 ;
// card in slot1 isn't Read Only
if ( ( Chipset . cards_status & ( P1W | P1C ) ) ! = P1C )
{
// use random state of NINT line
bNINT = bNINT & & ( ReadT2 ( ) & 0x1 ) ! = 0 ;
}
IOBit ( SRQ2 , NINT , bNINT ) ;
Chipset . HST | = MP ; // set Module Pulled
// Port1 and Port2 plugged and writeable or NINT2/NINT interrupt
if ( Chipset . cards_status ! = ( P2W | P1W | P2C | P1C )
| | ( Chipset . IORam [ SRQ2 ] & NINT2 ) = = 0
| | ( Chipset . IORam [ SRQ2 ] & NINT ) = = 0
)
{
Chipset . SoftInt = TRUE ; // set interrupt
bInterrupt = TRUE ;
}
}
Chipset . IORam [ d ] = c ;
break ;
// 0010F = NS:CARDSTATUS
// 0010F @ [P2W P1W P2C P1C] (read-only) Port 2 writable .. Port 1 inserted
case 0x0F : break ; // read-only
// 00110 = HP:IOC
// 00110 @ Serial I/O Control [SON ETBE ERBF ERBZ]
// 00110 @ Serial On, Interrupt On Recv.Buf.Empty, Full, Buzy
case 0x10 :
Chipset . IORam [ d ] = c ;
CheckSerial ( ) ; // handle UART on/off
if ( ( c & SON ) = = 0 ) // SON bit cleared
{
Chipset . IORam [ IOC ] = 0 ; // clear IOC
Chipset . IORam [ RCS ] = 0 ; // clear RCS
Chipset . IORam [ TCS ] = 0 ; // clear TCS
Chipset . IORam [ RBR_LSB ] = 0 ; // clear RBR
Chipset . IORam [ RBR_MSB ] = 0 ;
Chipset . IORam [ TBR_LSB ] = 0 ; // clear TBR
Chipset . IORam [ TBR_MSB ] = 0 ;
}
if ( UpdateUSRQ ( ) ) INTERRUPT ; // update USRQ bit
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: IOC write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
// 00111 = HP:RCS
// 00111 Serial Receive Control/Status [RX RER RBZ RBF] (bit 3 is read-only)
case 0x11 :
if ( Chipset . IORam [ IOC ] & SON )
{
EnterCriticalSection ( & csIOLock ) ;
{
// critical section because of RER access
Chipset . IORam [ d ] = ( Chipset . IORam [ d ] & 8 ) | ( c & 7 ) ;
}
LeaveCriticalSection ( & csIOLock ) ;
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: RCS write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
}
break ;
// 00112 = HP:TCS
// 00112 @ Serial Transmit Control/Status [BRK LPB TBZ TBF]
case 0x12 :
if ( Chipset . IORam [ IOC ] & SON )
{
Chipset . IORam [ d ] = c ;
CommTxBRK ( ) ; // update BRK condition
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: TCS write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
}
break ;
// 00113 = HP:CRER
// 00113 @ Serial Clear RER (writing anything clears RER bit)
case 0x13 :
IOBit ( RCS , RER , FALSE ) ;
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: CRER write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
// 00114 = HP:RBR
// 00114 @ Serial Receive Buffer Register (Reading clears RBF bit)
case 0x14 : break ; // read-only
case 0x15 : break ; // read-only
// 00116 = HP:TBR
// 00116 @ Serial Transmit Buffer Register (Writing sets TBF bit)
case 0x16 :
case 0x17 :
if ( Chipset . IORam [ IOC ] & SON )
{
Chipset . IORam [ d ] = c ;
tbr_acc = TRUE ; // new TBR value
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: TBR %s write: %x \n " ) , Chipset . pc , ( d = = 0x16 ) ? " LSB " : " MSB " , * a ) ;
OutputDebugString ( buffer ) ;
}
# endif
}
break ;
// 00118 = NS:SRR
// 00118 @ Service Request Register (read-only)
// 00118 @ [ISRQ TSRQ USRQ VSRQ] [KDN NINT2 NINT LSRQ]
case 0x18 : break ; // read-only
case 0x19 : break ; // read-only
// 0011A = HP:IRC
// 0011A @ IR Control Register [IRI EIRU EIRI IRE] (bit 3 is read-only)
// 0011A @ IR Input, Enable IR UART mode, Enable IR Interrupt, IR Event
case 0x1A :
2024-03-20 07:46:29 +01:00
// EIRU bit changed
if ( ( ( c ^ Chipset . IORam [ d ] ) & EIRU ) ! = 0 )
2024-03-20 07:41:14 +01:00
{
// save new value for COM open
Chipset . IORam [ d ] = ( Chipset . IORam [ d ] & 8 ) | ( c & 7 ) ;
// reopen COM port with new setting
2024-03-20 07:46:29 +01:00
CommOpen ( szSerialWire , szSerialIr ) ;
2024-03-20 07:41:14 +01:00
}
Chipset . IORam [ d ] = ( Chipset . IORam [ d ] & 8 ) | ( c & 7 ) ;
# if defined DEBUG_SERIAL
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: IRC write: %x \n " ) , Chipset . pc , Chipset . IORam [ d ] ) ;
OutputDebugString ( buffer ) ;
}
# endif
break ;
// 0011B = NS:BASENIBOFF
// 0011B @ Used as addressto get BASENIB from 11F to the 5th nibble
case 0x1B : break ;
// 0011C = NS:LCR
// 0011C @ Led Control Register [LED ELBE LBZ LBF] (Setting LED is draining)
case 0x1C :
// HP49G new mapping on LED bit change
if ( cCurrentRomType = = ' X ' & & ( ( c ^ Chipset . IORam [ d ] ) & LED ) )
{
Chipset . IORam [ d ] = c ; // save new value for mapping
Map ( Chipset . P2Base , Chipset . P2End ) ; // new ROM mapping
# if defined DEBUG_FLASH
{
TCHAR buffer [ 256 ] ;
wsprintf ( buffer , _T ( " %.5lx: NCE3: R%cM \n " ) , Chipset . pc , ( c & LED ) ? ' O ' : ' A ' ) ;
OutputDebugString ( buffer ) ;
}
# endif
}
2024-03-20 07:46:28 +01:00
// Saturnator on apples has no ELBE bit simulation
if ( cCurrentRomType ! = ' Q ' & & cCurrentRomType ! = ' 2 ' & & cCurrentRomType ! = ' P ' )
{
if ( ( c ^ Chipset . IORam [ d ] ) & ELBE ) // ELBE bit changed
{
// Led Service ReQuest on Led Buffer Empty enabled
BOOL bLSRQ = ( c & ( ELBE | LBF ) ) = = ELBE ;
IOBit ( SRQ2 , LSRQ , bLSRQ ) ; // update LSRQ bit
if ( bLSRQ ) // interrupt on Led Buffer Empty enabled
{
Chipset . SoftInt = TRUE ;
bInterrupt = TRUE ;
}
}
}
2024-03-20 07:41:14 +01:00
Chipset . IORam [ d ] = c ;
break ;
// 0011D = NS:LBR
// 0011D @ Led Buffer Register [0 0 0 LBO] (bits 1-3 read zero)
2024-03-20 07:46:28 +01:00
case 0x1D :
IrPrinter ( ( BYTE ) ( c & LBO ) ) ;
Chipset . IORam [ d ] = c & LBO ;
break ;
2024-03-20 07:41:14 +01:00
// 0011E = NS:SCRATCHPAD
// 0011E @ Scratch pad
case 0x1E : Chipset . IORam [ d ] = c ; break ;
// 0011F = NS:BASENIB
// 0011F @ 7 or 8 for base memory
case 0x1F : Chipset . IORam [ d ] = c ; break ;
// 00120 = NS:DISPADDR
// 00120 @ Display Start Address (write only)
// 00120 @ bit 0 is ignored (display must start on byte boundary)
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
Chipset . IORam [ d ] = c ;
bDISPADDR = TRUE ; // addr 0x120-0x124 changed
break ;
// 00125 = NS:LINEOFFS
// 00125 @ Display Line offset (write only) (no of bytes skipped after each line)
// 00125 @ MSG sign extended
case 0x25 :
case 0x26 :
case 0x27 :
Chipset . IORam [ d ] = c ;
bLINEOFFS = TRUE ; // addr 0x125-0x127 changed
break ;
// 00128 = NS:LINECOUNT
// 00128 @ Display Line Counter and miscellaneous (28-29)
// 00128 @ [LC3 LC2 LC1 LC0] [DA19 M32 LC5 LC4]
// 00128 @ Line counter 6 bits -> max = 2^6-1 = 63 = disp height
// 00128 @ Normally has 55 -> Menu starts at display row 56
case 0x28 :
// LSB of LINECOUNT changed
if ( c ! = ( BYTE ) ( Chipset . lcounter & 0xf ) )
{
Chipset . lcounter = ( Chipset . lcounter & ~ 0xF ) | c ;
disp | = ( DISP_POINTER | DISP_MAIN | DISP_MENUE ) ;
}
break ;
case 0x29 :
// MSB of LINECOUNT changed
b = ( c & 0x3 ) < < 4 ; // upper two bits
if ( b ! = ( Chipset . lcounter & 0x30 ) )
{
Chipset . lcounter = ( Chipset . lcounter & ~ 0x30 ) | b ;
disp | = ( DISP_POINTER | DISP_MAIN | DISP_MENUE ) ;
}
if ( ( c ^ Chipset . IORam [ d ] ) & DA19 ) // DA19 changed
{
Chipset . IORam [ d ] ^ = DA19 ; // save new DA19
Map ( 0x00 , 0xFF ) ; // new ROM mapping
}
break ;
case 0x2A : break ;
case 0x2B : break ;
case 0x2C : break ;
case 0x2D : break ;
// 0012E = NS:TIMER1CTRL
// 0012E @ TIMER1 Control [SRQ WKE INT XTRA]
case 0x2E :
Chipset . IORam [ d ] = c ; // don't clear XTRA bit
ReadT1 ( ) ; // dummy read for checking control bits
break ;
// 0012F = NS:TIMER2CTRL
// 0012F @ TIMER2 Control [SRQ WKE INT RUN]
case 0x2F :
Chipset . IORam [ d ] = c ;
ReadT2 ( ) ; // dummy read for checking control bits
if ( c & 1 )
StartTimers ( ) ;
else
StopTimers ( ) ;
2024-03-20 07:46:28 +01:00
dwAnnunciator = 0x3F ; // update all annunciators
2024-03-20 07:41:14 +01:00
break ;
// 00130 = NS:MENUADDR
// 00130 @ Display Secondary Start Address (write only) (30-34)
// 00130 @ Menu Display Address, no line offsets
case 0x30 :
case 0x31 :
case 0x32 :
case 0x33 :
case 0x34 :
Chipset . IORam [ d ] = c ;
bMENUADDR = TRUE ; // addr 0x130-0x134 changed
break ;
case 0x35 : break ;
case 0x36 : break ;
// 00137 = HP:TIMER1
// 00137 @ Decremented 16 times/s
case 0x37 :
SetT1 ( c ) ; // set new value
break ;
// 00138 = HP:TIMER2
// 00138 @ hardware timer (38-3F), decremented 8192 times/s
// nothing - fall through to default
default :
Chipset . IORam [ d ] = c ; // write data
if ( d > = TIMER2 ) // timer2 update
{
Nunpack ( Chipset . IORam + TIMER2 , ReadT2 ( ) , 8 ) ;
memcpy ( Chipset . IORam + d , a , s ) ;
SetT2 ( Npack ( Chipset . IORam + TIMER2 , 8 ) ) ;
goto finish ;
}
}
a + + ; d + + ;
} while ( - - s ) ;
finish :
if ( bDISPADDR ) // 0x120-0x124 changed
{
b = Npack ( Chipset . IORam + DISP1CTL , 5 ) & 0xFFFFE ;
if ( b ! = Chipset . start1 )
{
Chipset . start1 = b ;
disp | = ( DISP_POINTER | DISP_MAIN ) ;
}
}
if ( bLINEOFFS ) // addr 0x125-0x127 changed
{
signed short lo = ( signed short ) Npack ( Chipset . IORam + LINENIBS , 3 ) ;
if ( lo & 0x800 ) lo - = 0x1000 ;
if ( lo ! = Chipset . loffset )
{
Chipset . loffset = lo ;
disp | = ( DISP_POINTER | DISP_MAIN ) ;
}
}
if ( bMENUADDR ) // addr 0x130-0x134 changed
{
b = Npack ( Chipset . IORam + DISP2CTL , 5 ) & 0xFFFFE ;
if ( b ! = Chipset . start2 )
{
Chipset . start2 = b ;
disp | = ( DISP_POINTER | DISP_MENUE ) ;
}
}
if ( tbr_acc ) // addr 0x116-0x117 changed
{
IOBit ( TCS , TBF , TRUE ) ; // set transmit buffer full bit
CommTransmit ( ) ; // transmit char
}
if ( disp & DISP_POINTER )
{
disp & = ~ DISP_POINTER ; // display pointer updated
UpdateDisplayPointers ( ) ;
}
2024-03-20 07:46:28 +01:00
if ( dwAnnunciator )
2024-03-20 07:41:14 +01:00
{
2024-03-20 07:46:28 +01:00
UpdateAnnunciators ( dwAnnunciator ) ;
2024-03-20 07:41:14 +01:00
}
return ;
}