/* GLOBGLUE.c Copyright (C) 2003 Bernd Schmidt, Philip Cummins, Paul C. Pratt You can redistribute this file and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. You should have received a copy of the license along with this file; see the file COPYING. This file 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 license for more details. */ /* GLOBal GLUE (or GLOB of GLUE) Holds the program together. Some code here adapted from "custom.c" in vMac by Philip Cummins, in turn descended from code in the Un*x Amiga Emulator by Bernd Schmidt. */ #ifndef AllFiles #include "SYSDEPNS.h" #include "MYOSGLUE.h" #include "ENDIANAC.h" #include "EMCONFIG.h" #endif #include "GLOBGLUE.h" IMPORTPROC m68k_reset(void); IMPORTPROC IWM_Reset(void); IMPORTPROC SCC_Reset(void); IMPORTPROC SCSI_Reset(void); IMPORTPROC VIA1_Reset(void); #if EmVIA2 IMPORTPROC VIA2_Reset(void); #endif IMPORTPROC Sony_Reset(void); IMPORTPROC ExtnDisk_Access(CPTR p); IMPORTPROC ExtnSony_Access(CPTR p); #if EmVidCard IMPORTPROC ExtnVideo_Access(CPTR p); #endif IMPORTPROC Sony_SetQuitOnEject(void); IMPORTPROC m68k_IPLchangeNtfy(void); IMPORTPROC MINEM68K_Init( ui3b *fIPL); IMPORTFUNC ui5b GetCyclesRemaining(void); IMPORTPROC SetCyclesRemaining(ui5b n); IMPORTPROC SetHeadATTel(ATTep p); IMPORTFUNC ATTep FindATTel(CPTR addr); IMPORTFUNC ui5b SCSI_Access(ui5b Data, blnr WriteMem, CPTR addr); IMPORTFUNC ui5b SCC_Access(ui5b Data, blnr WriteMem, CPTR addr); IMPORTFUNC ui5b IWM_Access(ui5b Data, blnr WriteMem, CPTR addr); IMPORTFUNC ui5b VIA1_Access(ui5b Data, blnr WriteMem, CPTR addr); #if EmVIA2 IMPORTFUNC ui5b VIA2_Access(ui5b Data, blnr WriteMem, CPTR addr); #endif #if EmASC IMPORTFUNC ui5b ASC_Access(ui5b Data, blnr WriteMem, CPTR addr); #endif IMPORTFUNC ui3r get_vm_byte(CPTR addr); IMPORTFUNC ui4r get_vm_word(CPTR addr); IMPORTFUNC ui5r get_vm_long(CPTR addr); IMPORTPROC put_vm_byte(CPTR addr, ui3r b); IMPORTPROC put_vm_word(CPTR addr, ui4r w); IMPORTPROC put_vm_long(CPTR addr, ui5r l); GLOBALVAR ui5r my_disk_icon_addr; GLOBALPROC customreset(void) { IWM_Reset(); SCC_Reset(); SCSI_Reset(); VIA1_Reset(); #if EmVIA2 VIA2_Reset(); #endif Sony_Reset(); Extn_Reset(); #if CurEmMd <= kEmMd_Plus WantMacReset = trueblnr; /* kludge, code in Finder appears to do RESET and not expect to come back. Maybe asserting the RESET somehow causes other hardware compenents to later reset the 68000. */ #endif } GLOBALVAR ui3p RAM = nullpr; #if EmVidCard GLOBALVAR ui3p VidROM = nullpr; #endif #if IncludeVidMem GLOBALVAR ui3p VidMem = nullpr; #endif GLOBALVAR ui3b Wires[kNumWires]; #if WantDisasm IMPORTPROC m68k_WantDisasmContext(void); #endif #if WantDisasm GLOBALPROC dbglog_StartLine(void) { m68k_WantDisasmContext(); dbglog_writeCStr(" "); } #endif #if dbglog_HAVE GLOBALPROC dbglog_WriteMemArrow(blnr WriteMem) { if (WriteMem) { dbglog_writeCStr(" <- "); } else { dbglog_writeCStr(" -> "); } } #endif #if dbglog_HAVE GLOBALPROC dbglog_AddrAccess(char *s, ui5r Data, blnr WriteMem, ui5r addr) { dbglog_StartLine(); dbglog_writeCStr(s); dbglog_writeCStr("["); dbglog_writeHex(addr); dbglog_writeCStr("]"); dbglog_WriteMemArrow(WriteMem); dbglog_writeHex(Data); dbglog_writeReturn(); } #endif #if dbglog_HAVE GLOBALPROC dbglog_Access(char *s, ui5r Data, blnr WriteMem) { dbglog_StartLine(); dbglog_writeCStr(s); dbglog_WriteMemArrow(WriteMem); dbglog_writeHex(Data); dbglog_writeReturn(); } #endif #if dbglog_HAVE GLOBALPROC dbglog_WriteNote(char *s) { dbglog_StartLine(); dbglog_writeCStr(s); dbglog_writeReturn(); } #endif #if dbglog_HAVE GLOBALPROC dbglog_WriteSetBool(char *s, blnr v) { dbglog_StartLine(); dbglog_writeCStr(s); dbglog_writeCStr(" <- "); if (v) { dbglog_writeCStr("1"); } else { dbglog_writeCStr("0"); } dbglog_writeReturn(); } #endif LOCALVAR blnr GotOneAbnormal = falseblnr; #ifndef ReportAbnormalInterrupt #define ReportAbnormalInterrupt 0 #endif #if dbglog_HAVE GLOBALPROC DoReportAbnormal(char *s) #else GLOBALPROC DoReportAbnormal(void) #endif { #if dbglog_HAVE dbglog_StartLine(); dbglog_writeCStr("*** abnormal : "); dbglog_writeCStr(s); dbglog_writeReturn(); #endif if (! GotOneAbnormal) { WarnMsgAbnormal(); #if ReportAbnormalInterrupt SetInterruptButton(trueblnr); #endif GotOneAbnormal = trueblnr; } } /* map of address space */ #define kRAM_Base 0x00000000 /* when overlay off */ #if (CurEmMd == kEmMd_PB100) #define kRAM_ln2Spc 23 #elif (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) #define kRAM_ln2Spc 23 #else #define kRAM_ln2Spc 22 #endif #if IncludeVidMem #if CurEmMd == kEmMd_PB100 #define kVidMem_Base 0x00FA0000 #define kVidMem_ln2Spc 16 #else #define kVidMem_Base 0x00540000 #define kVidMem_ln2Spc 18 #endif #endif #if CurEmMd == kEmMd_PB100 #define kSCSI_Block_Base 0x00F90000 #define kSCSI_ln2Spc 16 #else #define kSCSI_Block_Base 0x00580000 #define kSCSI_ln2Spc 19 #endif #define kRAM_Overlay_Base 0x00600000 /* when overlay on */ #define kRAM_Overlay_Top 0x00800000 #if CurEmMd == kEmMd_PB100 #define kSCCRd_Block_Base 0x00FD0000 #define kSCC_ln2Spc 16 #else #define kSCCRd_Block_Base 0x00800000 #define kSCC_ln2Spc 22 #endif #if CurEmMd != kEmMd_PB100 #define kSCCWr_Block_Base 0x00A00000 #define kSCCWr_Block_Top 0x00C00000 #endif #if CurEmMd == kEmMd_PB100 #define kIWM_Block_Base 0x00F60000 #define kIWM_ln2Spc 16 #else #define kIWM_Block_Base 0x00C00000 #define kIWM_ln2Spc 21 #endif #if CurEmMd == kEmMd_PB100 #define kVIA1_Block_Base 0x00F70000 #define kVIA1_ln2Spc 16 #else #define kVIA1_Block_Base 0x00E80000 #define kVIA1_ln2Spc 19 #endif #if CurEmMd == kEmMd_PB100 #define kASC_Block_Base 0x00FB0000 #define kASC_ln2Spc 16 #endif #define kASC_Mask 0x00000FFF #if IncludeExtnPbufs LOCALFUNC tMacErr PbufTransferVM(CPTR Buffera, tPbuf i, ui5r offset, ui5r count, blnr IsWrite) { tMacErr result; ui5b contig; ui3p Buffer; label_1: if (0 == count) { result = mnvm_noErr; } else { Buffer = get_real_address0(count, ! IsWrite, Buffera, &contig); if (0 == contig) { result = mnvm_miscErr; } else { PbufTransfer(Buffer, i, offset, contig, IsWrite); offset += contig; Buffera += contig; count -= contig; goto label_1; } } return result; } #endif /* extension mechanism */ #if IncludeExtnPbufs #define kCmndPbufFeatures 1 #define kCmndPbufNew 2 #define kCmndPbufDispose 3 #define kCmndPbufGetSize 4 #define kCmndPbufTransfer 5 #endif #if IncludeExtnPbufs LOCALPROC ExtnParamBuffers_Access(CPTR p) { tMacErr result = mnvm_controlErr; switch (get_vm_word(p + ExtnDat_commnd)) { case kCmndVersion: put_vm_word(p + ExtnDat_version, 1); result = mnvm_noErr; break; case kCmndPbufFeatures: put_vm_long(p + ExtnDat_params + 0, 0); result = mnvm_noErr; break; case kCmndPbufNew: { tPbuf Pbuf_No; ui5b count = get_vm_long(p + ExtnDat_params + 4); /* reserved word at offset 2, should be zero */ result = PbufNew(count, &Pbuf_No); put_vm_word(p + ExtnDat_params + 0, Pbuf_No); } break; case kCmndPbufDispose: { tPbuf Pbuf_No = get_vm_word(p + ExtnDat_params + 0); /* reserved word at offset 2, should be zero */ result = CheckPbuf(Pbuf_No); if (mnvm_noErr == result) { PbufDispose(Pbuf_No); } } break; case kCmndPbufGetSize: { ui5r Count; tPbuf Pbuf_No = get_vm_word(p + ExtnDat_params + 0); /* reserved word at offset 2, should be zero */ result = PbufGetSize(Pbuf_No, &Count); if (mnvm_noErr == result) { put_vm_long(p + ExtnDat_params + 4, Count); } } break; case kCmndPbufTransfer: { ui5r PbufCount; tPbuf Pbuf_No = get_vm_word(p + ExtnDat_params + 0); /* reserved word at offset 2, should be zero */ ui5r offset = get_vm_long(p + ExtnDat_params + 4); ui5r count = get_vm_long(p + ExtnDat_params + 8); CPTR Buffera = get_vm_long(p + ExtnDat_params + 12); blnr IsWrite = (get_vm_word(p + ExtnDat_params + 16) != 0); result = PbufGetSize(Pbuf_No, &PbufCount); if (mnvm_noErr == result) { ui5r endoff = offset + count; if ((endoff < offset) /* overflow */ || (endoff > PbufCount)) { result = mnvm_eofErr; } else { result = PbufTransferVM(Buffera, Pbuf_No, offset, count, IsWrite); } } } break; } put_vm_word(p + ExtnDat_result, result); } #endif #if IncludeExtnHostTextClipExchange #define kCmndHTCEFeatures 1 #define kCmndHTCEExport 2 #define kCmndHTCEImport 3 #endif #if IncludeExtnHostTextClipExchange LOCALPROC ExtnHostTextClipExchange_Access(CPTR p) { tMacErr result = mnvm_controlErr; switch (get_vm_word(p + ExtnDat_commnd)) { case kCmndVersion: put_vm_word(p + ExtnDat_version, 1); result = mnvm_noErr; break; case kCmndHTCEFeatures: put_vm_long(p + ExtnDat_params + 0, 0); result = mnvm_noErr; break; case kCmndHTCEExport: { tPbuf Pbuf_No = get_vm_word(p + ExtnDat_params + 0); result = CheckPbuf(Pbuf_No); if (mnvm_noErr == result) { result = HTCEexport(Pbuf_No); } } break; case kCmndHTCEImport: { tPbuf Pbuf_No; result = HTCEimport(&Pbuf_No); put_vm_word(p + ExtnDat_params + 0, Pbuf_No); } break; } put_vm_word(p + ExtnDat_result, result); } #endif #define kFindExtnExtension 0x64E1F58A #define kDiskDriverExtension 0x4C9219E6 #if IncludeExtnPbufs #define kHostParamBuffersExtension 0x314C87BF #endif #if IncludeExtnHostTextClipExchange #define kHostClipExchangeExtension 0x27B130CA #endif #define kCmndFindExtnFind 1 #define kCmndFindExtnId2Code 2 #define kCmndFindExtnCount 3 #define kParamFindExtnTheExtn 8 #define kParamFindExtnTheId 12 LOCALPROC ExtnFind_Access(CPTR p) { tMacErr result = mnvm_controlErr; switch (get_vm_word(p + ExtnDat_commnd)) { case kCmndVersion: put_vm_word(p + ExtnDat_version, 1); result = mnvm_noErr; break; case kCmndFindExtnFind: { ui5b extn = get_vm_long(p + kParamFindExtnTheExtn); if (extn == kDiskDriverExtension) { put_vm_word(p + kParamFindExtnTheId, kExtnDisk); result = mnvm_noErr; } else #if IncludeExtnPbufs if (extn == kHostParamBuffersExtension) { put_vm_word(p + kParamFindExtnTheId, kExtnParamBuffers); result = mnvm_noErr; } else #endif #if IncludeExtnHostTextClipExchange if (extn == kHostClipExchangeExtension) { put_vm_word(p + kParamFindExtnTheId, kExtnHostTextClipExchange); result = mnvm_noErr; } else #endif if (extn == kFindExtnExtension) { put_vm_word(p + kParamFindExtnTheId, kExtnFindExtn); result = mnvm_noErr; } else { /* not found */ } } break; case kCmndFindExtnId2Code: { ui4r extn = get_vm_word(p + kParamFindExtnTheId); if (extn == kExtnDisk) { put_vm_long(p + kParamFindExtnTheExtn, kDiskDriverExtension); result = mnvm_noErr; } else #if IncludeExtnPbufs if (extn == kExtnParamBuffers) { put_vm_long(p + kParamFindExtnTheExtn, kHostParamBuffersExtension); result = mnvm_noErr; } else #endif #if IncludeExtnHostTextClipExchange if (extn == kExtnHostTextClipExchange) { put_vm_long(p + kParamFindExtnTheExtn, kHostClipExchangeExtension); result = mnvm_noErr; } else #endif if (extn == kExtnFindExtn) { put_vm_long(p + kParamFindExtnTheExtn, kFindExtnExtension); result = mnvm_noErr; } else { /* not found */ } } break; case kCmndFindExtnCount: put_vm_word(p + kParamFindExtnTheId, kNumExtns); result = mnvm_noErr; break; } put_vm_word(p + ExtnDat_result, result); } #define kDSK_Params_Hi 0 #define kDSK_Params_Lo 1 #define kDSK_QuitOnEject 3 /* obsolete */ LOCALVAR ui4b ParamAddrHi; LOCALPROC Extn_Access(ui5b Data, CPTR addr) { switch (addr) { case kDSK_Params_Hi: ParamAddrHi = Data; break; case kDSK_Params_Lo: { CPTR p = ParamAddrHi << 16 | Data; ParamAddrHi = (ui4b) - 1; if (kcom_callcheck == get_vm_word(p + ExtnDat_checkval)) { put_vm_word(p + ExtnDat_checkval, 0); switch (get_vm_word(p + ExtnDat_extension)) { case kExtnFindExtn: ExtnFind_Access(p); break; #if EmVidCard case kExtnVideo: ExtnVideo_Access(p); break; #endif #if IncludeExtnPbufs case kExtnParamBuffers: ExtnParamBuffers_Access(p); break; #endif #if IncludeExtnHostTextClipExchange case kExtnHostTextClipExchange: ExtnHostTextClipExchange_Access(p); break; #endif case kExtnDisk: ExtnDisk_Access(p); break; case kExtnSony: ExtnSony_Access(p); break; default: put_vm_word(p + ExtnDat_result, mnvm_controlErr); break; } } } break; case kDSK_QuitOnEject: /* obsolete, kept for compatibility */ Sony_SetQuitOnEject(); break; } } GLOBALPROC Extn_Reset(void) { ParamAddrHi = (ui4b) - 1; } /* implementation of read/write for everything but RAM and ROM */ #define kSCC_Mask 0x03 #define kVIA1_Mask 0x00000F #if EmVIA2 #define kVIA2_Mask 0x00000F #endif #define kIWM_Mask 0x00000F /* Allocated Memory Bandwidth for IWM */ #if CurEmMd <= kEmMd_512Ke #define ROM_CmpZeroMask 0 #elif CurEmMd <= kEmMd_Plus #define ROM_CmpZeroMask 0x00020000 #elif CurEmMd <= kEmMd_PB100 #define ROM_CmpZeroMask 0 #elif CurEmMd <= kEmMd_IIx #define ROM_CmpZeroMask 0 #else #error "ROM_CmpZeroMask not defined" #endif #define kROM_cmpmask (0x00F00000 | ROM_CmpZeroMask) #if CurEmMd <= kEmMd_512Ke #define Overlay_ROM_CmpZeroMask 0x00100000 #elif CurEmMd <= kEmMd_Plus #define Overlay_ROM_CmpZeroMask 0x00020000 #elif CurEmMd <= kEmMd_Classic #define Overlay_ROM_CmpZeroMask 0x00300000 #elif CurEmMd <= kEmMd_PB100 #define Overlay_ROM_CmpZeroMask 0 #elif CurEmMd <= kEmMd_IIx #define Overlay_ROM_CmpZeroMask 0 #else #error "Overlay_ROM_CmpZeroMask not defined" #endif enum { kMMDV_VIA1, #if EmVIA2 kMMDV_VIA2, #endif kMMDV_SCC, kMMDV_Extn, #if EmASC kMMDV_ASC, #endif kMMDV_SCSI, kMMDV_IWM, kNumMMDVs }; enum { #if CurEmMd >= kEmMd_SE kMAN_OverlayOff, #endif kNumMANs }; LOCALVAR ATTer ATTListA[MaxATTListN]; LOCALVAR ui4r LastATTel; LOCALPROC AddToATTList(ATTep p) { ui4r NewLast = LastATTel + 1; if (NewLast >= MaxATTListN) { ReportAbnormal("MaxATTListN not big enough"); } else { ATTListA[LastATTel] = *p; LastATTel = NewLast; } } LOCALPROC InitATTList(void) { LastATTel = 0; } LOCALPROC FinishATTList(void) { { /* add guard */ ATTer r; r.cmpmask = 0; r.cmpvalu = 0; r.usemask = 0; r.usebase = nullpr; r.Access = 0; AddToATTList(&r); } { ui4r i = LastATTel; ATTep p = &ATTListA[LastATTel]; ATTep h = nullpr; while (0 != i) { --i; --p; p->Next = h; h = p; } #if 0 /* verify list. not for final version */ { ATTep q1; ATTep q2; for (q1 = h; nullpr != q1->Next; q1 = q1->Next) { if ((q1->cmpvalu & ~ q1->cmpmask) != 0) { ReportAbnormal("ATTListA bad entry"); } for (q2 = q1->Next; nullpr != q2->Next; q2 = q2->Next) { ui5r common_mask = (q1->cmpmask) & (q2->cmpmask); if ((q1->cmpvalu & common_mask) == (q2->cmpvalu & common_mask)) { ReportAbnormal("ATTListA Conflict"); } } } } #endif SetHeadATTel(h); } } #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) LOCALPROC SetUp_RAM24(void) { ATTer r; ui5r bankbit = 0x00100000 << (((VIA2_iA7 << 1) | VIA2_iA6) << 1); #if kRAMa_Size == kRAMb_Size if (kRAMa_Size == bankbit) { /* properly set up balanced RAM */ r.cmpmask = 0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1); r.cmpvalu = 0; r.usemask = ((1 << kRAM_ln2Spc) - 1) & (kRAM_Size - 1); r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); } else #endif { bankbit &= 0x00FFFFFF; /* if too large, always use RAMa */ if (0 != bankbit) { #if kRAMb_Size != 0 r.cmpmask = bankbit | (0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = bankbit; r.usemask = ((1 << kRAM_ln2Spc) - 1) & (kRAMb_Size - 1); r.usebase = kRAMa_Size + RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif } { r.cmpmask = bankbit | (0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = 0; r.usemask = ((1 << kRAM_ln2Spc) - 1) & (kRAMa_Size - 1); r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); } } } #endif #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) LOCALPROC SetUp_io(void) { ATTer r; if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_VIA1; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x2000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x2000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_VIA2; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x4000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x4000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_SCC; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x0C000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x0C000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_Extn; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x10000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x10000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_SCSI; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x14000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x14000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_ASC; AddToATTList(&r); if (Addr32) { r.cmpmask = 0xFF01E000; r.cmpvalu = 0x50000000 | 0x16000; } else { r.cmpmask = 0x00F1E000; r.cmpvalu = 0x00F00000 | 0x16000; } r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_IWM; AddToATTList(&r); #if 0 case 14: /* fail, nothing supposed to be here, but rom accesses it anyway */ { ui5r addr2 = addr & 0x1FFFF; if ((addr2 != 0x1DA00) && (addr2 != 0x1DC00)) { ReportAbnormal("another unknown access"); } } get_fail_realblock(p); break; #endif } #endif #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) LOCALPROC SetUp_address24(void) { ATTer r; if (MemOverlay) { ReportAbnormal("Overlay with 24 bit addressing"); } if (MemOverlay) { r.cmpmask = Overlay_ROM_CmpZeroMask | (0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = kRAM_Base; r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; AddToATTList(&r); } else { SetUp_RAM24(); } r.cmpmask = kROM_cmpmask; r.cmpvalu = kROM_Base; r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; AddToATTList(&r); r.cmpmask = 0x00FFFFFF & ~ (0x100000 - 1); r.cmpvalu = 0x900000; r.usemask = (kVidMemRAM_Size - 1) & (0x100000 - 1); r.usebase = VidMem; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #if kVidMemRAM_Size >= 0x00200000 r.cmpmask = 0x00FFFFFF & ~ (0x100000 - 1); r.cmpvalu = 0xA00000; r.usemask = (0x100000 - 1); r.usebase = VidMem + (1 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif #if kVidMemRAM_Size >= 0x00400000 r.cmpmask = 0x00FFFFFF & ~ (0x100000 - 1); r.cmpvalu = 0xB00000; r.usemask = (0x100000 - 1); r.usebase = VidMem + (2 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); r.cmpmask = 0x00FFFFFF & ~ (0x100000 - 1); r.cmpvalu = 0xC00000; r.usemask = (0x100000 - 1); r.usebase = VidMem + (3 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif SetUp_io(); } #endif #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) LOCALPROC SetUp_address32(void) { ATTer r; if (MemOverlay) { r.cmpmask = ~ ((1 << 30) - 1); r.cmpvalu = 0; r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; AddToATTList(&r); } else { ui5r bankbit = 0x00100000 << (((VIA2_iA7 << 1) | VIA2_iA6) << 1); #if kRAMa_Size == kRAMb_Size if (kRAMa_Size == bankbit) { /* properly set up balanced RAM */ r.cmpmask = ~ ((1 << 30) - 1); r.cmpvalu = 0; r.usemask = kRAM_Size - 1; r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); } else #endif { #if kRAMb_Size != 0 r.cmpmask = bankbit | ~ ((1 << 30) - 1); r.cmpvalu = bankbit; r.usemask = kRAMb_Size - 1; r.usebase = kRAMa_Size + RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif r.cmpmask = bankbit | ~ ((1 << 30) - 1); r.cmpvalu = 0; r.usemask = kRAMa_Size - 1; r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); } } r.cmpmask = ~ ((1 << 28) - 1); r.cmpvalu = 0x40000000; r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; AddToATTList(&r); #if 0 /* haven't persuaded emulated computer to look here yet. */ /* NuBus super space */ r.cmpmask = ~ ((1 << 28) - 1); r.cmpvalu = 0x90000000; r.usemask = kVidMemRAM_Size - 1; r.usebase = VidMem; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif /* Standard NuBus space */ r.cmpmask = ~ ((1 << 20) - 1); r.cmpvalu = 0xF9F00000; r.usemask = kVidROM_Size - 1; r.usebase = VidROM; r.Access = kATTA_readreadymask; AddToATTList(&r); #if 0 r.cmpmask = ~ 0x007FFFFF; r.cmpvalu = 0xF9000000; r.usemask = 0x007FFFFF & (kVidMemRAM_Size - 1); r.usebase = VidMem; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif r.cmpmask = ~ 0x000FFFFF; r.cmpvalu = 0xF9900000; r.usemask = 0x000FFFFF & (kVidMemRAM_Size - 1); r.usebase = VidMem; r.Access = kATTA_readwritereadymask; AddToATTList(&r); /* kludge to allow more than 1M of Video Memory */ #if kVidMemRAM_Size >= 0x00200000 r.cmpmask = ~ 0x000FFFFF; r.cmpvalu = 0xF9A00000; r.usemask = 0x000FFFFF & (kVidMemRAM_Size - 1); r.usebase = VidMem + (1 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif #if kVidMemRAM_Size >= 0x00400000 r.cmpmask = ~ 0x000FFFFF; r.cmpvalu = 0xF9B00000; r.usemask = 0x000FFFFF & (kVidMemRAM_Size - 1); r.usebase = VidMem + (2 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); r.cmpmask = ~ 0x000FFFFF; r.cmpvalu = 0xF9C00000; r.usemask = 0x000FFFFF & (kVidMemRAM_Size - 1); r.usebase = VidMem + (3 << 20); r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif SetUp_io(); #if 0 if ((addr >= 0x58000000) && (addr < 0x58000004)) { /* test hardware. fail */ } #endif } #endif #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) LOCALPROC SetUp_address(void) { if (Addr32) { SetUp_address32(); } else { SetUp_address24(); } } #endif /* unlike in the real Mac Plus, Mini vMac will allow misaligned memory access, since it is easier to allow it than it is to correctly simulate a bus error and back out of the current instruction. */ #if (CurEmMd != kEmMd_II) && (CurEmMd != kEmMd_IIx) LOCALPROC SetUp_RAM24(void) { ATTer r; #if (0 == kRAMb_Size) || (kRAMa_Size == kRAMb_Size) r.cmpmask = 0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1); r.cmpvalu = kRAM_Base; r.usemask = kRAM_Size - 1; r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #else /* unbalanced memory */ #if 0 != (0x00FFFFFF & kRAMa_Size) /* condition should always be true if configuration file right */ r.cmpmask = 0x00FFFFFF & (kRAMa_Size | ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = kRAM_Base + kRAMa_Size; r.usemask = kRAMb_Size - 1; r.usebase = kRAMa_Size + RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif r.cmpmask = 0x00FFFFFF & (kRAMa_Size | ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = kRAM_Base; r.usemask = kRAMa_Size - 1; r.usebase = RAM; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif } #endif #if (CurEmMd != kEmMd_II) && (CurEmMd != kEmMd_IIx) LOCALPROC SetUp_address(void) { ATTer r; if (MemOverlay) { r.cmpmask = Overlay_ROM_CmpZeroMask | (0x00FFFFFF & ~ ((1 << kRAM_ln2Spc) - 1)); r.cmpvalu = kRAM_Base; r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; AddToATTList(&r); } else { SetUp_RAM24(); } r.cmpmask = kROM_cmpmask; r.cmpvalu = kROM_Base; #if (CurEmMd >= kEmMd_SE) if (MemOverlay) { r.usebase = nullpr; r.Access = kATTA_ntfymask; r.Ntfy = kMAN_OverlayOff; } else #endif { r.usemask = kROM_Size - 1; r.usebase = ROM; r.Access = kATTA_readreadymask; } AddToATTList(&r); if (MemOverlay) { r.cmpmask = 0x00E00000; r.cmpvalu = kRAM_Overlay_Base; #if (0 == kRAMb_Size) || (kRAMa_Size == kRAMb_Size) r.usemask = kRAM_Size - 1; /* note that cmpmask and usemask overlap for 4M */ r.usebase = RAM; r.Access = kATTA_readwritereadymask; #else /* unbalanced memory */ r.usemask = kRAMb_Size - 1; r.usebase = kRAMa_Size + RAM; r.Access = kATTA_readwritereadymask; #endif AddToATTList(&r); } #if IncludeVidMem r.cmpmask = 0x00FFFFFF & ~ ((1 << kVidMem_ln2Spc) - 1); r.cmpvalu = kVidMem_Base; r.usemask = kVidMemRAM_Size - 1; r.usebase = VidMem; r.Access = kATTA_readwritereadymask; AddToATTList(&r); #endif r.cmpmask = 0x00FFFFFF & ~ ((1 << kVIA1_ln2Spc) - 1); r.cmpvalu = kVIA1_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_VIA1; AddToATTList(&r); r.cmpmask = 0x00FFFFFF & ~ ((1 << kSCC_ln2Spc) - 1); r.cmpvalu = kSCCRd_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_SCC; AddToATTList(&r); r.cmpmask = 0x00FFFFFF & ~ ((1 << kExtn_ln2Spc) - 1); r.cmpvalu = kExtn_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_Extn; AddToATTList(&r); #if CurEmMd == kEmMd_PB100 r.cmpmask = 0x00FFFFFF & ~ ((1 << kASC_ln2Spc) - 1); r.cmpvalu = kASC_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_ASC; AddToATTList(&r); #endif r.cmpmask = 0x00FFFFFF & ~ ((1 << kSCSI_ln2Spc) - 1); r.cmpvalu = kSCSI_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_SCSI; AddToATTList(&r); r.cmpmask = 0x00FFFFFF & ~ ((1 << kIWM_ln2Spc) - 1); r.cmpvalu = kIWM_Block_Base; r.usebase = nullpr; r.Access = kATTA_mmdvmask; r.MMDV = kMMDV_IWM; AddToATTList(&r); } #endif LOCALPROC SetUpMemBanks(void) { InitATTList(); SetUp_address(); FinishATTList(); } #if 0 LOCALPROC get_fail_realblock(ATTep p) { p->cmpmask = 0; p->cmpvalu = 0xFFFFFFFF; p->usemask = 0; p->usebase = nullpr; p->Access = 0; } #endif GLOBALFUNC ui5b MMDV_Access(ATTep p, ui5b Data, blnr WriteMem, blnr ByteSize, CPTR addr) { switch (p->MMDV) { case kMMDV_VIA1: if (! ByteSize) { ReportAbnormal("access VIA1 word"); } else if ((addr & 1) != 0) { ReportAbnormal("access VIA1 odd"); } else { #if CurEmMd != kEmMd_PB100 #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) if ((addr & 0x000001FE) != 0x00000000) #else if ((addr & 0x000FE1FE) != 0x000FE1FE) #endif { ReportAbnormal("access VIA1 nonstandard address"); } #endif Data = VIA1_Access(Data, WriteMem, (addr >> 9) & kVIA1_Mask); } break; #if EmVIA2 case kMMDV_VIA2: if (! ByteSize) { if ((! WriteMem) && ((0x3e00 == (addr & 0x1FFFF)) || (0x3e02 == (addr & 0x1FFFF)))) { /* for weirdness at offset 0x71E in ROM */ Data = (VIA2_Access(Data, WriteMem, (addr >> 9) & kVIA2_Mask) << 8) | VIA2_Access(Data, WriteMem, (addr >> 9) & kVIA2_Mask); } else { ReportAbnormal("access VIA2 word"); } } else if ((addr & 1) != 0) { if (0x3FFF == (addr & 0x1FFFF)) { /* for weirdness at offset 0x7C4 in ROM. looks like bug. */ Data = VIA2_Access(Data, WriteMem, (addr >> 9) & kVIA2_Mask); } else { ReportAbnormal("access VIA2 odd"); } } else { if ((addr & 0x000001FE) != 0x00000000) { ReportAbnormal("access VIA2 nonstandard address"); } Data = VIA2_Access(Data, WriteMem, (addr >> 9) & kVIA2_Mask); } break; #endif case kMMDV_SCC: #if (CurEmMd >= kEmMd_SE) \ && ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if ((addr & 0x00100000) == 0) { ReportAbnormal("access SCC unassigned address"); } else #endif if (! ByteSize) { ReportAbnormal("Attemped Phase Adjust"); } else #if ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if (WriteMem != ((addr & 1) != 0)) { if (WriteMem) { #if CurEmMd >= kEmMd_512Ke #if CurEmMd != kEmMd_PB100 ReportAbnormal("access SCC even/odd"); /* This happens on boot with 64k ROM. */ #endif #endif } else { SCC_Reset(); } } else #endif #if (CurEmMd != kEmMd_PB100) \ && ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if (WriteMem != (addr >= kSCCWr_Block_Base)) { ReportAbnormal("access SCC wr/rd base wrong"); } else #endif { #if CurEmMd != kEmMd_PB100 #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) if ((addr & 0x1FF9) != 0x00000000) #else if ((addr & 0x001FFFF8) != 0x001FFFF8) #endif { ReportAbnormal("access SCC nonstandard address"); } #endif Data = SCC_Access(Data, WriteMem, (addr >> 1) & kSCC_Mask); } break; case kMMDV_Extn: if (ByteSize) { ReportAbnormal("access Sony byte"); } else if ((addr & 1) != 0) { ReportAbnormal("access Sony odd"); } else if (! WriteMem) { ReportAbnormal("access Sony read"); } else { Extn_Access(Data, (addr >> 1) & 0x0F); } break; #if EmASC case kMMDV_ASC: if (! ByteSize) { #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) if (WriteMem) { (void) ASC_Access((Data >> 8) & 0x00FF, WriteMem, addr & kASC_Mask); Data = ASC_Access((Data) & 0x00FF, WriteMem, (addr + 1) & kASC_Mask); } else { Data = (ASC_Access((Data >> 8) & 0x00FF, WriteMem, addr & kASC_Mask) << 8) | ASC_Access((Data) & 0x00FF, WriteMem, (addr + 1) & kASC_Mask); } #else ReportAbnormal("access ASC word"); #endif } else { Data = ASC_Access(Data, WriteMem, addr & kASC_Mask); } break; #endif case kMMDV_SCSI: if (! ByteSize) { ReportAbnormal("access SCSI word"); } else #if ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if (WriteMem != ((addr & 1) != 0)) { ReportAbnormal("access SCSI even/odd"); } else #endif { #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) if ((addr & 0x1F8F) != 0x00000000) { ReportAbnormal("access SCSI nonstandard address"); } #endif Data = SCSI_Access(Data, WriteMem, (addr >> 4) & 0x07); } break; case kMMDV_IWM: #if (CurEmMd >= kEmMd_SE) \ && ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if ((addr & 0x00100000) == 0) { ReportAbnormal("access IWM unassigned address"); } else #endif if (! ByteSize) { #if ExtraAbnormalReports ReportAbnormal("access IWM word"); /* This happens when quitting 'Glider 3.1.2'. perhaps a bad handle is being disposed of. */ #endif } else #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) if ((addr & 1) != 0) { ReportAbnormal("access IWM odd"); } else #else if ((addr & 1) == 0) { ReportAbnormal("access IWM even"); } else #endif { #if (CurEmMd != kEmMd_PB100) \ && ! ((CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx)) if ((addr & 0x001FE1FF) != 0x001FE1FF) { ReportAbnormal("access IWM nonstandard address"); } #endif Data = IWM_Access(Data, WriteMem, (addr >> 9) & kIWM_Mask); } break; } return Data; } GLOBALFUNC blnr MemAccessNtfy(ATTep pT) { blnr v = falseblnr; switch (pT->Ntfy) { #if CurEmMd >= kEmMd_SE case kMAN_OverlayOff: pT->Access = kATTA_readreadymask; MemOverlay = 0; SetUpMemBanks(); v = trueblnr; break; #endif } return v; } GLOBALPROC MemOverlay_ChangeNtfy(void) { #if CurEmMd <= kEmMd_Plus SetUpMemBanks(); #elif (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) SetUpMemBanks(); #endif } #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) GLOBALPROC Addr32_ChangeNtfy(void) { SetUpMemBanks(); } #endif LOCALFUNC ATTep get_address_realblock1(blnr WriteMem, CPTR addr) { ATTep p; Label_Retry: p = FindATTel(addr); if (0 != (p->Access & (WriteMem ? kATTA_writereadymask : kATTA_readreadymask))) { /* ok */ } else { if (0 != (p->Access & kATTA_ntfymask)) { if (MemAccessNtfy(p)) { goto Label_Retry; } } p = nullpr; /* fail */ } return p; } GLOBALFUNC ui3p get_real_address0(ui5b L, blnr WritableMem, CPTR addr, ui5b *actL) { ui5b RealSize; ui5b bankleft; ui3p p; ATTep q; q = get_address_realblock1(WritableMem, addr); if (nullpr == q) { *actL = 0; p = nullpr; } else { ui5b bankoffset = addr & q->usemask; RealSize = q->usemask + 1; bankleft = RealSize - bankoffset; p = bankoffset + q->usebase; if (bankleft >= L) { /* this block is big enough (by far the most common case) */ *actL = L; } else { /* not big enough, look if following block is contiguous in real memory. */ ui3p bankend; ui5b n = L; label_1: addr += bankleft; n -= bankleft; bankend = RealSize + q->usebase; q = get_address_realblock1(WritableMem, addr); if ((nullpr == q) || (q->usebase != bankend)) { /* following block not contiguous */ *actL = L - n; } else { RealSize = q->usemask + 1; if (RealSize >= n) { /* following block is contiguous and big enough */ *actL = L; /* ok */ } else { bankoffset = addr & q->usemask; if (bankoffset != 0) { ReportAbnormal( "problem with get_address_realblock1"); } bankleft = RealSize; goto label_1; } } } } return p; } GLOBALVAR blnr InterruptButton = falseblnr; GLOBALPROC SetInterruptButton(blnr v) { if (InterruptButton != v) { InterruptButton = v; VIAorSCCinterruptChngNtfy(); } } LOCALVAR ui3b CurIPL = 0; GLOBALPROC VIAorSCCinterruptChngNtfy(void) { #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) ui3b NewIPL; if (InterruptButton) { NewIPL = 7; } else if (SCCInterruptRequest) { NewIPL = 4; } else if (VIA2_InterruptRequest) { NewIPL = 2; } else if (VIA1_InterruptRequest) { NewIPL = 1; } else { NewIPL = 0; } #else ui3b VIAandNotSCC = VIA1_InterruptRequest & ~ SCCInterruptRequest; ui3b NewIPL = VIAandNotSCC | (SCCInterruptRequest << 1) | (InterruptButton << 2); #endif if (NewIPL != CurIPL) { CurIPL = NewIPL; m68k_IPLchangeNtfy(); } } GLOBALFUNC blnr AddrSpac_Init(void) { int i; for (i = 0; i < kNumWires; i++) { Wires[i] = 1; } MINEM68K_Init( &CurIPL); return trueblnr; } GLOBALPROC Memory_Reset(void) { MemOverlay = 1; SetUpMemBanks(); } #if (CurEmMd == kEmMd_II) || (CurEmMd == kEmMd_IIx) EXPORTPROC PowerOff_ChangeNtfy(void); GLOBALPROC PowerOff_ChangeNtfy(void) { if (! VIA2_iB2) { ForceMacOff = trueblnr; } } #endif /* user event queue utilities */ #if HaveMasterMyEvtQLock GLOBALVAR ui4r MasterMyEvtQLock = 0; /* Takes a few ticks to process button event because of debounce code of Mac. So have this mechanism to prevent processing further events meanwhile. */ #endif GLOBALFUNC blnr FindKeyEvent(int *VirtualKey, blnr *KeyDown) { MyEvtQEl *p; if ( #if HaveMasterMyEvtQLock (0 == MasterMyEvtQLock) && #endif (nullpr != (p = MyEvtQOutP()))) { if (MyEvtQElKindKey == p->kind) { *VirtualKey = p->u.press.key; *KeyDown = p->u.press.down; MyEvtQOutDone(); return trueblnr; } } return falseblnr; } /* task management */ #ifdef _VIA_Debug #include #endif GLOBALVAR uimr ICTactive; GLOBALVAR iCountt ICTwhen[kNumICTs]; GLOBALPROC ICT_Zap(void) { ICTactive = 0; } LOCALPROC InsertICT(int taskid, iCountt when) { ICTwhen[taskid] = when; ICTactive |= (1 << taskid); } GLOBALVAR iCountt NextiCount = 0; GLOBALFUNC iCountt GetCuriCount(void) { return NextiCount - GetCyclesRemaining(); } GLOBALPROC ICT_add(int taskid, ui5b n) { /* n must be > 0 */ si5r x = GetCyclesRemaining(); ui5b when = NextiCount - x + n; #ifdef _VIA_Debug fprintf(stderr, "ICT_add: %d, %d, %d\n", when, taskid, n); #endif InsertICT(taskid, when); if (x > (si5r)n) { SetCyclesRemaining(n); NextiCount = when; } }