diff --git a/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm b/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm index ba255317b..cec034ad8 100644 --- a/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm +++ b/devices/pc/bios/compaq/deskpro386/1988-01-28.nasm @@ -7,7 +7,9 @@ ; Additional post-processing performed by the PCjs TextOut module ; All post-processing, comments, etc copyright © 2012-2015 Jeff Parsons ; -; NOTE: This 32Kb ROM image is ORG'ed at 0x8000, because it needs to run at real-mode +; Overview +; -------- +; This 32Kb ROM image is ORG'ed at 0x8000, because it needs to run at real-mode ; addresses F000:8000 through F000:FFFF, as well as protected-mode physical addresses ; %FFFF8000 through %FFFFFFFF. Additionally, DeskPro 386 systems mirror this 32Kb ROM ; at real-mode addresses F000:0000 through F000:7FFF, as well as protected-mode physical @@ -20,16 +22,44 @@ ; %FE0000 through %FFFFFF to be mapped to %0E0000 through %0FFFFF, effectively replacing ; the ROM in the first megabyte with write-protected RAM; the top 64Kb of that RAM must ; first be initialized with the 64Kb at %0F0000 prior to remapping. It's also possible -; to copy external ROMs from %0E0000 through %0EFFFF into the bottom 64Kb of that RAM, but -; this is only done for ROMs known to contain relocatable code (eg, a Compaq Enhanced +; to copy external ROMs from %0C0000 through %0EFFFF into the bottom 64Kb of that RAM, +; but this is only done for ROMs known to contain relocatable code (eg, a Compaq Enhanced ; Video Graphics card). ; -; Every DeskPro 386 system must have a MINIMUM of 1Mb of RAM, of which either 256Kb, 512Kb, -; or 640Kb can be physically mapped as conventional memory (at the bottom of the first -; megabyte), with the remainder (either 768Kb, 512Kb, or 384Kb) physically mapped to the -; top of the 16th megabyte (ending at address %FFFFFF), the last 128Kb of which is -; used by the "RAM Relocation" feature. The remaining memory immediately below that +; Every DeskPro 386 system must have a MINIMUM of 1Mb of RAM, of which either 256Kb, +; 512Kb, or 640Kb can be physically mapped as conventional memory (at the bottom of the +; first megabyte), with the remainder (either 768Kb, 512Kb, or 384Kb) physically mapped +; to the top of the 16th megabyte (ending at address %FFFFFF), the last 128Kb of which +; is used by the "RAM Relocation" feature. The remaining memory immediately below that ; 128Kb (ie, below %FE0000) can only be accessed by special system software, such as CEMM. +; +; Compaq refers to that remaining memory as "Compaq Built-in Memory". +; +; As the Compaq 386/25 TechRef explains: +; +; A data structure in memory indicates how much of the COMPAQ Built-in Memory (F40000h +; to FE0000h) is [available and] in use. This memory is allocated downward (decreasing +; addresses) starting at address FE0000h. Applications developed specifically for the +; COMPAQ DESKPRO 386/25 Personal Computer, such as CEMM, read and modify this data +; structure to allocate and deallocate portions of the COMPAQ Built-in Memory for their +; use. The built-in memory data structure is located in write-protected memory at segment +; F000h. The offset is specified by the word at F000:FFE0. +; +; The format of the data structure is given [below]. Because the data structure resides +; in write-protected memory, the write-protection must be disabled when updating the data +; structure. +; +; Word Description +; ---- ----------- +; 0 FFFFh indicates that no COMPAQ Built-in Memory is available. Otherwise, words +; 1, 2, and 3 define the amount of memory available. +; +; 1 Total COMPAQ Built-in Memory size in 16-byte blocks. +; +; 2 Available built-in memory in 16-byte blocks. +; +; 3 Address for the last-used byte. The byte below (lower address) this byte is the +; first free byte in the COMPAQ Built-in Memory. ; org 0x8000 @@ -98,6 +128,7 @@ x8051: push bx ; 00008051 53 'S' push bp ; 00008053 55 'U' mov dl,al ; 00008054 8AD0 '..' mov bp,es ; 00008056 8CC5 '..' + ;; ;; 0x4C is the base portion of the descriptor at DS:0x48 ;; @@ -738,16 +769,18 @@ x853c: mov al,0x7f ; 0000853C B07F '..' cld ; 0000858F FC '.' rep movsd ; 00008590 66F3A5 'f..' - mov bx,rombuf1 ; 00008593 BBE0FF '...' + ;; + ;; (DI) -> 0x7FB6 + ;; + mov bx,bim_table_offset ; 00008593 BBE0FF '...' mov di,[bx] ; 00008596 8B3F '.?' + ;; - ;; (DI) == 0x7FB6 + ;; (SI) -> 0x7FBE ;; - mov bx,rombuf2 ; 00008598 BBE2FF '...' + mov bx,cpu_idrev_offset ; 00008598 BBE2FF '...' mov si,[bx] ; 0000859B 8B37 '.7' - ;; - ;; (SI) == 0x7FBE - ;; + pop ds ; 0000859D 1F '.' mov word [0x50],0xffff ; 0000859E C7065000FFFF '..P...' mov word [0x52],0x0 ; 000085A4 C70652000000 '..R...' @@ -755,37 +788,58 @@ x853c: mov al,0x7f ; 0000853C B07F '..' mov byte [0x55],0x92 ; 000085AF C606550092 '..U..' mov byte [0x56],0x0 ; 000085B4 C606560000 '..V..' mov byte [0x57],0x80 ; 000085B9 C606570080 '..W..' - mov bx,[0x8d] ; 000085BE 8B1E8D00 '....' + ;; ;; (BX) is 0x100 (256Kb) ;; + mov bx,[0x8d] ; 000085BE 8B1E8D00 '....' + push ds ; 000085C2 1E '.' - mov ax,0x50 ; 000085C3 B85000 '.P.' - mov ds,ax ; 000085C6 8ED8 '..' + ;; ;; (DS) -> 0x80C00000 ;; + mov ax,0x50 ; 000085C3 B85000 '.P.' + mov ds,ax ; 000085C6 8ED8 '..' + + ;; + ;; Disable IOCHK NMI, since it is possible to generate a + ;; parity error by simply reading the RAM Diagnostics Register. + ;; in al,0x61 ; 000085C8 E461 '.a' push ax ; 000085CA 50 'P' or al,0x8 ; 000085CB 0C08 '..' out 0x61,al ; 000085CD E661 '.a' + ;; - ;; Load the RAM Diagnostics Register from 0x80C00000 + ;; (AL) == RAM Diagnostics Register (from 0x80C00000) ;; mov al,[0x0] ; 000085CF A00000 '...' + + ;; + ;; Ensure that relocatable RAM at %FE0000 is NEITHER currently remapped NOR write-protected + ;; mov byte [0x0],0xff ; 000085D2 C6060000FF '.....' + ;; ;; Isolate the base memory settings in bits 5-4 (00=640Kb, 10=512Kb, 11=256Kb) ;; and al,0xf0 ; 000085D7 24F0 '$.' + ;; - ;; Update %FF7FB7 with base memory settings + ;; Update [bim_table_offset]+1 (eg, %FF7FB7) with base memory settings ;; mov [es:di+0x1],al ; 000085D9 26884501 '&.E.' pop ax ; 000085DD 58 'X' out 0x61,al ; 000085DE E661 '.a' + ;; - ;; Update %FF7FB6 with 0x10 + ;; Update [bim_table_offset]+0 (eg, %FF7FB6) with 0x10; that will set the + ;; first word of the built-in memory table to one of these values: + ;; + ;; 0x0010 256kb (1024 - 640 - 128) + ;; 0x2010 384Kb (1024 - 512 - 128) + ;; 0x3010 640Kb (1024 - 256 - 128) ;; mov byte [es:di],0x10 ; 000085E0 26C60510 @@ -796,40 +850,54 @@ x853c: mov al,0x7f ; 0000853C B07F '..' mov al,0xb0 ; 000085EC B0B0 '..' out 0x70,al ; 000085EE E670 '.p' in al,0x71 ; 000085F0 E471 '.q' + ;; - ;; (AX) contains CMOS EXTMEM2 value (0x400) + ;; (AX) contains CMOS EXTMEM2 value (eg, 0x400 or 1024Kb), + ;; to which we add another 1024Kb (for conventional memory) ;; add ax,0x400 ; 000085F2 050004 '...' mov cx,0x3f80 ; 000085F5 B9803F '..?' + ;; - ;; (CX) contains 0x3F80 (maximum # of supported Kb) + ;; (CX) contains 0x3F80 (maximum # of supported Kb), reduced + ;; by the amount of built-in memory ;; sub cx,bx ; 000085F8 2BCB '+.' + ;; ;; Compare (AX), total conventional+extended memory, to (CX) ;; cmp ax,cx ; 000085FA 3BC1 ';.' jc x8600 ; 000085FC 7202 'r.' xor bx,bx ; 000085FE 33DB '3.' -x8600: shl bx,0x6 ; 00008600 C1E306 '...' + ;; - ;; Move 0x4000 to %FF7FB8 and %FF7FBA + ;; Assuming no problems, convert Kb of built-in memory to paragraphs, + ;; by multiplying by 64 + ;; +x8600: shl bx,0x6 ; 00008600 C1E306 '...' + + ;; + ;; If (BX) was 0x100 (256Kb), we'll move the equivalent number of paragraphs + ;; (0x4000) to [bim_table_offset]+2 and +4 (eg, %FF7FB8 and %FF7FBA). ;; mov [es:di+0x2],bx ; 00008603 26895D02 '&.].' mov [es:di+0x4],bx ; 00008607 26895D04 '&.].' mov ch,0xfe ; 0000860B B5FE '..' xor cl,cl ; 0000860D 32C9 '2.' shl cx,0x4 ; 0000860F C1E104 '...' + ;; - ;; Move 0xE000 to %FF7FBC + ;; Move 0xE000 to [bim_table_offset]+6 (eg, %FF7FBC) ;; mov [es:di+0x6],cx ; 00008612 26894D06 '&.M.' mov di,si ; 00008616 8BFE '..' mov ax,gs ; 00008618 8CE8 '..' + ;; - ;; (AX) now contains the processor type and revision (AH=0x03, AL=0x04) - ;; - ;; Store the type in %FF7FBE and the revision in %FF7FBF + ;; (AX) contains the processor type and revision (AH=0x03, AL=0x04), + ;; which were preserved on reset in (GS); store them at the offset specified + ;; by cpu_idrev_offset (eg, type in %FF7FBE and revision in %FF7FBF). ;; mov [es:di],ah ; 0000861A 268825 '&.%' mov [es:di+0x1],al ; 0000861D 26884501 '&.E.' @@ -844,6 +912,7 @@ x862a: es lodsb ; 0000862A 26AC '&.' not ah ; 00008630 F6D4 '..' inc ah ; 00008632 FEC4 '..' mov [es:si],ah ; 00008634 268824 '&.$' + ;; ;; Relocate RAM at %FF0000 to %0F0000 ;; @@ -4229,7 +4298,7 @@ xa544: push bx ; 0000A544 53 'S' mov byte [bx+0x5],0x92 ; 0000A564 C6470592 '.G..' mov ax,0x20 ; 0000A568 B82000 '. .' mov es,ax ; 0000A56B 8EC0 '..' - mov bx,rombuf1 ; 0000A56D BBE0FF '...' + mov bx,bim_table_offset ; 0000A56D BBE0FF '...' mov bx,[es:bx] ; 0000A570 268B1F '&..' test word [es:bx],0xf00 ; 0000A573 26F707000F '&....' jnz xa57f ; 0000A578 7505 'u.' @@ -6310,11 +6379,11 @@ xbad3: cld ; 0000BAD3 FC '.' mov al,0xff ; 0000BAD9 B0FF '..' out 0x21,al ; 0000BADB E621 '.!' out 0xa1,al ; 0000BADD E6A1 '..' - mov bx,rombuf1 ; 0000BADF BBE0FF '...' + mov bx,bim_table_offset ; 0000BADF BBE0FF '...' mov bx,[bx] ; 0000BAE2 8B1F '..' test word [bx],0xf00 ; 0000BAE4 F707000F '....' jnz xbaf5 ; 0000BAE8 750B 'u.' - mov bx,rombuf2 ; 0000BAEA BBE2FF '...' + mov bx,cpu_idrev_offset ; 0000BAEA BBE2FF '...' mov bx,[bx] ; 0000BAED 8B1F '..' mov ax,[bx] ; 0000BAEF 8B07 '..' xchg al,ah ; 0000BAF1 86C4 '..' @@ -10901,7 +10970,7 @@ xdf34: mov bx,0x2 ; 0000DF34 BB0200 '...' lea si,[si+0x18] ; 0000DF48 8D7418 '.t.' call xdfbc ; 0000DF4B E86E00 '.n.' mov si,bx ; 0000DF4E 8BF3 '..' - mov di,rombuf1 ; 0000DF50 BFE0FF '...' + mov di,bim_table_offset ; 0000DF50 BFE0FF '...' mov di,[cs:di] ; 0000DF53 2E8B3D '..=' test word [cs:di],0xf00 ; 0000DF56 2EF705000F '.....' lea di,[si+0x38] ; 0000DF5B 8D7C38 '.|8' @@ -11519,7 +11588,7 @@ xe7dc: ret ; 0000E7DC C3 '.' sub al,0x2d ; 0000E7DD 2C2D ',-' (NOTE: This instruction doesn't appear reachable) -xe7df: mov si,rombuf1 ; 0000E7DF BEE0FF '...' +xe7df: mov si,bim_table_offset ; 0000E7DF BEE0FF '...' mov si,[cs:si] ; 0000E7E2 2E8B34 '..4' mov ax,[cs:si] ; 0000E7E5 2E8B04 '...' test ax,0xf00 ; 0000E7E8 A9000F '...' @@ -12646,7 +12715,7 @@ xf273: cmp bx,byte +0x0 ; 0000F273 83FB00 '...' sub ax,bx ; 0000F287 2BC3 '+.' mov cx,0xf000 ; 0000F289 B900F0 '...' mov es,cx ; 0000F28C 8EC1 '..' - mov di,rombuf1 ; 0000F28E BFE0FF '...' + mov di,bim_table_offset ; 0000F28E BFE0FF '...' mov di,[es:di] ; 0000F291 268B3D '&.=' mov [es:di],al ; 0000F294 268805 '&..' xf297: ret ; 0000F297 C3 '.' @@ -12817,21 +12886,23 @@ pattern2: xf480: mov al,0x7d ; 0000F480 B07D out 0x84,al ; 0000F482 E684 - mov si,rombuf1 ; 0000F484 BEE0FF - mov si,[cs:si] ; 0000F487 2E8B34 '..4' - test word [cs:si],0xf00 ; 0000F48A 2EF704000F '.....' - jz xf494 ; 0000F48F 7403 't.' - jmp xf684 ; 0000F491 E9F001 '...' + mov si,bim_table_offset ; 0000F484 BEE0FF + mov si,[cs:si] ; 0000F487 2E8B34 + test word [cs:si],0x0f00 ; 0000F48A 2EF704000F + jz xf494 ; 0000F48F 7403 + jmp xf684 ; 0000F491 E9F001 + +xf494: mov al,0x0 ; 0000F494 B000 + out 0x80,al ; 0000F496 E680 -xf494: mov al,0x0 ; 0000F494 B000 '..' - out 0x80,al ; 0000F496 E680 '..' - ;; - ;; TODO: Determine why the ROM uses gdtr_hi instead of gdtr_lo this time. ;; ;; When we arrive here, the A20 line has been disabled, so in theory, the GDT-in-ROM ;; is accessible only at the "lo" ROM address (%0F0730), not the "hi" address (%FF0730). ;; Which means the following JMP through selector 0x28 (indeed, any selector access) - ;; should immediately fail. Yet somehow this code still works? + ;; should immediately fail. TODO: Determine how this code works in "real life" + ;; + ;; It seems this code doesn't really do much PROVIDED bits 6 and 7 of the RAM Settings + ;; register are set to anything other than 0x40. ;; lgdt [cs:0x077e] ; 0000F498 load [gdtr_hi] into GDTR mov eax,cr0 ; 0000F49E 0F2000 @@ -12849,9 +12920,13 @@ xf4ac: mov ax,0x8 ; 0000F4AC B80800 '...' xchg ah,al ; 0000F4BC 86E0 '..' out 0x61,al ; 0000F4BE E661 '.a' and ah,0xc0 ; 0000F4C0 80E4C0 '...' - cmp ah,0x40 ; 0000F4C3 80FC40 '..@' - jz xf4cb ; 0000F4C6 7403 't.' - jmp xf655 ; 0000F4C8 E98A01 '...' + + ;; + ;; (AH) contains only bits 6 and 7 from the RAM Settings/Diagnostics register + ;; + cmp ah,0x40 ; 0000F4C3 80FC40 + jz xf4cb ; 0000F4C6 7403 + jmp xf655 ; 0000F4C8 E98A01 xf4cb: or byte [0x2],0x40 ; 0000F4CB 800E020040 '....@' mov ax,0x38 ; 0000F4D0 B83800 '.8.' @@ -13013,6 +13088,7 @@ xf63b: mov ax,0x8 ; 0000F63B B80800 '...' cmp al,0x0 ; 0000F64C 3C00 '<.' jnz xf655 ; 0000F64E 7505 'u.' or byte [0x2],0x40 ; 0000F650 800E020040 '....@' + xf655: mov ax,0x10 ; 0000F655 B81000 '...' mov es,ax ; 0000F658 8EC0 '..' mov ds,ax ; 0000F65A 8ED8 '..' @@ -13757,16 +13833,31 @@ xffb3: pop ds ; 0000FFB3 1F '.' times 29 db 0xFF ; 0000FFC0 - 0000FFDC - jmp x9f17 ; 0000FFDD E9379F '.7.' + jmp x9f17 ; 0000FFDD E9379F -rombuf1:dw 0x7FB6 ; 0000FFE0 B67F -rombuf2:dw 0x7FBE ; 0000FFE2 BE7F + ;; + ;; Offset for storing built-in memory table + ;; + ;; (Refer to "Compaq Built-in Memory" description at the top of this file) + ;; +bim_table_offset: + dw 0x7FB6 ; 0000FFE0 B67F - db 'G4J 03COMPAQ' ; 0000FFE4 47344A203033434F4D504151 + ;; + ;; Offset for storing CPU identifier (low byte) and revision number (high byte) + ;; +cpu_idrev_offset: + dw 0x7FBE ; 0000FFE2 BE7F + + db 'G' ; 0000FFE4 Product Family Code + db '4' ; 0000FFE5 Point-Release Code + db 'J ' ; 0000FFE6 Revision Code + db '03' ; 0000FFE8 BIOS Type Code + db 'COMPAQ' ; 0000FFEA Machine ID jmp 0xf000:reset ; 0000FFF0 EA05F900F0 - db 0x20 - db '01/28/88' - db 0xFC ; 0000FFFE FC - db 0x98 ; 0000FFFF 98 + db 0x20 ; 0000FFF5 + db '01/28/88' ; 0000FFF6 BIOS Revision Date + db 0xFC ; 0000FFFE Machine Type Code + db 0x98 ; 0000FFFF Checksum diff --git a/modules/pcjs/lib/bus.js b/modules/pcjs/lib/bus.js index 2a35ae219..14277a7fc 100644 --- a/modules/pcjs/lib/bus.js +++ b/modules/pcjs/lib/bus.js @@ -476,17 +476,21 @@ Bus.prototype.getA20 = function() */ Bus.prototype.setA20 = function(fEnable) { - this.assert(fEnable !== undefined); - if (fEnable !== undefined) { - if (this.nBusWidth > 20) { - var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0); - if (addrMask != this.busMask) { - this.busMask = addrMask; - /* - * This callback is required only because the CPU "insists" on using its own memory access functions. - */ - if (this.cpu) this.cpu.setAddressMask(addrMask); - } + /* + * TODO: Until I determine why the Compaq DeskPro 386 ROM is switching to protected-mode + * with the A20 line disabled, resulting in an almost immediate crash, I'm ignoring its requests + * to turn A20 off. + */ + if (I386 && COMPAQ386) fEnable = true; + + if (this.nBusWidth > 20) { + var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0); + if (addrMask != this.busMask) { + this.busMask = addrMask; + /* + * This callback is required only because the CPU "insists" on using its own memory access functions. + */ + if (this.cpu) this.cpu.setAddressMask(addrMask); } } }; diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index a2f849d29..0d4f7aef9 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -683,8 +683,8 @@ ChipSet.PPI_SW = { * READ WRITE REGISTER", but it is not otherwise discussed in the MODEL_5170 TechRef's 8042 documentation. * * There are brief references to bits 0 and 1 (KBC.RWREG.CLK_TIMER2 and KBC.RWREG.SPK_TIMER2), and the BIOS sets - * bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBC.RWREG.DISABLE_CHK, which are bits 2 and 3); why the BIOS - * also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100B rather than defined + * bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBC.RWREG.DISABLE_NMI, which are bits 2 and 3); why the BIOS + * also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100b rather than defined * constants. * * The bottom line: on a MODEL_5170, port 0x61 is still used for speaker control and parity checking, so we use @@ -751,12 +751,14 @@ ChipSet.KBC = { PORT: 0x61, CLK_TIMER2: 0x01, // set to enable clock to TIMER2 (R/W) SPK_TIMER2: 0x02, // set to connect output of TIMER2 to speaker (R/W) - DISABLE_CHK: 0x0C, // set to disable I/O and RAM parity checks, clear to enable (R/W) + COMPAQ_FSNMI: 0x04, // set to disable RAM/FS NMI (R/W, DESKPRO386) + COMPAQ_IONMI: 0x08, // set to disable IOCHK NMI (R/W, DESKPRO386) + DISABLE_NMI: 0x0C, // set to disable IOCHK and RAM/FS NMI, clear to enable (R/W) REFRESH_BIT: 0x10, // 0 if RAM refresh occurring, 1 if RAM not in refresh cycle (R/O) OUT_TIMER2: 0x20, // state of TIMER2 output signal (R/O, DESKPRO386) - IO_CHK: 0x40, // indicates I/O check (R/O); to reset, pulse bit 3 (0x08) - PARITY_CHK: 0x80, // indicates RAM parity check (R/O); to reset, pulse bit 2 (0x04) - PARITY_ERR: 0xC0 + IOCHK_NMI: 0x40, // IOCHK NMI (R/O); to reset, pulse bit 3 (0x08) + RAMFS_NMI: 0x80, // RAM/FS (parity or fail-safe) NMI (R/O); to reset, pulse bit 2 (0x04) + NMI_ERROR: 0xC0 }, CMD: { // this.b8042InBuff (on write to port 0x64, interpret this as a CMD) PORT: 0x64, @@ -4275,7 +4277,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom) { /* * Normally, we return whatever was last written to this port, but we do need to mask the - * two upper-most bits (KBC.RWREG.PARITY_ERR), as those are output-only bits used to signal + * two upper-most bits (KBC.RWREG.NMI_ERROR), as those are output-only bits used to signal * parity errors. * * Also, "TEST.09" of the MODEL_5170 BIOS expects the REFRESH_BIT to alternate, so we used to @@ -4297,7 +4299,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom) * in 1us, 64 cycles represents 8us, so that might be a bit fast for "WAITF", but bit 6 * is the only choice that also satisfies the pre-"TEST.11A" test as well. */ - var b = this.bPPIB & ~(ChipSet.KBC.RWREG.PARITY_ERR | ChipSet.KBC.RWREG.REFRESH_BIT) | ((this.cpu.getCycles() & 0x40)? ChipSet.KBC.RWREG.REFRESH_BIT : 0); + var b = this.bPPIB & ~(ChipSet.KBC.RWREG.NMI_ERROR | ChipSet.KBC.RWREG.REFRESH_BIT) | ((this.cpu.getCycles() & 0x40)? ChipSet.KBC.RWREG.REFRESH_BIT : 0); /* * Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages * unless both MESSAGE_8042 *and* MESSAGE_LOG are set. diff --git a/modules/pcjs/lib/memory.js b/modules/pcjs/lib/memory.js index beddb8656..bb21cc89b 100644 --- a/modules/pcjs/lib/memory.js +++ b/modules/pcjs/lib/memory.js @@ -386,12 +386,12 @@ Memory.prototype = { */ setReadAccess: function(afn, fDirect) { this.readByte = afn[0] || this.readNone; - this.readShort = afn[1] || this.readNone; - this.readLong = afn[2] || this.readNone; + this.readShort = afn[1] || this.readShortDefault; + this.readLong = afn[2] || this.readLongDefault; if (fDirect) { this.readByteDirect = afn[0] || this.readNone; - this.readShortDirect = afn[1] || this.readNone; - this.readLongDirect = afn[2] || this.readNone; + this.readShortDirect = afn[1] || this.readShortDefault; + this.readLongDirect = afn[2] || this.readLongDefault; } }, /** @@ -403,12 +403,12 @@ Memory.prototype = { */ setWriteAccess: function(afn, fDirect) { this.writeByte = !this.fReadOnly && afn[3] || this.writeNone; - this.writeShort = !this.fReadOnly && afn[4] || this.writeNone; - this.writeLong = !this.fReadOnly && afn[5] || this.writeNone; + this.writeShort = !this.fReadOnly && afn[4] || this.writeShortDefault; + this.writeLong = !this.fReadOnly && afn[5] || this.writeLongDefault; if (fDirect) { this.writeByteDirect = afn[3] || this.writeNone; - this.writeShortDirect = afn[4] || this.writeNone; - this.writeLongDirect = afn[5] || this.writeNone; + this.writeShortDirect = afn[4] || this.writeShortDefault; + this.writeLongDirect = afn[5] || this.writeLongDefault; } }, /** @@ -533,6 +533,55 @@ Memory.prototype = { this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true); } }, + /** + * readShortDefault(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readShortDefault: function readShortDefault(off) + { + return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8); + }, + /** + * readLongDefault(off) + * + * @this {Memory} + * @param {number} off + * @return {number} + */ + readLongDefault: function readLongDefault(off) + { + return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8) | (this.readByteDirect(off + 2) << 16) | (this.readByteDirect(off + 3) << 24); + }, + /** + * writeShortDefault(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeShortDefault: function writeShortDefault(off, w) + { + Component.assert(!(w & ~0xffff)); + this.writeByteDirect(off, w & 0xff); + this.writeByteDirect(off + 1, w >> 8); + }, + /** + * writeLongDefault(off, w) + * + * @this {Memory} + * @param {number} off + * @param {number} w + */ + writeLongDefault: function writeLongDefault(off, w) + { + this.writeByteDirect(off, w & 0xff); + this.writeByteDirect(off + 1, (w >> 8) & 0xff); + this.writeByteDirect(off + 2, (w >> 16) & 0xff); + this.writeByteDirect(off + 3, (w >>> 24)); + }, /** * readByteMemory(off) * diff --git a/modules/pcjs/lib/ram.js b/modules/pcjs/lib/ram.js index 4df70bd7d..d8b04e22a 100644 --- a/modules/pcjs/lib/ram.js +++ b/modules/pcjs/lib/ram.js @@ -33,6 +33,7 @@ "use strict"; if (typeof module !== 'undefined') { + var str = require("../../shared/lib/strlib"); var web = require("../../shared/lib/weblib"); var Component = require("../../shared/lib/component"); var Memory = require("./memory"); @@ -80,6 +81,7 @@ RAM.prototype.initBus = function(cmp, bus, cpu, dbg) { this.bus = bus; this.cpu = cpu; + this.dbg = dbg; this.chipset = cmp.getComponentByType("ChipSet"); this.setReady(); }; @@ -257,10 +259,10 @@ RAM.init = function() * The DeskPro 386 also contained two memory-mapped registers at 0x80C00000. The first is a write-only * mapping register that provides the ability to map the 128Kb at 0x00FE0000 to 0x000E0000, replacing * any ROMs in the range 0x000E0000-0x000FFFFF, and optionally write-protecting that 128Kb; internally, - * this register corresponds to bMappings. + * this register corresponds to wMappings. * * The second register is a read-only diagnostics register that indicates jumper configuration and - * parity errors; internally, this register corresponds to bSettings. + * parity errors; internally, this register corresponds to wSettings. * * To emulate the memory-mapped registers at 0x80C00000, the RAM component allocates a block at that * address using this custom controller once it sees an allocation for "ramCPQ". @@ -278,8 +280,12 @@ RAM.init = function() function CompaqController(ram) { this.ram = ram; - this.bMappings = CompaqController.MAPPINGS.DEFAULT; - this.bSettings = CompaqController.SETTINGS.BASE_640KB; + this.wMappings = CompaqController.MAPPINGS.DEFAULT; + /* + * TODO: wSettings needs to reflect the actual amount of configured memory.... + */ + this.wSettings = CompaqController.SETTINGS.DEFAULT; + this.wRAMSetup = CompaqController.RAMSETUP.DEFAULT; this.aBlocksDst = null; } @@ -289,19 +295,23 @@ CompaqController.MAP_DST = 0x000E0000; CompaqController.MAP_SIZE = 0x00020000; /* - * Bit definitions for the 8-bit write-only memory-mapping register (bMappings) + * Bit definitions for the 16-bit write-only memory-mapping register (wMappings) + * + * NOTE: Although Compaq says the memory at %FE0000 is "relocated", it actually remains addressable + * at %FE0000; it simply becomes addressable at %0E0000 as well, displacing any ROMs that used to be + * addressable at %0E0000 through %0FFFFF. */ CompaqController.MAPPINGS = { - UNMAPPED: 0x01, // is this bit is CLEAR, the last 128Kb (at 0x00FE0000) is mapped to 0x000E0000 - READWRITE: 0x02, // if this bit is CLEAR, the last 128Kb (at 0x00FE0000) is read-only (ie, write-protected) - RESERVED: 0xFC, // the remaining 6 bits are reserved and should always be SET - DEFAULT: 0xFF + UNMAPPED: 0x0001, // is this bit is CLEAR, the last 128Kb (at 0x00FE0000) is mapped to 0x000E0000 + READWRITE: 0x0002, // if this bit is CLEAR, the last 128Kb (at 0x00FE0000) is read-only (ie, write-protected) + RESERVED: 0xFFFC, // the remaining 6 bits are reserved and should always be SET + DEFAULT: 0xFFFF // our default settings (no mapping, no write-protection) }; /* - * Bit definitions for the 8-bit read-only settings/diagnostics register (bSettings) + * Bit definitions for the 16-bit read-only settings/diagnostics register (wSettings) * - * SW1-7 and SW1-8 are mapped to bits 5 and 4 of bSettings, respectively, as follows: + * SW1-7 and SW1-8 are mapped to bits 5 and 4 of wSettings, respectively, as follows: * * SW1-7 SW1-8 Bit5 Bit4 Amount (of base memory provided by the Compaq 32-bit memory board) * ----- ----- ---- ---- ------ @@ -330,64 +340,123 @@ CompaqController.MAPPINGS = { * SW1-6: ChipSet.KBC.INPORT.COMPAQ_NONDUAL clear if ON, set (0x40) if OFF */ CompaqController.SETTINGS = { - B0_PARITY: 0x01, - B1_PARITY: 0x02, - B2_PARITY: 0x04, - B3_PARITY: 0x08, - BASE_640KB: 0x00, // SW1-7,8: ON ON Bits 5,4: 00 - BASE_ERROR: 0x10, // SW1-7,8: ON OFF Bits 5,4: 01 - BASE_512KB: 0x20, // SW1-7,8: OFF ON Bits 5,4: 10 - BASE_256KB: 0x30, // SW1-7,8: OFF OFF Bits 5,4: 11 - ADDED_1MB: 0x40, - PIGGYBACK: 0x80 + B0_PARITY: 0x0001, // parity OK in byte 0 + B1_PARITY: 0x0002, // parity OK in byte 1 + B2_PARITY: 0x0004, // parity OK in byte 2 + B3_PARITY: 0x0008, // parity OK in byte 3 + BASE_640KB: 0x0000, // SW1-7,8: ON ON Bits 5,4: 00 + BASE_ERROR: 0x0010, // SW1-7,8: ON OFF Bits 5,4: 01 + BASE_512KB: 0x0020, // SW1-7,8: OFF ON Bits 5,4: 10 + BASE_256KB: 0x0030, // SW1-7,8: OFF OFF Bits 5,4: 11 + /* + * TODO: The DeskPro 386/25 TechRef says bit 6 (0x40) is always set, + * but setting it results in memory configuration errors; review. + */ + ADDED_1MB: 0x0040, + /* + * TODO: The DeskPro 386/25 TechRef says bit 7 (0x80) is always clear; review. + */ + PIGGYBACK: 0x0080, + SYS_4MB: 0x0100, // 4Mb on system board + SYS_1MB: 0x0200, // 1Mb on system board + SYS_NONE: 0x0300, // no memory on system board + MODA_4MB: 0x0400, // 4Mb on module A board + MODA_1MB: 0x0800, // 1Mb on module A board + MODA_NONE: 0x0C00, // no memory on module A board + MODB_4MB: 0x1000, // 4Mb on module B board + MODB_1MB: 0x2000, // 1Mb on module B board + MODB_NONE: 0x3000, // no memory on module B board + MODC_4MB: 0x4000, // 4Mb on module C board + MODC_1MB: 0x8000, // 1Mb on module C board + MODC_NONE: 0xC000, // no memory on module C board + /* + * NOTE: It doesn't seem to matter to the ROM whether I set any of bits 8-15 or not.... + */ + DEFAULT: 0x0A0F // our default settings (ie, parity OK, 640Kb base memory, 1Mb system memory, 1Mb module A memory) +}; + +CompaqController.RAMSETUP = { + SETUP: 0x000F, + CACHE: 0x0040, + RESERVED: 0xFFB0, + DEFAULT: 0x0002 // our default settings (ie, 2Mb, cache disabled) }; /** * readByte(off) * * @this {Memory} - * @param {number} off + * @param {number} off (relative to 0x80C00000) * @return {number} */ CompaqController.readByte = function readCompaqControllerByte(off) { - return this.controller.bSettings; + var b = 0xff; + if (off < 0x02) { + b = (off & 0x1)? (this.controller.wSettings >> 8) : (this.controller.wSettings & 0xff); + } + else if (off < 0x4) { + b = (off & 0x1)? (this.controller.wRAMSetup >> 8) : (this.controller.wRAMSetup & 0xff); + } + if (DEBUG) { + this.controller.ram.printMessage("CompaqController.readByte(" + str.toHexWord(off) + ") returned " + str.toHexByte(b), true, true); + if (MAXDEBUG && DEBUGGER && off >= 0x2) this.cpu.stopCPU(); + } + return b; }; /** * writeByte(off, b) * * @this {Memory} - * @param {number} off + * @param {number} off (relative to 0x80C00000) * @param {number} b */ CompaqController.writeByte = function writeCompaqControllerByte(off, b) { - var aBlocks; var controller = this.controller; - var bus = controller.ram.bus; - if (b != controller.bMappings) { - if (!(b & CompaqController.MAPPINGS.UNMAPPED)) { - if (!controller.aBlocksDst) { - controller.aBlocksDst = bus.getMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE); + + /* + * Check for write to 0x80C00000 + */ + if (!off) { + if (b != (controller.wMappings & 0xff)) { + var bus = controller.ram.bus; + if (!(b & CompaqController.MAPPINGS.UNMAPPED)) { + if (!controller.aBlocksDst) { + controller.aBlocksDst = bus.getMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE); + } + var aBlocks = bus.getMemoryBlocks(CompaqController.MAP_SRC, CompaqController.MAP_SIZE); + var type = (b & CompaqController.MAPPINGS.READWRITE)? Memory.TYPE.RAM : Memory.TYPE.ROM; + bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, aBlocks, type); } - aBlocks = bus.getMemoryBlocks(CompaqController.MAP_SRC, CompaqController.MAP_SIZE); - var type = (b & CompaqController.MAPPINGS.READWRITE)? Memory.TYPE.RAM : Memory.TYPE.ROM; - bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, aBlocks, type); - } - else { - if (controller.aBlocksDst) { - bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, controller.aBlocksDst); - controller.aBlocksDst = null; + else { + if (controller.aBlocksDst) { + bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, controller.aBlocksDst); + controller.aBlocksDst = null; + } } + controller.wMappings = (controller.wMappings & ~0xff) | b; + if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU(); } - controller.bMappings = b; - if (DEBUG) this.cpu.stopCPU(); + } + /* + * Check for write to 0x80C00002 + */ + else if (off == 0x2) { + controller.wRAMSetup = (controller.wRAMSetup & ~0xff) | b; + if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU(); + } + /* + * All bits in 0x80C00001 and 0x80C00003 are reserved, so we can simply ignore those writes. + */ + if (DEBUG) { + this.controller.ram.printMessage("CompaqController.writeByte(" + str.toHexWord(off) + "," + str.toHexByte(b) + ")", true, true); } }; -CompaqController.ACCESS = [CompaqController.readByte, CompaqController.readByte, CompaqController.readByte, - CompaqController.writeByte, CompaqController.writeByte, CompaqController.writeByte]; +CompaqController.BUFFER = [null, 0]; +CompaqController.ACCESS = [CompaqController.readByte, null, null, CompaqController.writeByte, null, null]; /** * getMemoryBuffer(addr) @@ -398,7 +467,7 @@ CompaqController.ACCESS = [CompaqController.readByte, CompaqController.readByte, */ CompaqController.prototype.getMemoryBuffer = function(addr) { - return [null, 0]; + return CompaqController.BUFFER; }; /** diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index cea9e2968..28a91ab27 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -1240,59 +1240,6 @@ Card.ACCESS.WRITE.MODE2OR = 0xA000; Card.ACCESS.WRITE.MODE2XOR = 0xE000; Card.ACCESS.WRITE.MASK = 0xff00; -/** - * readShort(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Card.ACCESS.readShort = function readShort(off) -{ - return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8); -}; - -/** - * readLong(off) - * - * @this {Memory} - * @param {number} off - * @return {number} - */ -Card.ACCESS.readLong = function readLong(off) -{ - return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8) | (this.readByteDirect(off + 2) << 16) | (this.readByteDirect(off + 3) << 24); -}; - -/** - * writeShort(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Card.ACCESS.writeShort = function writeShort(off, w) -{ - Component.assert(!(w & ~0xffff)); - this.writeByteDirect(off, w & 0xff); - this.writeByteDirect(off + 1, w >> 8); -}; - -/** - * writeLong(off, w) - * - * @this {Memory} - * @param {number} off - * @param {number} w - */ -Card.ACCESS.writeLong = function writeLong(off, w) -{ - this.writeByteDirect(off, w & 0xff); - this.writeByteDirect(off + 1, (w >> 8) & 0xff); - this.writeByteDirect(off + 2, (w >> 16) & 0xff); - this.writeByteDirect(off + 3, (w >>> 24)); -}; - /** * readByteMode0(off) * @@ -1952,9 +1899,7 @@ Card.prototype.setMemoryAccess = function(nAccess) fnWriteByte = Card.ACCESS.afn[Card.ACCESS.WRITE.EVENODD]; } } - if (!this.afnAccess) { - this.afnAccess = [null, Card.ACCESS.readShort, Card.ACCESS.readLong, null, Card.ACCESS.writeShort, Card.ACCESS.writeLong]; - } + if (!this.afnAccess) this.afnAccess = new Array(6); this.afnAccess[0] = fnReadByte; this.afnAccess[3] = fnWriteByte; this.nAccess = nAccess;